Fixed grammar, unified the docstring's format and added documentation to some classes that did not have any. Closes #32.
This commit is contained in:
parent
3f62fbaa2b
commit
646e0063be
|
@ -24,9 +24,16 @@ class Display:
|
||||||
self.pack = pack or TexturePack.get_pack("ascii")
|
self.pack = pack or TexturePack.get_pack("ascii")
|
||||||
|
|
||||||
def newpad(self, height: int, width: int) -> Union[FakePad, Any]:
|
def newpad(self, height: int, width: int) -> Union[FakePad, Any]:
|
||||||
|
"""
|
||||||
|
Overwrites the native curses function of the same name.
|
||||||
|
"""
|
||||||
return curses.newpad(height, width) if self.screen else FakePad()
|
return curses.newpad(height, width) if self.screen else FakePad()
|
||||||
|
|
||||||
def truncate(self, msg: str, height: int, width: int) -> str:
|
def truncate(self, msg: str, height: int, width: int) -> str:
|
||||||
|
"""
|
||||||
|
Truncates a string into a string adapted to the width and height of
|
||||||
|
the screen.
|
||||||
|
"""
|
||||||
height = max(0, height)
|
height = max(0, height)
|
||||||
width = max(0, width)
|
width = max(0, width)
|
||||||
lines = msg.split("\n")
|
lines = msg.split("\n")
|
||||||
|
@ -36,8 +43,8 @@ class Display:
|
||||||
|
|
||||||
def translate_color(self, color: Union[int, Tuple[int, int, int]]) -> int:
|
def translate_color(self, color: Union[int, Tuple[int, int, int]]) -> int:
|
||||||
"""
|
"""
|
||||||
Translate a tuple (R, G, B) into a curses color index.
|
Translates a tuple (R, G, B) into a curses color index.
|
||||||
If we have already a color index, then nothing is processed.
|
If we already have a color index, then nothing is processed.
|
||||||
If this is a tuple, we construct a new color index if non-existing
|
If this is a tuple, we construct a new color index if non-existing
|
||||||
and we return this index.
|
and we return this index.
|
||||||
The values of R, G and B must be between 0 and 1000, and not
|
The values of R, G and B must be between 0 and 1000, and not
|
||||||
|
@ -66,9 +73,9 @@ class Display:
|
||||||
low: bool = False, right: bool = False, top: bool = False,
|
low: bool = False, right: bool = False, top: bool = False,
|
||||||
vertical: bool = False, chartext: bool = False) -> None:
|
vertical: bool = False, chartext: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Display a message onto the pad.
|
Displays a message onto the pad.
|
||||||
If the message is too large, it is truncated vertically and horizontally
|
If the message is too large, it is truncated vertically and horizontally
|
||||||
The text can be bold, italic, blinking, ... if the good parameters are
|
The text can be bold, italic, blinking, ... if the right parameters are
|
||||||
given. These parameters are translated into curses attributes.
|
given. These parameters are translated into curses attributes.
|
||||||
The foreground and background colors can be given as curses constants
|
The foreground and background colors can be given as curses constants
|
||||||
(curses.COLOR_*), or by giving a tuple (R, G, B) that corresponds to
|
(curses.COLOR_*), or by giving a tuple (R, G, B) that corresponds to
|
||||||
|
@ -126,6 +133,9 @@ class Display:
|
||||||
|
|
||||||
def resize(self, y: int, x: int, height: int, width: int,
|
def resize(self, y: int, x: int, height: int, width: int,
|
||||||
resize_pad: bool = True) -> None:
|
resize_pad: bool = True) -> None:
|
||||||
|
"""
|
||||||
|
Resizes a pad.
|
||||||
|
"""
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
self.width = width
|
self.width = width
|
||||||
|
@ -136,6 +146,9 @@ class Display:
|
||||||
self.pad.resize(self.height + 1, self.width + 1)
|
self.pad.resize(self.height + 1, self.width + 1)
|
||||||
|
|
||||||
def refresh(self, *args, resize_pad: bool = True) -> None:
|
def refresh(self, *args, resize_pad: bool = True) -> None:
|
||||||
|
"""
|
||||||
|
Refreshes a pad
|
||||||
|
"""
|
||||||
if len(args) == 4:
|
if len(args) == 4:
|
||||||
self.resize(*args, resize_pad)
|
self.resize(*args, resize_pad)
|
||||||
self.display()
|
self.display()
|
||||||
|
@ -144,10 +157,10 @@ class Display:
|
||||||
window_y: int, window_x: int,
|
window_y: int, window_x: int,
|
||||||
last_y: int, last_x: int) -> None:
|
last_y: int, last_x: int) -> None:
|
||||||
"""
|
"""
|
||||||
Refresh a pad on a part of the window.
|
Refreshes a pad on a part of the window.
|
||||||
The refresh starts at coordinates (top_y, top_x) from the pad,
|
The refresh starts at coordinates (top_y, top_x) from the pad,
|
||||||
and is drawn from (window_y, window_x) to (last_y, last_x).
|
and is drawn from (window_y, window_x) to (last_y, last_x).
|
||||||
If coordinates are invalid (negative indexes/length..., then nothing
|
If coordinates are invalid (negative indexes/length...), then nothing
|
||||||
is drawn and no error is raised.
|
is drawn and no error is raised.
|
||||||
"""
|
"""
|
||||||
top_y, top_x = max(0, top_y), max(0, top_x)
|
top_y, top_x = max(0, top_y), max(0, top_x)
|
||||||
|
@ -167,7 +180,7 @@ class Display:
|
||||||
def handle_click(self, y: int, x: int, game: Game) -> None:
|
def handle_click(self, y: int, x: int, game: Game) -> None:
|
||||||
"""
|
"""
|
||||||
A mouse click was performed on the coordinates (y, x) of the pad.
|
A mouse click was performed on the coordinates (y, x) of the pad.
|
||||||
Maybe it can do something.
|
Maybe it should do something.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -181,7 +194,9 @@ class Display:
|
||||||
|
|
||||||
|
|
||||||
class VerticalSplit(Display):
|
class VerticalSplit(Display):
|
||||||
|
"""
|
||||||
|
A class to split the screen in two vertically with a pretty line.
|
||||||
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.pad = self.newpad(self.rows, 1)
|
self.pad = self.newpad(self.rows, 1)
|
||||||
|
@ -202,7 +217,9 @@ class VerticalSplit(Display):
|
||||||
|
|
||||||
|
|
||||||
class HorizontalSplit(Display):
|
class HorizontalSplit(Display):
|
||||||
|
"""
|
||||||
|
A class to split the screen in two horizontally with a pretty line.
|
||||||
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.pad = self.newpad(1, self.cols)
|
self.pad = self.newpad(1, self.cols)
|
||||||
|
@ -223,6 +240,9 @@ class HorizontalSplit(Display):
|
||||||
|
|
||||||
|
|
||||||
class Box(Display):
|
class Box(Display):
|
||||||
|
"""
|
||||||
|
A class for pretty boxes to print menus and other content.
|
||||||
|
"""
|
||||||
title: str = ""
|
title: str = ""
|
||||||
|
|
||||||
def update_title(self, title: str) -> None:
|
def update_title(self, title: str) -> None:
|
||||||
|
|
|
@ -41,6 +41,9 @@ class DisplayManager:
|
||||||
self.update_game_components()
|
self.update_game_components()
|
||||||
|
|
||||||
def handle_display_action(self, action: DisplayActions, *params) -> None:
|
def handle_display_action(self, action: DisplayActions, *params) -> None:
|
||||||
|
"""
|
||||||
|
Handles the differents values of display action.
|
||||||
|
"""
|
||||||
if action == DisplayActions.REFRESH:
|
if action == DisplayActions.REFRESH:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
elif action == DisplayActions.UPDATE:
|
elif action == DisplayActions.UPDATE:
|
||||||
|
@ -49,6 +52,9 @@ class DisplayManager:
|
||||||
self.handle_mouse_click(*params)
|
self.handle_mouse_click(*params)
|
||||||
|
|
||||||
def update_game_components(self) -> None:
|
def update_game_components(self) -> None:
|
||||||
|
"""
|
||||||
|
Updates the game components, for example when loading a game.
|
||||||
|
"""
|
||||||
for d in self.displays:
|
for d in self.displays:
|
||||||
d.pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
|
d.pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
|
||||||
self.mapdisplay.update_map(self.game.map)
|
self.mapdisplay.update_map(self.game.map)
|
||||||
|
@ -62,6 +68,9 @@ class DisplayManager:
|
||||||
self.messagedisplay.update_message(self.game.message)
|
self.messagedisplay.update_message(self.game.message)
|
||||||
|
|
||||||
def handle_mouse_click(self, y: int, x: int) -> None:
|
def handle_mouse_click(self, y: int, x: int) -> None:
|
||||||
|
"""
|
||||||
|
Handles the mouse clicks.
|
||||||
|
"""
|
||||||
displays = self.refresh()
|
displays = self.refresh()
|
||||||
display = None
|
display = None
|
||||||
for d in displays:
|
for d in displays:
|
||||||
|
@ -74,6 +83,9 @@ class DisplayManager:
|
||||||
display.handle_click(y - display.y, x - display.x, self.game)
|
display.handle_click(y - display.y, x - display.x, self.game)
|
||||||
|
|
||||||
def refresh(self) -> List[Display]:
|
def refresh(self) -> List[Display]:
|
||||||
|
"""
|
||||||
|
Refreshes all components on the screen.
|
||||||
|
"""
|
||||||
displays = []
|
displays = []
|
||||||
|
|
||||||
if self.game.state == GameMode.PLAY \
|
if self.game.state == GameMode.PLAY \
|
||||||
|
@ -127,7 +139,7 @@ class DisplayManager:
|
||||||
|
|
||||||
def resize_window(self) -> bool:
|
def resize_window(self) -> bool:
|
||||||
"""
|
"""
|
||||||
If the window got resized, ensure that the screen size got updated.
|
When the window is resized, ensures that the screen size is updated.
|
||||||
"""
|
"""
|
||||||
y, x = self.screen.getmaxyx() if self.screen else (0, 0)
|
y, x = self.screen.getmaxyx() if self.screen else (0, 0)
|
||||||
if self.screen and curses.is_term_resized(self.rows,
|
if self.screen and curses.is_term_resized(self.rows,
|
||||||
|
@ -138,8 +150,16 @@ class DisplayManager:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rows(self) -> int:
|
def rows(self) -> int:
|
||||||
|
"""
|
||||||
|
Overwrites the native curses attribute of the same name,
|
||||||
|
for testing purposes.
|
||||||
|
"""
|
||||||
return curses.LINES if self.screen else 42
|
return curses.LINES if self.screen else 42
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cols(self) -> int:
|
def cols(self) -> int:
|
||||||
|
"""
|
||||||
|
Overwrites the native curses attribute of the same name,
|
||||||
|
for testing purposes.
|
||||||
|
"""
|
||||||
return curses.COLS if self.screen else 42
|
return curses.COLS if self.screen else 42
|
||||||
|
|
|
@ -6,7 +6,9 @@ from squirrelbattle.interfaces import Logs
|
||||||
|
|
||||||
|
|
||||||
class LogsDisplay(Display):
|
class LogsDisplay(Display):
|
||||||
|
"""
|
||||||
|
A class to handle the display of the logs.
|
||||||
|
"""
|
||||||
def __init__(self, *args) -> None:
|
def __init__(self, *args) -> None:
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
self.pad = self.newpad(self.rows, self.cols)
|
self.pad = self.newpad(self.rows, self.cols)
|
||||||
|
|
|
@ -6,7 +6,9 @@ from .display import Display
|
||||||
|
|
||||||
|
|
||||||
class MapDisplay(Display):
|
class MapDisplay(Display):
|
||||||
|
"""
|
||||||
|
A class to handle the display of the map.
|
||||||
|
"""
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ from ..translations import gettext as _
|
||||||
|
|
||||||
class MenuDisplay(Display):
|
class MenuDisplay(Display):
|
||||||
"""
|
"""
|
||||||
A class to display the menu objects
|
A class to display the menu objects.
|
||||||
"""
|
"""
|
||||||
position: int
|
position: int
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ class MenuDisplay(Display):
|
||||||
|
|
||||||
class SettingsMenuDisplay(MenuDisplay):
|
class SettingsMenuDisplay(MenuDisplay):
|
||||||
"""
|
"""
|
||||||
A class to display specifically a settingsmenu object
|
A class to display specifically a settingsmenu object.
|
||||||
"""
|
"""
|
||||||
@property
|
@property
|
||||||
def values(self) -> List[str]:
|
def values(self) -> List[str]:
|
||||||
|
@ -91,7 +91,7 @@ class SettingsMenuDisplay(MenuDisplay):
|
||||||
|
|
||||||
class MainMenuDisplay(Display):
|
class MainMenuDisplay(Display):
|
||||||
"""
|
"""
|
||||||
A class to display specifically a mainmenu object
|
A class to display specifically a mainmenu object.
|
||||||
"""
|
"""
|
||||||
def __init__(self, menu: MainMenu, *args):
|
def __init__(self, menu: MainMenu, *args):
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
|
@ -135,6 +135,9 @@ class MainMenuDisplay(Display):
|
||||||
|
|
||||||
|
|
||||||
class PlayerInventoryDisplay(MenuDisplay):
|
class PlayerInventoryDisplay(MenuDisplay):
|
||||||
|
"""
|
||||||
|
A class to handle the display of the player's inventory.
|
||||||
|
"""
|
||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
self.menubox.update_title(_("INVENTORY"))
|
self.menubox.update_title(_("INVENTORY"))
|
||||||
for i, item in enumerate(self.menu.values):
|
for i, item in enumerate(self.menu.values):
|
||||||
|
@ -160,6 +163,9 @@ class PlayerInventoryDisplay(MenuDisplay):
|
||||||
|
|
||||||
|
|
||||||
class StoreInventoryDisplay(MenuDisplay):
|
class StoreInventoryDisplay(MenuDisplay):
|
||||||
|
"""
|
||||||
|
A class to handle the display of a merchant's inventory.
|
||||||
|
"""
|
||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
self.menubox.update_title(_("STALL"))
|
self.menubox.update_title(_("STALL"))
|
||||||
for i, item in enumerate(self.menu.values):
|
for i, item in enumerate(self.menu.values):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from squirrelbattle.display.display import Box, Display
|
||||||
|
|
||||||
class MessageDisplay(Display):
|
class MessageDisplay(Display):
|
||||||
"""
|
"""
|
||||||
Display a message in a popup.
|
A class to handle the display of popup messages.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
@ -9,6 +9,9 @@ from .display import Display
|
||||||
|
|
||||||
|
|
||||||
class StatsDisplay(Display):
|
class StatsDisplay(Display):
|
||||||
|
"""
|
||||||
|
A class to handle the display of the stats of the player.
|
||||||
|
"""
|
||||||
player: Player
|
player: Player
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
@ -6,6 +6,9 @@ from typing import Any
|
||||||
|
|
||||||
|
|
||||||
class TexturePack:
|
class TexturePack:
|
||||||
|
"""
|
||||||
|
A class to handle displaying several textures.
|
||||||
|
"""
|
||||||
_packs = dict()
|
_packs = dict()
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
|
|
|
@ -7,7 +7,7 @@ from random import choice
|
||||||
|
|
||||||
class Merchant(InventoryHolder, FriendlyEntity):
|
class Merchant(InventoryHolder, FriendlyEntity):
|
||||||
"""
|
"""
|
||||||
The class for merchants in the dungeon
|
The class of merchants in the dungeon.
|
||||||
"""
|
"""
|
||||||
def keys(self) -> list:
|
def keys(self) -> list:
|
||||||
"""
|
"""
|
||||||
|
@ -28,13 +28,13 @@ class Merchant(InventoryHolder, FriendlyEntity):
|
||||||
def talk_to(self, player: Player) -> str:
|
def talk_to(self, player: Player) -> str:
|
||||||
"""
|
"""
|
||||||
This function is used to open the merchant's inventory in a menu,
|
This function is used to open the merchant's inventory in a menu,
|
||||||
and allow the player to buy/sell objects
|
and allows the player to buy/sell objects.
|
||||||
"""
|
"""
|
||||||
return _("I don't sell any squirrel")
|
return _("I don't sell any squirrel")
|
||||||
|
|
||||||
def change_hazel_balance(self, hz: int) -> None:
|
def change_hazel_balance(self, hz: int) -> None:
|
||||||
"""
|
"""
|
||||||
Change the number of hazel the merchant has by hz.
|
Changes the number of hazel the merchant has by hz.
|
||||||
"""
|
"""
|
||||||
self.hazel += hz
|
self.hazel += hz
|
||||||
|
|
||||||
|
@ -49,4 +49,7 @@ class Sunflower(FriendlyEntity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dialogue_option(self) -> list:
|
def dialogue_option(self) -> list:
|
||||||
|
"""
|
||||||
|
Lists all that a sunflower can say to the player.
|
||||||
|
"""
|
||||||
return [_("Flower power!!"), _("The sun is warm today")]
|
return [_("Flower power!!"), _("The sun is warm today")]
|
||||||
|
|
|
@ -11,7 +11,7 @@ from ..translations import gettext as _
|
||||||
|
|
||||||
class Item(Entity):
|
class Item(Entity):
|
||||||
"""
|
"""
|
||||||
A class for items
|
A class for items.
|
||||||
"""
|
"""
|
||||||
held: bool
|
held: bool
|
||||||
held_by: Optional[InventoryHolder]
|
held_by: Optional[InventoryHolder]
|
||||||
|
@ -27,7 +27,7 @@ class Item(Entity):
|
||||||
|
|
||||||
def drop(self) -> None:
|
def drop(self) -> None:
|
||||||
"""
|
"""
|
||||||
The item is dropped from the inventory onto the floor
|
The item is dropped from the inventory onto the floor.
|
||||||
"""
|
"""
|
||||||
if self.held:
|
if self.held:
|
||||||
self.held_by.inventory.remove(self)
|
self.held_by.inventory.remove(self)
|
||||||
|
@ -48,7 +48,7 @@ class Item(Entity):
|
||||||
|
|
||||||
def hold(self, player: InventoryHolder) -> None:
|
def hold(self, player: InventoryHolder) -> None:
|
||||||
"""
|
"""
|
||||||
The item is taken from the floor and put into the inventory
|
The item is taken from the floor and put into the inventory.
|
||||||
"""
|
"""
|
||||||
self.held = True
|
self.held = True
|
||||||
self.held_by = player
|
self.held_by = player
|
||||||
|
@ -57,7 +57,7 @@ class Item(Entity):
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Saves the state of the entity into a dictionary
|
Saves the state of the item into a dictionary.
|
||||||
"""
|
"""
|
||||||
d = super().save_state()
|
d = super().save_state()
|
||||||
d["held"] = self.held
|
d["held"] = self.held
|
||||||
|
@ -65,13 +65,16 @@ class Item(Entity):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_items() -> list:
|
def get_all_items() -> list:
|
||||||
|
"""
|
||||||
|
Returns the list of all item classes.
|
||||||
|
"""
|
||||||
return [BodySnatchPotion, Bomb, Heart, Sword]
|
return [BodySnatchPotion, Bomb, Heart, Sword]
|
||||||
|
|
||||||
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool:
|
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool:
|
||||||
"""
|
"""
|
||||||
Does all necessary actions when an object is to be sold.
|
Does all necessary actions when an object is to be sold.
|
||||||
Is overwritten by some classes that cannot exist in the player's
|
Is overwritten by some classes that cannot exist in the player's
|
||||||
inventory
|
inventory.
|
||||||
"""
|
"""
|
||||||
if buyer.hazel >= self.price:
|
if buyer.hazel >= self.price:
|
||||||
self.hold(buyer)
|
self.hold(buyer)
|
||||||
|
@ -85,7 +88,7 @@ class Item(Entity):
|
||||||
|
|
||||||
class Heart(Item):
|
class Heart(Item):
|
||||||
"""
|
"""
|
||||||
A heart item to return health to the player
|
A heart item to return health to the player.
|
||||||
"""
|
"""
|
||||||
healing: int
|
healing: int
|
||||||
|
|
||||||
|
@ -96,14 +99,15 @@ class Heart(Item):
|
||||||
|
|
||||||
def hold(self, entity: InventoryHolder) -> None:
|
def hold(self, entity: InventoryHolder) -> None:
|
||||||
"""
|
"""
|
||||||
When holding a heart, heal the player and don't put item in inventory.
|
When holding a heart, the player is healed and
|
||||||
|
the item is not put in the inventory.
|
||||||
"""
|
"""
|
||||||
entity.health = min(entity.maxhealth, entity.health + self.healing)
|
entity.health = min(entity.maxhealth, entity.health + self.healing)
|
||||||
entity.map.remove_entity(self)
|
entity.map.remove_entity(self)
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Saves the state of the header into a dictionary
|
Saves the state of the heart into a dictionary.
|
||||||
"""
|
"""
|
||||||
d = super().save_state()
|
d = super().save_state()
|
||||||
d["healing"] = self.healing
|
d["healing"] = self.healing
|
||||||
|
@ -129,7 +133,7 @@ class Bomb(Item):
|
||||||
|
|
||||||
def use(self) -> None:
|
def use(self) -> None:
|
||||||
"""
|
"""
|
||||||
When the bomb is used, throw it and explodes it.
|
When the bomb is used, it is thrown and then it explodes.
|
||||||
"""
|
"""
|
||||||
if self.held:
|
if self.held:
|
||||||
self.owner = self.held_by
|
self.owner = self.held_by
|
||||||
|
@ -138,7 +142,7 @@ class Bomb(Item):
|
||||||
|
|
||||||
def act(self, m: Map) -> None:
|
def act(self, m: Map) -> None:
|
||||||
"""
|
"""
|
||||||
Special exploding action of the bomb
|
Special exploding action of the bomb.
|
||||||
"""
|
"""
|
||||||
if self.exploding:
|
if self.exploding:
|
||||||
if self.tick > 0:
|
if self.tick > 0:
|
||||||
|
@ -164,7 +168,7 @@ class Bomb(Item):
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Saves the state of the bomb into a dictionary
|
Saves the state of the bomb into a dictionary.
|
||||||
"""
|
"""
|
||||||
d = super().save_state()
|
d = super().save_state()
|
||||||
d["exploding"] = self.exploding
|
d["exploding"] = self.exploding
|
||||||
|
@ -181,13 +185,13 @@ class Explosion(Item):
|
||||||
|
|
||||||
def act(self, m: Map) -> None:
|
def act(self, m: Map) -> None:
|
||||||
"""
|
"""
|
||||||
The explosion instant dies.
|
The bomb disappears after exploding.
|
||||||
"""
|
"""
|
||||||
m.remove_entity(self)
|
m.remove_entity(self)
|
||||||
|
|
||||||
def hold(self, player: InventoryHolder) -> None:
|
def hold(self, player: InventoryHolder) -> None:
|
||||||
"""
|
"""
|
||||||
The player can't hold any explosion.
|
The player can't hold an explosion.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ from ..interfaces import FightingEntity, Map
|
||||||
class Monster(FightingEntity):
|
class Monster(FightingEntity):
|
||||||
"""
|
"""
|
||||||
The class for all monsters in the dungeon.
|
The class for all monsters in the dungeon.
|
||||||
A monster must override this class, and the parameters are given
|
All specific monster classes overwrite this class,
|
||||||
in the __init__ function.
|
and the parameters are given in the __init__ function.
|
||||||
An example of the specification of a monster that has a strength of 4
|
An example of the specification of a monster that has a strength of 4
|
||||||
and 20 max HP:
|
and 20 max HP:
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class Monster(FightingEntity):
|
||||||
super().__init__(name="my_monster", strength=strength,
|
super().__init__(name="my_monster", strength=strength,
|
||||||
maxhealth=maxhealth, *args, **kwargs)
|
maxhealth=maxhealth, *args, **kwargs)
|
||||||
|
|
||||||
With that way, attributes can be overwritten when the entity got created.
|
With that way, attributes can be overwritten when the entity is created.
|
||||||
"""
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
@ -29,7 +29,7 @@ class Monster(FightingEntity):
|
||||||
def act(self, m: Map) -> None:
|
def act(self, m: Map) -> None:
|
||||||
"""
|
"""
|
||||||
By default, a monster will move randomly where it is possible
|
By default, a monster will move randomly where it is possible
|
||||||
And if a player is close to the monster, the monster run on the player.
|
If the player is closeby, the monster runs to the player.
|
||||||
"""
|
"""
|
||||||
target = None
|
target = None
|
||||||
for entity in m.entities:
|
for entity in m.entities:
|
||||||
|
@ -38,12 +38,12 @@ class Monster(FightingEntity):
|
||||||
target = entity
|
target = entity
|
||||||
break
|
break
|
||||||
|
|
||||||
# A Dijkstra algorithm has ran that targets the player.
|
# Monsters move according to a Dijkstra algorithm
|
||||||
# With that way, monsters can simply follow the path.
|
# that targets the player.
|
||||||
# If they can't move and they are already close to the player,
|
# If they can not move and are already close to the player,
|
||||||
# They hit.
|
# they hit.
|
||||||
if target and (self.y, self.x) in target.paths:
|
if target and (self.y, self.x) in target.paths:
|
||||||
# Move to target player by choosing the best avaliable path
|
# Moves to target player by choosing the best available path
|
||||||
for next_y, next_x in target.paths[(self.y, self.x)]:
|
for next_y, next_x in target.paths[(self.y, self.x)]:
|
||||||
moved = self.check_move(next_y, next_x, True)
|
moved = self.check_move(next_y, next_x, True)
|
||||||
if moved:
|
if moved:
|
||||||
|
@ -52,8 +52,8 @@ class Monster(FightingEntity):
|
||||||
self.map.logs.add_message(self.hit(target))
|
self.map.logs.add_message(self.hit(target))
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# Move in a random direction
|
# Moves in a random direction
|
||||||
# If the direction is not available, try another one
|
# If the direction is not available, tries another one
|
||||||
moves = [self.move_up, self.move_down,
|
moves = [self.move_up, self.move_down,
|
||||||
self.move_left, self.move_right]
|
self.move_left, self.move_right]
|
||||||
shuffle(moves)
|
shuffle(moves)
|
||||||
|
@ -64,7 +64,7 @@ class Monster(FightingEntity):
|
||||||
|
|
||||||
class Tiger(Monster):
|
class Tiger(Monster):
|
||||||
"""
|
"""
|
||||||
A tiger monster
|
A tiger monster.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name: str = "tiger", strength: int = 2,
|
def __init__(self, name: str = "tiger", strength: int = 2,
|
||||||
maxhealth: int = 20, *args, **kwargs) -> None:
|
maxhealth: int = 20, *args, **kwargs) -> None:
|
||||||
|
@ -74,7 +74,7 @@ class Tiger(Monster):
|
||||||
|
|
||||||
class Hedgehog(Monster):
|
class Hedgehog(Monster):
|
||||||
"""
|
"""
|
||||||
A really mean hedgehog monster
|
A really mean hedgehog monster.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name: str = "hedgehog", strength: int = 3,
|
def __init__(self, name: str = "hedgehog", strength: int = 3,
|
||||||
maxhealth: int = 10, *args, **kwargs) -> None:
|
maxhealth: int = 10, *args, **kwargs) -> None:
|
||||||
|
@ -84,7 +84,7 @@ class Hedgehog(Monster):
|
||||||
|
|
||||||
class Rabbit(Monster):
|
class Rabbit(Monster):
|
||||||
"""
|
"""
|
||||||
A rabbit monster
|
A rabbit monster.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name: str = "rabbit", strength: int = 1,
|
def __init__(self, name: str = "rabbit", strength: int = 1,
|
||||||
maxhealth: int = 15, *args, **kwargs) -> None:
|
maxhealth: int = 15, *args, **kwargs) -> None:
|
||||||
|
@ -94,7 +94,7 @@ class Rabbit(Monster):
|
||||||
|
|
||||||
class TeddyBear(Monster):
|
class TeddyBear(Monster):
|
||||||
"""
|
"""
|
||||||
A cute teddybear monster
|
A cute teddybear monster.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name: str = "teddy_bear", strength: int = 0,
|
def __init__(self, name: str = "teddy_bear", strength: int = 0,
|
||||||
maxhealth: int = 50, *args, **kwargs) -> None:
|
maxhealth: int = 50, *args, **kwargs) -> None:
|
||||||
|
|
|
@ -11,7 +11,7 @@ from ..interfaces import FightingEntity, InventoryHolder
|
||||||
|
|
||||||
class Player(InventoryHolder, FightingEntity):
|
class Player(InventoryHolder, FightingEntity):
|
||||||
"""
|
"""
|
||||||
The class of the player
|
The class of the player.
|
||||||
"""
|
"""
|
||||||
current_xp: int = 0
|
current_xp: int = 0
|
||||||
max_xp: int = 10
|
max_xp: int = 10
|
||||||
|
@ -45,7 +45,7 @@ class Player(InventoryHolder, FightingEntity):
|
||||||
|
|
||||||
def level_up(self) -> None:
|
def level_up(self) -> None:
|
||||||
"""
|
"""
|
||||||
Add levels to the player as much as it is possible.
|
Add as many levels as possible to the player.
|
||||||
"""
|
"""
|
||||||
while self.current_xp > self.max_xp:
|
while self.current_xp > self.max_xp:
|
||||||
self.level += 1
|
self.level += 1
|
||||||
|
@ -59,8 +59,8 @@ class Player(InventoryHolder, FightingEntity):
|
||||||
|
|
||||||
def add_xp(self, xp: int) -> None:
|
def add_xp(self, xp: int) -> None:
|
||||||
"""
|
"""
|
||||||
Add some experience to the player.
|
Adds some experience to the player.
|
||||||
If the required amount is reached, level up.
|
If the required amount is reached, the player levels up.
|
||||||
"""
|
"""
|
||||||
self.current_xp += xp
|
self.current_xp += xp
|
||||||
self.level_up()
|
self.level_up()
|
||||||
|
@ -89,9 +89,8 @@ class Player(InventoryHolder, FightingEntity):
|
||||||
|
|
||||||
def recalculate_paths(self, max_distance: int = 8) -> None:
|
def recalculate_paths(self, max_distance: int = 8) -> None:
|
||||||
"""
|
"""
|
||||||
Use Dijkstra algorithm to calculate best paths for monsters to go to
|
Uses Dijkstra algorithm to calculate best paths for monsters to go to
|
||||||
the player. Actually, the paths are computed for each tile adjacent to
|
the player.
|
||||||
the player then for each step the monsters use the best path avaliable.
|
|
||||||
"""
|
"""
|
||||||
distances = []
|
distances = []
|
||||||
predecessors = []
|
predecessors = []
|
||||||
|
|
|
@ -16,12 +16,11 @@ class DisplayActions(Enum):
|
||||||
"""
|
"""
|
||||||
REFRESH = auto()
|
REFRESH = auto()
|
||||||
UPDATE = auto()
|
UPDATE = auto()
|
||||||
MOUSE = auto()
|
|
||||||
|
|
||||||
|
|
||||||
class GameMode(Enum):
|
class GameMode(Enum):
|
||||||
"""
|
"""
|
||||||
Game mode options
|
Game mode options.
|
||||||
"""
|
"""
|
||||||
MAINMENU = auto()
|
MAINMENU = auto()
|
||||||
PLAY = auto()
|
PLAY = auto()
|
||||||
|
@ -32,9 +31,8 @@ class GameMode(Enum):
|
||||||
|
|
||||||
class KeyValues(Enum):
|
class KeyValues(Enum):
|
||||||
"""
|
"""
|
||||||
Key values options used in the game
|
Key values options used in the game.
|
||||||
"""
|
"""
|
||||||
MOUSE = auto()
|
|
||||||
UP = auto()
|
UP = auto()
|
||||||
DOWN = auto()
|
DOWN = auto()
|
||||||
LEFT = auto()
|
LEFT = auto()
|
||||||
|
@ -46,12 +44,11 @@ class KeyValues(Enum):
|
||||||
DROP = auto()
|
DROP = auto()
|
||||||
SPACE = auto()
|
SPACE = auto()
|
||||||
CHAT = auto()
|
CHAT = auto()
|
||||||
WAIT = auto()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def translate_key(key: str, settings: Settings) -> Optional["KeyValues"]:
|
def translate_key(key: str, settings: Settings) -> Optional["KeyValues"]:
|
||||||
"""
|
"""
|
||||||
Translate the raw string key into an enum value that we can use.
|
Translates the raw string key into an enum value that we can use.
|
||||||
"""
|
"""
|
||||||
if key in (settings.KEY_DOWN_SECONDARY,
|
if key in (settings.KEY_DOWN_SECONDARY,
|
||||||
settings.KEY_DOWN_PRIMARY):
|
settings.KEY_DOWN_PRIMARY):
|
||||||
|
@ -79,6 +76,4 @@ class KeyValues(Enum):
|
||||||
return KeyValues.SPACE
|
return KeyValues.SPACE
|
||||||
elif key == settings.KEY_CHAT:
|
elif key == settings.KEY_CHAT:
|
||||||
return KeyValues.CHAT
|
return KeyValues.CHAT
|
||||||
elif key == settings.KEY_WAIT:
|
|
||||||
return KeyValues.WAIT
|
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Game:
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""
|
"""
|
||||||
Init the game.
|
Initiates the game.
|
||||||
"""
|
"""
|
||||||
self.state = GameMode.MAINMENU
|
self.state = GameMode.MAINMENU
|
||||||
self.waiting_for_friendly_key = False
|
self.waiting_for_friendly_key = False
|
||||||
|
@ -48,7 +48,7 @@ class Game:
|
||||||
|
|
||||||
def new_game(self) -> None:
|
def new_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
Create a new game on the screen.
|
Creates a new game on the screen.
|
||||||
"""
|
"""
|
||||||
# TODO generate a new map procedurally
|
# TODO generate a new map procedurally
|
||||||
self.map = Map.load(ResourceManager.get_asset_path("example_map.txt"))
|
self.map = Map.load(ResourceManager.get_asset_path("example_map.txt"))
|
||||||
|
@ -63,8 +63,8 @@ class Game:
|
||||||
def run(self, screen: Any) -> None:
|
def run(self, screen: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Main infinite loop.
|
Main infinite loop.
|
||||||
We wait for the player's action, then we do what that should be done
|
We wait for the player's action, then we do what should be done
|
||||||
when the given key gets pressed.
|
when a key gets pressed.
|
||||||
"""
|
"""
|
||||||
while True: # pragma no cover
|
while True: # pragma no cover
|
||||||
screen.erase()
|
screen.erase()
|
||||||
|
@ -81,7 +81,7 @@ class Game:
|
||||||
def handle_key_pressed(self, key: Optional[KeyValues], raw_key: str = '')\
|
def handle_key_pressed(self, key: Optional[KeyValues], raw_key: str = '')\
|
||||||
-> None:
|
-> None:
|
||||||
"""
|
"""
|
||||||
Indicates what should be done when the given key is pressed,
|
Indicates what should be done when a given key is pressed,
|
||||||
according to the current game state.
|
according to the current game state.
|
||||||
"""
|
"""
|
||||||
if self.message:
|
if self.message:
|
||||||
|
@ -133,8 +133,9 @@ class Game:
|
||||||
|
|
||||||
def handle_friendly_entity_chat(self, key: KeyValues) -> None:
|
def handle_friendly_entity_chat(self, key: KeyValues) -> None:
|
||||||
"""
|
"""
|
||||||
If the player is talking to a friendly entity, we get the direction
|
If the player tries to talk to a friendly entity, the game waits for
|
||||||
where the entity is, then we interact with it.
|
a directional key to be pressed, verifies there is a friendly entity
|
||||||
|
in that direction and then lets the player interact with it.
|
||||||
"""
|
"""
|
||||||
if not self.waiting_for_friendly_key:
|
if not self.waiting_for_friendly_key:
|
||||||
return
|
return
|
||||||
|
@ -210,7 +211,7 @@ class Game:
|
||||||
|
|
||||||
def handle_key_pressed_main_menu(self, key: KeyValues) -> None:
|
def handle_key_pressed_main_menu(self, key: KeyValues) -> None:
|
||||||
"""
|
"""
|
||||||
In the main menu, we can navigate through options.
|
In the main menu, we can navigate through different options.
|
||||||
"""
|
"""
|
||||||
if key == KeyValues.DOWN:
|
if key == KeyValues.DOWN:
|
||||||
self.main_menu.go_down()
|
self.main_menu.go_down()
|
||||||
|
@ -235,13 +236,13 @@ class Game:
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Saves the game to a dictionary
|
Saves the game to a dictionary.
|
||||||
"""
|
"""
|
||||||
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 dictionary
|
Loads the game from a dictionary.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.map.load_state(d)
|
self.map.load_state(d)
|
||||||
|
@ -265,7 +266,7 @@ class Game:
|
||||||
|
|
||||||
def load_game(self) -> None:
|
def load_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
Loads the game from a file
|
Loads the game from a file.
|
||||||
"""
|
"""
|
||||||
file_path = ResourceManager.get_config_path("save.json")
|
file_path = ResourceManager.get_config_path("save.json")
|
||||||
if os.path.isfile(file_path):
|
if os.path.isfile(file_path):
|
||||||
|
@ -282,7 +283,7 @@ class Game:
|
||||||
|
|
||||||
def save_game(self) -> None:
|
def save_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
Saves the game to a file
|
Saves the game to a file.
|
||||||
"""
|
"""
|
||||||
with open(ResourceManager.get_config_path("save.json"), "w") as f:
|
with open(ResourceManager.get_config_path("save.json"), "w") as f:
|
||||||
f.write(json.dumps(self.save_state()))
|
f.write(json.dumps(self.save_state()))
|
||||||
|
|
|
@ -12,7 +12,7 @@ from .translations import gettext as _
|
||||||
|
|
||||||
class Logs:
|
class Logs:
|
||||||
"""
|
"""
|
||||||
The logs object stores the messages to display. It is encapsulating a list
|
The logs object stores the messages to display. It encapsulates a list
|
||||||
of such messages, to allow multiple pointers to keep track of it even if
|
of such messages, to allow multiple pointers to keep track of it even if
|
||||||
the list was to be reassigned.
|
the list was to be reassigned.
|
||||||
"""
|
"""
|
||||||
|
@ -32,7 +32,7 @@ class Logs:
|
||||||
|
|
||||||
class Map:
|
class Map:
|
||||||
"""
|
"""
|
||||||
Object that represents a Map with its width, height
|
The Map object represents a with its width, height
|
||||||
and tiles, that have their custom properties.
|
and tiles, that have their custom properties.
|
||||||
"""
|
"""
|
||||||
width: int
|
width: int
|
||||||
|
@ -59,14 +59,14 @@ class Map:
|
||||||
|
|
||||||
def add_entity(self, entity: "Entity") -> None:
|
def add_entity(self, entity: "Entity") -> None:
|
||||||
"""
|
"""
|
||||||
Register a new entity in the map.
|
Registers a new entity in the map.
|
||||||
"""
|
"""
|
||||||
self.entities.append(entity)
|
self.entities.append(entity)
|
||||||
entity.map = self
|
entity.map = self
|
||||||
|
|
||||||
def remove_entity(self, entity: "Entity") -> None:
|
def remove_entity(self, entity: "Entity") -> None:
|
||||||
"""
|
"""
|
||||||
Unregister an entity from the map.
|
Unregisters an entity from the map.
|
||||||
"""
|
"""
|
||||||
if entity in self.entities:
|
if entity in self.entities:
|
||||||
self.entities.remove(entity)
|
self.entities.remove(entity)
|
||||||
|
@ -86,7 +86,7 @@ class Map:
|
||||||
def entity_is_present(self, y: int, x: int) -> bool:
|
def entity_is_present(self, y: int, x: int) -> bool:
|
||||||
"""
|
"""
|
||||||
Indicates that the tile at the coordinates (y, x) contains a killable
|
Indicates that the tile at the coordinates (y, x) contains a killable
|
||||||
entity
|
entity.
|
||||||
"""
|
"""
|
||||||
return 0 <= y < self.height and 0 <= x < self.width and \
|
return 0 <= y < self.height and 0 <= x < self.width and \
|
||||||
any(entity.x == x and entity.y == y and entity.is_friendly()
|
any(entity.x == x and entity.y == y and entity.is_friendly()
|
||||||
|
@ -95,7 +95,7 @@ class Map:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(filename: str) -> "Map":
|
def load(filename: str) -> "Map":
|
||||||
"""
|
"""
|
||||||
Read a file that contains the content of a map, and build a Map object.
|
Reads a file that contains the content of a map, and builds a Map object.
|
||||||
"""
|
"""
|
||||||
with open(filename, "r") as f:
|
with open(filename, "r") as f:
|
||||||
file = f.read()
|
file = f.read()
|
||||||
|
@ -104,7 +104,7 @@ class Map:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_from_string(content: str) -> "Map":
|
def load_from_string(content: str) -> "Map":
|
||||||
"""
|
"""
|
||||||
Load a map represented by its characters and build a Map object.
|
Loads a map represented by its characters and builds a Map object.
|
||||||
"""
|
"""
|
||||||
lines = content.split("\n")
|
lines = content.split("\n")
|
||||||
first_line = lines[0]
|
first_line = lines[0]
|
||||||
|
@ -120,7 +120,7 @@ class Map:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_dungeon_from_string(content: str) -> List[List["Tile"]]:
|
def load_dungeon_from_string(content: str) -> List[List["Tile"]]:
|
||||||
"""
|
"""
|
||||||
Transforms a string into the list of corresponding tiles
|
Transforms a string into the list of corresponding tiles.
|
||||||
"""
|
"""
|
||||||
lines = content.split("\n")
|
lines = content.split("\n")
|
||||||
tiles = [[Tile.from_ascii_char(c)
|
tiles = [[Tile.from_ascii_char(c)
|
||||||
|
@ -129,7 +129,7 @@ class Map:
|
||||||
|
|
||||||
def draw_string(self, pack: TexturePack) -> str:
|
def draw_string(self, pack: TexturePack) -> str:
|
||||||
"""
|
"""
|
||||||
Draw the current map as a string object that can be rendered
|
Draws the current map as a string object that can be rendered
|
||||||
in the window.
|
in the window.
|
||||||
"""
|
"""
|
||||||
return "\n".join("".join(tile.char(pack) for tile in line)
|
return "\n".join("".join(tile.char(pack) for tile in line)
|
||||||
|
@ -137,7 +137,7 @@ class Map:
|
||||||
|
|
||||||
def spawn_random_entities(self, count: int) -> None:
|
def spawn_random_entities(self, count: int) -> None:
|
||||||
"""
|
"""
|
||||||
Put randomly {count} entities on the map, where it is available.
|
Puts randomly {count} entities on the map, only on empty ground tiles.
|
||||||
"""
|
"""
|
||||||
for ignored in range(count):
|
for ignored in range(count):
|
||||||
y, x = 0, 0
|
y, x = 0, 0
|
||||||
|
@ -152,14 +152,14 @@ class Map:
|
||||||
|
|
||||||
def tick(self) -> None:
|
def tick(self) -> None:
|
||||||
"""
|
"""
|
||||||
Trigger all entity events.
|
Triggers all entity events.
|
||||||
"""
|
"""
|
||||||
for entity in self.entities:
|
for entity in self.entities:
|
||||||
entity.act(self)
|
entity.act(self)
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Saves the map's attributes to a dictionary
|
Saves the map's attributes to a dictionary.
|
||||||
"""
|
"""
|
||||||
d = dict()
|
d = dict()
|
||||||
d["width"] = self.width
|
d["width"] = self.width
|
||||||
|
@ -176,7 +176,7 @@ class Map:
|
||||||
|
|
||||||
def load_state(self, d: dict) -> None:
|
def load_state(self, d: dict) -> None:
|
||||||
"""
|
"""
|
||||||
Loads the map's attributes from a dictionary
|
Loads the map's attributes from a dictionary.
|
||||||
"""
|
"""
|
||||||
self.width = d["width"]
|
self.width = d["width"]
|
||||||
self.height = d["height"]
|
self.height = d["height"]
|
||||||
|
@ -193,7 +193,7 @@ class Map:
|
||||||
|
|
||||||
class Tile(Enum):
|
class Tile(Enum):
|
||||||
"""
|
"""
|
||||||
The internal representation of the tiles of the map
|
The internal representation of the tiles of the map.
|
||||||
"""
|
"""
|
||||||
EMPTY = auto()
|
EMPTY = auto()
|
||||||
WALL = auto()
|
WALL = auto()
|
||||||
|
@ -202,7 +202,7 @@ class Tile(Enum):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_ascii_char(ch: str) -> "Tile":
|
def from_ascii_char(ch: str) -> "Tile":
|
||||||
"""
|
"""
|
||||||
Maps an ascii character to its equivalent in the texture pack
|
Maps an ascii character to its equivalent in the texture pack.
|
||||||
"""
|
"""
|
||||||
for tile in Tile:
|
for tile in Tile:
|
||||||
if tile.char(TexturePack.ASCII_PACK) == ch:
|
if tile.char(TexturePack.ASCII_PACK) == ch:
|
||||||
|
@ -212,7 +212,7 @@ class Tile(Enum):
|
||||||
def char(self, pack: TexturePack) -> str:
|
def char(self, pack: TexturePack) -> str:
|
||||||
"""
|
"""
|
||||||
Translates a Tile to the corresponding character according
|
Translates a Tile to the corresponding character according
|
||||||
to the texture pack
|
to the texture pack.
|
||||||
"""
|
"""
|
||||||
return getattr(pack, self.name)
|
return getattr(pack, self.name)
|
||||||
|
|
||||||
|
@ -224,14 +224,14 @@ class Tile(Enum):
|
||||||
|
|
||||||
def can_walk(self) -> bool:
|
def can_walk(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if an entity (player or not) can move in this tile.
|
Checks if an entity (player or not) can move in this tile.
|
||||||
"""
|
"""
|
||||||
return not self.is_wall() and self != Tile.EMPTY
|
return not self.is_wall() and self != Tile.EMPTY
|
||||||
|
|
||||||
|
|
||||||
class Entity:
|
class Entity:
|
||||||
"""
|
"""
|
||||||
An Entity object represents any entity present on the map
|
An Entity object represents any entity present on the map.
|
||||||
"""
|
"""
|
||||||
y: int
|
y: int
|
||||||
x: int
|
x: int
|
||||||
|
@ -249,7 +249,7 @@ 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
|
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:
|
||||||
|
@ -258,7 +258,7 @@ class Entity:
|
||||||
|
|
||||||
def move(self, y: int, x: int) -> bool:
|
def move(self, y: int, x: int) -> bool:
|
||||||
"""
|
"""
|
||||||
Moves an entity to (y,x) coordinates
|
Moves an entity to (y,x) coordinates.
|
||||||
"""
|
"""
|
||||||
self.y = y
|
self.y = y
|
||||||
self.x = x
|
self.x = x
|
||||||
|
@ -266,49 +266,49 @@ class Entity:
|
||||||
|
|
||||||
def move_up(self, force: bool = False) -> bool:
|
def move_up(self, force: bool = False) -> bool:
|
||||||
"""
|
"""
|
||||||
Moves the entity up one tile, if possible
|
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
|
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
|
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
|
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)
|
||||||
|
|
||||||
def act(self, m: Map) -> None:
|
def act(self, m: Map) -> None:
|
||||||
"""
|
"""
|
||||||
Define the action of the entity that is ran each tick.
|
Defines the action the entity will do at each tick.
|
||||||
By default, does nothing.
|
By default, does nothing.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def distance_squared(self, other: "Entity") -> int:
|
def distance_squared(self, other: "Entity") -> int:
|
||||||
"""
|
"""
|
||||||
Get the square of the distance to another entity.
|
Gives the square of the distance to another entity.
|
||||||
Useful to check distances since square root takes time.
|
Useful to check distances since taking the square root takes time.
|
||||||
"""
|
"""
|
||||||
return (self.y - other.y) ** 2 + (self.x - other.x) ** 2
|
return (self.y - other.y) ** 2 + (self.x - other.x) ** 2
|
||||||
|
|
||||||
def distance(self, other: "Entity") -> float:
|
def distance(self, other: "Entity") -> float:
|
||||||
"""
|
"""
|
||||||
Get the cartesian distance to another entity.
|
Gives the cartesian distance to another entity.
|
||||||
"""
|
"""
|
||||||
return sqrt(self.distance_squared(other))
|
return sqrt(self.distance_squared(other))
|
||||||
|
|
||||||
|
@ -340,12 +340,15 @@ class Entity:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def translated_name(self) -> str:
|
def translated_name(self) -> str:
|
||||||
|
"""
|
||||||
|
Translates the name of entities.
|
||||||
|
"""
|
||||||
return _(self.name.replace("_", " "))
|
return _(self.name.replace("_", " "))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_entity_classes() -> list:
|
def get_all_entity_classes() -> list:
|
||||||
"""
|
"""
|
||||||
Returns all entities subclasses
|
Returns all entities subclasses.
|
||||||
"""
|
"""
|
||||||
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart
|
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart
|
||||||
from squirrelbattle.entities.monsters import Tiger, Hedgehog, \
|
from squirrelbattle.entities.monsters import Tiger, Hedgehog, \
|
||||||
|
@ -357,7 +360,7 @@ class Entity:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_entity_classes_in_a_dict() -> dict:
|
def get_all_entity_classes_in_a_dict() -> dict:
|
||||||
"""
|
"""
|
||||||
Returns all entities subclasses in a dictionary
|
Returns all entities subclasses in a dictionary.
|
||||||
"""
|
"""
|
||||||
from squirrelbattle.entities.player import Player
|
from squirrelbattle.entities.player import Player
|
||||||
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, \
|
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, \
|
||||||
|
@ -381,7 +384,7 @@ class Entity:
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Saves the coordinates of the entity
|
Saves the coordinates of the entity.
|
||||||
"""
|
"""
|
||||||
d = dict()
|
d = dict()
|
||||||
d["x"] = self.x
|
d["x"] = self.x
|
||||||
|
@ -393,7 +396,7 @@ class Entity:
|
||||||
class FightingEntity(Entity):
|
class FightingEntity(Entity):
|
||||||
"""
|
"""
|
||||||
A FightingEntity is an entity that can fight, and thus has a health,
|
A FightingEntity is an entity that can fight, and thus has a health,
|
||||||
level and stats
|
level and stats.
|
||||||
"""
|
"""
|
||||||
maxhealth: int
|
maxhealth: int
|
||||||
health: int
|
health: int
|
||||||
|
@ -420,11 +423,15 @@ class FightingEntity(Entity):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dead(self) -> bool:
|
def dead(self) -> bool:
|
||||||
|
"""
|
||||||
|
Is this entity dead ?
|
||||||
|
"""
|
||||||
return self.health <= 0
|
return self.health <= 0
|
||||||
|
|
||||||
def hit(self, opponent: "FightingEntity") -> str:
|
def hit(self, opponent: "FightingEntity") -> str:
|
||||||
"""
|
"""
|
||||||
Deals damage to the opponent, based on the stats
|
The entity deals damage to the opponent
|
||||||
|
based on their respective stats.
|
||||||
"""
|
"""
|
||||||
return _("{name} hits {opponent}.")\
|
return _("{name} hits {opponent}.")\
|
||||||
.format(name=_(self.translated_name.capitalize()),
|
.format(name=_(self.translated_name.capitalize()),
|
||||||
|
@ -433,7 +440,8 @@ class FightingEntity(Entity):
|
||||||
|
|
||||||
def take_damage(self, attacker: "Entity", amount: int) -> str:
|
def take_damage(self, attacker: "Entity", amount: int) -> str:
|
||||||
"""
|
"""
|
||||||
Take damage from the attacker, based on the stats
|
The entity takes damage from the attacker
|
||||||
|
based on their respective stats.
|
||||||
"""
|
"""
|
||||||
self.health -= amount
|
self.health -= amount
|
||||||
if self.health <= 0:
|
if self.health <= 0:
|
||||||
|
@ -446,20 +454,20 @@ class FightingEntity(Entity):
|
||||||
|
|
||||||
def die(self) -> None:
|
def die(self) -> None:
|
||||||
"""
|
"""
|
||||||
If a fighting entity has no more health, it dies and is removed
|
If a fighting entity has no more health, it dies and is removed.
|
||||||
"""
|
"""
|
||||||
self.map.remove_entity(self)
|
self.map.remove_entity(self)
|
||||||
|
|
||||||
def keys(self) -> list:
|
def keys(self) -> list:
|
||||||
"""
|
"""
|
||||||
Returns a fighting entity's specific attributes
|
Returns a fighting entity's specific attributes.
|
||||||
"""
|
"""
|
||||||
return ["name", "maxhealth", "health", "level", "strength",
|
return ["name", "maxhealth", "health", "level", "strength",
|
||||||
"intelligence", "charisma", "dexterity", "constitution"]
|
"intelligence", "charisma", "dexterity", "constitution"]
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Saves the state of the entity into a dictionary
|
Saves the state of the entity into a dictionary.
|
||||||
"""
|
"""
|
||||||
d = super().save_state()
|
d = super().save_state()
|
||||||
for name in self.keys():
|
for name in self.keys():
|
||||||
|
@ -469,7 +477,7 @@ class FightingEntity(Entity):
|
||||||
|
|
||||||
class FriendlyEntity(FightingEntity):
|
class FriendlyEntity(FightingEntity):
|
||||||
"""
|
"""
|
||||||
Friendly entities are living entities which do not attack the player
|
Friendly entities are living entities which do not attack the player.
|
||||||
"""
|
"""
|
||||||
dialogue_option: list
|
dialogue_option: list
|
||||||
|
|
||||||
|
@ -480,7 +488,7 @@ class FriendlyEntity(FightingEntity):
|
||||||
|
|
||||||
def keys(self) -> list:
|
def keys(self) -> list:
|
||||||
"""
|
"""
|
||||||
Returns a friendly entity's specific attributes
|
Returns a friendly entity's specific attributes.
|
||||||
"""
|
"""
|
||||||
return ["maxhealth", "health"]
|
return ["maxhealth", "health"]
|
||||||
|
|
||||||
|
@ -491,7 +499,7 @@ class InventoryHolder(Entity):
|
||||||
|
|
||||||
def translate_inventory(self, inventory: list) -> list:
|
def translate_inventory(self, inventory: list) -> list:
|
||||||
"""
|
"""
|
||||||
Translate the JSON-state of the inventory into a list of the items in
|
Translates the JSON save of the inventory into a list of the items in
|
||||||
the inventory.
|
the inventory.
|
||||||
"""
|
"""
|
||||||
for i in range(len(inventory)):
|
for i in range(len(inventory)):
|
||||||
|
@ -501,7 +509,7 @@ class InventoryHolder(Entity):
|
||||||
|
|
||||||
def dict_to_inventory(self, item_dict: dict) -> Entity:
|
def dict_to_inventory(self, item_dict: dict) -> Entity:
|
||||||
"""
|
"""
|
||||||
Translate a dict object that contains the state of an item
|
Translates a dictionnary that contains the state of an item
|
||||||
into an item object.
|
into an item object.
|
||||||
"""
|
"""
|
||||||
entity_classes = self.get_all_entity_classes_in_a_dict()
|
entity_classes = self.get_all_entity_classes_in_a_dict()
|
||||||
|
@ -511,7 +519,7 @@ class InventoryHolder(Entity):
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
We save the inventory of the merchant formatted as JSON
|
The inventory of the merchant is saved in a JSON format.
|
||||||
"""
|
"""
|
||||||
d = super().save_state()
|
d = super().save_state()
|
||||||
d["hazel"] = self.hazel
|
d["hazel"] = self.hazel
|
||||||
|
@ -520,19 +528,19 @@ class InventoryHolder(Entity):
|
||||||
|
|
||||||
def add_to_inventory(self, obj: Any) -> None:
|
def add_to_inventory(self, obj: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Adds an object to inventory
|
Adds an object to the inventory.
|
||||||
"""
|
"""
|
||||||
self.inventory.append(obj)
|
self.inventory.append(obj)
|
||||||
|
|
||||||
def remove_from_inventory(self, obj: Any) -> None:
|
def remove_from_inventory(self, obj: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Removes an object from the inventory
|
Removes an object from the inventory.
|
||||||
"""
|
"""
|
||||||
self.inventory.remove(obj)
|
self.inventory.remove(obj)
|
||||||
|
|
||||||
def change_hazel_balance(self, hz: int) -> None:
|
def change_hazel_balance(self, hz: int) -> None:
|
||||||
"""
|
"""
|
||||||
Change the number of hazel the entity has by hz. hz is negative
|
Changes the number of hazel the entity has by hz. hz is negative
|
||||||
when the player loses money and positive when he gains money
|
when the entity loses money and positive when it gains money.
|
||||||
"""
|
"""
|
||||||
self.hazel += hz
|
self.hazel += hz
|
||||||
|
|
|
@ -14,7 +14,7 @@ from .translations import gettext as _, Translator
|
||||||
|
|
||||||
class Menu:
|
class Menu:
|
||||||
"""
|
"""
|
||||||
A Menu object is the logical representation of a menu in the game
|
A Menu object is the logical representation of a menu in the game.
|
||||||
"""
|
"""
|
||||||
values: list
|
values: list
|
||||||
|
|
||||||
|
@ -23,26 +23,26 @@ class Menu:
|
||||||
|
|
||||||
def go_up(self) -> None:
|
def go_up(self) -> None:
|
||||||
"""
|
"""
|
||||||
Moves the pointer of the menu on the previous value
|
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
|
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
|
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
|
Values of the main menu.
|
||||||
"""
|
"""
|
||||||
START = "New game"
|
START = "New game"
|
||||||
RESUME = "Resume"
|
RESUME = "Resume"
|
||||||
|
@ -57,14 +57,14 @@ class MainMenuValues(Enum):
|
||||||
|
|
||||||
class MainMenu(Menu):
|
class MainMenu(Menu):
|
||||||
"""
|
"""
|
||||||
A special instance of a menu : the main menu
|
A special instance of a menu : the main menu.
|
||||||
"""
|
"""
|
||||||
values = [e for e in MainMenuValues]
|
values = [e for e in MainMenuValues]
|
||||||
|
|
||||||
|
|
||||||
class SettingsMenu(Menu):
|
class SettingsMenu(Menu):
|
||||||
"""
|
"""
|
||||||
A special instance of a menu : the settings menu
|
A special instance of a menu : the settings menu.
|
||||||
"""
|
"""
|
||||||
waiting_for_key: bool = False
|
waiting_for_key: bool = False
|
||||||
|
|
||||||
|
@ -75,7 +75,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:
|
||||||
"""
|
"""
|
||||||
In the setting menu, we van select a setting and change it
|
In the setting menu, we can 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.
|
||||||
|
@ -121,22 +121,40 @@ class SettingsMenu(Menu):
|
||||||
|
|
||||||
|
|
||||||
class InventoryMenu(Menu):
|
class InventoryMenu(Menu):
|
||||||
|
"""
|
||||||
|
A special instance of a menu : the menu for the inventory of the player.
|
||||||
|
"""
|
||||||
player: Player
|
player: Player
|
||||||
|
|
||||||
def update_player(self, player: Player) -> None:
|
def update_player(self, player: Player) -> None:
|
||||||
|
"""
|
||||||
|
Updates the player.
|
||||||
|
"""
|
||||||
self.player = player
|
self.player = player
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def values(self) -> list:
|
def values(self) -> list:
|
||||||
|
"""
|
||||||
|
Returns the values of the menu.
|
||||||
|
"""
|
||||||
return self.player.inventory
|
return self.player.inventory
|
||||||
|
|
||||||
|
|
||||||
class StoreMenu(Menu):
|
class StoreMenu(Menu):
|
||||||
|
"""
|
||||||
|
A special instance of a menu : the menu for the inventory of a merchant.
|
||||||
|
"""
|
||||||
merchant: Merchant
|
merchant: Merchant
|
||||||
|
|
||||||
def update_merchant(self, merchant: Merchant) -> None:
|
def update_merchant(self, merchant: Merchant) -> None:
|
||||||
|
"""
|
||||||
|
Updates the merchant.
|
||||||
|
"""
|
||||||
self.merchant = merchant
|
self.merchant = merchant
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def values(self) -> list:
|
def values(self) -> list:
|
||||||
|
"""
|
||||||
|
Returns the values of the menu.
|
||||||
|
"""
|
||||||
return self.merchant.inventory
|
return self.merchant.inventory
|
||||||
|
|
|
@ -13,9 +13,9 @@ from .translations import gettext as _
|
||||||
class Settings:
|
class Settings:
|
||||||
"""
|
"""
|
||||||
This class stores the settings of the game.
|
This class stores the settings of the game.
|
||||||
Settings can be get by using for example settings.TEXTURE_PACK directly.
|
Settings can be obtained by using for example settings.TEXTURE_PACK directly.
|
||||||
The comment can be get by using settings.get_comment('TEXTURE_PACK').
|
The comment can be obtained by using settings.get_comment('TEXTURE_PACK').
|
||||||
We can define the setting by simply use settings.TEXTURE_PACK = 'new_key'
|
We can set the setting by simply using settings.TEXTURE_PACK = 'new_key'
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.KEY_UP_PRIMARY = ['z', 'Main key to move up']
|
self.KEY_UP_PRIMARY = ['z', 'Main key to move up']
|
||||||
|
@ -50,7 +50,7 @@ class Settings:
|
||||||
|
|
||||||
def get_comment(self, item: str) -> str:
|
def get_comment(self, item: str) -> str:
|
||||||
"""
|
"""
|
||||||
Retrieve the comment of a setting.
|
Retrieves the comment relative to a setting.
|
||||||
"""
|
"""
|
||||||
if item in self.settings_keys:
|
if item in self.settings_keys:
|
||||||
return _(object.__getattribute__(self, item)[1])
|
return _(object.__getattribute__(self, item)[1])
|
||||||
|
@ -61,13 +61,13 @@ class Settings:
|
||||||
@property
|
@property
|
||||||
def settings_keys(self) -> Generator[str, Any, None]:
|
def settings_keys(self) -> Generator[str, Any, None]:
|
||||||
"""
|
"""
|
||||||
Get the list of all parameters.
|
Gets the list of all parameters.
|
||||||
"""
|
"""
|
||||||
return (key for key in self.__dict__)
|
return (key for key in self.__dict__)
|
||||||
|
|
||||||
def loads_from_string(self, json_str: str) -> None:
|
def loads_from_string(self, json_str: str) -> None:
|
||||||
"""
|
"""
|
||||||
Dump settings
|
Loads settings.
|
||||||
"""
|
"""
|
||||||
d = json.loads(json_str)
|
d = json.loads(json_str)
|
||||||
for key in d:
|
for key in d:
|
||||||
|
@ -75,7 +75,7 @@ class Settings:
|
||||||
|
|
||||||
def dumps_to_string(self) -> str:
|
def dumps_to_string(self) -> str:
|
||||||
"""
|
"""
|
||||||
Dump settings
|
Dumps settings.
|
||||||
"""
|
"""
|
||||||
d = dict()
|
d = dict()
|
||||||
for key in self.settings_keys:
|
for key in self.settings_keys:
|
||||||
|
|
|
@ -8,7 +8,7 @@ from types import TracebackType
|
||||||
class TermManager: # pragma: no cover
|
class TermManager: # pragma: no cover
|
||||||
"""
|
"""
|
||||||
The TermManager object initializes the terminal, returns a screen object and
|
The TermManager object initializes the terminal, returns a screen object and
|
||||||
de-initializes the terminal after use
|
de-initializes the terminal after use.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.screen = curses.initscr()
|
self.screen = curses.initscr()
|
||||||
|
|
|
@ -14,7 +14,7 @@ from squirrelbattle.resources import ResourceManager
|
||||||
class TestEntities(unittest.TestCase):
|
class TestEntities(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
"""
|
"""
|
||||||
Load example map that can be used in tests.
|
Loads example map that can be used in tests.
|
||||||
"""
|
"""
|
||||||
self.map = Map.load(ResourceManager.get_asset_path("example_map.txt"))
|
self.map = Map.load(ResourceManager.get_asset_path("example_map.txt"))
|
||||||
self.player = Player()
|
self.player = Player()
|
||||||
|
@ -23,7 +23,7 @@ class TestEntities(unittest.TestCase):
|
||||||
|
|
||||||
def test_basic_entities(self) -> None:
|
def test_basic_entities(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test some random stuff with basic entities.
|
Tests some random stuff with basic entities.
|
||||||
"""
|
"""
|
||||||
entity = Entity()
|
entity = Entity()
|
||||||
entity.move(42, 64)
|
entity.move(42, 64)
|
||||||
|
@ -38,7 +38,7 @@ class TestEntities(unittest.TestCase):
|
||||||
|
|
||||||
def test_fighting_entities(self) -> None:
|
def test_fighting_entities(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test some random stuff with fighting entities.
|
Tests some random stuff with fighting entities.
|
||||||
"""
|
"""
|
||||||
entity = Tiger()
|
entity = Tiger()
|
||||||
self.map.add_entity(entity)
|
self.map.add_entity(entity)
|
||||||
|
@ -91,7 +91,7 @@ class TestEntities(unittest.TestCase):
|
||||||
|
|
||||||
def test_items(self) -> None:
|
def test_items(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test some random stuff with items.
|
Tests some random stuff with items.
|
||||||
"""
|
"""
|
||||||
item = Item()
|
item = Item()
|
||||||
self.map.add_entity(item)
|
self.map.add_entity(item)
|
||||||
|
@ -112,7 +112,7 @@ class TestEntities(unittest.TestCase):
|
||||||
|
|
||||||
def test_bombs(self) -> None:
|
def test_bombs(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test some random stuff with bombs.
|
Tests some random stuff with bombs.
|
||||||
"""
|
"""
|
||||||
item = Bomb()
|
item = Bomb()
|
||||||
hedgehog = Hedgehog()
|
hedgehog = Hedgehog()
|
||||||
|
@ -156,7 +156,7 @@ class TestEntities(unittest.TestCase):
|
||||||
|
|
||||||
def test_hearts(self) -> None:
|
def test_hearts(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test some random stuff with hearts.
|
Tests some random stuff with hearts.
|
||||||
"""
|
"""
|
||||||
item = Heart()
|
item = Heart()
|
||||||
self.map.add_entity(item)
|
self.map.add_entity(item)
|
||||||
|
@ -171,7 +171,7 @@ class TestEntities(unittest.TestCase):
|
||||||
|
|
||||||
def test_body_snatch_potion(self) -> None:
|
def test_body_snatch_potion(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test some random stuff with body snatch potions.
|
Tests some random stuff with body snatch potions.
|
||||||
"""
|
"""
|
||||||
item = BodySnatchPotion()
|
item = BodySnatchPotion()
|
||||||
self.map.add_entity(item)
|
self.map.add_entity(item)
|
||||||
|
@ -189,7 +189,7 @@ class TestEntities(unittest.TestCase):
|
||||||
|
|
||||||
def test_players(self) -> None:
|
def test_players(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test some random stuff with players.
|
Tests some random stuff with players.
|
||||||
"""
|
"""
|
||||||
player = Player()
|
player = Player()
|
||||||
self.map.add_entity(player)
|
self.map.add_entity(player)
|
||||||
|
|
|
@ -21,7 +21,7 @@ from ..translations import gettext as _, Translator
|
||||||
class TestGame(unittest.TestCase):
|
class TestGame(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
"""
|
"""
|
||||||
Setup game.
|
Sets the game up.
|
||||||
"""
|
"""
|
||||||
self.game = Game()
|
self.game = Game()
|
||||||
self.game.new_game()
|
self.game.new_game()
|
||||||
|
@ -31,7 +31,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_load_game(self) -> None:
|
def test_load_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
Save a game and reload it.
|
Saves a game and reloads it.
|
||||||
"""
|
"""
|
||||||
bomb = Bomb()
|
bomb = Bomb()
|
||||||
self.game.map.add_entity(bomb)
|
self.game.map.add_entity(bomb)
|
||||||
|
@ -85,7 +85,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_bootstrap_fail(self) -> None:
|
def test_bootstrap_fail(self) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure that the test can't play the game,
|
Ensures that the test can't play the game,
|
||||||
because there is no associated shell.
|
because there is no associated shell.
|
||||||
Yeah, that's only for coverage.
|
Yeah, that's only for coverage.
|
||||||
"""
|
"""
|
||||||
|
@ -94,7 +94,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_key_translation(self) -> None:
|
def test_key_translation(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test key bindings.
|
Tests key bindings.
|
||||||
"""
|
"""
|
||||||
self.game.settings = Settings()
|
self.game.settings = Settings()
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_key_press(self) -> None:
|
def test_key_press(self) -> None:
|
||||||
"""
|
"""
|
||||||
Press a key and see what is done.
|
Presses a key and asserts what is done is correct.
|
||||||
"""
|
"""
|
||||||
self.assertEqual(self.game.state, GameMode.MAINMENU)
|
self.assertEqual(self.game.state, GameMode.MAINMENU)
|
||||||
self.assertEqual(self.game.main_menu.validate(),
|
self.assertEqual(self.game.main_menu.validate(),
|
||||||
|
@ -241,7 +241,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_mouse_click(self) -> None:
|
def test_mouse_click(self) -> None:
|
||||||
"""
|
"""
|
||||||
Simulate mouse clicks.
|
Simulates mouse clicks.
|
||||||
"""
|
"""
|
||||||
self.game.state = GameMode.MAINMENU
|
self.game.state = GameMode.MAINMENU
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_new_game(self) -> None:
|
def test_new_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure that the start button starts a new game.
|
Ensures that the start button starts a new game.
|
||||||
"""
|
"""
|
||||||
old_map = self.game.map
|
old_map = self.game.map
|
||||||
old_player = self.game.player
|
old_player = self.game.player
|
||||||
|
@ -294,7 +294,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_settings_menu(self) -> None:
|
def test_settings_menu(self) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure that the settings menu is working properly.
|
Ensures that the settings menu is working properly.
|
||||||
"""
|
"""
|
||||||
self.game.settings = Settings()
|
self.game.settings = Settings()
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_dead_screen(self) -> None:
|
def test_dead_screen(self) -> None:
|
||||||
"""
|
"""
|
||||||
Kill player and render dead screen.
|
Kills the player and renders the dead message on the fake screen.
|
||||||
"""
|
"""
|
||||||
self.game.state = GameMode.PLAY
|
self.game.state = GameMode.PLAY
|
||||||
# Kill player
|
# Kill player
|
||||||
|
@ -396,13 +396,13 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_not_implemented(self) -> None:
|
def test_not_implemented(self) -> None:
|
||||||
"""
|
"""
|
||||||
Check that some functions are not implemented, only for coverage.
|
Checks that some functions are not implemented, only for coverage.
|
||||||
"""
|
"""
|
||||||
self.assertRaises(NotImplementedError, Display.display, None)
|
self.assertRaises(NotImplementedError, Display.display, None)
|
||||||
|
|
||||||
def test_messages(self) -> None:
|
def test_messages(self) -> None:
|
||||||
"""
|
"""
|
||||||
Display error messages.
|
Displays error messages.
|
||||||
"""
|
"""
|
||||||
self.game.message = "I am an error"
|
self.game.message = "I am an error"
|
||||||
self.game.display_actions(DisplayActions.UPDATE)
|
self.game.display_actions(DisplayActions.UPDATE)
|
||||||
|
@ -412,7 +412,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_inventory_menu(self) -> None:
|
def test_inventory_menu(self) -> None:
|
||||||
"""
|
"""
|
||||||
Open the inventory menu and interact with items.
|
Opens the inventory menu and interacts with items.
|
||||||
"""
|
"""
|
||||||
self.game.state = GameMode.PLAY
|
self.game.state = GameMode.PLAY
|
||||||
# Open and close the inventory
|
# Open and close the inventory
|
||||||
|
@ -473,7 +473,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_talk_to_sunflowers(self) -> None:
|
def test_talk_to_sunflowers(self) -> None:
|
||||||
"""
|
"""
|
||||||
Interact with sunflowers
|
Interacts with sunflowers.
|
||||||
"""
|
"""
|
||||||
self.game.state = GameMode.PLAY
|
self.game.state = GameMode.PLAY
|
||||||
|
|
||||||
|
@ -524,7 +524,7 @@ class TestGame(unittest.TestCase):
|
||||||
|
|
||||||
def test_talk_to_merchant(self) -> None:
|
def test_talk_to_merchant(self) -> None:
|
||||||
"""
|
"""
|
||||||
Interact with merchants
|
Interacts with merchants.
|
||||||
"""
|
"""
|
||||||
self.game.state = GameMode.PLAY
|
self.game.state = GameMode.PLAY
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ from squirrelbattle.resources import ResourceManager
|
||||||
class TestInterfaces(unittest.TestCase):
|
class TestInterfaces(unittest.TestCase):
|
||||||
def test_map(self) -> None:
|
def test_map(self) -> None:
|
||||||
"""
|
"""
|
||||||
Create a map and check that it is well parsed.
|
Creates a map and checks that it is well parsed.
|
||||||
"""
|
"""
|
||||||
m = Map.load_from_string("0 0\n.#\n#.\n")
|
m = Map.load_from_string("0 0\n.#\n#.\n")
|
||||||
self.assertEqual(m.width, 2)
|
self.assertEqual(m.width, 2)
|
||||||
|
@ -20,7 +20,7 @@ class TestInterfaces(unittest.TestCase):
|
||||||
|
|
||||||
def test_load_map(self) -> None:
|
def test_load_map(self) -> None:
|
||||||
"""
|
"""
|
||||||
Try to load a map from a file.
|
Tries to load a map from a file.
|
||||||
"""
|
"""
|
||||||
m = Map.load(ResourceManager.get_asset_path("example_map.txt"))
|
m = Map.load(ResourceManager.get_asset_path("example_map.txt"))
|
||||||
self.assertEqual(m.width, 52)
|
self.assertEqual(m.width, 52)
|
||||||
|
@ -28,7 +28,7 @@ class TestInterfaces(unittest.TestCase):
|
||||||
|
|
||||||
def test_tiles(self) -> None:
|
def test_tiles(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test some things about tiles.
|
Tests some things about tiles.
|
||||||
"""
|
"""
|
||||||
self.assertFalse(Tile.FLOOR.is_wall())
|
self.assertFalse(Tile.FLOOR.is_wall())
|
||||||
self.assertTrue(Tile.WALL.is_wall())
|
self.assertTrue(Tile.WALL.is_wall())
|
||||||
|
|
|
@ -13,7 +13,7 @@ class TestSettings(unittest.TestCase):
|
||||||
|
|
||||||
def test_settings(self) -> None:
|
def test_settings(self) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure that settings are well loaded.
|
Ensures that settings are well loaded.
|
||||||
"""
|
"""
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
self.assertEqual(settings.KEY_UP_PRIMARY, 'z')
|
self.assertEqual(settings.KEY_UP_PRIMARY, 'z')
|
||||||
|
|
|
@ -11,7 +11,7 @@ class TestTranslations(unittest.TestCase):
|
||||||
|
|
||||||
def test_main_menu_translation(self) -> None:
|
def test_main_menu_translation(self) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure that the main menu is translated.
|
Ensures that the main menu is translated.
|
||||||
"""
|
"""
|
||||||
self.assertEqual(_("New game"), "Nouvelle partie")
|
self.assertEqual(_("New game"), "Nouvelle partie")
|
||||||
self.assertEqual(_("Resume"), "Continuer")
|
self.assertEqual(_("Resume"), "Continuer")
|
||||||
|
@ -22,7 +22,7 @@ class TestTranslations(unittest.TestCase):
|
||||||
|
|
||||||
def test_settings_menu_translation(self) -> None:
|
def test_settings_menu_translation(self) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure that the settings menu is translated.
|
Ensures that the settings menu is translated.
|
||||||
"""
|
"""
|
||||||
self.assertEqual(_("Main key to move up"),
|
self.assertEqual(_("Main key to move up"),
|
||||||
"Touche principale pour aller vers le haut")
|
"Touche principale pour aller vers le haut")
|
||||||
|
|
|
@ -13,7 +13,7 @@ class Translator:
|
||||||
"""
|
"""
|
||||||
This module uses gettext to translate strings.
|
This module uses gettext to translate strings.
|
||||||
Translator.setlocale defines the language of the strings,
|
Translator.setlocale defines the language of the strings,
|
||||||
then gettext() translates the message.
|
then gettext() translates the messages.
|
||||||
"""
|
"""
|
||||||
SUPPORTED_LOCALES: List[str] = ["de", "en", "es", "fr"]
|
SUPPORTED_LOCALES: List[str] = ["de", "en", "es", "fr"]
|
||||||
locale: str = "en"
|
locale: str = "en"
|
||||||
|
@ -22,7 +22,7 @@ class Translator:
|
||||||
@classmethod
|
@classmethod
|
||||||
def refresh_translations(cls) -> None:
|
def refresh_translations(cls) -> None:
|
||||||
"""
|
"""
|
||||||
Load compiled translations.
|
Loads compiled translations.
|
||||||
"""
|
"""
|
||||||
for language in cls.SUPPORTED_LOCALES:
|
for language in cls.SUPPORTED_LOCALES:
|
||||||
rep = Path(__file__).parent / "locale" / language / "LC_MESSAGES"
|
rep = Path(__file__).parent / "locale" / language / "LC_MESSAGES"
|
||||||
|
@ -37,7 +37,7 @@ class Translator:
|
||||||
@classmethod
|
@classmethod
|
||||||
def setlocale(cls, lang: str) -> None:
|
def setlocale(cls, lang: str) -> None:
|
||||||
"""
|
"""
|
||||||
Define the language used to translate the game.
|
Defines the language used to translate the game.
|
||||||
The language must be supported, otherwise nothing is done.
|
The language must be supported, otherwise nothing is done.
|
||||||
"""
|
"""
|
||||||
lang = lang[:2]
|
lang = lang[:2]
|
||||||
|
@ -51,7 +51,7 @@ class Translator:
|
||||||
@classmethod
|
@classmethod
|
||||||
def makemessages(cls) -> None: # pragma: no cover
|
def makemessages(cls) -> None: # pragma: no cover
|
||||||
"""
|
"""
|
||||||
Analyse all strings in the project and extract them.
|
Analyses all strings in the project and extracts them.
|
||||||
"""
|
"""
|
||||||
for language in cls.SUPPORTED_LOCALES:
|
for language in cls.SUPPORTED_LOCALES:
|
||||||
if language == "en":
|
if language == "en":
|
||||||
|
@ -83,7 +83,7 @@ class Translator:
|
||||||
@classmethod
|
@classmethod
|
||||||
def compilemessages(cls) -> None:
|
def compilemessages(cls) -> None:
|
||||||
"""
|
"""
|
||||||
Compile translation messages from source files.
|
Compiles translation messages from source files.
|
||||||
"""
|
"""
|
||||||
for language in cls.SUPPORTED_LOCALES:
|
for language in cls.SUPPORTED_LOCALES:
|
||||||
if language == "en":
|
if language == "en":
|
||||||
|
@ -99,7 +99,7 @@ class Translator:
|
||||||
|
|
||||||
def gettext(message: str) -> str:
|
def gettext(message: str) -> str:
|
||||||
"""
|
"""
|
||||||
Translate a message.
|
Translates a message.
|
||||||
"""
|
"""
|
||||||
return Translator.get_translator().gettext(message)
|
return Translator.get_translator().gettext(message)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue