generated from mwc/project_game
added a monster spawner and modified lvl mechanics
Monsters have a weighting on how many to spawn and roll which specific monster to spawn from the pool. I have not added the ability to advance levels yet, though that should work to add monsters if the Floor number advances. I did notice a bug where the player cannot be harmed by the monsters unless the player moves into them, not the other way around. The monsters seem to treat the player as a wall that cannot be passed through. This is confusing because the code for the player and monsters match as far as their ability to move into each other...
This commit is contained in:
parent
12d0763a95
commit
c3b2775a80
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
23
angband.py
23
angband.py
|
@ -1,3 +1,14 @@
|
|||
# angband.py
|
||||
# ------------
|
||||
# By Pat Wick
|
||||
# This game is a redevelopment of the retro game "Angband". Named after
|
||||
# the stronghold of Morgoth, the Sauron before Sauron in the Lord of the Rings,
|
||||
# the game is a dungeon-crawler adventure game where the player is tasked with
|
||||
# delving into Angband to confront Morgoth. Defeating monsters earns the player
|
||||
# experience points (xp) which allow for more power as the player levels up.
|
||||
# In this, v0.2, a general movement and combat system exists, but level
|
||||
# generation, items, and monster spawning won't happen until future versions.
|
||||
|
||||
from retro.game import Game
|
||||
from player import Player
|
||||
from dungeon import Dungeon
|
||||
|
@ -9,11 +20,7 @@ from map import (
|
|||
level_one,
|
||||
random_empty_position
|
||||
)
|
||||
from enemies import (
|
||||
Orc,
|
||||
Rat,
|
||||
Spider
|
||||
)
|
||||
from monster_spawner import MonsterSpawner
|
||||
|
||||
print("Welcome to AngBAD (a poor representation of Angband)!\n")
|
||||
|
||||
|
@ -35,10 +42,8 @@ x,y = board_size
|
|||
|
||||
walls = [Wall(position) for position in board_edges(board_size)]
|
||||
level = [Wall(position) for position in level_one(board_size)]
|
||||
game = Game(walls + level, {"Race":race, "Class":class_,}, board_size = board_size)
|
||||
game = Game(walls + level, {"Race":race, "Class":class_,"CharLevel":1,"Floor":1}, board_size = board_size)
|
||||
game.add_agent(MonsterSpawner())
|
||||
game.add_agent(Player((x//2,y//2),race,class_))
|
||||
game.add_agent(Orc(random_empty_position(game)))
|
||||
game.add_agent(Rat(random_empty_position(game)))
|
||||
game.add_agent(Spider(random_empty_position(game)))
|
||||
|
||||
game.play()
|
20
enemies.py
20
enemies.py
|
@ -4,8 +4,11 @@ from strategy import (
|
|||
)
|
||||
|
||||
class Orc:
|
||||
"""Scary.
|
||||
"""
|
||||
character = "O"
|
||||
hp = 20
|
||||
maxHp = 20
|
||||
hp = maxHp
|
||||
deadly = True
|
||||
speed = 25
|
||||
|
||||
|
@ -25,10 +28,14 @@ class Orc:
|
|||
|
||||
if self.hp <= 0:
|
||||
game.remove_agent(self)
|
||||
game.get_agent_by_name("player").xp += self.maxHp
|
||||
|
||||
class Rat:
|
||||
"""Not so scary.
|
||||
"""
|
||||
character = "R"
|
||||
hp = 2
|
||||
maxHp = 2
|
||||
hp = maxHp
|
||||
deadly = True
|
||||
speed = 15
|
||||
|
||||
|
@ -48,10 +55,14 @@ class Rat:
|
|||
|
||||
if self.hp <= 0:
|
||||
game.remove_agent(self)
|
||||
game.get_agent_by_name("player").xp += self.maxHp
|
||||
|
||||
class Spider:
|
||||
"""Creepy-crawly.
|
||||
"""
|
||||
character = "S"
|
||||
hp = 5
|
||||
maxHp = 5
|
||||
hp = maxHp
|
||||
deadly = True
|
||||
speed = 5
|
||||
|
||||
|
@ -70,4 +81,5 @@ class Spider:
|
|||
game.end()
|
||||
|
||||
if self.hp <= 0:
|
||||
game.remove_agent(self)
|
||||
game.remove_agent(self)
|
||||
game.get_agent_by_name("player").xp += self.maxHp
|
11
map.py
11
map.py
|
@ -5,6 +5,9 @@ from wall import Wall
|
|||
from random import randint
|
||||
|
||||
def board_edges(board_size):
|
||||
"""The outline of the generated board. Used in angband to surround
|
||||
the level with immovable objects to keep the enemies and player inside
|
||||
"""
|
||||
x,y = board_size
|
||||
positions = []
|
||||
top = [(i,0) for i in range(x)]
|
||||
|
@ -20,7 +23,7 @@ def inner_board(board_size):
|
|||
for j in range(1,y-1):
|
||||
positions.append((i,j))
|
||||
return positions
|
||||
|
||||
|
||||
def random_empty_position(game):
|
||||
"""Returns a random empty position.
|
||||
"""
|
||||
|
@ -43,6 +46,12 @@ def level_one(board_size):
|
|||
for j in range((y - (y // 4)), y-1):
|
||||
positions.append((i,j))
|
||||
|
||||
# Introduce randomness within predefined pattern
|
||||
for _ in range(10): # Example: Add 10 random obstacles
|
||||
rand_i = randint(1, x - 2)
|
||||
rand_j = randint(1, y - 2)
|
||||
positions.append((rand_i, rand_j))
|
||||
|
||||
# for i in range(1,x-1):
|
||||
# for j in range(1,y-1):
|
||||
# if i >=4 and i <= 7 or i >= 13 and i <= 16:
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
# asteroid_spawner.py
|
||||
# -------------------
|
||||
# By MWC Contributors
|
||||
# This module defines an AsteroidSpawner agent class.
|
||||
|
||||
from random import (
|
||||
randint,
|
||||
choices,
|
||||
)
|
||||
from enemies import *
|
||||
from map import random_empty_position
|
||||
|
||||
class MonsterSpawner:
|
||||
display = False
|
||||
floor = 0
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def play_turn(self, game):
|
||||
"""Places each of the monsters on the board for that level.
|
||||
"""
|
||||
toSpawn = self.should_spawn_monsters(game.state["Floor"])
|
||||
|
||||
for i in range(toSpawn):
|
||||
monster = self.choose_monster()(random_empty_position(game))
|
||||
game.add_agent(monster)
|
||||
|
||||
|
||||
def should_spawn_monsters(self, floor_number):
|
||||
"""Returns the number of monsters to spawn, given the player
|
||||
advanced a floor.
|
||||
"""
|
||||
numMonsters = 0
|
||||
if floor_number != self.floor:
|
||||
numMonsters = randint(1, floor_number // 10 + 3)
|
||||
self.floor = floor_number
|
||||
return numMonsters
|
||||
|
||||
def choose_monster(self):
|
||||
"""Picks a random monster out of a weighted list of monsters.
|
||||
"""
|
||||
monsters = [Orc, Rat, Spider]
|
||||
monster = choices(monsters, weights = (10, 30, 60))
|
||||
monster = monster[0]
|
||||
return monster
|
39
player.py
39
player.py
|
@ -19,7 +19,8 @@ class Player:
|
|||
damage = 0
|
||||
|
||||
def __init__(self, position, race, class_):
|
||||
"""Class and race will determine player stats and abilities."""
|
||||
"""Class and race will determine player stats and abilities.
|
||||
"""
|
||||
self.position = position
|
||||
self.race = race
|
||||
self.class_ = class_
|
||||
|
@ -47,16 +48,18 @@ class Player:
|
|||
self.damage = int(3 + (self.level / 2))
|
||||
|
||||
def attack(self,game):
|
||||
if self.class_ == "Warrior":
|
||||
if game.turn_number % self.speed == 0:
|
||||
agent = self.get_agent_in_position((self.position[0] + self.direction[0],self.position[1] + self.direction[1]),game)
|
||||
if agent:
|
||||
if agent.deadly:
|
||||
agent.hp -= game.get_agent_by_name("player").damage * 2
|
||||
else:
|
||||
projectile = Projectile((self.position[0] + self.direction[0],self.position[1] + self.direction[1]), self.direction, self.speed, game)
|
||||
game.add_agent(projectile)
|
||||
#print("pew pew pew")
|
||||
"""Warrior is a melee character, mage and rogue use ranged attacks.
|
||||
"""
|
||||
# if self.class_ == "Warrior":
|
||||
# if game.turn_number % self.speed == 0:
|
||||
# agent = self.get_agent_in_position((self.position[0] + self.direction[0],self.position[1] + self.direction[1]),game)
|
||||
# if agent:
|
||||
# if agent.deadly:
|
||||
# agent.hp -= game.get_agent_by_name("player").damage * 2
|
||||
# else:
|
||||
projectile = Projectile((self.position[0] + self.direction[0],self.position[1] + self.direction[1]), self.direction, self.speed, game)
|
||||
game.add_agent(projectile)
|
||||
#print("pew pew pew")
|
||||
|
||||
def handle_keystroke(self, keystroke, game):
|
||||
x, y = self.position
|
||||
|
@ -88,6 +91,8 @@ class Player:
|
|||
self.attack(game)
|
||||
|
||||
def try_to_move(self, position, game):
|
||||
"""Check if player moved into an enemy and loses.
|
||||
"""
|
||||
agent = self.get_agent_in_position(position,game)
|
||||
if agent:
|
||||
if agent.deadly:
|
||||
|
@ -96,16 +101,20 @@ class Player:
|
|||
|
||||
|
||||
def get_agent_in_position(self, position, game):
|
||||
|
||||
"""Checks a location for current agents.
|
||||
"""
|
||||
agents = game.get_agents_by_position()[position]
|
||||
if agents:
|
||||
return agents[0]
|
||||
|
||||
def level_up(self):
|
||||
xpToLevel = (self.level + self.level - 1) * 30
|
||||
"""Player levelup is managed by an xp curve.
|
||||
"""
|
||||
xpToLevel = (self.level + self.level - 1) * 20
|
||||
if self.xp >= xpToLevel:
|
||||
self.xp -= xpToLevel
|
||||
self.level += 1
|
||||
|
||||
|
||||
def play_turn(self,game):
|
||||
self.level_up()
|
||||
self.level_up()
|
||||
game.state["Level"] = self.level
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
# projectile.py
|
||||
# ------------
|
||||
# By Pat Wick
|
||||
# This module defines a "casted" projectile. This is the basis
|
||||
# for ranged character types' attacks.
|
||||
|
||||
from retro.game import Game
|
||||
|
||||
class Projectile:
|
||||
|
@ -13,10 +19,18 @@ class Projectile:
|
|||
self.character = "-"
|
||||
elif self.direction in [(0,1), (0,-1)]:
|
||||
self.character = "|"
|
||||
if game.get_agent_by_name("player").class_ == "Warrior":
|
||||
if self.direction in [(0,1), (0,-1)]:
|
||||
self.character = "|"
|
||||
elif self.direction == (1,0):
|
||||
self.character = "/"
|
||||
else:
|
||||
self.character = "\\"
|
||||
|
||||
def move(self, game):
|
||||
"""Try to move in direction set by player when launched. If blocked,
|
||||
disappear."""
|
||||
disappear. If projectile hits an enemy, lower hp by damage.
|
||||
"""
|
||||
dx, dy = self.direction
|
||||
new_position = (self.position[0] + dx, self.position[1] + dy)
|
||||
if game.on_board(new_position):
|
||||
|
@ -34,8 +48,16 @@ class Projectile:
|
|||
game.remove_agent(self)
|
||||
|
||||
def play_turn(self,game):
|
||||
"""Speed of projectiles depends on character race.
|
||||
"""
|
||||
if game.turn_number % self.speed == 0:
|
||||
self.move(game)
|
||||
try:
|
||||
if game.get_agent_by_name("player").class_ == "Warrior":
|
||||
game.remove_agent(self)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def get_agent_in_position(self, position, game):
|
||||
"""Returns an agent at the position, or returns None.
|
||||
|
|
Loading…
Reference in New Issue