Merge branch 'equipment' into doc

This commit is contained in:
Eichhornchen 2021-01-06 14:49:09 +01:00
commit 2dc178d67c
8 changed files with 341 additions and 40 deletions

View File

@ -23,15 +23,16 @@ class StatsDisplay(Display):
self.player = game.player self.player = game.player
def update_pad(self) -> None: def update_pad(self) -> None:
string2 = "Player -- LVL {}\nEXP {}/{}\nHP {}/{}"\ string2 = _("player").capitalize() + " -- LVL {}\nEXP {}/{}\nHP {}/{}"\
.format(self.player.level, self.player.current_xp, .format(self.player.level, self.player.current_xp,
self.player.max_xp, self.player.health, self.player.max_xp, self.player.health,
self.player.maxhealth) self.player.maxhealth)
self.addstr(self.pad, 0, 0, string2) self.addstr(self.pad, 0, 0, string2)
string3 = "STR {}\nINT {}\nCHR {}\nDEX {}\nCON {}"\ string3 = "STR {}\nINT {}\nCHR {}\nDEX {}\nCON {}\nCRI {}%"\
.format(self.player.strength, .format(self.player.strength,
self.player.intelligence, self.player.charisma, self.player.intelligence, self.player.charisma,
self.player.dexterity, self.player.constitution) self.player.dexterity, self.player.constitution,\
self.player.critical)
self.addstr(self.pad, 3, 0, string3) self.addstr(self.pad, 3, 0, string3)
inventory_str = _("Inventory:") + " " inventory_str = _("Inventory:") + " "
@ -47,13 +48,30 @@ 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:
f"x{self.player.hazel}") 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:") + " "
f"{self.pack[self.player.equipped_secondary.name.upper()]}")
if self.player.equipped_armor:
self.addstr(self.pad, 12, 0,
_("Equipped chestplate:") + " "
f"{self.pack[self.player.equipped_armor.name.upper()]}")
if self.player.equipped_helmet:
self.addstr(self.pad, 13, 0,
_("Equipped helmet:") + " "
f"{self.pack[self.player.equipped_helmet.name.upper()]}")
self.addstr(self.pad, 14, 0, f"{self.pack.HAZELNUT} "
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:

View File

@ -34,6 +34,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"
@ -64,7 +70,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='.',
@ -74,12 +80,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(
@ -101,10 +113,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='💍',
) )

View File

@ -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,58 @@ class Item(Entity):
""" """
Indicates what should be done when the item is equipped. Indicates what should be done when the item is equipped.
""" """
if isinstance(self, Chestplate):
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
elif isinstance(self, Helmet):
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
elif isinstance(self, Weapon):
if self.held_by.equipped_main:
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
# For weapons, they are equipped as main only if main is empty.
else:
self.held_by.remove_from_inventory(self)
self.held_by.equipped_main = self
else:
# 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.
"""
if isinstance(self, Chestplate):
self.held_by.equipped_armor = None
elif isinstance(self, Helmet):
self.held_by.equipped_helmet = None
elif isinstance(self, Weapon):
if self.held_by.equipped_main == self:
self.held_by.equipped_main = None
else:
self.held_by.equipped_secondary = None
else:
self.held_by.equipped_secondary = None
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 +110,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 +163,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,
@ -214,14 +257,80 @@ 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.
"""
super().equip()
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, *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, *args, **kwargs)
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, *args, **kwargs)
class BodySnatchPotion(Item): class BodySnatchPotion(Item):
@ -256,3 +365,69 @@ 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["constitution"] = self.constitution
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)

View File

@ -94,9 +94,9 @@ 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 +107,12 @@ 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)

View File

@ -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,44 @@ 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, *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,\
*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
if isinstance(equipped_main, dict):
equipped_main = self.dict_to_item(equipped_main)
if isinstance(equipped_armor, dict):
equipped_armor = self.dict_to_item(equipped_armor)
if isinstance(equipped_secondary, dict):
equipped_secondary = self.dict_to_item(equipped_secondary)
if isinstance(equipped_helmet, dict):
equipped_helmet = self.dict_to_item(equipped_helmet)
self.equipped_main = equipped_main
self.equipped_armor = equipped_armor
self.equipped_secondary = equipped_secondary
self.equipped_helmet = equipped_helmet
def move(self, y: int, x: int) -> None: def move(self, y: int, x: int) -> None:
""" """
@ -58,9 +82,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:
@ -90,4 +129,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

View File

@ -128,6 +128,9 @@ 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:
self.player.equipped_main.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:

View File

@ -7,6 +7,8 @@ from random import choice, 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
from random import choice, randint, choices
from typing import List, Optional, Any
from .display.texturepack import TexturePack from .display.texturepack import TexturePack
from .translations import gettext as _ from .translations import gettext as _
@ -152,7 +154,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)
@ -421,11 +424,20 @@ 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 Trumpet
return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear, return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear,
Sunflower, Tiger, Merchant, Trumpet] Sunflower, Tiger, Merchant, GiantSeaEagle, Trumpet]
@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:
@ -434,11 +446,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,
@ -452,6 +464,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:
@ -478,11 +496,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
@ -492,6 +511,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:
@ -505,21 +525,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(0, 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 "")
@ -576,10 +603,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.
@ -602,13 +629,15 @@ class InventoryHolder(Entity):
""" """
Adds an object to the inventory. Adds an object to the inventory.
""" """
self.inventory.append(obj) if obj not in self.inventory:
self.inventory.append(obj)
def remove_from_inventory(self, obj: Any) -> None: def remove_from_inventory(self, obj: Any) -> None:
""" """
Removes an object from the inventory. Removes an object from the inventory.
""" """
self.inventory.remove(obj) if obj in self.inventory:
self.inventory.remove(obj)
def change_hazel_balance(self, hz: int) -> None: def change_hazel_balance(self, hz: int) -> None:
""" """

View File

@ -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