1
0
Fork 0

Log messages in the game window

This commit is contained in:
Timothy Warren 2022-01-11 16:08:57 -05:00
parent 1d8539ee82
commit b0f5e2afe0
5 changed files with 110 additions and 5 deletions

View File

@ -1,6 +1,8 @@
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:
from engine import Engine
@ -71,11 +73,22 @@ class MeleeAction(ActionWithDirection):
damage = self.entity.fighter.power - target.fighter.defense
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:
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
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):

View File

@ -2,6 +2,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING
import color
from components.base_component import BaseComponent
from input_handlers import GameOverEventHandler
from render_order import RenderOrder
@ -32,9 +33,11 @@ class Fighter(BaseComponent):
def die(self) -> None:
if self.engine.player is self.entity:
death_message = "You died!"
death_message_color = color.player_die
self.engine.event_handler = GameOverEventHandler(self.engine)
else:
death_message = f"{self.entity.name} is dead!"
death_message_color = color.enemy_die
self.entity.char = "%"
self.entity.color = (191, 0, 0)
@ -43,4 +46,4 @@ class Fighter(BaseComponent):
self.entity.name = f"remains of {self.entity.name}"
self.entity.render_order = RenderOrder.CORPSE
print(death_message)
self.engine.message_log.add_message(death_message, death_message_color)

View File

@ -7,6 +7,7 @@ from tcod.console import Console
from tcod.map import compute_fov
from input_handlers import MainGameEventHandler
from message_log import MessageLog
from render_functions import render_bar
if TYPE_CHECKING:
@ -19,6 +20,7 @@ class Engine:
def __init__(self, player: Actor):
self.event_handler: EventHandler = MainGameEventHandler(self)
self.message_log = MessageLog()
self.player = player
def handle_enemy_turns(self) -> None:
@ -40,6 +42,8 @@ class Engine:
def render(self, console: Console, context: Context) -> None:
self.game_map.render(console)
self.message_log.render(console=console, x=21, y=45, width=40, height=5)
render_bar(
console,
current_value=self.player.fighter.hp,

View File

@ -3,6 +3,7 @@ import copy
import tcod
import color
from engine import Engine
import entity_factories
from procgen import generate_dungeon
@ -13,7 +14,7 @@ def main() -> None:
screen_height = 50
map_width = 80
map_height = 45
map_height = 43
room_max_size = 10
room_min_size = 6
@ -43,6 +44,11 @@ def main() -> None:
)
engine.update_fov()
engine.message_log.add_message(
"Hello and welcome, adventurer, to yet another dungeon!",
color.welcome_text
)
with tcod.context.new_terminal(
screen_width,
screen_height,

79
message_log.py Normal file
View 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