Stagger cloud trail dissolution so tiles fade one at a time

Each cloud in the trail gets a slightly longer TTL than the one
before it (0.15s stagger). The origin cloud dissolves first, then
each subsequent tile follows. Two consecutive flights produce a
trail where the oldest clouds are already gone.
This commit is contained in:
Jared Miller 2026-02-07 14:17:48 -05:00
parent 93ad4523e2
commit a10f3d4e70
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
2 changed files with 19 additions and 9 deletions

View file

@ -14,8 +14,10 @@ world: Any = None
# how far you fly
FLY_DISTANCE = 5
# how long cloud trail lingers (seconds)
CLOUD_TTL = 2.0
# origin cloud gets the base ttl, each step toward destination adds stagger.
# trail visibly shrinks from origin toward the player, one tile at a time.
CLOUD_TTL = 1.5
CLOUD_STAGGER = 0.4 # seconds between each cloud's expiry
# ANSI color for cloud trails
CLOUD_COLOR = BOLD + BRIGHT_WHITE
@ -68,10 +70,13 @@ async def cmd_fly(player: Player, args: str) -> None:
dx, dy = delta
start_x, start_y = player.x, player.y
# lay cloud trail at starting position and each intermediate step
# lay cloud trail at starting position and each intermediate step.
# origin cloud expires first, near-dest cloud lingers longest.
# the trail shrinks from behind toward the player over time.
for step in range(FLY_DISTANCE):
trail_x, trail_y = world.wrap(start_x + dx * step, start_y + dy * step)
add_effect(trail_x, trail_y, "~", CLOUD_COLOR, ttl=CLOUD_TTL)
ttl = CLOUD_TTL + step * CLOUD_STAGGER
add_effect(trail_x, trail_y, "~", CLOUD_COLOR, ttl=ttl)
# move player to destination
dest_x, dest_y = world.wrap(

View file

@ -219,17 +219,22 @@ async def test_cloud_trail_chars_are_tilde(player):
@pytest.mark.asyncio
async def test_cloud_trail_has_ttl(player):
"""Cloud effects should expire after roughly 2 seconds."""
async def test_cloud_trail_dissolves_from_origin(player):
"""Origin cloud expires first, trail shrinks toward player."""
players[player.name] = player
player.flying = True
before = time.monotonic()
await fly.cmd_fly(player, "east")
for e in active_effects:
remaining = e.expires_at - before
assert 1.5 <= remaining <= 2.5
# effects are in path order (step 0..4)
expiries = [e.expires_at for e in active_effects]
# each should expire after the previous one (origin fades first)
for i in range(1, len(expiries)):
assert expiries[i] > expiries[i - 1]
# origin cloud ~1.5s, near-dest cloud ~1.5 + 4*0.4 = ~3.1s
assert 1.3 <= expiries[0] - before <= 1.7
assert 2.9 <= expiries[-1] - before <= 3.3
@pytest.mark.asyncio