Overview
Peril Dice is a multiplayer elimination game where each player selects numbers before a die is rolled. If the peril player’s number is rolled, they lose a life. Players are eliminated when they reach zero lives.
🔧 Features
✅ Player System
Max players: 10
Each player starts with 3 lives
Players can Join, Leave, or mark themselves Ready
The first player to join gets a Start Game button
The owner can join the game and also has a special Owner menu
🎲 Dice Scaling
Dice type is automatically chosen to ensure at least 3 picks per player
Dice types supported: d6, d12, d20, d30
Player Count Dice Type
1–2 d6
3–4 d12
5–6 d20
7–10 d30
🧍 Test Players
Owner can add/remove test players (bots)
Test players rez stat floaters at offset positions to prevent overlap
Floater objects follow players and update in real time
🪟 HUD & Stat Floaters
Players receive a floating HUD showing:
Player name
Lives
Picks
Peril status or game state
📦 Modular Architecture
Separated scripts:
Main Controller: Handles core game logic
Dialog Handler: Manages pick dialogs
Dice Selector: Returns dice type based on player count
Stat Float Manager: Rezzes and updates floaters
Stat Float Object: Displays floating text per player
🕹️ Game Flow
Players touch the controller object to join the game
Once 2+ players have joined, the first player gets the option to Start Game
Dice type is selected automatically
Each player is prompted (in order) to select 3 numbers
After all picks are made:
The dice is rolled
The result is compared to each player’s picks
If the peril player’s number is rolled or no one picked it, the peril player loses a life
The system checks for eliminations and starts the next round
🧰 Admin Controls
Owner can:
Join or leave the game
Open a special Owner menu
Add/remove test bots
Reset the game
Debug current state (optional)
✅ [Added] Core Gameplay Logic
Turn-based number picking based on each player's remaining lives.
Dice roll system for the "peril" player via dialog prompt.
Automated peril player advancement and elimination for 0-life players.
Round transition system fully implemented.
⏱️ [Added] AFK Timeout System
10-minute inactivity timer with:
Warnings at 2, 5, and 9 minutes.
Auto-elimination after 10 minutes.
🔐 [Improved] Game Rules & Integrity
Blocked new players from joining once the game begins.
Implemented "Ready Check" for all players before start.
Enforced unique global number picks per round.
🛠️ [Added] Admin Tools
Owner-only debug dialog for:
Adding/removing test players.
Starting/resetting the game.
Testing dialogs and player picks.
"Leave Game" options for owner and all participants.
🔧 [Fixed] Syntax & Structural Issues
Resolved:
Mismatched braces and block closures.
Type mismatches (e.g., timeoutTimer).
Improper llParseString2List usage.
Stray placeholders like $1.
Removed redundant code and validated logic flow.
🧱 [Refactored] Function Structure
Renamed updatePlayerPick() to handlePlayerPick() for clarity.
Ensured all functions declare return types and include return 0; as required.
Declared variables at top for readability and compliance.
🔁 [Modularized] Code Architecture
Split pick dialog logic into Pick Dialog Handler script.
Created Roll Dialog Handler and merged into Roll and Confetti Module.
Replaced direct llDialog() calls with link messages for modularity.
🔗 [Integrated] Messaging & Effects
Main controller now uses MSG_SHOW_ROLL_DIALOG via link message.
Confetti effects tied to peril player elimination.
All dialog interactions now routed through modular link messaging.
🧪 [Tested & Validated] Game Flow
Verified:
Player joins/leaves.
Pick dialog with correct life-based limits (3L=1, 2L=2, 1L=3).
Dice roll outcomes and peril transitions.
Game reset and round restart functionality.
Implemented game state serialization and syncing.
⚙️ [Fixed] Loop & Variable Issues
Replaced reused loop variables (i, j) with unique names (loopI, loopJ, etc.).
Fixed broken loop logic and conditional scoping issues.
🧹 [Cleanup] Code Hygiene
Removed duplicate function definitions.
Ensured consistent naming and formatting across all modules.
Resolved scoping errors (e.g., ownerKey issue).
✅ [Current Status]
Scripts compile without errors.
All modules function as intended.
System ready for in-world testing.
Issue Identified:
The main issue was that the floater was showing 0 as the player's pick even after they made a selection, and the correct pick was not being reflected in the float.
Steps Taken:
Improved Data Synchronization: We ensured that the picksData list, which holds player choices, was properly updated and synchronized across all parts of the system.
State Serialization: The game state, including updated picksData, was serialized correctly using the serializeGameState() function. This ensured that the floater was aware of the new state whenever a player's pick changed.
Immediate Float Updates: After updating a player's pick, we immediately sent the new game state (gameSync) to all linked objects to update their floats, ensuring the pick was reflected in the UI.
Key Modifications:
Main Peril Dice Controller: We improved the way we updated picksData and immediately synchronized this update with the floater using MSG_SYNC_GAME_STATE.
StatFloat: Adjustments were made to handle receiving and displaying updated pick data, ensuring that picks were displayed correctly on the float after each update.
Dialog Handling: Proper dialogs were shown to players for pick choices, and feedback on their picks was sent back to update the floats in real-time.
Outcome:
The game now correctly updates and displays the player’s picks on their respective floats immediately after making a choice.
The picks are reflected in the logs as well, with the correct updated pick being shown rather than 0.
Final Result:
The issue of picks not being displayed correctly has been resolved, and the flow of data between the scripts (game state synchronization, float updates, etc.) is working as intended.
🎯 Refactored the Game Architecture
We modularized the original Peril Dice controller into separate cohesive components:
Main Peril Dice Controller
Handles core logic: player join/leave, peril selection, game sync, and communication routing.
Broadcasts updates via MSG_SYNC_GAME_STATE after major state changes.
Applies llSleep(0.2) to improve message delivery reliability.
Dialog Handler Module
Manages the number-picking dialog.
Tracks player picks and updates picksData accordingly.
Sends state sync after every valid pick.
Fixed pick serialization bugs and ensured updates trigger correctly.
Float Rezzer Module
Registers player data and rezzes a StatFloat object beside each participant.
Applies llSetObjectDesc(name); before rezzing for easier identification.
On update, broadcasts llRegionSay messages including current lives, peril, and picks.
StatFloat (HUD Script)
Listens on assigned channel to receive floating text updates.
Parses synced game state from link_message to extract lives, picks, and peril data.
Dynamically follows the avatar.
Enhanced parsing reliability and fixed index mapping for correct player display.
Roll and Confetti Module
Performs dice rolls and checks for matches.
Transfers peril role on match or removes a life otherwise.
Triggers confetti on a miss and updates floats for all players.
🛠 Debugging and Enhancements
Added llOwnerSay debug statements across all modules.
Resolved multiple name not defined within scope (nndws) issues.
Verified and cleaned up serialized game data formats across modules.
Ensured consistent use of player indexing and life count mapping.
Sequential Player Picking Logic
Players now pick in order starting with the peril player.
Number of picks is determined by the peril player’s current lives.
Picks are tracked globally to prevent duplicates.
Dynamic Dice Type Adjustment
Dice size (diceType) now adjusts based on player count:
1–2 players = 6
3–4 players = 12
5–6 players = 18, etc.
Prompt for Dice Roll
After all players have made their picks, the peril player is prompted to roll via a dialog.
Dice Roll Resolution Logic
If another player matches the roll, they become the new peril player.
If no one matches or the peril player matches, the peril player loses a life.
🔄 Fixes & Improvements
Fixed syntax and scoping errors (resultStr, newPeril, and timer logic).
Prevented duplicate rezzing of StatFloat objects.
Restored and ensured 🔢 Picks: are shown on the floating stat displays.
Updated floaters dynamically after each pick using llSetTimerEvent.