Draw three windows with frames: - map window - info window (hit point bar; turn count) - message window Clean up the UI code in the Engine.
		
			
				
	
	
		
			93 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Eryn Wells <eryn@erynwells.me>
 | 
						|
 | 
						|
'''
 | 
						|
Defines the classes the support the in-game message log. Messages are recorded to the log as game actions are handled. A
 | 
						|
short buffer of messages is displayed in the game's HUD, and a full list of messages can be viewed by the player at any
 | 
						|
time.
 | 
						|
'''
 | 
						|
 | 
						|
import textwrap
 | 
						|
from typing import List, Optional, Reversible, Tuple
 | 
						|
 | 
						|
import tcod
 | 
						|
 | 
						|
from .geometry import Rect
 | 
						|
 | 
						|
 | 
						|
class Message:
 | 
						|
    '''A message in the message log
 | 
						|
 | 
						|
    Attributes
 | 
						|
    ----------
 | 
						|
    text : str
 | 
						|
        The text of the message
 | 
						|
    foreground : Tuple[int, int, int]
 | 
						|
        The foreground color to render the message with
 | 
						|
    count : int
 | 
						|
        The number of times this message has stacked
 | 
						|
    '''
 | 
						|
 | 
						|
    def __init__(self, text: str, fg: Optional[Tuple[int, int, int]] = None):
 | 
						|
        self.text = text
 | 
						|
        self.foreground = fg
 | 
						|
        self.count = 1
 | 
						|
 | 
						|
    @property
 | 
						|
    def full_text(self) -> str:
 | 
						|
        '''The full text of the message, including a count of repeats, if present'''
 | 
						|
        if self.count == 1:
 | 
						|
            return self.text
 | 
						|
        return f'{self.text} (x{self.count})'
 | 
						|
 | 
						|
    def __str__(self) -> str:
 | 
						|
        return self.text
 | 
						|
 | 
						|
    def __repr__(self) -> str:
 | 
						|
        return f'{self.__class__.__name__}({repr(self.text)}, fg={self.foreground})'
 | 
						|
 | 
						|
 | 
						|
class MessageLog:
 | 
						|
    '''A buffer of messages sent to the player by the game'''
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.messages: List[Message] = []
 | 
						|
 | 
						|
    def add_message(self, text: str, fg: Optional[Tuple[int, int, int]] = None, stack: bool = True):
 | 
						|
        '''
 | 
						|
        Add a message to the buffer
 | 
						|
 | 
						|
        Parameters
 | 
						|
        ----------
 | 
						|
        text : str
 | 
						|
            The text of the message
 | 
						|
        fg : Tuple[int, int, int], optional
 | 
						|
            A foreground color to render the text
 | 
						|
        stack : bool
 | 
						|
            If True and the previous message in the buffer is the same as the text given, increment the count of that
 | 
						|
            message rather than adding a new message to the buffer
 | 
						|
        '''
 | 
						|
        if stack and self.messages and self.messages[-1].text == text:
 | 
						|
            self.messages[-1].count += 1
 | 
						|
        else:
 | 
						|
            self.messages.append(Message(text, fg))
 | 
						|
 | 
						|
    def render_to_console(self, console: tcod.console.Console, rect: Rect):
 | 
						|
        '''Render this message log to the given console in the given rect'''
 | 
						|
        self.render_messages(console, rect, self.messages)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def render_messages(console: tcod.console.Console, rect: Rect, messages: Reversible[Message]):
 | 
						|
        '''Render a list of messages to the console in the given rect'''
 | 
						|
        y_offset = min(rect.size.height, len(messages)) - 1
 | 
						|
 | 
						|
        for message in reversed(messages):
 | 
						|
            wrapped_text = textwrap.wrap(message.full_text, rect.size.width)
 | 
						|
            for line in wrapped_text:
 | 
						|
                console.print(x=rect.min_x, y=rect.min_y + y_offset, string=line, fg=message.foreground)
 | 
						|
                y_offset -= 1
 | 
						|
 | 
						|
                if y_offset < 0:
 | 
						|
                    break
 | 
						|
 | 
						|
            if y_offset < 0:
 | 
						|
                break
 |