Merge branch 'master' into 'lighting'
# Conflicts: # squirrelbattle/display/mapdisplay.py # squirrelbattle/interfaces.py
This commit is contained in:
97
squirrelbattle/display/creditsdisplay.py
Normal file
97
squirrelbattle/display/creditsdisplay.py
Normal file
@ -0,0 +1,97 @@
|
||||
# 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, game: Game) -> None:
|
||||
if self.pad.inch(y - 1, x - 1) != ord(" "):
|
||||
self.ascii_art_displayed = True
|
@ -24,9 +24,16 @@ class Display:
|
||||
self.pack = pack or TexturePack.get_pack("ascii")
|
||||
|
||||
def newpad(self, height: int, width: int) -> Union[FakePad, Any]:
|
||||
"""
|
||||
Overwrites the native curses function of the same name.
|
||||
"""
|
||||
return curses.newpad(height, width) if self.screen else FakePad()
|
||||
|
||||
def truncate(self, msg: str, height: int, width: int) -> str:
|
||||
"""
|
||||
Truncates a string into a string adapted to the width and height of
|
||||
the screen.
|
||||
"""
|
||||
height = max(0, height)
|
||||
width = max(0, width)
|
||||
lines = msg.split("\n")
|
||||
@ -36,8 +43,8 @@ class Display:
|
||||
|
||||
def translate_color(self, color: Union[int, Tuple[int, int, int]]) -> int:
|
||||
"""
|
||||
Translate a tuple (R, G, B) into a curses color index.
|
||||
If we have already a color index, then nothing is processed.
|
||||
Translates a tuple (R, G, B) into a curses color index.
|
||||
If we already have a color index, then nothing is processed.
|
||||
If this is a tuple, we construct a new color index if non-existing
|
||||
and we return this index.
|
||||
The values of R, G and B must be between 0 and 1000, and not
|
||||
@ -66,9 +73,9 @@ class Display:
|
||||
low: bool = False, right: bool = False, top: bool = False,
|
||||
vertical: bool = False, chartext: bool = False) -> None:
|
||||
"""
|
||||
Display a message onto the pad.
|
||||
Displays a message onto the pad.
|
||||
If the message is too large, it is truncated vertically and horizontally
|
||||
The text can be bold, italic, blinking, ... if the good parameters are
|
||||
The text can be bold, italic, blinking, ... if the right parameters are
|
||||
given. These parameters are translated into curses attributes.
|
||||
The foreground and background colors can be given as curses constants
|
||||
(curses.COLOR_*), or by giving a tuple (R, G, B) that corresponds to
|
||||
@ -126,6 +133,9 @@ class Display:
|
||||
|
||||
def resize(self, y: int, x: int, height: int, width: int,
|
||||
resize_pad: bool = True) -> None:
|
||||
"""
|
||||
Resizes a pad.
|
||||
"""
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = width
|
||||
@ -136,6 +146,9 @@ class Display:
|
||||
self.pad.resize(self.height + 1, self.width + 1)
|
||||
|
||||
def refresh(self, *args, resize_pad: bool = True) -> None:
|
||||
"""
|
||||
Refreshes a pad
|
||||
"""
|
||||
if len(args) == 4:
|
||||
self.resize(*args, resize_pad)
|
||||
self.display()
|
||||
@ -144,10 +157,10 @@ class Display:
|
||||
window_y: int, window_x: int,
|
||||
last_y: int, last_x: int) -> None:
|
||||
"""
|
||||
Refresh a pad on a part of the window.
|
||||
Refreshes a pad on a part of the window.
|
||||
The refresh starts at coordinates (top_y, top_x) from the pad,
|
||||
and is drawn from (window_y, window_x) to (last_y, last_x).
|
||||
If coordinates are invalid (negative indexes/length..., then nothing
|
||||
If coordinates are invalid (negative indexes/length...), then nothing
|
||||
is drawn and no error is raised.
|
||||
"""
|
||||
top_y, top_x = max(0, top_y), max(0, top_x)
|
||||
@ -159,15 +172,25 @@ class Display:
|
||||
|
||||
if last_y >= window_y and last_x >= window_x:
|
||||
# Refresh the pad only if coordinates are valid
|
||||
pad.refresh(top_y, top_x, window_y, window_x, last_y, last_x)
|
||||
pad.noutrefresh(top_y, top_x, window_y, window_x, last_y, last_x)
|
||||
|
||||
def display(self) -> None:
|
||||
"""
|
||||
Draw the content of the display and refresh pads.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, game: Game) -> None:
|
||||
"""
|
||||
The game state was updated.
|
||||
Indicate what to do with the new state.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def handle_click(self, y: int, x: int, game: Game) -> None:
|
||||
"""
|
||||
A mouse click was performed on the coordinates (y, x) of the pad.
|
||||
Maybe it can do something.
|
||||
Maybe it should do something.
|
||||
"""
|
||||
pass
|
||||
|
||||
@ -181,7 +204,9 @@ class Display:
|
||||
|
||||
|
||||
class VerticalSplit(Display):
|
||||
|
||||
"""
|
||||
A class to split the screen in two vertically with a pretty line.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.pad = self.newpad(self.rows, 1)
|
||||
@ -202,7 +227,9 @@ class VerticalSplit(Display):
|
||||
|
||||
|
||||
class HorizontalSplit(Display):
|
||||
|
||||
"""
|
||||
A class to split the screen in two horizontally with a pretty line.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.pad = self.newpad(1, self.cols)
|
||||
@ -223,6 +250,9 @@ class HorizontalSplit(Display):
|
||||
|
||||
|
||||
class Box(Display):
|
||||
"""
|
||||
A class for pretty boxes to print menus and other content.
|
||||
"""
|
||||
title: str = ""
|
||||
|
||||
def update_title(self, title: str) -> None:
|
||||
|
@ -2,6 +2,8 @@
|
||||
# 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
|
||||
@ -30,17 +32,21 @@ class DisplayManager:
|
||||
self.mainmenudisplay = MainMenuDisplay(self.game.main_menu,
|
||||
screen, pack)
|
||||
self.settingsmenudisplay = SettingsMenuDisplay(screen, pack)
|
||||
self.messagedisplay = MessageDisplay(screen=screen, pack=None)
|
||||
self.messagedisplay = MessageDisplay(screen, pack)
|
||||
self.hbar = HorizontalSplit(screen, pack)
|
||||
self.vbar = VerticalSplit(screen, pack)
|
||||
self.creditsdisplay = CreditsDisplay(screen, pack)
|
||||
self.displays = [self.statsdisplay, self.mapdisplay,
|
||||
self.mainmenudisplay, self.settingsmenudisplay,
|
||||
self.logsdisplay, self.messagedisplay,
|
||||
self.playerinventorydisplay,
|
||||
self.storeinventorydisplay]
|
||||
self.storeinventorydisplay, self.creditsdisplay]
|
||||
self.update_game_components()
|
||||
|
||||
def handle_display_action(self, action: DisplayActions, *params) -> None:
|
||||
"""
|
||||
Handles the differents values of display action.
|
||||
"""
|
||||
if action == DisplayActions.REFRESH:
|
||||
self.refresh()
|
||||
elif action == DisplayActions.UPDATE:
|
||||
@ -49,19 +55,18 @@ class DisplayManager:
|
||||
self.handle_mouse_click(*params)
|
||||
|
||||
def update_game_components(self) -> None:
|
||||
"""
|
||||
The game state was updated.
|
||||
Trigger all displays of these modifications.
|
||||
"""
|
||||
for d in self.displays:
|
||||
d.pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
|
||||
self.mapdisplay.update_map(self.game.map)
|
||||
self.statsdisplay.update_player(self.game.player)
|
||||
self.game.inventory_menu.update_player(self.game.player)
|
||||
self.game.store_menu.update_merchant(self.game.player)
|
||||
self.playerinventorydisplay.update_menu(self.game.inventory_menu)
|
||||
self.storeinventorydisplay.update_menu(self.game.store_menu)
|
||||
self.settingsmenudisplay.update_menu(self.game.settings_menu)
|
||||
self.logsdisplay.update_logs(self.game.logs)
|
||||
self.messagedisplay.update_message(self.game.message)
|
||||
d.update(self.game)
|
||||
|
||||
def handle_mouse_click(self, y: int, x: int) -> None:
|
||||
"""
|
||||
Handles the mouse clicks.
|
||||
"""
|
||||
displays = self.refresh()
|
||||
display = None
|
||||
for d in displays:
|
||||
@ -74,7 +79,11 @@ class DisplayManager:
|
||||
display.handle_click(y - display.y, x - display.x, self.game)
|
||||
|
||||
def refresh(self) -> List[Display]:
|
||||
"""
|
||||
Refreshes all components on the screen.
|
||||
"""
|
||||
displays = []
|
||||
pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
|
||||
|
||||
if self.game.state == GameMode.PLAY \
|
||||
or self.game.state == GameMode.INVENTORY \
|
||||
@ -97,27 +106,41 @@ class DisplayManager:
|
||||
|
||||
if self.game.state == GameMode.INVENTORY:
|
||||
self.playerinventorydisplay.refresh(
|
||||
self.rows // 10, self.cols // 2,
|
||||
8 * self.rows // 10, 2 * self.cols // 5)
|
||||
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)))
|
||||
displays.append(self.playerinventorydisplay)
|
||||
elif self.game.state == GameMode.STORE:
|
||||
self.storeinventorydisplay.refresh(
|
||||
self.rows // 10, self.cols // 2,
|
||||
8 * self.rows // 10, 2 * self.cols // 5)
|
||||
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.storeinventorydisplay)
|
||||
displays.append(self.playerinventorydisplay)
|
||||
elif self.game.state == GameMode.MAINMENU:
|
||||
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
|
||||
displays.append(self.mainmenudisplay)
|
||||
elif self.game.state == GameMode.SETTINGS:
|
||||
self.settingsmenudisplay.refresh(0, 0, self.rows, self.cols)
|
||||
displays.append(self.settingsmenudisplay)
|
||||
elif self.game.state == GameMode.CREDITS:
|
||||
self.creditsdisplay.refresh(0, 0, self.rows, self.cols)
|
||||
displays.append(self.creditsdisplay)
|
||||
|
||||
if self.game.message:
|
||||
height, width = 0, 0
|
||||
for line in self.game.message.split("\n"):
|
||||
height += 1
|
||||
width = max(width, len(line))
|
||||
y, x = (self.rows - height) // 2, (self.cols - width) // 2
|
||||
y = pack.tile_width * (self.rows - height) // (2 * pack.tile_width)
|
||||
x = pack.tile_width * ((self.cols - width) // (2 * pack.tile_width))
|
||||
self.messagedisplay.refresh(y, x, height, width)
|
||||
displays.append(self.messagedisplay)
|
||||
|
||||
@ -127,7 +150,7 @@ class DisplayManager:
|
||||
|
||||
def resize_window(self) -> bool:
|
||||
"""
|
||||
If the window got resized, ensure that the screen size got updated.
|
||||
When the window is resized, ensures that the screen size is updated.
|
||||
"""
|
||||
y, x = self.screen.getmaxyx() if self.screen else (0, 0)
|
||||
if self.screen and curses.is_term_resized(self.rows,
|
||||
@ -138,8 +161,16 @@ class DisplayManager:
|
||||
|
||||
@property
|
||||
def rows(self) -> int:
|
||||
"""
|
||||
Overwrites the native curses attribute of the same name,
|
||||
for testing purposes.
|
||||
"""
|
||||
return curses.LINES if self.screen else 42
|
||||
|
||||
@property
|
||||
def cols(self) -> int:
|
||||
"""
|
||||
Overwrites the native curses attribute of the same name,
|
||||
for testing purposes.
|
||||
"""
|
||||
return curses.COLS if self.screen else 42
|
||||
|
@ -2,17 +2,23 @@
|
||||
# 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_logs(self, logs: Logs) -> None:
|
||||
self.logs = logs
|
||||
def update(self, game: Game) -> None:
|
||||
self.logs = game.logs
|
||||
|
||||
def display(self) -> None:
|
||||
messages = self.logs.messages[-self.height:]
|
||||
|
@ -3,16 +3,23 @@
|
||||
|
||||
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_map(self, m: Map) -> None:
|
||||
self.map = m
|
||||
self.pad = self.newpad(m.height, self.pack.tile_width * m.width + 1)
|
||||
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)):
|
||||
|
@ -5,9 +5,10 @@ import curses
|
||||
from random import randint
|
||||
from typing import List
|
||||
|
||||
from squirrelbattle.menus import Menu, MainMenu
|
||||
from squirrelbattle.menus import Menu, MainMenu, SettingsMenu, StoreMenu
|
||||
from .display import Box, Display
|
||||
from ..enums import KeyValues
|
||||
from ..entities.player import Player
|
||||
from ..enums import KeyValues, GameMode
|
||||
from ..game import Game
|
||||
from ..resources import ResourceManager
|
||||
from ..translations import gettext as _
|
||||
@ -15,8 +16,9 @@ from ..translations import gettext as _
|
||||
|
||||
class MenuDisplay(Display):
|
||||
"""
|
||||
A class to display the menu objects
|
||||
A class to display the menu objects.
|
||||
"""
|
||||
menu: Menu
|
||||
position: int
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -78,8 +80,13 @@ class MenuDisplay(Display):
|
||||
|
||||
class SettingsMenuDisplay(MenuDisplay):
|
||||
"""
|
||||
A class to display specifically a settingsmenu object
|
||||
A class to display specifically a settingsmenu object.
|
||||
"""
|
||||
menu: SettingsMenu
|
||||
|
||||
def update(self, game: Game) -> None:
|
||||
self.update_menu(game.settings_menu)
|
||||
|
||||
@property
|
||||
def values(self) -> List[str]:
|
||||
return [_(a[1][1]) + (" : "
|
||||
@ -91,7 +98,7 @@ class SettingsMenuDisplay(MenuDisplay):
|
||||
|
||||
class MainMenuDisplay(Display):
|
||||
"""
|
||||
A class to display specifically a mainmenu object
|
||||
A class to display specifically a mainmenu object.
|
||||
"""
|
||||
def __init__(self, menu: MainMenu, *args):
|
||||
super().__init__(*args)
|
||||
@ -113,6 +120,8 @@ class MainMenuDisplay(Display):
|
||||
self.addstr(self.pad, 4 + i, max(self.width // 2
|
||||
- len(self.title[0]) // 2 - 1, 0), self.title[i],
|
||||
self.fg_color)
|
||||
msg = _("Credits")
|
||||
self.addstr(self.pad, self.height - 1, self.width - 1 - len(msg), msg)
|
||||
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||
self.height + self.y - 1,
|
||||
self.width + self.x - 1)
|
||||
@ -122,6 +131,9 @@ class MainMenuDisplay(Display):
|
||||
menuy, menux, min(self.menudisplay.preferred_height,
|
||||
self.height - menuy), menuwidth)
|
||||
|
||||
def update(self, game: Game) -> None:
|
||||
self.menudisplay.update_menu(game.main_menu)
|
||||
|
||||
def handle_click(self, y: int, x: int, game: Game) -> None:
|
||||
menuwidth = min(self.menudisplay.preferred_width, self.width)
|
||||
menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1
|
||||
@ -133,15 +145,41 @@ class MainMenuDisplay(Display):
|
||||
if y <= len(self.title):
|
||||
self.fg_color = randint(0, 1000), randint(0, 1000), randint(0, 1000)
|
||||
|
||||
if y == self.height - 1 and x >= self.width - 1 - len(_("Credits")):
|
||||
game.state = GameMode.CREDITS
|
||||
|
||||
|
||||
class PlayerInventoryDisplay(MenuDisplay):
|
||||
"""
|
||||
A class to handle the display of the player's inventory.
|
||||
"""
|
||||
player: Player = None
|
||||
selected: bool = True
|
||||
store_mode: bool = False
|
||||
|
||||
def update(self, game: Game) -> None:
|
||||
self.player = game.player
|
||||
self.update_menu(game.inventory_menu)
|
||||
self.store_mode = game.state == GameMode.STORE
|
||||
self.selected = game.state == GameMode.INVENTORY \
|
||||
or (self.store_mode and not game.is_in_store_menu)
|
||||
|
||||
def update_pad(self) -> None:
|
||||
self.menubox.update_title(_("INVENTORY"))
|
||||
for i, item in enumerate(self.menu.values):
|
||||
rep = self.pack[item.name.upper()]
|
||||
selection = f"[{rep}]" if i == self.menu.position else f" {rep} "
|
||||
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())
|
||||
+ " " + item.translated_name.capitalize()
|
||||
+ (": " + str(item.price) + " Hazels"
|
||||
if self.store_mode else ""))
|
||||
|
||||
if self.store_mode:
|
||||
price = f"{self.pack.HAZELNUT} {self.player.hazel} Hazels"
|
||||
width = len(price) + (self.pack.tile_width - 1)
|
||||
self.addstr(self.pad, self.height - 3, self.width - width - 2,
|
||||
price, italic=True)
|
||||
|
||||
@property
|
||||
def truewidth(self) -> int:
|
||||
@ -156,19 +194,36 @@ class PlayerInventoryDisplay(MenuDisplay):
|
||||
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_store_menu = False
|
||||
game.handle_key_pressed(KeyValues.ENTER)
|
||||
|
||||
|
||||
class StoreInventoryDisplay(MenuDisplay):
|
||||
"""
|
||||
A class to handle the display of a merchant's inventory.
|
||||
"""
|
||||
menu: StoreMenu
|
||||
selected: bool = False
|
||||
|
||||
def update(self, game: Game) -> None:
|
||||
self.update_menu(game.store_menu)
|
||||
self.selected = game.is_in_store_menu
|
||||
|
||||
def update_pad(self) -> None:
|
||||
self.menubox.update_title(_("STALL"))
|
||||
for i, item in enumerate(self.menu.values):
|
||||
rep = self.pack[item.name.upper()]
|
||||
selection = f"[{rep}]" if i == self.menu.position else f" {rep} "
|
||||
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()
|
||||
+ ": " + str(item.price) + " Hazels")
|
||||
|
||||
price = f"{self.pack.HAZELNUT} {self.menu.merchant.hazel} Hazels"
|
||||
width = len(price) + (self.pack.tile_width - 1)
|
||||
self.addstr(self.pad, self.height - 3, self.width - width - 2, price,
|
||||
italic=True)
|
||||
|
||||
@property
|
||||
def truewidth(self) -> int:
|
||||
return max(1, self.height if hasattr(self, "height") else 10)
|
||||
@ -182,4 +237,5 @@ class StoreInventoryDisplay(MenuDisplay):
|
||||
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_store_menu = True
|
||||
game.handle_key_pressed(KeyValues.ENTER)
|
||||
|
@ -3,11 +3,12 @@
|
||||
import curses
|
||||
|
||||
from squirrelbattle.display.display import Box, Display
|
||||
from squirrelbattle.game import Game
|
||||
|
||||
|
||||
class MessageDisplay(Display):
|
||||
"""
|
||||
Display a message in a popup.
|
||||
A class to handle the display of popup messages.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -17,8 +18,8 @@ class MessageDisplay(Display):
|
||||
self.message = ""
|
||||
self.pad = self.newpad(1, 1)
|
||||
|
||||
def update_message(self, msg: str) -> None:
|
||||
self.message = msg
|
||||
def update(self, game: Game) -> None:
|
||||
self.message = game.message
|
||||
|
||||
def display(self) -> None:
|
||||
self.box.refresh(self.y - 1, self.x - 2,
|
||||
|
@ -4,30 +4,36 @@
|
||||
import curses
|
||||
|
||||
from ..entities.player import Player
|
||||
from ..game import Game
|
||||
from ..translations import gettext as _
|
||||
from .display import Display
|
||||
|
||||
|
||||
class StatsDisplay(Display):
|
||||
"""
|
||||
A class to handle the display of the stats of the player.
|
||||
"""
|
||||
player: Player
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.pad = self.newpad(self.rows, self.cols)
|
||||
|
||||
def update_player(self, p: Player) -> None:
|
||||
self.player = p
|
||||
def update(self, game: Game) -> None:
|
||||
self.player = game.player
|
||||
|
||||
def update_pad(self) -> None:
|
||||
string2 = "Player -- LVL {}\nEXP {}/{}\nHP {}/{}"\
|
||||
.format(self.player.level, self.player.current_xp,
|
||||
self.player.max_xp, self.player.health,
|
||||
self.player.maxhealth)
|
||||
string2 = f"{_(self.player.name).capitalize()} " \
|
||||
f"-- LVL {self.player.level} -- " \
|
||||
f"FLOOR {-self.player.map.floor}\n" \
|
||||
f"EXP {self.player.current_xp}/{self.player.max_xp}\n" \
|
||||
f"HP {self.player.health}/{self.player.maxhealth}"
|
||||
self.addstr(self.pad, 0, 0, string2)
|
||||
string3 = "STR {}\nINT {}\nCHR {}\nDEX {}\nCON {}"\
|
||||
.format(self.player.strength,
|
||||
self.player.intelligence, self.player.charisma,
|
||||
self.player.dexterity, self.player.constitution)
|
||||
string3 = f"STR {self.player.strength}\n" \
|
||||
f"INT {self.player.intelligence}\n" \
|
||||
f"CHR {self.player.charisma}\n" \
|
||||
f"DEX {self.player.dexterity}\n" \
|
||||
f"CON {self.player.constitution}"
|
||||
self.addstr(self.pad, 3, 0, string3)
|
||||
|
||||
inventory_str = _("Inventory:") + " "
|
||||
|
@ -6,6 +6,9 @@ from typing import Any, Union, Tuple
|
||||
|
||||
|
||||
class TexturePack:
|
||||
"""
|
||||
A class to handle displaying several textures.
|
||||
"""
|
||||
_packs = dict()
|
||||
|
||||
name: str
|
||||
@ -30,6 +33,7 @@ class TexturePack:
|
||||
SWORD: str
|
||||
TEDDY_BEAR: str
|
||||
TIGER: str
|
||||
TRUMPET: str
|
||||
WALL: str
|
||||
|
||||
ASCII_PACK: "TexturePack"
|
||||
@ -66,6 +70,7 @@ TexturePack.ASCII_PACK = TexturePack(
|
||||
EMPTY=' ',
|
||||
EXPLOSION='%',
|
||||
FLOOR='.',
|
||||
LADDER='H',
|
||||
HAZELNUT='¤',
|
||||
HEART='❤',
|
||||
HEDGEHOG='*',
|
||||
@ -76,6 +81,7 @@ TexturePack.ASCII_PACK = TexturePack(
|
||||
SWORD='\u2020',
|
||||
TEDDY_BEAR='8',
|
||||
TIGER='n',
|
||||
TRUMPET='/',
|
||||
WALL='#',
|
||||
)
|
||||
|
||||
@ -93,6 +99,7 @@ TexturePack.SQUIRREL_PACK = TexturePack(
|
||||
EMPTY=' ',
|
||||
EXPLOSION='💥',
|
||||
FLOOR='██',
|
||||
LADDER=('🪜', curses.COLOR_WHITE, curses.COLOR_WHITE),
|
||||
HAZELNUT='🌰',
|
||||
HEART='💜',
|
||||
HEDGEHOG='🦔',
|
||||
@ -100,8 +107,9 @@ TexturePack.SQUIRREL_PACK = TexturePack(
|
||||
MERCHANT='🦜',
|
||||
RABBIT='🐇',
|
||||
SUNFLOWER='🌻',
|
||||
SWORD='🗡️',
|
||||
SWORD='🗡️ ',
|
||||
TEDDY_BEAR='🧸',
|
||||
TIGER='🐅',
|
||||
TRUMPET='🎺',
|
||||
WALL='🧱',
|
||||
)
|
||||
|
Reference in New Issue
Block a user