53 lines
2.1 KiB
Python
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
|