diff --git a/__pycache__/enemies.cpython-310.pyc b/__pycache__/enemies.cpython-310.pyc index 268a583..e98aad4 100644 Binary files a/__pycache__/enemies.cpython-310.pyc and b/__pycache__/enemies.cpython-310.pyc differ diff --git a/__pycache__/map.cpython-310.pyc b/__pycache__/map.cpython-310.pyc index 0f1d390..3e9fd19 100644 Binary files a/__pycache__/map.cpython-310.pyc and b/__pycache__/map.cpython-310.pyc differ diff --git a/__pycache__/monster_spawner.cpython-310.pyc b/__pycache__/monster_spawner.cpython-310.pyc new file mode 100644 index 0000000..7e29072 Binary files /dev/null and b/__pycache__/monster_spawner.cpython-310.pyc differ diff --git a/__pycache__/player.cpython-310.pyc b/__pycache__/player.cpython-310.pyc index 85cbfa9..2260ae8 100644 Binary files a/__pycache__/player.cpython-310.pyc and b/__pycache__/player.cpython-310.pyc differ diff --git a/__pycache__/projectile.cpython-310.pyc b/__pycache__/projectile.cpython-310.pyc index 01968ae..5d5d94a 100644 Binary files a/__pycache__/projectile.cpython-310.pyc and b/__pycache__/projectile.cpython-310.pyc differ diff --git a/angband.py b/angband.py index 4a15517..1ca13a1 100644 --- a/angband.py +++ b/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() \ No newline at end of file diff --git a/enemies.py b/enemies.py index a6dd311..629591f 100644 --- a/enemies.py +++ b/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) \ No newline at end of file + game.remove_agent(self) + game.get_agent_by_name("player").xp += self.maxHp \ No newline at end of file diff --git a/map.py b/map.py index 89597ad..842a8ea 100644 --- a/map.py +++ b/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: diff --git a/monster_spawner.py b/monster_spawner.py new file mode 100644 index 0000000..f164574 --- /dev/null +++ b/monster_spawner.py @@ -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 \ No newline at end of file diff --git a/player.py b/player.py index d6bfcc5..58949c8 100644 --- a/player.py +++ b/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() \ No newline at end of file + self.level_up() + game.state["Level"] = self.level diff --git a/projectile.py b/projectile.py index 2c7c749..633bf6e 100644 --- a/projectile.py +++ b/projectile.py @@ -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.