Merge branch 'master' into 'moreitems'

# Conflicts:
#   squirrelbattle/entities/items.py
#   squirrelbattle/interfaces.py
#   squirrelbattle/tests/game_test.py
This commit is contained in:
eichhornchen 2021-01-08 23:41:21 +01:00
commit eac9057f31
20 changed files with 503 additions and 180 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 ``🧸``.
Pyguargue
Pygargue
---------
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
.. _Hazel: ../index.html
.. _Plastron: ../entities/items.html#plastron
.. _Pyguargue: ../entities/monsters.html#Pyguargue
.. _Pygargue: ../entities/monsters.html#Pygargue
.. _Casque: ../entities/items.html#Casque
.. _Anneau: ../entities/items.html#Anneau
.. _Trompette: ../entities/items.html#Trompette
@ -64,7 +64,7 @@ Chaque tuile fait un caractère de large.
* Bouclier_ : ``D``
* Hazel_ : ``¤``
* Plastron_ : ``(``
* Pyguargue_ : ``µ``
* Pygargue_ : ``µ``
* Casque_ : ``0``
* Anneau_ : ``o``
* Trompette_ : ``/``
@ -95,7 +95,7 @@ Chaque tuile fait 2 caractères de large pour afficher les émojis proprement.
* Bouclier_ : ``🛡️``
* Hazel_ : ``🌰``
* Plastron_ : ``🦺``
* Pyguargue_ : ``🦅``
* Pygargue_ : ``🦅``
* Casque_ : ``⛑️``
* Anneau_ : ``💍``
* Trompette_ : ``🎺``

View File

@ -92,6 +92,6 @@ class CreditsDisplay(Display):
self.addstr(self.pad, y_offset + i, x_offset + j, c,
fg_color, bg_color, bold=bold)
def handle_click(self, y: int, x: int, game: Game) -> None:
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
if self.pad.inch(y - 1, x - 1) != ord(" "):
self.ascii_art_displayed = True

View File

@ -190,12 +190,11 @@ class Display:
"""
raise NotImplementedError
def handle_click(self, y: int, x: int, game: Game) -> None:
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
"""
A mouse click was performed on the coordinates (y, x) of the pad.
Maybe it should do something.
"""
pass
@property
def rows(self) -> int:

View File

@ -66,7 +66,7 @@ class DisplayManager:
d.pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
d.update(self.game)
def handle_mouse_click(self, y: int, x: int) -> None:
def handle_mouse_click(self, y: int, x: int, attr: int) -> None:
"""
Handles the mouse clicks.
"""
@ -79,7 +79,7 @@ class DisplayManager:
# of that display
display = d
if display:
display.handle_click(y - display.y, x - display.x, self.game)
display.handle_click(y - display.y, x - display.x, attr, self.game)
def refresh(self) -> List[Display]:
"""

View File

@ -51,7 +51,7 @@ class MenuDisplay(Display):
self.height - 2 + self.y,
self.width - 2 + self.x)
def handle_click(self, y: int, x: int, game: Game) -> None:
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
"""
We can select a menu item with the mouse.
"""
@ -135,13 +135,13 @@ class MainMenuDisplay(Display):
def update(self, game: Game) -> None:
self.menudisplay.update_menu(game.main_menu)
def handle_click(self, y: int, x: int, game: Game) -> None:
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
menuwidth = min(self.menudisplay.preferred_width, self.width)
menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1
menuheight = min(self.menudisplay.preferred_height, self.height - menuy)
if menuy <= y < menuy + menuheight and menux <= x < menux + menuwidth:
self.menudisplay.handle_click(y - menuy, x - menux, game)
self.menudisplay.handle_click(y - menuy, x - menux, attr, game)
if y <= len(self.title):
self.fg_color = randint(0, 1000), randint(0, 1000), randint(0, 1000)
@ -176,6 +176,7 @@ class PlayerInventoryDisplay(MenuDisplay):
and self.selected else f" {rep} "
self.addstr(self.pad, i + 1, 0, selection
+ " " + item.translated_name.capitalize()
+ (f" ({item.description})" if item.description else "")
+ (": " + str(item.price) + " Hazels"
if self.store_mode else ""))
@ -193,7 +194,7 @@ class PlayerInventoryDisplay(MenuDisplay):
def trueheight(self) -> int:
return 2 + super().trueheight
def handle_click(self, y: int, x: int, game: Game) -> None:
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
"""
We can select a menu item with the mouse.
"""
@ -221,6 +222,7 @@ class StoreInventoryDisplay(MenuDisplay):
and self.selected else f" {rep} "
self.addstr(self.pad, i + 1, 0, selection
+ " " + item.translated_name.capitalize()
+ (f" ({item.description})" if item.description else "")
+ ": " + str(item.price) + " Hazels")
price = f"{self.pack.HAZELNUT} {self.menu.merchant.hazel} Hazels"
@ -236,7 +238,7 @@ class StoreInventoryDisplay(MenuDisplay):
def trueheight(self) -> int:
return 2 + super().trueheight
def handle_click(self, y: int, x: int, game: Game) -> None:
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
"""
We can select a menu item with the mouse.
"""

View File

@ -3,8 +3,10 @@
import curses
from ..entities.items import Monocle
from ..entities.player import Player
from ..game import Game
from ..interfaces import FightingEntity
from ..translations import gettext as _
from .display import Display
@ -13,6 +15,7 @@ class StatsDisplay(Display):
"""
A class to handle the display of the stats of the player.
"""
game: Game
player: Player
def __init__(self, *args, **kwargs):
@ -20,6 +23,7 @@ class StatsDisplay(Display):
self.pad = self.newpad(self.rows, self.cols)
def update(self, game: Game) -> None:
self.game = game
self.player = game.player
def update_pad(self) -> None:
@ -77,6 +81,47 @@ class StatsDisplay(Display):
self.addstr(self.pad, 15, 0, _("YOU ARE DEAD"), curses.COLOR_RED,
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:
self.pad.erase()
self.update_pad()

View File

@ -93,6 +93,7 @@ TexturePack.ASCII_PACK = TexturePack(
HEDGEHOG='*',
HELMET='0',
MERCHANT='M',
MONOCLE='ô',
PLAYER='@',
RABBIT='Y',
RING_OF_CRITICAL_DAMAGE='o',
@ -133,9 +134,10 @@ TexturePack.SQUIRREL_PACK = TexturePack(
HAZELNUT='🌰',
HEART='💜',
HEDGEHOG='🦔',
HELMET='⛑️',
HELMET='⛑️ ',
PLAYER='🐿️ ',
MERCHANT='🦜',
MONOCLE='🧐',
RABBIT='🐇',
RING_OF_CRITICAL_DAMAGE='💍',
RING_OF_MORE_EXPERIENCE='💍',

View File

@ -24,6 +24,13 @@ class Item(Entity):
self.held_by = held_by
self.price = price
@property
def description(self) -> str:
"""
In the inventory, indicate the usefulness of the item.
"""
return ""
def drop(self) -> None:
"""
The item is dropped from the inventory onto the floor.
@ -84,9 +91,9 @@ class Item(Entity):
"""
Returns the list of all item classes.
"""
return [BodySnatchPotion, Bomb, Heart, Shield, Sword,
Chestplate, Helmet, RingCritical, RingXP,
ScrollofDamage, ScrollofWeakening, Ruler, Bow, FireBallStaff]
return [BodySnatchPotion, Bomb, Bow, Chestplate, FireBallStaff,
Heart, Helmet, Monocle, ScrollofDamage, ScrollofWeakening,
Shield, Sword, RingCritical, RingXP, Ruler]
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder,
for_free: bool = False) -> bool:
@ -120,6 +127,10 @@ class Heart(Item):
super().__init__(name=name, price=price, *args, **kwargs)
self.healing = healing
@property
def description(self) -> str:
return f"HP+{self.healing}"
def hold(self, entity: InventoryHolder) -> None:
"""
When holding a heart, the player is healed and
@ -228,6 +239,10 @@ class Weapon(Item):
super().__init__(*args, **kwargs)
self.damage = damage
@property
def description(self) -> str:
return f"STR+{self.damage}" if self.damage else super().description
def save_state(self) -> dict:
"""
Saves the state of the weapon into a dictionary
@ -281,6 +296,11 @@ class Armor(Item):
super().__init__(*args, **kwargs)
self.constitution = constitution
@property
def description(self) -> str:
return f"CON+{self.constitution}" if self.constitution \
else super().description
def equip(self) -> None:
super().equip()
self.held_by.constitution += self.constitution
@ -398,6 +418,14 @@ class Ring(Item):
self.critical = critical
self.experience = experience
@property
def description(self) -> str:
fields = [("MAX HP", self.maxhealth), ("STR", self.strength),
("INT", self.intelligence), ("CHR", self.charisma),
("DEX", self.dexterity), ("CON", self.constitution),
("CRI", self.critical), ("XP", self.experience)]
return ", ".join(f"{key}+{value}" for key, value in fields if value)
def equip(self) -> None:
super().equip()
self.held_by.maxhealth += self.maxhealth
@ -446,7 +474,6 @@ class RingXP(Ring):
super().__init__(name=name, price=price, experience=experience,
*args, **kwargs)
class ScrollofDamage(Item):
"""
A scroll that, when used, deals damage to all entities in a certain radius.
@ -604,3 +631,9 @@ class FireBallStaff(LongRangeWeapon):
explosion = Explosion(y=y, x=x)
self.held_by.map.add_entity(explosion)
class Monocle(Item):
def __init__(self, name: str = "monocle", price: int = 10,
*args, **kwargs):
super().__init__(name=name, price=price, *args, **kwargs)

View File

@ -43,7 +43,9 @@ class Monster(FightingEntity):
# that targets the player.
# If they can not move and are already close to the player,
# they hit.
if target and (self.y, self.x) in target.paths:
if target and (self.y, self.x) in target.paths and \
self.map.is_visible_from(self.y, self.x,
target.y, target.x, 5):
# Moves to target player by choosing the best available path
for next_y, next_x in target.paths[(self.y, self.x)]:
moved = self.check_move(next_y, next_x, True)

View File

@ -97,10 +97,14 @@ class Game:
screen.noutrefresh()
self.display_actions(DisplayActions.REFRESH)
curses.doupdate()
key = screen.getkey()
try:
key = screen.getkey()
except KeyboardInterrupt:
exit(0)
return
if key == "KEY_MOUSE":
_ignored1, x, y, _ignored2, _ignored3 = curses.getmouse()
self.display_actions(DisplayActions.MOUSE, y, x)
_ignored1, x, y, _ignored2, attr = curses.getmouse()
self.display_actions(DisplayActions.MOUSE, y, x, attr)
else:
self.handle_key_pressed(
KeyValues.translate_key(key, self.settings), key)
@ -401,14 +405,16 @@ class Game:
"""
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:
"""
Loads the game from a dictionary.
"""
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:
self.message = _("Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted.")
@ -425,6 +431,8 @@ class Game:
return
self.player = players[0]
self.map.compute_visibility(self.player.y, self.player.x,
self.player.vision)
self.display_actions(DisplayActions.UPDATE)
def load_game(self) -> None:

View File

@ -7,6 +7,7 @@ from random import choice, choices, randint
from typing import List, Optional, Any, Dict, Tuple
from queue import PriorityQueue
from functools import reduce
from copy import deepcopy
from .display.texturepack import TexturePack
from .translations import gettext as _
@ -80,18 +81,18 @@ class Map:
currentx: int
currenty: int
def __init__(self, width: int, height: int, tiles: list,
start_y: int, start_x: int):
def __init__(self, width: int = 0, height: int = 0, tiles: list = None,
start_y: int = 0, start_x: int = 0):
self.floor = 0
self.width = width
self.height = height
self.start_y = start_y
self.start_x = start_x
self.tiles = tiles
self.visibility = [[False for _ in range(len(tiles[0]))]
for _ in range(len(tiles))]
self.tiles = tiles or []
self.visibility = [[False for _ in range(len(self.tiles[0]))]
for _ in range(len(self.tiles))]
self.seen_tiles = [[False for _ in range(len(tiles[0]))]
for _ in range(len(tiles))]
for _ in range(len(self.tiles))]
self.entities = []
self.logs = Logs()
@ -193,6 +194,14 @@ class Map:
entity.move(y, x)
self.add_entity(entity)
def is_visible_from(self, starty: int, startx: int, desty: int, destx: int,
max_range: int) -> bool:
oldvisibility = deepcopy(self.visibility)
self.compute_visibility(starty, startx, max_range)
result = self.visibility[desty][destx]
self.visibility = oldvisibility
return result
def compute_visibility(self, y: int, x: int, max_range: int) -> None:
"""
Sets the visible tiles to be the ones visible by an entity at point
@ -245,10 +254,12 @@ class Map:
if x + y > max_range:
continue
is_opaque = self.is_wall(y, x, octant, origin)
if y == top_y and octant == 7 and x == 4:
self.logs.add_message(f"{x}, {y}, {top.X}, {top.Y}")
is_visible = is_opaque\
or ((y != top_y or top > Slope(y * 4 - 1, x * 4 + 1))
or ((y != top_y or top >= Slope(y, x))
and (y != bottom_y
or bottom < Slope(y * 4 + 1, x * 4 - 1)))
or bottom <= Slope(y, x)))
# is_visible = is_opaque\
# or ((y != top_y or top >= Slope(y, x))
# and (y != bottom_y or bottom <= Slope(y, x)))
@ -338,9 +349,10 @@ class Map:
for enti in self.entities:
d["entities"].append(enti.save_state())
d["map"] = self.draw_string(TexturePack.ASCII_PACK)
d["seen_tiles"] = self.seen_tiles
return d
def load_state(self, d: dict) -> None:
def load_state(self, d: dict) -> "Map":
"""
Loads the map's attributes from a dictionary.
"""
@ -351,11 +363,16 @@ class Map:
self.currentx = d["currentx"]
self.currenty = d["currenty"]
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 = []
dictclasses = Entity.get_all_entity_classes_in_a_dict()
for entisave in d["entities"]:
self.add_entity(dictclasses[entisave["type"]](**entisave))
return self
class Tile(Enum):
"""
@ -636,32 +653,34 @@ class Entity:
Trumpet, Chest
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, \
Heart, Sword, Shield, Chestplate, Helmet, RingCritical, RingXP, \
ScrollofDamage, ScrollofWeakening, Ruler, Bow, FireBallStaff
ScrollofDamage, ScrollofWeakening, Ruler, Bow, FireBallStaff, \
Monocle
return {
"Tiger": Tiger,
"Bomb": Bomb,
"Heart": Heart,
"BodySnatchPotion": BodySnatchPotion,
"Hedgehog": Hedgehog,
"Rabbit": Rabbit,
"TeddyBear": TeddyBear,
"Player": Player,
"Merchant": Merchant,
"Sunflower": Sunflower,
"Sword": Sword,
"Trumpet": Trumpet,
"Eagle": GiantSeaEagle,
"Shield": Shield,
"Bomb": Bomb,
"Bow": Bow,
"Chest": Chest,
"Chestplate": Chestplate,
"Eagle": GiantSeaEagle,
"FireBallStaff": FireBallStaff,
"Heart": Heart,
"Hedgehog": Hedgehog,
"Helmet": Helmet,
"Merchant": Merchant,
"Monocle": Monocle,
"Player": Player,
"Rabbit": Rabbit,
"RingCritical": RingCritical,
"RingXP": RingXP,
"Ruler": Ruler,
"ScrollofDamage": ScrollofDamage,
"ScrollofWeakening": ScrollofWeakening,
"Bow": Bow,
"FireBallStaff": FireBallStaff,
"Chest": Chest,
"Shield": Shield,
"Sunflower": Sunflower,
"Sword": Sword,
"Trumpet": Trumpet,
"TeddyBear": TeddyBear,
"Tiger": Tiger,
}
def save_state(self) -> dict:

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-08 01:57+0100\n"
"POT-Creation-Date: 2021-01-08 15:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,87 +17,116 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ring_of_critical_damage"
msgstr ""
msgid "ring_of_more_experience"
msgstr ""
#, python-brace-format
msgid "{name} takes {amount} damage."
msgstr "{name} nimmt {amount} Schadenspunkte."
#: squirrelbattle/display/menudisplay.py:160
#: squirrelbattle/display/creditsdisplay.py:28
#: squirrelbattle/display/menudisplay.py:123
#: squirrelbattle/display/menudisplay.py:148
msgid "Credits"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:32
msgid "Developers:"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:38
msgid "Translators:"
msgstr ""
#: squirrelbattle/display/menudisplay.py:168
msgid "INVENTORY"
msgstr "BESTAND"
#: squirrelbattle/display/menudisplay.py:202
#: squirrelbattle/display/menudisplay.py:214
msgid "STALL"
msgstr "STAND"
#: squirrelbattle/display/statsdisplay.py:23
#: squirrelbattle/tests/translations_test.py:60
msgid "player"
msgstr "Spieler"
#: squirrelbattle/display/statsdisplay.py:35
#: squirrelbattle/display/statsdisplay.py:44
msgid "Inventory:"
msgstr "Bestand:"
#: squirrelbattle/display/statsdisplay.py:52
#: squirrelbattle/display/statsdisplay.py:61
msgid "Equipped main:"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:56
#: squirrelbattle/display/statsdisplay.py:65
msgid "Equipped secondary:"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:61
#: squirrelbattle/display/statsdisplay.py:70
msgid "Equipped chestplate:"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:65
#: squirrelbattle/display/statsdisplay.py:74
msgid "Equipped helmet:"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:72
#: squirrelbattle/display/statsdisplay.py:81
msgid "YOU ARE DEAD"
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
#: squirrelbattle/entities/friendly.py:33
msgid "I don't sell any squirrel"
msgstr "Ich verkaufe keinen Eichhörnchen."
#: squirrelbattle/entities/friendly.py:52
#: squirrelbattle/entities/friendly.py:55
msgid "Flower power!!"
msgstr "Blumenmacht!!"
#: squirrelbattle/entities/friendly.py:52
#: squirrelbattle/entities/friendly.py:55
msgid "The sun is warm today"
msgstr "Die Sonne ist warm heute"
#. The bomb is exploding.
#. Each entity that is close to the bomb takes damages.
#. The player earn XP if the entity was killed.
#: squirrelbattle/entities/items.py:163
#: squirrelbattle/entities/items.py:178
msgid "Bomb is exploding."
msgstr "Die Bombe explodiert."
#: squirrelbattle/entities/items.py:344
#: squirrelbattle/entities/items.py:365
#, python-brace-format
msgid "{player} exchanged its body with {entity}."
msgstr "{player} täuscht seinem Körper mit {entity} aus."
#: squirrelbattle/game.py:182
#: squirrelbattle/game.py:200
#, python-brace-format
msgid "The player climbs down to the floor {floor}."
msgstr "Der Spieler klettert auf dem Stock {floor} hinunter."
#: squirrelbattle/game.py:195
#: squirrelbattle/game.py:213
#, python-brace-format
msgid "The player climbs up the floor {floor}."
msgstr "Der Spieler klettert auf dem Stock {floor} hinoben."
#: squirrelbattle/game.py:285 squirrelbattle/tests/game_test.py:592
#: squirrelbattle/game.py:304 squirrelbattle/tests/game_test.py:603
msgid "The buyer does not have enough money"
msgstr "Der Kaufer hat nicht genug Geld"
#: squirrelbattle/game.py:328
#: squirrelbattle/game.py:349
msgid ""
"Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted."
@ -105,7 +134,7 @@ msgstr ""
"In Ihrer Speicherdatei fehlen einige Schlüssel.\n"
"Ihre Speicherung scheint korrupt zu sein. Es wird gelöscht."
#: squirrelbattle/game.py:336
#: squirrelbattle/game.py:357
msgid ""
"No player was found on this map!\n"
"Maybe you died?"
@ -113,7 +142,7 @@ msgstr ""
"Auf dieser Karte wurde kein Spieler gefunden!\n"
"Vielleicht sind Sie gestorben?"
#: squirrelbattle/game.py:356
#: squirrelbattle/game.py:379
msgid ""
"The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted."
@ -121,26 +150,26 @@ msgstr ""
"Die JSON-Datei ist nicht korrekt.\n"
"Ihre Speicherung scheint korrumpiert. Sie wurde gelöscht."
#: squirrelbattle/interfaces.py:452
#: squirrelbattle/interfaces.py:718
msgid "It's a critical hit!"
msgstr ""
#: squirrelbattle/interfaces.py:453
#: squirrelbattle/interfaces.py:719
#, python-brace-format
msgid "{name} hits {opponent}."
msgstr "{name} schlägt {opponent}."
#: squirrelbattle/interfaces.py:465
#: squirrelbattle/interfaces.py:733
#, python-brace-format
msgid "{name} takes {damage} damage."
msgstr ""
#: squirrelbattle/interfaces.py:467
#: squirrelbattle/interfaces.py:735
#, python-brace-format
msgid "{name} dies."
msgstr "{name} stirbt."
#: squirrelbattle/interfaces.py:501
#: squirrelbattle/interfaces.py:769
#, python-brace-format
msgid "{entity} said: {message}"
msgstr "{entity} hat gesagt: {message}"
@ -149,8 +178,8 @@ msgstr "{entity} hat gesagt: {message}"
msgid "Back"
msgstr "Zurück"
#: squirrelbattle/tests/game_test.py:358 squirrelbattle/tests/game_test.py:361
#: squirrelbattle/tests/game_test.py:364 squirrelbattle/tests/game_test.py:367
#: squirrelbattle/tests/game_test.py:368 squirrelbattle/tests/game_test.py:371
#: squirrelbattle/tests/game_test.py:374 squirrelbattle/tests/game_test.py:377
#: squirrelbattle/tests/translations_test.py:16
msgid "New game"
msgstr "Neu Spiel"
@ -247,6 +276,10 @@ msgstr "Textur-Packung"
msgid "Language"
msgstr "Sprache"
#: squirrelbattle/tests/translations_test.py:62
msgid "player"
msgstr "Spieler"
#: squirrelbattle/tests/translations_test.py:64
msgid "hedgehog"
msgstr "Igel"
@ -271,22 +304,50 @@ msgstr "Teddybär"
msgid "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"
msgstr "Leichenfleddererzaubertrank"
#: squirrelbattle/tests/translations_test.py:72
#: squirrelbattle/tests/translations_test.py:73
msgid "bomb"
msgstr "Bombe"
#: squirrelbattle/tests/translations_test.py:73
#: squirrelbattle/tests/translations_test.py:74
msgid "explosion"
msgstr "Explosion"
#: squirrelbattle/tests/translations_test.py:74
#: squirrelbattle/tests/translations_test.py:75
msgid "heart"
msgstr "Herz"
#: squirrelbattle/tests/translations_test.py:75
#: squirrelbattle/tests/translations_test.py:76
msgid "sword"
msgstr "schwert"
#: squirrelbattle/tests/translations_test.py:77
msgid "helmet"
msgstr ""
#: squirrelbattle/tests/translations_test.py:78
msgid "chestplate"
msgstr ""
#: squirrelbattle/tests/translations_test.py:79
msgid "shield"
msgstr ""
#: squirrelbattle/tests/translations_test.py:80
msgid "ring of critical damage"
msgstr ""
#: squirrelbattle/tests/translations_test.py:82
msgid "ring of more experience"
msgstr ""
#: squirrelbattle/tests/translations_test.py:84
msgid "monocle"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-06 15:19+0100\n"
"POT-Creation-Date: 2021-01-08 15:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,86 +17,115 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ring_of_critical_damage"
msgstr ""
msgid "ring_of_more_experience"
msgstr ""
#, python-brace-format
msgid "{name} takes {amount} damage."
msgstr "{name} recibe {amount} daño."
#: squirrelbattle/display/menudisplay.py:160
#: squirrelbattle/display/creditsdisplay.py:28
#: squirrelbattle/display/menudisplay.py:123
#: squirrelbattle/display/menudisplay.py:148
msgid "Credits"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:32
msgid "Developers:"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:38
msgid "Translators:"
msgstr ""
#: squirrelbattle/display/menudisplay.py:168
msgid "INVENTORY"
msgstr "INVENTORIO"
#: squirrelbattle/display/menudisplay.py:202
#: squirrelbattle/display/menudisplay.py:214
msgid "STALL"
msgstr "PUESTO"
#: squirrelbattle/display/statsdisplay.py:23
#: squirrelbattle/tests/translations_test.py:60
msgid "player"
msgstr "jugador"
#: squirrelbattle/display/statsdisplay.py:35
#: squirrelbattle/display/statsdisplay.py:44
msgid "Inventory:"
msgstr "Inventorio :"
#: squirrelbattle/display/statsdisplay.py:52
#: squirrelbattle/display/statsdisplay.py:61
msgid "Equipped main:"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:56
#: squirrelbattle/display/statsdisplay.py:65
msgid "Equipped secondary:"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:61
#: squirrelbattle/display/statsdisplay.py:70
msgid "Equipped chestplate:"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:65
#: squirrelbattle/display/statsdisplay.py:74
msgid "Equipped helmet:"
msgstr ""
#: squirrelbattle/display/statsdisplay.py:72
#: squirrelbattle/display/statsdisplay.py:81
msgid "YOU ARE DEAD"
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
msgid "I don't sell any squirrel"
msgstr "No vendo ninguna ardilla"
#: squirrelbattle/entities/friendly.py:52
#: squirrelbattle/entities/friendly.py:55
msgid "Flower power!!"
msgstr "Poder de las flores!!"
#: squirrelbattle/entities/friendly.py:52
#: squirrelbattle/entities/friendly.py:55
msgid "The sun is warm today"
msgstr "El sol está caliente hoy"
#. The bomb is exploding.
#. Each entity that is close to the bomb takes damages.
#. The player earn XP if the entity was killed.
#: squirrelbattle/entities/items.py:163
#: squirrelbattle/entities/items.py:178
msgid "Bomb is exploding."
msgstr "La bomba está explotando."
#: squirrelbattle/entities/items.py:344
#: squirrelbattle/entities/items.py:365
#, python-brace-format
msgid "{player} exchanged its body with {entity}."
msgstr "{player} intercambió su cuerpo con {entity}."
#: squirrelbattle/game.py:182
#: squirrelbattle/game.py:200
#, python-brace-format
msgid "The player climbs down to the floor {floor}."
msgstr ""
#: squirrelbattle/game.py:195
#: squirrelbattle/game.py:213
#, python-brace-format
msgid "The player climbs up the floor {floor}."
msgstr ""
#: squirrelbattle/game.py:285 squirrelbattle/tests/game_test.py:592
#: squirrelbattle/game.py:304 squirrelbattle/tests/game_test.py:603
msgid "The buyer does not have enough money"
msgstr "El comprador no tiene suficiente dinero"
#: squirrelbattle/game.py:328
#: squirrelbattle/game.py:349
msgid ""
"Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted."
@ -104,7 +133,7 @@ msgstr ""
"Algunas claves faltan en su archivo de guarda.\n"
"Su guarda parece a ser corruptido. Fue eliminado."
#: squirrelbattle/game.py:336
#: squirrelbattle/game.py:357
msgid ""
"No player was found on this map!\n"
"Maybe you died?"
@ -112,7 +141,7 @@ msgstr ""
"No jugador encontrado sobre la carta !\n"
"¿ Quizas murió ?"
#: squirrelbattle/game.py:356
#: squirrelbattle/game.py:379
msgid ""
"The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted."
@ -120,26 +149,26 @@ msgstr ""
"El JSON archivo no es correcto.\n"
"Su guarda parece corrupta. Fue eliminada."
#: squirrelbattle/interfaces.py:452
#: squirrelbattle/interfaces.py:718
msgid "It's a critical hit!"
msgstr ""
#: squirrelbattle/interfaces.py:453
#: squirrelbattle/interfaces.py:719
#, python-brace-format
msgid "{name} hits {opponent}."
msgstr "{name} golpea a {opponent}."
#: squirrelbattle/interfaces.py:465
#: squirrelbattle/interfaces.py:733
#, python-brace-format
msgid "{name} takes {damage} damage."
msgstr ""
#: squirrelbattle/interfaces.py:467
#: squirrelbattle/interfaces.py:735
#, python-brace-format
msgid "{name} dies."
msgstr "{name} se muere."
#: squirrelbattle/interfaces.py:501
#: squirrelbattle/interfaces.py:769
#, python-brace-format
msgid "{entity} said: {message}"
msgstr "{entity} dijo : {message}"
@ -148,8 +177,8 @@ msgstr "{entity} dijo : {message}"
msgid "Back"
msgstr "Volver"
#: squirrelbattle/tests/game_test.py:358 squirrelbattle/tests/game_test.py:361
#: squirrelbattle/tests/game_test.py:364 squirrelbattle/tests/game_test.py:367
#: squirrelbattle/tests/game_test.py:368 squirrelbattle/tests/game_test.py:371
#: squirrelbattle/tests/game_test.py:374 squirrelbattle/tests/game_test.py:377
#: squirrelbattle/tests/translations_test.py:16
msgid "New game"
msgstr "Nuevo partido"
@ -246,6 +275,10 @@ msgstr "Paquete de texturas"
msgid "Language"
msgstr "Languaje"
#: squirrelbattle/tests/translations_test.py:62
msgid "player"
msgstr "jugador"
#: squirrelbattle/tests/translations_test.py:64
msgid "hedgehog"
msgstr "erizo"
@ -270,22 +303,50 @@ msgstr "osito de peluche"
msgid "tiger"
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"
msgstr "poción de intercambio"
#: squirrelbattle/tests/translations_test.py:72
#: squirrelbattle/tests/translations_test.py:73
msgid "bomb"
msgstr "bomba"
#: squirrelbattle/tests/translations_test.py:73
#: squirrelbattle/tests/translations_test.py:74
msgid "explosion"
msgstr "explosión"
#: squirrelbattle/tests/translations_test.py:74
#: squirrelbattle/tests/translations_test.py:75
msgid "heart"
msgstr "corazón"
#: squirrelbattle/tests/translations_test.py:75
#: squirrelbattle/tests/translations_test.py:76
msgid "sword"
msgstr "espada"
#: squirrelbattle/tests/translations_test.py:77
msgid "helmet"
msgstr ""
#: squirrelbattle/tests/translations_test.py:78
msgid "chestplate"
msgstr ""
#: squirrelbattle/tests/translations_test.py:79
msgid "shield"
msgstr ""
#: squirrelbattle/tests/translations_test.py:80
msgid "ring of critical damage"
msgstr ""
#: squirrelbattle/tests/translations_test.py:82
msgid "ring of more experience"
msgstr ""
#: squirrelbattle/tests/translations_test.py:84
msgid "monocle"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-06 15:19+0100\n"
"POT-Creation-Date: 2021-01-08 15:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -21,83 +21,106 @@ msgstr ""
msgid "{name} takes {amount} damage."
msgstr "{name} prend {amount} points de dégât."
#: squirrelbattle/display/menudisplay.py:160
#: squirrelbattle/display/creditsdisplay.py:28
#: squirrelbattle/display/menudisplay.py:123
#: squirrelbattle/display/menudisplay.py:148
msgid "Credits"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:32
msgid "Developers:"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:38
msgid "Translators:"
msgstr ""
#: squirrelbattle/display/menudisplay.py:168
msgid "INVENTORY"
msgstr "INVENTAIRE"
#: squirrelbattle/display/menudisplay.py:202
#: squirrelbattle/display/menudisplay.py:214
msgid "STALL"
msgstr "STAND"
#: squirrelbattle/display/statsdisplay.py:23
#: squirrelbattle/tests/translations_test.py:60
msgid "player"
msgstr "joueur"
#: squirrelbattle/display/statsdisplay.py:35
#: squirrelbattle/display/statsdisplay.py:44
msgid "Inventory:"
msgstr "Inventaire :"
#: squirrelbattle/display/statsdisplay.py:52
#: squirrelbattle/display/statsdisplay.py:61
msgid "Equipped main:"
msgstr "Équipement principal :"
#: squirrelbattle/display/statsdisplay.py:56
#: squirrelbattle/display/statsdisplay.py:65
msgid "Equipped secondary:"
msgstr "Équipement secondaire :"
#: squirrelbattle/display/statsdisplay.py:61
#: squirrelbattle/display/statsdisplay.py:70
msgid "Equipped chestplate:"
msgstr "Plastron équipé :"
#: squirrelbattle/display/statsdisplay.py:65
#: squirrelbattle/display/statsdisplay.py:74
msgid "Equipped helmet:"
msgstr "Casque équipé :"
#: squirrelbattle/display/statsdisplay.py:72
#: squirrelbattle/display/statsdisplay.py:81
msgid "YOU ARE DEAD"
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
#: squirrelbattle/entities/friendly.py:33
msgid "I don't sell any squirrel"
msgstr "Je ne vends pas d'écureuil"
#: squirrelbattle/entities/friendly.py:52
#: squirrelbattle/entities/friendly.py:55
msgid "Flower power!!"
msgstr "Pouvoir des fleurs !!"
#: squirrelbattle/entities/friendly.py:52
#: squirrelbattle/entities/friendly.py:55
msgid "The sun is warm today"
msgstr "Le soleil est chaud aujourd'hui"
#. The bomb is exploding.
#. Each entity that is close to the bomb takes damages.
#. The player earn XP if the entity was killed.
#: squirrelbattle/entities/items.py:163
#: squirrelbattle/entities/items.py:178
msgid "Bomb is exploding."
msgstr "La bombe explose."
#: squirrelbattle/entities/items.py:344
#: squirrelbattle/entities/items.py:365
#, python-brace-format
msgid "{player} exchanged its body with {entity}."
msgstr "{player} a échangé son corps avec {entity}."
#: squirrelbattle/game.py:182
#: squirrelbattle/game.py:200
#, python-brace-format
msgid "The player climbs down to the floor {floor}."
msgstr "Le joueur descend à l'étage {floor}."
#: squirrelbattle/game.py:195
#: squirrelbattle/game.py:213
#, python-brace-format
msgid "The player climbs up the floor {floor}."
msgstr "Le joueur monte à l'étage {floor}."
#: squirrelbattle/game.py:285 squirrelbattle/tests/game_test.py:592
#: squirrelbattle/game.py:304 squirrelbattle/tests/game_test.py:603
msgid "The buyer does not have enough money"
msgstr "L'acheteur n'a pas assez d'argent"
#: squirrelbattle/game.py:328
#: squirrelbattle/game.py:349
msgid ""
"Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted."
@ -105,7 +128,7 @@ msgstr ""
"Certaines clés de votre ficher de sauvegarde sont manquantes.\n"
"Votre sauvegarde semble corrompue. Elle a été supprimée."
#: squirrelbattle/game.py:336
#: squirrelbattle/game.py:357
msgid ""
"No player was found on this map!\n"
"Maybe you died?"
@ -113,7 +136,7 @@ msgstr ""
"Aucun joueur n'a été trouvé sur la carte !\n"
"Peut-être êtes-vous mort ?"
#: squirrelbattle/game.py:356
#: squirrelbattle/game.py:379
msgid ""
"The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted."
@ -121,26 +144,26 @@ msgstr ""
"Le fichier JSON de sauvegarde est incorrect.\n"
"Votre sauvegarde semble corrompue. Elle a été supprimée."
#: squirrelbattle/interfaces.py:452
#: squirrelbattle/interfaces.py:718
msgid "It's a critical hit!"
msgstr "C'est un coup critique !"
#: squirrelbattle/interfaces.py:453
#: squirrelbattle/interfaces.py:719
#, python-brace-format
msgid "{name} hits {opponent}."
msgstr "{name} frappe {opponent}."
#: squirrelbattle/interfaces.py:465
#: squirrelbattle/interfaces.py:733
#, python-brace-format
msgid "{name} takes {damage} damage."
msgstr "{name} prend {damage} dégâts."
#: squirrelbattle/interfaces.py:467
#: squirrelbattle/interfaces.py:735
#, python-brace-format
msgid "{name} dies."
msgstr "{name} meurt."
#: squirrelbattle/interfaces.py:501
#: squirrelbattle/interfaces.py:769
#, python-brace-format
msgid "{entity} said: {message}"
msgstr "{entity} a dit : {message}"
@ -149,8 +172,8 @@ msgstr "{entity} a dit : {message}"
msgid "Back"
msgstr "Retour"
#: squirrelbattle/tests/game_test.py:358 squirrelbattle/tests/game_test.py:361
#: squirrelbattle/tests/game_test.py:364 squirrelbattle/tests/game_test.py:367
#: squirrelbattle/tests/game_test.py:368 squirrelbattle/tests/game_test.py:371
#: squirrelbattle/tests/game_test.py:374 squirrelbattle/tests/game_test.py:377
#: squirrelbattle/tests/translations_test.py:16
msgid "New game"
msgstr "Nouvelle partie"
@ -247,6 +270,10 @@ msgstr "Pack de textures"
msgid "Language"
msgstr "Langue"
#: squirrelbattle/tests/translations_test.py:62
msgid "player"
msgstr "joueur"
#: squirrelbattle/tests/translations_test.py:64
msgid "hedgehog"
msgstr "hérisson"
@ -271,22 +298,50 @@ msgstr "nounours"
msgid "tiger"
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"
msgstr "potion d'arrachage de corps"
#: squirrelbattle/tests/translations_test.py:72
#: squirrelbattle/tests/translations_test.py:73
msgid "bomb"
msgstr "bombe"
#: squirrelbattle/tests/translations_test.py:73
#: squirrelbattle/tests/translations_test.py:74
msgid "explosion"
msgstr "explosion"
#: squirrelbattle/tests/translations_test.py:74
#: squirrelbattle/tests/translations_test.py:75
msgid "heart"
msgstr "cœur"
#: squirrelbattle/tests/translations_test.py:75
#: squirrelbattle/tests/translations_test.py:76
msgid "sword"
msgstr "épée"
#: squirrelbattle/tests/translations_test.py:77
msgid "helmet"
msgstr "casque"
#: squirrelbattle/tests/translations_test.py:78
msgid "chestplate"
msgstr "plastron"
#: squirrelbattle/tests/translations_test.py:79
msgid "shield"
msgstr "bouclier"
#: squirrelbattle/tests/translations_test.py:80
msgid "ring of critical damage"
msgstr "anneau de coup critique"
#: squirrelbattle/tests/translations_test.py:82
msgid "ring of more experience"
msgstr "anneau de plus d'expérience"
#: squirrelbattle/tests/translations_test.py:84
msgid "monocle"
msgstr "monocle"

View File

@ -74,7 +74,8 @@ class Settings:
"""
d = json.loads(json_str)
for key in d:
setattr(self, key, d[key])
if hasattr(self, key):
setattr(self, key, d[key])
def dumps_to_string(self) -> str:
"""

View File

@ -21,7 +21,7 @@ class TermManager: # pragma: no cover
# make cursor invisible
curses.curs_set(False)
# Catch mouse events
curses.mousemask(True)
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
# Enable colors
curses.start_color()

View File

@ -1,11 +1,12 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import random
import unittest
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart, Item, \
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.player import Player
from squirrelbattle.interfaces import Entity, Map
@ -264,3 +265,17 @@ class TestEntities(unittest.TestCase):
player_state = player.save_state()
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
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
import os
import random
import unittest
from ..bootstrap import Bootstrap
@ -11,7 +11,7 @@ from ..display.display_manager import DisplayManager
from ..entities.friendly import Merchant, Sunflower, Chest
from ..entities.items import Bomb, Heart, Sword, Explosion, Shield, Helmet, \
Chestplate, RingCritical, Bow, FireBallStaff, ScrollofDamage,\
ScrollofWeakening
ScrollofWeakening, Monocle
from ..entities.monsters import Rabbit, GiantSeaEagle
from ..entities.player import Player
from ..enums import DisplayActions, KeyValues, GameMode
@ -67,6 +67,7 @@ class TestGame(unittest.TestCase):
new_state = self.game.save_state()
self.assertEqual(old_state, new_state)
self.assertIsNone(self.game.message)
# Ensure that the bomb is loaded
self.assertTrue(self.game.player.inventory)
@ -258,10 +259,12 @@ class TestGame(unittest.TestCase):
self.game.state = GameMode.MAINMENU
# Change the color of the artwork
self.game.display_actions(DisplayActions.MOUSE, 0, 10)
self.game.display_actions(DisplayActions.MOUSE, 0, 10,
curses.BUTTON1_CLICKED)
# Settings menu
self.game.display_actions(DisplayActions.MOUSE, 25, 21)
self.game.display_actions(DisplayActions.MOUSE, 25, 21,
curses.BUTTON1_CLICKED)
self.assertEqual(self.game.main_menu.position, 4)
self.assertEqual(self.game.state, GameMode.SETTINGS)
@ -273,11 +276,13 @@ class TestGame(unittest.TestCase):
self.game.state = GameMode.INVENTORY
# Click nowhere
self.game.display_actions(DisplayActions.MOUSE, 0, 0)
self.game.display_actions(DisplayActions.MOUSE, 0, 0,
curses.BUTTON1_CLICKED)
self.assertEqual(self.game.state, GameMode.INVENTORY)
# Click on the second item
self.game.display_actions(DisplayActions.MOUSE, 8, 25)
self.game.display_actions(DisplayActions.MOUSE, 8, 25,
curses.BUTTON1_CLICKED)
self.assertEqual(self.game.state, GameMode.INVENTORY)
self.assertEqual(self.game.inventory_menu.position, 1)
@ -573,12 +578,14 @@ class TestGame(unittest.TestCase):
# Buy the second item by clicking on it
item = self.game.store_menu.validate()
self.assertIn(item, merchant.inventory)
self.game.display_actions(DisplayActions.MOUSE, 7, 25)
self.game.display_actions(DisplayActions.MOUSE, 7, 25,
curses.BUTTON1_CLICKED)
self.assertIn(item, self.game.player.inventory)
self.assertNotIn(item, merchant.inventory)
# Buy a heart
merchant.inventory[1] = Heart()
self.game.display_actions(DisplayActions.REFRESH)
item = self.game.store_menu.validate()
self.assertIn(item, merchant.inventory)
self.assertEqual(item, merchant.inventory[1])
@ -697,19 +704,21 @@ class TestGame(unittest.TestCase):
self.game.save_state()
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.player.critical = 10
self.game.state = GameMode.PLAY
monocle = Monocle()
monocle.hold(self.game.player)
monocle.equip()
sea_eagle = GiantSeaEagle()
self.game.map.add_entity(sea_eagle)
sea_eagle.move(2, 6)
old_health = sea_eagle.health
self.game.player.hit(sea_eagle)
self.assertEqual(sea_eagle.health,
old_health - self.game.player.strength * 4)
self.game.display_actions(DisplayActions.REFRESH)
def test_ladders(self) -> None:
"""
@ -748,9 +757,11 @@ class TestGame(unittest.TestCase):
"""
self.game.state = GameMode.MAINMENU
self.game.display_actions(DisplayActions.MOUSE, 41, 41)
self.game.display_actions(DisplayActions.MOUSE, 41, 41,
curses.BUTTON1_CLICKED)
self.assertEqual(self.game.state, GameMode.CREDITS)
self.game.display_actions(DisplayActions.MOUSE, 21, 21)
self.game.display_actions(DisplayActions.MOUSE, 21, 21,
curses.BUTTON1_CLICKED)
self.game.display_actions(DisplayActions.REFRESH)
self.game.state = GameMode.CREDITS

View File

@ -67,9 +67,18 @@ class TestTranslations(unittest.TestCase):
self.assertEqual(_("sunflower"), "tournesol")
self.assertEqual(_("teddy bear"), "nounours")
self.assertEqual(_("tiger"), "tigre")
self.assertEqual(_("eagle"), "pygargue")
self.assertEqual(_("body snatch potion"), "potion d'arrachage de corps")
self.assertEqual(_("bomb"), "bombe")
self.assertEqual(_("explosion"), "explosion")
self.assertEqual(_("heart"), "cœur")
self.assertEqual(_("sword"), "épée")
self.assertEqual(_("helmet"), "casque")
self.assertEqual(_("chestplate"), "plastron")
self.assertEqual(_("shield"), "bouclier")
self.assertEqual(_("ring of critical damage"),
"anneau de coup critique")
self.assertEqual(_("ring of more experience"),
"anneau de plus d'expérience")
self.assertEqual(_("monocle"), "monocle")