Added documentation on a lot of classes and functions (and removed some files I commited by mistake)

This commit is contained in:
eichhornchen 2020-11-18 12:19:27 +01:00 committed by Yohann D'ANELLO
parent 41d1696c9b
commit 8f932604f6
5 changed files with 126 additions and 33 deletions

View File

@ -4,6 +4,11 @@ from dungeonbattle.term_manager import TermManager
class Bootstrap: class Bootstrap:
"""
The bootstrap object is used to bootstrap the game so that it starts properly.
(It was initially created to avoid circulary imports between the Game and
Display classes)
"""
@staticmethod @staticmethod
def run_game(): def run_game():

View File

@ -3,13 +3,22 @@ from typing import Optional
from dungeonbattle.settings import Settings from dungeonbattle.settings import Settings
#This file contains a few useful enumeration classes used elsewhere in the code
class DisplayActions(Enum): class DisplayActions(Enum):
"""
Display actions options for the callable displayaction Game uses
(it just calls the same action on the display object displayaction refers to)
"""
REFRESH = auto() REFRESH = auto()
UPDATE = auto() UPDATE = auto()
class GameMode(Enum): class GameMode(Enum):
"""
Game mode options
"""
MAINMENU = auto() MAINMENU = auto()
PLAY = auto() PLAY = auto()
SETTINGS = auto() SETTINGS = auto()
@ -17,6 +26,9 @@ class GameMode(Enum):
class KeyValues(Enum): class KeyValues(Enum):
"""
Key values options used in the game
"""
UP = auto() UP = auto()
DOWN = auto() DOWN = auto()
LEFT = auto() LEFT = auto()

View File

@ -12,6 +12,9 @@ from typing import Callable
class Game: class Game:
"""
The game object controls all actions in the game.
"""
map: Map map: Map
player: Player player: Player
# display_actions is a display interface set by the bootstrapper # display_actions is a display interface set by the bootstrapper
@ -43,8 +46,8 @@ class Game:
def run(self, screen: Any) -> None: def run(self, screen: Any) -> None:
""" """
Main infinite loop. Main infinite loop.
We wait for a player action, then we do what that should be done We wait for the player's action, then we do what that should be done
when the given key got pressed. when the given key gets pressed.
""" """
while True: # pragma no cover while True: # pragma no cover
screen.clear() screen.clear()
@ -70,7 +73,7 @@ class Game:
def handle_key_pressed_play(self, key: KeyValues) -> None: def handle_key_pressed_play(self, key: KeyValues) -> None:
""" """
In play mode, arrows or zqsd should move the main character. In play mode, arrows or zqsd move the main character.
""" """
if key == KeyValues.UP: if key == KeyValues.UP:
if self.player.move_up(): if self.player.move_up():
@ -108,15 +111,16 @@ class Game:
elif option == menus.MainMenuValues.EXIT: elif option == menus.MainMenuValues.EXIT:
sys.exit(0) sys.exit(0)
def game_to_str(self) -> str:
d = dict()
d["Map"] = game.map
d["Player"] = game.player
def save_state(self) -> dict(): def save_state(self) -> dict():
"""
Saves the game to a dictionnary
"""
return self.map.save_state() return self.map.save_state()
def load_state(self, d: dict) -> None: def load_state(self, d: dict) -> None:
"""
Loads the game from a dictionnary
"""
self.map.load_state(d) self.map.load_state(d)
def load_game(self) -> None: def load_game(self) -> None:
@ -129,7 +133,7 @@ class Game:
def save_game(self) -> None: def save_game(self) -> None:
""" """
Save the game to a file Saves the game to a file
""" """
with open("save.json", "w") as f: with open("save.json", "w") as f:
f.write(json.dumps(self.save_state())) f.write(json.dumps(self.save_state()))

View File

@ -10,7 +10,7 @@ from dungeonbattle.display.texturepack import TexturePack
class Map: class Map:
""" """
Object that represents a Map with its width, height Object that represents a Map with its width, height
and the whole tiles, with their custom properties. and tiles, that have their custom properties.
""" """
width: int width: int
height: int height: int
@ -120,6 +120,9 @@ class Map:
entity.act(self) entity.act(self)
def save_state(self) -> dict: def save_state(self) -> dict:
"""
Saves the map's attributes to a dictionnary
"""
d = dict() d = dict()
d["width"] = self.width d["width"] = self.width
d["height"] = self.height d["height"] = self.height
@ -133,6 +136,9 @@ class Map:
return d return d
def load_state(self, d: dict) -> None: def load_state(self, d: dict) -> None:
"""
Loads the map's attributes from a dictionnary
"""
self.width = d["width"] self.width = d["width"]
self.height = d["height"] self.height = d["height"]
self.start_y = d["start_y"] self.start_y = d["start_y"]
@ -143,6 +149,9 @@ class Map:
#add entities #add entities
class Tile(Enum): class Tile(Enum):
"""
The internal representation of the tiles of the map
"""
EMPTY = auto() EMPTY = auto()
WALL = auto() WALL = auto()
FLOOR = auto() FLOOR = auto()
@ -158,9 +167,15 @@ class Tile(Enum):
raise ValueError(ch) raise ValueError(ch)
def char(self, pack: TexturePack) -> str: def char(self, pack: TexturePack) -> str:
"""
Translates a Tile to the corresponding character according to the texture pack
"""
return getattr(pack, self.name) return getattr(pack, self.name)
def is_wall(self) -> bool: def is_wall(self) -> bool:
"""
Is this Tile a wall?
"""
return self == Tile.WALL return self == Tile.WALL
def can_walk(self) -> bool: def can_walk(self) -> bool:
@ -171,10 +186,13 @@ class Tile(Enum):
class Entity: class Entity:
"""
An Entity object represents any entity present on the map
"""
y: int y: int
x: int x: int
name: str name: str
map: Map map: Map
def __init__(self): def __init__(self):
self.y = 0 self.y = 0
@ -182,29 +200,47 @@ class Entity:
def check_move(self, y: int, x: int, move_if_possible: bool = False)\ def check_move(self, y: int, x: int, move_if_possible: bool = False)\
-> bool: -> bool:
"""
Checks if moving to (y,x) is authorized
"""
free = self.map.is_free(y, x) free = self.map.is_free(y, x)
if free and move_if_possible: if free and move_if_possible:
self.move(y, x) self.move(y, x)
return free return free
def move(self, y: int, x: int) -> bool: def move(self, y: int, x: int) -> bool:
"""
Moves an entity to (y,x) coordinates
"""
self.y = y self.y = y
self.x = x self.x = x
return True return True
def move_up(self, force: bool = False) -> bool: def move_up(self, force: bool = False) -> bool:
"""
Moves the entity up one tile, if possible
"""
return self.move(self.y - 1, self.x) if force else \ return self.move(self.y - 1, self.x) if force else \
self.check_move(self.y - 1, self.x, True) self.check_move(self.y - 1, self.x, True)
def move_down(self, force: bool = False) -> bool: def move_down(self, force: bool = False) -> bool:
"""
Moves the entity down one tile, if possible
"""
return self.move(self.y + 1, self.x) if force else \ return self.move(self.y + 1, self.x) if force else \
self.check_move(self.y + 1, self.x, True) self.check_move(self.y + 1, self.x, True)
def move_left(self, force: bool = False) -> bool: def move_left(self, force: bool = False) -> bool:
"""
Moves the entity left one tile, if possible
"""
return self.move(self.y, self.x - 1) if force else \ return self.move(self.y, self.x - 1) if force else \
self.check_move(self.y, self.x - 1, True) self.check_move(self.y, self.x - 1, True)
def move_right(self, force: bool = False) -> bool: def move_right(self, force: bool = False) -> bool:
"""
Moves the entity right one tile, if possible
"""
return self.move(self.y, self.x + 1) if force else \ return self.move(self.y, self.x + 1) if force else \
self.check_move(self.y, self.x + 1, True) self.check_move(self.y, self.x + 1, True)
@ -229,14 +265,23 @@ class Entity:
return sqrt(self.distance_squared(other)) return sqrt(self.distance_squared(other))
def is_fighting_entity(self) -> bool: def is_fighting_entity(self) -> bool:
"""
Is this entity a fighting entity?
"""
return isinstance(self, FightingEntity) return isinstance(self, FightingEntity)
def is_item(self) -> bool: def is_item(self) -> bool:
"""
Is this entity an item?
"""
from dungeonbattle.entities.items import Item from dungeonbattle.entities.items import Item
return isinstance(self, Item) return isinstance(self, Item)
@staticmethod @staticmethod
def get_all_entity_classes(): def get_all_entity_classes():
"""
Returns all entities subclasses
"""
from dungeonbattle.entities.items import Heart, Bomb from dungeonbattle.entities.items import Heart, Bomb
from dungeonbattle.entities.monsters import Beaver, Hedgehog, \ from dungeonbattle.entities.monsters import Beaver, Hedgehog, \
Rabbit, TeddyBear Rabbit, TeddyBear
@ -260,6 +305,10 @@ class Entity:
class FightingEntity(Entity): class FightingEntity(Entity):
"""
A FightingEntity is an entity that can fight, and thus has a health,
level and stats
"""
maxhealth: int maxhealth: int
health: int health: int
strength: int strength: int
@ -285,27 +334,45 @@ class FightingEntity(Entity):
def hit(self, opponent: "FightingEntity") -> None: def hit(self, opponent: "FightingEntity") -> None:
"""
Deals damage to the opponent, based on the stats
"""
opponent.take_damage(self, self.strength) opponent.take_damage(self, self.strength)
def take_damage(self, attacker: "Entity", amount: int) -> None: def take_damage(self, attacker: "Entity", amount: int) -> None:
"""
Take damage from the attacker, based on the stats
"""
self.health -= amount self.health -= amount
if self.health <= 0: if self.health <= 0:
self.die() self.die()
def die(self) -> None: def die(self) -> None:
"""
If a fighting entity has no more health, it dies and is removed
"""
self.dead = True self.dead = True
self.map.remove_entity(self) self.map.remove_entity(self)
def keys(self) -> list: def keys(self) -> list:
"""
Returns a fighting entities specific attributes
"""
return ["maxhealth", "health", "level", "dead", "strength", "intelligence", "charisma", "dexterity", "constitution"] return ["maxhealth", "health", "level", "dead", "strength", "intelligence", "charisma", "dexterity", "constitution"]
def save_state(self) -> dict: def save_state(self) -> dict:
"""
Saves the state of the entity into a dictionnary
"""
d = super().save_state() d = super().save_state()
for name in self.keys(): for name in self.keys():
d[name] = self.__getattribute__(name) d[name] = self.__getattribute__(name)
return d return d
def recover_state(self, d : dict) -> None: def recover_state(self, d : dict) -> None:
"""
Loads the state of an entity from a dictionnary
"""
super().recover_state(d) super().recover_state(d)
for name in d.keys(): for name in d.keys():
self.__setattribute__(name, d[name]) self.__setattribute__(name, d[name])

View File

@ -8,24 +8,41 @@ from .settings import Settings
class Menu: class Menu:
"""
A Menu object is the logical representation of a menu in the game
"""
values: list values: list
def __init__(self): def __init__(self):
self.position = 0 self.position = 0
def go_up(self) -> None: def go_up(self) -> None:
"""
Moves the pointer of the menu on the previous value
"""
self.position = max(0, self.position - 1) self.position = max(0, self.position - 1)
def go_down(self) -> None: def go_down(self) -> None:
"""
Moves the pointer of the menu on the next value
"""
self.position = min(len(self.values) - 1, self.position + 1) self.position = min(len(self.values) - 1, self.position + 1)
def validate(self) -> Any: def validate(self) -> Any:
"""
Selects the value that is pointed by the menu pointer
"""
return self.values[self.position] return self.values[self.position]
class MainMenuValues(Enum): class MainMenuValues(Enum):
"""
Values of the main menu
"""
START = 'Nouvelle partie' START = 'Nouvelle partie'
RESUME = 'Continuer' RESUME = 'Continuer'
SAVE = 'Sauvegarder'
LOAD = 'Charger'
SETTINGS = 'Paramètres' SETTINGS = 'Paramètres'
EXIT = 'Quitter' EXIT = 'Quitter'
@ -34,34 +51,22 @@ class MainMenuValues(Enum):
class MainMenu(Menu): class MainMenu(Menu):
"""
A special instance of a menu : the main menu
"""
values = [e for e in MainMenuValues] values = [e for e in MainMenuValues]
def handle_key_pressed(self, key: KeyValues, game: Any) -> None:
"""
In the main menu, we can navigate through options.
"""
if key == KeyValues.DOWN:
self.go_down()
if key == KeyValues.UP:
self.go_up()
if key == KeyValues.ENTER:
option = self.validate()
if option == MainMenuValues.START:
game.new_game()
game.state = GameMode.PLAY
game.display_actions(DisplayActions.UPDATE)
elif option == MainMenuValues.RESUME:
game.state = GameMode.PLAY
elif option == MainMenuValues.SETTINGS:
game.state = GameMode.SETTINGS
elif option == MainMenuValues.EXIT:
sys.exit(0)
class SettingsMenu(Menu): class SettingsMenu(Menu):
"""
A special instance of a menu : the settings menu
"""
waiting_for_key: bool = False waiting_for_key: bool = False
def update_values(self, settings: Settings) -> None: def update_values(self, settings: Settings) -> None:
"""
The settings can change, so they are updated
"""
self.values = [] self.values = []
for i, key in enumerate(settings.settings_keys): for i, key in enumerate(settings.settings_keys):
s = settings.get_comment(key) s = settings.get_comment(key)
@ -81,7 +86,7 @@ class SettingsMenu(Menu):
def handle_key_pressed(self, key: Optional[KeyValues], raw_key: str, def handle_key_pressed(self, key: Optional[KeyValues], raw_key: str,
game: Any) -> None: game: Any) -> None:
""" """
Update settings In the setting menu, we van select a setting and change it
""" """
if not self.waiting_for_key: if not self.waiting_for_key:
# Navigate normally through the menu. # Navigate normally through the menu.