Mi2dRPGamEng/resources/logic/organs.py

53 lines
2.1 KiB
Python

from __future__ import annotations
from engine.character import Character
from engine.defs import DefRegistry
def apply_organ_interactions_tick(character: Character, registry: DefRegistry, ticks: int) -> None:
"""Damaged organs stress the organs they affect (OrganDef.affects_organs), e.g. a weakened
heart gradually strains the kidneys. Damage per tick is proportional to both the source
organ's own damage fraction and the elapsed ticks. Sources are snapshotted before any
damage is applied, so effects don't cascade within the same tick (a heart hit doesn't also
immediately hit whatever the newly-damaged kidneys affect, this call).
"""
if ticks <= 0:
return
sources: list[tuple[str, float]] = []
for part in character.resolved_body_parts().values():
if part is None:
continue
for organ in part.organs:
if organ.removed:
continue
organ_def = registry.get_organ_def(organ.organ_def_id)
if not organ_def.affects_organs:
continue
damage_fraction = 1.0 - (organ.integrity / 100.0)
if damage_fraction <= 0.0:
continue
sources.append((organ_def.id, damage_fraction))
for source_id, damage_fraction in sources:
source_def = registry.get_organ_def(source_id)
for target_organ_id, rate in source_def.affects_organs.items():
_damage_organ(character, target_organ_id, rate * damage_fraction * ticks)
def _damage_organ(character: Character, organ_def_id: str, amount: float) -> None:
if amount <= 0:
return
for slot, part in character.resolved_body_parts().items():
if part is None:
continue
if not any(o.organ_def_id == organ_def_id for o in part.organs):
continue
override = character.get_or_create_body_part_override(slot)
assert override is not None
organ = next(o for o in override.organs if o.organ_def_id == organ_def_id)
organ.integrity = max(0.0, organ.integrity - amount)
if organ.integrity <= 0.0:
organ.removed = True
return