Merge remote branch
This commit is contained in:
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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):
|
@ -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)
|
@ -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)
|
@ -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
|
||||
|
@ -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)
|
@ -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='📜',
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
|
@ -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,11 +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
|
||||
# TODO Remove it, that's only fun
|
||||
self.map.spawn_random_entities(randint(3 * self.level,
|
||||
10 * self.level))
|
||||
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:
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -1,21 +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 random import randint
|
||||
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
|
||||
|
||||
|
||||
@ -36,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()
|
||||
@ -46,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
|
||||
|
||||
@ -61,7 +63,6 @@ class Game:
|
||||
self.player = Player()
|
||||
self.map.add_entity(self.player)
|
||||
self.player.move(self.map.start_y, self.map.start_x)
|
||||
self.map.spawn_random_entities(randint(3, 10))
|
||||
self.inventory_menu.update_player(self.player)
|
||||
|
||||
@property
|
||||
@ -121,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:
|
||||
@ -131,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)
|
||||
@ -159,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:
|
||||
@ -168,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:
|
||||
"""
|
||||
@ -248,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:
|
||||
"""
|
||||
@ -304,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.
|
||||
@ -345,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
|
||||
@ -361,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)
|
||||
|
@ -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, choices, 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, randint
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from .display.texturepack import TexturePack
|
||||
from .translations import gettext as _
|
||||
@ -180,21 +181,15 @@ class Map:
|
||||
return "\n".join("".join(tile.char(pack) for tile in line)
|
||||
for line in self.tiles)
|
||||
|
||||
def spawn_random_entities(self, count: int) -> None:
|
||||
"""
|
||||
Puts randomly {count} entities on the map, only on empty ground tiles.
|
||||
"""
|
||||
for _ignored in range(count):
|
||||
y, x = 0, 0
|
||||
while True:
|
||||
y, x = randint(0, self.height - 1), randint(0, self.width - 1)
|
||||
tile = self.tiles[y][x]
|
||||
if tile.can_walk():
|
||||
break
|
||||
entity = choices(Entity.get_all_entity_classes(),
|
||||
weights=Entity.get_weights(), k=1)[0]()
|
||||
entity.move(y, x)
|
||||
self.add_entity(entity)
|
||||
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:
|
||||
"""
|
||||
@ -249,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)))
|
||||
@ -619,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:
|
||||
"""
|
||||
@ -635,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:
|
||||
@ -645,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:
|
||||
@ -657,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:
|
||||
@ -708,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,
|
||||
@ -723,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:
|
||||
@ -731,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
|
||||
@ -752,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()
|
||||
|
@ -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"
|
||||
|
@ -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 ""
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -1,10 +1,10 @@
|
||||
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from random import random, randint, shuffle, choice, choices
|
||||
from random import choice, choices, randint, random, shuffle
|
||||
from typing import List, Tuple
|
||||
|
||||
from ..interfaces import Map, Tile, Entity
|
||||
from ..interfaces import Entity, Map, Tile
|
||||
|
||||
DEFAULT_PARAMS = {
|
||||
"width": 120,
|
||||
@ -20,10 +20,10 @@ DEFAULT_PARAMS = {
|
||||
"max_h_corr": 12,
|
||||
"large_circular_room": .10,
|
||||
"circular_holes": .5,
|
||||
"loop_tries" : 40,
|
||||
"loop_max" : 5,
|
||||
"loop_threshold" : 15,
|
||||
"spawn_per_region" : [1, 2],
|
||||
"loop_tries": 40,
|
||||
"loop_max": 5,
|
||||
"loop_threshold": 15,
|
||||
"spawn_per_region": [1, 2],
|
||||
}
|
||||
|
||||
def dist(level, y1, x1, y2, x2):
|
||||
@ -31,7 +31,7 @@ def dist(level, y1, x1, y2, x2):
|
||||
Compute the minimum walking distance between points (y1, x1) and (y2, x2) on a Tile grid
|
||||
"""
|
||||
# simple breadth first search
|
||||
copy = [[t for t in l] for l in level]
|
||||
copy = [[t for t in row] for row in level]
|
||||
dist = -1
|
||||
queue, next_queue = [[y1, x1]], [0]
|
||||
while next_queue:
|
||||
@ -40,7 +40,7 @@ def dist(level, y1, x1, y2, x2):
|
||||
while queue:
|
||||
y, x = queue.pop()
|
||||
copy[y][x] = Tile.EMPTY
|
||||
if y == y2 and x == x2:
|
||||
if y == y2 and x == x2:
|
||||
return dist
|
||||
for y, x in Map.neighbourhood(copy, y, x):
|
||||
if copy[y][x].can_walk():
|
||||
@ -48,6 +48,7 @@ def dist(level, y1, x1, y2, x2):
|
||||
queue = next_queue
|
||||
return -1
|
||||
|
||||
|
||||
class Generator:
|
||||
def __init__(self, params: dict = None):
|
||||
self.params = params or DEFAULT_PARAMS
|
||||
@ -104,7 +105,7 @@ class Generator:
|
||||
level[y - door_y + ry][x - door_x + rx] = Tile.FLOOR
|
||||
|
||||
@staticmethod
|
||||
def add_loop(level: List[List[Tile]], y: int, x: int) -> None:
|
||||
def add_loop(level: List[List[Tile]], y: int, x: int) -> bool:
|
||||
"""
|
||||
Try to add a corridor between two far apart floor tiles, passing
|
||||
through point (y, x).
|
||||
@ -127,23 +128,26 @@ class Generator:
|
||||
if not(0 <= x1 <= x2 < w and 0 <= y1 <= y2 < h):
|
||||
continue
|
||||
|
||||
def verify_sides():
|
||||
def verify_sides() -> bool:
|
||||
# switching up dy and dx here pivots the axis, so
|
||||
# (y+dx, x+dy) and (y-dx, x-dy) are the tiles adjacent to
|
||||
# (y, x), but not on the original axis
|
||||
for Dx, Dy in [[dy, dx], [-dy, -dx]]:
|
||||
for i in range(1, y2-y1+x2-x1):
|
||||
if not(0<= y1+Dy+i*dy < h and 0 <= x1+Dx+i*dx < w) or \
|
||||
level[y1+Dy+i*dy][x1+Dx+i*dx].can_walk():
|
||||
for delta_x, delta_y in [[dy, dx], [-dy, -dx]]:
|
||||
for i in range(1, y2 - y1 + x2 - x1):
|
||||
if not (0 <= y1 + delta_y + i * dy < h
|
||||
and 0 <= x1 + delta_x + i * dx < w) or \
|
||||
level[y1 + delta_y + i * dy][x1 + delta_x
|
||||
+ i * dx]\
|
||||
.can_walk():
|
||||
return False
|
||||
return True
|
||||
# if adding the path would make the two tiles significantly closer
|
||||
# and its sides don't touch already placed terrain, build it
|
||||
if dist(level, y1, x1, y2, x2) < 20 and verify_sides():
|
||||
y, x = y1+dy, x1+dx
|
||||
y, x = y1 + dy, x1 + dx
|
||||
while level[y][x] == Tile.EMPTY:
|
||||
level[y][x] = Tile.FLOOR
|
||||
y, x = y+dy, x+dx
|
||||
y, x = y + dy, x + dx
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -187,7 +191,8 @@ class Generator:
|
||||
return 0, 0, 0, 0
|
||||
|
||||
@staticmethod
|
||||
def build_door(room, y, x, dy, dx, length):
|
||||
def build_door(room: List[List[Tile]], y: int, x: int,
|
||||
dy: int, dx: int, length: int) -> bool:
|
||||
"""
|
||||
Tries to build the exit from the room at given coordinates
|
||||
Depending on parameter length, it will either attempt to build a
|
||||
@ -206,7 +211,7 @@ class Generator:
|
||||
and room[ny][nx] != Tile.EMPTY:
|
||||
return False
|
||||
# see if the path ahead is clear. needed in the case of non convex room
|
||||
for i in range(length+1):
|
||||
for i in range(length + 1):
|
||||
if room[y + i * dy][x + i * dx] != Tile.EMPTY:
|
||||
return False
|
||||
for i in range(length):
|
||||
@ -214,8 +219,8 @@ class Generator:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def attach_door(room: List[List[Tile]], h_sup: int, w_sup: int,
|
||||
h_off: int, w_off: int) -> Tuple[int, int, int, int]:
|
||||
def attach_door(room: List[List[Tile]], h_sup: int, w_sup: int,
|
||||
h_off: int, w_off: int) -> Tuple[int, int, int, int]:
|
||||
"""
|
||||
Attach an exit to the room. If extra space was allocated to
|
||||
the grid, make sure a corridor is properly built
|
||||
@ -300,7 +305,7 @@ class Generator:
|
||||
"""
|
||||
return self.create_circular_room()
|
||||
|
||||
def register_spawn_area(self, area:List[List[Tile]]):
|
||||
def register_spawn_area(self, area: List[List[Tile]]) -> None:
|
||||
"""
|
||||
Register all floor positions relative to the input grid
|
||||
for later use
|
||||
@ -312,7 +317,7 @@ class Generator:
|
||||
spawn_positions.append([y, x])
|
||||
self.queued_area = spawn_positions
|
||||
|
||||
def update_spawnable(self, y, x):
|
||||
def update_spawnable(self, y: int, x: int) -> None:
|
||||
"""
|
||||
Convert previous spawn positions relative to the room grid to actual
|
||||
actual spawn positions on the level grid, using the position of the
|
||||
@ -324,11 +329,16 @@ class Generator:
|
||||
self.spawn_areas.append(translated_area)
|
||||
self.queued_area = None
|
||||
|
||||
def populate(self, rv):
|
||||
def populate(self, rv: Map) -> None:
|
||||
"""
|
||||
Populate every spawnable area with some randomly chosen, randomly
|
||||
placed entity
|
||||
"""
|
||||
if self.queued_area is not None:
|
||||
translated_area = [[y + ry, x + rx] for ry, rx in self.queued_area]
|
||||
self.spawn_areas.append(translated_area)
|
||||
self.queued_area = None
|
||||
|
||||
min_c, max_c = self.params["spawn_per_region"]
|
||||
for region in self.spawn_areas:
|
||||
entity_count = randint(min_c, max_c)
|
||||
@ -349,7 +359,7 @@ class Generator:
|
||||
|
||||
# the starting room must have no corridor
|
||||
mem, self.params["corridor_chance"] = self.params["corridor_chance"], 0
|
||||
starting_room, _, _, _, _ = self.create_random_room(spawnable = False)
|
||||
starting_room, _, _, _, _ = self.create_random_room(spawnable=False)
|
||||
dim_v, dim_h = len(starting_room), len(starting_room[0])
|
||||
# because Generator.room_fits checks that the exit door is correctly
|
||||
# placed, but the starting room has no exit door, we find a positoin
|
||||
@ -399,7 +409,7 @@ class Generator:
|
||||
while tries < self.params["loop_tries"] and \
|
||||
loops < self.params["loop_max"]:
|
||||
tries += 1
|
||||
y, x = randint(0, height-1), randint(0, width-1)
|
||||
y, x = randint(0, height - 1), randint(0, width - 1)
|
||||
loops += self.add_loop(level, y, x)
|
||||
|
||||
# place an exit ladder
|
||||
|
@ -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 []
|
||||
|
@ -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
|
||||
|
@ -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']
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -1,22 +1,22 @@
|
||||
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import unittest
|
||||
from random import randint
|
||||
from typing import List
|
||||
import unittest
|
||||
|
||||
from squirrelbattle.interfaces import Map, Tile
|
||||
from squirrelbattle.mapgeneration import broguelike
|
||||
from squirrelbattle.display.texturepack import TexturePack
|
||||
from ..display.texturepack import TexturePack
|
||||
from ..interfaces import Map, Tile
|
||||
from ..mapgeneration import broguelike
|
||||
|
||||
|
||||
class TestBroguelike(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.generator = broguelike.Generator()
|
||||
self.stom = lambda x : Map.load_from_string("0 0\n" + x)
|
||||
self.mtos = lambda x : x.draw_string(TexturePack.ASCII_PACK)
|
||||
self.stom = lambda x: Map.load_from_string("0 0\n" + x)
|
||||
self.mtos = lambda x: x.draw_string(TexturePack.ASCII_PACK)
|
||||
|
||||
def test_dist(self):
|
||||
def test_dist(self) -> None:
|
||||
m = self.stom(".. ..\n ... ")
|
||||
distance = broguelike.dist(m.tiles, 0, 0, 0, 4)
|
||||
self.assertEqual(distance, 6)
|
||||
@ -37,7 +37,7 @@ class TestBroguelike(unittest.TestCase):
|
||||
queue += Map.neighbourhood(grid, y, x)
|
||||
return not any([t.can_walk() for row in grid for t in row])
|
||||
|
||||
def test_build_doors(self):
|
||||
def test_build_doors(self) -> None:
|
||||
m = self.stom(". .\n. .\n. .\n")
|
||||
self.assertFalse(self.generator.build_door(m.tiles, 1, 1, 0, 1, 2))
|
||||
|
||||
@ -46,11 +46,10 @@ class TestBroguelike(unittest.TestCase):
|
||||
self.assertTrue(self.is_connex(m.tiles))
|
||||
|
||||
def test_loops(self) -> None:
|
||||
m = self.stom(3*".. ..\n")
|
||||
m = self.stom(3 * ".. ..\n")
|
||||
self.generator.add_loop(m.tiles, 1, 3)
|
||||
s = self.mtos(m)
|
||||
self.assertEqual(s, ".. ..\n.......\n.. ..")
|
||||
self.assertFalse(self.generator.add_loop(m.tiles, 0, 0))
|
||||
m = self.stom("...\n. .\n...")
|
||||
self.assertFalse(self.generator.add_loop(m.tiles, 1, 1))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"),
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user