Files
zombie-fps/docs/GRENADES-WAVES.md

89 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Grenades and growing waves
## Rifle grenade: contact detonation
- Right mouse button / touch GRENADE: launch while alive (mouse captured on desktop).
- Cooldown: **15 seconds from launch**, displayed in HUD; repeated clicks cannot bypass it.
- Physical `RigidBody3D`: sphere radius 0.12 m, mass 0.4 kg, **no bounce**, friction 0.65,
gravity and continuous collision detection (CCD). Velocity: forward 12 m/s + up 3 m/s
+ player velocity. The thrower is excluded from projectile collision, not blast damage.
- **First contact detonates immediately**: ground, walls, office props and enemies.
`contact_monitor=true`, `max_contacts_reported=8`; `_integrate_forces()` captures the
physics position, `body_entered` is a fallback. One synchronous `exploded` guard and
one deferred `_explode()` prevent duplicate effects/damage and scene changes during
physics callbacks. Damage rays start at the sphere centre, on the free side of the wall.
- Window panes are `Area3D`, layer 8, not physical bodies: a swept ray between physics
positions detects these separately, including fast crossings of thin glass. This does
not add environmental destruction (the existing zombie-entry glass shatter is unchanged).
- **No 4-second fuse anymore**. A lost projectile is deleted after 15 seconds without
an explosion, avoiding orphan nodes or delayed airborne blasts.
- Blast radius **5 m**, maximum damage **320**, linear falloff; a world-mask ray prevents
damage through walls. The living thrower is still included.
## Original Half-Life explosion
`scripts/grenade_explosion.gd` uses Valve's `sprites/zerogxplode.spr`, the fireball
referenced by Half-Life's `TE_EXPLOSION`. The original SDK uses **15 FPS** and the
sprite has **15 frames, 64×64 each**: one second, no looping.
`tools/extract_explosion_sprite.py` reads the local Steam installation without changing
it, validates IDSP v2 / additive format, and converts the original RGB palette/frames to
`assets/effects/explosion/zerogxplode_atlas.png`. Source/output SHA256, frame origins,
format and timing are recorded in the adjacent `source_manifest.json`.
- PNG atlas **340×204**, 5×3 frames with 2-pixel black gutters; UVs crop the gutters to
avoid bleeding between frames under linear filtering.
- Camera-facing 3.2 m quad, **additive and unshaded**, normal depth testing (not visible
through walls), no shadows. Original RGB is preserved: black contributes zero under
additive blending; do not treat the last palette index as alpha-test transparency.
- Fireball raised 0.8 m above the physical blast centre to reduce floor clipping. Damage
stays at the actual impact; visual position does not change blast distance or occlusion.
- Orange flash fades over 0.3 s, with no shadow-casting light; 18 small CPU embers are
secondary to the fireball. Original `weapons/explode3–5.wav` unchanged. The effect node
remains alive 4 s for audio, while the sprite disappears after its single playback.
- Plain PNG/QuadMesh/StandardMaterial3D and CPU particles: compatible with the Web
Compatibility renderer; no native SPR importer or GPU-only effects at runtime.
Other original assets: `grenade.mdl` (two embedded textures), native `grenade.scn` for
Web and explosion WAVs; provenance `assets/half_life_manifest.json`, extraction
`tools/extract_grenade_assets.py`.
## Growing waves
Ordinary wave size: **4 + 2 × wave** (6, 8, 10, ...), no old cap of 24. Every tenth
wave (10, 20, 30, ...) is instead **one Alien Grunt boss**, with no ordinary zombies;
see `docs/BOSS.md` for scaling, teleport arrival and the native-only test sandbox.
Next wave three seconds after all enemies die and spawning completes. Scheduling
guard prevents duplicate wave timers. Corpses remain.
## Tests and visual verification
Godot **4.7.1**, not the older binary on PATH:
```bash
G="$HOME/.local/opt/godot-4.7.1/Godot_v4.7.1-stable_linux.x86_64"
"$G" --headless --path . --script res://tools/test_grenade.gd
"$G" --headless --path . --script res://tools/test_wave_growth.gd
DISPLAY=:0 "$G" --display-driver x11 --rendering-method gl_compatibility --path . \
--script res://tools/shot_grenade.gd
```
`test_grenade`: **24 checks**, real floor/desk/thin-wall/enemy/glass collisions, rapid
crossings at 80 m/s, single detonation, enemy damage, motion/gravity/thrower exclusion,
real 15-second cooldown, blast LOS/range/self-damage, absence of a 4-second fuse,
non-explosive cleanup, additive billboard atlas and one-shot frame timing, wave growth.
Visual harness captures original frames 0/3/7/11/14 **after an actual floor impact** in
the office (`/tmp/zombie-grenade-frame-*.png`). Desktop tests use no public scores API.
The start-screen GUI regression needs a real display, not the headless dummy driver.
Sources:
- https://github.com/ValveSoftware/halflife/blob/master/dlls/ggrenade.cpp (`ShootContact`,
`ExplodeTouch`, `TE_EXPLOSION`, frame rate 15).
- https://github.com/ValveSoftware/halflife/blob/master/dlls/weapons.cpp (fireball precache).
- https://github.com/ValveSoftware/halflife/blob/master/utils/sprgen/sprgen.c (SPR format).
- https://docs.godotengine.org/en/stable/classes/class_rigidbody3d.html (contact reporting).
Historical first grenade release: `4e181f0fe5d02cc9` used the old 4-second fuse and a
particle-only explosion. It is superseded; current behavior is described above.