Merge branch 'save_floors' into 'master'

Save floors

Closes #62 et #61

See merge request ynerant/squirrel-battle!58
This commit is contained in:
ynerant 2021-01-08 16:05:10 +01:00
commit 4a80dc36ad
13 changed files with 277 additions and 113 deletions

View File

@ -57,7 +57,7 @@ Dans le `pack de textures`_ ASCII, il est représenté par le caractère ``8``.
Dans le `pack de textures`_ écureuil, il est représenté par l'émoji ``🧸``. Dans le `pack de textures`_ écureuil, il est représenté par l'émoji ``🧸``.
Pyguargue Pygargue
--------- ---------
Son nom est fixé à `eagle`. Il a par défaut une force à **1000** et **5000** points de vie. Son nom est fixé à `eagle`. Il a par défaut une force à **1000** et **5000** points de vie.

View File

@ -22,7 +22,7 @@ Pack de textures
.. _Bouclier: entities/items.html#bouclier .. _Bouclier: entities/items.html#bouclier
.. _Hazel: ../index.html .. _Hazel: ../index.html
.. _Plastron: ../entities/items.html#plastron .. _Plastron: ../entities/items.html#plastron
.. _Pyguargue: ../entities/monsters.html#Pyguargue .. _Pygargue: ../entities/monsters.html#Pygargue
.. _Casque: ../entities/items.html#Casque .. _Casque: ../entities/items.html#Casque
.. _Anneau: ../entities/items.html#Anneau .. _Anneau: ../entities/items.html#Anneau
.. _Trompette: ../entities/items.html#Trompette .. _Trompette: ../entities/items.html#Trompette
@ -64,7 +64,7 @@ Chaque tuile fait un caractère de large.
* Bouclier_ : ``D`` * Bouclier_ : ``D``
* Hazel_ : ``¤`` * Hazel_ : ``¤``
* Plastron_ : ``(`` * Plastron_ : ``(``
* Pyguargue_ : ``µ`` * Pygargue_ : ``µ``
* Casque_ : ``0`` * Casque_ : ``0``
* Anneau_ : ``o`` * Anneau_ : ``o``
* Trompette_ : ``/`` * Trompette_ : ``/``
@ -95,7 +95,7 @@ Chaque tuile fait 2 caractères de large pour afficher les émojis proprement.
* Bouclier_ : ``🛡️`` * Bouclier_ : ``🛡️``
* Hazel_ : ``🌰`` * Hazel_ : ``🌰``
* Plastron_ : ``🦺`` * Plastron_ : ``🦺``
* Pyguargue_ : ``🦅`` * Pygargue_ : ``🦅``
* Casque_ : ``⛑️`` * Casque_ : ``⛑️``
* Anneau_ : ``💍`` * Anneau_ : ``💍``
* Trompette_ : ``🎺`` * Trompette_ : ``🎺``

View File

@ -3,8 +3,10 @@
import curses import curses
from ..entities.items import Monocle
from ..entities.player import Player from ..entities.player import Player
from ..game import Game from ..game import Game
from ..interfaces import FightingEntity
from ..translations import gettext as _ from ..translations import gettext as _
from .display import Display from .display import Display
@ -13,6 +15,7 @@ class StatsDisplay(Display):
""" """
A class to handle the display of the stats of the player. A class to handle the display of the stats of the player.
""" """
game: Game
player: Player player: Player
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -20,6 +23,7 @@ class StatsDisplay(Display):
self.pad = self.newpad(self.rows, self.cols) self.pad = self.newpad(self.rows, self.cols)
def update(self, game: Game) -> None: def update(self, game: Game) -> None:
self.game = game
self.player = game.player self.player = game.player
def update_pad(self) -> None: def update_pad(self) -> None:
@ -77,6 +81,47 @@ class StatsDisplay(Display):
self.addstr(self.pad, 15, 0, _("YOU ARE DEAD"), curses.COLOR_RED, self.addstr(self.pad, 15, 0, _("YOU ARE DEAD"), curses.COLOR_RED,
bold=True, blink=True, standout=True) bold=True, blink=True, standout=True)
if self.player.map.tiles[self.player.y][self.player.x].is_ladder():
msg = _("Use {key} to use the ladder") \
.format(key=self.game.settings.KEY_LADDER.upper())
self.addstr(self.pad, self.height - 2, 0, msg,
italic=True, reverse=True)
self.update_entities_stats()
def update_entities_stats(self) -> None:
"""
Display information about a near entity if we have a monocle.
"""
for dy, dx in [(-1, 0), (0, -1), (0, 1), (1, 0)]:
for entity in self.player.map.find_entities(FightingEntity):
if entity == self.player:
continue
if entity.y == self.player.y + dy \
and entity.x == self.player.x + dx:
if entity.is_friendly():
msg = _("Move to the friendly entity to talk to it") \
if self.game.waiting_for_friendly_key else \
_("Use {key} then move to talk to the entity") \
.format(key=self.game.settings.KEY_CHAT.upper())
self.addstr(self.pad, self.height - 1, 0, msg,
italic=True, reverse=True)
if isinstance(self.player.equipped_secondary, Monocle):
# Truth monocle
message = f"{entity.translated_name.capitalize()} " \
f"{self.pack[entity.name.upper()]}\n" \
f"STR {entity.strength}\n" \
f"INT {entity.intelligence}\n" \
f"CHR {entity.charisma}\n" \
f"DEX {entity.dexterity}\n" \
f"CON {entity.constitution}\n" \
f"CRI {entity.critical}%"
self.addstr(self.pad, 17, 0, message)
# Only display one entity
break
def display(self) -> None: def display(self) -> None:
self.pad.erase() self.pad.erase()
self.update_pad() self.update_pad()

View File

@ -84,6 +84,7 @@ TexturePack.ASCII_PACK = TexturePack(
HEDGEHOG='*', HEDGEHOG='*',
HELMET='0', HELMET='0',
MERCHANT='M', MERCHANT='M',
MONOCLE='ô',
PLAYER='@', PLAYER='@',
RABBIT='Y', RABBIT='Y',
RING_OF_CRITICAL_DAMAGE='o', RING_OF_CRITICAL_DAMAGE='o',
@ -121,6 +122,7 @@ TexturePack.SQUIRREL_PACK = TexturePack(
HELMET='⛑️ ', HELMET='⛑️ ',
PLAYER='🐿️ ', PLAYER='🐿️ ',
MERCHANT='🦜', MERCHANT='🦜',
MONOCLE='🧐',
RABBIT='🐇', RABBIT='🐇',
RING_OF_CRITICAL_DAMAGE='💍', RING_OF_CRITICAL_DAMAGE='💍',
RING_OF_MORE_EXPERIENCE='💍', RING_OF_MORE_EXPERIENCE='💍',

View File

@ -86,8 +86,8 @@ class Item(Entity):
""" """
Returns the list of all item classes. Returns the list of all item classes.
""" """
return [BodySnatchPotion, Bomb, Heart, Shield, Sword, return [BodySnatchPotion, Chestplate, Bomb, Heart, Helmet, Monocle,
Chestplate, Helmet, RingCritical, RingXP] Shield, Sword, RingCritical, RingXP]
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool: def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool:
""" """
@ -453,3 +453,9 @@ class RingXP(Ring):
experience: float = 2, *args, **kwargs): experience: float = 2, *args, **kwargs):
super().__init__(name=name, price=price, experience=experience, super().__init__(name=name, price=price, experience=experience,
*args, **kwargs) *args, **kwargs)
class Monocle(Item):
def __init__(self, name: str = "monocle", price: int = 10,
*args, **kwargs):
super().__init__(name=name, price=price, *args, **kwargs)

View File

@ -335,14 +335,16 @@ class Game:
""" """
Saves the game to a dictionary. Saves the game to a dictionary.
""" """
return self.map.save_state() return dict(map_index=self.map_index,
maps=[m.save_state() for m in self.maps])
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_index = d["map_index"]
self.maps = [Map().load_state(map_dict) for map_dict in d["maps"]]
except KeyError: except KeyError:
self.message = _("Some keys are missing in your save file.\n" self.message = _("Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted.") "Your save seems to be corrupt. It got deleted.")
@ -359,6 +361,8 @@ class Game:
return return
self.player = players[0] self.player = players[0]
self.map.compute_visibility(self.player.y, self.player.x,
self.player.vision)
self.display_actions(DisplayActions.UPDATE) self.display_actions(DisplayActions.UPDATE)
def load_game(self) -> None: def load_game(self) -> None:

View File

@ -80,18 +80,18 @@ class Map:
currentx: int currentx: int
currenty: int currenty: int
def __init__(self, width: int, height: int, tiles: list, def __init__(self, width: int = 0, height: int = 0, tiles: list = None,
start_y: int, start_x: int): start_y: int = 0, start_x: int = 0):
self.floor = 0 self.floor = 0
self.width = width self.width = width
self.height = height self.height = height
self.start_y = start_y self.start_y = start_y
self.start_x = start_x self.start_x = start_x
self.tiles = tiles self.tiles = tiles or []
self.visibility = [[False for _ in range(len(tiles[0]))] self.visibility = [[False for _ in range(len(self.tiles[0]))]
for _ in range(len(tiles))] for _ in range(len(self.tiles))]
self.seen_tiles = [[False for _ in range(len(tiles[0]))] self.seen_tiles = [[False for _ in range(len(tiles[0]))]
for _ in range(len(tiles))] for _ in range(len(self.tiles))]
self.entities = [] self.entities = []
self.logs = Logs() self.logs = Logs()
@ -338,9 +338,10 @@ class Map:
for enti in self.entities: for enti in self.entities:
d["entities"].append(enti.save_state()) d["entities"].append(enti.save_state())
d["map"] = self.draw_string(TexturePack.ASCII_PACK) d["map"] = self.draw_string(TexturePack.ASCII_PACK)
d["seen_tiles"] = self.seen_tiles
return d return d
def load_state(self, d: dict) -> None: def load_state(self, d: dict) -> "Map":
""" """
Loads the map's attributes from a dictionary. Loads the map's attributes from a dictionary.
""" """
@ -351,11 +352,16 @@ class Map:
self.currentx = d["currentx"] self.currentx = d["currentx"]
self.currenty = d["currenty"] self.currenty = d["currenty"]
self.tiles = self.load_dungeon_from_string(d["map"]) self.tiles = self.load_dungeon_from_string(d["map"])
self.seen_tiles = d["seen_tiles"]
self.visibility = [[False for _ in range(len(self.tiles[0]))]
for _ in range(len(self.tiles))]
self.entities = [] self.entities = []
dictclasses = Entity.get_all_entity_classes_in_a_dict() dictclasses = Entity.get_all_entity_classes_in_a_dict()
for entisave in d["entities"]: for entisave in d["entities"]:
self.add_entity(dictclasses[entisave["type"]](**entisave)) self.add_entity(dictclasses[entisave["type"]](**entisave))
return self
class Tile(Enum): class Tile(Enum):
""" """
@ -629,24 +635,26 @@ class Entity:
from squirrelbattle.entities.friendly import Merchant, Sunflower, \ from squirrelbattle.entities.friendly import Merchant, Sunflower, \
Trumpet Trumpet
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, \ from squirrelbattle.entities.items import BodySnatchPotion, Bomb, \
Heart, Sword, Shield, Chestplate, Helmet, RingCritical, RingXP Heart, Monocle, Sword, Shield, Chestplate, Helmet, \
RingCritical, RingXP
return { return {
"Tiger": Tiger,
"Bomb": Bomb, "Bomb": Bomb,
"Chestplate": Chestplate,
"Heart": Heart, "Heart": Heart,
"BodySnatchPotion": BodySnatchPotion, "BodySnatchPotion": BodySnatchPotion,
"Eagle": GiantSeaEagle,
"Hedgehog": Hedgehog, "Hedgehog": Hedgehog,
"Rabbit": Rabbit, "Helmet": Helmet,
"TeddyBear": TeddyBear,
"Player": Player, "Player": Player,
"Merchant": Merchant, "Merchant": Merchant,
"Monocle": Monocle,
"Sunflower": Sunflower, "Sunflower": Sunflower,
"Sword": Sword, "Sword": Sword,
"Trumpet": Trumpet, "Trumpet": Trumpet,
"Eagle": GiantSeaEagle,
"Shield": Shield, "Shield": Shield,
"Chestplate": Chestplate, "TeddyBear": TeddyBear,
"Helmet": Helmet, "Tiger": Tiger,
"Rabbit": Rabbit,
"RingCritical": RingCritical, "RingCritical": RingCritical,
"RingXP": RingXP, "RingXP": RingXP,
} }

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n" "Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" "Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-08 12:03+0100\n" "POT-Creation-Date: 2021-01-08 15:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,6 +17,12 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
msgid "ring_of_critical_damage"
msgstr ""
msgid "ring_of_more_experience"
msgstr ""
#, python-brace-format #, python-brace-format
msgid "{name} takes {amount} damage." msgid "{name} takes {amount} damage."
msgstr "{name} nimmt {amount} Schadenspunkte." msgstr "{name} nimmt {amount} Schadenspunkte."
@ -43,30 +49,44 @@ msgstr "BESTAND"
msgid "STALL" msgid "STALL"
msgstr "STAND" msgstr "STAND"
#: squirrelbattle/display/statsdisplay.py:40 #: squirrelbattle/display/statsdisplay.py:44
msgid "Inventory:" msgid "Inventory:"
msgstr "Bestand:" msgstr "Bestand:"
#: squirrelbattle/display/statsdisplay.py:57 #: squirrelbattle/display/statsdisplay.py:61
msgid "Equipped main:" msgid "Equipped main:"
msgstr "" msgstr ""
#: squirrelbattle/display/statsdisplay.py:61 #: squirrelbattle/display/statsdisplay.py:65
msgid "Equipped secondary:" msgid "Equipped secondary:"
msgstr "" msgstr ""
#: squirrelbattle/display/statsdisplay.py:66 #: squirrelbattle/display/statsdisplay.py:70
msgid "Equipped chestplate:" msgid "Equipped chestplate:"
msgstr "" msgstr ""
#: squirrelbattle/display/statsdisplay.py:70 #: squirrelbattle/display/statsdisplay.py:74
msgid "Equipped helmet:" msgid "Equipped helmet:"
msgstr "" msgstr ""
#: squirrelbattle/display/statsdisplay.py:77 #: squirrelbattle/display/statsdisplay.py:81
msgid "YOU ARE DEAD" msgid "YOU ARE DEAD"
msgstr "SIE WURDEN GESTORBEN" msgstr "SIE WURDEN GESTORBEN"
#: squirrelbattle/display/statsdisplay.py:85
#, python-brace-format
msgid "Use {key} to use the ladder"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:94
msgid "Move to the friendly entity to talk to it"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:96
#, python-brace-format
msgid "Use {key} then move to talk to the entity"
msgstr ""
#. TODO #. TODO
#: squirrelbattle/entities/friendly.py:33 #: squirrelbattle/entities/friendly.py:33
msgid "I don't sell any squirrel" msgid "I don't sell any squirrel"
@ -106,7 +126,7 @@ msgstr "Der Spieler klettert auf dem Stock {floor} hinoben."
msgid "The buyer does not have enough money" msgid "The buyer does not have enough money"
msgstr "Der Kaufer hat nicht genug Geld" msgstr "Der Kaufer hat nicht genug Geld"
#: squirrelbattle/game.py:347 #: squirrelbattle/game.py:349
msgid "" msgid ""
"Some keys are missing in your save file.\n" "Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted." "Your save seems to be corrupt. It got deleted."
@ -114,7 +134,7 @@ msgstr ""
"In Ihrer Speicherdatei fehlen einige Schlüssel.\n" "In Ihrer Speicherdatei fehlen einige Schlüssel.\n"
"Ihre Speicherung scheint korrupt zu sein. Es wird gelöscht." "Ihre Speicherung scheint korrupt zu sein. Es wird gelöscht."
#: squirrelbattle/game.py:355 #: squirrelbattle/game.py:357
msgid "" msgid ""
"No player was found on this map!\n" "No player was found on this map!\n"
"Maybe you died?" "Maybe you died?"
@ -122,7 +142,7 @@ msgstr ""
"Auf dieser Karte wurde kein Spieler gefunden!\n" "Auf dieser Karte wurde kein Spieler gefunden!\n"
"Vielleicht sind Sie gestorben?" "Vielleicht sind Sie gestorben?"
#: squirrelbattle/game.py:375 #: squirrelbattle/game.py:379
msgid "" msgid ""
"The JSON file is not correct.\n" "The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted." "Your save seems corrupted. It got deleted."
@ -130,26 +150,26 @@ msgstr ""
"Die JSON-Datei ist nicht korrekt.\n" "Die JSON-Datei ist nicht korrekt.\n"
"Ihre Speicherung scheint korrumpiert. Sie wurde gelöscht." "Ihre Speicherung scheint korrumpiert. Sie wurde gelöscht."
#: squirrelbattle/interfaces.py:712 #: squirrelbattle/interfaces.py:718
msgid "It's a critical hit!" msgid "It's a critical hit!"
msgstr "" msgstr ""
#: squirrelbattle/interfaces.py:713 #: squirrelbattle/interfaces.py:719
#, python-brace-format #, python-brace-format
msgid "{name} hits {opponent}." msgid "{name} hits {opponent}."
msgstr "{name} schlägt {opponent}." msgstr "{name} schlägt {opponent}."
#: squirrelbattle/interfaces.py:727 #: squirrelbattle/interfaces.py:733
#, python-brace-format #, python-brace-format
msgid "{name} takes {damage} damage." msgid "{name} takes {damage} damage."
msgstr "" msgstr ""
#: squirrelbattle/interfaces.py:729 #: squirrelbattle/interfaces.py:735
#, python-brace-format #, python-brace-format
msgid "{name} dies." msgid "{name} dies."
msgstr "{name} stirbt." msgstr "{name} stirbt."
#: squirrelbattle/interfaces.py:763 #: squirrelbattle/interfaces.py:769
#, python-brace-format #, python-brace-format
msgid "{entity} said: {message}" msgid "{entity} said: {message}"
msgstr "{entity} hat gesagt: {message}" msgstr "{entity} hat gesagt: {message}"
@ -284,42 +304,50 @@ msgstr "Teddybär"
msgid "tiger" msgid "tiger"
msgstr "Tiger" msgstr "Tiger"
#: squirrelbattle/tests/translations_test.py:71 #: squirrelbattle/tests/translations_test.py:70
msgid "eagle"
msgstr ""
#: squirrelbattle/tests/translations_test.py:72
msgid "body snatch potion" msgid "body snatch potion"
msgstr "Leichenfleddererzaubertrank" msgstr "Leichenfleddererzaubertrank"
#: squirrelbattle/tests/translations_test.py:72 #: squirrelbattle/tests/translations_test.py:73
msgid "bomb" msgid "bomb"
msgstr "Bombe" msgstr "Bombe"
#: squirrelbattle/tests/translations_test.py:73 #: squirrelbattle/tests/translations_test.py:74
msgid "explosion" msgid "explosion"
msgstr "Explosion" msgstr "Explosion"
#: squirrelbattle/tests/translations_test.py:74 #: squirrelbattle/tests/translations_test.py:75
msgid "heart" msgid "heart"
msgstr "Herz" msgstr "Herz"
#: squirrelbattle/tests/translations_test.py:75 #: squirrelbattle/tests/translations_test.py:76
msgid "sword" msgid "sword"
msgstr "schwert" msgstr "schwert"
#: squirrelbattle/tests/translations_test.py:76 #: squirrelbattle/tests/translations_test.py:77
msgid "helmet" msgid "helmet"
msgstr "" msgstr ""
#: squirrelbattle/tests/translations_test.py:77 #: squirrelbattle/tests/translations_test.py:78
msgid "chestplate" msgid "chestplate"
msgstr "" msgstr ""
#: squirrelbattle/tests/translations_test.py:78 #: squirrelbattle/tests/translations_test.py:79
msgid "shield" msgid "shield"
msgstr "" msgstr ""
#: squirrelbattle/tests/translations_test.py:79 #: squirrelbattle/tests/translations_test.py:80
msgid "ring_of_critical_damage" msgid "ring of critical damage"
msgstr "" msgstr ""
#: squirrelbattle/tests/translations_test.py:81 #: squirrelbattle/tests/translations_test.py:82
msgid "ring_of_more_experience" msgid "ring of more experience"
msgstr ""
#: squirrelbattle/tests/translations_test.py:84
msgid "monocle"
msgstr "" msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n" "Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" "Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-08 12:03+0100\n" "POT-Creation-Date: 2021-01-08 15:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,6 +17,12 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
msgid "ring_of_critical_damage"
msgstr ""
msgid "ring_of_more_experience"
msgstr ""
#, python-brace-format #, python-brace-format
msgid "{name} takes {amount} damage." msgid "{name} takes {amount} damage."
msgstr "{name} recibe {amount} daño." msgstr "{name} recibe {amount} daño."
@ -43,30 +49,44 @@ msgstr "INVENTORIO"
msgid "STALL" msgid "STALL"
msgstr "PUESTO" msgstr "PUESTO"
#: squirrelbattle/display/statsdisplay.py:40 #: squirrelbattle/display/statsdisplay.py:44
msgid "Inventory:" msgid "Inventory:"
msgstr "Inventorio :" msgstr "Inventorio :"
#: squirrelbattle/display/statsdisplay.py:57 #: squirrelbattle/display/statsdisplay.py:61
msgid "Equipped main:" msgid "Equipped main:"
msgstr "" msgstr ""
#: squirrelbattle/display/statsdisplay.py:61 #: squirrelbattle/display/statsdisplay.py:65
msgid "Equipped secondary:" msgid "Equipped secondary:"
msgstr "" msgstr ""
#: squirrelbattle/display/statsdisplay.py:66 #: squirrelbattle/display/statsdisplay.py:70
msgid "Equipped chestplate:" msgid "Equipped chestplate:"
msgstr "" msgstr ""
#: squirrelbattle/display/statsdisplay.py:70 #: squirrelbattle/display/statsdisplay.py:74
msgid "Equipped helmet:" msgid "Equipped helmet:"
msgstr "" msgstr ""
#: squirrelbattle/display/statsdisplay.py:77 #: squirrelbattle/display/statsdisplay.py:81
msgid "YOU ARE DEAD" msgid "YOU ARE DEAD"
msgstr "ERES MUERTO" msgstr "ERES MUERTO"
#: squirrelbattle/display/statsdisplay.py:85
#, python-brace-format
msgid "Use {key} to use the ladder"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:94
msgid "Move to the friendly entity to talk to it"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:96
#, python-brace-format
msgid "Use {key} then move to talk to the entity"
msgstr ""
#: squirrelbattle/entities/friendly.py:33 #: squirrelbattle/entities/friendly.py:33
msgid "I don't sell any squirrel" msgid "I don't sell any squirrel"
msgstr "No vendo ninguna ardilla" msgstr "No vendo ninguna ardilla"
@ -105,7 +125,7 @@ msgstr ""
msgid "The buyer does not have enough money" msgid "The buyer does not have enough money"
msgstr "El comprador no tiene suficiente dinero" msgstr "El comprador no tiene suficiente dinero"
#: squirrelbattle/game.py:347 #: squirrelbattle/game.py:349
msgid "" msgid ""
"Some keys are missing in your save file.\n" "Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted." "Your save seems to be corrupt. It got deleted."
@ -113,7 +133,7 @@ msgstr ""
"Algunas claves faltan en su archivo de guarda.\n" "Algunas claves faltan en su archivo de guarda.\n"
"Su guarda parece a ser corruptido. Fue eliminado." "Su guarda parece a ser corruptido. Fue eliminado."
#: squirrelbattle/game.py:355 #: squirrelbattle/game.py:357
msgid "" msgid ""
"No player was found on this map!\n" "No player was found on this map!\n"
"Maybe you died?" "Maybe you died?"
@ -121,7 +141,7 @@ msgstr ""
"No jugador encontrado sobre la carta !\n" "No jugador encontrado sobre la carta !\n"
"¿ Quizas murió ?" "¿ Quizas murió ?"
#: squirrelbattle/game.py:375 #: squirrelbattle/game.py:379
msgid "" msgid ""
"The JSON file is not correct.\n" "The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted." "Your save seems corrupted. It got deleted."
@ -129,26 +149,26 @@ msgstr ""
"El JSON archivo no es correcto.\n" "El JSON archivo no es correcto.\n"
"Su guarda parece corrupta. Fue eliminada." "Su guarda parece corrupta. Fue eliminada."
#: squirrelbattle/interfaces.py:712 #: squirrelbattle/interfaces.py:718
msgid "It's a critical hit!" msgid "It's a critical hit!"
msgstr "" msgstr ""
#: squirrelbattle/interfaces.py:713 #: squirrelbattle/interfaces.py:719
#, python-brace-format #, python-brace-format
msgid "{name} hits {opponent}." msgid "{name} hits {opponent}."
msgstr "{name} golpea a {opponent}." msgstr "{name} golpea a {opponent}."
#: squirrelbattle/interfaces.py:727 #: squirrelbattle/interfaces.py:733
#, python-brace-format #, python-brace-format
msgid "{name} takes {damage} damage." msgid "{name} takes {damage} damage."
msgstr "" msgstr ""
#: squirrelbattle/interfaces.py:729 #: squirrelbattle/interfaces.py:735
#, python-brace-format #, python-brace-format
msgid "{name} dies." msgid "{name} dies."
msgstr "{name} se muere." msgstr "{name} se muere."
#: squirrelbattle/interfaces.py:763 #: squirrelbattle/interfaces.py:769
#, python-brace-format #, python-brace-format
msgid "{entity} said: {message}" msgid "{entity} said: {message}"
msgstr "{entity} dijo : {message}" msgstr "{entity} dijo : {message}"
@ -283,42 +303,50 @@ msgstr "osito de peluche"
msgid "tiger" msgid "tiger"
msgstr "tigre" msgstr "tigre"
#: squirrelbattle/tests/translations_test.py:71 #: squirrelbattle/tests/translations_test.py:70
msgid "eagle"
msgstr ""
#: squirrelbattle/tests/translations_test.py:72
msgid "body snatch potion" msgid "body snatch potion"
msgstr "poción de intercambio" msgstr "poción de intercambio"
#: squirrelbattle/tests/translations_test.py:72 #: squirrelbattle/tests/translations_test.py:73
msgid "bomb" msgid "bomb"
msgstr "bomba" msgstr "bomba"
#: squirrelbattle/tests/translations_test.py:73 #: squirrelbattle/tests/translations_test.py:74
msgid "explosion" msgid "explosion"
msgstr "explosión" msgstr "explosión"
#: squirrelbattle/tests/translations_test.py:74 #: squirrelbattle/tests/translations_test.py:75
msgid "heart" msgid "heart"
msgstr "corazón" msgstr "corazón"
#: squirrelbattle/tests/translations_test.py:75 #: squirrelbattle/tests/translations_test.py:76
msgid "sword" msgid "sword"
msgstr "espada" msgstr "espada"
#: squirrelbattle/tests/translations_test.py:76 #: squirrelbattle/tests/translations_test.py:77
msgid "helmet" msgid "helmet"
msgstr "" msgstr ""
#: squirrelbattle/tests/translations_test.py:77 #: squirrelbattle/tests/translations_test.py:78
msgid "chestplate" msgid "chestplate"
msgstr "" msgstr ""
#: squirrelbattle/tests/translations_test.py:78 #: squirrelbattle/tests/translations_test.py:79
msgid "shield" msgid "shield"
msgstr "" msgstr ""
#: squirrelbattle/tests/translations_test.py:79 #: squirrelbattle/tests/translations_test.py:80
msgid "ring_of_critical_damage" msgid "ring of critical damage"
msgstr "" msgstr ""
#: squirrelbattle/tests/translations_test.py:81 #: squirrelbattle/tests/translations_test.py:82
msgid "ring_of_more_experience" msgid "ring of more experience"
msgstr ""
#: squirrelbattle/tests/translations_test.py:84
msgid "monocle"
msgstr "" msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n" "Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" "Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-08 12:03+0100\n" "POT-Creation-Date: 2021-01-08 15:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -43,30 +43,44 @@ msgstr "INVENTAIRE"
msgid "STALL" msgid "STALL"
msgstr "STAND" msgstr "STAND"
#: squirrelbattle/display/statsdisplay.py:40 #: squirrelbattle/display/statsdisplay.py:44
msgid "Inventory:" msgid "Inventory:"
msgstr "Inventaire :" msgstr "Inventaire :"
#: squirrelbattle/display/statsdisplay.py:57 #: squirrelbattle/display/statsdisplay.py:61
msgid "Equipped main:" msgid "Equipped main:"
msgstr "Équipement principal :" msgstr "Équipement principal :"
#: squirrelbattle/display/statsdisplay.py:61 #: squirrelbattle/display/statsdisplay.py:65
msgid "Equipped secondary:" msgid "Equipped secondary:"
msgstr "Équipement secondaire :" msgstr "Équipement secondaire :"
#: squirrelbattle/display/statsdisplay.py:66 #: squirrelbattle/display/statsdisplay.py:70
msgid "Equipped chestplate:" msgid "Equipped chestplate:"
msgstr "Plastron équipé :" msgstr "Plastron équipé :"
#: squirrelbattle/display/statsdisplay.py:70 #: squirrelbattle/display/statsdisplay.py:74
msgid "Equipped helmet:" msgid "Equipped helmet:"
msgstr "Casque équipé :" msgstr "Casque équipé :"
#: squirrelbattle/display/statsdisplay.py:77 #: squirrelbattle/display/statsdisplay.py:81
msgid "YOU ARE DEAD" msgid "YOU ARE DEAD"
msgstr "VOUS ÊTES MORT" msgstr "VOUS ÊTES MORT"
#: squirrelbattle/display/statsdisplay.py:85
#, python-brace-format
msgid "Use {key} to use the ladder"
msgstr "Appuyez sur {key} pour utiliser l'échelle"
#: squirrelbattle/display/statsdisplay.py:94
msgid "Move to the friendly entity to talk to it"
msgstr "Avancez vers l'entité pour lui parler"
#: squirrelbattle/display/statsdisplay.py:96
#, python-brace-format
msgid "Use {key} then move to talk to the entity"
msgstr "Appuyez sur {key} puis déplacez-vous pour parler"
#. TODO #. TODO
#: squirrelbattle/entities/friendly.py:33 #: squirrelbattle/entities/friendly.py:33
msgid "I don't sell any squirrel" msgid "I don't sell any squirrel"
@ -106,7 +120,7 @@ msgstr "Le joueur monte à l'étage {floor}."
msgid "The buyer does not have enough money" msgid "The buyer does not have enough money"
msgstr "L'acheteur n'a pas assez d'argent" msgstr "L'acheteur n'a pas assez d'argent"
#: squirrelbattle/game.py:347 #: squirrelbattle/game.py:349
msgid "" msgid ""
"Some keys are missing in your save file.\n" "Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted." "Your save seems to be corrupt. It got deleted."
@ -114,7 +128,7 @@ msgstr ""
"Certaines clés de votre ficher de sauvegarde sont manquantes.\n" "Certaines clés de votre ficher de sauvegarde sont manquantes.\n"
"Votre sauvegarde semble corrompue. Elle a été supprimée." "Votre sauvegarde semble corrompue. Elle a été supprimée."
#: squirrelbattle/game.py:355 #: squirrelbattle/game.py:357
msgid "" msgid ""
"No player was found on this map!\n" "No player was found on this map!\n"
"Maybe you died?" "Maybe you died?"
@ -122,7 +136,7 @@ msgstr ""
"Aucun joueur n'a été trouvé sur la carte !\n" "Aucun joueur n'a été trouvé sur la carte !\n"
"Peut-être êtes-vous mort ?" "Peut-être êtes-vous mort ?"
#: squirrelbattle/game.py:375 #: squirrelbattle/game.py:379
msgid "" msgid ""
"The JSON file is not correct.\n" "The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted." "Your save seems corrupted. It got deleted."
@ -130,26 +144,26 @@ msgstr ""
"Le fichier JSON de sauvegarde est incorrect.\n" "Le fichier JSON de sauvegarde est incorrect.\n"
"Votre sauvegarde semble corrompue. Elle a été supprimée." "Votre sauvegarde semble corrompue. Elle a été supprimée."
#: squirrelbattle/interfaces.py:712 #: squirrelbattle/interfaces.py:718
msgid "It's a critical hit!" msgid "It's a critical hit!"
msgstr "C'est un coup critique !" msgstr "C'est un coup critique !"
#: squirrelbattle/interfaces.py:713 #: squirrelbattle/interfaces.py:719
#, python-brace-format #, python-brace-format
msgid "{name} hits {opponent}." msgid "{name} hits {opponent}."
msgstr "{name} frappe {opponent}." msgstr "{name} frappe {opponent}."
#: squirrelbattle/interfaces.py:727 #: squirrelbattle/interfaces.py:733
#, python-brace-format #, python-brace-format
msgid "{name} takes {damage} damage." msgid "{name} takes {damage} damage."
msgstr "{name} prend {damage} dégâts." msgstr "{name} prend {damage} dégâts."
#: squirrelbattle/interfaces.py:729 #: squirrelbattle/interfaces.py:735
#, python-brace-format #, python-brace-format
msgid "{name} dies." msgid "{name} dies."
msgstr "{name} meurt." msgstr "{name} meurt."
#: squirrelbattle/interfaces.py:763 #: squirrelbattle/interfaces.py:769
#, python-brace-format #, python-brace-format
msgid "{entity} said: {message}" msgid "{entity} said: {message}"
msgstr "{entity} a dit : {message}" msgstr "{entity} a dit : {message}"
@ -284,42 +298,50 @@ msgstr "nounours"
msgid "tiger" msgid "tiger"
msgstr "tigre" msgstr "tigre"
#: squirrelbattle/tests/translations_test.py:71 #: squirrelbattle/tests/translations_test.py:70
msgid "eagle"
msgstr "pygargue"
#: squirrelbattle/tests/translations_test.py:72
msgid "body snatch potion" msgid "body snatch potion"
msgstr "potion d'arrachage de corps" msgstr "potion d'arrachage de corps"
#: squirrelbattle/tests/translations_test.py:72 #: squirrelbattle/tests/translations_test.py:73
msgid "bomb" msgid "bomb"
msgstr "bombe" msgstr "bombe"
#: squirrelbattle/tests/translations_test.py:73 #: squirrelbattle/tests/translations_test.py:74
msgid "explosion" msgid "explosion"
msgstr "explosion" msgstr "explosion"
#: squirrelbattle/tests/translations_test.py:74 #: squirrelbattle/tests/translations_test.py:75
msgid "heart" msgid "heart"
msgstr "cœur" msgstr "cœur"
#: squirrelbattle/tests/translations_test.py:75 #: squirrelbattle/tests/translations_test.py:76
msgid "sword" msgid "sword"
msgstr "épée" msgstr "épée"
#: squirrelbattle/tests/translations_test.py:76 #: squirrelbattle/tests/translations_test.py:77
msgid "helmet" msgid "helmet"
msgstr "casque" msgstr "casque"
#: squirrelbattle/tests/translations_test.py:77 #: squirrelbattle/tests/translations_test.py:78
msgid "chestplate" msgid "chestplate"
msgstr "plastron" msgstr "plastron"
#: squirrelbattle/tests/translations_test.py:78 #: squirrelbattle/tests/translations_test.py:79
msgid "shield" msgid "shield"
msgstr "bouclier" msgstr "bouclier"
#: squirrelbattle/tests/translations_test.py:79 #: squirrelbattle/tests/translations_test.py:80
msgid "ring of critical damage" msgid "ring of critical damage"
msgstr "anneau de coup critique" msgstr "anneau de coup critique"
#: squirrelbattle/tests/translations_test.py:81 #: squirrelbattle/tests/translations_test.py:82
msgid "ring of more experience" msgid "ring of more experience"
msgstr "anneau de plus d'expérience" msgstr "anneau de plus d'expérience"
#: squirrelbattle/tests/translations_test.py:84
msgid "monocle"
msgstr "monocle"

View File

@ -1,11 +1,12 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse # Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import random
import unittest import unittest
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart, Item, \ from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart, Item, \
Explosion Explosion
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, TeddyBear from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit,\
TeddyBear, GiantSeaEagle
from squirrelbattle.entities.friendly import Trumpet from squirrelbattle.entities.friendly import Trumpet
from squirrelbattle.entities.player import Player from squirrelbattle.entities.player import Player
from squirrelbattle.interfaces import Entity, Map from squirrelbattle.interfaces import Entity, Map
@ -264,3 +265,17 @@ class TestEntities(unittest.TestCase):
player_state = player.save_state() player_state = player.save_state()
self.assertEqual(player_state["current_xp"], 10) self.assertEqual(player_state["current_xp"], 10)
def test_critical_hit(self) -> None:
"""
Ensure that critical hits are working.
"""
random.seed(2) # Next random.randint(1, 100) will output 8
self.player.critical = 10
sea_eagle = GiantSeaEagle()
self.map.add_entity(sea_eagle)
sea_eagle.move(2, 6)
old_health = sea_eagle.health
self.player.hit(sea_eagle)
self.assertEqual(sea_eagle.health,
old_health - self.player.strength * 4)

View File

@ -1,8 +1,8 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse # Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import curses import curses
import os import os
import random
import unittest import unittest
from ..bootstrap import Bootstrap from ..bootstrap import Bootstrap
@ -10,7 +10,7 @@ from ..display.display import Display
from ..display.display_manager import DisplayManager from ..display.display_manager import DisplayManager
from ..entities.friendly import Merchant, Sunflower from ..entities.friendly import Merchant, Sunflower
from ..entities.items import Bomb, Heart, Sword, Explosion, Shield, Helmet, \ from ..entities.items import Bomb, Heart, Sword, Explosion, Shield, Helmet, \
Chestplate, RingCritical Chestplate, RingCritical, Monocle
from ..entities.monsters import GiantSeaEagle from ..entities.monsters import GiantSeaEagle
from ..entities.player import Player from ..entities.player import Player
from ..enums import DisplayActions from ..enums import DisplayActions
@ -66,6 +66,7 @@ class TestGame(unittest.TestCase):
new_state = self.game.save_state() new_state = self.game.save_state()
self.assertEqual(old_state, new_state) self.assertEqual(old_state, new_state)
self.assertIsNone(self.game.message)
# Ensure that the bomb is loaded # Ensure that the bomb is loaded
self.assertTrue(self.game.player.inventory) self.assertTrue(self.game.player.inventory)
@ -583,6 +584,7 @@ class TestGame(unittest.TestCase):
# Buy a heart # Buy a heart
merchant.inventory[1] = Heart() merchant.inventory[1] = Heart()
self.game.display_actions(DisplayActions.REFRESH)
item = self.game.store_menu.validate() item = self.game.store_menu.validate()
self.assertIn(item, merchant.inventory) self.assertIn(item, merchant.inventory)
self.assertEqual(item, merchant.inventory[1]) self.assertEqual(item, merchant.inventory[1])
@ -701,19 +703,21 @@ class TestGame(unittest.TestCase):
self.game.save_state() self.game.save_state()
ring.unequip() ring.unequip()
def test_critical_hit(self) -> None: def test_monocle(self) -> None:
""" """
Ensure that critical hits are working. The player is wearing a monocle, then the stats are displayed.
""" """
random.seed(2) # Next random.randint(1, 100) will output 8 self.game.state = GameMode.PLAY
self.game.player.critical = 10
monocle = Monocle()
monocle.hold(self.game.player)
monocle.equip()
sea_eagle = GiantSeaEagle() sea_eagle = GiantSeaEagle()
self.game.map.add_entity(sea_eagle) self.game.map.add_entity(sea_eagle)
sea_eagle.move(2, 6) sea_eagle.move(2, 6)
old_health = sea_eagle.health
self.game.player.hit(sea_eagle) self.game.display_actions(DisplayActions.REFRESH)
self.assertEqual(sea_eagle.health,
old_health - self.game.player.strength * 4)
def test_ladders(self) -> None: def test_ladders(self) -> None:
""" """

View File

@ -67,6 +67,7 @@ class TestTranslations(unittest.TestCase):
self.assertEqual(_("sunflower"), "tournesol") self.assertEqual(_("sunflower"), "tournesol")
self.assertEqual(_("teddy bear"), "nounours") self.assertEqual(_("teddy bear"), "nounours")
self.assertEqual(_("tiger"), "tigre") self.assertEqual(_("tiger"), "tigre")
self.assertEqual(_("eagle"), "pygargue")
self.assertEqual(_("body snatch potion"), "potion d'arrachage de corps") self.assertEqual(_("body snatch potion"), "potion d'arrachage de corps")
self.assertEqual(_("bomb"), "bombe") self.assertEqual(_("bomb"), "bombe")
@ -80,3 +81,4 @@ class TestTranslations(unittest.TestCase):
"anneau de coup critique") "anneau de coup critique")
self.assertEqual(_("ring of more experience"), self.assertEqual(_("ring of more experience"),
"anneau de plus d'expérience") "anneau de plus d'expérience")
self.assertEqual(_("monocle"), "monocle")