45 lines
1.8 KiB
Python
45 lines
1.8 KiB
Python
from __future__ import annotations
|
|
|
|
from engine.character import Character
|
|
from engine.world import TimeWarpZone, World
|
|
|
|
DEFAULT_RADIUS = 3.0
|
|
DEFAULT_SPEED_FACTOR = 0.3 # 30% normal speed inside the sphere
|
|
DEFAULT_DURATION = 5.0 # seconds
|
|
|
|
|
|
def cast_time_warp_sphere(
|
|
caster: Character,
|
|
world: World,
|
|
now: float,
|
|
center: tuple[float, float, float] | None = None,
|
|
radius: float = DEFAULT_RADIUS,
|
|
speed_factor: float = DEFAULT_SPEED_FACTOR,
|
|
duration: float = DEFAULT_DURATION,
|
|
whitelist: set[str] | None = None,
|
|
) -> TimeWarpZone:
|
|
"""Sample ability: everything inside the sphere (except the caster and `whitelist`, e.g.
|
|
allies) moves at `speed_factor` of normal for `duration` seconds. Size, speed factor,
|
|
whitelist, and time are all just arguments - this is deliberately not tied to being cast
|
|
from a character ability vs. an item; see grants_ability on ItemDef and resources/logic/
|
|
actions.py::activate_hand for the item attachment point, and Character.can_perform_ability
|
|
for gating a direct character-ability trigger the same way leap/melee/ranged already are.
|
|
Note: only entity *movement* speed is actually slowed (see World.speed_multiplier_at) -
|
|
this engine resolves shots as instant hit-scans with no travel-time to slow.
|
|
"""
|
|
assert caster.position is not None
|
|
if center is None:
|
|
center = (caster.position.x, caster.position.y, caster.position.z)
|
|
immune = set(whitelist) if whitelist is not None else set()
|
|
immune.add(caster.entity_id)
|
|
zone = TimeWarpZone(
|
|
map_id=caster.position.map_id,
|
|
center=center,
|
|
radius=radius,
|
|
speed_factor=speed_factor,
|
|
expires_at=now + duration,
|
|
immune_entity_ids=immune,
|
|
)
|
|
world.time_warp_zones.append(zone)
|
|
return zone
|