Mi2dRPGamEng/engine/start_screen.py

68 lines
2.7 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
from engine.character import Character
from engine.character_library import CharacterLibrary
from engine.defs import DefRegistry
from engine.entity import EntityPosition
from engine.world import World
@dataclass
class StartScreen:
"""Pure interaction state for the pre-game start screen: pick one of the current account's
persistent characters (see engine/character_library.py::CharacterLibrary) to join a session
with - single-player continuation or joining someone else's multiplayer world with a
character built up over time.
No rendering here - same boundary as LayerPickerMenu/AbilityBar/CharacterMenu in
engine/ui.py: listing characters as clickable rows and drawing the screen itself is a
follow-up UI-layer task. This is the state/logic side: which characters exist for this
account, which one is currently selected, and handing off to join_selected_character()
once confirmed. Creating a brand new character is a separate flow - see
engine/character_creator.py.
"""
account_id: str
characters: list[tuple[str, str, str | None]] = field(default_factory=list) # (character_id, name, species_id)
selected_index: int | None = None
@classmethod
def load_for_account(cls, account_id: str, library: CharacterLibrary) -> "StartScreen":
return cls(account_id=account_id, characters=library.list_characters(account_id))
def refresh(self, library: CharacterLibrary) -> None:
"""Re-reads the character list (e.g. after creating or deleting one) and clears selection."""
self.characters = library.list_characters(self.account_id)
self.selected_index = None
def select(self, index: int) -> None:
if 0 <= index < len(self.characters):
self.selected_index = index
def selected_character_id(self) -> str | None:
if self.selected_index is None:
return None
return self.characters[self.selected_index][0]
def join_world_with_character(
world: World,
library: CharacterLibrary,
account_id: str,
character_id: str,
registry: DefRegistry,
spawn_position: EntityPosition,
) -> Character | None:
"""Loads a persistent character from the library and drops it into `world` at
`spawn_position` - the "confirm join" action once a StartScreen selection is made. Returns
None (no-op on `world`) if no such character exists for this account.
"""
character = library.load_character(account_id, character_id, registry)
if character is None:
return None
character.position = spawn_position
world.add_entity(character)
return character