84 lines
3.3 KiB
Python
84 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
import uuid
|
|
from dataclasses import dataclass, field
|
|
|
|
from engine.character import Character
|
|
from engine.defs import DefRegistry
|
|
from engine.item import ItemInstance
|
|
|
|
|
|
@dataclass
|
|
class DevSpawnMenu:
|
|
"""Dev-mode-only cheat tool: cycle through every loaded item def and materialize one
|
|
straight into the player's inventory (first free-fitting slot). Gated off in normal play by
|
|
engine/dev_config.py::DevConfig.enabled - see main.py's dev_spawn_object handling.
|
|
|
|
No world floor-item system exists in this engine yet (items only ever live in an Inventory,
|
|
or worn/held on a Character), so "spawning" here means "into inventory", not placing a loose
|
|
item on the ground - that's a bigger feature this doesn't attempt.
|
|
"""
|
|
|
|
registry: DefRegistry
|
|
item_ids: list[str] = field(default_factory=list)
|
|
selected_index: int = 0
|
|
|
|
def __post_init__(self) -> None:
|
|
if not self.item_ids:
|
|
# secret items (see ItemDef.secret, e.g. a one-off vanity implant) are deliberately
|
|
# left out of the cycle - they still work fine if granted some other way, they just
|
|
# aren't discoverable through this menu.
|
|
self.item_ids = sorted(def_id for def_id, item_def in self.registry.item_defs.items() if not item_def.secret)
|
|
|
|
def cycle(self, delta: int) -> None:
|
|
if self.item_ids:
|
|
self.selected_index = (self.selected_index + delta) % len(self.item_ids)
|
|
|
|
def selected_item_id(self) -> str | None:
|
|
if not self.item_ids:
|
|
return None
|
|
return self.item_ids[self.selected_index]
|
|
|
|
def spawn_into(self, character: Character) -> bool:
|
|
"""Returns whether it actually fit - a no-op (False) if the character has no inventory
|
|
or the selected item has nowhere left to go.
|
|
"""
|
|
item_id = self.selected_item_id()
|
|
if item_id is None or character.inventory is None:
|
|
return False
|
|
item_def = self.registry.get_item_def(item_id)
|
|
slot = character.inventory.find_first_fit(item_def)
|
|
if slot is None:
|
|
return False
|
|
instance = ItemInstance(f"dev-spawn-{uuid.uuid4().hex[:8]}", item_id)
|
|
return character.inventory.place(instance, item_def, *slot)
|
|
|
|
|
|
@dataclass
|
|
class DevTurretMenu:
|
|
"""Dev-mode-only cheat tool: cycle through every turret entity template (see entities.json's
|
|
turret_pistol/turret_autocannon - any template with turret_weapon_item_id set, so a new
|
|
variant only needs adding to entities.json, not here) and place the selected one into the
|
|
world - see main.py's dev_place_turret handling.
|
|
"""
|
|
|
|
registry: DefRegistry
|
|
entity_def_ids: list[str] = field(default_factory=list)
|
|
selected_index: int = 0
|
|
|
|
def __post_init__(self) -> None:
|
|
if not self.entity_def_ids:
|
|
self.entity_def_ids = sorted(
|
|
def_id for def_id, entity_def in self.registry.entity_defs.items()
|
|
if entity_def.turret_weapon_item_id is not None
|
|
)
|
|
|
|
def cycle(self, delta: int) -> None:
|
|
if self.entity_def_ids:
|
|
self.selected_index = (self.selected_index + delta) % len(self.entity_def_ids)
|
|
|
|
def selected_entity_def_id(self) -> str | None:
|
|
if not self.entity_def_ids:
|
|
return None
|
|
return self.entity_def_ids[self.selected_index]
|