Log messages in the game window
This commit is contained in:
parent
1d8539ee82
commit
b0f5e2afe0
19
actions.py
19
actions.py
@ -1,6 +1,8 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Optional, Tuple, TYPE_CHECKING, overload
|
from typing import overload, Optional, Tuple, TYPE_CHECKING
|
||||||
|
|
||||||
|
import color
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from engine import Engine
|
from engine import Engine
|
||||||
@ -71,11 +73,22 @@ class MeleeAction(ActionWithDirection):
|
|||||||
damage = self.entity.fighter.power - target.fighter.defense
|
damage = self.entity.fighter.power - target.fighter.defense
|
||||||
|
|
||||||
attack_desc = f"{self.entity.name.capitalize()} attacks {target.name}"
|
attack_desc = f"{self.entity.name.capitalize()} attacks {target.name}"
|
||||||
|
if self.entity is self.engine.player:
|
||||||
|
attack_color = color.player_atk
|
||||||
|
else:
|
||||||
|
attack_color = color.enemy_atk
|
||||||
|
|
||||||
if damage > 0:
|
if damage > 0:
|
||||||
print(f"{attack_desc} for {damage} hit points.")
|
self.engine.message_log.add_message(
|
||||||
|
f"{attack_desc} for {damage} hit points.",
|
||||||
|
attack_color,
|
||||||
|
)
|
||||||
target.fighter.hp -= damage
|
target.fighter.hp -= damage
|
||||||
else:
|
else:
|
||||||
print(f"{attack_desc} but does no damage.")
|
self.engine.message_log.add_message(
|
||||||
|
f"{attack_desc} but does no damage.",
|
||||||
|
attack_color,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MovementAction(ActionWithDirection):
|
class MovementAction(ActionWithDirection):
|
||||||
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import color
|
||||||
from components.base_component import BaseComponent
|
from components.base_component import BaseComponent
|
||||||
from input_handlers import GameOverEventHandler
|
from input_handlers import GameOverEventHandler
|
||||||
from render_order import RenderOrder
|
from render_order import RenderOrder
|
||||||
@ -32,9 +33,11 @@ class Fighter(BaseComponent):
|
|||||||
def die(self) -> None:
|
def die(self) -> None:
|
||||||
if self.engine.player is self.entity:
|
if self.engine.player is self.entity:
|
||||||
death_message = "You died!"
|
death_message = "You died!"
|
||||||
|
death_message_color = color.player_die
|
||||||
self.engine.event_handler = GameOverEventHandler(self.engine)
|
self.engine.event_handler = GameOverEventHandler(self.engine)
|
||||||
else:
|
else:
|
||||||
death_message = f"{self.entity.name} is dead!"
|
death_message = f"{self.entity.name} is dead!"
|
||||||
|
death_message_color = color.enemy_die
|
||||||
|
|
||||||
self.entity.char = "%"
|
self.entity.char = "%"
|
||||||
self.entity.color = (191, 0, 0)
|
self.entity.color = (191, 0, 0)
|
||||||
@ -43,4 +46,4 @@ class Fighter(BaseComponent):
|
|||||||
self.entity.name = f"remains of {self.entity.name}"
|
self.entity.name = f"remains of {self.entity.name}"
|
||||||
self.entity.render_order = RenderOrder.CORPSE
|
self.entity.render_order = RenderOrder.CORPSE
|
||||||
|
|
||||||
print(death_message)
|
self.engine.message_log.add_message(death_message, death_message_color)
|
||||||
|
@ -7,6 +7,7 @@ from tcod.console import Console
|
|||||||
from tcod.map import compute_fov
|
from tcod.map import compute_fov
|
||||||
|
|
||||||
from input_handlers import MainGameEventHandler
|
from input_handlers import MainGameEventHandler
|
||||||
|
from message_log import MessageLog
|
||||||
from render_functions import render_bar
|
from render_functions import render_bar
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -19,6 +20,7 @@ class Engine:
|
|||||||
|
|
||||||
def __init__(self, player: Actor):
|
def __init__(self, player: Actor):
|
||||||
self.event_handler: EventHandler = MainGameEventHandler(self)
|
self.event_handler: EventHandler = MainGameEventHandler(self)
|
||||||
|
self.message_log = MessageLog()
|
||||||
self.player = player
|
self.player = player
|
||||||
|
|
||||||
def handle_enemy_turns(self) -> None:
|
def handle_enemy_turns(self) -> None:
|
||||||
@ -40,6 +42,8 @@ class Engine:
|
|||||||
def render(self, console: Console, context: Context) -> None:
|
def render(self, console: Console, context: Context) -> None:
|
||||||
self.game_map.render(console)
|
self.game_map.render(console)
|
||||||
|
|
||||||
|
self.message_log.render(console=console, x=21, y=45, width=40, height=5)
|
||||||
|
|
||||||
render_bar(
|
render_bar(
|
||||||
console,
|
console,
|
||||||
current_value=self.player.fighter.hp,
|
current_value=self.player.fighter.hp,
|
||||||
|
8
main.py
8
main.py
@ -3,6 +3,7 @@ import copy
|
|||||||
|
|
||||||
import tcod
|
import tcod
|
||||||
|
|
||||||
|
import color
|
||||||
from engine import Engine
|
from engine import Engine
|
||||||
import entity_factories
|
import entity_factories
|
||||||
from procgen import generate_dungeon
|
from procgen import generate_dungeon
|
||||||
@ -13,7 +14,7 @@ def main() -> None:
|
|||||||
screen_height = 50
|
screen_height = 50
|
||||||
|
|
||||||
map_width = 80
|
map_width = 80
|
||||||
map_height = 45
|
map_height = 43
|
||||||
|
|
||||||
room_max_size = 10
|
room_max_size = 10
|
||||||
room_min_size = 6
|
room_min_size = 6
|
||||||
@ -43,6 +44,11 @@ def main() -> None:
|
|||||||
)
|
)
|
||||||
engine.update_fov()
|
engine.update_fov()
|
||||||
|
|
||||||
|
engine.message_log.add_message(
|
||||||
|
"Hello and welcome, adventurer, to yet another dungeon!",
|
||||||
|
color.welcome_text
|
||||||
|
)
|
||||||
|
|
||||||
with tcod.context.new_terminal(
|
with tcod.context.new_terminal(
|
||||||
screen_width,
|
screen_width,
|
||||||
screen_height,
|
screen_height,
|
||||||
|
79
message_log.py
Normal file
79
message_log.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
from typing import List, Reversible, Tuple
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
import tcod
|
||||||
|
|
||||||
|
import color
|
||||||
|
|
||||||
|
|
||||||
|
class Message:
|
||||||
|
def __init__(self, text: str, fg: Tuple[int, int, int]):
|
||||||
|
self.plain_text = text
|
||||||
|
self.fg = fg
|
||||||
|
self.count = 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_text(self) -> str:
|
||||||
|
"""The full text of this message, including the count if necessary."""
|
||||||
|
if self.count > 1:
|
||||||
|
return f"{self.plain_text} (x{self.count}"
|
||||||
|
|
||||||
|
return self.plain_text
|
||||||
|
|
||||||
|
|
||||||
|
class MessageLog:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.messages: List[Message] = []
|
||||||
|
|
||||||
|
def add_message(
|
||||||
|
self,
|
||||||
|
text: str,
|
||||||
|
fg: Tuple[int, int, int] = color.white,
|
||||||
|
*,
|
||||||
|
stack: bool = True
|
||||||
|
) -> None:
|
||||||
|
"""Add a message to this log.
|
||||||
|
`text` is the message text, `fg` is the text color.
|
||||||
|
If `stack is True then the message can stack with a previous message
|
||||||
|
of the same text.
|
||||||
|
"""
|
||||||
|
if stack and self.messages and text == self.messages[-1].plain_text:
|
||||||
|
self.messages[-1].count += 1
|
||||||
|
else:
|
||||||
|
self.messages.append(Message(text, fg))
|
||||||
|
|
||||||
|
def render(
|
||||||
|
self,
|
||||||
|
console: tcod.Console,
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
width: int,
|
||||||
|
height: int,
|
||||||
|
) -> None:
|
||||||
|
"""Render this log over the given area.
|
||||||
|
`x`, `y`, `width`, `height` is the rectangular region to render onto
|
||||||
|
the `console`.
|
||||||
|
"""
|
||||||
|
self.render_messages(console, x, y, width, height, self.messages)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def render_messages(
|
||||||
|
console: tcod.Console,
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
width: int,
|
||||||
|
height: int,
|
||||||
|
messages: Reversible[Message],
|
||||||
|
) -> None:
|
||||||
|
"""Render the messages provided.
|
||||||
|
The `messages` are rendered starting at the last message and working
|
||||||
|
backwards.
|
||||||
|
"""
|
||||||
|
y_offset = height - 1
|
||||||
|
|
||||||
|
for message in reversed(messages):
|
||||||
|
for line in reversed(textwrap.wrap(message.full_text, width)):
|
||||||
|
console.print(x=x, y=y + y_offset, string=line, fg=message.fg)
|
||||||
|
y_offset -= 1
|
||||||
|
if y_offset < 0:
|
||||||
|
return # No more space to print messages
|
Loading…
Reference in New Issue
Block a user