Merge branch 'moreitems' into 'master'
Moreitems Closes #64 and #60 See merge request ynerant/squirrel-battle!60
This commit is contained in:
commit
93a9e5e4c4
|
@ -10,7 +10,8 @@ from squirrelbattle.display.mapdisplay import MapDisplay
|
||||||
from squirrelbattle.display.messagedisplay import MessageDisplay
|
from squirrelbattle.display.messagedisplay import MessageDisplay
|
||||||
from squirrelbattle.display.statsdisplay import StatsDisplay
|
from squirrelbattle.display.statsdisplay import StatsDisplay
|
||||||
from squirrelbattle.display.menudisplay import MainMenuDisplay, \
|
from squirrelbattle.display.menudisplay import MainMenuDisplay, \
|
||||||
PlayerInventoryDisplay, StoreInventoryDisplay, SettingsMenuDisplay
|
PlayerInventoryDisplay, StoreInventoryDisplay, SettingsMenuDisplay, \
|
||||||
|
ChestInventoryDisplay
|
||||||
from squirrelbattle.display.logsdisplay import LogsDisplay
|
from squirrelbattle.display.logsdisplay import LogsDisplay
|
||||||
from squirrelbattle.display.texturepack import TexturePack
|
from squirrelbattle.display.texturepack import TexturePack
|
||||||
from typing import Any, List
|
from typing import Any, List
|
||||||
|
@ -29,6 +30,7 @@ class DisplayManager:
|
||||||
self.logsdisplay = LogsDisplay(screen, pack)
|
self.logsdisplay = LogsDisplay(screen, pack)
|
||||||
self.playerinventorydisplay = PlayerInventoryDisplay(screen, pack)
|
self.playerinventorydisplay = PlayerInventoryDisplay(screen, pack)
|
||||||
self.storeinventorydisplay = StoreInventoryDisplay(screen, pack)
|
self.storeinventorydisplay = StoreInventoryDisplay(screen, pack)
|
||||||
|
self.chestinventorydisplay = ChestInventoryDisplay(screen, pack)
|
||||||
self.mainmenudisplay = MainMenuDisplay(self.game.main_menu,
|
self.mainmenudisplay = MainMenuDisplay(self.game.main_menu,
|
||||||
screen, pack)
|
screen, pack)
|
||||||
self.settingsmenudisplay = SettingsMenuDisplay(screen, pack)
|
self.settingsmenudisplay = SettingsMenuDisplay(screen, pack)
|
||||||
|
@ -40,7 +42,8 @@ class DisplayManager:
|
||||||
self.mainmenudisplay, self.settingsmenudisplay,
|
self.mainmenudisplay, self.settingsmenudisplay,
|
||||||
self.logsdisplay, self.messagedisplay,
|
self.logsdisplay, self.messagedisplay,
|
||||||
self.playerinventorydisplay,
|
self.playerinventorydisplay,
|
||||||
self.storeinventorydisplay, self.creditsdisplay]
|
self.storeinventorydisplay, self.creditsdisplay,
|
||||||
|
self.chestinventorydisplay]
|
||||||
self.update_game_components()
|
self.update_game_components()
|
||||||
|
|
||||||
def handle_display_action(self, action: DisplayActions, *params) -> None:
|
def handle_display_action(self, action: DisplayActions, *params) -> None:
|
||||||
|
@ -87,7 +90,8 @@ class DisplayManager:
|
||||||
|
|
||||||
if self.game.state == GameMode.PLAY \
|
if self.game.state == GameMode.PLAY \
|
||||||
or self.game.state == GameMode.INVENTORY \
|
or self.game.state == GameMode.INVENTORY \
|
||||||
or self.game.state == GameMode.STORE:
|
or self.game.state == GameMode.STORE\
|
||||||
|
or self.game.state == GameMode.CHEST:
|
||||||
# The map pad has already the good size
|
# The map pad has already the good size
|
||||||
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5,
|
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5,
|
||||||
self.mapdisplay.pack.tile_width
|
self.mapdisplay.pack.tile_width
|
||||||
|
@ -124,6 +128,19 @@ class DisplayManager:
|
||||||
pack.tile_width * (2 * self.cols // (5 * pack.tile_width)))
|
pack.tile_width * (2 * self.cols // (5 * pack.tile_width)))
|
||||||
displays.append(self.storeinventorydisplay)
|
displays.append(self.storeinventorydisplay)
|
||||||
displays.append(self.playerinventorydisplay)
|
displays.append(self.playerinventorydisplay)
|
||||||
|
elif self.game.state == GameMode.CHEST:
|
||||||
|
self.chestinventorydisplay.refresh(
|
||||||
|
self.rows // 10,
|
||||||
|
pack.tile_width * (self.cols // (2 * pack.tile_width)),
|
||||||
|
8 * self.rows // 10,
|
||||||
|
pack.tile_width * (2 * self.cols // (5 * pack.tile_width)))
|
||||||
|
self.playerinventorydisplay.refresh(
|
||||||
|
self.rows // 10,
|
||||||
|
pack.tile_width * (self.cols // (10 * pack.tile_width)),
|
||||||
|
8 * self.rows // 10,
|
||||||
|
pack.tile_width * (2 * self.cols // (5 * pack.tile_width)))
|
||||||
|
displays.append(self.chestinventorydisplay)
|
||||||
|
displays.append(self.playerinventorydisplay)
|
||||||
elif self.game.state == GameMode.MAINMENU:
|
elif self.game.state == GameMode.MAINMENU:
|
||||||
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
|
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
|
||||||
displays.append(self.mainmenudisplay)
|
displays.append(self.mainmenudisplay)
|
||||||
|
|
|
@ -5,7 +5,8 @@ import curses
|
||||||
from random import randint
|
from random import randint
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from squirrelbattle.menus import Menu, MainMenu, SettingsMenu, StoreMenu
|
from squirrelbattle.menus import Menu, MainMenu, SettingsMenu, StoreMenu,\
|
||||||
|
ChestMenu
|
||||||
from .display import Box, Display
|
from .display import Box, Display
|
||||||
from ..entities.player import Player
|
from ..entities.player import Player
|
||||||
from ..enums import KeyValues, GameMode
|
from ..enums import KeyValues, GameMode
|
||||||
|
@ -156,13 +157,16 @@ class PlayerInventoryDisplay(MenuDisplay):
|
||||||
player: Player = None
|
player: Player = None
|
||||||
selected: bool = True
|
selected: bool = True
|
||||||
store_mode: bool = False
|
store_mode: bool = False
|
||||||
|
chest_mode: bool = False
|
||||||
|
|
||||||
def update(self, game: Game) -> None:
|
def update(self, game: Game) -> None:
|
||||||
self.player = game.player
|
self.player = game.player
|
||||||
self.update_menu(game.inventory_menu)
|
self.update_menu(game.inventory_menu)
|
||||||
self.store_mode = game.state == GameMode.STORE
|
self.store_mode = game.state == GameMode.STORE
|
||||||
|
self.chest_mode = game.state == GameMode.CHEST
|
||||||
self.selected = game.state == GameMode.INVENTORY \
|
self.selected = game.state == GameMode.INVENTORY \
|
||||||
or (self.store_mode and not game.is_in_store_menu)
|
or (self.store_mode and not game.is_in_store_menu)\
|
||||||
|
or (self.chest_mode and not game.is_in_chest_menu)
|
||||||
|
|
||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
self.menubox.update_title(_("INVENTORY"))
|
self.menubox.update_title(_("INVENTORY"))
|
||||||
|
@ -241,3 +245,40 @@ class StoreInventoryDisplay(MenuDisplay):
|
||||||
self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2))
|
self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2))
|
||||||
game.is_in_store_menu = True
|
game.is_in_store_menu = True
|
||||||
game.handle_key_pressed(KeyValues.ENTER)
|
game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
|
||||||
|
|
||||||
|
class ChestInventoryDisplay(MenuDisplay):
|
||||||
|
"""
|
||||||
|
A class to handle the display of a merchant's inventory.
|
||||||
|
"""
|
||||||
|
menu: ChestMenu
|
||||||
|
selected: bool = False
|
||||||
|
|
||||||
|
def update(self, game: Game) -> None:
|
||||||
|
self.update_menu(game.chest_menu)
|
||||||
|
self.selected = game.is_in_chest_menu
|
||||||
|
|
||||||
|
def update_pad(self) -> None:
|
||||||
|
self.menubox.update_title(_("CHEST"))
|
||||||
|
for i, item in enumerate(self.menu.values):
|
||||||
|
rep = self.pack[item.name.upper()]
|
||||||
|
selection = f"[{rep}]" if i == self.menu.position \
|
||||||
|
and self.selected else f" {rep} "
|
||||||
|
self.addstr(self.pad, i + 1, 0, selection
|
||||||
|
+ " " + item.translated_name.capitalize())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def truewidth(self) -> int:
|
||||||
|
return max(1, self.height if hasattr(self, "height") else 10)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def trueheight(self) -> int:
|
||||||
|
return 2 + super().trueheight
|
||||||
|
|
||||||
|
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
|
||||||
|
"""
|
||||||
|
We can select a menu item with the mouse.
|
||||||
|
"""
|
||||||
|
self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2))
|
||||||
|
game.is_in_chest_menu = True
|
||||||
|
game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
|
|
@ -21,9 +21,12 @@ class TexturePack:
|
||||||
|
|
||||||
BODY_SNATCH_POTION: str
|
BODY_SNATCH_POTION: str
|
||||||
BOMB: str
|
BOMB: str
|
||||||
|
BOW: str
|
||||||
|
CHEST: str
|
||||||
CHESTPLATE: str
|
CHESTPLATE: str
|
||||||
EAGLE: str
|
EAGLE: str
|
||||||
EMPTY: str
|
EMPTY: str
|
||||||
|
FIRE_BALL_STAFF: str
|
||||||
FLOOR: str
|
FLOOR: str
|
||||||
HAZELNUT: str
|
HAZELNUT: str
|
||||||
HEART: str
|
HEART: str
|
||||||
|
@ -34,6 +37,9 @@ class TexturePack:
|
||||||
RABBIT: str
|
RABBIT: str
|
||||||
RING_OF_CRITICAL_DAMAGE: str
|
RING_OF_CRITICAL_DAMAGE: str
|
||||||
RING_OF_MORE_EXPERIENCE: str
|
RING_OF_MORE_EXPERIENCE: str
|
||||||
|
RULER: str
|
||||||
|
SCROLL_OF_DAMAGE: str
|
||||||
|
SCROLL_OF_WEAKENING: str
|
||||||
SHIELD: str
|
SHIELD: str
|
||||||
SUNFLOWER: str
|
SUNFLOWER: str
|
||||||
SWORD: str
|
SWORD: str
|
||||||
|
@ -73,10 +79,13 @@ TexturePack.ASCII_PACK = TexturePack(
|
||||||
|
|
||||||
BODY_SNATCH_POTION='S',
|
BODY_SNATCH_POTION='S',
|
||||||
BOMB='ç',
|
BOMB='ç',
|
||||||
|
BOW=')',
|
||||||
|
CHEST='□',
|
||||||
CHESTPLATE='(',
|
CHESTPLATE='(',
|
||||||
EAGLE='µ',
|
EAGLE='µ',
|
||||||
EMPTY=' ',
|
EMPTY=' ',
|
||||||
EXPLOSION='%',
|
EXPLOSION='%',
|
||||||
|
FIRE_BALL_STAFF=':',
|
||||||
FLOOR='.',
|
FLOOR='.',
|
||||||
LADDER='H',
|
LADDER='H',
|
||||||
HAZELNUT='¤',
|
HAZELNUT='¤',
|
||||||
|
@ -89,6 +98,7 @@ TexturePack.ASCII_PACK = TexturePack(
|
||||||
RABBIT='Y',
|
RABBIT='Y',
|
||||||
RING_OF_CRITICAL_DAMAGE='o',
|
RING_OF_CRITICAL_DAMAGE='o',
|
||||||
RING_OF_MORE_EXPERIENCE='o',
|
RING_OF_MORE_EXPERIENCE='o',
|
||||||
|
RULER='\\',
|
||||||
SHIELD='D',
|
SHIELD='D',
|
||||||
SUNFLOWER='I',
|
SUNFLOWER='I',
|
||||||
SWORD='\u2020',
|
SWORD='\u2020',
|
||||||
|
@ -96,6 +106,8 @@ TexturePack.ASCII_PACK = TexturePack(
|
||||||
TIGER='n',
|
TIGER='n',
|
||||||
TRUMPET='/',
|
TRUMPET='/',
|
||||||
WALL='#',
|
WALL='#',
|
||||||
|
SCROLL_OF_DAMAGE=']',
|
||||||
|
SCROLL_OF_WEAKENING=']',
|
||||||
)
|
)
|
||||||
|
|
||||||
TexturePack.SQUIRREL_PACK = TexturePack(
|
TexturePack.SQUIRREL_PACK = TexturePack(
|
||||||
|
@ -109,10 +121,13 @@ TexturePack.SQUIRREL_PACK = TexturePack(
|
||||||
|
|
||||||
BODY_SNATCH_POTION='🔀',
|
BODY_SNATCH_POTION='🔀',
|
||||||
BOMB='💣',
|
BOMB='💣',
|
||||||
|
BOW='🏹',
|
||||||
|
CHEST='🧰',
|
||||||
CHESTPLATE='🦺',
|
CHESTPLATE='🦺',
|
||||||
EAGLE='🦅',
|
EAGLE='🦅',
|
||||||
EMPTY=' ',
|
EMPTY=' ',
|
||||||
EXPLOSION='💥',
|
EXPLOSION='💥',
|
||||||
|
FIRE_BALL_STAFF='🪄',
|
||||||
FLOOR='██',
|
FLOOR='██',
|
||||||
LADDER=('🪜', curses.COLOR_WHITE, (1000, 1000, 1000),
|
LADDER=('🪜', curses.COLOR_WHITE, (1000, 1000, 1000),
|
||||||
curses.COLOR_WHITE, (1000, 1000, 1000)),
|
curses.COLOR_WHITE, (1000, 1000, 1000)),
|
||||||
|
@ -126,6 +141,7 @@ TexturePack.SQUIRREL_PACK = TexturePack(
|
||||||
RABBIT='🐇',
|
RABBIT='🐇',
|
||||||
RING_OF_CRITICAL_DAMAGE='💍',
|
RING_OF_CRITICAL_DAMAGE='💍',
|
||||||
RING_OF_MORE_EXPERIENCE='💍',
|
RING_OF_MORE_EXPERIENCE='💍',
|
||||||
|
RULER='📏',
|
||||||
SHIELD='🛡️ ',
|
SHIELD='🛡️ ',
|
||||||
SUNFLOWER='🌻',
|
SUNFLOWER='🌻',
|
||||||
SWORD='🗡️ ',
|
SWORD='🗡️ ',
|
||||||
|
@ -133,4 +149,6 @@ TexturePack.SQUIRREL_PACK = TexturePack(
|
||||||
TIGER='🐅',
|
TIGER='🐅',
|
||||||
TRUMPET='🎺',
|
TRUMPET='🎺',
|
||||||
WALL='🧱',
|
WALL='🧱',
|
||||||
|
SCROLL_OF_DAMAGE='📜',
|
||||||
|
SCROLL_OF_WEAKENING='📜',
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from ..interfaces import FriendlyEntity, InventoryHolder, Map, FightingEntity
|
from ..interfaces import Entity, FriendlyEntity, InventoryHolder, \
|
||||||
|
Map, FightingEntity
|
||||||
from ..translations import gettext as _
|
from ..translations import gettext as _
|
||||||
from .player import Player
|
from .player import Player
|
||||||
from .monsters import Monster
|
from .monsters import Monster
|
||||||
|
@ -17,8 +18,8 @@ class Merchant(InventoryHolder, FriendlyEntity):
|
||||||
return super().keys() + ["inventory", "hazel"]
|
return super().keys() + ["inventory", "hazel"]
|
||||||
|
|
||||||
def __init__(self, name: str = "merchant", inventory: list = None,
|
def __init__(self, name: str = "merchant", inventory: list = None,
|
||||||
hazel: int = 75, *args, **kwargs):
|
hazel: int = 75, maxhealth: int = 8, *args, **kwargs):
|
||||||
super().__init__(name=name, *args, **kwargs)
|
super().__init__(name=name, maxhealth=maxhealth, *args, **kwargs)
|
||||||
self.inventory = self.translate_inventory(inventory or [])
|
self.inventory = self.translate_inventory(inventory or [])
|
||||||
self.hazel = hazel
|
self.hazel = hazel
|
||||||
if not self.inventory:
|
if not self.inventory:
|
||||||
|
@ -39,6 +40,40 @@ class Merchant(InventoryHolder, FriendlyEntity):
|
||||||
self.hazel += hz
|
self.hazel += hz
|
||||||
|
|
||||||
|
|
||||||
|
class Chest(InventoryHolder, FriendlyEntity):
|
||||||
|
"""
|
||||||
|
A class of chest inanimate entities which contain objects.
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str = "chest", inventory: list = None,
|
||||||
|
hazel: int = 0, *args, **kwargs):
|
||||||
|
super().__init__(name=name, *args, **kwargs)
|
||||||
|
self.hazel = hazel
|
||||||
|
self.inventory = self.translate_inventory(inventory or [])
|
||||||
|
if not self.inventory:
|
||||||
|
for i in range(3):
|
||||||
|
self.inventory.append(choice(Item.get_all_items())())
|
||||||
|
|
||||||
|
def talk_to(self, player: Player) -> str:
|
||||||
|
"""
|
||||||
|
This function is used to open the chest's inventory in a menu,
|
||||||
|
and allows the player to take objects.
|
||||||
|
"""
|
||||||
|
return _("You have opened the chest")
|
||||||
|
|
||||||
|
def take_damage(self, attacker: Entity, amount: int) -> str:
|
||||||
|
"""
|
||||||
|
A chest is not living, it can not take damage
|
||||||
|
"""
|
||||||
|
return _("It's not really effective")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dead(self) -> bool:
|
||||||
|
"""
|
||||||
|
Chest can not die
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Sunflower(FriendlyEntity):
|
class Sunflower(FriendlyEntity):
|
||||||
"""
|
"""
|
||||||
A friendly sunflower.
|
A friendly sunflower.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from random import choice, randint
|
from random import choice, randint
|
||||||
from typing import Optional
|
from typing import Optional, Any
|
||||||
|
|
||||||
from ..interfaces import Entity, FightingEntity, Map, InventoryHolder
|
from ..interfaces import Entity, FightingEntity, Map, InventoryHolder
|
||||||
from ..translations import gettext as _
|
from ..translations import gettext as _
|
||||||
|
@ -47,6 +47,11 @@ class Item(Entity):
|
||||||
Indicates what should be done when the item is used.
|
Indicates what should be done when the item is used.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def throw(self, direction: int) -> None:
|
||||||
|
"""
|
||||||
|
Indicates what should be done when the item is thrown.
|
||||||
|
"""
|
||||||
|
|
||||||
def equip(self) -> None:
|
def equip(self) -> None:
|
||||||
"""
|
"""
|
||||||
Indicates what should be done when the item is equipped.
|
Indicates what should be done when the item is equipped.
|
||||||
|
@ -86,16 +91,22 @@ class Item(Entity):
|
||||||
"""
|
"""
|
||||||
Returns the list of all item classes.
|
Returns the list of all item classes.
|
||||||
"""
|
"""
|
||||||
return [BodySnatchPotion, Chestplate, Bomb, Heart, Helmet, Monocle,
|
return [BodySnatchPotion, Bomb, Bow, Chestplate, FireBallStaff,
|
||||||
Shield, Sword, RingCritical, RingXP]
|
Heart, Helmet, Monocle, ScrollofDamage, ScrollofWeakening,
|
||||||
|
Shield, Sword, RingCritical, RingXP, Ruler]
|
||||||
|
|
||||||
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool:
|
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder,
|
||||||
|
for_free: bool = False) -> bool:
|
||||||
"""
|
"""
|
||||||
Does all necessary actions when an object is to be sold.
|
Does all necessary actions when an object is to be sold.
|
||||||
Is overwritten by some classes that cannot exist in the player's
|
Is overwritten by some classes that cannot exist in the player's
|
||||||
inventory.
|
inventory.
|
||||||
"""
|
"""
|
||||||
if buyer.hazel >= self.price:
|
if for_free:
|
||||||
|
self.hold(buyer)
|
||||||
|
seller.remove_from_inventory(self)
|
||||||
|
return True
|
||||||
|
elif buyer.hazel >= self.price:
|
||||||
self.hold(buyer)
|
self.hold(buyer)
|
||||||
seller.remove_from_inventory(self)
|
seller.remove_from_inventory(self)
|
||||||
buyer.change_hazel_balance(-self.price)
|
buyer.change_hazel_balance(-self.price)
|
||||||
|
@ -266,6 +277,15 @@ class Sword(Weapon):
|
||||||
super().__init__(name=name, price=price, *args, **kwargs)
|
super().__init__(name=name, price=price, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class Ruler(Weapon):
|
||||||
|
"""
|
||||||
|
A basic weapon
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str = "ruler", price: int = 2,
|
||||||
|
damage: int = 1, *args, **kwargs):
|
||||||
|
super().__init__(name=name, price=price, damage=damage, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Armor(Item):
|
class Armor(Item):
|
||||||
"""
|
"""
|
||||||
Class of items that increase the player's constitution.
|
Class of items that increase the player's constitution.
|
||||||
|
@ -455,6 +475,165 @@ class RingXP(Ring):
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ScrollofDamage(Item):
|
||||||
|
"""
|
||||||
|
A scroll that, when used, deals damage to all entities in a certain radius.
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str = "scroll_of_damage", price: int = 18,
|
||||||
|
*args, **kwargs):
|
||||||
|
super().__init__(name=name, price=price, *args, **kwargs)
|
||||||
|
|
||||||
|
def use(self) -> None:
|
||||||
|
"""
|
||||||
|
Find all entities within a radius of 5, and deal damage based on the
|
||||||
|
player's intelligence.
|
||||||
|
"""
|
||||||
|
for entity in self.held_by.map.entities:
|
||||||
|
if entity.is_fighting_entity() and not entity == self.held_by:
|
||||||
|
if entity.distance(self.held_by) <= 5:
|
||||||
|
self.held_by.map.logs.add_message(entity.take_damage(
|
||||||
|
self.held_by, self.held_by.intelligence))
|
||||||
|
self.held_by.inventory.remove(self)
|
||||||
|
|
||||||
|
|
||||||
|
class ScrollofWeakening(Item):
|
||||||
|
"""
|
||||||
|
A scroll that, when used, reduces the damage of the ennemies for 3 turn.
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str = "scroll_of_weakening", price: int = 13,
|
||||||
|
*args, **kwargs):
|
||||||
|
super().__init__(name=name, price=price, *args, **kwargs)
|
||||||
|
|
||||||
|
def use(self) -> None:
|
||||||
|
"""
|
||||||
|
Find all entities and reduce their damage.
|
||||||
|
"""
|
||||||
|
for entity in self.held_by.map.entities:
|
||||||
|
if entity.is_fighting_entity() and not entity == self.held_by:
|
||||||
|
entity.strength = entity.strength - \
|
||||||
|
max(1, self.held_by.intelligence // 2)
|
||||||
|
entity.effects.append(["strength",
|
||||||
|
-max(1, self.held_by.intelligence // 2),
|
||||||
|
3])
|
||||||
|
self.held_by.map.logs.add_message(
|
||||||
|
_(f"The ennemies have -{max(1, self.held_by.intelligence // 2)}"
|
||||||
|
+ "strength for 3 turns"))
|
||||||
|
self.held_by.inventory.remove(self)
|
||||||
|
|
||||||
|
|
||||||
|
class LongRangeWeapon(Item):
|
||||||
|
def __init__(self, damage: int = 4,
|
||||||
|
rang: int = 3, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.damage = damage
|
||||||
|
self.range = rang
|
||||||
|
|
||||||
|
def throw(self, direction: int) -> Any:
|
||||||
|
to_kill = None
|
||||||
|
for entity in self.held_by.map.entities:
|
||||||
|
if entity.is_fighting_entity():
|
||||||
|
if direction == 0 and self.held_by.x == entity.x \
|
||||||
|
and self.held_by.y - entity.y > 0 and \
|
||||||
|
self.held_by.y - entity.y <= self.range:
|
||||||
|
to_kill = entity
|
||||||
|
elif direction == 2 and self.held_by.x == entity.x \
|
||||||
|
and entity.y - self.held_by.y > 0 and \
|
||||||
|
entity.y - self.held_by.y <= self.range:
|
||||||
|
to_kill = entity
|
||||||
|
elif direction == 1 and self.held_by.y == entity.y \
|
||||||
|
and entity.x - self.held_by.x > 0 and \
|
||||||
|
entity.x - self.held_by.x <= self.range:
|
||||||
|
to_kill = entity
|
||||||
|
elif direction == 3 and self.held_by.y == entity.y \
|
||||||
|
and self.held_by.x - entity.x > 0 and \
|
||||||
|
self.held_by.x - entity.x <= self.range:
|
||||||
|
to_kill = entity
|
||||||
|
if to_kill:
|
||||||
|
line = _("{name}").format(name=to_kill.translated_name.capitalize()
|
||||||
|
) + self.string + " "\
|
||||||
|
+ to_kill.take_damage(
|
||||||
|
self.held_by, self.damage
|
||||||
|
+ getattr(self.held_by, self.stat))
|
||||||
|
self.held_by.map.logs.add_message(line)
|
||||||
|
return (to_kill.x, to_kill.y) if to_kill else None
|
||||||
|
|
||||||
|
def equip(self) -> None:
|
||||||
|
"""
|
||||||
|
Equip the weapon.
|
||||||
|
"""
|
||||||
|
self.held_by.remove_from_inventory(self)
|
||||||
|
self.held_by.equipped_main = self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stat(self) -> str:
|
||||||
|
"""
|
||||||
|
The stat that is used when using the object: dexterity for a bow
|
||||||
|
or intelligence for a magic staff.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string(self) -> str:
|
||||||
|
"""
|
||||||
|
The string that is printed when we hit an ennemy.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class Bow(LongRangeWeapon):
|
||||||
|
"""
|
||||||
|
A type of long range weapon that deals damage
|
||||||
|
based on the player's dexterity
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str = "bow", price: int = 22, damage: int = 4,
|
||||||
|
rang: int = 3, *args, **kwargs):
|
||||||
|
super().__init__(name=name, price=price, damage=damage,
|
||||||
|
rang=rang, *args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stat(self) -> str:
|
||||||
|
"""
|
||||||
|
Here it is dexterity
|
||||||
|
"""
|
||||||
|
return "dexterity"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string(self) -> str:
|
||||||
|
return " is shot by an arrow."
|
||||||
|
|
||||||
|
|
||||||
|
class FireBallStaff(LongRangeWeapon):
|
||||||
|
"""
|
||||||
|
A type of powerful long range weapon that deals damage
|
||||||
|
based on the player's intelligence
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str = "fire_ball_staff", price: int = 36,
|
||||||
|
damage: int = 6, rang: int = 4, *args, **kwargs):
|
||||||
|
super().__init__(name=name, price=price, damage=damage,
|
||||||
|
rang=rang, *args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stat(self) -> str:
|
||||||
|
"""
|
||||||
|
Here it is dexterity
|
||||||
|
"""
|
||||||
|
return "intelligence"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string(self) -> str:
|
||||||
|
return " is shot by a fire ball."
|
||||||
|
|
||||||
|
def throw(self, direction: int) -> None:
|
||||||
|
"""
|
||||||
|
Adds an explosion animation when killing something.
|
||||||
|
"""
|
||||||
|
coord = super().throw(direction)
|
||||||
|
if coord:
|
||||||
|
x = coord[0]
|
||||||
|
y = coord[1]
|
||||||
|
|
||||||
|
explosion = Explosion(y=y, x=x)
|
||||||
|
self.held_by.map.add_entity(explosion)
|
||||||
|
|
||||||
|
|
||||||
class Monocle(Item):
|
class Monocle(Item):
|
||||||
def __init__(self, name: str = "monocle", price: int = 10,
|
def __init__(self, name: str = "monocle", price: int = 10,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
|
|
|
@ -31,6 +31,7 @@ class Monster(FightingEntity):
|
||||||
By default, a monster will move randomly where it is possible
|
By default, a monster will move randomly where it is possible
|
||||||
If the player is closeby, the monster runs to the player.
|
If the player is closeby, the monster runs to the player.
|
||||||
"""
|
"""
|
||||||
|
super().act(m)
|
||||||
target = None
|
target = None
|
||||||
for entity in m.entities:
|
for entity in m.entities:
|
||||||
if self.distance_squared(entity) <= 25 and \
|
if self.distance_squared(entity) <= 25 and \
|
||||||
|
|
|
@ -28,6 +28,7 @@ class GameMode(Enum):
|
||||||
SETTINGS = auto()
|
SETTINGS = auto()
|
||||||
INVENTORY = auto()
|
INVENTORY = auto()
|
||||||
STORE = auto()
|
STORE = auto()
|
||||||
|
CHEST = auto()
|
||||||
CREDITS = auto()
|
CREDITS = auto()
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ class KeyValues(Enum):
|
||||||
CHAT = auto()
|
CHAT = auto()
|
||||||
WAIT = auto()
|
WAIT = auto()
|
||||||
LADDER = auto()
|
LADDER = auto()
|
||||||
|
LAUNCH = auto()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def translate_key(key: str, settings: Settings) -> Optional["KeyValues"]:
|
def translate_key(key: str, settings: Settings) -> Optional["KeyValues"]:
|
||||||
|
@ -84,4 +86,6 @@ class KeyValues(Enum):
|
||||||
return KeyValues.WAIT
|
return KeyValues.WAIT
|
||||||
elif key == settings.KEY_LADDER:
|
elif key == settings.KEY_LADDER:
|
||||||
return KeyValues.LADDER
|
return KeyValues.LADDER
|
||||||
|
elif key == settings.KEY_LAUNCH:
|
||||||
|
return KeyValues.LAUNCH
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -35,7 +35,9 @@ class Game:
|
||||||
"""
|
"""
|
||||||
self.state = GameMode.MAINMENU
|
self.state = GameMode.MAINMENU
|
||||||
self.waiting_for_friendly_key = False
|
self.waiting_for_friendly_key = False
|
||||||
|
self.waiting_for_launch_key = False
|
||||||
self.is_in_store_menu = True
|
self.is_in_store_menu = True
|
||||||
|
self.is_in_chest_menu = True
|
||||||
self.settings = Settings()
|
self.settings = Settings()
|
||||||
self.settings.load_settings()
|
self.settings.load_settings()
|
||||||
self.settings.write_settings()
|
self.settings.write_settings()
|
||||||
|
@ -45,6 +47,7 @@ class Game:
|
||||||
self.settings_menu.update_values(self.settings)
|
self.settings_menu.update_values(self.settings)
|
||||||
self.inventory_menu = menus.InventoryMenu()
|
self.inventory_menu = menus.InventoryMenu()
|
||||||
self.store_menu = menus.StoreMenu()
|
self.store_menu = menus.StoreMenu()
|
||||||
|
self.chest_menu = menus.ChestMenu()
|
||||||
self.logs = Logs()
|
self.logs = Logs()
|
||||||
self.message = None
|
self.message = None
|
||||||
|
|
||||||
|
@ -121,6 +124,9 @@ class Game:
|
||||||
if self.waiting_for_friendly_key:
|
if self.waiting_for_friendly_key:
|
||||||
# The player requested to talk with a friendly entity
|
# The player requested to talk with a friendly entity
|
||||||
self.handle_friendly_entity_chat(key)
|
self.handle_friendly_entity_chat(key)
|
||||||
|
elif self.waiting_for_launch_key:
|
||||||
|
# The player requested to launch
|
||||||
|
self.handle_launch(key)
|
||||||
else:
|
else:
|
||||||
self.handle_key_pressed_play(key)
|
self.handle_key_pressed_play(key)
|
||||||
elif self.state == GameMode.INVENTORY:
|
elif self.state == GameMode.INVENTORY:
|
||||||
|
@ -131,6 +137,8 @@ class Game:
|
||||||
self.settings_menu.handle_key_pressed(key, raw_key, self)
|
self.settings_menu.handle_key_pressed(key, raw_key, self)
|
||||||
elif self.state == GameMode.STORE:
|
elif self.state == GameMode.STORE:
|
||||||
self.handle_key_pressed_store(key)
|
self.handle_key_pressed_store(key)
|
||||||
|
elif self.state == GameMode.CHEST:
|
||||||
|
self.handle_key_pressed_chest(key)
|
||||||
elif self.state == GameMode.CREDITS:
|
elif self.state == GameMode.CREDITS:
|
||||||
self.state = GameMode.MAINMENU
|
self.state = GameMode.MAINMENU
|
||||||
self.display_actions(DisplayActions.REFRESH)
|
self.display_actions(DisplayActions.REFRESH)
|
||||||
|
@ -159,6 +167,9 @@ class Game:
|
||||||
self.player.equipped_main.use()
|
self.player.equipped_main.use()
|
||||||
if self.player.equipped_secondary:
|
if self.player.equipped_secondary:
|
||||||
self.player.equipped_secondary.use()
|
self.player.equipped_secondary.use()
|
||||||
|
elif key == KeyValues.LAUNCH:
|
||||||
|
# Wait for the direction to launch in
|
||||||
|
self.waiting_for_launch_key = True
|
||||||
elif key == KeyValues.SPACE:
|
elif key == KeyValues.SPACE:
|
||||||
self.state = GameMode.MAINMENU
|
self.state = GameMode.MAINMENU
|
||||||
elif key == KeyValues.CHAT:
|
elif key == KeyValues.CHAT:
|
||||||
|
@ -250,6 +261,35 @@ class Game:
|
||||||
self.is_in_store_menu = True
|
self.is_in_store_menu = True
|
||||||
self.store_menu.update_merchant(entity)
|
self.store_menu.update_merchant(entity)
|
||||||
self.display_actions(DisplayActions.UPDATE)
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
elif entity.is_chest():
|
||||||
|
self.state = GameMode.CHEST
|
||||||
|
self.is_in_chest_menu = True
|
||||||
|
self.chest_menu.update_chest(entity)
|
||||||
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
|
||||||
|
def handle_launch(self, key: KeyValues) -> None:
|
||||||
|
"""
|
||||||
|
If the player tries to throw something in a direction, the game looks
|
||||||
|
for entities in that direction and within the range of the player's
|
||||||
|
weapon and adds damage
|
||||||
|
"""
|
||||||
|
if not self.waiting_for_launch_key:
|
||||||
|
return
|
||||||
|
self.waiting_for_launch_key = False
|
||||||
|
|
||||||
|
if key == KeyValues.UP:
|
||||||
|
direction = 0
|
||||||
|
elif key == KeyValues.DOWN:
|
||||||
|
direction = 2
|
||||||
|
elif key == KeyValues.LEFT:
|
||||||
|
direction = 3
|
||||||
|
elif key == KeyValues.RIGHT:
|
||||||
|
direction = 1
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.player.equipped_main:
|
||||||
|
self.player.equipped_main.throw(direction)
|
||||||
|
|
||||||
def handle_key_pressed_inventory(self, key: KeyValues) -> None:
|
def handle_key_pressed_inventory(self, key: KeyValues) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -306,6 +346,36 @@ class Game:
|
||||||
# Ensure that the cursor has a good position
|
# Ensure that the cursor has a good position
|
||||||
menu.position = min(menu.position, len(menu.values) - 1)
|
menu.position = min(menu.position, len(menu.values) - 1)
|
||||||
|
|
||||||
|
def handle_key_pressed_chest(self, key: KeyValues) -> None:
|
||||||
|
"""
|
||||||
|
In a chest menu, we can take or put items or close the menu.
|
||||||
|
"""
|
||||||
|
menu = self.chest_menu if self.is_in_chest_menu else self.inventory_menu
|
||||||
|
|
||||||
|
if key == KeyValues.SPACE or key == KeyValues.INVENTORY:
|
||||||
|
self.state = GameMode.PLAY
|
||||||
|
elif key == KeyValues.UP:
|
||||||
|
menu.go_up()
|
||||||
|
elif key == KeyValues.DOWN:
|
||||||
|
menu.go_down()
|
||||||
|
elif key == KeyValues.LEFT:
|
||||||
|
self.is_in_chest_menu = False
|
||||||
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
elif key == KeyValues.RIGHT:
|
||||||
|
self.is_in_chest_menu = True
|
||||||
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
if menu.values and not self.player.dead:
|
||||||
|
if key == KeyValues.ENTER:
|
||||||
|
item = menu.validate()
|
||||||
|
owner = self.chest_menu.chest if self.is_in_chest_menu \
|
||||||
|
else self.player
|
||||||
|
buyer = self.player if self.is_in_chest_menu \
|
||||||
|
else self.chest_menu.chest
|
||||||
|
item.be_sold(buyer, owner, for_free=True)
|
||||||
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
# Ensure that the cursor has a good position
|
||||||
|
menu.position = min(menu.position, len(menu.values) - 1)
|
||||||
|
|
||||||
def handle_key_pressed_main_menu(self, key: KeyValues) -> None:
|
def handle_key_pressed_main_menu(self, key: KeyValues) -> None:
|
||||||
"""
|
"""
|
||||||
In the main menu, we can navigate through different options.
|
In the main menu, we can navigate through different options.
|
||||||
|
|
|
@ -606,6 +606,13 @@ class Entity:
|
||||||
from squirrelbattle.entities.friendly import Merchant
|
from squirrelbattle.entities.friendly import Merchant
|
||||||
return isinstance(self, Merchant)
|
return isinstance(self, Merchant)
|
||||||
|
|
||||||
|
def is_chest(self) -> bool:
|
||||||
|
"""
|
||||||
|
Is this entity a chest?
|
||||||
|
"""
|
||||||
|
from squirrelbattle.entities.friendly import Chest
|
||||||
|
return isinstance(self, Chest)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def translated_name(self) -> str:
|
def translated_name(self) -> str:
|
||||||
"""
|
"""
|
||||||
|
@ -622,9 +629,9 @@ class Entity:
|
||||||
from squirrelbattle.entities.monsters import Tiger, Hedgehog, \
|
from squirrelbattle.entities.monsters import Tiger, Hedgehog, \
|
||||||
Rabbit, TeddyBear, GiantSeaEagle
|
Rabbit, TeddyBear, GiantSeaEagle
|
||||||
from squirrelbattle.entities.friendly import Merchant, Sunflower, \
|
from squirrelbattle.entities.friendly import Merchant, Sunflower, \
|
||||||
Trumpet
|
Trumpet, Chest
|
||||||
return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear,
|
return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear,
|
||||||
Sunflower, Tiger, Merchant, GiantSeaEagle, Trumpet]
|
Sunflower, Tiger, Merchant, GiantSeaEagle, Trumpet, Chest]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_weights() -> list:
|
def get_weights() -> list:
|
||||||
|
@ -632,8 +639,7 @@ class Entity:
|
||||||
Returns a weigth list associated to the above function, to
|
Returns a weigth list associated to the above function, to
|
||||||
be used to spawn random entities with a certain probability.
|
be used to spawn random entities with a certain probability.
|
||||||
"""
|
"""
|
||||||
return [3, 5, 6, 5, 5, 5,
|
return [3, 5, 6, 5, 5, 5, 5, 4, 3, 1, 2, 4]
|
||||||
5, 4, 4, 1, 2]
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_entity_classes_in_a_dict() -> dict:
|
def get_all_entity_classes_in_a_dict() -> dict:
|
||||||
|
@ -644,30 +650,37 @@ class Entity:
|
||||||
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, \
|
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, \
|
||||||
TeddyBear, GiantSeaEagle
|
TeddyBear, GiantSeaEagle
|
||||||
from squirrelbattle.entities.friendly import Merchant, Sunflower, \
|
from squirrelbattle.entities.friendly import Merchant, Sunflower, \
|
||||||
Trumpet
|
Trumpet, Chest
|
||||||
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, \
|
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, \
|
||||||
Heart, Monocle, Sword, Shield, Chestplate, Helmet, \
|
Heart, Sword, Shield, Chestplate, Helmet, RingCritical, RingXP, \
|
||||||
RingCritical, RingXP
|
ScrollofDamage, ScrollofWeakening, Ruler, Bow, FireBallStaff, \
|
||||||
|
Monocle
|
||||||
return {
|
return {
|
||||||
"Bomb": Bomb,
|
|
||||||
"Chestplate": Chestplate,
|
|
||||||
"Heart": Heart,
|
|
||||||
"BodySnatchPotion": BodySnatchPotion,
|
"BodySnatchPotion": BodySnatchPotion,
|
||||||
|
"Bomb": Bomb,
|
||||||
|
"Bow": Bow,
|
||||||
|
"Chest": Chest,
|
||||||
|
"Chestplate": Chestplate,
|
||||||
"Eagle": GiantSeaEagle,
|
"Eagle": GiantSeaEagle,
|
||||||
|
"FireBallStaff": FireBallStaff,
|
||||||
|
"Heart": Heart,
|
||||||
"Hedgehog": Hedgehog,
|
"Hedgehog": Hedgehog,
|
||||||
"Helmet": Helmet,
|
"Helmet": Helmet,
|
||||||
"Player": Player,
|
|
||||||
"Merchant": Merchant,
|
"Merchant": Merchant,
|
||||||
"Monocle": Monocle,
|
"Monocle": Monocle,
|
||||||
"Sunflower": Sunflower,
|
"Player": Player,
|
||||||
"Sword": Sword,
|
|
||||||
"Trumpet": Trumpet,
|
|
||||||
"Shield": Shield,
|
|
||||||
"TeddyBear": TeddyBear,
|
|
||||||
"Tiger": Tiger,
|
|
||||||
"Rabbit": Rabbit,
|
"Rabbit": Rabbit,
|
||||||
"RingCritical": RingCritical,
|
"RingCritical": RingCritical,
|
||||||
"RingXP": RingXP,
|
"RingXP": RingXP,
|
||||||
|
"Ruler": Ruler,
|
||||||
|
"ScrollofDamage": ScrollofDamage,
|
||||||
|
"ScrollofWeakening": ScrollofWeakening,
|
||||||
|
"Shield": Shield,
|
||||||
|
"Sunflower": Sunflower,
|
||||||
|
"Sword": Sword,
|
||||||
|
"Trumpet": Trumpet,
|
||||||
|
"TeddyBear": TeddyBear,
|
||||||
|
"Tiger": Tiger,
|
||||||
}
|
}
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
|
@ -710,6 +723,7 @@ class FightingEntity(Entity):
|
||||||
self.constitution = constitution
|
self.constitution = constitution
|
||||||
self.level = level
|
self.level = level
|
||||||
self.critical = critical
|
self.critical = critical
|
||||||
|
self.effects = [] # effects = temporary buff or weakening of the stats.
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dead(self) -> bool:
|
def dead(self) -> bool:
|
||||||
|
@ -718,13 +732,27 @@ class FightingEntity(Entity):
|
||||||
"""
|
"""
|
||||||
return self.health <= 0
|
return self.health <= 0
|
||||||
|
|
||||||
|
def act(self, m: Map) -> None:
|
||||||
|
"""
|
||||||
|
Refreshes all current effects.
|
||||||
|
"""
|
||||||
|
for i in range(len(self.effects)):
|
||||||
|
self.effects[i][2] -= 1
|
||||||
|
|
||||||
|
copy = self.effects[:]
|
||||||
|
for i in range(len(copy)):
|
||||||
|
if copy[i][2] <= 0:
|
||||||
|
setattr(self, copy[i][0],
|
||||||
|
getattr(self, copy[i][0]) - copy[i][1])
|
||||||
|
self.effects.remove(copy[i])
|
||||||
|
|
||||||
def hit(self, opponent: "FightingEntity") -> str:
|
def hit(self, opponent: "FightingEntity") -> str:
|
||||||
"""
|
"""
|
||||||
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)
|
diceroll = randint(1, 100)
|
||||||
damage = self.strength
|
damage = max(0, self.strength)
|
||||||
string = " "
|
string = " "
|
||||||
if diceroll <= self.critical: # It is a critical hit
|
if diceroll <= self.critical: # It is a critical hit
|
||||||
damage *= 4
|
damage *= 4
|
||||||
|
|
|
@ -6,7 +6,7 @@ from typing import Any, Optional
|
||||||
|
|
||||||
from .display.texturepack import TexturePack
|
from .display.texturepack import TexturePack
|
||||||
from .entities.player import Player
|
from .entities.player import Player
|
||||||
from .entities.friendly import Merchant
|
from .entities.friendly import Merchant, Chest
|
||||||
from .enums import GameMode, KeyValues, DisplayActions
|
from .enums import GameMode, KeyValues, DisplayActions
|
||||||
from .settings import Settings
|
from .settings import Settings
|
||||||
from .translations import gettext as _, Translator
|
from .translations import gettext as _, Translator
|
||||||
|
@ -158,3 +158,23 @@ class StoreMenu(Menu):
|
||||||
Returns the values of the menu.
|
Returns the values of the menu.
|
||||||
"""
|
"""
|
||||||
return self.merchant.inventory if self.merchant else []
|
return self.merchant.inventory if self.merchant else []
|
||||||
|
|
||||||
|
|
||||||
|
class ChestMenu(Menu):
|
||||||
|
"""
|
||||||
|
A special instance of a menu : the menu for the inventory of a chest.
|
||||||
|
"""
|
||||||
|
chest: Chest = None
|
||||||
|
|
||||||
|
def update_chest(self, chest: Chest) -> None:
|
||||||
|
"""
|
||||||
|
Updates the player.
|
||||||
|
"""
|
||||||
|
self.chest = chest
|
||||||
|
|
||||||
|
@property
|
||||||
|
def values(self) -> list:
|
||||||
|
"""
|
||||||
|
Returns the values of the menu.
|
||||||
|
"""
|
||||||
|
return self.chest.inventory if self.chest else []
|
||||||
|
|
|
@ -35,6 +35,7 @@ class Settings:
|
||||||
self.KEY_CHAT = ['t', 'Key used to talk to a friendly entity']
|
self.KEY_CHAT = ['t', 'Key used to talk to a friendly entity']
|
||||||
self.KEY_WAIT = ['w', 'Key used to wait']
|
self.KEY_WAIT = ['w', 'Key used to wait']
|
||||||
self.KEY_LADDER = ['<', 'Key used to use ladders']
|
self.KEY_LADDER = ['<', 'Key used to use ladders']
|
||||||
|
self.KEY_LAUNCH = ['l', 'Key used to use a bow']
|
||||||
self.TEXTURE_PACK = ['ascii', 'Texture pack']
|
self.TEXTURE_PACK = ['ascii', 'Texture pack']
|
||||||
self.LOCALE = [locale.getlocale()[0][:2], 'Language']
|
self.LOCALE = [locale.getlocale()[0][:2], 'Language']
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,14 @@ 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, Chest
|
||||||
from ..entities.items import Bomb, Heart, Sword, Explosion, Shield, Helmet, \
|
from ..entities.items import Bomb, Heart, Sword, Explosion, Shield, Helmet, \
|
||||||
Chestplate, RingCritical, Monocle
|
Chestplate, RingCritical, Bow, FireBallStaff, ScrollofDamage,\
|
||||||
from ..entities.monsters import GiantSeaEagle
|
ScrollofWeakening, Monocle
|
||||||
|
from ..entities.monsters import Rabbit, GiantSeaEagle
|
||||||
from ..entities.player import Player
|
from ..entities.player import Player
|
||||||
from ..enums import DisplayActions
|
from ..enums import DisplayActions, KeyValues, GameMode
|
||||||
from ..game import Game, KeyValues, GameMode
|
from ..game import Game
|
||||||
from ..interfaces import Map
|
from ..interfaces import Map
|
||||||
from ..menus import MainMenuValues
|
from ..menus import MainMenuValues
|
||||||
from ..resources import ResourceManager
|
from ..resources import ResourceManager
|
||||||
|
@ -349,7 +350,7 @@ class TestGame(unittest.TestCase):
|
||||||
self.assertEqual(self.game.settings.KEY_LEFT_PRIMARY, 'a')
|
self.assertEqual(self.game.settings.KEY_LEFT_PRIMARY, 'a')
|
||||||
|
|
||||||
# Navigate to "texture pack"
|
# Navigate to "texture pack"
|
||||||
for ignored in range(12):
|
for ignored in range(13):
|
||||||
self.game.handle_key_pressed(KeyValues.DOWN)
|
self.game.handle_key_pressed(KeyValues.DOWN)
|
||||||
|
|
||||||
# Change texture pack
|
# Change texture pack
|
||||||
|
@ -767,3 +768,157 @@ class TestGame(unittest.TestCase):
|
||||||
self.game.handle_key_pressed(KeyValues.ENTER)
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
|
||||||
self.assertEqual(self.game.state, GameMode.MAINMENU)
|
self.assertEqual(self.game.state, GameMode.MAINMENU)
|
||||||
|
|
||||||
|
def test_launch(self) -> None:
|
||||||
|
"""
|
||||||
|
Use the long range weapons to kill some entities.
|
||||||
|
"""
|
||||||
|
self.game.state = GameMode.PLAY
|
||||||
|
self.game.player.move(2, 6)
|
||||||
|
|
||||||
|
b = Bow()
|
||||||
|
b.held_by = self.game.player
|
||||||
|
self.game.player.equipped_main = b
|
||||||
|
self.assertTrue(self.game.player.equipped_main)
|
||||||
|
|
||||||
|
entity = Rabbit()
|
||||||
|
entity.health = 1
|
||||||
|
self.game.map.add_entity(entity)
|
||||||
|
entity.move(3, 6)
|
||||||
|
|
||||||
|
self.game.handle_launch(KeyValues.UP)
|
||||||
|
|
||||||
|
self.game.waiting_for_launch_key = True
|
||||||
|
self.game.handle_key_pressed(KeyValues.CHAT)
|
||||||
|
|
||||||
|
entity = Rabbit()
|
||||||
|
entity.health = 1
|
||||||
|
self.game.map.add_entity(entity)
|
||||||
|
entity.move(2, 8)
|
||||||
|
self.game.waiting_for_launch_key = True
|
||||||
|
self.game.handle_key_pressed(KeyValues.RIGHT)
|
||||||
|
|
||||||
|
entity = Rabbit()
|
||||||
|
entity.health = 1
|
||||||
|
self.game.map.add_entity(entity)
|
||||||
|
entity.move(2, 5)
|
||||||
|
self.game.waiting_for_launch_key = True
|
||||||
|
self.game.handle_key_pressed(KeyValues.LEFT)
|
||||||
|
|
||||||
|
key = "l"
|
||||||
|
KeyValues.translate_key(key, self.game.settings)
|
||||||
|
|
||||||
|
self.game.handle_key_pressed(KeyValues.LAUNCH)
|
||||||
|
self.assertTrue(self.game.waiting_for_launch_key)
|
||||||
|
self.game.handle_key_pressed(KeyValues.DOWN)
|
||||||
|
|
||||||
|
self.assertTrue(entity.dead)
|
||||||
|
|
||||||
|
entity2 = Rabbit()
|
||||||
|
entity2.health = 1
|
||||||
|
self.game.map.add_entity(entity2)
|
||||||
|
entity2.move(1, 6)
|
||||||
|
|
||||||
|
b = FireBallStaff()
|
||||||
|
self.game.player.inventory.append(b)
|
||||||
|
b.held_by = self.game.player
|
||||||
|
b.equip()
|
||||||
|
|
||||||
|
self.game.handle_key_pressed(KeyValues.LAUNCH)
|
||||||
|
self.assertTrue(self.game.waiting_for_launch_key)
|
||||||
|
self.game.handle_key_pressed(KeyValues.UP)
|
||||||
|
|
||||||
|
self.assertTrue(entity2.dead)
|
||||||
|
|
||||||
|
def test_scrolls(self) -> None:
|
||||||
|
"""
|
||||||
|
Use the scrolls.
|
||||||
|
"""
|
||||||
|
self.game.state = GameMode.PLAY
|
||||||
|
self.game.player.move(2, 6)
|
||||||
|
|
||||||
|
entity = Rabbit()
|
||||||
|
self.game.map.add_entity(entity)
|
||||||
|
entity.move(3, 6)
|
||||||
|
|
||||||
|
entity2 = GiantSeaEagle()
|
||||||
|
self.game.map.add_entity(entity2)
|
||||||
|
entity2.move(3, 8)
|
||||||
|
|
||||||
|
scroll1 = ScrollofDamage()
|
||||||
|
scroll2 = ScrollofWeakening()
|
||||||
|
self.game.player.inventory.append(scroll1)
|
||||||
|
self.game.player.inventory.append(scroll2)
|
||||||
|
scroll1.held_by = self.game.player
|
||||||
|
scroll2.held_by = self.game.player
|
||||||
|
|
||||||
|
scroll1.use()
|
||||||
|
self.assertTrue(entity.health != entity.maxhealth)
|
||||||
|
self.assertTrue(entity2.health != entity2.maxhealth)
|
||||||
|
|
||||||
|
scroll2.use()
|
||||||
|
self.assertEqual(entity.strength, 0)
|
||||||
|
self.assertEqual(entity2.strength, 999)
|
||||||
|
|
||||||
|
self.game.map.tick(self.game.player)
|
||||||
|
self.game.map.tick(self.game.player)
|
||||||
|
self.game.map.tick(self.game.player)
|
||||||
|
|
||||||
|
self.assertEqual(entity2.effects, [])
|
||||||
|
|
||||||
|
def test_chests(self) -> None:
|
||||||
|
"""
|
||||||
|
Interacts with chests.
|
||||||
|
"""
|
||||||
|
self.game.state = GameMode.PLAY
|
||||||
|
|
||||||
|
chest = Chest()
|
||||||
|
chest.move(2, 6)
|
||||||
|
self.game.map.add_entity(chest)
|
||||||
|
chest.inventory.append(FireBallStaff())
|
||||||
|
|
||||||
|
# Talk to merchant
|
||||||
|
self.game.handle_key_pressed(KeyValues.CHAT)
|
||||||
|
self.assertTrue(self.game.waiting_for_friendly_key)
|
||||||
|
self.game.handle_key_pressed(KeyValues.DOWN)
|
||||||
|
self.assertFalse(self.game.waiting_for_friendly_key)
|
||||||
|
self.assertEqual(self.game.state, GameMode.CHEST)
|
||||||
|
self.assertTrue(self.game.logs.messages)
|
||||||
|
|
||||||
|
# Navigate in the menu
|
||||||
|
self.game.handle_key_pressed(KeyValues.DOWN)
|
||||||
|
self.game.handle_key_pressed(KeyValues.DOWN)
|
||||||
|
self.game.handle_key_pressed(KeyValues.LEFT)
|
||||||
|
self.assertFalse(self.game.is_in_chest_menu)
|
||||||
|
self.game.handle_key_pressed(KeyValues.RIGHT)
|
||||||
|
self.assertTrue(self.game.is_in_chest_menu)
|
||||||
|
self.game.handle_key_pressed(KeyValues.UP)
|
||||||
|
self.assertEqual(self.game.chest_menu.position, 1)
|
||||||
|
|
||||||
|
# The second item is not a heart
|
||||||
|
chest.inventory[1] = sword = Sword()
|
||||||
|
# Take the second item
|
||||||
|
item = self.game.chest_menu.validate()
|
||||||
|
self.assertIn(item, chest.inventory)
|
||||||
|
self.game.display_actions(DisplayActions.MOUSE, 7, 25,
|
||||||
|
curses.BUTTON1_CLICKED)
|
||||||
|
self.assertIn(item, self.game.player.inventory)
|
||||||
|
self.assertNotIn(item, chest.inventory)
|
||||||
|
|
||||||
|
# Give an item back
|
||||||
|
self.game.inventory_menu.position = len(self.game.player.inventory) - 1
|
||||||
|
self.game.handle_key_pressed(KeyValues.LEFT)
|
||||||
|
self.assertFalse(self.game.is_in_chest_menu)
|
||||||
|
self.assertIn(sword, self.game.player.inventory)
|
||||||
|
self.assertEqual(self.game.inventory_menu.validate(), sword)
|
||||||
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
self.assertNotIn(sword, self.game.player.inventory)
|
||||||
|
self.assertIn(sword, chest.inventory)
|
||||||
|
|
||||||
|
# Test immortality
|
||||||
|
self.game.player.hit(chest)
|
||||||
|
self.assertTrue(not chest.dead)
|
||||||
|
|
||||||
|
# Exit the menu
|
||||||
|
self.game.handle_key_pressed(KeyValues.SPACE)
|
||||||
|
self.assertEqual(self.game.state, GameMode.PLAY)
|
||||||
|
|
Loading…
Reference in New Issue