- Add fists weapon viewmodel with idle/hit animation states (220ms hit pose)
- Implement mouse-wheel weapon cycling that skips unowned weapons
- Add 33% chance for killed guards to drop ammo-clip pickups at death location
- Introduce campaign carry-over system preserving weapons/ammo/health between missions
- Fix stale 'attack' state clearing when enemies lose sight of player
- Extend save/load serialization to persist nextPickupId counter
- Update level-e1m1 with pistol pickup at spawn point
- Add comprehensive test coverage for all new features in verifyWolfenstein.js
- Add shotgun, machine gun, gatling gun, and plasma rifle weapons with
distinct fire modes (semi-auto, auto, burst) and damage profiles
- Refactor ammo from per-weapon pools to shared pools keyed by ammo type
(9mm, shells, plasma), allowing multiple weapons to share the same pool
- Add pickup system with 11 item types: 5 weapons, 4 ammo variants, and
2 health packs, all with spritesheet frames for rendering
- Update level editor with dynamic pickup dropdown populated from rules.json
- Generalize weapon viewmodel rendering to support multiple weapon images
with per-weapon bob/sway animation
- Add cosmetic pickup animations: vertical bobbing and orbiting sparkle
effects drawn in screen space around each pickup billboard
- Bump save version to v3 to invalidate old saves with incompatible ammo
structure
- Update keyboard bindings for weapon switching (keys 1-6)
- Add comprehensive test coverage for new weapons, burst fire mechanics,
ammo pooling, and pickup behavior
- Rename weapon_gattling.png to weapon_gatling.png to fix spelling
Introduces a new "Object" entity type that blocks movement but not sight/bullets, distinct from walls and pickups:
- **Data**: New `objects` array in level JSON (`{x, y, frame}`), with `data/wolfenstein-objects.json` as the frame registry (Tall Bush, Gold Eagle)
- **Artwork**: New `objects.png` spritesheet registered in `wolfenstein-artwork.json`; placeholder texture via `paintObject()` in WolfensteinArt.js
- **Logic**: Objects stored in `state.objects`, with a derived `map.objectBlocked` Set checked only by movement collision (`isWallCell`) — raycaster/sight/bullets never read it, so objects are see-through and shoot-through by construction
- **View**: Rendered as billboard sprites in `_drawSprites` with ground-anchored positioning (bottom edge on floor) and asymptotic depth sorting that stays below the weapon viewmodel
- **Editor**: New "Object" tool category with dynamic dropdown; click open floor to place/remove (toggle), click wall is a no-op; teal square indicator on board
- **Validation**: `validateLevel` checks objects sit on open floor; save/load round-trips with graceful degradation for pre-existing saves
- **Tests**: Verifies object blocks player movement but bullets pass through
**Analysis of the Diff:**
1. **Binary Files:** `walls.png` and `walls.psd` are updated. This suggests an asset update, likely related to the "wolfenstein" theme mentioned in the paths.
2. **JavaScript File:** `tools/verifyWolfenstein.js` is modified.
* A new test case is added under `section('4. Enemy AI');`.
* The test verifies that an enemy (guard) alerts when hit by a projectile, specifically in a scenario where:
* Visual detection (LOS+FOV) is blocked/blind (guard facing away).
* "Heard gunfire" alert path is blocked (different room/door logic).
* The test sets up a specific level layout, forces a door open, fires a pistol, and checks if the enemy's state changes from 'idle' to something else (alerted) and health drops.
* It explicitly mentions fixing an issue with `stepDoors` auto-close countdown underflow by setting `timer`.
**Synthesis:**
The primary functional change is adding a test case to ensure that direct hits alert enemies even when other alert mechanisms (vision, sound through doors) fail. The asset changes are likely incidental or part of the same feature branch (Wolfenstein theme).
**Drafting the Commit Message:**
* **Subject:** Add test for enemy alert on direct hit bypassing vision/sound checks
* **Body:**
* Update Wolfenstein wall assets (PNG/PSD).
* Add verification test in `verifyWolfenstein.js` ensuring enemies alert when shot, even if they cannot see the player or hear gunfire through doors.
* Fix door timer initialization in the test to prevent auto-close interference during projectile flight.
**Refining for Conciseness:**
Subject: Add enemy hit-alert test and update Wolfenstein assets
Body:
- Update `walls.png` and `walls.psd`.
- Add a test case in `verifyWolfenstein.js` verifying that direct hits alert enemies unconditionally, independent of vision cone or room-based sound alerts.
- Ensure door state is correctly initialized in the test to prevent auto-close interference with projectile simulation.
Let's make it standard conventional commit style if possible, or just clear and descriptive.
**Final Polish:**
Subject: Add test for unconditional enemy alert on direct hit
Body:
Update Wolfenstein wall assets (`walls.png`, `walls.psd`).
Add a new test case in `verifyWolfenstein.js` to verify that enemies alert when directly hit by a projectile, even when visual detection (LOS/FOV) and sound-based alerts (through doors) are inactive. This ensures the direct-hit alert path works independently.
Also fixes door timer initialization in the test setup to prevent auto-close logic from interfering with the projectile simulation.
This looks good. I will provide just the message as requested.
This refactors weapon/enemy combat systems to support per-weapon cooldowns,
fire modes (auto/semi), and data-driven damage rolls via ammo types. Guards
now use the pistol's stats for ranged attacks and can be stunned by non-lethal
hits. The level editor now includes a directional facing picker for newly placed
enemies and displays enemy orientation as arrows instead of dots.
Key changes:
- Logic: Replaced single weaponCooldownMs with per-weapon cooldowns map; added
prevFireHeld for semi-auto trigger-edge detection; guards now reference real
weapon definitions via rangedWeapon; projectiles carry ammoType and resolve
damage at hit time using rollDamage(); non-lethal ranged hits apply stunMs to
enemies, freezing their AI until it expires.
- Rules: Added ammoTypes array with damageMin/damageMax; weapons now specify
fireMode and ammoType (projectiles) or damage (melee); enemy definitions
include stunMs and reference weapon IDs instead of hardcoded projectile stats.
- Editor: Added FACING_DIRS constants and drawFacingPicker() overlay that lets
users click N/S/E/W neighbor cells to set a just-placed enemy's facing;
enemies now render as directional arrows showing their spawn orientation;
pendingFacingEnemy state tracks the in-progress pick across tool switches,
undo/redo, and level resets.
- View: Added GUARD_FRAME.stunned (frame 9) which takes visual priority over
all other states when e.stunMs > 0, ensuring the flinch pose displays even if
the enemy's internal state still reads 'attack' or 'chase'.
- Data: Expanded level-e1m1 to 19x21 grid with repositioned doors/enemies/exit;
bumped SAVE_VERSION to 2 since player.cooldowns and prevFireHeld are new
required fields absent from v1 saves.
- Tests: Added coverage for semi-auto trigger-edge behavior, stun application
and duration, melee non-stun behavior, damage roll range bounds, and guard
projectile ammo type/cooldown spacing; updated existing tests to use new
cooldowns/ammoType fields and toggle fireHeld for repeated shots.
Add computeRooms + alertEnemiesInPlayerRoom: a gunshot now alerts every
idle guard sharing the player's room regardless of range/LOS/cone. A
door cell is always treated as a room boundary for this purpose, even
when fully open — two rooms joined only by a doorway stay distinct
("gunfire carries through the room, not through doorways").
Fix _guardFacing side-walk/side-idle flip: was `rel > 0`, read
backwards in-game, now `rel < 0`.
Cover with three verifyWolfenstein cases: same-room alert fires,
behind-closed-door does not, through-open-door does not (door forced
slide=1 / wall zeroed to exercise the slide-independent path).
- Implement 90° field-of-view check for idle/patrolling guards (only alerts when player is within cone, in range, and has clear line of sight)
- Change patrol behavior: 0-1 waypoints ping-pong, 2+ waypoints form a one-way loop (home → nodes → home → ...)
- Reduce patrol speed to 50% of chase speed for natural movement
- Update editor to display loop closing line when 2+ patrol nodes exist
- Add new weapon sprite images (gattling, machinegun, plasma, rocket, shotgun)
- Extend map parser to support patrol route definitions via `opts.patrols`
- Add patrol routes to e1m1 (guard at 2.5,18.5) and e1m2 (guard at 9.5,8.5)
- Add comprehensive tests for vision cone (inside/outside edge cases) and patrol loop/ping-pong behavior