- Deleted unused character images: woman_in_science_lab_coat.png and woman_with_black_long_hair_bow_in_hair_long_sleeve_(1).png.
- Added new padlock icon asset for UI.
- Introduced player_preferences.css for styling the player preferences configuration screen.
- Updated game.js to load new character atlases with simplified filenames.
- Enhanced player.js to create custom idle animations for characters.
- Implemented sprite-grid.js for sprite selection UI, including a preview feature.
- Updated database schema to include break_escape_player_preferences table for storing player settings.
- Modified convert_pixellab_to_spritesheet.py to map character names to simplified filenames and extract headshots from character images.
- Updated the game to support new character sprite atlases for both male and female characters, allowing for a wider variety of NPC designs.
- Improved player sprite initialization to dynamically select between atlas-based and legacy sprites, enhancing flexibility in character representation.
- Refined collision box settings based on sprite type, ensuring accurate physics interactions for both atlas (80x80) and legacy (64x64) sprites.
- Enhanced NPC behavior to utilize atlas animations, allowing for more fluid and diverse animations based on available frames.
Files modified:
- game.js: Added new character atlases and updated sprite loading logic.
- player.js: Improved player sprite handling and collision box adjustments.
- npc-behavior.js: Updated animation handling for NPCs to support atlas-based animations.
- npc-sprites.js: Enhanced NPC sprite creation to accommodate atlas detection and initial frame selection.
- scenario.json.erb: Updated player and NPC configurations to utilize new sprite sheets and animation settings.
- m01_npc_sarah.ink: Revised dialogue options to include new interactions related to NPCs.
- Updated the games_controller to remove starting items from the inventory response, ensuring no duplicates are sent to the client.
- Enhanced the inventory processing logic in JavaScript to check for existing items by ID, type, or name before adding new items, preventing duplicate entries in the player's inventory.
Files modified:
- games_controller.rb: Adjusted inventory response handling.
- inventory.js: Added duplicate item check during inventory processing.
- Implemented keyboard event handling to allow players to use the spacebar to continue and number keys (1-9) to select choices in the minigame.
- Updated UI to display choice buttons with number prefixes for easier selection.
Files modified:
- person-chat-minigame.js: Added keyboard event listener for choice selection.
- person-chat-ui.js: Updated choice button creation to include number prefixes.
- Changed CSS file paths in index.html and show.html.erb to reflect new directory structure under public/break_escape.
- Added a new tutorial.css file with styles tailored for the tutorial system, ensuring a cohesive pixel-art aesthetic.
- Enhanced the tutorial manager to track player interactions, including clicks to move and inventory item usage, improving the tutorial experience for new players.
- Updated tutorial steps to dynamically include objectives based on the current scenario.
Files modified:
- index.html: Updated CSS links.
- show.html.erb: Updated CSS links.
- tutorial.css: New styles for the tutorial system.
- player.js: Added notifications for player actions.
- tutorial-manager.js: Enhanced logic for tracking tutorial progress and objectives.
- interactions.js: Added notifications for inventory interactions.
Implements a comprehensive tutorial system that:
- Prompts first-time players with option to take tutorial
- Detects device type (mobile vs keyboard) for appropriate instructions
- Shows interactive steps with objectives for basic controls:
* Keyboard: WASD movement, Shift to run, E to interact
* Mobile: Click/tap to move and interact
- Tracks player actions to progress through tutorial steps
- Saves completion status in localStorage
- Includes polished UI with animations and responsive design
Files added:
- tutorial-manager.js: Core tutorial logic and state management
- tutorial.css: Styled UI components with animations
Files modified:
- game.js: Integrated tutorial check on first load
- player.js: Added tutorial notifications for movement/running
- interactions.js: Added tutorial notification for interactions
- main.js: Imported tutorial manager system
- index.html: Added tutorial CSS stylesheet
Fixes two critical issues when multiple doors lead to the same room:
1. Room reloading: Added checks in loadRoom() and createRoom() to prevent
reloading/recreating rooms that are already loaded. This prevents the
room from being unnecessarily recreated when opening a second door to
the same room.
2. Door location detection: Updated removeMatchingDoorSprite() to use
position and direction when finding the matching door. Previously it
only checked connectedRoom, which caused it to remove the wrong door
when multiple doors connected the same two rooms at different locations.
Now it checks:
- Opposite direction matches
- Position matches within tolerance (X for N/S doors, Y for E/W doors)
This ensures that opening different doors to the same room works correctly
without causing room reloads or removing the wrong door sprites.
- Removed unnecessary trailing whitespace from `remove_unique_game_constraint.rb`, `flag-station-minigame.css`, `vm-launcher-minigame.css`, and `hacktivity-cable.js` to enhance code quality and maintain consistency across the codebase.
- Introduced buttons in the Crypto and Lab Workstation title bars to allow users to open the respective workstations in new tabs.
- Implemented JavaScript functions `openCryptoWorkstationInNewTab` and `openLabWorkstationInNewTab` to handle the new tab functionality.
- Updated CSS styles for the new buttons to ensure proper positioning and visual appeal.
- Made necessary imports and exports in helper files to integrate the new functionality across the application.
- Cleaned up trailing whitespace in migration file `remove_unique_game_constraint.rb` to maintain code quality.
- Removed unnecessary whitespace from CSS files for `flag-station-minigame.css` and `vm-launcher-minigame.css`, ensuring cleaner stylesheets.
- Tidied up JavaScript file `hacktivity-cable.js` by eliminating trailing whitespace, improving readability and consistency across the codebase.
- Updated `validate_scenario.rb` to enforce correct usage of `targetKnot` in timed conversations, ensuring compliance with new requirements.
- Added checks for missing properties in timed conversations, including `delay` and `targetKnot`, to improve scenario integrity.
- Enhanced logging for validation issues, providing clearer feedback on scenario configuration errors.
- Updated relevant scenarios to align with the new validation rules, ensuring consistency across gameplay elements.
- Added functionality to include current player inventory in game state for page reload recovery, allowing players to restore their inventory seamlessly.
- Implemented filtering of container contents to exclude items already in the player's inventory, enhancing user experience and gameplay clarity.
- Updated game mechanics to support both type-based and ID-based matching for inventory items, improving task validation and objectives tracking.
- Enhanced logging for better visibility into inventory processing and container content loading, aiding in debugging and game state management.
- Updated scenarios to reflect changes in item identification and task requirements, ensuring consistency across gameplay elements.
- Added support for submit_flags tasks in GamesController, allowing players to submit flags for validation and task completion.
- Updated game state management to track submitted flags and validate against required flags for task completion.
- Enhanced ObjectivesManager to handle flag submissions, including syncing progress with the server and managing task states.
- Introduced a new locksmith NPC for lockpicking tutorials, expanding gameplay elements and player engagement.
- Updated scenario schema to include submit_flags task type and associated properties, ensuring proper integration into the game mechanics.
- Improved logging and debugging information for flag submissions and task progress updates, enhancing visibility into game state changes.
- Added functionality to complete tasks via the objectives manager in FlagStationMinigame, improving gameplay interaction.
- Updated scenario.json.erb to replace flags_submitted with specific SSH and privilege flag submissions, enhancing clarity in task objectives.
- Introduced new task types in the scenario schema to support task completion mechanics, ensuring better integration of gameplay elements.
- Introduced a lab workstation popup in the game interface for accessing lab sheets via an iframe.
- Implemented JavaScript functions to create, open, and close the lab workstation, enhancing user interaction.
- Updated CSS styles for the lab workstation popup to ensure a seamless visual experience.
- Enhanced interaction handling to allow players to open lab workstations from inventory items.
- Added new scenario files for the Linux Fundamentals and Security Lab, including detailed instructions and objectives for players.
- Updated scenario schema to include the new lab workstation type, ensuring proper integration into the game mechanics.
- Updated scenario-schema.json to include "tutorial" as a valid difficulty level.
- Changed position coordinates from integer to number for better precision.
- Added new item types ("id_badge", "rfid_cloner") in scenario schema with descriptions.
- Improved validate_scenario.rb to check for common issues, including room connection directions and NPC configurations.
- Added suggestions for gameplay improvements based on scenario features.
- Updated SCENARIO_JSON_FORMAT_GUIDE.md to clarify valid directions and bidirectional connections.
- Introduced guidelines for lock type variety and progression in room layout design.
- Established dialogue pacing rules in Ink scripting to enhance player engagement.
- Included validation steps in scenario assembly documentation to ensure structural integrity.
- Decreased the display time for various failure and success messages from 3000ms to 1000ms or 1500ms, enhancing responsiveness during gameplay.
- Adjusted the cancellation message display time from 2000ms to 800ms for quicker feedback.
- Added functionality to disable WASD key capture during text input, enhancing user experience.
- Implemented a fallback mechanism to dynamically import the pauseKeyboardInput method if not available on the window object, ensuring compatibility across different environments.
- Updated `GamesController` to parse and store VM IPs from JSON input, improving player state management.
- Modified `Game` model to include VM IPs in the context for better integration with gameplay.
- Enhanced `Mission` model's `vm_object` method to override IPs from the context when available.
- Revamped `new.html.erb` to provide a clearer interface for entering VM IP addresses and flag hints.
- Improved `vm-launcher-minigame.js` to display VM IPs and provide connection instructions in standalone mode.
- Updated `GamesController` and `Game` model to include RFID lock types in the filtering logic for 'requires' attributes, ensuring proper handling of biometric, bluetooth, and RFID types.
- Improved `RFIDMinigame` to standardize card ID retrieval, supporting both `card_id` and `key_id`.
- Enhanced `unlock-system.js` to prioritize physical keycard checks and streamline the unlocking process with detailed logging.
- Adjusted scenario JSON files to replace `keyId` with `card_id` for consistency and added new lock requirements for various rooms.
- Updated `GamesController` to support XML flag hints for standalone mode, improving backward compatibility with legacy flag input.
- Introduced `parse_flag_hints_xml` method in `Mission` model to extract flags from XML content.
- Enhanced `Game` model to incorporate `flags_by_vm` from player state for better flag management.
- Modified `new.html.erb` to update UI for flag hints input, replacing the previous comma-separated flags format.
- Improved `FlagStationMinigame` to display accepted VM flags and handle flag submissions more effectively.
- Adjusted scenario JSON to include flag stations with VM-specific flag handling.
- Added `vm_object` method in `mission.rb` to fetch VM details from context or return a fallback.
- Introduced new images for VM launchers and flag stations in the assets directory.
- Updated `game.js` to preload new VM launcher and flag station images.
- Refactored `vm-launcher-minigame.js` to streamline VM handling and improve UI messaging.
- Adjusted scenario JSON to utilize the new `vm_object` method for VM data retrieval.
- Updated `GamesController` to use `current_player` for VM set retrieval.
- Improved `MissionsController` to handle redirection for both Hacktivity and standalone modes.
- Modified `new.html.erb` to include UI for standalone flag input alongside VM set selection.
- Added new CSS styles for standalone mode instructions and flags input form.
- Introduced new mission configuration for the SecGen VM Lab, integrating VM and flag capture elements.
- Added ObjectivesManager to track mission objectives and tasks.
- Created ObjectivesPanel for displaying objectives in a collapsible HUD.
- Integrated objectives state restoration from the server during game initialization.
- Implemented task completion and unlocking mechanisms via game actions.
- Added CSS styles for the objectives panel with a pixel-art aesthetic.
- Developed a test scenario to validate the objectives system functionality.
- Updated database schema to include fields for tracking completed objectives and tasks.
refactor: Update key-lock system and minigame starters to utilize KeyCutCalculator for cut depth generation
chore: Normalize keyPins in scenario data to align with new cut depth calculations
- Implemented a global character registry to manage player and NPC data.
- Added methods for setting the player, registering NPCs, and retrieving character information.
- Integrated character registry updates into the NPC manager for seamless NPC registration.
- Created test scenarios for line prefix speaker format, including narrator modes and background changes.
- Developed comprehensive NPC sprite test scenario with various NPC interactions and items.
PROBLEM:
NPC unlocks had timing-dependent behavior:
- If NPC unlocked door BEFORE room loaded: client saw it as unlocked
- If NPC unlocked door AFTER room loaded: door sprite stayed locked
SOLUTION:
1. Server-side persistent tracking:
- Added npcUnlockedTargets array to player_state
- Track all NPC unlocks separately from unlockedRooms/unlockedObjects
- Initialize npcUnlockedTargets in new games
2. Server merges NPC unlock state:
- filtered_room_data checks npcUnlockedTargets
- Marks doors/containers as unlocked if NPC unlocked them
- Works regardless of when room is loaded
3. Client updates existing sprites:
- NPC unlock handler finds ALL door sprites for target room
- Updates sprite state immediately after server unlock
- Handles both pre-loaded and late-loaded rooms
Changes:
- app/models/break_escape/game.rb: Add npc_unlock_target!, npc_unlocked?, merge state in filtered_room_data
- app/controllers/break_escape/games_controller.rb: Track NPC unlocks in unlock endpoint
- public/break_escape/js/minigames/person-chat/person-chat-conversation.js: Update all door sprites after NPC unlock
- public/break_escape/js/systems/doors.js: Export unlockDoor globally
- test/integration/unlock_system_test.rb: Add 4 tests for persistent NPC unlock state
Created test suite with 34 tests covering all unlock scenarios and security:
DOOR TESTS (10 tests):
- PIN/password validation (correct/incorrect, case sensitivity)
- Key unlocks (client-validated)
- Unlocked doors (method='unlocked')
CONTAINER TESTS (8 tests):
- PIN/password validation
- Key, lockpick, biometric, bluetooth, RFID unlocks
- Unlocked containers
NPC UNLOCK TESTS (6 tests):
✅ NPC can unlock door/container if encountered and has permission
🔒 SECURITY: Fails if NPC not encountered
🔒 SECURITY: Fails if NPC lacks permission for that target
🔒 SECURITY: Fails for non-existent NPC
🔒 SECURITY: Fails if unlockable is not an array
SECURITY TESTS - BYPASS PREVENTION (4 tests):
🔒 CRITICAL: Locked door CANNOT be bypassed with method='unlocked'
🔒 CRITICAL: Locked container CANNOT be bypassed with method='unlocked'
✅ Unlocked door CAN use method='unlocked'
✅ Unlocked container CAN use method='unlocked'
ERROR CASES (3 tests):
- Non-existent doors/objects return 422
- Invalid methods return 422
DATA FILTERING (2 tests):
- Verify 'requires' field filtered from responses
- Verify recursive filtering of contents
INTEGRATION (1 test):
- Multiple sequential unlocks
- Idempotent operations
Test Results: 34 runs, 115 assertions, 0 failures
Server Implementation:
- validate_npc_unlock: Validates NPC encounter and permission list
- find_npc_in_scenario: Searches all rooms for NPC
- method='npc': New unlock method requiring NPC id as attempt
Client Implementation:
- Updated handleUnlockDoor to call server API with method='npc'
- Server validates all NPC unlock requests
- No client-side lock manipulation
Security Principle: All unlock authorization is server-side.
Client cannot bypass locks by manipulating state or claiming NPC unlocks.
Fixed issue where unlocked doors and containers wouldn't open because
getLockRequirements functions returned null for unlocked items, causing
early return.
Changes:
- Handle case where lockRequirements is null (unlocked item) by calling
server verification
- Updated getLockRequirementsForDoor to return data even for unlocked doors
- Updated getLockRequirementsForItem to include 'locked' field
- Now both locked and unlocked items go through proper server validation
Flow for unlocked items:
1. getLockRequirements returns null (no lock data) OR returns {locked: false}
2. Call notifyServerUnlock with method='unlocked'
3. Server validates item is actually unlocked in scenario_data
4. Server returns roomData (doors) or contents (containers)
5. Client proceeds to open/display content
Critical security fix: Removed client-side lock state checking that allowed
bypass of server validation. Clients can no longer manipulate lock states to
gain unauthorized access.
Previous vulnerability:
- Client checked props.locked (client-side data)
- If false, directly called notifyServerUnlock with method='unlocked'
- Server trusted this without validating its own scenario data
- Attacker could: set doorSprite.doorProperties.locked = false, then access
New secure flow:
- Client ALWAYS calls handleUnlock regardless of perceived lock state
- handleUnlock calls server with method='unlocked' for unlocked items
- Server ALWAYS validates against its own scenario_data
- Server only grants access if item is actually unlocked in server state
- Client state is never trusted for authorization decisions
Changes:
- doors.js: Removed client-side lock check, always call handleUnlock
- unlock-system.js: Handle unlocked items by verifying with server
- interactions.js: Removed client-side container lock check
- interactions.js: Removed notifyServerForUnlockedContainer helper
Security principle: Never trust the client. All authorization must be
server-side based on server state, not client-reported state.
Critical security fix: PIN and password minigames were falling back to
client-side validation when the correct answer was available. This allowed
players to bypass security by inspecting client-side code.
Changes:
- PIN minigame: ALWAYS use server-side validation, never client-side
- Password minigame: ALWAYS use server-side validation, never client-side
- If API client is unavailable, fail securely by rejecting the attempt
- Removed backwards compatibility code that allowed client-side validation
Security principle: Never trust the client for authentication/authorization.
All PIN and password validation must go through the server.
Fixed ReferenceError where notifyServerUnlock was not defined in doors.js.
The function was internal to unlock-system.js but is now needed by doors.js
for notifying the server when unlocked doors are opened.
Changes:
- Export notifyServerUnlock from unlock-system.js
- Import notifyServerUnlock in doors.js
Fixed issue where unlocked doors/containers couldn't be opened because
the server wasn't being notified to add them to unlockedRooms/unlockedObjects.
Server changes (game.rb):
- Updated validate_unlock to accept method='unlocked' for unlocked targets
- Added logic to grant access for unlocked doors/objects without validation
Client changes (doors.js):
- Updated handleDoorInteraction to notify server for unlocked doors
- Calls notifyServerUnlock with method='unlocked' before opening
Client changes (interactions.js):
- Added notifyServerForUnlockedContainer helper function
- Updated container interaction to notify server before launching minigame
This ensures that all room/container access is properly authorized on the
server side, preventing 403 Forbidden errors when loading room/container data.