Mi2dRPGamEng/engine/tile.py

81 lines
3.1 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
TILE_LAYERS = ("subfloor", "flooring", "room", "roof")
@dataclass(frozen=True)
class TileLayerDef:
id: str
layer: str
texture: str | None = None
color: tuple[int, int, int] = (255, 0, 255)
walkable: bool = True
blocks_los: bool = False
deconstruct_item_id: str | None = None # item yielded by a careful (right-click) deconstruction
is_helm: bool = False # standing here lets a character steer the embedded map it's part of
staircase_direction: str | None = None # "up" or "down" - see Tile.staircase_direction
speed_multiplier: float = 1.0 # e.g. mud/water slow movement - see World.speed_multiplier_at
extra: dict = field(default_factory=dict)
@dataclass
class TileLayerInstance:
"""A layer's actual per-cell state (as opposed to its static def)."""
def_id: str
integrity: float = 100.0
@dataclass
class Tile:
subfloor: TileLayerInstance | None = None
flooring: TileLayerInstance | None = None
room: TileLayerInstance | None = None
roof: TileLayerInstance | None = None
def get_layer(self, layer: str) -> TileLayerInstance | None:
return getattr(self, layer)
def has_any_layer(self) -> bool:
"""False for a completely bare/unset tile - e.g. the open air a generated-terrain
column leaves above its own surface when nothing (slope/cave) was placed there. See
Renderer's depth-shading: it looks straight through tiles like this to whatever's
below, the same way World._apply_gravity does for movement.
"""
return any(self.get_layer(layer) is not None for layer in TILE_LAYERS)
def set_layer(self, layer: str, instance: TileLayerInstance | None) -> None:
setattr(self, layer, instance)
def layer_id(self, layer: str) -> str | None:
instance = self.get_layer(layer)
return instance.def_id if instance is not None else None
def is_walkable(self, registry) -> bool:
for layer in ("room", "flooring"):
layer_def = registry.get_tile_layer_def(layer, self.layer_id(layer))
if layer_def is not None and not layer_def.walkable:
return False
return True
def staircase_direction(self, registry) -> str | None:
"""'up'/'down' if either layer here is a staircase/ladder, else None."""
for layer in ("room", "flooring"):
layer_def = registry.get_tile_layer_def(layer, self.layer_id(layer))
if layer_def is not None and layer_def.staircase_direction is not None:
return layer_def.staircase_direction
return None
def speed_multiplier(self, registry) -> float:
"""The most restrictive speed_multiplier among this tile's layers (e.g. mud/water
flooring slowing movement) - 1.0 (no slow) if nothing here restricts it.
"""
multiplier = 1.0
for layer in ("room", "flooring"):
layer_def = registry.get_tile_layer_def(layer, self.layer_id(layer))
if layer_def is not None:
multiplier = min(multiplier, layer_def.speed_multiplier)
return multiplier