Detonate rifle grenades on impact with original Half-Life fireball

This commit is contained in:
enne2
2026-10-15 14:20:07 +02:00
parent ae32ad9615
commit 5761e160c1
12 changed files with 581 additions and 81 deletions
+78 -14
View File
@@ -1,22 +1,86 @@
# Grenades and growing waves
- Right mouse button: throw while mouse is captured and player alive.
- Cooldown: 15 seconds from launch, displayed in HUD; cannot be bypassed by repeated clicks.
- Physical RigidBody3D: sphere radius 0.12m, mass0.4kg, bounce0.45, friction0.65, gravity, CCD; launch velocity forward12m/s + up3m/s + player velocity. Thrower excluded from projectile collision but not blast damage.
- Fuse: four physics seconds from spawn; one deferred detonation.
- Blast radius5m, maximum damage160 diminishing linearly with distance; world collision ray blocks damage through walls. Includes thrower if alive. CPU particles/flash and original Half-Life explode3–5.wav.
- Original Valve grenade.mdl contains two embedded textures; copied unchanged and exported to native grenade.scn for Web. Provenance in assets/half_life_manifest.json; extraction script tools/extract_grenade_assets.py.
- Wave size: 4 + 2*wave (6,8,10,...), no old24 limit. Next wave three seconds after all enemies die and spawning completes. Scheduling guard prevents duplicate wave timers. Corpses remain.
## Rifle grenade: contact detonation
## Tests
- 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 **160**, linear falloff; a world-mask ray prevents
damage through walls. The living thrower is still included.
Godot4.7.1:
## Original Half-Life explosion
```
--headless --path . --script res://tools/test_grenade.gd
--headless --path . --script res://tools/test_wave_growth.gd
`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
Wave size: **4 + 2 × wave** (6, 8, 10, ...), no old cap of 24. 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
```
Grenade test PASS: movement/gravity, fuse3.997s, actual15s cooldown, visible/blocked/out-of-radius damage, self-damage and formula26 enemies for wave11. Wave test PASS: six zombies cleared, single next wave spawns eight, six corpses retained; an existing shutdown resource warning remains in the wave test, not a gameplay error.
`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.
Published Web release4e181f0fe5d02cc9 at https://enne2.net/pub/zombie-fps/; gzip+immutable cache retained. Browser right-click test showed HUD countdown10s after throw. Backup prior root HTML: /home/debian/zombie-fps-backups/index-before-grenade.html. Previous releases kept; no nginx changes.
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.