Merge branch 'equipment' into 'master'
Equipment Closes #19, #30, #48, #51 et #52 See merge request ynerant/squirrel-battle!54
This commit was merged in pull request #135.
	This commit is contained in:
		| @@ -33,7 +33,8 @@ class StatsDisplay(Display): | |||||||
|                   f"INT {self.player.intelligence}\n" \ |                   f"INT {self.player.intelligence}\n" \ | ||||||
|                   f"CHR {self.player.charisma}\n" \ |                   f"CHR {self.player.charisma}\n" \ | ||||||
|                   f"DEX {self.player.dexterity}\n" \ |                   f"DEX {self.player.dexterity}\n" \ | ||||||
|                   f"CON {self.player.constitution}" |                   f"CON {self.player.constitution}\n" \ | ||||||
|  |                   f"CRI {self.player.critical}%" | ||||||
|         self.addstr(self.pad, 3, 0, string3) |         self.addstr(self.pad, 3, 0, string3) | ||||||
|  |  | ||||||
|         inventory_str = _("Inventory:") + " " |         inventory_str = _("Inventory:") + " " | ||||||
| @@ -49,13 +50,31 @@ class StatsDisplay(Display): | |||||||
|             if count > 1: |             if count > 1: | ||||||
|                 inventory_str += f"x{count} " |                 inventory_str += f"x{count} " | ||||||
|             printed_items.append(item) |             printed_items.append(item) | ||||||
|         self.addstr(self.pad, 8, 0, inventory_str) |         self.addstr(self.pad, 9, 0, inventory_str) | ||||||
|  |  | ||||||
|         self.addstr(self.pad, 9, 0, f"{self.pack.HAZELNUT} " |         if self.player.equipped_main: | ||||||
|  |             self.addstr(self.pad, 10, 0, | ||||||
|  |                         _("Equipped main:") + " " | ||||||
|  |                         f"{self.pack[self.player.equipped_main.name.upper()]}") | ||||||
|  |         if self.player.equipped_secondary: | ||||||
|  |             self.addstr(self.pad, 11, 0, | ||||||
|  |                         _("Equipped secondary:") + " " | ||||||
|  |                         + self.pack[self.player.equipped_secondary | ||||||
|  |                                     .name.upper()]) | ||||||
|  |         if self.player.equipped_armor: | ||||||
|  |             self.addstr(self.pad, 12, 0, | ||||||
|  |                         _("Equipped chestplate:") + " " | ||||||
|  |                         + self.pack[self.player.equipped_armor.name.upper()]) | ||||||
|  |         if self.player.equipped_helmet: | ||||||
|  |             self.addstr(self.pad, 13, 0, | ||||||
|  |                         _("Equipped helmet:") + " " | ||||||
|  |                         + self.pack[self.player.equipped_helmet.name.upper()]) | ||||||
|  |  | ||||||
|  |         self.addstr(self.pad, 14, 0, f"{self.pack.HAZELNUT} " | ||||||
|                                      f"x{self.player.hazel}") |                                      f"x{self.player.hazel}") | ||||||
|  |  | ||||||
|         if self.player.dead: |         if self.player.dead: | ||||||
|             self.addstr(self.pad, 11, 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) | ||||||
|  |  | ||||||
|     def display(self) -> None: |     def display(self) -> None: | ||||||
|   | |||||||
| @@ -35,6 +35,12 @@ class TexturePack: | |||||||
|     TIGER: str |     TIGER: str | ||||||
|     TRUMPET: str |     TRUMPET: str | ||||||
|     WALL: str |     WALL: str | ||||||
|  |     EAGLE: str | ||||||
|  |     SHIELD: str | ||||||
|  |     CHESTPLATE: str | ||||||
|  |     HELMET: str | ||||||
|  |     RING_OF_MORE_EXPERIENCE: str | ||||||
|  |     RING_OF_CRITICAL_DAMAGE: str | ||||||
|  |  | ||||||
|     ASCII_PACK: "TexturePack" |     ASCII_PACK: "TexturePack" | ||||||
|     SQUIRREL_PACK: "TexturePack" |     SQUIRREL_PACK: "TexturePack" | ||||||
| @@ -66,7 +72,7 @@ TexturePack.ASCII_PACK = TexturePack( | |||||||
|     entity_bg_color=curses.COLOR_BLACK, |     entity_bg_color=curses.COLOR_BLACK, | ||||||
|  |  | ||||||
|     BODY_SNATCH_POTION='S', |     BODY_SNATCH_POTION='S', | ||||||
|     BOMB='o', |     BOMB='ç', | ||||||
|     EMPTY=' ', |     EMPTY=' ', | ||||||
|     EXPLOSION='%', |     EXPLOSION='%', | ||||||
|     FLOOR='.', |     FLOOR='.', | ||||||
| @@ -77,12 +83,18 @@ TexturePack.ASCII_PACK = TexturePack( | |||||||
|     MERCHANT='M', |     MERCHANT='M', | ||||||
|     PLAYER='@', |     PLAYER='@', | ||||||
|     RABBIT='Y', |     RABBIT='Y', | ||||||
|  |     SHIELD='D', | ||||||
|     SUNFLOWER='I', |     SUNFLOWER='I', | ||||||
|     SWORD='\u2020', |     SWORD='\u2020', | ||||||
|     TEDDY_BEAR='8', |     TEDDY_BEAR='8', | ||||||
|     TIGER='n', |     TIGER='n', | ||||||
|     TRUMPET='/', |     TRUMPET='/', | ||||||
|     WALL='#', |     WALL='#', | ||||||
|  |     EAGLE='µ', | ||||||
|  |     CHESTPLATE='(', | ||||||
|  |     HELMET='0', | ||||||
|  |     RING_OF_MORE_EXPERIENCE='o', | ||||||
|  |     RING_OF_CRITICAL_DAMAGE='o', | ||||||
| ) | ) | ||||||
|  |  | ||||||
| TexturePack.SQUIRREL_PACK = TexturePack( | TexturePack.SQUIRREL_PACK = TexturePack( | ||||||
| @@ -107,10 +119,16 @@ TexturePack.SQUIRREL_PACK = TexturePack( | |||||||
|     PLAYER='🐿️ ️', |     PLAYER='🐿️ ️', | ||||||
|     MERCHANT='🦜', |     MERCHANT='🦜', | ||||||
|     RABBIT='🐇', |     RABBIT='🐇', | ||||||
|  |     SHIELD='🛡️ ', | ||||||
|     SUNFLOWER='🌻', |     SUNFLOWER='🌻', | ||||||
|     SWORD='🗡️ ', |     SWORD='🗡️ ', | ||||||
|     TEDDY_BEAR='🧸', |     TEDDY_BEAR='🧸', | ||||||
|     TIGER='🐅', |     TIGER='🐅', | ||||||
|     TRUMPET='🎺', |     TRUMPET='🎺', | ||||||
|     WALL='🧱', |     WALL='🧱', | ||||||
|  |     EAGLE='🦅', | ||||||
|  |     CHESTPLATE='🦺', | ||||||
|  |     HELMET='⛑️', | ||||||
|  |     RING_OF_MORE_EXPERIENCE='💍', | ||||||
|  |     RING_OF_CRITICAL_DAMAGE='💍', | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ | |||||||
| from random import choice, randint | from random import choice, randint | ||||||
| from typing import Optional | from typing import Optional | ||||||
|  |  | ||||||
| from .player import Player |  | ||||||
| from ..interfaces import Entity, FightingEntity, Map, InventoryHolder | from ..interfaces import Entity, FightingEntity, Map, InventoryHolder | ||||||
| from ..translations import gettext as _ | from ..translations import gettext as _ | ||||||
|  |  | ||||||
| @@ -30,7 +29,7 @@ class Item(Entity): | |||||||
|         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.remove_from_inventory(self) | ||||||
|             self.held_by.map.add_entity(self) |             self.held_by.map.add_entity(self) | ||||||
|             self.move(self.held_by.y, self.held_by.x) |             self.move(self.held_by.y, self.held_by.x) | ||||||
|             self.held = False |             self.held = False | ||||||
| @@ -45,15 +44,27 @@ class Item(Entity): | |||||||
|         """ |         """ | ||||||
|         Indicates what should be done when the item is equipped. |         Indicates what should be done when the item is equipped. | ||||||
|         """ |         """ | ||||||
|  |         # Other objects are only equipped as secondary. | ||||||
|  |         if self.held_by.equipped_secondary: | ||||||
|  |             self.held_by.equipped_secondary.unequip() | ||||||
|  |         self.held_by.remove_from_inventory(self) | ||||||
|  |         self.held_by.equipped_secondary = self | ||||||
|  |  | ||||||
|     def hold(self, player: InventoryHolder) -> None: |     def unequip(self) -> None: | ||||||
|  |         """ | ||||||
|  |         Indicates what should be done when the item is unequipped. | ||||||
|  |         """ | ||||||
|  |         self.held_by.remove_from_inventory(self) | ||||||
|  |         self.held_by.add_to_inventory(self) | ||||||
|  |  | ||||||
|  |     def hold(self, holder: 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 = holder | ||||||
|         self.held_by.map.remove_entity(self) |         self.held_by.map.remove_entity(self) | ||||||
|         player.add_to_inventory(self) |         holder.add_to_inventory(self) | ||||||
|  |  | ||||||
|     def save_state(self) -> dict: |     def save_state(self) -> dict: | ||||||
|         """ |         """ | ||||||
| @@ -68,7 +79,8 @@ class Item(Entity): | |||||||
|         """ |         """ | ||||||
|         Returns the list of all item classes. |         Returns the list of all item classes. | ||||||
|         """ |         """ | ||||||
|         return [BodySnatchPotion, Bomb, Heart, Sword] |         return [BodySnatchPotion, Bomb, Heart, Shield, Sword, | ||||||
|  |                 Chestplate, Helmet, RingCritical, RingXP] | ||||||
|  |  | ||||||
|     def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool: |     def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool: | ||||||
|         """ |         """ | ||||||
| @@ -120,7 +132,7 @@ class Bomb(Item): | |||||||
|     """ |     """ | ||||||
|     damage: int = 5 |     damage: int = 5 | ||||||
|     exploding: bool |     exploding: bool | ||||||
|     owner: Optional["Player"] |     owner: Optional["InventoryHolder"] | ||||||
|     tick: int |     tick: int | ||||||
|  |  | ||||||
|     def __init__(self, name: str = "bomb", damage: int = 5, |     def __init__(self, name: str = "bomb", damage: int = 5, | ||||||
| @@ -193,7 +205,6 @@ class Explosion(Item): | |||||||
|         """ |         """ | ||||||
|         The player can't hold an explosion. |         The player can't hold an explosion. | ||||||
|         """ |         """ | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Weapon(Item): | class Weapon(Item): | ||||||
| @@ -214,14 +225,99 @@ class Weapon(Item): | |||||||
|         d["damage"] = self.damage |         d["damage"] = self.damage | ||||||
|         return d |         return d | ||||||
|  |  | ||||||
|  |     def equip(self) -> None: | ||||||
|  |         """ | ||||||
|  |         When a weapon is equipped, the player gains strength. | ||||||
|  |         """ | ||||||
|  |         self.held_by.remove_from_inventory(self) | ||||||
|  |         self.held_by.equipped_main = self | ||||||
|  |         self.held_by.strength += self.damage | ||||||
|  |  | ||||||
|  |     def unequip(self) -> None: | ||||||
|  |         """ | ||||||
|  |         Remove the strength earned by the weapon. | ||||||
|  |         :return: | ||||||
|  |         """ | ||||||
|  |         super().unequip() | ||||||
|  |         self.held_by.strength -= self.damage | ||||||
|  |  | ||||||
|  |  | ||||||
| class Sword(Weapon): | class Sword(Weapon): | ||||||
|     """ |     """ | ||||||
|     A basic weapon |     A basic weapon | ||||||
|     """ |     """ | ||||||
|     def __init__(self, name: str = "sword", price: int = 20, *args, **kwargs): |     def __init__(self, name: str = "sword", price: int = 20, | ||||||
|  |                  *args, **kwargs): | ||||||
|         super().__init__(name=name, price=price, *args, **kwargs) |         super().__init__(name=name, price=price, *args, **kwargs) | ||||||
|         self.name = name |  | ||||||
|  |  | ||||||
|  | class Armor(Item): | ||||||
|  |     """ | ||||||
|  |     Class of items that increase the player's constitution. | ||||||
|  |     """ | ||||||
|  |     constitution: int | ||||||
|  |  | ||||||
|  |     def __init__(self, constitution: int, *args, **kwargs): | ||||||
|  |         super().__init__(*args, **kwargs) | ||||||
|  |         self.constitution = constitution | ||||||
|  |  | ||||||
|  |     def equip(self) -> None: | ||||||
|  |         super().equip() | ||||||
|  |         self.held_by.constitution += self.constitution | ||||||
|  |  | ||||||
|  |     def unequip(self) -> None: | ||||||
|  |         super().unequip() | ||||||
|  |         self.held_by.constitution -= self.constitution | ||||||
|  |  | ||||||
|  |     def save_state(self) -> dict: | ||||||
|  |         d = super().save_state() | ||||||
|  |         d["constitution"] = self.constitution | ||||||
|  |         return d | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Shield(Armor): | ||||||
|  |     """ | ||||||
|  |     Class of shield items, they can be equipped in the other hand. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, name: str = "shield", constitution: int = 2, | ||||||
|  |                  price: int = 6, *args, **kwargs): | ||||||
|  |         super().__init__(name=name, constitution=constitution, price=price, | ||||||
|  |                          *args, **kwargs) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Helmet(Armor): | ||||||
|  |     """ | ||||||
|  |     Class of helmet items, they can be equipped on the head. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, name: str = "helmet", constitution: int = 2, | ||||||
|  |                  price: int = 8, *args, **kwargs): | ||||||
|  |         super().__init__(name=name, constitution=constitution, price=price, | ||||||
|  |                          *args, **kwargs) | ||||||
|  |  | ||||||
|  |     def equip(self) -> None: | ||||||
|  |         if self.held_by.equipped_helmet: | ||||||
|  |             self.held_by.equipped_helmet.unequip() | ||||||
|  |         self.held_by.remove_from_inventory(self) | ||||||
|  |         self.held_by.equipped_helmet = self | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Chestplate(Armor): | ||||||
|  |     """ | ||||||
|  |     Class of chestplate items, they can be equipped on the body. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, name: str = "chestplate", constitution: int = 4, | ||||||
|  |                  price: int = 15, *args, **kwargs): | ||||||
|  |         super().__init__(name=name, constitution=constitution, price=price, | ||||||
|  |                          *args, **kwargs) | ||||||
|  |  | ||||||
|  |     def equip(self) -> None: | ||||||
|  |         if self.held_by.equipped_armor: | ||||||
|  |             self.held_by.equipped_armor.unequip() | ||||||
|  |         self.held_by.remove_from_inventory(self) | ||||||
|  |         self.held_by.equipped_armor = self | ||||||
|  |  | ||||||
|  |  | ||||||
| class BodySnatchPotion(Item): | class BodySnatchPotion(Item): | ||||||
| @@ -256,3 +352,79 @@ class BodySnatchPotion(Item): | |||||||
|         self.held_by.recalculate_paths() |         self.held_by.recalculate_paths() | ||||||
|  |  | ||||||
|         self.held_by.inventory.remove(self) |         self.held_by.inventory.remove(self) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Ring(Item): | ||||||
|  |     """ | ||||||
|  |     A class of rings that boost the player's statistics. | ||||||
|  |     """ | ||||||
|  |     maxhealth: int | ||||||
|  |     strength: int | ||||||
|  |     intelligence: int | ||||||
|  |     charisma: int | ||||||
|  |     dexterity: int | ||||||
|  |     constitution: int | ||||||
|  |     critical: int | ||||||
|  |     experience: float | ||||||
|  |  | ||||||
|  |     def __init__(self, maxhealth: int = 0, strength: int = 0, | ||||||
|  |                  intelligence: int = 0, charisma: int = 0, | ||||||
|  |                  dexterity: int = 0, constitution: int = 0, | ||||||
|  |                  critical: int = 0, experience: float = 0, *args, **kwargs): | ||||||
|  |         super().__init__(*args, **kwargs) | ||||||
|  |         self.maxhealth = maxhealth | ||||||
|  |         self.strength = strength | ||||||
|  |         self.intelligence = intelligence | ||||||
|  |         self.charisma = charisma | ||||||
|  |         self.dexterity = dexterity | ||||||
|  |         self.constitution = constitution | ||||||
|  |         self.critical = critical | ||||||
|  |         self.experience = experience | ||||||
|  |  | ||||||
|  |     def equip(self) -> None: | ||||||
|  |         super().equip() | ||||||
|  |         self.held_by.maxhealth += self.maxhealth | ||||||
|  |         self.held_by.strength += self.strength | ||||||
|  |         self.held_by.intelligence += self.intelligence | ||||||
|  |         self.held_by.charisma += self.charisma | ||||||
|  |         self.held_by.dexterity += self.dexterity | ||||||
|  |         self.held_by.constitution += self.constitution | ||||||
|  |         self.held_by.critical += self.critical | ||||||
|  |         self.held_by.xp_buff += self.experience | ||||||
|  |  | ||||||
|  |     def unequip(self) -> None: | ||||||
|  |         super().unequip() | ||||||
|  |         self.held_by.maxhealth -= self.maxhealth | ||||||
|  |         self.held_by.strength -= self.strength | ||||||
|  |         self.held_by.intelligence -= self.intelligence | ||||||
|  |         self.held_by.charisma -= self.charisma | ||||||
|  |         self.held_by.dexterity -= self.dexterity | ||||||
|  |         self.held_by.constitution -= self.constitution | ||||||
|  |         self.held_by.critical -= self.critical | ||||||
|  |         self.held_by.xp_buff -= self.experience | ||||||
|  |  | ||||||
|  |     def save_state(self) -> dict: | ||||||
|  |         d = super().save_state() | ||||||
|  |         d["maxhealth"] = self.maxhealth | ||||||
|  |         d["strength"] = self.strength | ||||||
|  |         d["intelligence"] = self.intelligence | ||||||
|  |         d["charisma"] = self.charisma | ||||||
|  |         d["dexterity"] = self.dexterity | ||||||
|  |         d["constitution"] = self.constitution | ||||||
|  |         d["critical"] = self.critical | ||||||
|  |         d["experience"] = self.experience | ||||||
|  |         return d | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class RingCritical(Ring): | ||||||
|  |     def __init__(self, name: str = "ring_of_critical_damage", price: int = 15, | ||||||
|  |                  critical: int = 20, *args, **kwargs): | ||||||
|  |         super().__init__(name=name, price=price, critical=critical, | ||||||
|  |                          *args, **kwargs) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class RingXP(Ring): | ||||||
|  |     def __init__(self, name: str = "ring_of_more_experience", price: int = 25, | ||||||
|  |                  experience: float = 2, *args, **kwargs): | ||||||
|  |         super().__init__(name=name, price=price, experience=experience, | ||||||
|  |                          *args, **kwargs) | ||||||
|   | |||||||
| @@ -94,9 +94,11 @@ 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, critical: int = 30, | ||||||
|  |                  *args, **kwargs) -> None: | ||||||
|         super().__init__(name=name, strength=strength, |         super().__init__(name=name, strength=strength, | ||||||
|                          maxhealth=maxhealth, *args, **kwargs) |                          maxhealth=maxhealth, critical=critical, | ||||||
|  |                          *args, **kwargs) | ||||||
|  |  | ||||||
|  |  | ||||||
| class TeddyBear(Monster): | class TeddyBear(Monster): | ||||||
| @@ -107,3 +109,13 @@ class TeddyBear(Monster): | |||||||
|                  maxhealth: int = 50, *args, **kwargs) -> None: |                  maxhealth: int = 50, *args, **kwargs) -> None: | ||||||
|         super().__init__(name=name, strength=strength, |         super().__init__(name=name, strength=strength, | ||||||
|                          maxhealth=maxhealth, *args, **kwargs) |                          maxhealth=maxhealth, *args, **kwargs) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class GiantSeaEagle(Monster): | ||||||
|  |     """ | ||||||
|  |     An eagle boss | ||||||
|  |     """ | ||||||
|  |     def __init__(self, name: str = "eagle", strength: int = 1000, | ||||||
|  |                  maxhealth: int = 5000, *args, **kwargs) -> None: | ||||||
|  |         super().__init__(name=name, strength=strength, | ||||||
|  |                          maxhealth=maxhealth, *args, **kwargs) | ||||||
|   | |||||||
| @@ -2,7 +2,9 @@ | |||||||
| # SPDX-License-Identifier: GPL-3.0-or-later | # SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  | ||||||
| from random import randint | from random import randint | ||||||
|  | from typing import Dict, Optional, Tuple | ||||||
|  |  | ||||||
|  | from .items import Item | ||||||
| from ..interfaces import FightingEntity, InventoryHolder | from ..interfaces import FightingEntity, InventoryHolder | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -12,22 +14,40 @@ class Player(InventoryHolder, FightingEntity): | |||||||
|     """ |     """ | ||||||
|     current_xp: int = 0 |     current_xp: int = 0 | ||||||
|     max_xp: int = 10 |     max_xp: int = 10 | ||||||
|  |     xp_buff: float = 1 | ||||||
|  |     paths: Dict[Tuple[int, int], Tuple[int, int]] | ||||||
|  |     equipped_main: Optional[Item] | ||||||
|  |     equipped_secondary: Optional[Item] | ||||||
|  |     equipped_helmet: Optional[Item] | ||||||
|  |     equipped_armor: Optional[Item] | ||||||
|  |  | ||||||
|     def __init__(self, name: str = "player", maxhealth: int = 20, |     def __init__(self, name: str = "player", maxhealth: int = 20, | ||||||
|                  strength: int = 5, intelligence: int = 1, charisma: int = 1, |                  strength: int = 5, intelligence: int = 1, charisma: int = 1, | ||||||
|                  dexterity: int = 1, constitution: int = 1, level: int = 1, |                  dexterity: int = 1, constitution: int = 1, level: int = 1, | ||||||
|                  current_xp: int = 0, max_xp: int = 10, inventory: list = None, |                  current_xp: int = 0, max_xp: int = 10, inventory: list = None, | ||||||
|                  hazel: int = 42, vision: int = 5, *args, **kwargs) \ |                  hazel: int = 42, equipped_main: Optional[Item] = None, | ||||||
|             -> None: |                  equipped_armor: Optional[Item] = None, critical: int = 5, | ||||||
|  |                  equipped_secondary: Optional[Item] = None, | ||||||
|  |                  equipped_helmet: Optional[Item] = None, xp_buff: float = 1, | ||||||
|  |                  vision: int = 5, *args, **kwargs) -> None: | ||||||
|         super().__init__(name=name, maxhealth=maxhealth, strength=strength, |         super().__init__(name=name, maxhealth=maxhealth, strength=strength, | ||||||
|                          intelligence=intelligence, charisma=charisma, |                          intelligence=intelligence, charisma=charisma, | ||||||
|                          dexterity=dexterity, constitution=constitution, |                          dexterity=dexterity, constitution=constitution, | ||||||
|                          level=level, *args, **kwargs) |                          level=level, critical=critical, *args, **kwargs) | ||||||
|         self.current_xp = current_xp |         self.current_xp = current_xp | ||||||
|         self.max_xp = max_xp |         self.max_xp = max_xp | ||||||
|  |         self.xp_buff = xp_buff | ||||||
|         self.inventory = self.translate_inventory(inventory or []) |         self.inventory = self.translate_inventory(inventory or []) | ||||||
|         self.paths = dict() |         self.paths = dict() | ||||||
|         self.hazel = hazel |         self.hazel = hazel | ||||||
|  |         self.equipped_main = self.dict_to_item(equipped_main) \ | ||||||
|  |             if isinstance(equipped_main, dict) else equipped_main | ||||||
|  |         self.equipped_armor = self.dict_to_item(equipped_armor) \ | ||||||
|  |             if isinstance(equipped_armor, dict) else equipped_armor | ||||||
|  |         self.equipped_secondary = self.dict_to_item(equipped_secondary) \ | ||||||
|  |             if isinstance(equipped_secondary, dict) else equipped_secondary | ||||||
|  |         self.equipped_helmet = self.dict_to_item(equipped_helmet) \ | ||||||
|  |             if isinstance(equipped_helmet, dict) else equipped_helmet | ||||||
|         self.vision = vision |         self.vision = vision | ||||||
|  |  | ||||||
|     def move(self, y: int, x: int) -> None: |     def move(self, y: int, x: int) -> None: | ||||||
| @@ -60,9 +80,24 @@ class Player(InventoryHolder, FightingEntity): | |||||||
|         Adds some experience to the player. |         Adds some experience to the player. | ||||||
|         If the required amount is reached, the player levels up. |         If the required amount is reached, the player levels up. | ||||||
|         """ |         """ | ||||||
|         self.current_xp += xp |         self.current_xp += int(xp * self.xp_buff) | ||||||
|         self.level_up() |         self.level_up() | ||||||
|  |  | ||||||
|  |     def remove_from_inventory(self, obj: Item) -> None: | ||||||
|  |         """ | ||||||
|  |         Remove the given item from the inventory, even if the item is equipped. | ||||||
|  |         """ | ||||||
|  |         if obj == self.equipped_main: | ||||||
|  |             self.equipped_main = None | ||||||
|  |         elif obj == self.equipped_armor: | ||||||
|  |             self.equipped_armor = None | ||||||
|  |         elif obj == self.equipped_secondary: | ||||||
|  |             self.equipped_secondary = None | ||||||
|  |         elif obj == self.equipped_helmet: | ||||||
|  |             self.equipped_helmet = None | ||||||
|  |         else: | ||||||
|  |             return super().remove_from_inventory(obj) | ||||||
|  |  | ||||||
|     # noinspection PyTypeChecker,PyUnresolvedReferences |     # noinspection PyTypeChecker,PyUnresolvedReferences | ||||||
|     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: | ||||||
| @@ -92,4 +127,12 @@ class Player(InventoryHolder, FightingEntity): | |||||||
|         d = super().save_state() |         d = super().save_state() | ||||||
|         d["current_xp"] = self.current_xp |         d["current_xp"] = self.current_xp | ||||||
|         d["max_xp"] = self.max_xp |         d["max_xp"] = self.max_xp | ||||||
|  |         d["equipped_main"] = self.equipped_main.save_state()\ | ||||||
|  |             if self.equipped_main else None | ||||||
|  |         d["equipped_armor"] = self.equipped_armor.save_state()\ | ||||||
|  |             if self.equipped_armor else None | ||||||
|  |         d["equipped_secondary"] = self.equipped_secondary.save_state()\ | ||||||
|  |             if self.equipped_secondary else None | ||||||
|  |         d["equipped_helmet"] = self.equipped_helmet.save_state()\ | ||||||
|  |             if self.equipped_helmet else None | ||||||
|         return d |         return d | ||||||
|   | |||||||
| @@ -131,7 +131,7 @@ class Game: | |||||||
|             self.state = GameMode.MAINMENU |             self.state = GameMode.MAINMENU | ||||||
|         self.display_actions(DisplayActions.REFRESH) |         self.display_actions(DisplayActions.REFRESH) | ||||||
|  |  | ||||||
|     def handle_key_pressed_play(self, key: KeyValues) -> None: |     def handle_key_pressed_play(self, key: KeyValues) -> None:  # noqa: C901 | ||||||
|         """ |         """ | ||||||
|         In play mode, arrows or zqsd move the main character. |         In play mode, arrows or zqsd move the main character. | ||||||
|         """ |         """ | ||||||
| @@ -149,6 +149,12 @@ class Game: | |||||||
|                 self.map.tick(self.player) |                 self.map.tick(self.player) | ||||||
|         elif key == KeyValues.INVENTORY: |         elif key == KeyValues.INVENTORY: | ||||||
|             self.state = GameMode.INVENTORY |             self.state = GameMode.INVENTORY | ||||||
|  |             self.display_actions(DisplayActions.UPDATE) | ||||||
|  |         elif key == KeyValues.USE and self.player.equipped_main: | ||||||
|  |             if self.player.equipped_main: | ||||||
|  |                 self.player.equipped_main.use() | ||||||
|  |             if self.player.equipped_secondary: | ||||||
|  |                 self.player.equipped_secondary.use() | ||||||
|         elif key == KeyValues.SPACE: |         elif key == KeyValues.SPACE: | ||||||
|             self.state = GameMode.MAINMENU |             self.state = GameMode.MAINMENU | ||||||
|         elif key == KeyValues.CHAT: |         elif key == KeyValues.CHAT: | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
|  |  | ||||||
| from enum import Enum, auto | from enum import Enum, auto | ||||||
| from math import ceil, sqrt | from math import ceil, sqrt | ||||||
| from random import choice, randint | from random import choice, choices, randint | ||||||
| from typing import List, Optional, Any, Dict, Tuple | from typing import List, Optional, Any, Dict, Tuple | ||||||
| from queue import PriorityQueue | from queue import PriorityQueue | ||||||
| from functools import reduce | from functools import reduce | ||||||
| @@ -188,7 +188,8 @@ class Map: | |||||||
|                 tile = self.tiles[y][x] |                 tile = self.tiles[y][x] | ||||||
|                 if tile.can_walk(): |                 if tile.can_walk(): | ||||||
|                     break |                     break | ||||||
|             entity = choice(Entity.get_all_entity_classes())() |             entity = choices(Entity.get_all_entity_classes(), | ||||||
|  |                              weights=Entity.get_weights(), k=1)[0]() | ||||||
|             entity.move(y, x) |             entity.move(y, x) | ||||||
|             self.add_entity(entity) |             self.add_entity(entity) | ||||||
|  |  | ||||||
| @@ -602,11 +603,19 @@ class Entity: | |||||||
|         """ |         """ | ||||||
|         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, \ | ||||||
|             Rabbit, TeddyBear |             Rabbit, TeddyBear, GiantSeaEagle | ||||||
|         from squirrelbattle.entities.friendly import Merchant, Sunflower, \ |         from squirrelbattle.entities.friendly import Merchant, Sunflower | ||||||
|             Trumpet |  | ||||||
|         return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear, |         return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear, | ||||||
|                 Sunflower, Tiger, Merchant, Trumpet] |                 Sunflower, Tiger, Merchant, GiantSeaEagle] | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def get_weights() -> list: | ||||||
|  |         """ | ||||||
|  |         Returns a weigth list associated to the above function, to | ||||||
|  |         be used to spawn random entities with a certain probability. | ||||||
|  |         """ | ||||||
|  |         return [3, 5, 6, 5, 5, 5, | ||||||
|  |                 5, 4, 4, 1] | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def get_all_entity_classes_in_a_dict() -> dict: |     def get_all_entity_classes_in_a_dict() -> dict: | ||||||
| @@ -615,11 +624,11 @@ class Entity: | |||||||
|         """ |         """ | ||||||
|         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, \ | ||||||
|             TeddyBear |             TeddyBear, GiantSeaEagle | ||||||
|         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 |             Heart, Sword, Shield, Chestplate, Helmet, RingCritical, RingXP | ||||||
|         return { |         return { | ||||||
|             "Tiger": Tiger, |             "Tiger": Tiger, | ||||||
|             "Bomb": Bomb, |             "Bomb": Bomb, | ||||||
| @@ -633,6 +642,12 @@ class Entity: | |||||||
|             "Sunflower": Sunflower, |             "Sunflower": Sunflower, | ||||||
|             "Sword": Sword, |             "Sword": Sword, | ||||||
|             "Trumpet": Trumpet, |             "Trumpet": Trumpet, | ||||||
|  |             "Eagle": GiantSeaEagle, | ||||||
|  |             "Shield": Shield, | ||||||
|  |             "Chestplate": Chestplate, | ||||||
|  |             "Helmet": Helmet, | ||||||
|  |             "RingCritical": RingCritical, | ||||||
|  |             "RingXP": RingXP, | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     def save_state(self) -> dict: |     def save_state(self) -> dict: | ||||||
| @@ -659,11 +674,12 @@ class FightingEntity(Entity): | |||||||
|     dexterity: int |     dexterity: int | ||||||
|     constitution: int |     constitution: int | ||||||
|     level: int |     level: int | ||||||
|  |     critical: int | ||||||
|  |  | ||||||
|     def __init__(self, maxhealth: int = 0, health: Optional[int] = None, |     def __init__(self, maxhealth: int = 0, health: Optional[int] = None, | ||||||
|                  strength: int = 0, intelligence: int = 0, charisma: int = 0, |                  strength: int = 0, intelligence: int = 0, charisma: int = 0, | ||||||
|                  dexterity: int = 0, constitution: int = 0, level: int = 0, |                  dexterity: int = 0, constitution: int = 0, level: int = 0, | ||||||
|                  *args, **kwargs) -> None: |                  critical: int = 0, *args, **kwargs) -> None: | ||||||
|         super().__init__(*args, **kwargs) |         super().__init__(*args, **kwargs) | ||||||
|         self.maxhealth = maxhealth |         self.maxhealth = maxhealth | ||||||
|         self.health = maxhealth if health is None else health |         self.health = maxhealth if health is None else health | ||||||
| @@ -673,6 +689,7 @@ class FightingEntity(Entity): | |||||||
|         self.dexterity = dexterity |         self.dexterity = dexterity | ||||||
|         self.constitution = constitution |         self.constitution = constitution | ||||||
|         self.level = level |         self.level = level | ||||||
|  |         self.critical = critical | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def dead(self) -> bool: |     def dead(self) -> bool: | ||||||
| @@ -686,21 +703,28 @@ class FightingEntity(Entity): | |||||||
|         The entity deals damage to the opponent |         The entity deals damage to the opponent | ||||||
|         based on their respective stats. |         based on their respective stats. | ||||||
|         """ |         """ | ||||||
|  |         diceroll = randint(1, 100) | ||||||
|  |         damage = self.strength | ||||||
|  |         string = " " | ||||||
|  |         if diceroll <= self.critical:  # It is a critical hit | ||||||
|  |             damage *= 4 | ||||||
|  |             string = " " + _("It's a critical hit!") + " " | ||||||
|         return _("{name} hits {opponent}.")\ |         return _("{name} hits {opponent}.")\ | ||||||
|             .format(name=_(self.translated_name.capitalize()), |             .format(name=_(self.translated_name.capitalize()), | ||||||
|                     opponent=_(opponent.translated_name)) + " " + \ |                     opponent=_(opponent.translated_name)) + string + \ | ||||||
|             opponent.take_damage(self, self.strength) |             opponent.take_damage(self, damage) | ||||||
|  |  | ||||||
|     def take_damage(self, attacker: "Entity", amount: int) -> str: |     def take_damage(self, attacker: "Entity", amount: int) -> str: | ||||||
|         """ |         """ | ||||||
|         The entity takes damage from the attacker |         The entity takes damage from the attacker | ||||||
|         based on their respective stats. |         based on their respective stats. | ||||||
|         """ |         """ | ||||||
|         self.health -= amount |         damage = max(0, amount - self.constitution) | ||||||
|  |         self.health -= damage | ||||||
|         if self.health <= 0: |         if self.health <= 0: | ||||||
|             self.die() |             self.die() | ||||||
|         return _("{name} takes {amount} damage.")\ |         return _("{name} takes {damage} damage.")\ | ||||||
|             .format(name=self.translated_name.capitalize(), amount=str(amount))\ |             .format(name=self.translated_name.capitalize(), damage=str(damage))\ | ||||||
|             + (" " + _("{name} dies.") |             + (" " + _("{name} dies.") | ||||||
|                .format(name=self.translated_name.capitalize()) |                .format(name=self.translated_name.capitalize()) | ||||||
|                if self.health <= 0 else "") |                if self.health <= 0 else "") | ||||||
| @@ -757,10 +781,10 @@ class InventoryHolder(Entity): | |||||||
|         """ |         """ | ||||||
|         for i in range(len(inventory)): |         for i in range(len(inventory)): | ||||||
|             if isinstance(inventory[i], dict): |             if isinstance(inventory[i], dict): | ||||||
|                 inventory[i] = self.dict_to_inventory(inventory[i]) |                 inventory[i] = self.dict_to_item(inventory[i]) | ||||||
|         return inventory |         return inventory | ||||||
|  |  | ||||||
|     def dict_to_inventory(self, item_dict: dict) -> Entity: |     def dict_to_item(self, item_dict: dict) -> Entity: | ||||||
|         """ |         """ | ||||||
|         Translates a dictionnary 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. | ||||||
| @@ -783,12 +807,14 @@ class InventoryHolder(Entity): | |||||||
|         """ |         """ | ||||||
|         Adds an object to the inventory. |         Adds an object to the inventory. | ||||||
|         """ |         """ | ||||||
|  |         if obj not in self.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. | ||||||
|         """ |         """ | ||||||
|  |         if obj in self.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: | ||||||
|   | |||||||
| @@ -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-06 15:19+0100\n" | "POT-Creation-Date: 2021-01-08 01:57+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,10 @@ 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" | ||||||
|  |  | ||||||
|  | #, python-brace-format | ||||||
|  | msgid "{name} takes {amount} damage." | ||||||
|  | msgstr "{name} nimmt {amount} Schadenspunkte." | ||||||
|  |  | ||||||
| #: squirrelbattle/display/menudisplay.py:160 | #: squirrelbattle/display/menudisplay.py:160 | ||||||
| msgid "INVENTORY" | msgid "INVENTORY" | ||||||
| msgstr "BESTAND" | msgstr "BESTAND" | ||||||
| @@ -25,11 +29,32 @@ msgstr "BESTAND" | |||||||
| msgid "STALL" | msgid "STALL" | ||||||
| msgstr "STAND" | msgstr "STAND" | ||||||
|  |  | ||||||
| #: squirrelbattle/display/statsdisplay.py:36 | #: squirrelbattle/display/statsdisplay.py:23 | ||||||
|  | #: squirrelbattle/tests/translations_test.py:60 | ||||||
|  | msgid "player" | ||||||
|  | msgstr "Spieler" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:35 | ||||||
| msgid "Inventory:" | msgid "Inventory:" | ||||||
| msgstr "Bestand:" | msgstr "Bestand:" | ||||||
|  |  | ||||||
| #: squirrelbattle/display/statsdisplay.py:55 | #: squirrelbattle/display/statsdisplay.py:52 | ||||||
|  | msgid "Equipped main:" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:56 | ||||||
|  | msgid "Equipped secondary:" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:61 | ||||||
|  | msgid "Equipped chestplate:" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:65 | ||||||
|  | msgid "Equipped helmet:" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:72 | ||||||
| msgid "YOU ARE DEAD" | msgid "YOU ARE DEAD" | ||||||
| msgstr "SIE WURDEN GESTORBEN" | msgstr "SIE WURDEN GESTORBEN" | ||||||
|  |  | ||||||
| @@ -49,11 +74,11 @@ msgstr "Die Sonne ist warm heute" | |||||||
| #. The bomb is exploding. | #. The bomb is exploding. | ||||||
| #. Each entity that is close to the bomb takes damages. | #. Each entity that is close to the bomb takes damages. | ||||||
| #. The player earn XP if the entity was killed. | #. The player earn XP if the entity was killed. | ||||||
| #: squirrelbattle/entities/items.py:151 | #: squirrelbattle/entities/items.py:163 | ||||||
| msgid "Bomb is exploding." | msgid "Bomb is exploding." | ||||||
| msgstr "Die Bombe explodiert." | msgstr "Die Bombe explodiert." | ||||||
|  |  | ||||||
| #: squirrelbattle/entities/items.py:248 | #: squirrelbattle/entities/items.py:344 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{player} exchanged its body with {entity}." | msgid "{player} exchanged its body with {entity}." | ||||||
| msgstr "{player} täuscht seinem Körper mit {entity} aus." | msgstr "{player} täuscht seinem Körper mit {entity} aus." | ||||||
| @@ -96,6 +121,10 @@ 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:452 | ||||||
|  | msgid "It's a critical hit!" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:453 | #: squirrelbattle/interfaces.py:453 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{name} hits {opponent}." | msgid "{name} hits {opponent}." | ||||||
| @@ -103,8 +132,8 @@ msgstr "{name} schlägt {opponent}." | |||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:465 | #: squirrelbattle/interfaces.py:465 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{name} takes {amount} damage." | msgid "{name} takes {damage} damage." | ||||||
| msgstr "{name} nimmt {amount} Schadenspunkte." | msgstr "" | ||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:467 | #: squirrelbattle/interfaces.py:467 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| @@ -218,10 +247,6 @@ msgstr "Textur-Packung" | |||||||
| msgid "Language" | msgid "Language" | ||||||
| msgstr "Sprache" | msgstr "Sprache" | ||||||
|  |  | ||||||
| #: squirrelbattle/tests/translations_test.py:62 |  | ||||||
| msgid "player" |  | ||||||
| msgstr "Spieler" |  | ||||||
|  |  | ||||||
| #: squirrelbattle/tests/translations_test.py:64 | #: squirrelbattle/tests/translations_test.py:64 | ||||||
| msgid "hedgehog" | msgid "hedgehog" | ||||||
| msgstr "Igel" | msgstr "Igel" | ||||||
|   | |||||||
| @@ -17,6 +17,10 @@ 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" | ||||||
|  |  | ||||||
|  | #, python-brace-format | ||||||
|  | msgid "{name} takes {amount} damage." | ||||||
|  | msgstr "{name} recibe {amount} daño." | ||||||
|  |  | ||||||
| #: squirrelbattle/display/menudisplay.py:160 | #: squirrelbattle/display/menudisplay.py:160 | ||||||
| msgid "INVENTORY" | msgid "INVENTORY" | ||||||
| msgstr "INVENTORIO" | msgstr "INVENTORIO" | ||||||
| @@ -25,11 +29,32 @@ msgstr "INVENTORIO" | |||||||
| msgid "STALL" | msgid "STALL" | ||||||
| msgstr "PUESTO" | msgstr "PUESTO" | ||||||
|  |  | ||||||
| #: squirrelbattle/display/statsdisplay.py:36 | #: squirrelbattle/display/statsdisplay.py:23 | ||||||
|  | #: squirrelbattle/tests/translations_test.py:60 | ||||||
|  | msgid "player" | ||||||
|  | msgstr "jugador" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:35 | ||||||
| msgid "Inventory:" | msgid "Inventory:" | ||||||
| msgstr "Inventorio :" | msgstr "Inventorio :" | ||||||
|  |  | ||||||
| #: squirrelbattle/display/statsdisplay.py:55 | #: squirrelbattle/display/statsdisplay.py:52 | ||||||
|  | msgid "Equipped main:" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:56 | ||||||
|  | msgid "Equipped secondary:" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:61 | ||||||
|  | msgid "Equipped chestplate:" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:65 | ||||||
|  | msgid "Equipped helmet:" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:72 | ||||||
| msgid "YOU ARE DEAD" | msgid "YOU ARE DEAD" | ||||||
| msgstr "ERES MUERTO" | msgstr "ERES MUERTO" | ||||||
|  |  | ||||||
| @@ -48,11 +73,11 @@ msgstr "El sol está caliente hoy" | |||||||
| #. The bomb is exploding. | #. The bomb is exploding. | ||||||
| #. Each entity that is close to the bomb takes damages. | #. Each entity that is close to the bomb takes damages. | ||||||
| #. The player earn XP if the entity was killed. | #. The player earn XP if the entity was killed. | ||||||
| #: squirrelbattle/entities/items.py:151 | #: squirrelbattle/entities/items.py:163 | ||||||
| msgid "Bomb is exploding." | msgid "Bomb is exploding." | ||||||
| msgstr "La bomba está explotando." | msgstr "La bomba está explotando." | ||||||
|  |  | ||||||
| #: squirrelbattle/entities/items.py:248 | #: squirrelbattle/entities/items.py:344 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{player} exchanged its body with {entity}." | msgid "{player} exchanged its body with {entity}." | ||||||
| msgstr "{player} intercambió su cuerpo con {entity}." | msgstr "{player} intercambió su cuerpo con {entity}." | ||||||
| @@ -95,6 +120,10 @@ 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:452 | ||||||
|  | msgid "It's a critical hit!" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:453 | #: squirrelbattle/interfaces.py:453 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{name} hits {opponent}." | msgid "{name} hits {opponent}." | ||||||
| @@ -102,8 +131,8 @@ msgstr "{name} golpea a {opponent}." | |||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:465 | #: squirrelbattle/interfaces.py:465 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{name} takes {amount} damage." | msgid "{name} takes {damage} damage." | ||||||
| msgstr "{name} recibe {amount} daño." | msgstr "" | ||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:467 | #: squirrelbattle/interfaces.py:467 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| @@ -217,10 +246,6 @@ msgstr "Paquete de texturas" | |||||||
| msgid "Language" | msgid "Language" | ||||||
| msgstr "Languaje" | msgstr "Languaje" | ||||||
|  |  | ||||||
| #: squirrelbattle/tests/translations_test.py:62 |  | ||||||
| msgid "player" |  | ||||||
| msgstr "jugador" |  | ||||||
|  |  | ||||||
| #: squirrelbattle/tests/translations_test.py:64 | #: squirrelbattle/tests/translations_test.py:64 | ||||||
| msgid "hedgehog" | msgid "hedgehog" | ||||||
| msgstr "erizo" | msgstr "erizo" | ||||||
|   | |||||||
| @@ -17,6 +17,10 @@ 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" | ||||||
|  |  | ||||||
|  | #, python-brace-format | ||||||
|  | msgid "{name} takes {amount} damage." | ||||||
|  | msgstr "{name} prend {amount} points de dégât." | ||||||
|  |  | ||||||
| #: squirrelbattle/display/menudisplay.py:160 | #: squirrelbattle/display/menudisplay.py:160 | ||||||
| msgid "INVENTORY" | msgid "INVENTORY" | ||||||
| msgstr "INVENTAIRE" | msgstr "INVENTAIRE" | ||||||
| @@ -25,11 +29,32 @@ msgstr "INVENTAIRE" | |||||||
| msgid "STALL" | msgid "STALL" | ||||||
| msgstr "STAND" | msgstr "STAND" | ||||||
|  |  | ||||||
| #: squirrelbattle/display/statsdisplay.py:36 | #: squirrelbattle/display/statsdisplay.py:23 | ||||||
|  | #: squirrelbattle/tests/translations_test.py:60 | ||||||
|  | msgid "player" | ||||||
|  | msgstr "joueur" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:35 | ||||||
| msgid "Inventory:" | msgid "Inventory:" | ||||||
| msgstr "Inventaire :" | msgstr "Inventaire :" | ||||||
|  |  | ||||||
| #: squirrelbattle/display/statsdisplay.py:55 | #: squirrelbattle/display/statsdisplay.py:52 | ||||||
|  | msgid "Equipped main:" | ||||||
|  | msgstr "Équipement principal :" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:56 | ||||||
|  | msgid "Equipped secondary:" | ||||||
|  | msgstr "Équipement secondaire :" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:61 | ||||||
|  | msgid "Equipped chestplate:" | ||||||
|  | msgstr "Plastron équipé :" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:65 | ||||||
|  | msgid "Equipped helmet:" | ||||||
|  | msgstr "Casque équipé :" | ||||||
|  |  | ||||||
|  | #: squirrelbattle/display/statsdisplay.py:72 | ||||||
| msgid "YOU ARE DEAD" | msgid "YOU ARE DEAD" | ||||||
| msgstr "VOUS ÊTES MORT" | msgstr "VOUS ÊTES MORT" | ||||||
|  |  | ||||||
| @@ -49,11 +74,11 @@ msgstr "Le soleil est chaud aujourd'hui" | |||||||
| #. The bomb is exploding. | #. The bomb is exploding. | ||||||
| #. Each entity that is close to the bomb takes damages. | #. Each entity that is close to the bomb takes damages. | ||||||
| #. The player earn XP if the entity was killed. | #. The player earn XP if the entity was killed. | ||||||
| #: squirrelbattle/entities/items.py:151 | #: squirrelbattle/entities/items.py:163 | ||||||
| msgid "Bomb is exploding." | msgid "Bomb is exploding." | ||||||
| msgstr "La bombe explose." | msgstr "La bombe explose." | ||||||
|  |  | ||||||
| #: squirrelbattle/entities/items.py:248 | #: squirrelbattle/entities/items.py:344 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{player} exchanged its body with {entity}." | msgid "{player} exchanged its body with {entity}." | ||||||
| msgstr "{player} a échangé son corps avec {entity}." | msgstr "{player} a échangé son corps avec {entity}." | ||||||
| @@ -96,6 +121,10 @@ 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:452 | ||||||
|  | msgid "It's a critical hit!" | ||||||
|  | msgstr "C'est un coup critique !" | ||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:453 | #: squirrelbattle/interfaces.py:453 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{name} hits {opponent}." | msgid "{name} hits {opponent}." | ||||||
| @@ -103,8 +132,8 @@ msgstr "{name} frappe {opponent}." | |||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:465 | #: squirrelbattle/interfaces.py:465 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "{name} takes {amount} damage." | msgid "{name} takes {damage} damage." | ||||||
| msgstr "{name} prend {amount} points de dégât." | msgstr "{name} prend {damage} dégâts." | ||||||
|  |  | ||||||
| #: squirrelbattle/interfaces.py:467 | #: squirrelbattle/interfaces.py:467 | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| @@ -218,10 +247,6 @@ msgstr "Pack de textures" | |||||||
| msgid "Language" | msgid "Language" | ||||||
| msgstr "Langue" | msgstr "Langue" | ||||||
|  |  | ||||||
| #: squirrelbattle/tests/translations_test.py:62 |  | ||||||
| msgid "player" |  | ||||||
| msgstr "joueur" |  | ||||||
|  |  | ||||||
| #: squirrelbattle/tests/translations_test.py:64 | #: squirrelbattle/tests/translations_test.py:64 | ||||||
| msgid "hedgehog" | msgid "hedgehog" | ||||||
| msgstr "hérisson" | msgstr "hérisson" | ||||||
| @@ -256,7 +281,7 @@ msgstr "bombe" | |||||||
|  |  | ||||||
| #: squirrelbattle/tests/translations_test.py:73 | #: squirrelbattle/tests/translations_test.py:73 | ||||||
| msgid "explosion" | msgid "explosion" | ||||||
| msgstr "" | msgstr "explosion" | ||||||
|  |  | ||||||
| #: squirrelbattle/tests/translations_test.py:74 | #: squirrelbattle/tests/translations_test.py:74 | ||||||
| msgid "heart" | msgid "heart" | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ class TestEntities(unittest.TestCase): | |||||||
|         """ |         """ | ||||||
|         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() | ||||||
|  |         self.player.constitution = 0 | ||||||
|         self.map.add_entity(self.player) |         self.map.add_entity(self.player) | ||||||
|         self.player.move(self.map.start_y, self.map.start_x) |         self.player.move(self.map.start_y, self.map.start_x) | ||||||
|  |  | ||||||
| @@ -55,6 +56,7 @@ class TestEntities(unittest.TestCase): | |||||||
|         self.assertTrue(entity.dead) |         self.assertTrue(entity.dead) | ||||||
|  |  | ||||||
|         entity = Rabbit() |         entity = Rabbit() | ||||||
|  |         entity.critical = 0 | ||||||
|         self.map.add_entity(entity) |         self.map.add_entity(entity) | ||||||
|         entity.move(15, 44) |         entity.move(15, 44) | ||||||
|         # Move randomly |         # Move randomly | ||||||
| @@ -76,6 +78,7 @@ class TestEntities(unittest.TestCase): | |||||||
| {self.player.name.capitalize()} takes {entity.strength} damage.") | {self.player.name.capitalize()} takes {entity.strength} damage.") | ||||||
|  |  | ||||||
|         # Fight the rabbit |         # Fight the rabbit | ||||||
|  |         self.player.critical = 0 | ||||||
|         old_health = entity.health |         old_health = entity.health | ||||||
|         self.player.move_down() |         self.player.move_down() | ||||||
|         self.assertEqual(entity.health, old_health - self.player.strength) |         self.assertEqual(entity.health, old_health - self.player.strength) | ||||||
|   | |||||||
| @@ -2,13 +2,16 @@ | |||||||
| # SPDX-License-Identifier: GPL-3.0-or-later | # SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  | ||||||
| import os | import os | ||||||
|  | import random | ||||||
| import unittest | import unittest | ||||||
|  |  | ||||||
| from ..bootstrap import Bootstrap | from ..bootstrap import Bootstrap | ||||||
| from ..display.display import Display | 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 | from ..entities.items import Bomb, Heart, Sword, Explosion, Shield, Helmet, \ | ||||||
|  |     Chestplate, RingCritical | ||||||
|  | from ..entities.monsters import GiantSeaEagle | ||||||
| from ..entities.player import Player | from ..entities.player import Player | ||||||
| from ..enums import DisplayActions | from ..enums import DisplayActions | ||||||
| from ..game import Game, KeyValues, GameMode | from ..game import Game, KeyValues, GameMode | ||||||
| @@ -613,6 +616,100 @@ class TestGame(unittest.TestCase): | |||||||
|         self.game.handle_key_pressed(KeyValues.SPACE) |         self.game.handle_key_pressed(KeyValues.SPACE) | ||||||
|         self.assertEqual(self.game.state, GameMode.PLAY) |         self.assertEqual(self.game.state, GameMode.PLAY) | ||||||
|  |  | ||||||
|  |     def test_equipment(self) -> None: | ||||||
|  |         """ | ||||||
|  |         Ensure that equipment is working. | ||||||
|  |         """ | ||||||
|  |         self.game.state = GameMode.INVENTORY | ||||||
|  |  | ||||||
|  |         # sword goes into the main equipment slot | ||||||
|  |         sword = Sword() | ||||||
|  |         sword.hold(self.game.player) | ||||||
|  |         self.game.handle_key_pressed(KeyValues.EQUIP) | ||||||
|  |         self.assertEqual(self.game.player.equipped_main, sword) | ||||||
|  |         self.assertFalse(self.game.player.inventory) | ||||||
|  |  | ||||||
|  |         # shield goes into the secondary equipment slot | ||||||
|  |         shield = Shield() | ||||||
|  |         shield.hold(self.game.player) | ||||||
|  |         self.game.handle_key_pressed(KeyValues.EQUIP) | ||||||
|  |         self.assertEqual(self.game.player.equipped_secondary, shield) | ||||||
|  |         self.assertFalse(self.game.player.inventory) | ||||||
|  |  | ||||||
|  |         # helmet goes into the helmet slot | ||||||
|  |         helmet = Helmet() | ||||||
|  |         helmet.hold(self.game.player) | ||||||
|  |         self.game.handle_key_pressed(KeyValues.EQUIP) | ||||||
|  |         self.assertEqual(self.game.player.equipped_helmet, helmet) | ||||||
|  |         self.assertFalse(self.game.player.inventory) | ||||||
|  |  | ||||||
|  |         # helmet goes into the armor slot | ||||||
|  |         chestplate = Chestplate() | ||||||
|  |         chestplate.hold(self.game.player) | ||||||
|  |         self.game.handle_key_pressed(KeyValues.EQUIP) | ||||||
|  |         self.assertEqual(self.game.player.equipped_armor, chestplate) | ||||||
|  |         self.assertFalse(self.game.player.inventory) | ||||||
|  |  | ||||||
|  |         # Use bomb | ||||||
|  |         bomb = Bomb() | ||||||
|  |         bomb.hold(self.game.player) | ||||||
|  |         self.game.handle_key_pressed(KeyValues.EQUIP) | ||||||
|  |         self.assertEqual(self.game.player.equipped_secondary, bomb) | ||||||
|  |         self.assertIn(shield, self.game.player.inventory) | ||||||
|  |         self.game.state = GameMode.PLAY | ||||||
|  |         self.game.handle_key_pressed(KeyValues.USE) | ||||||
|  |         self.assertIsNone(self.game.player.equipped_secondary) | ||||||
|  |         self.game.state = GameMode.INVENTORY | ||||||
|  |         self.game.handle_key_pressed(KeyValues.EQUIP) | ||||||
|  |         self.assertEqual(self.game.player.equipped_secondary, shield) | ||||||
|  |         self.assertFalse(self.game.player.inventory) | ||||||
|  |  | ||||||
|  |         # Reequip, which is useless but covers code | ||||||
|  |         sword.equip() | ||||||
|  |         shield.equip() | ||||||
|  |         helmet.equip() | ||||||
|  |         chestplate.equip() | ||||||
|  |         self.game.save_state() | ||||||
|  |  | ||||||
|  |         # Unequip all | ||||||
|  |         sword.unequip() | ||||||
|  |         shield.unequip() | ||||||
|  |         helmet.unequip() | ||||||
|  |         chestplate.unequip() | ||||||
|  |         self.assertIsNone(self.game.player.equipped_main) | ||||||
|  |         self.assertIsNone(self.game.player.equipped_secondary) | ||||||
|  |         self.assertIsNone(self.game.player.equipped_helmet) | ||||||
|  |         self.assertIsNone(self.game.player.equipped_armor) | ||||||
|  |         self.assertIn(sword, self.game.player.inventory) | ||||||
|  |         self.assertIn(shield, self.game.player.inventory) | ||||||
|  |         self.assertIn(helmet, self.game.player.inventory) | ||||||
|  |         self.assertIn(chestplate, self.game.player.inventory) | ||||||
|  |  | ||||||
|  |         # Test rings | ||||||
|  |         self.game.player.inventory.clear() | ||||||
|  |         ring = RingCritical() | ||||||
|  |         ring.hold(self.game.player) | ||||||
|  |         old_critical = self.game.player.critical | ||||||
|  |         self.game.handle_key_pressed(KeyValues.EQUIP) | ||||||
|  |         self.assertEqual(self.game.player.critical, | ||||||
|  |                          old_critical + ring.critical) | ||||||
|  |         self.game.save_state() | ||||||
|  |         ring.unequip() | ||||||
|  |  | ||||||
|  |     def test_critical_hit(self) -> None: | ||||||
|  |         """ | ||||||
|  |         Ensure that critical hits are working. | ||||||
|  |         """ | ||||||
|  |         random.seed(2)  # Next random.randint(1, 100) will output 8 | ||||||
|  |         self.game.player.critical = 10 | ||||||
|  |         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) | ||||||
|  |  | ||||||
|     def test_ladders(self) -> None: |     def test_ladders(self) -> None: | ||||||
|         """ |         """ | ||||||
|         Ensure that the player can climb on ladders. |         Ensure that the player can climb on ladders. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user