Merge branch 'master' into map_generation

# Conflicts:
#	squirrelbattle/entities/player.py
#	squirrelbattle/game.py
#	squirrelbattle/interfaces.py
#	squirrelbattle/tests/game_test.py
This commit is contained in:
Yohann D'ANELLO
2021-01-10 22:16:11 +01:00
54 changed files with 1909 additions and 934 deletions

View File

@ -1,2 +1,2 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later

View File

@ -1,9 +1,9 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from squirrelbattle.game import Game
from squirrelbattle.display.display_manager import DisplayManager
from squirrelbattle.term_manager import TermManager
from .display.display_manager import DisplayManager
from .game import Game
from .term_manager import TermManager
class Bootstrap:

View File

@ -1,2 +1,2 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later

View File

@ -1,97 +0,0 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
from ..display.display import Box, Display
from ..game import Game
from ..resources import ResourceManager
from ..translations import gettext as _
class CreditsDisplay(Display):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.box = Box(*args, **kwargs)
self.pad = self.newpad(1, 1)
self.ascii_art_displayed = False
def update(self, game: Game) -> None:
return
def display(self) -> None:
self.box.refresh(self.y, self.x, self.height, self.width)
self.box.display()
self.pad.erase()
messages = [
_("Credits"),
"",
"Squirrel Battle",
"",
_("Developers:"),
"Yohann \"ÿnérant\" D'ANELLO",
"Mathilde \"eichhornchen\" DÉPRÉS",
"Nicolas \"nicomarg\" MARGULIES",
"Charles \"charsle\" PEYRAT",
"",
_("Translators:"),
"Hugo \"ifugao\" JACOB (español)",
]
for i, msg in enumerate(messages):
self.addstr(self.pad, i + (self.height - len(messages)) // 2,
(self.width - len(msg)) // 2, msg,
bold=(i == 0), italic=(":" in msg))
if self.ascii_art_displayed:
self.display_ascii_art()
self.refresh_pad(self.pad, 0, 0, self.y + 1, self.x + 1,
self.height + self.y - 2,
self.width + self.x - 2)
def display_ascii_art(self) -> None:
with open(ResourceManager.get_asset_path("ascii-art-ecureuil.txt"))\
as f:
ascii_art = f.read().split("\n")
height, width = len(ascii_art), len(ascii_art[0])
y_offset, x_offset = (self.height - height) // 2,\
(self.width - width) // 2
for i, line in enumerate(ascii_art):
for j, c in enumerate(line):
bg_color = curses.COLOR_WHITE
fg_color = curses.COLOR_BLACK
bold = False
if c == ' ':
bg_color = curses.COLOR_BLACK
elif c == '' or c == '' or c == '':
bold = True
fg_color = curses.COLOR_WHITE
bg_color = curses.COLOR_BLACK
elif c == '|':
bold = True # c = '┃'
fg_color = (100, 700, 1000)
bg_color = curses.COLOR_BLACK
elif c == '':
fg_color = (700, 300, 0)
elif c == '':
fg_color = (700, 300, 0)
bg_color = curses.COLOR_BLACK
elif c == '':
fg_color = (350, 150, 0)
elif c == '':
fg_color = (0, 0, 0)
bg_color = curses.COLOR_BLACK
elif c == '':
c = ''
fg_color = (1000, 1000, 1000)
bg_color = curses.COLOR_BLACK
self.addstr(self.pad, y_offset + i, x_offset + j, c,
fg_color, bg_color, bold=bold)
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
if self.pad.inch(y - 1, x - 1) != ord(" "):
self.ascii_art_displayed = True

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
@ -124,15 +124,24 @@ class Display:
return pad.addstr(y, x, msg, attr)
def init_pair(self, number: int, foreground: int, background: int) -> None:
foreground = foreground if self.screen and curses.can_change_color() \
and foreground < curses.COLORS \
else curses.COLOR_WHITE
background = background if self.screen and curses.can_change_color() \
and background < curses.COLORS \
else curses.COLOR_WHITE
return curses.init_pair(number, foreground, background) \
if self.screen else None
if self.screen and curses.can_change_color() \
and number < curses.COLOR_PAIRS else None
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 \
and number < curses.COLOR_PAIRS 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
if self.screen and curses.can_change_color() \
and number < curses.COLORS else None
def resize(self, y: int, x: int, height: int, width: int,
resize_pad: bool = True) -> None:
@ -281,3 +290,29 @@ class Box(Display):
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
self.y + self.height - 1, self.x + self.width - 1)
class MessageDisplay(Display):
"""
A class to handle the display of popup messages.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.box = Box(fg_border_color=curses.COLOR_RED, *args, **kwargs)
self.message = ""
self.pad = self.newpad(1, 1)
def update(self, game: Game) -> None:
self.message = game.message
def display(self) -> None:
self.box.refresh(self.y - 1, self.x - 2,
self.height + 2, self.width + 4)
self.box.display()
self.pad.erase()
self.addstr(self.pad, 0, 0, self.message, bold=True)
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
self.height + self.y - 1,
self.width + self.x - 1)

View File

@ -1,21 +1,17 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
from squirrelbattle.display.creditsdisplay import CreditsDisplay
from squirrelbattle.display.display import VerticalSplit, HorizontalSplit, \
Display
from squirrelbattle.display.mapdisplay import MapDisplay
from squirrelbattle.display.messagedisplay import MessageDisplay
from squirrelbattle.display.statsdisplay import StatsDisplay
from squirrelbattle.display.menudisplay import MainMenuDisplay, \
PlayerInventoryDisplay, StoreInventoryDisplay, SettingsMenuDisplay
from squirrelbattle.display.logsdisplay import LogsDisplay
from squirrelbattle.display.texturepack import TexturePack
from typing import Any, List
from squirrelbattle.game import Game, GameMode
from squirrelbattle.enums import DisplayActions
from .display import Display, HorizontalSplit, MessageDisplay, VerticalSplit
from .gamedisplay import LogsDisplay, MapDisplay, StatsDisplay
from .menudisplay import ChestInventoryDisplay, CreditsDisplay, \
MainMenuDisplay, PlayerInventoryDisplay, \
SettingsMenuDisplay, StoreInventoryDisplay
from .texturepack import TexturePack
from ..enums import DisplayActions
from ..game import Game, GameMode
class DisplayManager:
@ -29,6 +25,7 @@ class DisplayManager:
self.logsdisplay = LogsDisplay(screen, pack)
self.playerinventorydisplay = PlayerInventoryDisplay(screen, pack)
self.storeinventorydisplay = StoreInventoryDisplay(screen, pack)
self.chestinventorydisplay = ChestInventoryDisplay(screen, pack)
self.mainmenudisplay = MainMenuDisplay(self.game.main_menu,
screen, pack)
self.settingsmenudisplay = SettingsMenuDisplay(screen, pack)
@ -40,7 +37,8 @@ class DisplayManager:
self.mainmenudisplay, self.settingsmenudisplay,
self.logsdisplay, self.messagedisplay,
self.playerinventorydisplay,
self.storeinventorydisplay, self.creditsdisplay]
self.storeinventorydisplay, self.creditsdisplay,
self.chestinventorydisplay]
self.update_game_components()
def handle_display_action(self, action: DisplayActions, *params) -> None:
@ -87,7 +85,8 @@ class DisplayManager:
if self.game.state == GameMode.PLAY \
or self.game.state == GameMode.INVENTORY \
or self.game.state == GameMode.STORE:
or self.game.state == GameMode.STORE\
or self.game.state == GameMode.CHEST:
# The map pad has already the good size
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5,
self.mapdisplay.pack.tile_width
@ -124,6 +123,19 @@ class DisplayManager:
pack.tile_width * (2 * self.cols // (5 * pack.tile_width)))
displays.append(self.storeinventorydisplay)
displays.append(self.playerinventorydisplay)
elif self.game.state == GameMode.CHEST:
self.chestinventorydisplay.refresh(
self.rows // 10,
pack.tile_width * (self.cols // (2 * pack.tile_width)),
8 * self.rows // 10,
pack.tile_width * (2 * self.cols // (5 * pack.tile_width)))
self.playerinventorydisplay.refresh(
self.rows // 10,
pack.tile_width * (self.cols // (10 * pack.tile_width)),
8 * self.rows // 10,
pack.tile_width * (2 * self.cols // (5 * pack.tile_width)))
displays.append(self.chestinventorydisplay)
displays.append(self.playerinventorydisplay)
elif self.game.state == GameMode.MAINMENU:
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
displays.append(self.mainmenudisplay)

View File

@ -1,14 +1,120 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
from .display import Display
from ..entities.items import Monocle
from ..entities.player import Player
from ..game import Game
from ..interfaces import FightingEntity
from ..interfaces import FightingEntity, Logs, Map
from ..translations import gettext as _
from .display import Display
class LogsDisplay(Display):
"""
A class to handle the display of the logs.
"""
logs: Logs
def __init__(self, *args) -> None:
super().__init__(*args)
self.pad = self.newpad(self.rows, self.cols)
def update(self, game: Game) -> None:
self.logs = game.logs
def display(self) -> None:
messages = self.logs.messages[-self.height:]
messages = messages[::-1]
self.pad.erase()
for i in range(min(self.height, len(messages))):
self.addstr(self.pad, self.height - i - 1, self.x,
messages[i][:self.width])
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
self.y + self.height - 1, self.x + self.width - 1)
class MapDisplay(Display):
"""
A class to handle the display of the map.
"""
map: Map
def __init__(self, *args):
super().__init__(*args)
def update(self, game: Game) -> None:
self.map = game.map
self.pad = self.newpad(self.map.height,
self.pack.tile_width * self.map.width + 1)
def update_pad(self) -> None:
for j in range(len(self.map.tiles)):
for i in range(len(self.map.tiles[j])):
if not self.map.seen_tiles[j][i]:
continue
fg, bg = self.map.tiles[j][i].visible_color(self.pack) if \
self.map.visibility[j][i] else \
self.map.tiles[j][i].hidden_color(self.pack)
self.addstr(self.pad, j, self.pack.tile_width * i,
self.map.tiles[j][i].char(self.pack), fg, bg)
for e in self.map.entities:
if self.map.visibility[e.y][e.x]:
self.addstr(self.pad, e.y, self.pack.tile_width * e.x,
self.pack[e.name.upper()],
self.pack.entity_fg_color,
self.pack.entity_bg_color)
# Display Path map for debug purposes
# from squirrelbattle.entities.player import Player
# players = [ p for p in self.map.entities if isinstance(p,Player) ]
# player = players[0] if len(players) > 0 else None
# if player:
# for x in range(self.map.width):
# for y in range(self.map.height):
# if (y,x) in player.paths:
# deltay, deltax = (y - player.paths[(y, x)][0],
# x - player.paths[(y, x)][1])
# if (deltay, deltax) == (-1, 0):
# character = '↓'
# elif (deltay, deltax) == (1, 0):
# character = '↑'
# elif (deltay, deltax) == (0, -1):
# character = '→'
# else:
# character = '←'
# self.addstr(self.pad, y, self.pack.tile_width * x,
# character, self.pack.tile_fg_color,
# self.pack.tile_bg_color)
def display(self) -> None:
y, x = self.map.currenty, self.pack.tile_width * self.map.currentx
deltay, deltax = (self.height // 2) + 1, (self.width // 2) + 1
pminrow, pmincol = y - deltay, x - deltax
sminrow, smincol = max(-pminrow, 0), max(-pmincol, 0)
deltay, deltax = self.height - deltay, self.width - deltax
smaxrow = self.map.height - (y + deltay) + self.height - 1
smaxrow = min(smaxrow, self.height - 1)
smaxcol = self.pack.tile_width * self.map.width - \
(x + deltax) + self.width - 1
# Wrap perfectly the map according to the width of the tiles
pmincol = self.pack.tile_width * (pmincol // self.pack.tile_width)
smincol = self.pack.tile_width * (smincol // self.pack.tile_width)
smaxcol = self.pack.tile_width \
* (smaxcol // self.pack.tile_width + 1) - 1
smaxcol = min(smaxcol, self.width - 1)
pminrow = max(0, min(self.map.height, pminrow))
pmincol = max(0, min(self.pack.tile_width * self.map.width, pmincol))
self.pad.erase()
self.update_pad()
self.refresh_pad(self.pad, pminrow, pmincol, sminrow, smincol, smaxrow,
smaxcol)
class StatsDisplay(Display):

View File

@ -1,31 +0,0 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from squirrelbattle.display.display import Display
from squirrelbattle.game import Game
from squirrelbattle.interfaces import Logs
class LogsDisplay(Display):
"""
A class to handle the display of the logs.
"""
logs: Logs
def __init__(self, *args) -> None:
super().__init__(*args)
self.pad = self.newpad(self.rows, self.cols)
def update(self, game: Game) -> None:
self.logs = game.logs
def display(self) -> None:
messages = self.logs.messages[-self.height:]
messages = messages[::-1]
self.pad.erase()
for i in range(min(self.height, len(messages))):
self.addstr(self.pad, self.height - i - 1, self.x,
messages[i][:self.width])
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
self.y + self.height - 1, self.x + self.width - 1)

View File

@ -1,87 +0,0 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from squirrelbattle.interfaces import Map
from .display import Display
from ..game import Game
class MapDisplay(Display):
"""
A class to handle the display of the map.
"""
map: Map
def __init__(self, *args):
super().__init__(*args)
def update(self, game: Game) -> None:
self.map = game.map
self.pad = self.newpad(self.map.height,
self.pack.tile_width * self.map.width + 1)
def update_pad(self) -> None:
for j in range(len(self.map.tiles)):
for i in range(len(self.map.tiles[j])):
if not self.map.seen_tiles[j][i]:
continue
fg, bg = self.map.tiles[j][i].visible_color(self.pack) if \
self.map.visibility[j][i] else \
self.map.tiles[j][i].hidden_color(self.pack)
self.addstr(self.pad, j, self.pack.tile_width * i,
self.map.tiles[j][i].char(self.pack), fg, bg)
for e in self.map.entities:
if self.map.visibility[e.y][e.x]:
self.addstr(self.pad, e.y, self.pack.tile_width * e.x,
self.pack[e.name.upper()],
self.pack.entity_fg_color,
self.pack.entity_bg_color)
# Display Path map for debug purposes
# from squirrelbattle.entities.player import Player
# players = [ p for p in self.map.entities if isinstance(p,Player) ]
# player = players[0] if len(players) > 0 else None
# if player:
# for x in range(self.map.width):
# for y in range(self.map.height):
# if (y,x) in player.paths:
# deltay, deltax = (y - player.paths[(y, x)][0],
# x - player.paths[(y, x)][1])
# if (deltay, deltax) == (-1, 0):
# character = '↓'
# elif (deltay, deltax) == (1, 0):
# character = '↑'
# elif (deltay, deltax) == (0, -1):
# character = '→'
# else:
# character = '←'
# self.addstr(self.pad, y, self.pack.tile_width * x,
# character, self.pack.tile_fg_color,
# self.pack.tile_bg_color)
def display(self) -> None:
y, x = self.map.currenty, self.pack.tile_width * self.map.currentx
deltay, deltax = (self.height // 2) + 1, (self.width // 2) + 1
pminrow, pmincol = y - deltay, x - deltax
sminrow, smincol = max(-pminrow, 0), max(-pmincol, 0)
deltay, deltax = self.height - deltay, self.width - deltax
smaxrow = self.map.height - (y + deltay) + self.height - 1
smaxrow = min(smaxrow, self.height - 1)
smaxcol = self.pack.tile_width * self.map.width - \
(x + deltax) + self.width - 1
# Wrap perfectly the map according to the width of the tiles
pmincol = self.pack.tile_width * (pmincol // self.pack.tile_width)
smincol = self.pack.tile_width * (smincol // self.pack.tile_width)
smaxcol = self.pack.tile_width \
* (smaxcol // self.pack.tile_width + 1) - 1
smaxcol = min(smaxcol, self.width - 1)
pminrow = max(0, min(self.map.height, pminrow))
pmincol = max(0, min(self.pack.tile_width * self.map.width, pmincol))
self.pad.erase()
self.update_pad()
self.refresh_pad(self.pad, pminrow, pmincol, sminrow, smincol, smaxrow,
smaxcol)

View File

@ -1,15 +1,15 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
from random import randint
from typing import List
from squirrelbattle.menus import Menu, MainMenu, SettingsMenu, StoreMenu
from .display import Box, Display
from ..entities.player import Player
from ..enums import KeyValues, GameMode
from ..enums import GameMode, KeyValues
from ..game import Game
from ..menus import ChestMenu, MainMenu, Menu, SettingsMenu, StoreMenu
from ..resources import ResourceManager
from ..translations import gettext as _
@ -104,7 +104,8 @@ class MainMenuDisplay(Display):
super().__init__(*args)
self.menu = menu
with open(ResourceManager.get_asset_path("ascii_art.txt"), "r") as file:
with open(ResourceManager.get_asset_path("ascii_art-title.txt"), "r")\
as file:
self.title = file.read().split("\n")
self.pad = self.newpad(max(self.rows, len(self.title) + 30),
@ -156,13 +157,17 @@ class PlayerInventoryDisplay(MenuDisplay):
player: Player = None
selected: bool = True
store_mode: bool = False
chest_mode: bool = False
def update(self, game: Game) -> None:
self.player = game.player
self.update_menu(game.inventory_menu)
game.inventory_menu.update_player(self.player)
self.store_mode = game.state == GameMode.STORE
self.chest_mode = game.state == GameMode.CHEST
self.selected = game.state == GameMode.INVENTORY \
or (self.store_mode and not game.is_in_store_menu)
or (self.store_mode and not game.is_in_store_menu)\
or (self.chest_mode and not game.is_in_chest_menu)
def update_pad(self) -> None:
self.menubox.update_title(_("INVENTORY"))
@ -241,3 +246,128 @@ class StoreInventoryDisplay(MenuDisplay):
self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2))
game.is_in_store_menu = True
game.handle_key_pressed(KeyValues.ENTER)
class ChestInventoryDisplay(MenuDisplay):
"""
A class to handle the display of a merchant's inventory.
"""
menu: ChestMenu
selected: bool = False
def update(self, game: Game) -> None:
self.update_menu(game.chest_menu)
self.selected = game.is_in_chest_menu
def update_pad(self) -> None:
self.menubox.update_title(_("CHEST"))
for i, item in enumerate(self.menu.values):
rep = self.pack[item.name.upper()]
selection = f"[{rep}]" if i == self.menu.position \
and self.selected else f" {rep} "
self.addstr(self.pad, i + 1, 0, selection
+ " " + item.translated_name.capitalize())
@property
def truewidth(self) -> int:
return max(1, self.height if hasattr(self, "height") else 10)
@property
def trueheight(self) -> int:
return 2 + super().trueheight
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
"""
We can select a menu item with the mouse.
"""
self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2))
game.is_in_chest_menu = True
game.handle_key_pressed(KeyValues.ENTER)
class CreditsDisplay(Display):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.box = Box(*args, **kwargs)
self.pad = self.newpad(1, 1)
self.ascii_art_displayed = False
def update(self, game: Game) -> None:
return
def display(self) -> None:
self.box.refresh(self.y, self.x, self.height, self.width)
self.box.display()
self.pad.erase()
messages = [
_("Credits"),
"",
"Squirrel Battle",
"",
_("Developers:"),
"Yohann \"ÿnérant\" D'ANELLO",
"Mathilde \"eichhornchen\" DÉPRÉS",
"Nicolas \"nicomarg\" MARGULIES",
"Charles \"charsle\" PEYRAT",
"",
_("Translators:"),
"Hugo \"ifugao\" JACOB (español)",
]
for i, msg in enumerate(messages):
self.addstr(self.pad, i + (self.height - len(messages)) // 2,
(self.width - len(msg)) // 2, msg,
bold=(i == 0), italic=(":" in msg))
if self.ascii_art_displayed:
self.display_ascii_art()
self.refresh_pad(self.pad, 0, 0, self.y + 1, self.x + 1,
self.height + self.y - 2,
self.width + self.x - 2)
def display_ascii_art(self) -> None:
with open(ResourceManager.get_asset_path("ascii-art-ecureuil.txt"))\
as f:
ascii_art = f.read().split("\n")
height, width = len(ascii_art), len(ascii_art[0])
y_offset, x_offset = (self.height - height) // 2,\
(self.width - width) // 2
for i, line in enumerate(ascii_art):
for j, c in enumerate(line):
bg_color = curses.COLOR_WHITE
fg_color = curses.COLOR_BLACK
bold = False
if c == ' ':
bg_color = curses.COLOR_BLACK
elif c == '' or c == '' or c == '':
bold = True
fg_color = curses.COLOR_WHITE
bg_color = curses.COLOR_BLACK
elif c == '|':
bold = True # c = '┃'
fg_color = (100, 700, 1000)
bg_color = curses.COLOR_BLACK
elif c == '':
fg_color = (700, 300, 0)
elif c == '':
fg_color = (700, 300, 0)
bg_color = curses.COLOR_BLACK
elif c == '':
fg_color = (350, 150, 0)
elif c == '':
fg_color = (0, 0, 0)
bg_color = curses.COLOR_BLACK
elif c == '':
c = ''
fg_color = (1000, 1000, 1000)
bg_color = curses.COLOR_BLACK
self.addstr(self.pad, y_offset + i, x_offset + j, c,
fg_color, bg_color, bold=bold)
def handle_click(self, y: int, x: int, attr: int, game: Game) -> None:
if self.pad.inch(y - 1, x - 1) != ord(" "):
self.ascii_art_displayed = True

View File

@ -1,32 +0,0 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
from squirrelbattle.display.display import Box, Display
from squirrelbattle.game import Game
class MessageDisplay(Display):
"""
A class to handle the display of popup messages.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.box = Box(fg_border_color=curses.COLOR_RED, *args, **kwargs)
self.message = ""
self.pad = self.newpad(1, 1)
def update(self, game: Game) -> None:
self.message = game.message
def display(self) -> None:
self.box.refresh(self.y - 1, self.x - 2,
self.height + 2, self.width + 4)
self.box.display()
self.pad.erase()
self.addstr(self.pad, 0, 0, self.message, bold=True)
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
self.height + self.y - 1,
self.width + self.x - 1)

View File

@ -1,8 +1,8 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
from typing import Any, Union, Tuple
from typing import Any, Tuple, Union
class TexturePack:
@ -21,9 +21,12 @@ class TexturePack:
BODY_SNATCH_POTION: str
BOMB: str
BOW: str
CHEST: str
CHESTPLATE: str
EAGLE: str
EMPTY: str
FIRE_BALL_STAFF: str
FLOOR: str
HAZELNUT: str
HEART: str
@ -34,6 +37,9 @@ class TexturePack:
RABBIT: str
RING_OF_CRITICAL_DAMAGE: str
RING_OF_MORE_EXPERIENCE: str
RULER: str
SCROLL_OF_DAMAGE: str
SCROLL_OF_WEAKENING: str
SHIELD: str
SUNFLOWER: str
SWORD: str
@ -73,10 +79,13 @@ TexturePack.ASCII_PACK = TexturePack(
BODY_SNATCH_POTION='S',
BOMB='ç',
BOW=')',
CHEST='',
CHESTPLATE='(',
EAGLE='µ',
EMPTY=' ',
EXPLOSION='%',
FIRE_BALL_STAFF=':',
FLOOR='.',
LADDER='H',
HAZELNUT='¤',
@ -89,6 +98,7 @@ TexturePack.ASCII_PACK = TexturePack(
RABBIT='Y',
RING_OF_CRITICAL_DAMAGE='o',
RING_OF_MORE_EXPERIENCE='o',
RULER='\\',
SHIELD='D',
SUNFLOWER='I',
SWORD='\u2020',
@ -96,6 +106,8 @@ TexturePack.ASCII_PACK = TexturePack(
TIGER='n',
TRUMPET='/',
WALL='#',
SCROLL_OF_DAMAGE=']',
SCROLL_OF_WEAKENING=']',
)
TexturePack.SQUIRREL_PACK = TexturePack(
@ -109,10 +121,13 @@ TexturePack.SQUIRREL_PACK = TexturePack(
BODY_SNATCH_POTION='🔀',
BOMB='💣',
BOW='🏹',
CHEST='🧰',
CHESTPLATE='🦺',
EAGLE='🦅',
EMPTY=' ',
EXPLOSION='💥',
FIRE_BALL_STAFF='🪄',
FLOOR='██',
LADDER=('🪜', curses.COLOR_WHITE, (1000, 1000, 1000),
curses.COLOR_WHITE, (1000, 1000, 1000)),
@ -126,6 +141,7 @@ TexturePack.SQUIRREL_PACK = TexturePack(
RABBIT='🐇',
RING_OF_CRITICAL_DAMAGE='💍',
RING_OF_MORE_EXPERIENCE='💍',
RULER='📏',
SHIELD='🛡️ ',
SUNFLOWER='🌻',
SWORD='🗡️ ',
@ -133,4 +149,6 @@ TexturePack.SQUIRREL_PACK = TexturePack(
TIGER='🐅',
TRUMPET='🎺',
WALL='🧱',
SCROLL_OF_DAMAGE='📜',
SCROLL_OF_WEAKENING='📜',
)

View File

@ -1,2 +1,2 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later

View File

@ -1,10 +1,15 @@
from ..interfaces import FriendlyEntity, InventoryHolder, Map, FightingEntity
from ..translations import gettext as _
from .player import Player
from .monsters import Monster
from .items import Item
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from random import choice, shuffle
from .items import Bomb, Item
from .monsters import Monster
from .player import Player
from ..interfaces import Entity, FightingEntity, FriendlyEntity, \
InventoryHolder, Map
from ..translations import gettext as _
class Merchant(InventoryHolder, FriendlyEntity):
"""
@ -17,11 +22,13 @@ class Merchant(InventoryHolder, FriendlyEntity):
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 [])
hazel: int = 75, maxhealth: int = 8, *args, **kwargs):
super().__init__(name=name, maxhealth=maxhealth, *args, **kwargs)
self.inventory = self.translate_inventory(inventory) \
if inventory is not None else None
self.hazel = hazel
if not self.inventory:
if self.inventory is None:
self.inventory = []
for i in range(5):
self.inventory.append(choice(Item.get_all_items())())
@ -39,11 +46,54 @@ class Merchant(InventoryHolder, FriendlyEntity):
self.hazel += hz
class Chest(InventoryHolder, FriendlyEntity):
"""
A class of chest inanimate entities which contain objects.
"""
annihilated: bool
def __init__(self, name: str = "chest", inventory: list = None,
hazel: int = 0, *args, **kwargs):
super().__init__(name=name, *args, **kwargs)
self.hazel = hazel
self.inventory = self.translate_inventory(inventory) \
if inventory is not None else None
self.annihilated = False
if self.inventory is None:
self.inventory = []
for i in range(3):
self.inventory.append(choice(Item.get_all_items())())
def talk_to(self, player: Player) -> str:
"""
This function is used to open the chest's inventory in a menu,
and allows the player to take objects.
"""
return _("You have opened the chest")
def take_damage(self, attacker: Entity, amount: int) -> str:
"""
A chest is not living, it can not take damage
"""
if isinstance(attacker, Bomb):
self.die()
self.annihilated = True
return _("The chest exploded")
return _("It's not really effective")
@property
def dead(self) -> bool:
"""
Chest can not die
"""
return self.annihilated
class Sunflower(FriendlyEntity):
"""
A friendly sunflower.
"""
def __init__(self, maxhealth: int = 15,
def __init__(self, maxhealth: int = 20,
*args, **kwargs) -> None:
super().__init__(name="sunflower", maxhealth=maxhealth, *args, **kwargs)
@ -123,6 +173,6 @@ class Trumpet(Familiar):
A class of familiars.
"""
def __init__(self, name: str = "trumpet", strength: int = 3,
maxhealth: int = 20, *args, **kwargs) -> None:
maxhealth: int = 30, *args, **kwargs) -> None:
super().__init__(name=name, strength=strength,
maxhealth=maxhealth, *args, **kwargs)

View File

@ -1,10 +1,10 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from random import choice, randint
from typing import Optional
from typing import Any, Optional
from ..interfaces import Entity, FightingEntity, Map, InventoryHolder
from ..interfaces import Entity, FightingEntity, InventoryHolder, Map
from ..translations import gettext as _
@ -47,6 +47,11 @@ class Item(Entity):
Indicates what should be done when the item is used.
"""
def throw(self, direction: int) -> Any:
"""
Indicates what should be done when the item is thrown.
"""
def equip(self) -> None:
"""
Indicates what should be done when the item is equipped.
@ -86,16 +91,22 @@ class Item(Entity):
"""
Returns the list of all item classes.
"""
return [BodySnatchPotion, Chestplate, Bomb, Heart, Helmet, Monocle,
Shield, Sword, RingCritical, RingXP]
return [BodySnatchPotion, Bomb, Bow, Chestplate, FireBallStaff,
Heart, Helmet, Monocle, ScrollofDamage, ScrollofWeakening,
Shield, Sword, RingCritical, RingXP, Ruler]
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder) -> bool:
def be_sold(self, buyer: InventoryHolder, seller: InventoryHolder,
for_free: bool = False) -> bool:
"""
Does all necessary actions when an object is to be sold.
Is overwritten by some classes that cannot exist in the player's
inventory.
"""
if buyer.hazel >= self.price:
if for_free:
self.hold(buyer)
seller.remove_from_inventory(self)
return True
elif buyer.hazel >= self.price:
self.hold(buyer)
seller.remove_from_inventory(self)
buyer.change_hazel_balance(-self.price)
@ -266,6 +277,15 @@ class Sword(Weapon):
super().__init__(name=name, price=price, *args, **kwargs)
class Ruler(Weapon):
"""
A basic weapon
"""
def __init__(self, name: str = "ruler", price: int = 2,
damage: int = 1, *args, **kwargs):
super().__init__(name=name, price=price, damage=damage, *args, **kwargs)
class Armor(Item):
"""
Class of items that increase the player's constitution.
@ -455,6 +475,166 @@ class RingXP(Ring):
*args, **kwargs)
class ScrollofDamage(Item):
"""
A scroll that, when used, deals damage to all entities in a certain radius.
"""
def __init__(self, name: str = "scroll_of_damage", price: int = 18,
*args, **kwargs):
super().__init__(name=name, price=price, *args, **kwargs)
def use(self) -> None:
"""
Find all entities within a radius of 5, and deal damage based on the
player's intelligence.
"""
for entity in self.held_by.map.entities:
if entity.is_fighting_entity() and not entity == self.held_by:
if entity.distance(self.held_by) <= 5:
self.held_by.map.logs.add_message(entity.take_damage(
self.held_by, self.held_by.intelligence))
self.held_by.inventory.remove(self)
class ScrollofWeakening(Item):
"""
A scroll that, when used, reduces the damage of the ennemies for 3 turns.
"""
def __init__(self, name: str = "scroll_of_weakening", price: int = 13,
*args, **kwargs):
super().__init__(name=name, price=price, *args, **kwargs)
def use(self) -> None:
"""
Find all entities and reduce their damage.
"""
for entity in self.held_by.map.entities:
if entity.is_fighting_entity() and not entity == self.held_by:
entity.strength = entity.strength - \
max(1, self.held_by.intelligence // 2)
entity.effects.append(["strength",
-max(1, self.held_by.intelligence // 2),
3])
self.held_by.map.logs.add_message(
_(f"The ennemies have -{max(1, self.held_by.intelligence // 2)}"
+ "strength for 3 turns"))
self.held_by.inventory.remove(self)
class LongRangeWeapon(Weapon):
def __init__(self, damage: int = 4,
rang: int = 3, *args, **kwargs):
super().__init__(*args, **kwargs)
self.damage = damage
self.range = rang
def throw(self, direction: int) -> Any:
to_kill = None
for entity in self.held_by.map.entities:
if entity.is_fighting_entity():
if direction == 0 and self.held_by.x == entity.x \
and self.held_by.y - entity.y > 0 and \
self.held_by.y - entity.y <= self.range:
to_kill = entity
elif direction == 2 and self.held_by.x == entity.x \
and entity.y - self.held_by.y > 0 and \
entity.y - self.held_by.y <= self.range:
to_kill = entity
elif direction == 1 and self.held_by.y == entity.y \
and entity.x - self.held_by.x > 0 and \
entity.x - self.held_by.x <= self.range:
to_kill = entity
elif direction == 3 and self.held_by.y == entity.y \
and self.held_by.x - entity.x > 0 and \
self.held_by.x - entity.x <= self.range:
to_kill = entity
if to_kill:
line = _("{name}").format(name=to_kill.translated_name.capitalize()
) + self.string + " "\
+ to_kill.take_damage(
self.held_by, self.damage
+ getattr(self.held_by, self.stat))
self.held_by.map.logs.add_message(line)
return (to_kill.y, to_kill.x) if to_kill else None
def equip(self) -> None:
"""
Equip the weapon.
"""
self.held_by.remove_from_inventory(self)
self.held_by.equipped_main = self
@property
def stat(self) -> str:
"""
The stat that is used when using the object: dexterity for a bow
or intelligence for a magic staff.
"""
@property
def string(self) -> str:
"""
The string that is printed when we hit an ennemy.
"""
class Bow(LongRangeWeapon):
"""
A type of long range weapon that deals damage
based on the player's dexterity
"""
def __init__(self, name: str = "bow", price: int = 22, damage: int = 4,
rang: int = 3, *args, **kwargs):
super().__init__(name=name, price=price, damage=damage,
rang=rang, *args, **kwargs)
@property
def stat(self) -> str:
"""
Here it is dexterity
"""
return "dexterity"
@property
def string(self) -> str:
return _(" is shot by an arrow.")
class FireBallStaff(LongRangeWeapon):
"""
A type of powerful long range weapon that deals damage
based on the player's intelligence
"""
def __init__(self, name: str = "fire_ball_staff", price: int = 36,
damage: int = 6, rang: int = 4, *args, **kwargs):
super().__init__(name=name, price=price, damage=damage,
rang=rang, *args, **kwargs)
@property
def stat(self) -> str:
"""
Here it is intelligence
"""
return "intelligence"
@property
def string(self) -> str:
return _(" is shot by a fire ball.")
def throw(self, direction: int) -> Any:
"""
Adds an explosion animation when killing something.
"""
coord = super().throw(direction)
if coord:
y = coord[0]
x = coord[1]
explosion = Explosion(y=y, x=x)
self.held_by.map.add_entity(explosion)
return y, x
class Monocle(Item):
def __init__(self, name: str = "monocle", price: int = 10,
*args, **kwargs):

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from random import shuffle
@ -31,6 +31,7 @@ class Monster(FightingEntity):
By default, a monster will move randomly where it is possible
If the player is closeby, the monster runs to the player.
"""
super().act(m)
target = None
for entity in m.entities:
if self.distance_squared(entity) <= 25 and \
@ -42,7 +43,9 @@ class Monster(FightingEntity):
# that targets the player.
# If they can not move and are already close to the player,
# they hit.
if target and (self.y, self.x) in target.paths:
if target and (self.y, self.x) in target.paths and \
self.map.is_visible_from(self.y, self.x,
target.y, target.x, 5):
# Moves to target player by choosing the best available path
for next_y, next_x in target.paths[(self.y, self.x)]:
moved = self.check_move(next_y, next_x, True)
@ -73,8 +76,8 @@ class Tiger(Monster):
"""
A tiger monster.
"""
def __init__(self, name: str = "tiger", strength: int = 2,
maxhealth: int = 20, *args, **kwargs) -> None:
def __init__(self, name: str = "tiger", strength: int = 5,
maxhealth: int = 30, *args, **kwargs) -> None:
super().__init__(name=name, strength=strength,
maxhealth=maxhealth, *args, **kwargs)
@ -94,7 +97,7 @@ class Rabbit(Monster):
A rabbit monster.
"""
def __init__(self, name: str = "rabbit", strength: int = 1,
maxhealth: int = 15, critical: int = 30,
maxhealth: int = 20, critical: int = 30,
*args, **kwargs) -> None:
super().__init__(name=name, strength=strength,
maxhealth=maxhealth, critical=critical,

View File

@ -1,11 +1,13 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from math import log
from random import randint
from typing import Dict, Optional, Tuple
from .items import Item
from ..interfaces import FightingEntity, InventoryHolder
from ..translations import gettext as _
class Player(InventoryHolder, FightingEntity):
@ -61,6 +63,31 @@ class Player(InventoryHolder, FightingEntity):
self.recalculate_paths()
self.map.compute_visibility(self.y, self.x, self.vision)
def dance(self) -> None:
"""
Dancing has a certain probability or making ennemies unable
to fight for 3 turns. That probability depends on the player's
charisma.
"""
diceroll = randint(1, 10)
found = False
if diceroll <= self.charisma:
for entity in self.map.entities:
if entity.is_fighting_entity() and not entity == self \
and entity.distance(self) <= 3:
found = True
entity.confused = 1
entity.effects.append(["confused", 1, 3])
if found:
self.map.logs.add_message(_(
"It worked! Nearby ennemies will be confused for 3 turns."))
else:
self.map.logs.add_message(_(
"It worked, but there is no one nearby..."))
else:
self.map.logs.add_message(
_("The dance was not effective..."))
def level_up(self) -> None:
"""
Add as many levels as possible to the player.
@ -69,8 +96,18 @@ class Player(InventoryHolder, FightingEntity):
self.level += 1
self.current_xp -= self.max_xp
self.max_xp = self.level * 10
self.maxhealth += int(2 * log(self.level) / log(2))
self.health = self.maxhealth
self.strength = self.strength + 1
if self.level % 3 == 0:
self.dexterity += 1
self.constitution += 1
if self.level % 4 == 0:
self.intelligence += 1
if self.level % 6 == 0:
self.charisma += 1
if self.level % 10 == 0 and self.critical < 95:
self.critical += (100 - self.charisma) // 30
def add_xp(self, xp: int) -> None:
"""

View File

@ -1,7 +1,7 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from enum import Enum, auto
from enum import auto, Enum
from typing import Optional
from squirrelbattle.settings import Settings
@ -28,6 +28,7 @@ class GameMode(Enum):
SETTINGS = auto()
INVENTORY = auto()
STORE = auto()
CHEST = auto()
CREDITS = auto()
@ -48,9 +49,12 @@ class KeyValues(Enum):
CHAT = auto()
WAIT = auto()
LADDER = auto()
LAUNCH = auto()
DANCE = auto()
@staticmethod
def translate_key(key: str, settings: Settings) -> Optional["KeyValues"]:
def translate_key(key: str, settings: Settings) \
-> Optional["KeyValues"]: # noqa: C901
"""
Translates the raw string key into an enum value that we can use.
"""
@ -84,4 +88,7 @@ class KeyValues(Enum):
return KeyValues.WAIT
elif key == settings.KEY_LADDER:
return KeyValues.LADDER
return None
elif key == settings.KEY_LAUNCH:
return KeyValues.LAUNCH
elif key == settings.KEY_DANCE:
return KeyValues.DANCE

View File

@ -1,20 +1,20 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from json import JSONDecodeError
from typing import Any, Optional, List
import curses
import json
from json import JSONDecodeError
import os
import sys
from typing import Any, List, Optional
from . import menus
from .entities.player import Player
from .enums import GameMode, KeyValues, DisplayActions
from .interfaces import Map, Logs
from .enums import DisplayActions, GameMode, KeyValues
from .interfaces import Logs, Map
from .mapgeneration import broguelike
from .resources import ResourceManager
from .settings import Settings
from . import menus
from .translations import gettext as _, Translator
@ -35,7 +35,9 @@ class Game:
"""
self.state = GameMode.MAINMENU
self.waiting_for_friendly_key = False
self.waiting_for_launch_key = False
self.is_in_store_menu = True
self.is_in_chest_menu = True
self.settings = Settings()
self.settings.load_settings()
self.settings.write_settings()
@ -45,6 +47,7 @@ class Game:
self.settings_menu.update_values(self.settings)
self.inventory_menu = menus.InventoryMenu()
self.store_menu = menus.StoreMenu()
self.chest_menu = menus.ChestMenu()
self.logs = Logs()
self.message = None
@ -119,6 +122,9 @@ class Game:
if self.waiting_for_friendly_key:
# The player requested to talk with a friendly entity
self.handle_friendly_entity_chat(key)
elif self.waiting_for_launch_key:
# The player requested to launch
self.handle_launch(key)
else:
self.handle_key_pressed_play(key)
elif self.state == GameMode.INVENTORY:
@ -129,6 +135,8 @@ class Game:
self.settings_menu.handle_key_pressed(key, raw_key, self)
elif self.state == GameMode.STORE:
self.handle_key_pressed_store(key)
elif self.state == GameMode.CHEST:
self.handle_key_pressed_chest(key)
elif self.state == GameMode.CREDITS:
self.state = GameMode.MAINMENU
self.display_actions(DisplayActions.REFRESH)
@ -157,6 +165,9 @@ class Game:
self.player.equipped_main.use()
if self.player.equipped_secondary:
self.player.equipped_secondary.use()
elif key == KeyValues.LAUNCH:
# Wait for the direction to launch in
self.waiting_for_launch_key = True
elif key == KeyValues.SPACE:
self.state = GameMode.MAINMENU
elif key == KeyValues.CHAT:
@ -166,6 +177,9 @@ class Game:
self.map.tick(self.player)
elif key == KeyValues.LADDER:
self.handle_ladder()
elif key == KeyValues.DANCE:
self.player.dance()
self.map.tick(self.player)
def handle_ladder(self) -> None:
"""
@ -246,6 +260,36 @@ class Game:
self.is_in_store_menu = True
self.store_menu.update_merchant(entity)
self.display_actions(DisplayActions.UPDATE)
elif entity.is_chest():
self.state = GameMode.CHEST
self.is_in_chest_menu = True
self.chest_menu.update_chest(entity)
self.display_actions(DisplayActions.UPDATE)
def handle_launch(self, key: KeyValues) -> None:
"""
If the player tries to throw something in a direction, the game looks
for entities in that direction and within the range of the player's
weapon and adds damage
"""
if not self.waiting_for_launch_key:
return
self.waiting_for_launch_key = False
if key == KeyValues.UP:
direction = 0
elif key == KeyValues.DOWN:
direction = 2
elif key == KeyValues.LEFT:
direction = 3
elif key == KeyValues.RIGHT:
direction = 1
else:
return
if self.player.equipped_main:
if self.player.equipped_main.throw(direction):
self.map.tick(self.player)
def handle_key_pressed_inventory(self, key: KeyValues) -> None:
"""
@ -302,6 +346,36 @@ class Game:
# Ensure that the cursor has a good position
menu.position = min(menu.position, len(menu.values) - 1)
def handle_key_pressed_chest(self, key: KeyValues) -> None:
"""
In a chest menu, we can take or put items or close the menu.
"""
menu = self.chest_menu if self.is_in_chest_menu else self.inventory_menu
if key == KeyValues.SPACE or key == KeyValues.INVENTORY:
self.state = GameMode.PLAY
elif key == KeyValues.UP:
menu.go_up()
elif key == KeyValues.DOWN:
menu.go_down()
elif key == KeyValues.LEFT:
self.is_in_chest_menu = False
self.display_actions(DisplayActions.UPDATE)
elif key == KeyValues.RIGHT:
self.is_in_chest_menu = True
self.display_actions(DisplayActions.UPDATE)
if menu.values and not self.player.dead:
if key == KeyValues.ENTER:
item = menu.validate()
owner = self.chest_menu.chest if self.is_in_chest_menu \
else self.player
buyer = self.player if self.is_in_chest_menu \
else self.chest_menu.chest
item.be_sold(buyer, owner, for_free=True)
self.display_actions(DisplayActions.UPDATE)
# Ensure that the cursor has a good position
menu.position = min(menu.position, len(menu.values) - 1)
def handle_key_pressed_main_menu(self, key: KeyValues) -> None:
"""
In the main menu, we can navigate through different options.
@ -343,9 +417,10 @@ class Game:
self.maps = [Map().load_state(map_dict) for map_dict in d["maps"]]
for i, m in enumerate(self.maps):
m.floor = i
except KeyError:
except KeyError as error:
self.message = _("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.")\
+ f"\n{error}"
os.unlink(ResourceManager.get_config_path("save.json"))
self.display_actions(DisplayActions.UPDATE)
return
@ -359,6 +434,7 @@ class Game:
return
self.player = players[0]
self.inventory_menu.update_player(self.player)
self.map.compute_visibility(self.player.y, self.player.x,
self.player.vision)
self.display_actions(DisplayActions.UPDATE)

View File

@ -1,13 +1,14 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from enum import Enum, auto
from math import ceil, sqrt
from itertools import product
from random import choice, randint
from typing import List, Optional, Any, Dict, Tuple
from queue import PriorityQueue
from copy import deepcopy
from enum import auto, Enum
from functools import reduce
from itertools import product
from math import ceil, sqrt
from queue import PriorityQueue
from random import choice, choices, randint
from typing import Any, Dict, List, Optional, Tuple
from .display.texturepack import TexturePack
from .translations import gettext as _
@ -180,6 +181,16 @@ class Map:
return "\n".join("".join(tile.char(pack) for tile in line)
for line in self.tiles)
def is_visible_from(self, starty: int, startx: int, desty: int, destx: int,
max_range: int) -> bool:
oldvisibility = deepcopy(self.visibility)
oldseen = deepcopy(self.seen_tiles)
self.compute_visibility(starty, startx, max_range)
result = self.visibility[desty][destx]
self.visibility = oldvisibility
self.seen_tiles = oldseen
return result
def compute_visibility(self, y: int, x: int, max_range: int) -> None:
"""
Sets the visible tiles to be the ones visible by an entity at point
@ -233,9 +244,9 @@ class Map:
continue
is_opaque = self.is_wall(y, x, octant, origin)
is_visible = is_opaque\
or ((y != top_y or top > Slope(y * 4 - 1, x * 4 + 1))
or ((y != top_y or top >= Slope(y, x))
and (y != bottom_y
or bottom < Slope(y * 4 + 1, x * 4 - 1)))
or bottom <= Slope(y, x)))
# is_visible = is_opaque\
# or ((y != top_y or top >= Slope(y, x))
# and (y != bottom_y or bottom <= Slope(y, x)))
@ -603,6 +614,13 @@ class Entity:
from squirrelbattle.entities.friendly import Merchant
return isinstance(self, Merchant)
def is_chest(self) -> bool:
"""
Is this entity a chest?
"""
from squirrelbattle.entities.friendly import Chest
return isinstance(self, Chest)
@property
def translated_name(self) -> str:
"""
@ -619,9 +637,10 @@ class Entity:
from squirrelbattle.entities.monsters import Tiger, Hedgehog, \
Rabbit, TeddyBear, GiantSeaEagle
from squirrelbattle.entities.friendly import Merchant, Sunflower, \
Trumpet
return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear,
Sunflower, Tiger, Merchant, GiantSeaEagle, Trumpet]
Trumpet, Chest
return [BodySnatchPotion, Bomb, Chest, GiantSeaEagle, Heart,
Hedgehog, Merchant, Rabbit, Sunflower, TeddyBear, Tiger,
Trumpet]
@staticmethod
def get_weights() -> list:
@ -629,8 +648,7 @@ class Entity:
Returns a weigth list associated to the above function, to
be used to spawn random entities with a certain probability.
"""
return [3, 5, 6, 5, 5, 5,
5, 4, 4, 1, 2]
return [30, 80, 50, 1, 100, 100, 60, 70, 70, 20, 40, 40]
@staticmethod
def get_all_entity_classes_in_a_dict() -> dict:
@ -641,30 +659,37 @@ class Entity:
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, \
TeddyBear, GiantSeaEagle
from squirrelbattle.entities.friendly import Merchant, Sunflower, \
Trumpet
Trumpet, Chest
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, \
Heart, Monocle, Sword, Shield, Chestplate, Helmet, \
RingCritical, RingXP
Heart, Sword, Shield, Chestplate, Helmet, RingCritical, RingXP, \
ScrollofDamage, ScrollofWeakening, Ruler, Bow, FireBallStaff, \
Monocle
return {
"Bomb": Bomb,
"Chestplate": Chestplate,
"Heart": Heart,
"BodySnatchPotion": BodySnatchPotion,
"Eagle": GiantSeaEagle,
"Bomb": Bomb,
"Bow": Bow,
"Chest": Chest,
"Chestplate": Chestplate,
"FireBallStaff": FireBallStaff,
"GiantSeaEagle": GiantSeaEagle,
"Heart": Heart,
"Hedgehog": Hedgehog,
"Helmet": Helmet,
"Player": Player,
"Merchant": Merchant,
"Monocle": Monocle,
"Sunflower": Sunflower,
"Sword": Sword,
"Trumpet": Trumpet,
"Shield": Shield,
"TeddyBear": TeddyBear,
"Tiger": Tiger,
"Player": Player,
"Rabbit": Rabbit,
"RingCritical": RingCritical,
"RingXP": RingXP,
"Ruler": Ruler,
"ScrollofDamage": ScrollofDamage,
"ScrollofWeakening": ScrollofWeakening,
"Shield": Shield,
"Sunflower": Sunflower,
"Sword": Sword,
"Trumpet": Trumpet,
"TeddyBear": TeddyBear,
"Tiger": Tiger,
}
def save_state(self) -> dict:
@ -692,6 +717,7 @@ class FightingEntity(Entity):
constitution: int
level: int
critical: int
confused: int # Seulement 0 ou 1
def __init__(self, maxhealth: int = 0, health: Optional[int] = None,
strength: int = 0, intelligence: int = 0, charisma: int = 0,
@ -707,6 +733,8 @@ class FightingEntity(Entity):
self.constitution = constitution
self.level = level
self.critical = critical
self.effects = [] # effects = temporary buff or weakening of the stats.
self.confused = 0
@property
def dead(self) -> bool:
@ -715,13 +743,31 @@ class FightingEntity(Entity):
"""
return self.health <= 0
def act(self, m: Map) -> None:
"""
Refreshes all current effects.
"""
for i in range(len(self.effects)):
self.effects[i][2] -= 1
copy = self.effects[:]
for i in range(len(copy)):
if copy[i][2] <= 0:
setattr(self, copy[i][0],
getattr(self, copy[i][0]) - copy[i][1])
self.effects.remove(copy[i])
def hit(self, opponent: "FightingEntity") -> str:
"""
The entity deals damage to the opponent
based on their respective stats.
"""
if self.confused:
return _("{name} is confused, it can not hit {opponent}.")\
.format(name=_(self.translated_name.capitalize()),
opponent=_(opponent.translated_name))
diceroll = randint(1, 100)
damage = self.strength
damage = max(0, self.strength)
string = " "
if diceroll <= self.critical: # It is a critical hit
damage *= 4
@ -736,7 +782,9 @@ class FightingEntity(Entity):
The entity takes damage from the attacker
based on their respective stats.
"""
damage = max(0, amount - self.constitution)
damage = 0
if amount != 0:
damage = max(1, amount - self.constitution)
self.health -= damage
if self.health <= 0:
self.die()

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-08 15:15+0100\n"
"POT-Creation-Date: 2021-01-10 21:30+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,116 +17,158 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ring_of_critical_damage"
msgstr ""
msgid "ring_of_more_experience"
msgstr ""
#, python-brace-format
msgid "{name} takes {amount} damage."
msgstr "{name} nimmt {amount} Schadenspunkte."
#: squirrelbattle/display/creditsdisplay.py:28
#: squirrelbattle/display/menudisplay.py:123
#: squirrelbattle/display/menudisplay.py:148
msgid "Credits"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:32
msgid "Developers:"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:38
msgid "Translators:"
msgstr ""
#: squirrelbattle/display/menudisplay.py:168
msgid "INVENTORY"
msgstr "BESTAND"
#: squirrelbattle/display/menudisplay.py:214
msgid "STALL"
msgstr "STAND"
#: squirrelbattle/display/statsdisplay.py:44
#: squirrelbattle/display/gamedisplay.py:150
msgid "Inventory:"
msgstr "Bestand:"
#: squirrelbattle/display/statsdisplay.py:61
#: squirrelbattle/display/gamedisplay.py:167
msgid "Equipped main:"
msgstr ""
msgstr "Hauptausgestattete Ding"
#: squirrelbattle/display/statsdisplay.py:65
#: squirrelbattle/display/gamedisplay.py:171
msgid "Equipped secondary:"
msgstr ""
msgstr "zusätzlich Ausgestattete Ding"
#: squirrelbattle/display/statsdisplay.py:70
#: squirrelbattle/display/gamedisplay.py:176
msgid "Equipped chestplate:"
msgstr ""
msgstr "Ausgestattet Harnisch"
#: squirrelbattle/display/statsdisplay.py:74
#: squirrelbattle/display/gamedisplay.py:180
msgid "Equipped helmet:"
msgstr ""
msgstr "Ausgestattet Helm"
#: squirrelbattle/display/statsdisplay.py:81
#: squirrelbattle/display/gamedisplay.py:187
msgid "YOU ARE DEAD"
msgstr "SIE WURDEN GESTORBEN"
#: squirrelbattle/display/statsdisplay.py:85
#: squirrelbattle/display/gamedisplay.py:191
#, python-brace-format
msgid "Use {key} to use the ladder"
msgstr ""
msgstr "Nutzen {key} um die Leiter zu nutzen"
#: squirrelbattle/display/statsdisplay.py:94
#: squirrelbattle/display/gamedisplay.py:210
msgid "Move to the friendly entity to talk to it"
msgstr ""
msgstr "Ziehen Sie zu der freundlichen Einheit hin, um mit ihr zu sprechen"
#: squirrelbattle/display/statsdisplay.py:96
#: squirrelbattle/display/gamedisplay.py:212
#, python-brace-format
msgid "Use {key} then move to talk to the entity"
msgstr ""
"Verwenden Sie {key} dann bewegen Sie sich, um mit der Einheit zu sprechen"
#: squirrelbattle/display/menudisplay.py:124
#: squirrelbattle/display/menudisplay.py:149
#: squirrelbattle/display/menudisplay.py:304
msgid "Credits"
msgstr "Abspann"
#: squirrelbattle/display/menudisplay.py:173
msgid "INVENTORY"
msgstr "BESTAND"
#: squirrelbattle/display/menudisplay.py:219
msgid "STALL"
msgstr "STAND"
#: squirrelbattle/display/menudisplay.py:263
msgid "CHEST"
msgstr "KASTE"
#: squirrelbattle/display/menudisplay.py:308
msgid "Developers:"
msgstr "Entwickler:"
#: squirrelbattle/display/menudisplay.py:314
msgid "Translators:"
msgstr "Ubersetzer:"
#. TODO
#: squirrelbattle/entities/friendly.py:33
#: squirrelbattle/entities/friendly.py:38
msgid "I don't sell any squirrel"
msgstr "Ich verkaufe keinen Eichhörnchen."
#: squirrelbattle/entities/friendly.py:55
#: squirrelbattle/entities/friendly.py:68
msgid "You have opened the chest"
msgstr "Sie haben der Kaste geöffnet"
#: squirrelbattle/entities/friendly.py:77
msgid "The chest exploded"
msgstr "Der Kaste explodierte"
#: squirrelbattle/entities/friendly.py:78
msgid "It's not really effective"
msgstr "Es ist nicht wirklich effektiv"
#: squirrelbattle/entities/friendly.py:101
msgid "Flower power!!"
msgstr "Blumenmacht!!"
#: squirrelbattle/entities/friendly.py:55
#: squirrelbattle/entities/friendly.py:101
msgid "The sun is warm today"
msgstr "Die Sonne ist warm heute"
#. The bomb is exploding.
#. Each entity that is close to the bomb takes damages.
#. The player earn XP if the entity was killed.
#: squirrelbattle/entities/items.py:178
#: squirrelbattle/entities/items.py:189
msgid "Bomb is exploding."
msgstr "Die Bombe explodiert."
#: squirrelbattle/entities/items.py:365
#: squirrelbattle/entities/items.py:385
#, python-brace-format
msgid "{player} exchanged its body with {entity}."
msgstr "{player} täuscht seinem Körper mit {entity} aus."
#: squirrelbattle/game.py:200
#: squirrelbattle/entities/items.py:519
msgid ""
"The ennemies have -{max(1, self.held_by.intelligence // 2)}strength for 3 "
"turns"
msgstr ""
"Die Feinde haben 3 Runden lang - {max(1, self.held_by.intelligence // 2)} "
"Stärke"
#: squirrelbattle/entities/items.py:552
#, python-brace-format
msgid "{name}"
msgstr "{name}"
#: squirrelbattle/entities/items.py:600
msgid " is shot by an arrow."
msgstr " wird von einem Pfeil erschossen."
#: squirrelbattle/entities/items.py:622
msgid " is shot by a fire ball."
msgstr " wird von eine Feuerball erschossen."
#: squirrelbattle/entities/player.py:83
msgid "It worked! Nearby ennemies will be confused for 3 turns."
msgstr ""
"Es funktionierte! In der Nähe befindliche Feinde werden 3 Runden lang "
"verwirrt."
#: squirrelbattle/entities/player.py:86
msgid "It worked, but there is no one nearby..."
msgstr "Es hat funktioniert, aber es ist niemand in der Nähe ..."
#: squirrelbattle/entities/player.py:89
msgid "The dance was not effective..."
msgstr "Der Tanz war nicht effektiv ..."
#: squirrelbattle/game.py:214
#, python-brace-format
msgid "The player climbs down to the floor {floor}."
msgstr "Der Spieler klettert auf dem Stock {floor} hinunter."
#: squirrelbattle/game.py:213
#: squirrelbattle/game.py:227
#, python-brace-format
msgid "The player climbs up the floor {floor}."
msgstr "Der Spieler klettert auf dem Stock {floor} hinoben."
#: squirrelbattle/game.py:304 squirrelbattle/tests/game_test.py:603
#: squirrelbattle/game.py:348 squirrelbattle/tests/game_test.py:631
msgid "The buyer does not have enough money"
msgstr "Der Kaufer hat nicht genug Geld"
#: squirrelbattle/game.py:349
#: squirrelbattle/game.py:423
msgid ""
"Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted."
@ -134,7 +176,7 @@ msgstr ""
"In Ihrer Speicherdatei fehlen einige Schlüssel.\n"
"Ihre Speicherung scheint korrupt zu sein. Es wird gelöscht."
#: squirrelbattle/game.py:357
#: squirrelbattle/game.py:431
msgid ""
"No player was found on this map!\n"
"Maybe you died?"
@ -142,7 +184,7 @@ msgstr ""
"Auf dieser Karte wurde kein Spieler gefunden!\n"
"Vielleicht sind Sie gestorben?"
#: squirrelbattle/game.py:379
#: squirrelbattle/game.py:454
msgid ""
"The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted."
@ -150,26 +192,31 @@ msgstr ""
"Die JSON-Datei ist nicht korrekt.\n"
"Ihre Speicherung scheint korrumpiert. Sie wurde gelöscht."
#: squirrelbattle/interfaces.py:718
msgid "It's a critical hit!"
msgstr ""
#: squirrelbattle/interfaces.py:758 squirrelbattle/tests/game_test.py:264
#, python-brace-format
msgid "{name} is confused, it can not hit {opponent}."
msgstr "{name} ist verwirrt, es kann {opponent} nicht schlagen."
#: squirrelbattle/interfaces.py:719
#: squirrelbattle/interfaces.py:766
msgid "It's a critical hit!"
msgstr "Es ist ein kritischer Treffer!"
#: squirrelbattle/interfaces.py:767
#, python-brace-format
msgid "{name} hits {opponent}."
msgstr "{name} schlägt {opponent}."
#: squirrelbattle/interfaces.py:733
#: squirrelbattle/interfaces.py:782
#, python-brace-format
msgid "{name} takes {damage} damage."
msgstr ""
msgstr "{name} erleidet {damage} Schaden."
#: squirrelbattle/interfaces.py:735
#: squirrelbattle/interfaces.py:784
#, python-brace-format
msgid "{name} dies."
msgstr "{name} stirbt."
#: squirrelbattle/interfaces.py:769
#: squirrelbattle/interfaces.py:818
#, python-brace-format
msgid "{entity} said: {message}"
msgstr "{entity} hat gesagt: {message}"
@ -178,8 +225,8 @@ msgstr "{entity} hat gesagt: {message}"
msgid "Back"
msgstr "Zurück"
#: squirrelbattle/tests/game_test.py:368 squirrelbattle/tests/game_test.py:371
#: squirrelbattle/tests/game_test.py:374 squirrelbattle/tests/game_test.py:377
#: squirrelbattle/tests/game_test.py:395 squirrelbattle/tests/game_test.py:398
#: squirrelbattle/tests/game_test.py:401 squirrelbattle/tests/game_test.py:404
#: squirrelbattle/tests/translations_test.py:16
msgid "New game"
msgstr "Neu Spiel"
@ -269,85 +316,113 @@ msgid "Key used to use ladders"
msgstr "Leitertaste"
#: squirrelbattle/tests/translations_test.py:58
msgid "Key used to use a bow"
msgstr "Bogentaste"
#: squirrelbattle/tests/translations_test.py:60
msgid "Key used to dance"
msgstr "Tanztaste"
#: squirrelbattle/tests/translations_test.py:62
msgid "Texture pack"
msgstr "Textur-Packung"
#: squirrelbattle/tests/translations_test.py:59
#: squirrelbattle/tests/translations_test.py:63
msgid "Language"
msgstr "Sprache"
#: squirrelbattle/tests/translations_test.py:62
#: squirrelbattle/tests/translations_test.py:66
msgid "player"
msgstr "Spieler"
#: squirrelbattle/tests/translations_test.py:64
#: squirrelbattle/tests/translations_test.py:68
msgid "hedgehog"
msgstr "Igel"
#: squirrelbattle/tests/translations_test.py:65
#: squirrelbattle/tests/translations_test.py:69
msgid "merchant"
msgstr "Kaufmann"
#: squirrelbattle/tests/translations_test.py:66
#: squirrelbattle/tests/translations_test.py:70
msgid "rabbit"
msgstr "Kanninchen"
#: squirrelbattle/tests/translations_test.py:67
#: squirrelbattle/tests/translations_test.py:71
msgid "sunflower"
msgstr "Sonnenblume"
#: squirrelbattle/tests/translations_test.py:68
#: squirrelbattle/tests/translations_test.py:72
msgid "teddy bear"
msgstr "Teddybär"
#: squirrelbattle/tests/translations_test.py:69
#: squirrelbattle/tests/translations_test.py:73
msgid "tiger"
msgstr "Tiger"
#: squirrelbattle/tests/translations_test.py:70
#: squirrelbattle/tests/translations_test.py:74
msgid "eagle"
msgstr ""
msgstr "Adler"
#: squirrelbattle/tests/translations_test.py:72
#: squirrelbattle/tests/translations_test.py:76
msgid "body snatch potion"
msgstr "Leichenfleddererzaubertrank"
#: squirrelbattle/tests/translations_test.py:73
#: squirrelbattle/tests/translations_test.py:77
msgid "bomb"
msgstr "Bombe"
#: squirrelbattle/tests/translations_test.py:74
#: squirrelbattle/tests/translations_test.py:78
msgid "explosion"
msgstr "Explosion"
#: squirrelbattle/tests/translations_test.py:75
#: squirrelbattle/tests/translations_test.py:79
msgid "heart"
msgstr "Herz"
#: squirrelbattle/tests/translations_test.py:76
#: squirrelbattle/tests/translations_test.py:80
msgid "sword"
msgstr "schwert"
#: squirrelbattle/tests/translations_test.py:77
#: squirrelbattle/tests/translations_test.py:81
msgid "helmet"
msgstr ""
#: squirrelbattle/tests/translations_test.py:78
msgid "chestplate"
msgstr ""
#: squirrelbattle/tests/translations_test.py:79
msgid "shield"
msgstr ""
#: squirrelbattle/tests/translations_test.py:80
msgid "ring of critical damage"
msgstr ""
msgstr "Helm"
#: squirrelbattle/tests/translations_test.py:82
msgid "ring of more experience"
msgstr ""
msgid "chestplate"
msgstr "Brustpanzer"
#: squirrelbattle/tests/translations_test.py:83
msgid "shield"
msgstr "Schild"
#: squirrelbattle/tests/translations_test.py:84
msgid "ruler"
msgstr "Lineal"
#: squirrelbattle/tests/translations_test.py:85
msgid "scroll of damage"
msgstr "Schriftrolle des Schadens"
#: squirrelbattle/tests/translations_test.py:86
msgid "scroll of weakness"
msgstr "Schriftrolle der Schwäche"
#: squirrelbattle/tests/translations_test.py:87
msgid "bow"
msgstr "Bogen"
#: squirrelbattle/tests/translations_test.py:88
msgid "fire ball staff"
msgstr "Feuerball Stab"
#: squirrelbattle/tests/translations_test.py:89
msgid "ring of critical damage"
msgstr "Ring des kritischen Schadens"
#: squirrelbattle/tests/translations_test.py:91
msgid "ring of more experience"
msgstr "Ring der mehr Erfahrung"
#: squirrelbattle/tests/translations_test.py:93
msgid "monocle"
msgstr ""
msgstr "Monokel"

View File

@ -1,207 +0,0 @@
# 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 ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-08 15:15+0100\n"
"POT-Creation-Date: 2021-01-10 21:30+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,115 +17,154 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ring_of_critical_damage"
msgstr ""
msgid "ring_of_more_experience"
msgstr ""
#, python-brace-format
msgid "{name} takes {amount} damage."
msgstr "{name} recibe {amount} daño."
#: squirrelbattle/display/creditsdisplay.py:28
#: squirrelbattle/display/menudisplay.py:123
#: squirrelbattle/display/menudisplay.py:148
msgid "Credits"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:32
msgid "Developers:"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:38
msgid "Translators:"
msgstr ""
#: squirrelbattle/display/menudisplay.py:168
msgid "INVENTORY"
msgstr "INVENTORIO"
#: squirrelbattle/display/menudisplay.py:214
msgid "STALL"
msgstr "PUESTO"
#: squirrelbattle/display/statsdisplay.py:44
#: squirrelbattle/display/gamedisplay.py:150
msgid "Inventory:"
msgstr "Inventorio :"
#: squirrelbattle/display/statsdisplay.py:61
#: squirrelbattle/display/gamedisplay.py:167
msgid "Equipped main:"
msgstr ""
msgstr "Principal equipado:"
#: squirrelbattle/display/statsdisplay.py:65
#: squirrelbattle/display/gamedisplay.py:171
msgid "Equipped secondary:"
msgstr ""
msgstr "Equipado secundario:"
#: squirrelbattle/display/statsdisplay.py:70
#: squirrelbattle/display/gamedisplay.py:176
msgid "Equipped chestplate:"
msgstr ""
msgstr "Pechera equipada:"
#: squirrelbattle/display/statsdisplay.py:74
#: squirrelbattle/display/gamedisplay.py:180
msgid "Equipped helmet:"
msgstr ""
msgstr "Casco equipado:"
#: squirrelbattle/display/statsdisplay.py:81
#: squirrelbattle/display/gamedisplay.py:187
msgid "YOU ARE DEAD"
msgstr "ERES MUERTO"
#: squirrelbattle/display/statsdisplay.py:85
#: squirrelbattle/display/gamedisplay.py:191
#, python-brace-format
msgid "Use {key} to use the ladder"
msgstr ""
msgstr "Usa {key} para usar la escalera"
#: squirrelbattle/display/statsdisplay.py:94
#: squirrelbattle/display/gamedisplay.py:210
msgid "Move to the friendly entity to talk to it"
msgstr ""
msgstr "Muévete hacia la entidad amiga para hablar con ella."
#: squirrelbattle/display/statsdisplay.py:96
#: squirrelbattle/display/gamedisplay.py:212
#, python-brace-format
msgid "Use {key} then move to talk to the entity"
msgstr ""
msgstr "Usa {key} y luego muévete para hablar con la entidad"
#: squirrelbattle/entities/friendly.py:33
#: squirrelbattle/display/menudisplay.py:124
#: squirrelbattle/display/menudisplay.py:149
#: squirrelbattle/display/menudisplay.py:304
msgid "Credits"
msgstr "Creditos"
#: squirrelbattle/display/menudisplay.py:173
msgid "INVENTORY"
msgstr "INVENTORIO"
#: squirrelbattle/display/menudisplay.py:219
msgid "STALL"
msgstr "PUESTO"
#: squirrelbattle/display/menudisplay.py:263
msgid "CHEST"
msgstr "COFRE"
#: squirrelbattle/display/menudisplay.py:308
msgid "Developers:"
msgstr "Desarrollador:"
#: squirrelbattle/display/menudisplay.py:314
msgid "Translators:"
msgstr "Traductores:"
#: squirrelbattle/entities/friendly.py:38
msgid "I don't sell any squirrel"
msgstr "No vendo ninguna ardilla"
#: squirrelbattle/entities/friendly.py:55
#: squirrelbattle/entities/friendly.py:68
msgid "You have opened the chest"
msgstr "Abriste el cofre"
#: squirrelbattle/entities/friendly.py:77
msgid "The chest exploded"
msgstr "El cofre explotó"
#: squirrelbattle/entities/friendly.py:78
msgid "It's not really effective"
msgstr "No es realmente efectivo"
#: squirrelbattle/entities/friendly.py:101
msgid "Flower power!!"
msgstr "Poder de las flores!!"
#: squirrelbattle/entities/friendly.py:55
#: squirrelbattle/entities/friendly.py:101
msgid "The sun is warm today"
msgstr "El sol está caliente hoy"
#. The bomb is exploding.
#. Each entity that is close to the bomb takes damages.
#. The player earn XP if the entity was killed.
#: squirrelbattle/entities/items.py:178
#: squirrelbattle/entities/items.py:189
msgid "Bomb is exploding."
msgstr "La bomba está explotando."
#: squirrelbattle/entities/items.py:365
#: squirrelbattle/entities/items.py:385
#, python-brace-format
msgid "{player} exchanged its body with {entity}."
msgstr "{player} intercambió su cuerpo con {entity}."
#: squirrelbattle/game.py:200
#: squirrelbattle/entities/items.py:519
msgid ""
"The ennemies have -{max(1, self.held_by.intelligence // 2)}strength for 3 "
"turns"
msgstr ""
"Los enemigos tienen - {max(1, self.held_by.intelligence // 2)} fuerza "
"durante 3turnos"
#: squirrelbattle/entities/items.py:552
#, python-brace-format
msgid "{name}"
msgstr "{name}"
#: squirrelbattle/entities/items.py:600
msgid " is shot by an arrow."
msgstr " es disparado por una flecha."
#: squirrelbattle/entities/items.py:622
msgid " is shot by a fire ball."
msgstr " es disparado por una bola de fuego."
#: squirrelbattle/entities/player.py:83
msgid "It worked! Nearby ennemies will be confused for 3 turns."
msgstr "¡Funcionó! Los enemigos cercanos se confundirán durante 3 turnos."
#: squirrelbattle/entities/player.py:86
msgid "It worked, but there is no one nearby..."
msgstr "Funcionó, pero no hay nadie cerca ..."
#: squirrelbattle/entities/player.py:89
msgid "The dance was not effective..."
msgstr "El baile no fue efectivo ..."
#: squirrelbattle/game.py:214
#, python-brace-format
msgid "The player climbs down to the floor {floor}."
msgstr ""
msgstr "El jugador desciende alla planta {floor}."
#: squirrelbattle/game.py:213
#: squirrelbattle/game.py:227
#, python-brace-format
msgid "The player climbs up the floor {floor}."
msgstr ""
msgstr "El jugador sube por la planta {floor}."
#: squirrelbattle/game.py:304 squirrelbattle/tests/game_test.py:603
#: squirrelbattle/game.py:348 squirrelbattle/tests/game_test.py:631
msgid "The buyer does not have enough money"
msgstr "El comprador no tiene suficiente dinero"
#: squirrelbattle/game.py:349
#: squirrelbattle/game.py:423
msgid ""
"Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted."
@ -133,7 +172,7 @@ msgstr ""
"Algunas claves faltan en su archivo de guarda.\n"
"Su guarda parece a ser corruptido. Fue eliminado."
#: squirrelbattle/game.py:357
#: squirrelbattle/game.py:431
msgid ""
"No player was found on this map!\n"
"Maybe you died?"
@ -141,7 +180,7 @@ msgstr ""
"No jugador encontrado sobre la carta !\n"
"¿ Quizas murió ?"
#: squirrelbattle/game.py:379
#: squirrelbattle/game.py:454
msgid ""
"The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted."
@ -149,26 +188,31 @@ msgstr ""
"El JSON archivo no es correcto.\n"
"Su guarda parece corrupta. Fue eliminada."
#: squirrelbattle/interfaces.py:718
msgid "It's a critical hit!"
msgstr ""
#: squirrelbattle/interfaces.py:758 squirrelbattle/tests/game_test.py:264
#, python-brace-format
msgid "{name} is confused, it can not hit {opponent}."
msgstr "{name} está confundido, no puede golpear a {opponent}."
#: squirrelbattle/interfaces.py:719
#: squirrelbattle/interfaces.py:766
msgid "It's a critical hit!"
msgstr "¡Es un golpe crítico!"
#: squirrelbattle/interfaces.py:767
#, python-brace-format
msgid "{name} hits {opponent}."
msgstr "{name} golpea a {opponent}."
#: squirrelbattle/interfaces.py:733
#: squirrelbattle/interfaces.py:782
#, python-brace-format
msgid "{name} takes {damage} damage."
msgstr ""
msgstr "{name} recibe {damage} daño."
#: squirrelbattle/interfaces.py:735
#: squirrelbattle/interfaces.py:784
#, python-brace-format
msgid "{name} dies."
msgstr "{name} se muere."
#: squirrelbattle/interfaces.py:769
#: squirrelbattle/interfaces.py:818
#, python-brace-format
msgid "{entity} said: {message}"
msgstr "{entity} dijo : {message}"
@ -177,8 +221,8 @@ msgstr "{entity} dijo : {message}"
msgid "Back"
msgstr "Volver"
#: squirrelbattle/tests/game_test.py:368 squirrelbattle/tests/game_test.py:371
#: squirrelbattle/tests/game_test.py:374 squirrelbattle/tests/game_test.py:377
#: squirrelbattle/tests/game_test.py:395 squirrelbattle/tests/game_test.py:398
#: squirrelbattle/tests/game_test.py:401 squirrelbattle/tests/game_test.py:404
#: squirrelbattle/tests/translations_test.py:16
msgid "New game"
msgstr "Nuevo partido"
@ -268,85 +312,113 @@ msgid "Key used to use ladders"
msgstr "Tecla para el uso de las escaleras"
#: squirrelbattle/tests/translations_test.py:58
msgid "Key used to use a bow"
msgstr "Tecla para usar un arco"
#: squirrelbattle/tests/translations_test.py:60
msgid "Key used to dance"
msgstr "Tecla para bailar"
#: squirrelbattle/tests/translations_test.py:62
msgid "Texture pack"
msgstr "Paquete de texturas"
#: squirrelbattle/tests/translations_test.py:59
#: squirrelbattle/tests/translations_test.py:63
msgid "Language"
msgstr "Languaje"
#: squirrelbattle/tests/translations_test.py:62
#: squirrelbattle/tests/translations_test.py:66
msgid "player"
msgstr "jugador"
#: squirrelbattle/tests/translations_test.py:64
#: squirrelbattle/tests/translations_test.py:68
msgid "hedgehog"
msgstr "erizo"
#: squirrelbattle/tests/translations_test.py:65
#: squirrelbattle/tests/translations_test.py:69
msgid "merchant"
msgstr "comerciante"
#: squirrelbattle/tests/translations_test.py:66
#: squirrelbattle/tests/translations_test.py:70
msgid "rabbit"
msgstr "conejo"
#: squirrelbattle/tests/translations_test.py:67
#: squirrelbattle/tests/translations_test.py:71
msgid "sunflower"
msgstr "girasol"
#: squirrelbattle/tests/translations_test.py:68
#: squirrelbattle/tests/translations_test.py:72
msgid "teddy bear"
msgstr "osito de peluche"
#: squirrelbattle/tests/translations_test.py:69
#: squirrelbattle/tests/translations_test.py:73
msgid "tiger"
msgstr "tigre"
#: squirrelbattle/tests/translations_test.py:70
#: squirrelbattle/tests/translations_test.py:74
msgid "eagle"
msgstr ""
msgstr "águila"
#: squirrelbattle/tests/translations_test.py:72
#: squirrelbattle/tests/translations_test.py:76
msgid "body snatch potion"
msgstr "poción de intercambio"
#: squirrelbattle/tests/translations_test.py:73
#: squirrelbattle/tests/translations_test.py:77
msgid "bomb"
msgstr "bomba"
#: squirrelbattle/tests/translations_test.py:74
#: squirrelbattle/tests/translations_test.py:78
msgid "explosion"
msgstr "explosión"
#: squirrelbattle/tests/translations_test.py:75
#: squirrelbattle/tests/translations_test.py:79
msgid "heart"
msgstr "corazón"
#: squirrelbattle/tests/translations_test.py:76
#: squirrelbattle/tests/translations_test.py:80
msgid "sword"
msgstr "espada"
#: squirrelbattle/tests/translations_test.py:77
#: squirrelbattle/tests/translations_test.py:81
msgid "helmet"
msgstr ""
#: squirrelbattle/tests/translations_test.py:78
msgid "chestplate"
msgstr ""
#: squirrelbattle/tests/translations_test.py:79
msgid "shield"
msgstr ""
#: squirrelbattle/tests/translations_test.py:80
msgid "ring of critical damage"
msgstr ""
msgstr "casco"
#: squirrelbattle/tests/translations_test.py:82
msgid "ring of more experience"
msgstr ""
msgid "chestplate"
msgstr "pechera"
#: squirrelbattle/tests/translations_test.py:83
msgid "shield"
msgstr "escudo"
#: squirrelbattle/tests/translations_test.py:84
msgid "ruler"
msgstr "Regla"
#: squirrelbattle/tests/translations_test.py:85
msgid "scroll of damage"
msgstr "rollo de daño"
#: squirrelbattle/tests/translations_test.py:86
msgid "scroll of weakness"
msgstr "rollo de debilidad"
#: squirrelbattle/tests/translations_test.py:87
msgid "bow"
msgstr "arco"
#: squirrelbattle/tests/translations_test.py:88
msgid "fire ball staff"
msgstr "bastón de bola de fuego"
#: squirrelbattle/tests/translations_test.py:89
msgid "ring of critical damage"
msgstr "anillo de daño crítico"
#: squirrelbattle/tests/translations_test.py:91
msgid "ring of more experience"
msgstr "anillo de más experiencia"
#: squirrelbattle/tests/translations_test.py:93
msgid "monocle"
msgstr ""
msgstr "monóculo"

View File

@ -1,3 +1,7 @@
#, python-brace-format
msgid "{name} takes {amount} damage."
msgstr "{name} prend {amount} points de dégât."
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ÿnérant, eichhornchen, nicomarg, charlse, ifugao
# This file is distributed under the same license as the squirrelbattle package.
@ -8,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: squirrelbattle 3.14.1\n"
"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n"
"POT-Creation-Date: 2021-01-08 15:15+0100\n"
"POT-Creation-Date: 2021-01-10 21:30+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,110 +21,155 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#, python-brace-format
msgid "{name} takes {amount} damage."
msgstr "{name} prend {amount} points de dégât."
#: squirrelbattle/display/creditsdisplay.py:28
#: squirrelbattle/display/menudisplay.py:123
#: squirrelbattle/display/menudisplay.py:148
msgid "Credits"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:32
msgid "Developers:"
msgstr ""
#: squirrelbattle/display/creditsdisplay.py:38
msgid "Translators:"
msgstr ""
#: squirrelbattle/display/menudisplay.py:168
msgid "INVENTORY"
msgstr "INVENTAIRE"
#: squirrelbattle/display/menudisplay.py:214
msgid "STALL"
msgstr "STAND"
#: squirrelbattle/display/statsdisplay.py:44
#: squirrelbattle/display/gamedisplay.py:150
msgid "Inventory:"
msgstr "Inventaire :"
#: squirrelbattle/display/statsdisplay.py:61
#: squirrelbattle/display/gamedisplay.py:167
msgid "Equipped main:"
msgstr "Équipement principal :"
#: squirrelbattle/display/statsdisplay.py:65
#: squirrelbattle/display/gamedisplay.py:171
msgid "Equipped secondary:"
msgstr "Équipement secondaire :"
#: squirrelbattle/display/statsdisplay.py:70
#: squirrelbattle/display/gamedisplay.py:176
msgid "Equipped chestplate:"
msgstr "Plastron équipé :"
#: squirrelbattle/display/statsdisplay.py:74
#: squirrelbattle/display/gamedisplay.py:180
msgid "Equipped helmet:"
msgstr "Casque équipé :"
#: squirrelbattle/display/statsdisplay.py:81
#: squirrelbattle/display/gamedisplay.py:187
msgid "YOU ARE DEAD"
msgstr "VOUS ÊTES MORT"
#: squirrelbattle/display/statsdisplay.py:85
#: squirrelbattle/display/gamedisplay.py:191
#, python-brace-format
msgid "Use {key} to use the ladder"
msgstr "Appuyez sur {key} pour utiliser l'échelle"
#: squirrelbattle/display/statsdisplay.py:94
#: squirrelbattle/display/gamedisplay.py:210
msgid "Move to the friendly entity to talk to it"
msgstr "Avancez vers l'entité pour lui parler"
#: squirrelbattle/display/statsdisplay.py:96
#: squirrelbattle/display/gamedisplay.py:212
#, python-brace-format
msgid "Use {key} then move to talk to the entity"
msgstr "Appuyez sur {key} puis déplacez-vous pour parler"
#: squirrelbattle/display/menudisplay.py:124
#: squirrelbattle/display/menudisplay.py:149
#: squirrelbattle/display/menudisplay.py:304
msgid "Credits"
msgstr "Crédits"
#: squirrelbattle/display/menudisplay.py:173
msgid "INVENTORY"
msgstr "INVENTAIRE"
#: squirrelbattle/display/menudisplay.py:219
msgid "STALL"
msgstr "STAND"
#: squirrelbattle/display/menudisplay.py:263
msgid "CHEST"
msgstr "COFFRE"
#: squirrelbattle/display/menudisplay.py:308
msgid "Developers:"
msgstr "Développeurs:"
#: squirrelbattle/display/menudisplay.py:314
msgid "Translators:"
msgstr "Traducteurs:"
#. TODO
#: squirrelbattle/entities/friendly.py:33
#: squirrelbattle/entities/friendly.py:38
msgid "I don't sell any squirrel"
msgstr "Je ne vends pas d'écureuil"
#: squirrelbattle/entities/friendly.py:55
#: squirrelbattle/entities/friendly.py:68
msgid "You have opened the chest"
msgstr "Vous avez ouvert le coffre"
#: squirrelbattle/entities/friendly.py:77
msgid "The chest exploded"
msgstr "Le coffre a explosé"
#: squirrelbattle/entities/friendly.py:78
msgid "It's not really effective"
msgstr "Ce n'est pas très efficace"
#: squirrelbattle/entities/friendly.py:101
msgid "Flower power!!"
msgstr "Pouvoir des fleurs !!"
#: squirrelbattle/entities/friendly.py:55
#: squirrelbattle/entities/friendly.py:101
msgid "The sun is warm today"
msgstr "Le soleil est chaud aujourd'hui"
#. The bomb is exploding.
#. Each entity that is close to the bomb takes damages.
#. The player earn XP if the entity was killed.
#: squirrelbattle/entities/items.py:178
#: squirrelbattle/entities/items.py:189
msgid "Bomb is exploding."
msgstr "La bombe explose."
#: squirrelbattle/entities/items.py:365
#: squirrelbattle/entities/items.py:385
#, python-brace-format
msgid "{player} exchanged its body with {entity}."
msgstr "{player} a échangé son corps avec {entity}."
#: squirrelbattle/game.py:200
#: squirrelbattle/entities/items.py:519
msgid ""
"The ennemies have -{max(1, self.held_by.intelligence // 2)}strength for 3 "
"turns"
msgstr ""
"Les ennemis ont -{max(1, self.held_by.intelligence // 2)} de force pour 3 "
"tours"
#: squirrelbattle/entities/items.py:552
#, python-brace-format
msgid "{name}"
msgstr "{name}"
#: squirrelbattle/entities/items.py:600
msgid " is shot by an arrow."
msgstr " est frappé par une flèche."
#: squirrelbattle/entities/items.py:622
msgid " is shot by a fire ball."
msgstr " est frappé par une boule de feu."
#: squirrelbattle/entities/player.py:83
msgid "It worked! Nearby ennemies will be confused for 3 turns."
msgstr "Ça a marché ! Les ennemis proches seront confus pendant 3 tours"
#: squirrelbattle/entities/player.py:86
msgid "It worked, but there is no one nearby..."
msgstr "Ça a marché, mais il n'y a personne à proximité..."
#: squirrelbattle/entities/player.py:89
msgid "The dance was not effective..."
msgstr "La dance n'a pas fonctionné..."
#: squirrelbattle/game.py:214
#, python-brace-format
msgid "The player climbs down to the floor {floor}."
msgstr "Le joueur descend à l'étage {floor}."
#: squirrelbattle/game.py:213
#: squirrelbattle/game.py:227
#, python-brace-format
msgid "The player climbs up the floor {floor}."
msgstr "Le joueur monte à l'étage {floor}."
#: squirrelbattle/game.py:304 squirrelbattle/tests/game_test.py:603
#: squirrelbattle/game.py:348 squirrelbattle/tests/game_test.py:631
msgid "The buyer does not have enough money"
msgstr "L'acheteur n'a pas assez d'argent"
#: squirrelbattle/game.py:349
#: squirrelbattle/game.py:423
msgid ""
"Some keys are missing in your save file.\n"
"Your save seems to be corrupt. It got deleted."
@ -128,7 +177,7 @@ msgstr ""
"Certaines clés de votre ficher de sauvegarde sont manquantes.\n"
"Votre sauvegarde semble corrompue. Elle a été supprimée."
#: squirrelbattle/game.py:357
#: squirrelbattle/game.py:431
msgid ""
"No player was found on this map!\n"
"Maybe you died?"
@ -136,7 +185,7 @@ msgstr ""
"Aucun joueur n'a été trouvé sur la carte !\n"
"Peut-être êtes-vous mort ?"
#: squirrelbattle/game.py:379
#: squirrelbattle/game.py:454
msgid ""
"The JSON file is not correct.\n"
"Your save seems corrupted. It got deleted."
@ -144,26 +193,31 @@ msgstr ""
"Le fichier JSON de sauvegarde est incorrect.\n"
"Votre sauvegarde semble corrompue. Elle a été supprimée."
#: squirrelbattle/interfaces.py:718
#: squirrelbattle/interfaces.py:758 squirrelbattle/tests/game_test.py:264
#, python-brace-format
msgid "{name} is confused, it can not hit {opponent}."
msgstr "{name} est confus et ne peut pas frapper {opponent}."
#: squirrelbattle/interfaces.py:766
msgid "It's a critical hit!"
msgstr "C'est un coup critique !"
#: squirrelbattle/interfaces.py:719
#: squirrelbattle/interfaces.py:767
#, python-brace-format
msgid "{name} hits {opponent}."
msgstr "{name} frappe {opponent}."
#: squirrelbattle/interfaces.py:733
#: squirrelbattle/interfaces.py:782
#, python-brace-format
msgid "{name} takes {damage} damage."
msgstr "{name} prend {damage} dégâts."
#: squirrelbattle/interfaces.py:735
#: squirrelbattle/interfaces.py:784
#, python-brace-format
msgid "{name} dies."
msgstr "{name} meurt."
#: squirrelbattle/interfaces.py:769
#: squirrelbattle/interfaces.py:818
#, python-brace-format
msgid "{entity} said: {message}"
msgstr "{entity} a dit : {message}"
@ -172,8 +226,8 @@ msgstr "{entity} a dit : {message}"
msgid "Back"
msgstr "Retour"
#: squirrelbattle/tests/game_test.py:368 squirrelbattle/tests/game_test.py:371
#: squirrelbattle/tests/game_test.py:374 squirrelbattle/tests/game_test.py:377
#: squirrelbattle/tests/game_test.py:395 squirrelbattle/tests/game_test.py:398
#: squirrelbattle/tests/game_test.py:401 squirrelbattle/tests/game_test.py:404
#: squirrelbattle/tests/translations_test.py:16
msgid "New game"
msgstr "Nouvelle partie"
@ -263,85 +317,113 @@ msgid "Key used to use ladders"
msgstr "Touche pour utiliser les échelles"
#: squirrelbattle/tests/translations_test.py:58
msgid "Key used to use a bow"
msgstr "Touche pour utiliser un arc"
#: squirrelbattle/tests/translations_test.py:60
msgid "Key used to dance"
msgstr "Touche pour danser"
#: squirrelbattle/tests/translations_test.py:62
msgid "Texture pack"
msgstr "Pack de textures"
#: squirrelbattle/tests/translations_test.py:59
#: squirrelbattle/tests/translations_test.py:63
msgid "Language"
msgstr "Langue"
#: squirrelbattle/tests/translations_test.py:62
#: squirrelbattle/tests/translations_test.py:66
msgid "player"
msgstr "joueur"
#: squirrelbattle/tests/translations_test.py:64
#: squirrelbattle/tests/translations_test.py:68
msgid "hedgehog"
msgstr "hérisson"
#: squirrelbattle/tests/translations_test.py:65
#: squirrelbattle/tests/translations_test.py:69
msgid "merchant"
msgstr "marchand"
#: squirrelbattle/tests/translations_test.py:66
#: squirrelbattle/tests/translations_test.py:70
msgid "rabbit"
msgstr "lapin"
#: squirrelbattle/tests/translations_test.py:67
#: squirrelbattle/tests/translations_test.py:71
msgid "sunflower"
msgstr "tournesol"
#: squirrelbattle/tests/translations_test.py:68
#: squirrelbattle/tests/translations_test.py:72
msgid "teddy bear"
msgstr "nounours"
#: squirrelbattle/tests/translations_test.py:69
#: squirrelbattle/tests/translations_test.py:73
msgid "tiger"
msgstr "tigre"
#: squirrelbattle/tests/translations_test.py:70
#: squirrelbattle/tests/translations_test.py:74
msgid "eagle"
msgstr "pygargue"
#: squirrelbattle/tests/translations_test.py:72
#: squirrelbattle/tests/translations_test.py:76
msgid "body snatch potion"
msgstr "potion d'arrachage de corps"
#: squirrelbattle/tests/translations_test.py:73
#: squirrelbattle/tests/translations_test.py:77
msgid "bomb"
msgstr "bombe"
#: squirrelbattle/tests/translations_test.py:74
#: squirrelbattle/tests/translations_test.py:78
msgid "explosion"
msgstr "explosion"
#: squirrelbattle/tests/translations_test.py:75
#: squirrelbattle/tests/translations_test.py:79
msgid "heart"
msgstr "cœur"
#: squirrelbattle/tests/translations_test.py:76
#: squirrelbattle/tests/translations_test.py:80
msgid "sword"
msgstr "épée"
#: squirrelbattle/tests/translations_test.py:77
#: squirrelbattle/tests/translations_test.py:81
msgid "helmet"
msgstr "casque"
#: squirrelbattle/tests/translations_test.py:78
#: squirrelbattle/tests/translations_test.py:82
msgid "chestplate"
msgstr "plastron"
#: squirrelbattle/tests/translations_test.py:79
#: squirrelbattle/tests/translations_test.py:83
msgid "shield"
msgstr "bouclier"
#: squirrelbattle/tests/translations_test.py:80
#: squirrelbattle/tests/translations_test.py:84
msgid "ruler"
msgstr "règle"
#: squirrelbattle/tests/translations_test.py:85
msgid "scroll of damage"
msgstr "parchemin de dégâts"
#: squirrelbattle/tests/translations_test.py:86
msgid "scroll of weakness"
msgstr "parchemin de faiblesse"
#: squirrelbattle/tests/translations_test.py:87
msgid "bow"
msgstr "arc"
#: squirrelbattle/tests/translations_test.py:88
msgid "fire ball staff"
msgstr "baton de boule de feu"
#: squirrelbattle/tests/translations_test.py:89
msgid "ring of critical damage"
msgstr "anneau de coup critique"
#: squirrelbattle/tests/translations_test.py:82
#: squirrelbattle/tests/translations_test.py:91
msgid "ring of more experience"
msgstr "anneau de plus d'expérience"
#: squirrelbattle/tests/translations_test.py:84
#: squirrelbattle/tests/translations_test.py:93
msgid "monocle"
msgstr "monocle"

View File

@ -1,13 +1,13 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from enum import Enum
from typing import Any, Optional
from .display.texturepack import TexturePack
from .entities.friendly import Chest, Merchant
from .entities.player import Player
from .entities.friendly import Merchant
from .enums import GameMode, KeyValues, DisplayActions
from .enums import DisplayActions, GameMode, KeyValues
from .settings import Settings
from .translations import gettext as _, Translator
@ -158,3 +158,23 @@ class StoreMenu(Menu):
Returns the values of the menu.
"""
return self.merchant.inventory if self.merchant else []
class ChestMenu(Menu):
"""
A special instance of a menu : the menu for the inventory of a chest.
"""
chest: Chest = None
def update_chest(self, chest: Chest) -> None:
"""
Updates the player.
"""
self.chest = chest
@property
def values(self) -> list:
"""
Returns the values of the menu.
"""
return self.chest.inventory if self.chest else []

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from pathlib import Path

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import json
@ -35,6 +35,8 @@ class Settings:
self.KEY_CHAT = ['t', 'Key used to talk to a friendly entity']
self.KEY_WAIT = ['w', 'Key used to wait']
self.KEY_LADDER = ['<', 'Key used to use ladders']
self.KEY_LAUNCH = ['l', 'Key used to use a bow']
self.KEY_DANCE = ['y', 'Key used to dance']
self.TEXTURE_PACK = ['ascii', 'Texture pack']
self.LOCALE = [locale.getlocale()[0][:2], 'Language']

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses

View File

@ -1,2 +1,2 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later

View File

@ -1,16 +1,16 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import random
import unittest
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart, Item, \
Explosion
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit,\
TeddyBear, GiantSeaEagle
from squirrelbattle.entities.friendly import Trumpet
from squirrelbattle.entities.player import Player
from squirrelbattle.interfaces import Entity, Map
from squirrelbattle.resources import ResourceManager
from ..entities.friendly import Chest, Trumpet
from ..entities.items import BodySnatchPotion, Bomb, Explosion, Heart, Item
from ..entities.monsters import GiantSeaEagle, Hedgehog, Rabbit, \
TeddyBear, Tiger
from ..entities.player import Player
from ..interfaces import Entity, Map
from ..resources import ResourceManager
class TestEntities(unittest.TestCase):
@ -45,18 +45,19 @@ class TestEntities(unittest.TestCase):
"""
entity = Tiger()
self.map.add_entity(entity)
self.assertEqual(entity.maxhealth, 20)
self.assertEqual(entity.maxhealth, 30)
self.assertEqual(entity.maxhealth, entity.health)
self.assertEqual(entity.strength, 2)
for _ in range(9):
self.assertEqual(entity.strength, 5)
for _ in range(5):
self.assertEqual(entity.hit(entity),
"Tiger hits tiger. Tiger takes 2 damage.")
"Tiger hits tiger. Tiger takes 5 damage.")
self.assertFalse(entity.dead)
self.assertEqual(entity.hit(entity), "Tiger hits tiger. "
+ "Tiger takes 2 damage. Tiger dies.")
+ "Tiger takes 5 damage. Tiger dies.")
self.assertTrue(entity.dead)
entity = Rabbit()
entity.health = 15
entity.critical = 0
self.map.add_entity(entity)
entity.move(15, 44)
@ -94,7 +95,20 @@ class TestEntities(unittest.TestCase):
self.assertTrue(entity.dead)
self.assertGreaterEqual(self.player.current_xp, 3)
# Test the familiars
# Test that a chest is destroyed by a bomb
bomb = Bomb()
bomb.owner = self.player
bomb.move(3, 6)
self.map.add_entity(bomb)
chest = Chest()
chest.move(4, 6)
self.map.add_entity(chest)
bomb.exploding = True
for _ in range(5):
self.map.tick(self.player)
self.assertTrue(chest.annihilated)
def test_familiar(self) -> None:
fam = Trumpet()
entity = Rabbit()
self.map.add_entity(entity)
@ -266,6 +280,15 @@ class TestEntities(unittest.TestCase):
player_state = player.save_state()
self.assertEqual(player_state["current_xp"], 10)
player = Player()
player.map = self.map
player.add_xp(700)
for _ in range(13):
player.level_up()
self.assertEqual(player.level, 12)
self.assertEqual(player.critical, 5 + 95 // 30)
self.assertEqual(player.charisma, 3)
def test_critical_hit(self) -> None:
"""
Ensure that critical hits are working.

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import curses
@ -8,13 +8,14 @@ import unittest
from ..bootstrap import Bootstrap
from ..display.display import Display
from ..display.display_manager import DisplayManager
from ..entities.friendly import Merchant, Sunflower
from ..entities.items import Bomb, Heart, Sword, Explosion, Shield, Helmet, \
Chestplate, RingCritical, Monocle
from ..entities.monsters import GiantSeaEagle
from ..entities.friendly import Chest, Merchant, Sunflower
from ..entities.items import Bomb, Bow, Chestplate, Explosion, FireBallStaff, \
Heart, Helmet, Monocle, RingCritical, ScrollofDamage, ScrollofWeakening, \
Shield, Sword
from ..entities.monsters import GiantSeaEagle, Rabbit
from ..entities.player import Player
from ..enums import DisplayActions
from ..game import Game, KeyValues, GameMode
from ..enums import DisplayActions, GameMode, KeyValues
from ..game import Game
from ..interfaces import Map, Tile
from ..menus import MainMenuValues
from ..resources import ResourceManager
@ -159,6 +160,9 @@ class TestGame(unittest.TestCase):
KeyValues.SPACE)
self.assertEqual(KeyValues.translate_key('plop', self.game.settings),
None)
self.assertEqual(KeyValues.translate_key(
self.game.settings.KEY_DANCE, self.game.settings),
KeyValues.DANCE)
def test_key_press(self) -> None:
"""
@ -254,6 +258,28 @@ class TestGame(unittest.TestCase):
self.game.handle_key_pressed(KeyValues.WAIT)
self.assertNotIn(explosion, self.game.map.entities)
rabbit = Rabbit()
self.game.map.add_entity(rabbit)
self.game.player.move(1, 6)
rabbit.move(3, 6)
self.game.player.charisma = 11
self.game.handle_key_pressed(KeyValues.DANCE)
self.assertEqual(rabbit.confused, 1)
string = rabbit.hit(self.game.player)
self.assertEqual(
string, _("{name} is confused, it can not hit {opponent}.")
.format(name=rabbit.translated_name.capitalize(),
opponent=self.game.player.translated_name))
rabbit.confused = 0
self.game.player.charisma = 0
self.game.handle_key_pressed(KeyValues.DANCE)
self.assertEqual(rabbit.confused, 0)
rabbit.die()
self.game.player.charisma = 11
self.game.handle_key_pressed(KeyValues.DANCE)
self.game.player.charisma = 1
self.game.handle_key_pressed(KeyValues.SPACE)
self.assertEqual(self.game.state, GameMode.MAINMENU)
@ -355,7 +381,7 @@ class TestGame(unittest.TestCase):
self.assertEqual(self.game.settings.KEY_LEFT_PRIMARY, 'a')
# Navigate to "texture pack"
for ignored in range(12):
for ignored in range(14):
self.game.handle_key_pressed(KeyValues.DOWN)
# Change texture pack
@ -771,3 +797,157 @@ class TestGame(unittest.TestCase):
self.game.handle_key_pressed(KeyValues.ENTER)
self.assertEqual(self.game.state, GameMode.MAINMENU)
def test_launch(self) -> None:
"""
Use the long range weapons to kill some entities.
"""
self.game.state = GameMode.PLAY
self.game.player.move(2, 6)
b = Bow()
b.held_by = self.game.player
self.game.player.equipped_main = b
self.assertTrue(self.game.player.equipped_main)
entity = Rabbit()
entity.health = 1
self.game.map.add_entity(entity)
entity.move(3, 6)
self.game.handle_launch(KeyValues.UP)
self.game.waiting_for_launch_key = True
self.game.handle_key_pressed(KeyValues.CHAT)
entity = Rabbit()
entity.health = 1
self.game.map.add_entity(entity)
entity.move(2, 8)
self.game.waiting_for_launch_key = True
self.game.handle_key_pressed(KeyValues.RIGHT)
entity = Rabbit()
entity.health = 1
self.game.map.add_entity(entity)
entity.move(2, 5)
self.game.waiting_for_launch_key = True
self.game.handle_key_pressed(KeyValues.LEFT)
key = "l"
KeyValues.translate_key(key, self.game.settings)
self.game.handle_key_pressed(KeyValues.LAUNCH)
self.assertTrue(self.game.waiting_for_launch_key)
self.game.handle_key_pressed(KeyValues.DOWN)
self.assertTrue(entity.dead)
entity2 = Rabbit()
entity2.health = 1
self.game.map.add_entity(entity2)
entity2.move(1, 6)
b = FireBallStaff()
self.game.player.inventory.append(b)
b.held_by = self.game.player
b.equip()
self.game.handle_key_pressed(KeyValues.LAUNCH)
self.assertTrue(self.game.waiting_for_launch_key)
self.game.handle_key_pressed(KeyValues.UP)
self.assertTrue(entity2.dead)
def test_scrolls(self) -> None:
"""
Use the scrolls.
"""
self.game.state = GameMode.PLAY
self.game.player.move(2, 6)
entity = Rabbit()
self.game.map.add_entity(entity)
entity.move(3, 6)
entity2 = GiantSeaEagle()
self.game.map.add_entity(entity2)
entity2.move(3, 8)
scroll1 = ScrollofDamage()
scroll2 = ScrollofWeakening()
self.game.player.inventory.append(scroll1)
self.game.player.inventory.append(scroll2)
scroll1.held_by = self.game.player
scroll2.held_by = self.game.player
scroll1.use()
self.assertTrue(entity.health != entity.maxhealth)
self.assertTrue(entity2.health != entity2.maxhealth)
scroll2.use()
self.assertEqual(entity.strength, 0)
self.assertEqual(entity2.strength, 999)
self.game.map.tick(self.game.player)
self.game.map.tick(self.game.player)
self.game.map.tick(self.game.player)
self.assertEqual(entity2.effects, [])
def test_chests(self) -> None:
"""
Interacts with chests.
"""
self.game.state = GameMode.PLAY
chest = Chest()
chest.move(2, 6)
self.game.map.add_entity(chest)
chest.inventory.append(FireBallStaff())
# Talk to merchant
self.game.handle_key_pressed(KeyValues.CHAT)
self.assertTrue(self.game.waiting_for_friendly_key)
self.game.handle_key_pressed(KeyValues.DOWN)
self.assertFalse(self.game.waiting_for_friendly_key)
self.assertEqual(self.game.state, GameMode.CHEST)
self.assertTrue(self.game.logs.messages)
# Navigate in the menu
self.game.handle_key_pressed(KeyValues.DOWN)
self.game.handle_key_pressed(KeyValues.DOWN)
self.game.handle_key_pressed(KeyValues.LEFT)
self.assertFalse(self.game.is_in_chest_menu)
self.game.handle_key_pressed(KeyValues.RIGHT)
self.assertTrue(self.game.is_in_chest_menu)
self.game.handle_key_pressed(KeyValues.UP)
self.assertEqual(self.game.chest_menu.position, 1)
# The second item is not a heart
chest.inventory[1] = sword = Sword()
# Take the second item
item = self.game.chest_menu.validate()
self.assertIn(item, chest.inventory)
self.game.display_actions(DisplayActions.MOUSE, 7, 25,
curses.BUTTON1_CLICKED)
self.assertIn(item, self.game.player.inventory)
self.assertNotIn(item, chest.inventory)
# Give an item back
self.game.inventory_menu.position = len(self.game.player.inventory) - 1
self.game.handle_key_pressed(KeyValues.LEFT)
self.assertFalse(self.game.is_in_chest_menu)
self.assertIn(sword, self.game.player.inventory)
self.assertEqual(self.game.inventory_menu.validate(), sword)
self.game.handle_key_pressed(KeyValues.ENTER)
self.assertNotIn(sword, self.game.player.inventory)
self.assertIn(sword, chest.inventory)
# Test immortality
self.game.player.hit(chest)
self.assertTrue(not chest.dead)
# Exit the menu
self.game.handle_key_pressed(KeyValues.SPACE)
self.assertEqual(self.game.state, GameMode.PLAY)

View File

@ -1,11 +1,11 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import unittest
from squirrelbattle.display.texturepack import TexturePack
from squirrelbattle.interfaces import Map, Tile, Slope
from squirrelbattle.resources import ResourceManager
from ..display.texturepack import TexturePack
from ..interfaces import Map, Slope, Tile
from ..resources import ResourceManager
class TestInterfaces(unittest.TestCase):

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from typing import Tuple

View File

@ -1,4 +1,4 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import unittest

View File

@ -55,6 +55,10 @@ class TestTranslations(unittest.TestCase):
self.assertEqual(_("Key used to wait"), "Touche pour attendre")
self.assertEqual(_("Key used to use ladders"),
"Touche pour utiliser les échelles")
self.assertEqual(_("Key used to use a bow"),
"Touche pour utiliser un arc")
self.assertEqual(_("Key used to dance"),
"Touche pour danser")
self.assertEqual(_("Texture pack"), "Pack de textures")
self.assertEqual(_("Language"), "Langue")
@ -77,6 +81,11 @@ class TestTranslations(unittest.TestCase):
self.assertEqual(_("helmet"), "casque")
self.assertEqual(_("chestplate"), "plastron")
self.assertEqual(_("shield"), "bouclier")
self.assertEqual(_("ruler"), "règle")
self.assertEqual(_("scroll of damage"), "parchemin de dégâts")
self.assertEqual(_("scroll of weakness"), "parchemin de faiblesse")
self.assertEqual(_("bow"), "arc")
self.assertEqual(_("fire ball staff"), "baton de boule de feu")
self.assertEqual(_("ring of critical damage"),
"anneau de coup critique")
self.assertEqual(_("ring of more experience"),

View File

@ -1,11 +1,11 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
import gettext as gt
import os
from pathlib import Path
import re
import subprocess
from pathlib import Path
from typing import Any, List