Merge remote-tracking branch 'origin/master' into lighting
This commit is contained in:
commit
62ce2b5c71
|
@ -2,9 +2,10 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Optional, Tuple, Union
|
||||||
|
|
||||||
from squirrelbattle.display.texturepack import TexturePack
|
from squirrelbattle.display.texturepack import TexturePack
|
||||||
|
from squirrelbattle.game import Game
|
||||||
from squirrelbattle.tests.screen import FakePad
|
from squirrelbattle.tests.screen import FakePad
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,6 +16,9 @@ class Display:
|
||||||
height: int
|
height: int
|
||||||
pad: Any
|
pad: Any
|
||||||
|
|
||||||
|
_color_pairs = {(curses.COLOR_WHITE, curses.COLOR_BLACK): 0}
|
||||||
|
_colors_rgb = {}
|
||||||
|
|
||||||
def __init__(self, screen: Any, pack: Optional[TexturePack] = None):
|
def __init__(self, screen: Any, pack: Optional[TexturePack] = None):
|
||||||
self.screen = screen
|
self.screen = screen
|
||||||
self.pack = pack or TexturePack.get_pack("ascii")
|
self.pack = pack or TexturePack.get_pack("ascii")
|
||||||
|
@ -30,15 +34,84 @@ class Display:
|
||||||
lines = [line[:width] for line in lines]
|
lines = [line[:width] for line in lines]
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
def addstr(self, pad: Any, y: int, x: int, msg: str, *options) -> None:
|
def translate_color(self, color: Union[int, Tuple[int, int, int]]) -> int:
|
||||||
|
"""
|
||||||
|
Translate a tuple (R, G, B) into a curses color index.
|
||||||
|
If we have already a color index, then nothing is processed.
|
||||||
|
If this is a tuple, we construct a new color index if non-existing
|
||||||
|
and we return this index.
|
||||||
|
The values of R, G and B must be between 0 and 1000, and not
|
||||||
|
between 0 and 255.
|
||||||
|
"""
|
||||||
|
if isinstance(color, tuple):
|
||||||
|
# The color is a tuple (R, G, B), that is potentially unknown.
|
||||||
|
# We translate it into a curses color number.
|
||||||
|
if color not in self._colors_rgb:
|
||||||
|
# The color does not exist, we create it.
|
||||||
|
color_nb = len(self._colors_rgb) + 8
|
||||||
|
self.init_color(color_nb, color[0], color[1], color[2])
|
||||||
|
self._colors_rgb[color] = color_nb
|
||||||
|
color = self._colors_rgb[color]
|
||||||
|
return color
|
||||||
|
|
||||||
|
def addstr(self, pad: Any, y: int, x: int, msg: str,
|
||||||
|
fg_color: Union[int, Tuple[int, int, int]] = curses.COLOR_WHITE,
|
||||||
|
bg_color: Union[int, Tuple[int, int, int]] = curses.COLOR_BLACK,
|
||||||
|
*, altcharset: bool = False, blink: bool = False,
|
||||||
|
bold: bool = False, dim: bool = False, invis: bool = False,
|
||||||
|
italic: bool = False, normal: bool = False,
|
||||||
|
protect: bool = False, reverse: bool = False,
|
||||||
|
standout: bool = False, underline: bool = False,
|
||||||
|
horizontal: bool = False, left: bool = False,
|
||||||
|
low: bool = False, right: bool = False, top: bool = False,
|
||||||
|
vertical: bool = False, chartext: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Display a message onto the pad.
|
Display a message onto the pad.
|
||||||
If the message is too large, it is truncated vertically and horizontally
|
If the message is too large, it is truncated vertically and horizontally
|
||||||
|
The text can be bold, italic, blinking, ... if the good parameters are
|
||||||
|
given. These parameters are translated into curses attributes.
|
||||||
|
The foreground and background colors can be given as curses constants
|
||||||
|
(curses.COLOR_*), or by giving a tuple (R, G, B) that corresponds to
|
||||||
|
the color. R, G, B must be between 0 and 1000, and not 0 and 255.
|
||||||
"""
|
"""
|
||||||
height, width = pad.getmaxyx()
|
height, width = pad.getmaxyx()
|
||||||
|
# Truncate message if it is too large
|
||||||
msg = self.truncate(msg, height - y, width - x - 1)
|
msg = self.truncate(msg, height - y, width - x - 1)
|
||||||
if msg.replace("\n", "") and x >= 0 and y >= 0:
|
if msg.replace("\n", "") and x >= 0 and y >= 0:
|
||||||
return pad.addstr(y, x, msg, *options)
|
fg_color = self.translate_color(fg_color)
|
||||||
|
bg_color = self.translate_color(bg_color)
|
||||||
|
|
||||||
|
# Get the pair number for the tuple (fg, bg)
|
||||||
|
# If it does not exist, create it and give a new unique id.
|
||||||
|
if (fg_color, bg_color) in self._color_pairs:
|
||||||
|
pair_nb = self._color_pairs[(fg_color, bg_color)]
|
||||||
|
else:
|
||||||
|
pair_nb = len(self._color_pairs)
|
||||||
|
self.init_pair(pair_nb, fg_color, bg_color)
|
||||||
|
self._color_pairs[(fg_color, bg_color)] = pair_nb
|
||||||
|
|
||||||
|
# Compute curses attributes from the parameters
|
||||||
|
attr = self.color_pair(pair_nb)
|
||||||
|
attr |= curses.A_ALTCHARSET if altcharset else 0
|
||||||
|
attr |= curses.A_BLINK if blink else 0
|
||||||
|
attr |= curses.A_BOLD if bold else 0
|
||||||
|
attr |= curses.A_DIM if dim else 0
|
||||||
|
attr |= curses.A_INVIS if invis else 0
|
||||||
|
attr |= curses.A_ITALIC if italic else 0
|
||||||
|
attr |= curses.A_NORMAL if normal else 0
|
||||||
|
attr |= curses.A_PROTECT if protect else 0
|
||||||
|
attr |= curses.A_REVERSE if reverse else 0
|
||||||
|
attr |= curses.A_STANDOUT if standout else 0
|
||||||
|
attr |= curses.A_UNDERLINE if underline else 0
|
||||||
|
attr |= curses.A_HORIZONTAL if horizontal else 0
|
||||||
|
attr |= curses.A_LEFT if left else 0
|
||||||
|
attr |= curses.A_LOW if low else 0
|
||||||
|
attr |= curses.A_RIGHT if right else 0
|
||||||
|
attr |= curses.A_TOP if top else 0
|
||||||
|
attr |= curses.A_VERTICAL if vertical else 0
|
||||||
|
attr |= curses.A_CHARTEXT if chartext else 0
|
||||||
|
|
||||||
|
return pad.addstr(y, x, msg, attr)
|
||||||
|
|
||||||
def init_pair(self, number: int, foreground: int, background: int) -> None:
|
def init_pair(self, number: int, foreground: int, background: int) -> None:
|
||||||
return curses.init_pair(number, foreground, background) \
|
return curses.init_pair(number, foreground, background) \
|
||||||
|
@ -47,6 +120,10 @@ class Display:
|
||||||
def color_pair(self, number: int) -> int:
|
def color_pair(self, number: int) -> int:
|
||||||
return curses.color_pair(number) if self.screen else 0
|
return curses.color_pair(number) if self.screen else 0
|
||||||
|
|
||||||
|
def init_color(self, number: int, red: int, green: int, blue: int) -> None:
|
||||||
|
return curses.init_color(number, red, green, blue) \
|
||||||
|
if self.screen else None
|
||||||
|
|
||||||
def resize(self, y: int, x: int, height: int, width: int,
|
def resize(self, y: int, x: int, height: int, width: int,
|
||||||
resize_pad: bool = True) -> None:
|
resize_pad: bool = True) -> None:
|
||||||
self.x = x
|
self.x = x
|
||||||
|
@ -55,6 +132,7 @@ class Display:
|
||||||
self.height = height
|
self.height = height
|
||||||
if hasattr(self, "pad") and resize_pad and \
|
if hasattr(self, "pad") and resize_pad and \
|
||||||
self.height >= 0 and self.width >= 0:
|
self.height >= 0 and self.width >= 0:
|
||||||
|
self.pad.erase()
|
||||||
self.pad.resize(self.height + 1, self.width + 1)
|
self.pad.resize(self.height + 1, self.width + 1)
|
||||||
|
|
||||||
def refresh(self, *args, resize_pad: bool = True) -> None:
|
def refresh(self, *args, resize_pad: bool = True) -> None:
|
||||||
|
@ -86,6 +164,13 @@ class Display:
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def handle_click(self, y: int, x: int, game: Game) -> None:
|
||||||
|
"""
|
||||||
|
A mouse click was performed on the coordinates (y, x) of the pad.
|
||||||
|
Maybe it can do something.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rows(self) -> int:
|
def rows(self) -> int:
|
||||||
return curses.LINES if self.screen else 42
|
return curses.LINES if self.screen else 42
|
||||||
|
@ -138,23 +223,29 @@ class HorizontalSplit(Display):
|
||||||
|
|
||||||
|
|
||||||
class Box(Display):
|
class Box(Display):
|
||||||
|
title: str = ""
|
||||||
|
|
||||||
|
def update_title(self, title: str) -> None:
|
||||||
|
self.title = title
|
||||||
|
|
||||||
def __init__(self, *args, fg_border_color: Optional[int] = None, **kwargs):
|
def __init__(self, *args, fg_border_color: Optional[int] = None, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.pad = self.newpad(self.rows, self.cols)
|
self.pad = self.newpad(self.rows, self.cols)
|
||||||
self.fg_border_color = fg_border_color or curses.COLOR_WHITE
|
self.fg_border_color = fg_border_color or curses.COLOR_WHITE
|
||||||
|
|
||||||
pair_number = 4 + self.fg_border_color
|
|
||||||
self.init_pair(pair_number, self.fg_border_color, curses.COLOR_BLACK)
|
|
||||||
self.pair = self.color_pair(pair_number)
|
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
self.addstr(self.pad, 0, 0, "┏" + "━" * (self.width - 2) + "┓",
|
self.addstr(self.pad, 0, 0, "┏" + "━" * (self.width - 2) + "┓",
|
||||||
self.pair)
|
self.fg_border_color)
|
||||||
for i in range(1, self.height - 1):
|
for i in range(1, self.height - 1):
|
||||||
self.addstr(self.pad, i, 0, "┃", self.pair)
|
self.addstr(self.pad, i, 0, "┃", self.fg_border_color)
|
||||||
self.addstr(self.pad, i, self.width - 1, "┃", self.pair)
|
self.addstr(self.pad, i, self.width - 1, "┃", self.fg_border_color)
|
||||||
self.addstr(self.pad, self.height - 1, 0,
|
self.addstr(self.pad, self.height - 1, 0,
|
||||||
"┗" + "━" * (self.width - 2) + "┛", self.pair)
|
"┗" + "━" * (self.width - 2) + "┛", self.fg_border_color)
|
||||||
|
|
||||||
|
if self.title:
|
||||||
|
self.addstr(self.pad, 0, (self.width - len(self.title) - 8) // 2,
|
||||||
|
f" == {self.title} == ", curses.COLOR_GREEN,
|
||||||
|
italic=True, bold=True)
|
||||||
|
|
||||||
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
self.y + self.height - 1, self.x + self.width - 1)
|
self.y + self.height - 1, self.x + self.width - 1)
|
||||||
|
|
|
@ -2,15 +2,16 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
from squirrelbattle.display.display import VerticalSplit, HorizontalSplit
|
from squirrelbattle.display.display import VerticalSplit, HorizontalSplit, \
|
||||||
|
Display
|
||||||
from squirrelbattle.display.mapdisplay import MapDisplay
|
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, \
|
||||||
InventoryDisplay, SettingsMenuDisplay
|
PlayerInventoryDisplay, StoreInventoryDisplay, SettingsMenuDisplay
|
||||||
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
|
from typing import Any, List
|
||||||
from squirrelbattle.game import Game, GameMode
|
from squirrelbattle.game import Game, GameMode
|
||||||
from squirrelbattle.enums import DisplayActions
|
from squirrelbattle.enums import DisplayActions
|
||||||
|
|
||||||
|
@ -24,7 +25,8 @@ class DisplayManager:
|
||||||
self.mapdisplay = MapDisplay(screen, pack)
|
self.mapdisplay = MapDisplay(screen, pack)
|
||||||
self.statsdisplay = StatsDisplay(screen, pack)
|
self.statsdisplay = StatsDisplay(screen, pack)
|
||||||
self.logsdisplay = LogsDisplay(screen, pack)
|
self.logsdisplay = LogsDisplay(screen, pack)
|
||||||
self.inventorydisplay = InventoryDisplay(screen, pack)
|
self.playerinventorydisplay = PlayerInventoryDisplay(screen, pack)
|
||||||
|
self.storeinventorydisplay = StoreInventoryDisplay(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)
|
||||||
|
@ -33,28 +35,50 @@ class DisplayManager:
|
||||||
self.vbar = VerticalSplit(screen, pack)
|
self.vbar = VerticalSplit(screen, pack)
|
||||||
self.displays = [self.statsdisplay, self.mapdisplay,
|
self.displays = [self.statsdisplay, self.mapdisplay,
|
||||||
self.mainmenudisplay, self.settingsmenudisplay,
|
self.mainmenudisplay, self.settingsmenudisplay,
|
||||||
self.logsdisplay, self.messagedisplay]
|
self.logsdisplay, self.messagedisplay,
|
||||||
|
self.playerinventorydisplay,
|
||||||
|
self.storeinventorydisplay]
|
||||||
self.update_game_components()
|
self.update_game_components()
|
||||||
|
|
||||||
def handle_display_action(self, action: DisplayActions) -> None:
|
def handle_display_action(self, action: DisplayActions, *params) -> None:
|
||||||
if action == DisplayActions.REFRESH:
|
if action == DisplayActions.REFRESH:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
elif action == DisplayActions.UPDATE:
|
elif action == DisplayActions.UPDATE:
|
||||||
self.update_game_components()
|
self.update_game_components()
|
||||||
|
elif action == DisplayActions.MOUSE:
|
||||||
|
self.handle_mouse_click(*params)
|
||||||
|
|
||||||
def update_game_components(self) -> None:
|
def update_game_components(self) -> None:
|
||||||
for d in self.displays:
|
for d in self.displays:
|
||||||
d.pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
|
d.pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
|
||||||
self.mapdisplay.update_map(self.game.map)
|
self.mapdisplay.update_map(self.game.map)
|
||||||
self.statsdisplay.update_player(self.game.player)
|
self.statsdisplay.update_player(self.game.player)
|
||||||
self.inventorydisplay.update_menu(self.game.inventory_menu)
|
self.game.inventory_menu.update_player(self.game.player)
|
||||||
|
self.game.store_menu.update_merchant(self.game.player)
|
||||||
|
self.playerinventorydisplay.update_menu(self.game.inventory_menu)
|
||||||
|
self.storeinventorydisplay.update_menu(self.game.store_menu)
|
||||||
self.settingsmenudisplay.update_menu(self.game.settings_menu)
|
self.settingsmenudisplay.update_menu(self.game.settings_menu)
|
||||||
self.logsdisplay.update_logs(self.game.logs)
|
self.logsdisplay.update_logs(self.game.logs)
|
||||||
self.messagedisplay.update_message(self.game.message)
|
self.messagedisplay.update_message(self.game.message)
|
||||||
|
|
||||||
def refresh(self) -> None:
|
def handle_mouse_click(self, y: int, x: int) -> None:
|
||||||
|
displays = self.refresh()
|
||||||
|
display = None
|
||||||
|
for d in displays:
|
||||||
|
top_y, top_x, height, width = d.y, d.x, d.height, d.width
|
||||||
|
if top_y <= y < top_y + height and top_x <= x < top_x + width:
|
||||||
|
# The click coordinates correspond to the coordinates
|
||||||
|
# of that display
|
||||||
|
display = d
|
||||||
|
if display:
|
||||||
|
display.handle_click(y - display.y, x - display.x, self.game)
|
||||||
|
|
||||||
|
def refresh(self) -> List[Display]:
|
||||||
|
displays = []
|
||||||
|
|
||||||
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:
|
||||||
# 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
|
||||||
|
@ -67,15 +91,26 @@ class DisplayManager:
|
||||||
self.rows // 5 - 1, self.cols * 4 // 5)
|
self.rows // 5 - 1, self.cols * 4 // 5)
|
||||||
self.hbar.refresh(self.rows * 4 // 5, 0, 1, self.cols * 4 // 5)
|
self.hbar.refresh(self.rows * 4 // 5, 0, 1, self.cols * 4 // 5)
|
||||||
self.vbar.refresh(0, self.cols * 4 // 5, self.rows, 1)
|
self.vbar.refresh(0, self.cols * 4 // 5, self.rows, 1)
|
||||||
|
|
||||||
|
displays += [self.mapdisplay, self.statsdisplay, self.logsdisplay,
|
||||||
|
self.hbar, self.vbar]
|
||||||
|
|
||||||
if self.game.state == GameMode.INVENTORY:
|
if self.game.state == GameMode.INVENTORY:
|
||||||
self.inventorydisplay.refresh(self.rows // 10,
|
self.playerinventorydisplay.refresh(
|
||||||
self.cols // 2,
|
self.rows // 10, self.cols // 2,
|
||||||
8 * self.rows // 10,
|
8 * self.rows // 10, 2 * self.cols // 5)
|
||||||
2 * self.cols // 5)
|
displays.append(self.playerinventorydisplay)
|
||||||
|
elif self.game.state == GameMode.STORE:
|
||||||
|
self.storeinventorydisplay.refresh(
|
||||||
|
self.rows // 10, self.cols // 2,
|
||||||
|
8 * self.rows // 10, 2 * self.cols // 5)
|
||||||
|
displays.append(self.storeinventorydisplay)
|
||||||
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)
|
||||||
elif self.game.state == GameMode.SETTINGS:
|
elif self.game.state == GameMode.SETTINGS:
|
||||||
self.settingsmenudisplay.refresh(0, 0, self.rows, self.cols)
|
self.settingsmenudisplay.refresh(0, 0, self.rows, self.cols)
|
||||||
|
displays.append(self.settingsmenudisplay)
|
||||||
|
|
||||||
if self.game.message:
|
if self.game.message:
|
||||||
height, width = 0, 0
|
height, width = 0, 0
|
||||||
|
@ -84,9 +119,12 @@ class DisplayManager:
|
||||||
width = max(width, len(line))
|
width = max(width, len(line))
|
||||||
y, x = (self.rows - height) // 2, (self.cols - width) // 2
|
y, x = (self.rows - height) // 2, (self.cols - width) // 2
|
||||||
self.messagedisplay.refresh(y, x, height, width)
|
self.messagedisplay.refresh(y, x, height, width)
|
||||||
|
displays.append(self.messagedisplay)
|
||||||
|
|
||||||
self.resize_window()
|
self.resize_window()
|
||||||
|
|
||||||
|
return displays
|
||||||
|
|
||||||
def resize_window(self) -> bool:
|
def resize_window(self) -> bool:
|
||||||
"""
|
"""
|
||||||
If the window got resized, ensure that the screen size got updated.
|
If the window got resized, ensure that the screen size got updated.
|
||||||
|
|
|
@ -15,15 +15,14 @@ class MapDisplay(Display):
|
||||||
self.pad = self.newpad(m.height, self.pack.tile_width * m.width + 1)
|
self.pad = self.newpad(m.height, self.pack.tile_width * m.width + 1)
|
||||||
|
|
||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
self.init_pair(1, self.pack.tile_fg_color, self.pack.tile_bg_color)
|
|
||||||
self.init_pair(2, self.pack.entity_fg_color, self.pack.entity_bg_color)
|
|
||||||
self.addstr(self.pad, 0, 0, self.map.draw_string(self.pack),
|
self.addstr(self.pad, 0, 0, self.map.draw_string(self.pack),
|
||||||
self.color_pair(1))
|
self.pack.tile_fg_color, self.pack.tile_bg_color)
|
||||||
for e in self.map.entities:
|
for e in self.map.entities:
|
||||||
self.addstr(self.pad, e.y, self.pack.tile_width * e.x,
|
self.addstr(self.pad, e.y, self.pack.tile_width * e.x,
|
||||||
self.pack[e.name.upper()], self.color_pair(2))
|
self.pack[e.name.upper()],
|
||||||
|
self.pack.entity_fg_color, self.pack.entity_bg_color)
|
||||||
|
|
||||||
# Display Path map for deubg purposes
|
# Display Path map for debug purposes
|
||||||
# from squirrelbattle.entities.player import Player
|
# from squirrelbattle.entities.player import Player
|
||||||
# players = [ p for p in self.map.entities if isinstance(p,Player) ]
|
# players = [ p for p in self.map.entities if isinstance(p,Player) ]
|
||||||
# player = players[0] if len(players) > 0 else None
|
# player = players[0] if len(players) > 0 else None
|
||||||
|
@ -42,7 +41,8 @@ class MapDisplay(Display):
|
||||||
# else:
|
# else:
|
||||||
# character = '←'
|
# character = '←'
|
||||||
# self.addstr(self.pad, y, self.pack.tile_width * x,
|
# self.addstr(self.pad, y, self.pack.tile_width * x,
|
||||||
# character, self.color_pair(1))
|
# character, self.pack.tile_fg_color,
|
||||||
|
# self.pack.tile_bg_color)
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
y, x = self.map.currenty, self.pack.tile_width * self.map.currentx
|
y, x = self.map.currenty, self.pack.tile_width * self.map.currentx
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
|
from random import randint
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from squirrelbattle.menus import Menu, MainMenu
|
from squirrelbattle.menus import Menu, MainMenu
|
||||||
from .display import Display, Box
|
from .display import Box, Display
|
||||||
|
from ..enums import KeyValues
|
||||||
|
from ..game import Game
|
||||||
from ..resources import ResourceManager
|
from ..resources import ResourceManager
|
||||||
from ..translations import gettext as _
|
from ..translations import gettext as _
|
||||||
|
|
||||||
|
|
||||||
class MenuDisplay(Display):
|
class MenuDisplay(Display):
|
||||||
|
"""
|
||||||
|
A class to display the menu objects
|
||||||
|
"""
|
||||||
position: int
|
position: int
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -24,9 +31,9 @@ class MenuDisplay(Display):
|
||||||
|
|
||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
for i in range(self.trueheight):
|
for i in range(self.trueheight):
|
||||||
self.addstr(self.pad, i, 0, " " + self.values[i])
|
self.addstr(self.pad, i, 0, " " + self.values[i])
|
||||||
# set a marker on the selected line
|
# set a marker on the selected line
|
||||||
self.addstr(self.pad, self.menu.position, 0, ">")
|
self.addstr(self.pad, self.menu.position, 0, " >")
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
cornery = 0 if self.height - 2 >= self.menu.position - 1 \
|
cornery = 0 if self.height - 2 >= self.menu.position - 1 \
|
||||||
|
@ -37,10 +44,17 @@ class MenuDisplay(Display):
|
||||||
self.menubox.refresh(self.y, self.x, self.height, self.width)
|
self.menubox.refresh(self.y, self.x, self.height, self.width)
|
||||||
self.pad.erase()
|
self.pad.erase()
|
||||||
self.update_pad()
|
self.update_pad()
|
||||||
self.refresh_pad(self.pad, cornery, 0, self.y + 1, self.x + 2,
|
self.refresh_pad(self.pad, cornery, 0, self.y + 1, self.x + 1,
|
||||||
self.height - 2 + self.y,
|
self.height - 2 + self.y,
|
||||||
self.width - 2 + self.x)
|
self.width - 2 + self.x)
|
||||||
|
|
||||||
|
def handle_click(self, y: int, x: 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 - 1))
|
||||||
|
game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def truewidth(self) -> int:
|
def truewidth(self) -> int:
|
||||||
return max([len(str(a)) for a in self.values])
|
return max([len(str(a)) for a in self.values])
|
||||||
|
@ -63,6 +77,9 @@ class MenuDisplay(Display):
|
||||||
|
|
||||||
|
|
||||||
class SettingsMenuDisplay(MenuDisplay):
|
class SettingsMenuDisplay(MenuDisplay):
|
||||||
|
"""
|
||||||
|
A class to display specifically a settingsmenu object
|
||||||
|
"""
|
||||||
@property
|
@property
|
||||||
def values(self) -> List[str]:
|
def values(self) -> List[str]:
|
||||||
return [_(a[1][1]) + (" : "
|
return [_(a[1][1]) + (" : "
|
||||||
|
@ -73,6 +90,9 @@ class SettingsMenuDisplay(MenuDisplay):
|
||||||
|
|
||||||
|
|
||||||
class MainMenuDisplay(Display):
|
class MainMenuDisplay(Display):
|
||||||
|
"""
|
||||||
|
A class to display specifically a mainmenu object
|
||||||
|
"""
|
||||||
def __init__(self, menu: MainMenu, *args):
|
def __init__(self, menu: MainMenu, *args):
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
self.menu = menu
|
self.menu = menu
|
||||||
|
@ -83,13 +103,16 @@ class MainMenuDisplay(Display):
|
||||||
self.pad = self.newpad(max(self.rows, len(self.title) + 30),
|
self.pad = self.newpad(max(self.rows, len(self.title) + 30),
|
||||||
max(len(self.title[0]) + 5, self.cols))
|
max(len(self.title[0]) + 5, self.cols))
|
||||||
|
|
||||||
|
self.fg_color = curses.COLOR_WHITE
|
||||||
|
|
||||||
self.menudisplay = MenuDisplay(self.screen, self.pack)
|
self.menudisplay = MenuDisplay(self.screen, self.pack)
|
||||||
self.menudisplay.update_menu(self.menu)
|
self.menudisplay.update_menu(self.menu)
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
for i in range(len(self.title)):
|
for i in range(len(self.title)):
|
||||||
self.addstr(self.pad, 4 + i, max(self.width // 2
|
self.addstr(self.pad, 4 + i, max(self.width // 2
|
||||||
- len(self.title[0]) // 2 - 1, 0), self.title[i])
|
- len(self.title[0]) // 2 - 1, 0), self.title[i],
|
||||||
|
self.fg_color)
|
||||||
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
self.height + self.y - 1,
|
self.height + self.y - 1,
|
||||||
self.width + self.x - 1)
|
self.width + self.x - 1)
|
||||||
|
@ -99,16 +122,25 @@ class MainMenuDisplay(Display):
|
||||||
menuy, menux, min(self.menudisplay.preferred_height,
|
menuy, menux, min(self.menudisplay.preferred_height,
|
||||||
self.height - menuy), menuwidth)
|
self.height - menuy), menuwidth)
|
||||||
|
|
||||||
|
def handle_click(self, y: int, x: int, game: Game) -> None:
|
||||||
|
menuwidth = min(self.menudisplay.preferred_width, self.width)
|
||||||
|
menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1
|
||||||
|
menuheight = min(self.menudisplay.preferred_height, self.height - menuy)
|
||||||
|
|
||||||
class InventoryDisplay(MenuDisplay):
|
if menuy <= y < menuy + menuheight and menux <= x < menux + menuwidth:
|
||||||
|
self.menudisplay.handle_click(y - menuy, x - menux, game)
|
||||||
|
|
||||||
|
if y <= len(self.title):
|
||||||
|
self.fg_color = randint(0, 1000), randint(0, 1000), randint(0, 1000)
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerInventoryDisplay(MenuDisplay):
|
||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
message = _("== INVENTORY ==")
|
self.menubox.update_title(_("INVENTORY"))
|
||||||
self.addstr(self.pad, 0, (self.width - len(message)) // 2, message,
|
|
||||||
curses.A_BOLD | curses.A_ITALIC)
|
|
||||||
for i, item in enumerate(self.menu.values):
|
for i, item in enumerate(self.menu.values):
|
||||||
rep = self.pack[item.name.upper()]
|
rep = self.pack[item.name.upper()]
|
||||||
selection = f"[{rep}]" if i == self.menu.position else f" {rep} "
|
selection = f"[{rep}]" if i == self.menu.position else f" {rep} "
|
||||||
self.addstr(self.pad, 2 + i, 0, selection
|
self.addstr(self.pad, i + 1, 0, selection
|
||||||
+ " " + item.translated_name.capitalize())
|
+ " " + item.translated_name.capitalize())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -118,3 +150,36 @@ class InventoryDisplay(MenuDisplay):
|
||||||
@property
|
@property
|
||||||
def trueheight(self) -> int:
|
def trueheight(self) -> int:
|
||||||
return 2 + super().trueheight
|
return 2 + super().trueheight
|
||||||
|
|
||||||
|
def handle_click(self, y: int, x: 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.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
|
||||||
|
|
||||||
|
class StoreInventoryDisplay(MenuDisplay):
|
||||||
|
def update_pad(self) -> None:
|
||||||
|
self.menubox.update_title(_("STALL"))
|
||||||
|
for i, item in enumerate(self.menu.values):
|
||||||
|
rep = self.pack[item.name.upper()]
|
||||||
|
selection = f"[{rep}]" if i == self.menu.position else f" {rep} "
|
||||||
|
self.addstr(self.pad, i + 1, 0, selection
|
||||||
|
+ " " + item.translated_name.capitalize()
|
||||||
|
+ ": " + str(item.price) + " Hazels")
|
||||||
|
|
||||||
|
@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, 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.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
|
|
@ -25,7 +25,7 @@ class MessageDisplay(Display):
|
||||||
self.height + 2, self.width + 4)
|
self.height + 2, self.width + 4)
|
||||||
self.box.display()
|
self.box.display()
|
||||||
self.pad.erase()
|
self.pad.erase()
|
||||||
self.addstr(self.pad, 0, 0, self.message, curses.A_BOLD)
|
self.addstr(self.pad, 0, 0, self.message, bold=True)
|
||||||
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
self.height + self.y - 1,
|
self.height + self.y - 1,
|
||||||
self.width + self.x - 1)
|
self.width + self.x - 1)
|
||||||
|
|
|
@ -14,7 +14,6 @@ class StatsDisplay(Display):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.pad = self.newpad(self.rows, self.cols)
|
self.pad = self.newpad(self.rows, self.cols)
|
||||||
self.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)
|
|
||||||
|
|
||||||
def update_player(self, p: Player) -> None:
|
def update_player(self, p: Player) -> None:
|
||||||
self.player = p
|
self.player = p
|
||||||
|
@ -46,10 +45,12 @@ class StatsDisplay(Display):
|
||||||
printed_items.append(item)
|
printed_items.append(item)
|
||||||
self.addstr(self.pad, 8, 0, inventory_str)
|
self.addstr(self.pad, 8, 0, inventory_str)
|
||||||
|
|
||||||
|
self.addstr(self.pad, 9, 0, f"{self.pack.HAZELNUT} "
|
||||||
|
f"x{self.player.hazel}")
|
||||||
|
|
||||||
if self.player.dead:
|
if self.player.dead:
|
||||||
self.addstr(self.pad, 10, 0, _("YOU ARE DEAD"),
|
self.addstr(self.pad, 11, 0, _("YOU ARE DEAD"), curses.COLOR_RED,
|
||||||
curses.A_BOLD | curses.A_BLINK | curses.A_STANDOUT
|
bold=True, blink=True, standout=True)
|
||||||
| self.color_pair(3))
|
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
self.pad.erase()
|
self.pad.erase()
|
||||||
|
|
|
@ -14,10 +14,22 @@ class TexturePack:
|
||||||
tile_bg_color: int
|
tile_bg_color: int
|
||||||
entity_fg_color: int
|
entity_fg_color: int
|
||||||
entity_bg_color: int
|
entity_bg_color: int
|
||||||
|
|
||||||
|
BODY_SNATCH_POTION: str
|
||||||
|
BOMB: str
|
||||||
|
HEART: str
|
||||||
|
HEDGEHOG: str
|
||||||
EMPTY: str
|
EMPTY: str
|
||||||
WALL: str
|
|
||||||
FLOOR: str
|
FLOOR: str
|
||||||
|
HAZELNUT: str
|
||||||
|
MERCHANT: str
|
||||||
PLAYER: str
|
PLAYER: str
|
||||||
|
RABBIT: str
|
||||||
|
SUNFLOWER: str
|
||||||
|
SWORD: str
|
||||||
|
TEDDY_BEAR: str
|
||||||
|
TIGER: str
|
||||||
|
WALL: str
|
||||||
|
|
||||||
ASCII_PACK: "TexturePack"
|
ASCII_PACK: "TexturePack"
|
||||||
SQUIRREL_PACK: "TexturePack"
|
SQUIRREL_PACK: "TexturePack"
|
||||||
|
@ -46,17 +58,23 @@ TexturePack.ASCII_PACK = TexturePack(
|
||||||
tile_bg_color=curses.COLOR_BLACK,
|
tile_bg_color=curses.COLOR_BLACK,
|
||||||
entity_fg_color=curses.COLOR_WHITE,
|
entity_fg_color=curses.COLOR_WHITE,
|
||||||
entity_bg_color=curses.COLOR_BLACK,
|
entity_bg_color=curses.COLOR_BLACK,
|
||||||
EMPTY=' ',
|
|
||||||
WALL='#',
|
|
||||||
FLOOR='.',
|
|
||||||
PLAYER='@',
|
|
||||||
HEDGEHOG='*',
|
|
||||||
HEART='❤',
|
|
||||||
BOMB='o',
|
|
||||||
RABBIT='Y',
|
|
||||||
TIGER='n',
|
|
||||||
TEDDY_BEAR='8',
|
|
||||||
BODY_SNATCH_POTION='S',
|
BODY_SNATCH_POTION='S',
|
||||||
|
BOMB='o',
|
||||||
|
EMPTY=' ',
|
||||||
|
EXPLOSION='%',
|
||||||
|
FLOOR='.',
|
||||||
|
HAZELNUT='¤',
|
||||||
|
HEART='❤',
|
||||||
|
HEDGEHOG='*',
|
||||||
|
MERCHANT='M',
|
||||||
|
PLAYER='@',
|
||||||
|
RABBIT='Y',
|
||||||
|
SUNFLOWER='I',
|
||||||
|
SWORD='\u2020',
|
||||||
|
TEDDY_BEAR='8',
|
||||||
|
TIGER='n',
|
||||||
|
WALL='#',
|
||||||
)
|
)
|
||||||
|
|
||||||
TexturePack.SQUIRREL_PACK = TexturePack(
|
TexturePack.SQUIRREL_PACK = TexturePack(
|
||||||
|
@ -66,15 +84,21 @@ TexturePack.SQUIRREL_PACK = TexturePack(
|
||||||
tile_bg_color=curses.COLOR_BLACK,
|
tile_bg_color=curses.COLOR_BLACK,
|
||||||
entity_fg_color=curses.COLOR_WHITE,
|
entity_fg_color=curses.COLOR_WHITE,
|
||||||
entity_bg_color=curses.COLOR_WHITE,
|
entity_bg_color=curses.COLOR_WHITE,
|
||||||
EMPTY=' ',
|
|
||||||
WALL='🧱',
|
|
||||||
FLOOR='██',
|
|
||||||
PLAYER='🐿️ ️',
|
|
||||||
HEDGEHOG='🦔',
|
|
||||||
HEART='💜',
|
|
||||||
BOMB='💣',
|
|
||||||
RABBIT='🐇',
|
|
||||||
TIGER='🐅',
|
|
||||||
TEDDY_BEAR='🧸',
|
|
||||||
BODY_SNATCH_POTION='🔀',
|
BODY_SNATCH_POTION='🔀',
|
||||||
|
BOMB='💣',
|
||||||
|
EMPTY=' ',
|
||||||
|
EXPLOSION='💥',
|
||||||
|
FLOOR='██',
|
||||||
|
HAZELNUT='🌰',
|
||||||
|
HEART='💜',
|
||||||
|
HEDGEHOG='🦔',
|
||||||
|
PLAYER='🐿️ ️',
|
||||||
|
MERCHANT='🦜',
|
||||||
|
RABBIT='🐇',
|
||||||
|
SUNFLOWER='🌻',
|
||||||
|
SWORD='🗡️',
|
||||||
|
TEDDY_BEAR='🧸',
|
||||||
|
TIGER='🐅',
|
||||||
|
WALL='🧱',
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
from ..interfaces import FriendlyEntity, InventoryHolder
|
||||||
|
from ..translations import gettext as _
|
||||||
|
from .player import Player
|
||||||
|
from .items import Item
|
||||||
|
from random import choice
|
||||||
|
|
||||||
|
|
||||||
|
class Merchant(InventoryHolder, FriendlyEntity):
|
||||||
|
"""
|
||||||
|
The class for merchants in the dungeon
|
||||||
|
"""
|
||||||
|
def keys(self) -> list:
|
||||||
|
"""
|
||||||
|
Returns a friendly entitie's specific attributes
|
||||||
|
"""
|
||||||
|
return super().keys() + ["inventory", "hazel"]
|
||||||
|
|
||||||
|
def __init__(self, name: str = "merchant", inventory: list = None,
|
||||||
|
hazel: int = 75, *args, **kwargs):
|
||||||
|
super().__init__(name=name, *args, **kwargs)
|
||||||
|
self.inventory = self.translate_inventory(inventory or [])
|
||||||
|
self.hazel = hazel
|
||||||
|
|
||||||
|
if not self.inventory:
|
||||||
|
for i in range(5):
|
||||||
|
self.inventory.append(choice(Item.get_all_items())())
|
||||||
|
|
||||||
|
def talk_to(self, player: Player) -> str:
|
||||||
|
"""
|
||||||
|
This function is used to open the merchant's inventory in a menu,
|
||||||
|
and allow the player to buy/sell objects
|
||||||
|
"""
|
||||||
|
return _("I don't sell any squirrel")
|
||||||
|
|
||||||
|
def change_hazel_balance(self, hz: int) -> None:
|
||||||
|
"""
|
||||||
|
Change the number of hazel the merchant has by hz.
|
||||||
|
"""
|
||||||
|
self.hazel += hz
|
||||||
|
|
||||||
|
|
||||||
|
class Sunflower(FriendlyEntity):
|
||||||
|
"""
|
||||||
|
A friendly sunflower
|
||||||
|
"""
|
||||||
|
def __init__(self, maxhealth: int = 15,
|
||||||
|
*args, **kwargs) -> None:
|
||||||
|
super().__init__(name="sunflower", maxhealth=maxhealth, *args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dialogue_option(self) -> list:
|
||||||
|
return [_("Flower power!!"), _("The sun is warm today")]
|
|
@ -5,7 +5,7 @@ from random import choice, randint
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from .player import Player
|
from .player import Player
|
||||||
from ..interfaces import Entity, FightingEntity, Map
|
from ..interfaces import Entity, FightingEntity, Map, InventoryHolder
|
||||||
from ..translations import gettext as _
|
from ..translations import gettext as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,13 +14,16 @@ class Item(Entity):
|
||||||
A class for items
|
A class for items
|
||||||
"""
|
"""
|
||||||
held: bool
|
held: bool
|
||||||
held_by: Optional[Player]
|
held_by: Optional[InventoryHolder]
|
||||||
|
price: int
|
||||||
|
|
||||||
def __init__(self, held: bool = False, held_by: Optional[Player] = None,
|
def __init__(self, held: bool = False,
|
||||||
*args, **kwargs):
|
held_by: Optional[InventoryHolder] = None,
|
||||||
|
price: int = 2, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.held = held
|
self.held = held
|
||||||
self.held_by = held_by
|
self.held_by = held_by
|
||||||
|
self.price = price
|
||||||
|
|
||||||
def drop(self) -> None:
|
def drop(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -28,7 +31,7 @@ class Item(Entity):
|
||||||
"""
|
"""
|
||||||
if self.held:
|
if self.held:
|
||||||
self.held_by.inventory.remove(self)
|
self.held_by.inventory.remove(self)
|
||||||
self.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
|
||||||
self.held_by = None
|
self.held_by = None
|
||||||
|
@ -43,14 +46,14 @@ class Item(Entity):
|
||||||
Indicates what should be done when the item is equipped.
|
Indicates what should be done when the item is equipped.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def hold(self, player: "Player") -> None:
|
def hold(self, player: 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 = player
|
||||||
self.map.remove_entity(self)
|
self.held_by.map.remove_entity(self)
|
||||||
player.inventory.append(self)
|
player.add_to_inventory(self)
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
|
@ -60,6 +63,25 @@ class Item(Entity):
|
||||||
d["held"] = self.held
|
d["held"] = self.held
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_all_items() -> list:
|
||||||
|
return [BodySnatchPotion, Bomb, Heart, Sword]
|
||||||
|
|
||||||
|
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool:
|
||||||
|
"""
|
||||||
|
Does all necessary actions when an object is to be sold.
|
||||||
|
Is overwritten by some classes that cannot exist in the player's
|
||||||
|
inventory
|
||||||
|
"""
|
||||||
|
if buyer.hazel >= self.price:
|
||||||
|
self.hold(buyer)
|
||||||
|
seller.remove_from_inventory(self)
|
||||||
|
buyer.change_hazel_balance(-self.price)
|
||||||
|
seller.change_hazel_balance(self.price)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Heart(Item):
|
class Heart(Item):
|
||||||
"""
|
"""
|
||||||
|
@ -67,16 +89,17 @@ class Heart(Item):
|
||||||
"""
|
"""
|
||||||
healing: int
|
healing: int
|
||||||
|
|
||||||
def __init__(self, name: str = "heart", healing: int = 5, *args, **kwargs):
|
def __init__(self, name: str = "heart", healing: int = 5, price: int = 3,
|
||||||
super().__init__(name=name, *args, **kwargs)
|
*args, **kwargs):
|
||||||
|
super().__init__(name=name, price=price, *args, **kwargs)
|
||||||
self.healing = healing
|
self.healing = healing
|
||||||
|
|
||||||
def hold(self, player: "Player") -> None:
|
def hold(self, entity: InventoryHolder) -> None:
|
||||||
"""
|
"""
|
||||||
When holding a heart, heal the player and don't put item in inventory.
|
When holding a heart, heal the player and don't put item in inventory.
|
||||||
"""
|
"""
|
||||||
player.health = min(player.maxhealth, player.health + self.healing)
|
entity.health = min(entity.maxhealth, entity.health + self.healing)
|
||||||
self.map.remove_entity(self)
|
entity.map.remove_entity(self)
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
|
@ -97,8 +120,8 @@ class Bomb(Item):
|
||||||
tick: int
|
tick: int
|
||||||
|
|
||||||
def __init__(self, name: str = "bomb", damage: int = 5,
|
def __init__(self, name: str = "bomb", damage: int = 5,
|
||||||
exploding: bool = False, *args, **kwargs):
|
exploding: bool = False, price: int = 4, *args, **kwargs):
|
||||||
super().__init__(name=name, *args, **kwargs)
|
super().__init__(name=name, price=price, *args, **kwargs)
|
||||||
self.damage = damage
|
self.damage = damage
|
||||||
self.exploding = exploding
|
self.exploding = exploding
|
||||||
self.tick = 4
|
self.tick = 4
|
||||||
|
@ -135,6 +158,10 @@ class Bomb(Item):
|
||||||
m.logs.add_message(log_message)
|
m.logs.add_message(log_message)
|
||||||
m.entities.remove(self)
|
m.entities.remove(self)
|
||||||
|
|
||||||
|
# Add sparkles where the bomb exploded.
|
||||||
|
explosion = Explosion(y=self.y, x=self.x)
|
||||||
|
self.map.add_entity(explosion)
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Saves the state of the bomb into a dictionary
|
Saves the state of the bomb into a dictionary
|
||||||
|
@ -145,14 +172,63 @@ class Bomb(Item):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
class Explosion(Item):
|
||||||
|
"""
|
||||||
|
When a bomb explodes, the explosion is displayed.
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(name="explosion", *args, **kwargs)
|
||||||
|
|
||||||
|
def act(self, m: Map) -> None:
|
||||||
|
"""
|
||||||
|
The explosion instant dies.
|
||||||
|
"""
|
||||||
|
m.remove_entity(self)
|
||||||
|
|
||||||
|
def hold(self, player: InventoryHolder) -> None:
|
||||||
|
"""
|
||||||
|
The player can't hold any explosion.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Weapon(Item):
|
||||||
|
"""
|
||||||
|
Non-throwable items that improve player damage
|
||||||
|
"""
|
||||||
|
damage: int
|
||||||
|
|
||||||
|
def __init__(self, damage: int = 3, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.damage = damage
|
||||||
|
|
||||||
|
def save_state(self) -> dict:
|
||||||
|
"""
|
||||||
|
Saves the state of the weapon into a dictionary
|
||||||
|
"""
|
||||||
|
d = super().save_state()
|
||||||
|
d["damage"] = self.damage
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
class Sword(Weapon):
|
||||||
|
"""
|
||||||
|
A basic weapon
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str = "sword", price: int = 20, *args, **kwargs):
|
||||||
|
super().__init__(name=name, price=price, *args, **kwargs)
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
class BodySnatchPotion(Item):
|
class BodySnatchPotion(Item):
|
||||||
"""
|
"""
|
||||||
The body-snatch potion allows to exchange all characteristics with a random
|
The body-snatch potion allows to exchange all characteristics with a random
|
||||||
other entity.
|
other entity.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str = "body_snatch_potion", *args, **kwargs):
|
def __init__(self, name: str = "body_snatch_potion", price: int = 14,
|
||||||
super().__init__(name=name, *args, **kwargs)
|
*args, **kwargs):
|
||||||
|
super().__init__(name=name, price=price, *args, **kwargs)
|
||||||
|
|
||||||
def use(self) -> None:
|
def use(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,23 +6,22 @@ from queue import PriorityQueue
|
||||||
from random import randint
|
from random import randint
|
||||||
from typing import Dict, Tuple
|
from typing import Dict, Tuple
|
||||||
|
|
||||||
from ..interfaces import FightingEntity
|
from ..interfaces import FightingEntity, InventoryHolder
|
||||||
|
|
||||||
|
|
||||||
class Player(FightingEntity):
|
class Player(InventoryHolder, FightingEntity):
|
||||||
"""
|
"""
|
||||||
The class of the player
|
The class of the player
|
||||||
"""
|
"""
|
||||||
current_xp: int = 0
|
current_xp: int = 0
|
||||||
max_xp: int = 10
|
max_xp: int = 10
|
||||||
inventory: list
|
|
||||||
paths: Dict[Tuple[int, int], Tuple[int, int]]
|
paths: Dict[Tuple[int, int], Tuple[int, int]]
|
||||||
|
|
||||||
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,
|
||||||
*args, **kwargs) \
|
hazel: int = 42, *args, **kwargs) \
|
||||||
-> None:
|
-> 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,
|
||||||
|
@ -30,13 +29,9 @@ class Player(FightingEntity):
|
||||||
level=level, *args, **kwargs)
|
level=level, *args, **kwargs)
|
||||||
self.current_xp = current_xp
|
self.current_xp = current_xp
|
||||||
self.max_xp = max_xp
|
self.max_xp = max_xp
|
||||||
self.inventory = inventory if inventory else list()
|
self.inventory = self.translate_inventory(inventory or [])
|
||||||
for i in range(len(self.inventory)):
|
|
||||||
if isinstance(self.inventory[i], dict):
|
|
||||||
entity_classes = self.get_all_entity_classes_in_a_dict()
|
|
||||||
item_class = entity_classes[self.inventory[i]["type"]]
|
|
||||||
self.inventory[i] = item_class(**self.inventory[i])
|
|
||||||
self.paths = dict()
|
self.paths = dict()
|
||||||
|
self.hazel = hazel
|
||||||
|
|
||||||
def move(self, y: int, x: int) -> None:
|
def move(self, y: int, x: int) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -149,5 +144,4 @@ class Player(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["inventory"] = [item.save_state() for item in self.inventory]
|
|
||||||
return d
|
return d
|
||||||
|
|
|
@ -16,6 +16,7 @@ class DisplayActions(Enum):
|
||||||
"""
|
"""
|
||||||
REFRESH = auto()
|
REFRESH = auto()
|
||||||
UPDATE = auto()
|
UPDATE = auto()
|
||||||
|
MOUSE = auto()
|
||||||
|
|
||||||
|
|
||||||
class GameMode(Enum):
|
class GameMode(Enum):
|
||||||
|
@ -26,12 +27,14 @@ class GameMode(Enum):
|
||||||
PLAY = auto()
|
PLAY = auto()
|
||||||
SETTINGS = auto()
|
SETTINGS = auto()
|
||||||
INVENTORY = auto()
|
INVENTORY = auto()
|
||||||
|
STORE = auto()
|
||||||
|
|
||||||
|
|
||||||
class KeyValues(Enum):
|
class KeyValues(Enum):
|
||||||
"""
|
"""
|
||||||
Key values options used in the game
|
Key values options used in the game
|
||||||
"""
|
"""
|
||||||
|
MOUSE = auto()
|
||||||
UP = auto()
|
UP = auto()
|
||||||
DOWN = auto()
|
DOWN = auto()
|
||||||
LEFT = auto()
|
LEFT = auto()
|
||||||
|
@ -42,6 +45,8 @@ class KeyValues(Enum):
|
||||||
EQUIP = auto()
|
EQUIP = auto()
|
||||||
DROP = auto()
|
DROP = auto()
|
||||||
SPACE = auto()
|
SPACE = auto()
|
||||||
|
CHAT = auto()
|
||||||
|
WAIT = auto()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def translate_key(key: str, settings: Settings) -> Optional["KeyValues"]:
|
def translate_key(key: str, settings: Settings) -> Optional["KeyValues"]:
|
||||||
|
@ -72,4 +77,8 @@ class KeyValues(Enum):
|
||||||
return KeyValues.DROP
|
return KeyValues.DROP
|
||||||
elif key == ' ':
|
elif key == ' ':
|
||||||
return KeyValues.SPACE
|
return KeyValues.SPACE
|
||||||
|
elif key == settings.KEY_CHAT:
|
||||||
|
return KeyValues.CHAT
|
||||||
|
elif key == settings.KEY_WAIT:
|
||||||
|
return KeyValues.WAIT
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
from random import randint
|
from random import randint
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
import curses
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -15,7 +16,6 @@ from .resources import ResourceManager
|
||||||
from .settings import Settings
|
from .settings import Settings
|
||||||
from . import menus
|
from . import menus
|
||||||
from .translations import gettext as _, Translator
|
from .translations import gettext as _, Translator
|
||||||
from typing import Callable
|
|
||||||
|
|
||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
|
@ -24,14 +24,16 @@ class Game:
|
||||||
"""
|
"""
|
||||||
map: Map
|
map: Map
|
||||||
player: Player
|
player: Player
|
||||||
|
screen: Any
|
||||||
# display_actions is a display interface set by the bootstrapper
|
# display_actions is a display interface set by the bootstrapper
|
||||||
display_actions: Callable[[DisplayActions], None]
|
display_actions: callable
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""
|
"""
|
||||||
Init the game.
|
Init the game.
|
||||||
"""
|
"""
|
||||||
self.state = GameMode.MAINMENU
|
self.state = GameMode.MAINMENU
|
||||||
|
self.waiting_for_friendly_key = False
|
||||||
self.settings = Settings()
|
self.settings = Settings()
|
||||||
self.settings.load_settings()
|
self.settings.load_settings()
|
||||||
self.settings.write_settings()
|
self.settings.write_settings()
|
||||||
|
@ -40,6 +42,7 @@ class Game:
|
||||||
self.settings_menu = menus.SettingsMenu()
|
self.settings_menu = menus.SettingsMenu()
|
||||||
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.logs = Logs()
|
self.logs = Logs()
|
||||||
self.message = None
|
self.message = None
|
||||||
|
|
||||||
|
@ -68,8 +71,12 @@ class Game:
|
||||||
screen.refresh()
|
screen.refresh()
|
||||||
self.display_actions(DisplayActions.REFRESH)
|
self.display_actions(DisplayActions.REFRESH)
|
||||||
key = screen.getkey()
|
key = screen.getkey()
|
||||||
self.handle_key_pressed(
|
if key == "KEY_MOUSE":
|
||||||
KeyValues.translate_key(key, self.settings), key)
|
_ignored1, x, y, _ignored2, _ignored3 = curses.getmouse()
|
||||||
|
self.display_actions(DisplayActions.MOUSE, y, x)
|
||||||
|
else:
|
||||||
|
self.handle_key_pressed(
|
||||||
|
KeyValues.translate_key(key, self.settings), key)
|
||||||
|
|
||||||
def handle_key_pressed(self, key: Optional[KeyValues], raw_key: str = '')\
|
def handle_key_pressed(self, key: Optional[KeyValues], raw_key: str = '')\
|
||||||
-> None:
|
-> None:
|
||||||
|
@ -83,13 +90,19 @@ class Game:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.state == GameMode.PLAY:
|
if self.state == GameMode.PLAY:
|
||||||
self.handle_key_pressed_play(key)
|
if self.waiting_for_friendly_key:
|
||||||
|
# The player requested to talk with a friendly entity
|
||||||
|
self.handle_friendly_entity_chat(key)
|
||||||
|
else:
|
||||||
|
self.handle_key_pressed_play(key)
|
||||||
elif self.state == GameMode.INVENTORY:
|
elif self.state == GameMode.INVENTORY:
|
||||||
self.handle_key_pressed_inventory(key)
|
self.handle_key_pressed_inventory(key)
|
||||||
elif self.state == GameMode.MAINMENU:
|
elif self.state == GameMode.MAINMENU:
|
||||||
self.handle_key_pressed_main_menu(key)
|
self.handle_key_pressed_main_menu(key)
|
||||||
elif self.state == GameMode.SETTINGS:
|
elif self.state == GameMode.SETTINGS:
|
||||||
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:
|
||||||
|
self.handle_key_pressed_store(key)
|
||||||
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:
|
||||||
|
@ -112,6 +125,44 @@ class Game:
|
||||||
self.state = GameMode.INVENTORY
|
self.state = GameMode.INVENTORY
|
||||||
elif key == KeyValues.SPACE:
|
elif key == KeyValues.SPACE:
|
||||||
self.state = GameMode.MAINMENU
|
self.state = GameMode.MAINMENU
|
||||||
|
elif key == KeyValues.CHAT:
|
||||||
|
# Wait for the direction of the friendly entity
|
||||||
|
self.waiting_for_friendly_key = True
|
||||||
|
elif key == KeyValues.WAIT:
|
||||||
|
self.map.tick()
|
||||||
|
|
||||||
|
def handle_friendly_entity_chat(self, key: KeyValues) -> None:
|
||||||
|
"""
|
||||||
|
If the player is talking to a friendly entity, we get the direction
|
||||||
|
where the entity is, then we interact with it.
|
||||||
|
"""
|
||||||
|
if not self.waiting_for_friendly_key:
|
||||||
|
return
|
||||||
|
self.waiting_for_friendly_key = False
|
||||||
|
|
||||||
|
if key == KeyValues.UP:
|
||||||
|
xp = self.player.x
|
||||||
|
yp = self.player.y - 1
|
||||||
|
elif key == KeyValues.DOWN:
|
||||||
|
xp = self.player.x
|
||||||
|
yp = self.player.y + 1
|
||||||
|
elif key == KeyValues.LEFT:
|
||||||
|
xp = self.player.x - 1
|
||||||
|
yp = self.player.y
|
||||||
|
elif key == KeyValues.RIGHT:
|
||||||
|
xp = self.player.x + 1
|
||||||
|
yp = self.player.y
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
if self.map.entity_is_present(yp, xp):
|
||||||
|
for entity in self.map.entities:
|
||||||
|
if entity.is_friendly() and entity.x == xp and \
|
||||||
|
entity.y == yp:
|
||||||
|
msg = entity.talk_to(self.player)
|
||||||
|
self.logs.add_message(msg)
|
||||||
|
if entity.is_merchant():
|
||||||
|
self.state = GameMode.STORE
|
||||||
|
self.store_menu.update_merchant(entity)
|
||||||
|
|
||||||
def handle_key_pressed_inventory(self, key: KeyValues) -> None:
|
def handle_key_pressed_inventory(self, key: KeyValues) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -136,6 +187,27 @@ class Game:
|
||||||
len(self.inventory_menu.values)
|
len(self.inventory_menu.values)
|
||||||
- 1)
|
- 1)
|
||||||
|
|
||||||
|
def handle_key_pressed_store(self, key: KeyValues) -> None:
|
||||||
|
"""
|
||||||
|
In a store menu, we can buy items or close the menu.
|
||||||
|
"""
|
||||||
|
if key == KeyValues.SPACE:
|
||||||
|
self.state = GameMode.PLAY
|
||||||
|
elif key == KeyValues.UP:
|
||||||
|
self.store_menu.go_up()
|
||||||
|
elif key == KeyValues.DOWN:
|
||||||
|
self.store_menu.go_down()
|
||||||
|
if self.store_menu.values and not self.player.dead:
|
||||||
|
if key == KeyValues.ENTER:
|
||||||
|
item = self.store_menu.validate()
|
||||||
|
flag = item.be_sold(self.player, self.store_menu.merchant)
|
||||||
|
if not flag:
|
||||||
|
self.message = _("You do not have enough money")
|
||||||
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
# Ensure that the cursor has a good position
|
||||||
|
self.store_menu.position = min(self.store_menu.position,
|
||||||
|
len(self.store_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 options.
|
In the main menu, we can navigate through options.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from math import sqrt
|
from math import sqrt
|
||||||
from random import choice, randint
|
from random import choice, randint
|
||||||
from typing import List, Optional, Union, Tuple
|
from typing import List, Optional, Union, Tuple, Any
|
||||||
|
|
||||||
from .display.texturepack import TexturePack
|
from .display.texturepack import TexturePack
|
||||||
from .translations import gettext as _
|
from .translations import gettext as _
|
||||||
|
@ -93,7 +93,8 @@ class Map:
|
||||||
"""
|
"""
|
||||||
Unregister an entity from the map.
|
Unregister an entity from the map.
|
||||||
"""
|
"""
|
||||||
self.entities.remove(entity)
|
if entity in self.entities:
|
||||||
|
self.entities.remove(entity)
|
||||||
|
|
||||||
def find_entities(self, entity_class: type) -> list:
|
def find_entities(self, entity_class: type) -> list:
|
||||||
return [entity for entity in self.entities
|
return [entity for entity in self.entities
|
||||||
|
@ -101,12 +102,21 @@ class Map:
|
||||||
|
|
||||||
def is_free(self, y: int, x: int) -> bool:
|
def is_free(self, y: int, x: int) -> bool:
|
||||||
"""
|
"""
|
||||||
Indicates that the case at the coordinates (y, x) is empty.
|
Indicates that the tile at the coordinates (y, x) is empty.
|
||||||
"""
|
"""
|
||||||
return 0 <= y < self.height and 0 <= x < self.width and \
|
return 0 <= y < self.height and 0 <= x < self.width and \
|
||||||
self.tiles[y][x].can_walk() and \
|
self.tiles[y][x].can_walk() and \
|
||||||
not any(entity.x == x and entity.y == y for entity in self.entities)
|
not any(entity.x == x and entity.y == y for entity in self.entities)
|
||||||
|
|
||||||
|
def entity_is_present(self, y: int, x: int) -> bool:
|
||||||
|
"""
|
||||||
|
Indicates that the tile at the coordinates (y, x) contains a killable
|
||||||
|
entity
|
||||||
|
"""
|
||||||
|
return 0 <= y < self.height and 0 <= x < self.width and \
|
||||||
|
any(entity.x == x and entity.y == y and entity.is_friendly()
|
||||||
|
for entity in self.entities)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(filename: str) -> "Map":
|
def load(filename: str) -> "Map":
|
||||||
"""
|
"""
|
||||||
|
@ -152,7 +162,7 @@ class Map:
|
||||||
|
|
||||||
def spawn_random_entities(self, count: int) -> None:
|
def spawn_random_entities(self, count: int) -> None:
|
||||||
"""
|
"""
|
||||||
Put randomly {count} hedgehogs on the map, where it is available.
|
Put randomly {count} entities on the map, where it is available.
|
||||||
"""
|
"""
|
||||||
for _ignored in range(count):
|
for _ignored in range(count):
|
||||||
y, x = 0, 0
|
y, x = 0, 0
|
||||||
|
@ -459,20 +469,34 @@ class Entity:
|
||||||
from squirrelbattle.entities.items import Item
|
from squirrelbattle.entities.items import Item
|
||||||
return isinstance(self, Item)
|
return isinstance(self, Item)
|
||||||
|
|
||||||
|
def is_friendly(self) -> bool:
|
||||||
|
"""
|
||||||
|
Is this entity a friendly entity?
|
||||||
|
"""
|
||||||
|
return isinstance(self, FriendlyEntity)
|
||||||
|
|
||||||
|
def is_merchant(self) -> bool:
|
||||||
|
"""
|
||||||
|
Is this entity a merchant?
|
||||||
|
"""
|
||||||
|
from squirrelbattle.entities.friendly import Merchant
|
||||||
|
return isinstance(self, Merchant)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def translated_name(self) -> str:
|
def translated_name(self) -> str:
|
||||||
return _(self.name.replace("_", " "))
|
return _(self.name.replace("_", " "))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_entity_classes():
|
def get_all_entity_classes() -> list:
|
||||||
"""
|
"""
|
||||||
Returns all entities subclasses
|
Returns all entities subclasses
|
||||||
"""
|
"""
|
||||||
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
|
||||||
return [BodySnatchPotion, Bomb, Heart, Hedgehog,
|
from squirrelbattle.entities.friendly import Merchant, Sunflower
|
||||||
Rabbit, TeddyBear, Tiger]
|
return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear,
|
||||||
|
Sunflower, Tiger, Merchant]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_entity_classes_in_a_dict() -> dict:
|
def get_all_entity_classes_in_a_dict() -> dict:
|
||||||
|
@ -482,7 +506,9 @@ 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
|
||||||
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart
|
from squirrelbattle.entities.friendly import Merchant, Sunflower
|
||||||
|
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, \
|
||||||
|
Heart, Sword
|
||||||
return {
|
return {
|
||||||
"Tiger": Tiger,
|
"Tiger": Tiger,
|
||||||
"Bomb": Bomb,
|
"Bomb": Bomb,
|
||||||
|
@ -492,6 +518,9 @@ class Entity:
|
||||||
"Rabbit": Rabbit,
|
"Rabbit": Rabbit,
|
||||||
"TeddyBear": TeddyBear,
|
"TeddyBear": TeddyBear,
|
||||||
"Player": Player,
|
"Player": Player,
|
||||||
|
"Merchant": Merchant,
|
||||||
|
"Sunflower": Sunflower,
|
||||||
|
"Sword": Sword,
|
||||||
}
|
}
|
||||||
|
|
||||||
def save_state(self) -> dict:
|
def save_state(self) -> dict:
|
||||||
|
@ -567,7 +596,7 @@ class FightingEntity(Entity):
|
||||||
|
|
||||||
def keys(self) -> list:
|
def keys(self) -> list:
|
||||||
"""
|
"""
|
||||||
Returns a fighting entities specific attributes
|
Returns a fighting entity's specific attributes
|
||||||
"""
|
"""
|
||||||
return ["name", "maxhealth", "health", "level", "strength",
|
return ["name", "maxhealth", "health", "level", "strength",
|
||||||
"intelligence", "charisma", "dexterity", "constitution"]
|
"intelligence", "charisma", "dexterity", "constitution"]
|
||||||
|
@ -580,3 +609,74 @@ class FightingEntity(Entity):
|
||||||
for name in self.keys():
|
for name in self.keys():
|
||||||
d[name] = getattr(self, name)
|
d[name] = getattr(self, name)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
class FriendlyEntity(FightingEntity):
|
||||||
|
"""
|
||||||
|
Friendly entities are living entities which do not attack the player
|
||||||
|
"""
|
||||||
|
dialogue_option: list
|
||||||
|
|
||||||
|
def talk_to(self, player: Any) -> str:
|
||||||
|
return _("{entity} said: {message}").format(
|
||||||
|
entity=self.translated_name.capitalize(),
|
||||||
|
message=choice(self.dialogue_option))
|
||||||
|
|
||||||
|
def keys(self) -> list:
|
||||||
|
"""
|
||||||
|
Returns a friendly entity's specific attributes
|
||||||
|
"""
|
||||||
|
return ["maxhealth", "health"]
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryHolder(Entity):
|
||||||
|
hazel: int # Currency of the game
|
||||||
|
inventory: list
|
||||||
|
|
||||||
|
def translate_inventory(self, inventory: list) -> list:
|
||||||
|
"""
|
||||||
|
Translate the JSON-state of the inventory into a list of the items in
|
||||||
|
the inventory.
|
||||||
|
"""
|
||||||
|
for i in range(len(inventory)):
|
||||||
|
if isinstance(inventory[i], dict):
|
||||||
|
inventory[i] = self.dict_to_inventory(inventory[i])
|
||||||
|
return inventory
|
||||||
|
|
||||||
|
def dict_to_inventory(self, item_dict: dict) -> Entity:
|
||||||
|
"""
|
||||||
|
Translate a dict object that contains the state of an item
|
||||||
|
into an item object.
|
||||||
|
"""
|
||||||
|
entity_classes = self.get_all_entity_classes_in_a_dict()
|
||||||
|
|
||||||
|
item_class = entity_classes[item_dict["type"]]
|
||||||
|
return item_class(**item_dict)
|
||||||
|
|
||||||
|
def save_state(self) -> dict:
|
||||||
|
"""
|
||||||
|
We save the inventory of the merchant formatted as JSON
|
||||||
|
"""
|
||||||
|
d = super().save_state()
|
||||||
|
d["hazel"] = self.hazel
|
||||||
|
d["inventory"] = [item.save_state() for item in self.inventory]
|
||||||
|
return d
|
||||||
|
|
||||||
|
def add_to_inventory(self, obj: Any) -> None:
|
||||||
|
"""
|
||||||
|
Adds an object to inventory
|
||||||
|
"""
|
||||||
|
self.inventory.append(obj)
|
||||||
|
|
||||||
|
def remove_from_inventory(self, obj: Any) -> None:
|
||||||
|
"""
|
||||||
|
Removes an object from the inventory
|
||||||
|
"""
|
||||||
|
self.inventory.remove(obj)
|
||||||
|
|
||||||
|
def change_hazel_balance(self, hz: int) -> None:
|
||||||
|
"""
|
||||||
|
Change the number of hazel the entity has by hz. hz is negative
|
||||||
|
when the player loses money and positive when he gains money
|
||||||
|
"""
|
||||||
|
self.hazel += hz
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
# German translation of Squirrel Battle
|
# SOME DESCRIPTIVE TITLE.
|
||||||
# Copyright (C) YEAR ÿnérant, eichhornchen, nicomarg, charlse
|
# Copyright (C) YEAR ÿnérant, eichhornchen, nicomarg, charlse, ifugao
|
||||||
# This file is distributed under the same license as the squirrelbattle package.
|
# This file is distributed under the same license as the squirrelbattle package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
|
#, fuzzy
|
||||||
msgid ""
|
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: 2020-12-05 14:46+0100\n"
|
"POT-Creation-Date: 2020-12-12 18:02+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"
|
||||||
|
@ -15,31 +17,52 @@ 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"
|
||||||
|
|
||||||
#: squirrelbattle/display/menudisplay.py:105
|
#: squirrelbattle/display/menudisplay.py:139
|
||||||
msgid "== INVENTORY =="
|
msgid "INVENTORY"
|
||||||
msgstr "== BESTAND =="
|
msgstr "BESTAND"
|
||||||
|
|
||||||
#: squirrelbattle/display/statsdisplay.py:34
|
#: squirrelbattle/display/menudisplay.py:164
|
||||||
|
msgid "STALL"
|
||||||
|
msgstr "STAND"
|
||||||
|
|
||||||
|
#: squirrelbattle/display/statsdisplay.py:33
|
||||||
msgid "Inventory:"
|
msgid "Inventory:"
|
||||||
msgstr "Bestand:"
|
msgstr "Bestand:"
|
||||||
|
|
||||||
#: squirrelbattle/display/statsdisplay.py:50
|
#: squirrelbattle/display/statsdisplay.py:52
|
||||||
msgid "YOU ARE DEAD"
|
msgid "YOU ARE DEAD"
|
||||||
msgstr "SIE WURDEN GESTORBEN"
|
msgstr "SIE WURDEN GESTORBEN"
|
||||||
|
|
||||||
|
#. TODO
|
||||||
|
#: squirrelbattle/entities/friendly.py:33
|
||||||
|
msgid "I don't sell any squirrel"
|
||||||
|
msgstr "Ich verkaufe keinen Eichhörnchen."
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:52
|
||||||
|
msgid "Flower power!!"
|
||||||
|
msgstr "Blumenmacht!!"
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:52
|
||||||
|
msgid "The sun is warm today"
|
||||||
|
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:128
|
#: squirrelbattle/entities/items.py:151
|
||||||
msgid "Bomb is exploding."
|
msgid "Bomb is exploding."
|
||||||
msgstr "Die Bombe explodiert."
|
msgstr "Die Bombe explodiert."
|
||||||
|
|
||||||
#: squirrelbattle/entities/items.py:172
|
#: squirrelbattle/entities/items.py:248
|
||||||
#, 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."
|
||||||
|
|
||||||
#: squirrelbattle/game.py:177
|
#: squirrelbattle/game.py:205 squirrelbattle/tests/game_test.py:573
|
||||||
|
msgid "You do not have enough money"
|
||||||
|
msgstr "Sie haben nicht genug Geld"
|
||||||
|
|
||||||
|
#: squirrelbattle/game.py:249
|
||||||
msgid ""
|
msgid ""
|
||||||
"Some keys are missing in your save file.\n"
|
"Some keys are missing in your save file.\n"
|
||||||
"Your save seems to be corrupt. It got deleted."
|
"Your save seems to be corrupt. It got deleted."
|
||||||
|
@ -47,7 +70,7 @@ msgstr ""
|
||||||
"In Ihrer Speicherdatei fehlen einige Schlüssel.\n"
|
"In Ihrer Speicherdatei fehlen einige Schlüssel.\n"
|
||||||
"Ihre Speicherung scheint korrupt zu sein. Es wird gelöscht."
|
"Ihre Speicherung scheint korrupt zu sein. Es wird gelöscht."
|
||||||
|
|
||||||
#: squirrelbattle/game.py:185
|
#: squirrelbattle/game.py:257
|
||||||
msgid ""
|
msgid ""
|
||||||
"No player was found on this map!\n"
|
"No player was found on this map!\n"
|
||||||
"Maybe you died?"
|
"Maybe you died?"
|
||||||
|
@ -55,7 +78,7 @@ msgstr ""
|
||||||
"Auf dieser Karte wurde kein Spieler gefunden!\n"
|
"Auf dieser Karte wurde kein Spieler gefunden!\n"
|
||||||
"Vielleicht sind Sie gestorben?"
|
"Vielleicht sind Sie gestorben?"
|
||||||
|
|
||||||
#: squirrelbattle/game.py:205
|
#: squirrelbattle/game.py:277
|
||||||
msgid ""
|
msgid ""
|
||||||
"The JSON file is not correct.\n"
|
"The JSON file is not correct.\n"
|
||||||
"Your save seems corrupted. It got deleted."
|
"Your save seems corrupted. It got deleted."
|
||||||
|
@ -63,27 +86,32 @@ 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:400
|
#: squirrelbattle/interfaces.py:429
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} hits {opponent}."
|
msgid "{name} hits {opponent}."
|
||||||
msgstr "{name} schlägt {opponent}."
|
msgstr "{name} schlägt {opponent}."
|
||||||
|
|
||||||
#: squirrelbattle/interfaces.py:412
|
#: squirrelbattle/interfaces.py:441
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} takes {amount} damage."
|
msgid "{name} takes {amount} damage."
|
||||||
msgstr "{name} nimmt {amount} Schadenspunkte."
|
msgstr "{name} nimmt {amount} Schadenspunkte."
|
||||||
|
|
||||||
#: squirrelbattle/interfaces.py:414
|
#: squirrelbattle/interfaces.py:443
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} dies."
|
msgid "{name} dies."
|
||||||
msgstr "{name} stirbt."
|
msgstr "{name} stirbt."
|
||||||
|
|
||||||
#: squirrelbattle/menus.py:72
|
#: squirrelbattle/interfaces.py:477
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{entity} said: {message}"
|
||||||
|
msgstr "{entity} hat gesagt: {message}"
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:73
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Zurück"
|
msgstr "Zurück"
|
||||||
|
|
||||||
#: squirrelbattle/tests/game_test.py:300 squirrelbattle/tests/game_test.py:303
|
#: squirrelbattle/tests/game_test.py:344 squirrelbattle/tests/game_test.py:347
|
||||||
#: squirrelbattle/tests/game_test.py:306
|
#: squirrelbattle/tests/game_test.py:350 squirrelbattle/tests/game_test.py:353
|
||||||
#: squirrelbattle/tests/translations_test.py:16
|
#: squirrelbattle/tests/translations_test.py:16
|
||||||
msgid "New game"
|
msgid "New game"
|
||||||
msgstr "Neu Spiel"
|
msgstr "Neu Spiel"
|
||||||
|
@ -161,41 +189,65 @@ msgid "Key used to drop an item in the inventory"
|
||||||
msgstr "Taste um eines Objekts im Bestand zu werfen"
|
msgstr "Taste um eines Objekts im Bestand zu werfen"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:53
|
#: squirrelbattle/tests/translations_test.py:53
|
||||||
|
msgid "Key used to talk to a friendly entity"
|
||||||
|
msgstr "Taste um mit einer friedlicher Entität zu sprechen"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:55
|
||||||
|
msgid "Key used to wait"
|
||||||
|
msgstr "Wartentaste"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:56
|
||||||
msgid "Texture pack"
|
msgid "Texture pack"
|
||||||
msgstr "Textur-Packung"
|
msgstr "Textur-Packung"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:54
|
#: squirrelbattle/tests/translations_test.py:57
|
||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Sprache"
|
msgstr "Sprache"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:57
|
#: squirrelbattle/tests/translations_test.py:60
|
||||||
msgid "player"
|
msgid "player"
|
||||||
msgstr "Spieler"
|
msgstr "Spieler"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:59
|
#: squirrelbattle/tests/translations_test.py:62
|
||||||
msgid "tiger"
|
|
||||||
msgstr "Tiger"
|
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:60
|
|
||||||
msgid "hedgehog"
|
msgid "hedgehog"
|
||||||
msgstr "Igel"
|
msgstr "Igel"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:61
|
#: squirrelbattle/tests/translations_test.py:63
|
||||||
|
msgid "merchant"
|
||||||
|
msgstr "Kaufmann"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:64
|
||||||
msgid "rabbit"
|
msgid "rabbit"
|
||||||
msgstr "Kanninchen"
|
msgstr "Kanninchen"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:62
|
#: squirrelbattle/tests/translations_test.py:65
|
||||||
|
msgid "sunflower"
|
||||||
|
msgstr "Sonnenblume"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:66
|
||||||
msgid "teddy bear"
|
msgid "teddy bear"
|
||||||
msgstr "Teddybär"
|
msgstr "Teddybär"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:64
|
#: squirrelbattle/tests/translations_test.py:67
|
||||||
|
msgid "tiger"
|
||||||
|
msgstr "Tiger"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:69
|
||||||
msgid "body snatch potion"
|
msgid "body snatch potion"
|
||||||
msgstr "Leichenfleddererzaubertrank"
|
msgstr "Leichenfleddererzaubertrank"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:65
|
#: squirrelbattle/tests/translations_test.py:70
|
||||||
msgid "bomb"
|
msgid "bomb"
|
||||||
msgstr "Bombe"
|
msgstr "Bombe"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:66
|
#: squirrelbattle/tests/translations_test.py:71
|
||||||
|
msgid "explosion"
|
||||||
|
msgstr "Explosion"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:72
|
||||||
msgid "heart"
|
msgid "heart"
|
||||||
msgstr "Herz"
|
msgstr "Herz"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:73
|
||||||
|
msgid "sword"
|
||||||
|
msgstr "schwert"
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# This file is distributed under the same license as the squirrelbattle package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: squirrelbattle 3.14.1\n"
|
||||||
|
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
|
||||||
|
"POT-Creation-Date: 2020-12-01 17:10+0100\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#: squirrelbattle/display/statsdisplay.py:34
|
||||||
|
msgid "Inventory:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/display/statsdisplay.py:39
|
||||||
|
msgid "YOU ARE DEAD"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/interfaces.py:394 squirrelbattle/interfaces.py:398
|
||||||
|
#: squirrelbattle/interfaces.py:408
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{name} hits {opponent}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/interfaces.py:405 squirrelbattle/interfaces.py:410
|
||||||
|
#: squirrelbattle/interfaces.py:420
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{name} takes {amount} damage."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:45 squirrelbattle/tests/translations_test.py:14
|
||||||
|
#: squirrelbattle/tests/game_test.py:284 squirrelbattle/tests/game_test.py:287
|
||||||
|
#: squirrelbattle/tests/translations_test.py:16
|
||||||
|
#: squirrelbattle/tests/game_test.py:290
|
||||||
|
msgid "New game"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:46 squirrelbattle/tests/translations_test.py:15
|
||||||
|
#: squirrelbattle/tests/translations_test.py:17
|
||||||
|
msgid "Resume"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:47 squirrelbattle/tests/translations_test.py:17
|
||||||
|
#: squirrelbattle/tests/translations_test.py:19
|
||||||
|
msgid "Save"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:48 squirrelbattle/tests/translations_test.py:16
|
||||||
|
#: squirrelbattle/tests/translations_test.py:18
|
||||||
|
msgid "Load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:49 squirrelbattle/tests/translations_test.py:18
|
||||||
|
#: squirrelbattle/tests/translations_test.py:20
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:50 squirrelbattle/tests/translations_test.py:19
|
||||||
|
#: squirrelbattle/tests/translations_test.py:21
|
||||||
|
msgid "Exit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:71
|
||||||
|
msgid "Back"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/game.py:147 squirrelbattle/game.py:148
|
||||||
|
msgid ""
|
||||||
|
"Some keys are missing in your save file.\n"
|
||||||
|
"Your save seems to be corrupt. It got deleted."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/game.py:155 squirrelbattle/game.py:156
|
||||||
|
msgid ""
|
||||||
|
"No player was found on this map!\n"
|
||||||
|
"Maybe you died?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/game.py:175 squirrelbattle/game.py:176
|
||||||
|
msgid ""
|
||||||
|
"The JSON file is not correct.\n"
|
||||||
|
"Your save seems corrupted. It got deleted."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:21 squirrelbattle/tests/translations_test.py:21
|
||||||
|
#: squirrelbattle/tests/translations_test.py:25
|
||||||
|
#: squirrelbattle/tests/translations_test.py:27
|
||||||
|
msgid "Main key to move up"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:22 squirrelbattle/tests/translations_test.py:23
|
||||||
|
#: squirrelbattle/tests/translations_test.py:27
|
||||||
|
#: squirrelbattle/tests/translations_test.py:29
|
||||||
|
msgid "Secondary key to move up"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:23 squirrelbattle/tests/translations_test.py:25
|
||||||
|
#: squirrelbattle/tests/translations_test.py:29
|
||||||
|
#: squirrelbattle/tests/translations_test.py:31
|
||||||
|
msgid "Main key to move down"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:24 squirrelbattle/tests/translations_test.py:27
|
||||||
|
#: squirrelbattle/tests/translations_test.py:31
|
||||||
|
#: squirrelbattle/tests/translations_test.py:33
|
||||||
|
msgid "Secondary key to move down"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:25 squirrelbattle/tests/translations_test.py:29
|
||||||
|
#: squirrelbattle/tests/translations_test.py:33
|
||||||
|
#: squirrelbattle/tests/translations_test.py:35
|
||||||
|
msgid "Main key to move left"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:26 squirrelbattle/tests/translations_test.py:31
|
||||||
|
#: squirrelbattle/tests/translations_test.py:35
|
||||||
|
#: squirrelbattle/tests/translations_test.py:37
|
||||||
|
msgid "Secondary key to move left"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:27 squirrelbattle/tests/translations_test.py:33
|
||||||
|
#: squirrelbattle/tests/translations_test.py:37
|
||||||
|
#: squirrelbattle/tests/translations_test.py:39
|
||||||
|
msgid "Main key to move right"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:29 squirrelbattle/tests/translations_test.py:35
|
||||||
|
#: squirrelbattle/tests/translations_test.py:39
|
||||||
|
#: squirrelbattle/tests/translations_test.py:41
|
||||||
|
msgid "Secondary key to move right"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:30 squirrelbattle/tests/translations_test.py:37
|
||||||
|
#: squirrelbattle/tests/translations_test.py:41
|
||||||
|
#: squirrelbattle/tests/translations_test.py:43
|
||||||
|
msgid "Key to validate a menu"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:31 squirrelbattle/tests/translations_test.py:39
|
||||||
|
#: squirrelbattle/tests/translations_test.py:43
|
||||||
|
#: squirrelbattle/tests/translations_test.py:45
|
||||||
|
msgid "Texture pack"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40
|
||||||
|
#: squirrelbattle/tests/translations_test.py:44
|
||||||
|
#: squirrelbattle/tests/translations_test.py:46
|
||||||
|
msgid "Language"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/interfaces.py:407 squirrelbattle/interfaces.py:412
|
||||||
|
#: squirrelbattle/interfaces.py:422
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{name} dies."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:47
|
||||||
|
#: squirrelbattle/tests/translations_test.py:49
|
||||||
|
msgid "player"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:49
|
||||||
|
#: squirrelbattle/tests/translations_test.py:51
|
||||||
|
msgid "tiger"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:50
|
||||||
|
#: squirrelbattle/tests/translations_test.py:52
|
||||||
|
msgid "hedgehog"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:51
|
||||||
|
#: squirrelbattle/tests/translations_test.py:53
|
||||||
|
msgid "rabbit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:52
|
||||||
|
#: squirrelbattle/tests/translations_test.py:54
|
||||||
|
msgid "teddy bear"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:54
|
||||||
|
#: squirrelbattle/tests/translations_test.py:56
|
||||||
|
msgid "bomb"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:55
|
||||||
|
#: squirrelbattle/tests/translations_test.py:57
|
||||||
|
msgid "heart"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:31
|
||||||
|
msgid "Flower power!!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:31
|
||||||
|
msgid "The sun is warm today"
|
||||||
|
msgstr ""
|
|
@ -1,49 +1,67 @@
|
||||||
# Spanish translation of Squirrel Battle
|
# SOME DESCRIPTIVE TITLE.
|
||||||
# Copyright (C) YEAR ÿnérant, eichhornchen, nicomarg, charlse
|
# Copyright (C) YEAR ÿnérant, eichhornchen, nicomarg, charlse, ifugao
|
||||||
# This file is distributed under the same license as the squirrelbattle package.
|
# This file is distributed under the same license as the squirrelbattle package.
|
||||||
# Translation by ifugaao
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
|
#, fuzzy
|
||||||
msgid ""
|
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: 2020-12-05 14:46+0100\n"
|
"POT-Creation-Date: 2020-12-12 18:02+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: ifugao\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"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"
|
||||||
|
|
||||||
# Suggested in Weblate: == INVENTORIO ==
|
#: squirrelbattle/display/menudisplay.py:139
|
||||||
#: squirrelbattle/display/menudisplay.py:105
|
msgid "INVENTORY"
|
||||||
msgid "== INVENTORY =="
|
msgstr "INVENTORIO"
|
||||||
msgstr "== INVENTORIO =="
|
|
||||||
|
|
||||||
# Suggested in Weblate: Inventorio :
|
#: squirrelbattle/display/menudisplay.py:164
|
||||||
#: squirrelbattle/display/statsdisplay.py:34
|
msgid "STALL"
|
||||||
|
msgstr "PUESTO"
|
||||||
|
|
||||||
|
#: squirrelbattle/display/statsdisplay.py:33
|
||||||
msgid "Inventory:"
|
msgid "Inventory:"
|
||||||
msgstr "Inventorio :"
|
msgstr "Inventorio :"
|
||||||
|
|
||||||
# Suggested in Weblate: ERES MUERTO
|
#: squirrelbattle/display/statsdisplay.py:52
|
||||||
#: squirrelbattle/display/statsdisplay.py:50
|
|
||||||
msgid "YOU ARE DEAD"
|
msgid "YOU ARE DEAD"
|
||||||
msgstr "ERES MUERTO"
|
msgstr "ERES MUERTO"
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:33
|
||||||
|
msgid "I don't sell any squirrel"
|
||||||
|
msgstr "No vendo ninguna ardilla"
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:52
|
||||||
|
msgid "Flower power!!"
|
||||||
|
msgstr "Poder de las flores!!"
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:52
|
||||||
|
msgid "The sun is warm today"
|
||||||
|
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:128
|
#: squirrelbattle/entities/items.py:151
|
||||||
msgid "Bomb is exploding."
|
msgid "Bomb is exploding."
|
||||||
msgstr "La bomba está explotando."
|
msgstr "La bomba está explotando."
|
||||||
|
|
||||||
#: squirrelbattle/entities/items.py:172
|
#: squirrelbattle/entities/items.py:248
|
||||||
#, 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}."
|
||||||
|
|
||||||
#: squirrelbattle/game.py:177
|
#: squirrelbattle/game.py:205 squirrelbattle/tests/game_test.py:573
|
||||||
|
msgid "You do not have enough money"
|
||||||
|
msgstr "No tienes suficiente dinero"
|
||||||
|
|
||||||
|
#: squirrelbattle/game.py:249
|
||||||
msgid ""
|
msgid ""
|
||||||
"Some keys are missing in your save file.\n"
|
"Some keys are missing in your save file.\n"
|
||||||
"Your save seems to be corrupt. It got deleted."
|
"Your save seems to be corrupt. It got deleted."
|
||||||
|
@ -51,7 +69,7 @@ msgstr ""
|
||||||
"Algunas claves faltan en su archivo de guarda.\n"
|
"Algunas claves faltan en su archivo de guarda.\n"
|
||||||
"Su guarda parece a ser corruptido. Fue eliminado."
|
"Su guarda parece a ser corruptido. Fue eliminado."
|
||||||
|
|
||||||
#: squirrelbattle/game.py:185
|
#: squirrelbattle/game.py:257
|
||||||
msgid ""
|
msgid ""
|
||||||
"No player was found on this map!\n"
|
"No player was found on this map!\n"
|
||||||
"Maybe you died?"
|
"Maybe you died?"
|
||||||
|
@ -59,7 +77,7 @@ msgstr ""
|
||||||
"No jugador encontrado sobre la carta !\n"
|
"No jugador encontrado sobre la carta !\n"
|
||||||
"¿ Quizas murió ?"
|
"¿ Quizas murió ?"
|
||||||
|
|
||||||
#: squirrelbattle/game.py:205
|
#: squirrelbattle/game.py:277
|
||||||
msgid ""
|
msgid ""
|
||||||
"The JSON file is not correct.\n"
|
"The JSON file is not correct.\n"
|
||||||
"Your save seems corrupted. It got deleted."
|
"Your save seems corrupted. It got deleted."
|
||||||
|
@ -67,28 +85,32 @@ 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:400
|
#: squirrelbattle/interfaces.py:429
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} hits {opponent}."
|
msgid "{name} hits {opponent}."
|
||||||
msgstr "{name} golpea a {opponent}."
|
msgstr "{name} golpea a {opponent}."
|
||||||
|
|
||||||
#: squirrelbattle/interfaces.py:412
|
#: squirrelbattle/interfaces.py:441
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} takes {amount} damage."
|
msgid "{name} takes {amount} damage."
|
||||||
msgstr "{name} recibe {amount} daño."
|
msgstr "{name} recibe {amount} daño."
|
||||||
|
|
||||||
#: squirrelbattle/interfaces.py:414
|
#: squirrelbattle/interfaces.py:443
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} dies."
|
msgid "{name} dies."
|
||||||
msgstr "{name} se muere."
|
msgstr "{name} se muere."
|
||||||
|
|
||||||
#: squirrelbattle/menus.py:72
|
#: squirrelbattle/interfaces.py:477
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{entity} said: {message}"
|
||||||
|
msgstr "{entity} dijo : {message}"
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:73
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Volver"
|
msgstr "Volver"
|
||||||
|
|
||||||
#: squirrelbattle/tests/game_test.py:300,
|
#: squirrelbattle/tests/game_test.py:344 squirrelbattle/tests/game_test.py:347
|
||||||
#: squirrelbattle/tests/game_test.py:303,
|
#: squirrelbattle/tests/game_test.py:350 squirrelbattle/tests/game_test.py:353
|
||||||
#: squirrelbattle/tests/game_test.py:306,
|
|
||||||
#: squirrelbattle/tests/translations_test.py:16
|
#: squirrelbattle/tests/translations_test.py:16
|
||||||
msgid "New game"
|
msgid "New game"
|
||||||
msgstr "Nuevo partido"
|
msgstr "Nuevo partido"
|
||||||
|
@ -166,41 +188,65 @@ msgid "Key used to drop an item in the inventory"
|
||||||
msgstr "Tecla para dejar un objeto del inventorio"
|
msgstr "Tecla para dejar un objeto del inventorio"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:53
|
#: squirrelbattle/tests/translations_test.py:53
|
||||||
|
msgid "Key used to talk to a friendly entity"
|
||||||
|
msgstr "Tecla para hablar con una entidad amiga"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:55
|
||||||
|
msgid "Key used to wait"
|
||||||
|
msgstr "Tecla para espera"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:56
|
||||||
msgid "Texture pack"
|
msgid "Texture pack"
|
||||||
msgstr "Paquete de texturas"
|
msgstr "Paquete de texturas"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:54
|
#: squirrelbattle/tests/translations_test.py:57
|
||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Languaje"
|
msgstr "Languaje"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:57
|
#: squirrelbattle/tests/translations_test.py:60
|
||||||
msgid "player"
|
msgid "player"
|
||||||
msgstr "jugador"
|
msgstr "jugador"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:59
|
#: squirrelbattle/tests/translations_test.py:62
|
||||||
msgid "tiger"
|
|
||||||
msgstr "tigre"
|
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:60
|
|
||||||
msgid "hedgehog"
|
msgid "hedgehog"
|
||||||
msgstr "erizo"
|
msgstr "erizo"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:61
|
#: squirrelbattle/tests/translations_test.py:63
|
||||||
|
msgid "merchant"
|
||||||
|
msgstr "comerciante"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:64
|
||||||
msgid "rabbit"
|
msgid "rabbit"
|
||||||
msgstr "conejo"
|
msgstr "conejo"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:62
|
#: squirrelbattle/tests/translations_test.py:65
|
||||||
|
msgid "sunflower"
|
||||||
|
msgstr "girasol"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:66
|
||||||
msgid "teddy bear"
|
msgid "teddy bear"
|
||||||
msgstr "osito de peluche"
|
msgstr "osito de peluche"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:64
|
#: squirrelbattle/tests/translations_test.py:67
|
||||||
|
msgid "tiger"
|
||||||
|
msgstr "tigre"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:69
|
||||||
msgid "body snatch potion"
|
msgid "body snatch potion"
|
||||||
msgstr "poción de intercambio"
|
msgstr "poción de intercambio"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:65
|
#: squirrelbattle/tests/translations_test.py:70
|
||||||
msgid "bomb"
|
msgid "bomb"
|
||||||
msgstr "bomba"
|
msgstr "bomba"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:66
|
#: squirrelbattle/tests/translations_test.py:71
|
||||||
|
msgid "explosion"
|
||||||
|
msgstr "explosión"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:72
|
||||||
msgid "heart"
|
msgid "heart"
|
||||||
msgstr "corazón"
|
msgstr "corazón"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:73
|
||||||
|
msgid "sword"
|
||||||
|
msgstr "espada"
|
||||||
|
|
|
@ -1,46 +1,68 @@
|
||||||
# French translation of Squirrel Battle
|
# SOME DESCRIPTIVE TITLE.
|
||||||
# Copyright (C) YEAR ÿnérant, eichhornchen, nicomarg, charlse
|
# Copyright (C) YEAR ÿnérant, eichhornchen, nicomarg, charlse, ifugao
|
||||||
# This file is distributed under the same license as the squirrelbattle package.
|
# This file is distributed under the same license as the squirrelbattle package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
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: 2020-12-05 14:46+0100\n"
|
"POT-Creation-Date: 2020-12-12 18:02+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"
|
||||||
"Language: fr\n"
|
"Language: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"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"
|
||||||
|
|
||||||
#: squirrelbattle/display/menudisplay.py:105
|
#: squirrelbattle/display/menudisplay.py:139
|
||||||
msgid "== INVENTORY =="
|
msgid "INVENTORY"
|
||||||
msgstr "== INVENTAIRE =="
|
msgstr "INVENTAIRE"
|
||||||
|
|
||||||
#: squirrelbattle/display/statsdisplay.py:34
|
#: squirrelbattle/display/menudisplay.py:164
|
||||||
|
msgid "STALL"
|
||||||
|
msgstr "STAND"
|
||||||
|
|
||||||
|
#: squirrelbattle/display/statsdisplay.py:33
|
||||||
msgid "Inventory:"
|
msgid "Inventory:"
|
||||||
msgstr "Inventaire :"
|
msgstr "Inventaire :"
|
||||||
|
|
||||||
#: squirrelbattle/display/statsdisplay.py:50
|
#: squirrelbattle/display/statsdisplay.py:52
|
||||||
msgid "YOU ARE DEAD"
|
msgid "YOU ARE DEAD"
|
||||||
msgstr "VOUS ÊTES MORT"
|
msgstr "VOUS ÊTES MORT"
|
||||||
|
|
||||||
|
#. TODO
|
||||||
|
#: squirrelbattle/entities/friendly.py:33
|
||||||
|
msgid "I don't sell any squirrel"
|
||||||
|
msgstr "Je ne vends pas d'écureuil"
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:52
|
||||||
|
msgid "Flower power!!"
|
||||||
|
msgstr "Pouvoir des fleurs !!"
|
||||||
|
|
||||||
|
#: squirrelbattle/entities/friendly.py:52
|
||||||
|
msgid "The sun is warm today"
|
||||||
|
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:128
|
#: squirrelbattle/entities/items.py:151
|
||||||
msgid "Bomb is exploding."
|
msgid "Bomb is exploding."
|
||||||
msgstr "La bombe explose."
|
msgstr "La bombe explose."
|
||||||
|
|
||||||
#: squirrelbattle/entities/items.py:172
|
#: squirrelbattle/entities/items.py:248
|
||||||
#, 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}."
|
||||||
|
|
||||||
#: squirrelbattle/game.py:177
|
#: squirrelbattle/game.py:205 squirrelbattle/tests/game_test.py:573
|
||||||
|
msgid "You do not have enough money"
|
||||||
|
msgstr "Vous n'avez pas assez d'argent"
|
||||||
|
|
||||||
|
#: squirrelbattle/game.py:249
|
||||||
msgid ""
|
msgid ""
|
||||||
"Some keys are missing in your save file.\n"
|
"Some keys are missing in your save file.\n"
|
||||||
"Your save seems to be corrupt. It got deleted."
|
"Your save seems to be corrupt. It got deleted."
|
||||||
|
@ -48,7 +70,7 @@ msgstr ""
|
||||||
"Certaines clés de votre ficher de sauvegarde sont manquantes.\n"
|
"Certaines clés de votre ficher de sauvegarde sont manquantes.\n"
|
||||||
"Votre sauvegarde semble corrompue. Elle a été supprimée."
|
"Votre sauvegarde semble corrompue. Elle a été supprimée."
|
||||||
|
|
||||||
#: squirrelbattle/game.py:185
|
#: squirrelbattle/game.py:257
|
||||||
msgid ""
|
msgid ""
|
||||||
"No player was found on this map!\n"
|
"No player was found on this map!\n"
|
||||||
"Maybe you died?"
|
"Maybe you died?"
|
||||||
|
@ -56,7 +78,7 @@ msgstr ""
|
||||||
"Aucun joueur n'a été trouvé sur la carte !\n"
|
"Aucun joueur n'a été trouvé sur la carte !\n"
|
||||||
"Peut-être êtes-vous mort ?"
|
"Peut-être êtes-vous mort ?"
|
||||||
|
|
||||||
#: squirrelbattle/game.py:205
|
#: squirrelbattle/game.py:277
|
||||||
msgid ""
|
msgid ""
|
||||||
"The JSON file is not correct.\n"
|
"The JSON file is not correct.\n"
|
||||||
"Your save seems corrupted. It got deleted."
|
"Your save seems corrupted. It got deleted."
|
||||||
|
@ -64,27 +86,32 @@ 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:400
|
#: squirrelbattle/interfaces.py:429
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} hits {opponent}."
|
msgid "{name} hits {opponent}."
|
||||||
msgstr "{name} frappe {opponent}."
|
msgstr "{name} frappe {opponent}."
|
||||||
|
|
||||||
#: squirrelbattle/interfaces.py:412
|
#: squirrelbattle/interfaces.py:441
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} takes {amount} damage."
|
msgid "{name} takes {amount} damage."
|
||||||
msgstr "{name} prend {amount} points de dégât."
|
msgstr "{name} prend {amount} points de dégât."
|
||||||
|
|
||||||
#: squirrelbattle/interfaces.py:414
|
#: squirrelbattle/interfaces.py:443
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} dies."
|
msgid "{name} dies."
|
||||||
msgstr "{name} meurt."
|
msgstr "{name} meurt."
|
||||||
|
|
||||||
#: squirrelbattle/menus.py:72
|
#: squirrelbattle/interfaces.py:477
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "{entity} said: {message}"
|
||||||
|
msgstr "{entity} a dit : {message}"
|
||||||
|
|
||||||
|
#: squirrelbattle/menus.py:73
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Retour"
|
msgstr "Retour"
|
||||||
|
|
||||||
#: squirrelbattle/tests/game_test.py:300 squirrelbattle/tests/game_test.py:303
|
#: squirrelbattle/tests/game_test.py:344 squirrelbattle/tests/game_test.py:347
|
||||||
#: squirrelbattle/tests/game_test.py:306
|
#: squirrelbattle/tests/game_test.py:350 squirrelbattle/tests/game_test.py:353
|
||||||
#: squirrelbattle/tests/translations_test.py:16
|
#: squirrelbattle/tests/translations_test.py:16
|
||||||
msgid "New game"
|
msgid "New game"
|
||||||
msgstr "Nouvelle partie"
|
msgstr "Nouvelle partie"
|
||||||
|
@ -162,41 +189,65 @@ msgid "Key used to drop an item in the inventory"
|
||||||
msgstr "Touche pour jeter un objet de l'inventaire"
|
msgstr "Touche pour jeter un objet de l'inventaire"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:53
|
#: squirrelbattle/tests/translations_test.py:53
|
||||||
|
msgid "Key used to talk to a friendly entity"
|
||||||
|
msgstr "Touche pour parler à une entité pacifique"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:55
|
||||||
|
msgid "Key used to wait"
|
||||||
|
msgstr "Touche pour attendre"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:56
|
||||||
msgid "Texture pack"
|
msgid "Texture pack"
|
||||||
msgstr "Pack de textures"
|
msgstr "Pack de textures"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:54
|
#: squirrelbattle/tests/translations_test.py:57
|
||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Langue"
|
msgstr "Langue"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:57
|
#: squirrelbattle/tests/translations_test.py:60
|
||||||
msgid "player"
|
msgid "player"
|
||||||
msgstr "joueur"
|
msgstr "joueur"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:59
|
#: squirrelbattle/tests/translations_test.py:62
|
||||||
msgid "tiger"
|
|
||||||
msgstr "tigre"
|
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:60
|
|
||||||
msgid "hedgehog"
|
msgid "hedgehog"
|
||||||
msgstr "hérisson"
|
msgstr "hérisson"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:61
|
#: squirrelbattle/tests/translations_test.py:63
|
||||||
|
msgid "merchant"
|
||||||
|
msgstr "marchand"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:64
|
||||||
msgid "rabbit"
|
msgid "rabbit"
|
||||||
msgstr "lapin"
|
msgstr "lapin"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:62
|
#: squirrelbattle/tests/translations_test.py:65
|
||||||
|
msgid "sunflower"
|
||||||
|
msgstr "tournesol"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:66
|
||||||
msgid "teddy bear"
|
msgid "teddy bear"
|
||||||
msgstr "nounours"
|
msgstr "nounours"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:64
|
#: squirrelbattle/tests/translations_test.py:67
|
||||||
|
msgid "tiger"
|
||||||
|
msgstr "tigre"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:69
|
||||||
msgid "body snatch potion"
|
msgid "body snatch potion"
|
||||||
msgstr "potion d'arrachage de corps"
|
msgstr "potion d'arrachage de corps"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:65
|
#: squirrelbattle/tests/translations_test.py:70
|
||||||
msgid "bomb"
|
msgid "bomb"
|
||||||
msgstr "bombe"
|
msgstr "bombe"
|
||||||
|
|
||||||
#: squirrelbattle/tests/translations_test.py:66
|
#: squirrelbattle/tests/translations_test.py:71
|
||||||
|
msgid "explosion"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:72
|
||||||
msgid "heart"
|
msgid "heart"
|
||||||
msgstr "cœur"
|
msgstr "cœur"
|
||||||
|
|
||||||
|
#: squirrelbattle/tests/translations_test.py:73
|
||||||
|
msgid "sword"
|
||||||
|
msgstr "épée"
|
||||||
|
|
|
@ -6,6 +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 .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
|
||||||
|
@ -128,3 +129,14 @@ class InventoryMenu(Menu):
|
||||||
@property
|
@property
|
||||||
def values(self) -> list:
|
def values(self) -> list:
|
||||||
return self.player.inventory
|
return self.player.inventory
|
||||||
|
|
||||||
|
|
||||||
|
class StoreMenu(Menu):
|
||||||
|
merchant: Merchant
|
||||||
|
|
||||||
|
def update_merchant(self, merchant: Merchant) -> None:
|
||||||
|
self.merchant = merchant
|
||||||
|
|
||||||
|
@property
|
||||||
|
def values(self) -> list:
|
||||||
|
return self.merchant.inventory
|
||||||
|
|
|
@ -31,6 +31,8 @@ class Settings:
|
||||||
self.KEY_USE = ['u', 'Key used to use an item in the inventory']
|
self.KEY_USE = ['u', 'Key used to use an item in the inventory']
|
||||||
self.KEY_EQUIP = ['e', 'Key used to equip an item in the inventory']
|
self.KEY_EQUIP = ['e', 'Key used to equip an item in the inventory']
|
||||||
self.KEY_DROP = ['r', 'Key used to drop an item in the inventory']
|
self.KEY_DROP = ['r', 'Key used to drop an item in the inventory']
|
||||||
|
self.KEY_CHAT = ['t', 'Key used to talk to a friendly entity']
|
||||||
|
self.KEY_WAIT = ['w', 'Key used to wait']
|
||||||
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']
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ class TermManager: # pragma: no cover
|
||||||
curses.cbreak()
|
curses.cbreak()
|
||||||
# make cursor invisible
|
# make cursor invisible
|
||||||
curses.curs_set(False)
|
curses.curs_set(False)
|
||||||
|
# Catch mouse events
|
||||||
|
curses.mousemask(True)
|
||||||
# Enable colors
|
# Enable colors
|
||||||
curses.start_color()
|
curses.start_color()
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart, Item
|
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart, Item, \
|
||||||
|
Explosion
|
||||||
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, TeddyBear
|
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, TeddyBear
|
||||||
from squirrelbattle.entities.player import Player
|
from squirrelbattle.entities.player import Player
|
||||||
from squirrelbattle.interfaces import Entity, Map
|
from squirrelbattle.interfaces import Entity, Map
|
||||||
|
@ -138,6 +139,20 @@ class TestEntities(unittest.TestCase):
|
||||||
self.assertTrue(teddy_bear.dead)
|
self.assertTrue(teddy_bear.dead)
|
||||||
bomb_state = item.save_state()
|
bomb_state = item.save_state()
|
||||||
self.assertEqual(bomb_state["damage"], item.damage)
|
self.assertEqual(bomb_state["damage"], item.damage)
|
||||||
|
explosions = self.map.find_entities(Explosion)
|
||||||
|
self.assertTrue(explosions)
|
||||||
|
explosion = explosions[0]
|
||||||
|
self.assertEqual(explosion.y, item.y)
|
||||||
|
self.assertEqual(explosion.x, item.x)
|
||||||
|
|
||||||
|
# The player can't hold the explosion
|
||||||
|
explosion.hold(self.player)
|
||||||
|
self.assertNotIn(explosion, self.player.inventory)
|
||||||
|
self.assertFalse(explosion.held)
|
||||||
|
|
||||||
|
# The explosion disappears after one tick
|
||||||
|
explosion.act(self.map)
|
||||||
|
self.assertNotIn(explosion, self.map.entities)
|
||||||
|
|
||||||
def test_hearts(self) -> None:
|
def test_hearts(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,7 +7,8 @@ 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.items import Bomb
|
from ..entities.friendly import Merchant, Sunflower
|
||||||
|
from ..entities.items import Bomb, Heart, Sword, Explosion
|
||||||
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
|
||||||
|
@ -34,7 +35,17 @@ class TestGame(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
bomb = Bomb()
|
bomb = Bomb()
|
||||||
self.game.map.add_entity(bomb)
|
self.game.map.add_entity(bomb)
|
||||||
|
sword = Sword()
|
||||||
|
self.game.map.add_entity(sword)
|
||||||
|
# Add items in the inventory to check that it is well loaded
|
||||||
bomb.hold(self.game.player)
|
bomb.hold(self.game.player)
|
||||||
|
sword.hold(self.game.player)
|
||||||
|
|
||||||
|
# Ensure that merchants can be saved
|
||||||
|
merchant = Merchant()
|
||||||
|
merchant.move(3, 6)
|
||||||
|
self.game.map.add_entity(merchant)
|
||||||
|
|
||||||
old_state = self.game.save_state()
|
old_state = self.game.save_state()
|
||||||
|
|
||||||
self.game.handle_key_pressed(KeyValues.DOWN)
|
self.game.handle_key_pressed(KeyValues.DOWN)
|
||||||
|
@ -117,6 +128,9 @@ class TestGame(unittest.TestCase):
|
||||||
self.assertEqual(KeyValues.translate_key(
|
self.assertEqual(KeyValues.translate_key(
|
||||||
self.game.settings.KEY_INVENTORY, self.game.settings),
|
self.game.settings.KEY_INVENTORY, self.game.settings),
|
||||||
KeyValues.INVENTORY)
|
KeyValues.INVENTORY)
|
||||||
|
self.assertEqual(KeyValues.translate_key(
|
||||||
|
self.game.settings.KEY_CHAT, self.game.settings),
|
||||||
|
KeyValues.CHAT)
|
||||||
self.assertEqual(KeyValues.translate_key(
|
self.assertEqual(KeyValues.translate_key(
|
||||||
self.game.settings.KEY_USE, self.game.settings),
|
self.game.settings.KEY_USE, self.game.settings),
|
||||||
KeyValues.USE)
|
KeyValues.USE)
|
||||||
|
@ -126,6 +140,9 @@ class TestGame(unittest.TestCase):
|
||||||
self.assertEqual(KeyValues.translate_key(
|
self.assertEqual(KeyValues.translate_key(
|
||||||
self.game.settings.KEY_DROP, self.game.settings),
|
self.game.settings.KEY_DROP, self.game.settings),
|
||||||
KeyValues.DROP)
|
KeyValues.DROP)
|
||||||
|
self.assertEqual(KeyValues.translate_key(
|
||||||
|
self.game.settings.KEY_WAIT, self.game.settings),
|
||||||
|
KeyValues.WAIT)
|
||||||
self.assertEqual(KeyValues.translate_key(' ', self.game.settings),
|
self.assertEqual(KeyValues.translate_key(' ', self.game.settings),
|
||||||
KeyValues.SPACE)
|
KeyValues.SPACE)
|
||||||
self.assertEqual(KeyValues.translate_key('plop', self.game.settings),
|
self.assertEqual(KeyValues.translate_key('plop', self.game.settings),
|
||||||
|
@ -213,9 +230,45 @@ class TestGame(unittest.TestCase):
|
||||||
self.assertEqual(new_y, y)
|
self.assertEqual(new_y, y)
|
||||||
self.assertEqual(new_x, x - 1)
|
self.assertEqual(new_x, x - 1)
|
||||||
|
|
||||||
|
explosion = Explosion()
|
||||||
|
self.game.map.add_entity(explosion)
|
||||||
|
self.assertIn(explosion, self.game.map.entities)
|
||||||
|
self.game.handle_key_pressed(KeyValues.WAIT)
|
||||||
|
self.assertNotIn(explosion, self.game.map.entities)
|
||||||
|
|
||||||
self.game.handle_key_pressed(KeyValues.SPACE)
|
self.game.handle_key_pressed(KeyValues.SPACE)
|
||||||
self.assertEqual(self.game.state, GameMode.MAINMENU)
|
self.assertEqual(self.game.state, GameMode.MAINMENU)
|
||||||
|
|
||||||
|
def test_mouse_click(self) -> None:
|
||||||
|
"""
|
||||||
|
Simulate mouse clicks.
|
||||||
|
"""
|
||||||
|
self.game.state = GameMode.MAINMENU
|
||||||
|
|
||||||
|
# Change the color of the artwork
|
||||||
|
self.game.display_actions(DisplayActions.MOUSE, 0, 10)
|
||||||
|
|
||||||
|
# Settings menu
|
||||||
|
self.game.display_actions(DisplayActions.MOUSE, 25, 21)
|
||||||
|
self.assertEqual(self.game.main_menu.position, 4)
|
||||||
|
self.assertEqual(self.game.state, GameMode.SETTINGS)
|
||||||
|
|
||||||
|
bomb = Bomb()
|
||||||
|
bomb.hold(self.game.player)
|
||||||
|
bomb2 = Bomb()
|
||||||
|
bomb2.hold(self.game.player)
|
||||||
|
|
||||||
|
self.game.state = GameMode.INVENTORY
|
||||||
|
|
||||||
|
# Click nowhere
|
||||||
|
self.game.display_actions(DisplayActions.MOUSE, 0, 0)
|
||||||
|
self.assertEqual(self.game.state, GameMode.INVENTORY)
|
||||||
|
|
||||||
|
# Click on the second item
|
||||||
|
self.game.display_actions(DisplayActions.MOUSE, 8, 25)
|
||||||
|
self.assertEqual(self.game.state, GameMode.INVENTORY)
|
||||||
|
self.assertEqual(self.game.inventory_menu.position, 1)
|
||||||
|
|
||||||
def test_new_game(self) -> None:
|
def test_new_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure that the start button starts a new game.
|
Ensure that the start button starts a new game.
|
||||||
|
@ -253,13 +306,13 @@ class TestGame(unittest.TestCase):
|
||||||
self.game.handle_key_pressed(KeyValues.ENTER)
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
self.assertEqual(self.game.state, GameMode.SETTINGS)
|
self.assertEqual(self.game.state, GameMode.SETTINGS)
|
||||||
|
|
||||||
# Define the "move up" key to 'w'
|
# Define the "move up" key to 'h'
|
||||||
self.assertFalse(self.game.settings_menu.waiting_for_key)
|
self.assertFalse(self.game.settings_menu.waiting_for_key)
|
||||||
self.game.handle_key_pressed(KeyValues.ENTER)
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
self.assertTrue(self.game.settings_menu.waiting_for_key)
|
self.assertTrue(self.game.settings_menu.waiting_for_key)
|
||||||
self.game.handle_key_pressed(None, 'w')
|
self.game.handle_key_pressed(None, 'h')
|
||||||
self.assertFalse(self.game.settings_menu.waiting_for_key)
|
self.assertFalse(self.game.settings_menu.waiting_for_key)
|
||||||
self.assertEqual(self.game.settings.KEY_UP_PRIMARY, 'w')
|
self.assertEqual(self.game.settings.KEY_UP_PRIMARY, 'h')
|
||||||
|
|
||||||
# Navigate to "move left"
|
# Navigate to "move left"
|
||||||
self.game.handle_key_pressed(KeyValues.DOWN)
|
self.game.handle_key_pressed(KeyValues.DOWN)
|
||||||
|
@ -280,7 +333,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(9):
|
for ignored in range(11):
|
||||||
self.game.handle_key_pressed(KeyValues.DOWN)
|
self.game.handle_key_pressed(KeyValues.DOWN)
|
||||||
|
|
||||||
# Change texture pack
|
# Change texture pack
|
||||||
|
@ -417,3 +470,118 @@ class TestGame(unittest.TestCase):
|
||||||
self.assertTrue(bomb.exploding)
|
self.assertTrue(bomb.exploding)
|
||||||
self.assertEqual(bomb.y, self.game.player.y)
|
self.assertEqual(bomb.y, self.game.player.y)
|
||||||
self.assertEqual(bomb.x, self.game.player.x)
|
self.assertEqual(bomb.x, self.game.player.x)
|
||||||
|
|
||||||
|
def test_talk_to_sunflowers(self) -> None:
|
||||||
|
"""
|
||||||
|
Interact with sunflowers
|
||||||
|
"""
|
||||||
|
self.game.state = GameMode.PLAY
|
||||||
|
|
||||||
|
sunflower = Sunflower()
|
||||||
|
sunflower.move(2, 6)
|
||||||
|
self.game.map.add_entity(sunflower)
|
||||||
|
|
||||||
|
# Does nothing
|
||||||
|
self.assertIsNone(self.game.handle_friendly_entity_chat(KeyValues.UP))
|
||||||
|
|
||||||
|
# Talk to sunflower... or not
|
||||||
|
self.game.handle_key_pressed(KeyValues.CHAT)
|
||||||
|
self.assertTrue(self.game.waiting_for_friendly_key)
|
||||||
|
# Wrong key
|
||||||
|
self.game.handle_key_pressed(KeyValues.EQUIP)
|
||||||
|
self.assertFalse(self.game.waiting_for_friendly_key)
|
||||||
|
self.game.handle_key_pressed(KeyValues.CHAT)
|
||||||
|
self.assertTrue(self.game.waiting_for_friendly_key)
|
||||||
|
self.game.handle_key_pressed(KeyValues.UP)
|
||||||
|
self.assertFalse(self.game.waiting_for_friendly_key)
|
||||||
|
self.assertEqual(self.game.state, GameMode.PLAY)
|
||||||
|
self.assertFalse(len(self.game.logs.messages) > 1)
|
||||||
|
|
||||||
|
# Talk to sunflower
|
||||||
|
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.PLAY)
|
||||||
|
self.assertTrue(self.game.logs.messages)
|
||||||
|
# Ensure that the message is a good message
|
||||||
|
self.assertTrue(any(self.game.logs.messages[1].endswith(msg)
|
||||||
|
for msg in Sunflower().dialogue_option))
|
||||||
|
|
||||||
|
# Test all directions to detect the friendly entity
|
||||||
|
self.game.player.move(3, 6)
|
||||||
|
self.game.handle_key_pressed(KeyValues.CHAT)
|
||||||
|
self.game.handle_key_pressed(KeyValues.UP)
|
||||||
|
self.assertEqual(len(self.game.logs.messages), 3)
|
||||||
|
self.game.player.move(2, 7)
|
||||||
|
self.game.handle_key_pressed(KeyValues.CHAT)
|
||||||
|
self.game.handle_key_pressed(KeyValues.LEFT)
|
||||||
|
self.assertEqual(len(self.game.logs.messages), 4)
|
||||||
|
self.game.player.move(2, 5)
|
||||||
|
self.game.handle_key_pressed(KeyValues.CHAT)
|
||||||
|
self.game.handle_key_pressed(KeyValues.RIGHT)
|
||||||
|
self.assertEqual(len(self.game.logs.messages), 5)
|
||||||
|
|
||||||
|
def test_talk_to_merchant(self) -> None:
|
||||||
|
"""
|
||||||
|
Interact with merchants
|
||||||
|
"""
|
||||||
|
self.game.state = GameMode.PLAY
|
||||||
|
|
||||||
|
merchant = Merchant()
|
||||||
|
merchant.move(2, 6)
|
||||||
|
self.game.map.add_entity(merchant)
|
||||||
|
|
||||||
|
# Does nothing
|
||||||
|
self.assertIsNone(self.game.handle_friendly_entity_chat(KeyValues.UP))
|
||||||
|
|
||||||
|
# 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.STORE)
|
||||||
|
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.UP)
|
||||||
|
self.assertEqual(self.game.store_menu.position, 1)
|
||||||
|
|
||||||
|
self.game.player.hazel = 0x7ffff42ff
|
||||||
|
|
||||||
|
# The second item is not a heart
|
||||||
|
merchant.inventory[1] = Sword()
|
||||||
|
# Buy the second item by clicking on it
|
||||||
|
item = self.game.store_menu.validate()
|
||||||
|
self.assertIn(item, merchant.inventory)
|
||||||
|
self.game.display_actions(DisplayActions.MOUSE, 7, 25)
|
||||||
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
self.assertIn(item, self.game.player.inventory)
|
||||||
|
self.assertNotIn(item, merchant.inventory)
|
||||||
|
|
||||||
|
# Buy a heart
|
||||||
|
merchant.inventory[1] = Heart()
|
||||||
|
item = self.game.store_menu.validate()
|
||||||
|
self.assertIn(item, merchant.inventory)
|
||||||
|
self.assertEqual(item, merchant.inventory[1])
|
||||||
|
self.game.player.health = self.game.player.maxhealth - 1 - item.healing
|
||||||
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
self.assertNotIn(item, self.game.player.inventory)
|
||||||
|
self.assertNotIn(item, merchant.inventory)
|
||||||
|
self.assertEqual(self.game.player.health,
|
||||||
|
self.game.player.maxhealth - 1)
|
||||||
|
|
||||||
|
# We don't have enough of money
|
||||||
|
self.game.player.hazel = 0
|
||||||
|
item = self.game.store_menu.validate()
|
||||||
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
self.assertNotIn(item, self.game.player.inventory)
|
||||||
|
self.assertIn(item, merchant.inventory)
|
||||||
|
self.assertEqual(self.game.message, _("You do not have enough money"))
|
||||||
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
|
|
||||||
|
# Exit the menu
|
||||||
|
self.game.handle_key_pressed(KeyValues.SPACE)
|
||||||
|
self.assertEqual(self.game.state, GameMode.PLAY)
|
||||||
|
|
|
@ -50,17 +50,24 @@ class TestTranslations(unittest.TestCase):
|
||||||
"Touche pour équiper un objet de l'inventaire")
|
"Touche pour équiper un objet de l'inventaire")
|
||||||
self.assertEqual(_("Key used to drop an item in the inventory"),
|
self.assertEqual(_("Key used to drop an item in the inventory"),
|
||||||
"Touche pour jeter un objet de l'inventaire")
|
"Touche pour jeter un objet de l'inventaire")
|
||||||
|
self.assertEqual(_("Key used to talk to a friendly entity"),
|
||||||
|
"Touche pour parler à une entité pacifique")
|
||||||
|
self.assertEqual(_("Key used to wait"), "Touche pour attendre")
|
||||||
self.assertEqual(_("Texture pack"), "Pack de textures")
|
self.assertEqual(_("Texture pack"), "Pack de textures")
|
||||||
self.assertEqual(_("Language"), "Langue")
|
self.assertEqual(_("Language"), "Langue")
|
||||||
|
|
||||||
def test_entities_translation(self) -> None:
|
def test_entities_translation(self) -> None:
|
||||||
self.assertEqual(_("player"), "joueur")
|
self.assertEqual(_("player"), "joueur")
|
||||||
|
|
||||||
self.assertEqual(_("tiger"), "tigre")
|
|
||||||
self.assertEqual(_("hedgehog"), "hérisson")
|
self.assertEqual(_("hedgehog"), "hérisson")
|
||||||
|
self.assertEqual(_("merchant"), "marchand")
|
||||||
self.assertEqual(_("rabbit"), "lapin")
|
self.assertEqual(_("rabbit"), "lapin")
|
||||||
|
self.assertEqual(_("sunflower"), "tournesol")
|
||||||
self.assertEqual(_("teddy bear"), "nounours")
|
self.assertEqual(_("teddy bear"), "nounours")
|
||||||
|
self.assertEqual(_("tiger"), "tigre")
|
||||||
|
|
||||||
self.assertEqual(_("body snatch potion"), "potion d'arrachage de corps")
|
self.assertEqual(_("body snatch potion"), "potion d'arrachage de corps")
|
||||||
self.assertEqual(_("bomb"), "bombe")
|
self.assertEqual(_("bomb"), "bombe")
|
||||||
|
self.assertEqual(_("explosion"), "explosion")
|
||||||
self.assertEqual(_("heart"), "cœur")
|
self.assertEqual(_("heart"), "cœur")
|
||||||
|
self.assertEqual(_("sword"), "épée")
|
||||||
|
|
Loading…
Reference in New Issue