"""Base entity class for characters in the world.""" from __future__ import annotations from dataclasses import dataclass, field from typing import TYPE_CHECKING from mudlib.object import Object if TYPE_CHECKING: from mudlib.npc_schedule import NpcSchedule @dataclass(eq=False) class Entity(Object): """Base class for anything with position and identity in the world. Inherits name, location from Object. Narrows x, y to int (entities always have spatial coordinates). """ # Entities always have spatial coordinates (override Object's int | None) x: int = 0 y: int = 0 # Combat stats pl: float = 100.0 # power level (health and damage multiplier) max_pl: float = 100.0 # maximum power level stamina: float = 100.0 # current stamina max_stamina: float = 100.0 # stamina ceiling defense_locked_until: float = 0.0 # monotonic time when defense recovery ends resting: bool = False # whether this entity is currently resting sleeping: bool = False # whether this entity is currently sleeping (deep rest) _last_stamina_cue: float = 1.0 # Last stamina percentage that triggered a cue @property def posture(self) -> str: """Return entity's current posture for room display. Priority order: unconscious > fighting > flying > sleeping > resting > standing """ # Unconscious (highest priority) if self.pl <= 0 or self.stamina <= 0: return "unconscious" # Fighting (only for Player with mode="combat") if hasattr(self, "mode") and self.mode == "combat": return "fighting" # Flying (only for Player) if getattr(self, "flying", False): return "flying" # Sleeping (before resting since sleeping implies resting) if self.sleeping: return "sleeping" # Resting if self.resting: return "resting" # Default return "standing" def can_accept(self, obj: Object) -> bool: """Entities accept portable Things (inventory).""" from mudlib.thing import Thing return isinstance(obj, Thing) and obj.portable async def send(self, message: str) -> None: """Send a message to this entity. Base implementation is a no-op.""" pass @dataclass(eq=False) class Mob(Entity): """Represents a non-player character (NPC) in the world.""" description: str = "" alive: bool = True moves: list[str] = field(default_factory=list) next_action_at: float = 0.0 home_x_min: int | None = None home_x_max: int | None = None home_y_min: int | None = None home_y_max: int | None = None # NPC behavior state machine behavior_state: str = "idle" behavior_data: dict = field(default_factory=dict) npc_name: str | None = None # links to dialogue tree schedule: NpcSchedule | None = None # time-based behavior schedule schedule_last_hour: int | None = None # last hour schedule was processed