Merge branch 'game-logs' into 'master'
Game logs, see #12 See merge request ynerant/squirrel-battle!18
This commit is contained in:
commit
b7207bb738
|
@ -33,7 +33,7 @@ class Display:
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
if hasattr(self, "pad") and resize_pad:
|
if hasattr(self, "pad") and resize_pad:
|
||||||
self.pad.resize(self.height - 1, self.width - 1)
|
self.pad.resize(self.height, self.width)
|
||||||
|
|
||||||
def refresh(self, *args, resize_pad: bool = True) -> None:
|
def refresh(self, *args, resize_pad: bool = True) -> None:
|
||||||
if len(args) == 4:
|
if len(args) == 4:
|
||||||
|
|
|
@ -3,6 +3,7 @@ from squirrelbattle.display.mapdisplay import MapDisplay
|
||||||
from squirrelbattle.display.statsdisplay import StatsDisplay
|
from squirrelbattle.display.statsdisplay import StatsDisplay
|
||||||
from squirrelbattle.display.menudisplay import SettingsMenuDisplay, \
|
from squirrelbattle.display.menudisplay import SettingsMenuDisplay, \
|
||||||
MainMenuDisplay
|
MainMenuDisplay
|
||||||
|
from squirrelbattle.display.logsdisplay import LogsDisplay
|
||||||
from squirrelbattle.display.texturepack import TexturePack
|
from squirrelbattle.display.texturepack import TexturePack
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from squirrelbattle.game import Game, GameMode
|
from squirrelbattle.game import Game, GameMode
|
||||||
|
@ -20,8 +21,10 @@ class DisplayManager:
|
||||||
self.mainmenudisplay = MainMenuDisplay(self.game.main_menu,
|
self.mainmenudisplay = MainMenuDisplay(self.game.main_menu,
|
||||||
screen, pack)
|
screen, pack)
|
||||||
self.settingsmenudisplay = SettingsMenuDisplay(screen, pack)
|
self.settingsmenudisplay = SettingsMenuDisplay(screen, pack)
|
||||||
|
self.logsdisplay = LogsDisplay(screen, pack)
|
||||||
self.displays = [self.statsdisplay, self.mapdisplay,
|
self.displays = [self.statsdisplay, self.mapdisplay,
|
||||||
self.mainmenudisplay, self.settingsmenudisplay]
|
self.mainmenudisplay, self.settingsmenudisplay,
|
||||||
|
self.logsdisplay]
|
||||||
self.update_game_components()
|
self.update_game_components()
|
||||||
|
|
||||||
def handle_display_action(self, action: DisplayActions) -> None:
|
def handle_display_action(self, action: DisplayActions) -> None:
|
||||||
|
@ -36,6 +39,7 @@ class DisplayManager:
|
||||||
self.mapdisplay.update_map(self.game.map)
|
self.mapdisplay.update_map(self.game.map)
|
||||||
self.statsdisplay.update_player(self.game.player)
|
self.statsdisplay.update_player(self.game.player)
|
||||||
self.settingsmenudisplay.update_menu(self.game.settings_menu)
|
self.settingsmenudisplay.update_menu(self.game.settings_menu)
|
||||||
|
self.logsdisplay.update_logs(self.game.logs)
|
||||||
|
|
||||||
def refresh(self) -> None:
|
def refresh(self) -> None:
|
||||||
if self.game.state == GameMode.PLAY:
|
if self.game.state == GameMode.PLAY:
|
||||||
|
@ -43,7 +47,9 @@ class DisplayManager:
|
||||||
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5, self.cols,
|
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5, self.cols,
|
||||||
resize_pad=False)
|
resize_pad=False)
|
||||||
self.statsdisplay.refresh(self.rows * 4 // 5, 0,
|
self.statsdisplay.refresh(self.rows * 4 // 5, 0,
|
||||||
self.rows // 5, self.cols)
|
self.rows // 10, self.cols)
|
||||||
|
self.logsdisplay.refresh(self.rows * 9 // 10, 0,
|
||||||
|
self.rows // 10, self.cols)
|
||||||
if self.game.state == GameMode.MAINMENU:
|
if self.game.state == GameMode.MAINMENU:
|
||||||
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
|
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
|
||||||
if self.game.state == GameMode.SETTINGS:
|
if self.game.state == GameMode.SETTINGS:
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
from squirrelbattle.display.display import Display
|
||||||
|
from squirrelbattle.interfaces import Logs
|
||||||
|
|
||||||
|
|
||||||
|
class LogsDisplay(Display):
|
||||||
|
|
||||||
|
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 display(self) -> None:
|
||||||
|
print(type(self.logs.messages), flush=True)
|
||||||
|
messages = self.logs.messages[-self.height:]
|
||||||
|
messages = messages[::-1]
|
||||||
|
self.pad.clear()
|
||||||
|
for i in range(min(self.height, len(messages))):
|
||||||
|
self.pad.addstr(self.height - i - 1, self.x,
|
||||||
|
messages[i][:self.width])
|
||||||
|
self.pad.refresh(0, 0, self.y, self.x, self.y + self.height,
|
||||||
|
self.x + self.width)
|
|
@ -44,7 +44,7 @@ class Monster(FightingEntity):
|
||||||
next_y, next_x = target.paths[(self.y, self.x)]
|
next_y, next_x = target.paths[(self.y, self.x)]
|
||||||
moved = self.check_move(next_y, next_x, True)
|
moved = self.check_move(next_y, next_x, True)
|
||||||
if not moved and self.distance_squared(target) <= 1:
|
if not moved and self.distance_squared(target) <= 1:
|
||||||
self.hit(target)
|
self.map.logs.add_message(self.hit(target))
|
||||||
else:
|
else:
|
||||||
for _ in range(100):
|
for _ in range(100):
|
||||||
if choice([self.move_up, self.move_down,
|
if choice([self.move_up, self.move_down,
|
||||||
|
|
|
@ -72,7 +72,7 @@ class Player(FightingEntity):
|
||||||
for entity in self.map.entities:
|
for entity in self.map.entities:
|
||||||
if entity.y == y and entity.x == x:
|
if entity.y == y and entity.x == x:
|
||||||
if entity.is_fighting_entity():
|
if entity.is_fighting_entity():
|
||||||
self.hit(entity)
|
self.map.logs.add_message(self.hit(entity))
|
||||||
if entity.dead:
|
if entity.dead:
|
||||||
self.add_xp(randint(3, 7))
|
self.add_xp(randint(3, 7))
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -6,7 +6,7 @@ import sys
|
||||||
|
|
||||||
from .entities.player import Player
|
from .entities.player import Player
|
||||||
from .enums import GameMode, KeyValues, DisplayActions
|
from .enums import GameMode, KeyValues, DisplayActions
|
||||||
from .interfaces import Map
|
from .interfaces import Map, Logs
|
||||||
from .resources import ResourceManager
|
from .resources import ResourceManager
|
||||||
from .settings import Settings
|
from .settings import Settings
|
||||||
from . import menus
|
from . import menus
|
||||||
|
@ -33,6 +33,7 @@ class Game:
|
||||||
self.settings.load_settings()
|
self.settings.load_settings()
|
||||||
self.settings.write_settings()
|
self.settings.write_settings()
|
||||||
self.settings_menu.update_values(self.settings)
|
self.settings_menu.update_values(self.settings)
|
||||||
|
self.logs = Logs()
|
||||||
|
|
||||||
def new_game(self) -> None:
|
def new_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -40,6 +41,8 @@ class Game:
|
||||||
"""
|
"""
|
||||||
# TODO generate a new map procedurally
|
# TODO generate a new map procedurally
|
||||||
self.map = Map.load(ResourceManager.get_asset_path("example_map_2.txt"))
|
self.map = Map.load(ResourceManager.get_asset_path("example_map_2.txt"))
|
||||||
|
self.map.logs = self.logs
|
||||||
|
self.logs.clear()
|
||||||
self.player = Player()
|
self.player = Player()
|
||||||
self.map.add_entity(self.player)
|
self.map.add_entity(self.player)
|
||||||
self.player.move(self.map.start_y, self.map.start_x)
|
self.player.move(self.map.start_y, self.map.start_x)
|
||||||
|
|
|
@ -7,6 +7,26 @@ from typing import List, Optional
|
||||||
from squirrelbattle.display.texturepack import TexturePack
|
from squirrelbattle.display.texturepack import TexturePack
|
||||||
|
|
||||||
|
|
||||||
|
class Logs:
|
||||||
|
"""
|
||||||
|
The logs object stores the messages to display. It is encapsulating a list
|
||||||
|
of such messages, to allow multiple pointers to keep track of it even if
|
||||||
|
the list was to be reassigned.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.messages = []
|
||||||
|
|
||||||
|
def add_message(self, msg: str) -> None:
|
||||||
|
self.messages.append(msg)
|
||||||
|
|
||||||
|
def add_messages(self, msg: List[str]) -> None:
|
||||||
|
self.messages += msg
|
||||||
|
|
||||||
|
def clear(self) -> None:
|
||||||
|
self.messages = []
|
||||||
|
|
||||||
|
|
||||||
class Map:
|
class Map:
|
||||||
"""
|
"""
|
||||||
Object that represents a Map with its width, height
|
Object that represents a Map with its width, height
|
||||||
|
@ -18,6 +38,7 @@ class Map:
|
||||||
start_x: int
|
start_x: int
|
||||||
tiles: List[List["Tile"]]
|
tiles: List[List["Tile"]]
|
||||||
entities: List["Entity"]
|
entities: List["Entity"]
|
||||||
|
logs: Logs
|
||||||
# coordinates of the point that should be
|
# coordinates of the point that should be
|
||||||
# on the topleft corner of the screen
|
# on the topleft corner of the screen
|
||||||
currentx: int
|
currentx: int
|
||||||
|
@ -31,6 +52,7 @@ class Map:
|
||||||
self.start_x = start_x
|
self.start_x = start_x
|
||||||
self.tiles = tiles
|
self.tiles = tiles
|
||||||
self.entities = []
|
self.entities = []
|
||||||
|
self.logs = Logs()
|
||||||
|
|
||||||
def add_entity(self, entity: "Entity") -> None:
|
def add_entity(self, entity: "Entity") -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -362,19 +384,22 @@ class FightingEntity(Entity):
|
||||||
def dead(self) -> bool:
|
def dead(self) -> bool:
|
||||||
return self.health <= 0
|
return self.health <= 0
|
||||||
|
|
||||||
def hit(self, opponent: "FightingEntity") -> None:
|
def hit(self, opponent: "FightingEntity") -> str:
|
||||||
"""
|
"""
|
||||||
Deals damage to the opponent, based on the stats
|
Deals damage to the opponent, based on the stats
|
||||||
"""
|
"""
|
||||||
opponent.take_damage(self, self.strength)
|
return f"{self.name} hits {opponent.name}. "\
|
||||||
|
+ opponent.take_damage(self, self.strength)
|
||||||
|
|
||||||
def take_damage(self, attacker: "Entity", amount: int) -> None:
|
def take_damage(self, attacker: "Entity", amount: int) -> str:
|
||||||
"""
|
"""
|
||||||
Take damage from the attacker, based on the stats
|
Take damage from the attacker, based on the stats
|
||||||
"""
|
"""
|
||||||
self.health -= amount
|
self.health -= amount
|
||||||
if self.health <= 0:
|
if self.health <= 0:
|
||||||
self.die()
|
self.die()
|
||||||
|
return f"{self.name} takes {amount} damage."\
|
||||||
|
+ (f" {self.name} dies." if self.health <= 0 else "")
|
||||||
|
|
||||||
def die(self) -> None:
|
def die(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -42,9 +42,11 @@ class TestEntities(unittest.TestCase):
|
||||||
self.assertEqual(entity.maxhealth, entity.health)
|
self.assertEqual(entity.maxhealth, entity.health)
|
||||||
self.assertEqual(entity.strength, 2)
|
self.assertEqual(entity.strength, 2)
|
||||||
for _ in range(9):
|
for _ in range(9):
|
||||||
self.assertIsNone(entity.hit(entity))
|
self.assertEqual(entity.hit(entity),
|
||||||
|
"beaver hits beaver. beaver takes 2 damage.")
|
||||||
self.assertFalse(entity.dead)
|
self.assertFalse(entity.dead)
|
||||||
self.assertIsNone(entity.hit(entity))
|
self.assertEqual(entity.hit(entity), "beaver hits beaver. "
|
||||||
|
+ "beaver takes 2 damage. beaver dies.")
|
||||||
self.assertTrue(entity.dead)
|
self.assertTrue(entity.dead)
|
||||||
|
|
||||||
entity = Rabbit()
|
entity = Rabbit()
|
||||||
|
@ -64,6 +66,9 @@ class TestEntities(unittest.TestCase):
|
||||||
self.map.tick()
|
self.map.tick()
|
||||||
self.assertTrue(entity.y == 2 and entity.x == 6)
|
self.assertTrue(entity.y == 2 and entity.x == 6)
|
||||||
self.assertEqual(old_health - entity.strength, self.player.health)
|
self.assertEqual(old_health - entity.strength, self.player.health)
|
||||||
|
self.assertEqual(self.map.logs.messages[-1],
|
||||||
|
f"{entity.name} hits {self.player.name}. \
|
||||||
|
{self.player.name} takes {entity.strength} damage.")
|
||||||
|
|
||||||
# Fight the rabbit
|
# Fight the rabbit
|
||||||
old_health = entity.health
|
old_health = entity.health
|
||||||
|
@ -156,7 +161,7 @@ class TestEntities(unittest.TestCase):
|
||||||
self.assertFalse(player.move_up())
|
self.assertFalse(player.move_up())
|
||||||
self.assertTrue(player.move_left())
|
self.assertTrue(player.move_left())
|
||||||
self.assertFalse(player.move_left())
|
self.assertFalse(player.move_left())
|
||||||
for i in range(8):
|
for _ in range(8):
|
||||||
self.assertTrue(player.move_down())
|
self.assertTrue(player.move_down())
|
||||||
self.assertFalse(player.move_down())
|
self.assertFalse(player.move_down())
|
||||||
self.assertTrue(player.move_right())
|
self.assertTrue(player.move_right())
|
||||||
|
|
|
@ -17,6 +17,7 @@ class TestGame(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
self.game = Game()
|
self.game = Game()
|
||||||
self.game.new_game()
|
self.game.new_game()
|
||||||
|
self.game.logs.add_message("Hello World !")
|
||||||
display = DisplayManager(None, self.game)
|
display = DisplayManager(None, self.game)
|
||||||
self.game.display_actions = display.handle_display_action
|
self.game.display_actions = display.handle_display_action
|
||||||
|
|
||||||
|
@ -256,6 +257,17 @@ class TestGame(unittest.TestCase):
|
||||||
self.game.handle_key_pressed(KeyValues.ENTER)
|
self.game.handle_key_pressed(KeyValues.ENTER)
|
||||||
self.assertEqual(self.game.state, GameMode.MAINMENU)
|
self.assertEqual(self.game.state, GameMode.MAINMENU)
|
||||||
|
|
||||||
|
def test_logs(self) -> None:
|
||||||
|
"""
|
||||||
|
Tests the use of logs
|
||||||
|
"""
|
||||||
|
self.assertEqual(self.game.logs.messages, ["Hello World !"])
|
||||||
|
self.game.logs.add_messages(["Hello", "World"])
|
||||||
|
self.assertEqual(self.game.logs.messages, ["Hello World !",
|
||||||
|
"Hello", "World"])
|
||||||
|
self.game.logs.clear()
|
||||||
|
self.assertEqual(self.game.logs.messages, [])
|
||||||
|
|
||||||
def test_dead_screen(self) -> None:
|
def test_dead_screen(self) -> None:
|
||||||
"""
|
"""
|
||||||
Kill player and render dead screen.
|
Kill player and render dead screen.
|
||||||
|
|
Loading…
Reference in New Issue