168 lines
4.7 KiB
Python
168 lines
4.7 KiB
Python
"""Pure functions for prompt rendering."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
from mudlib.render.colors import colorize
|
|
from mudlib.world.terrain import World
|
|
|
|
if TYPE_CHECKING:
|
|
from mudlib.player import Player
|
|
|
|
# Reverse lookup: char → name
|
|
_CHAR_TO_TERRAIN = {v: k for k, v in World.TERRAIN_CHARS.items()}
|
|
|
|
# Default prompt templates by mode
|
|
DEFAULT_TEMPLATES: dict[str, str] = {
|
|
"normal": "{stamina_gauge} <{pl}/{max_pl}> ",
|
|
"combat": "{stamina_gauge} <{pl}/{max_pl}> vs {opponent} > ",
|
|
"paint": (
|
|
"{stamina_gauge} <{pl}/{max_pl}>"
|
|
" ({x},{y}) [brush: {paint_brush}] {paint_state} "
|
|
),
|
|
"editor": "editor> ",
|
|
"if": "> ",
|
|
}
|
|
|
|
ADMIN_TEMPLATES: dict[str, str] = {
|
|
"normal": "{stamina_gauge} <{pl}/{max_pl}> ({x},{y}) {terrain} ",
|
|
"combat": "{stamina_gauge} <{pl}/{max_pl}> vs {opponent} > ({x},{y}) ",
|
|
}
|
|
|
|
|
|
def render_prompt(player: Player) -> str:
|
|
"""Render the prompt string based on player state and mode.
|
|
|
|
Args:
|
|
player: The player whose prompt to render
|
|
|
|
Returns:
|
|
Formatted prompt string with ANSI codes based on player color support
|
|
"""
|
|
# Get template from player override or mode default
|
|
if player.prompt_template:
|
|
template = player.prompt_template
|
|
elif player.paint_mode:
|
|
template = DEFAULT_TEMPLATES["paint"]
|
|
elif player.is_admin:
|
|
template = ADMIN_TEMPLATES.get(
|
|
player.mode, DEFAULT_TEMPLATES.get(player.mode, "{stamina_gauge} {pl} > ")
|
|
)
|
|
else:
|
|
template = DEFAULT_TEMPLATES.get(player.mode, "{stamina_gauge} {pl} > ")
|
|
|
|
# Build variable dictionary
|
|
stamina_pct = (
|
|
int((player.stamina / player.max_stamina) * 100)
|
|
if player.max_stamina > 0
|
|
else 0
|
|
)
|
|
|
|
# Compute stamina gauge with conditional coloring
|
|
if stamina_pct >= 60:
|
|
stamina_gauge = f"{{green}}<{stamina_pct}%>{{/}}"
|
|
elif stamina_pct >= 30:
|
|
stamina_gauge = f"{{yellow}}<{stamina_pct}%>{{/}}"
|
|
else:
|
|
stamina_gauge = f"{{red}}<{stamina_pct}%>{{/}}"
|
|
|
|
variables = {
|
|
"stamina_pct": str(stamina_pct),
|
|
"stamina": str(round(player.stamina)),
|
|
"max_stamina": str(round(player.max_stamina)),
|
|
"stamina_gauge": stamina_gauge,
|
|
"pl": str(round(player.pl)),
|
|
"max_pl": str(round(player.max_pl)),
|
|
"opponent": _get_opponent_name(player),
|
|
"move": _get_current_move(player),
|
|
"name": player.name,
|
|
"mode": player.mode,
|
|
"x": str(player.x),
|
|
"y": str(player.y),
|
|
"combat_state": _get_combat_state(player),
|
|
"terrain": _get_terrain_name(player),
|
|
"paint_brush": player.paint_brush,
|
|
"paint_state": "PAINTING" if player.painting else "SURVEYING",
|
|
}
|
|
|
|
# Substitute variables in template
|
|
result = template
|
|
for key, value in variables.items():
|
|
result = result.replace(f"{{{key}}}", value)
|
|
|
|
# Process color tags based on player's color support
|
|
result = colorize(result, player.color_depth)
|
|
|
|
return result
|
|
|
|
|
|
def _get_opponent_name(player: Player) -> str:
|
|
"""Get the name of the player's combat opponent if any.
|
|
|
|
Args:
|
|
player: The player to check
|
|
|
|
Returns:
|
|
Opponent name if in combat, empty string otherwise
|
|
"""
|
|
from mudlib.combat.engine import get_encounter
|
|
|
|
encounter = get_encounter(player)
|
|
if encounter is None:
|
|
return ""
|
|
|
|
# Determine who the opponent is (the other entity in the encounter)
|
|
if encounter.attacker is player:
|
|
return encounter.defender.name
|
|
return encounter.attacker.name
|
|
|
|
|
|
def _get_current_move(player: Player) -> str:
|
|
"""Get the name of the player's current combat move if any.
|
|
|
|
Args:
|
|
player: The player to check
|
|
|
|
Returns:
|
|
Move name if in combat with active move, empty string otherwise
|
|
"""
|
|
from mudlib.combat.engine import get_encounter
|
|
|
|
encounter = get_encounter(player)
|
|
if encounter is None:
|
|
return ""
|
|
|
|
if encounter.current_move is None:
|
|
return ""
|
|
|
|
return encounter.current_move.name
|
|
|
|
|
|
def _get_combat_state(player: Player) -> str:
|
|
"""Get the current combat state for the player.
|
|
|
|
Args:
|
|
player: The player to check
|
|
|
|
Returns:
|
|
Combat state string: "idle", "telegraph", "window", or "resolve"
|
|
"""
|
|
from mudlib.combat.engine import get_encounter
|
|
|
|
encounter = get_encounter(player)
|
|
if encounter is None:
|
|
return "idle"
|
|
|
|
return encounter.state.value
|
|
|
|
|
|
def _get_terrain_name(player: Player) -> str:
|
|
"""Get human-readable terrain name for player's current tile."""
|
|
from mudlib.zone import Zone
|
|
|
|
if not isinstance(player.location, Zone):
|
|
return "unknown"
|
|
|
|
tile = player.location.get_tile(player.x, player.y)
|
|
return _CHAR_TO_TERRAIN.get(tile, tile)
|