## [2.8.2] - 2025-08-21
This commit is contained in:
parent
d1cc376f2a
commit
fa8a0c9ca4
10 changed files with 548 additions and 24 deletions
42
CHANGELOG.md
42
CHANGELOG.md
|
|
@ -4,6 +4,48 @@
|
|||
|
||||
All notable changes to Peril Dice will be documented in this file.
|
||||
|
||||
## [2.8.2] - 2025-08-21
|
||||
|
||||
### 🔥 **Critical Scoreboard Spam Fix**
|
||||
- **Eliminated Player Sync Loop**: Fixed major bug where eliminated players caused continuous scoreboard update spam
|
||||
- Main Controller now properly updates peril player variable immediately after player elimination
|
||||
- Prevents stale sync messages containing eliminated player data from being broadcast repeatedly
|
||||
- Eliminates infinite scoreboard update loops that occurred when peril player was eliminated
|
||||
- Fixed root cause where Main Controller kept sending outdated peril player references in sync messages
|
||||
- **Peril Player Validation**: Enhanced peril player assignment during elimination sequences
|
||||
- Checks if eliminated player is currently the peril player before final sync
|
||||
- Assigns new valid living player as peril player or sets to "NONE" if no players remain
|
||||
- Ensures updateHelpers() always sends clean game state without stale player references
|
||||
- Prevents perpetual "Noose the Bunny" style spam messages after player elimination
|
||||
|
||||
### 🎯 **Peril Status Display Fixes (Re-Fixed)**
|
||||
- **Enhanced Floater Peril Status**: Re-implemented and improved peril status display on floating displays
|
||||
- Fixed peril status showing "waiting for game to start" during active gameplay (again)
|
||||
- Enhanced peril player detection logic in floater management
|
||||
- Improved sync message processing to ensure consistent peril status across all displays
|
||||
- Better handling of peril player transitions during plot twist scenarios
|
||||
|
||||
### 💖 **Elimination Heart Display Fixes (Re-Fixed)**
|
||||
- **0 Hearts Before Elimination**: Re-fixed elimination sequence to properly show 0 hearts before player removal
|
||||
- Enhanced Main Controller elimination logic to ensure 0 hearts display timing
|
||||
- Extended display delay to make 0 hearts clearly visible on both scoreboard and floaters
|
||||
- Improved coordination between heart updates and player cleanup processes
|
||||
- Fixed race conditions where players were removed before 0 hearts could be displayed
|
||||
- **Visual Elimination Feedback**: Strengthened elimination experience for better player feedback
|
||||
- Players now consistently see their elimination status with 0 hearts before removal
|
||||
- Scoreboard and floaters maintain synchronized elimination heart display
|
||||
- Enhanced user experience during elimination events with proper visual timing
|
||||
|
||||
### 🛠️ **Technical Improvements**
|
||||
- **Elimination Sequence Enhancement**: Improved coordination between player removal and sync message broadcasting
|
||||
- Added peril player validation step before final updateHelpers() call
|
||||
- Enhanced elimination handler to prevent sync message corruption during player cleanup
|
||||
- Better synchronization between Main Controller state updates and helper script notifications
|
||||
- **Display System Reliability**: Strengthened display update mechanisms for consistent visual feedback
|
||||
- Enhanced floater update triggers during game state changes
|
||||
- Improved peril status determination and heart display coordination
|
||||
- Better error handling for edge cases during elimination sequences
|
||||
|
||||
## [2.8.1] - 2025-08-14
|
||||
|
||||
### 🎯 **Peril Status Display Fixes**
|
||||
|
|
|
|||
|
|
@ -3,6 +3,49 @@ PERIL DICE CHANGELOG
|
|||
|
||||
All notable changes to Peril Dice are documented in this file.
|
||||
|
||||
[2.8.2] - 2025-08-21
|
||||
====================
|
||||
|
||||
🔥 CRITICAL SCOREBOARD SPAM FIX
|
||||
- Eliminated Player Sync Loop: Fixed major bug where eliminated players caused continuous scoreboard update spam
|
||||
* Main Controller now properly updates peril player variable immediately after player elimination
|
||||
* Prevents stale sync messages containing eliminated player data from being broadcast repeatedly
|
||||
* Eliminates infinite scoreboard update loops that occurred when peril player was eliminated
|
||||
* Fixed root cause where Main Controller kept sending outdated peril player references in sync messages
|
||||
- Peril Player Validation: Enhanced peril player assignment during elimination sequences
|
||||
* Checks if eliminated player is currently the peril player before final sync
|
||||
* Assigns new valid living player as peril player or sets to "NONE" if no players remain
|
||||
* Ensures updateHelpers() always sends clean game state without stale player references
|
||||
* Prevents perpetual "Noose the Bunny" style spam messages after player elimination
|
||||
|
||||
🎯 PERIL STATUS DISPLAY FIXES (RE-FIXED)
|
||||
- Enhanced Floater Peril Status: Re-implemented and improved peril status display on floating displays
|
||||
* Fixed peril status showing "waiting for game to start" during active gameplay (again)
|
||||
* Enhanced peril player detection logic in floater management
|
||||
* Improved sync message processing to ensure consistent peril status across all displays
|
||||
* Better handling of peril player transitions during plot twist scenarios
|
||||
|
||||
💖 ELIMINATION HEART DISPLAY FIXES (RE-FIXED)
|
||||
- 0 Hearts Before Elimination: Re-fixed elimination sequence to properly show 0 hearts before player removal
|
||||
* Enhanced Main Controller elimination logic to ensure 0 hearts display timing
|
||||
* Extended display delay to make 0 hearts clearly visible on both scoreboard and floaters
|
||||
* Improved coordination between heart updates and player cleanup processes
|
||||
* Fixed race conditions where players were removed before 0 hearts could be displayed
|
||||
- Visual Elimination Feedback: Strengthened elimination experience for better player feedback
|
||||
* Players now consistently see their elimination status with 0 hearts before removal
|
||||
* Scoreboard and floaters maintain synchronized elimination heart display
|
||||
* Enhanced user experience during elimination events with proper visual timing
|
||||
|
||||
🛠️ TECHNICAL IMPROVEMENTS
|
||||
- Elimination Sequence Enhancement: Improved coordination between player removal and sync message broadcasting
|
||||
* Added peril player validation step before final updateHelpers() call
|
||||
* Enhanced elimination handler to prevent sync message corruption during player cleanup
|
||||
* Better synchronization between Main Controller state updates and helper script notifications
|
||||
- Display System Reliability: Strengthened display update mechanisms for consistent visual feedback
|
||||
* Enhanced floater update triggers during game state changes
|
||||
* Improved peril status determination and heart display coordination
|
||||
* Better error handling for edge cases during elimination sequences
|
||||
|
||||
[2.8.1] - 2025-08-14
|
||||
====================
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,16 @@ default {
|
|||
|
||||
string perilName;
|
||||
// Show proper peril status based on current game state
|
||||
if (perilPlayer == "" || perilPlayer == "NONE" || llSubStringIndex(perilPlayer, ",") != -1) {
|
||||
// Check if we have any players with lives > 0 to determine if game is active
|
||||
integer gameActive = FALSE;
|
||||
integer i;
|
||||
for (i = 0; i < llGetListLength(lives); i++) {
|
||||
if (llList2Integer(lives, i) > 0) {
|
||||
gameActive = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gameActive || perilPlayer == "" || perilPlayer == "NONE" || llSubStringIndex(perilPlayer, ",") != -1) {
|
||||
perilName = "🧑 Status: Waiting for game to start...";
|
||||
} else if (name == perilPlayer) {
|
||||
// This player is currently in peril
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ key currentPicker;
|
|||
integer roundStarted = FALSE;
|
||||
integer diceTypeProcessed = FALSE; // Track if we've already processed dice type for this round
|
||||
integer ignorePicksSync = FALSE; // Temporarily ignore picks data sync during round initialization
|
||||
integer roundContinueInProgress = FALSE; // Prevent multiple rapid calls to continueCurrentRound
|
||||
|
||||
// Duplicate request prevention
|
||||
string lastHumanPickMessage = "";
|
||||
|
|
@ -288,7 +289,46 @@ default {
|
|||
// Receive game state updates from main controller
|
||||
if (num == MSG_SYNC_GAME_STATE) {
|
||||
list parts = llParseString2List(str, ["~"], []);
|
||||
if (llGetListLength(parts) >= 4) {
|
||||
|
||||
// EARLY VALIDATION: Extract peril player from any sync message and validate it
|
||||
// This prevents loops from incomplete sync messages with invalid peril players
|
||||
if (llGetListLength(parts) >= 3) {
|
||||
string receivedPerilPlayer = llList2String(parts, 2);
|
||||
list newNames = [];
|
||||
if (llGetListLength(parts) >= 4) {
|
||||
newNames = llCSV2List(llList2String(parts, 3));
|
||||
}
|
||||
|
||||
// PROTECTION: Don't accept peril player updates for players that don't exist OR have 0 lives
|
||||
if (receivedPerilPlayer != "NONE" && receivedPerilPlayer != "" && receivedPerilPlayer != perilPlayer) {
|
||||
// If we have the names list, validate against it
|
||||
if (llGetListLength(newNames) > 0) {
|
||||
integer receivedPlayerExists = llListFindList(newNames, [receivedPerilPlayer]) != -1;
|
||||
if (!receivedPlayerExists) {
|
||||
llOwnerSay("⚠️ [Game Manager] EARLY REJECTION: Invalid peril player update " + receivedPerilPlayer + " (player no longer exists) - IGNORING entire message");
|
||||
return; // Reject the entire sync message
|
||||
}
|
||||
|
||||
// ADDITIONAL CHECK: If we have lives data, reject players with 0 lives
|
||||
if (llGetListLength(parts) >= 1) {
|
||||
list newLivesCheck = llCSV2List(llList2String(parts, 0));
|
||||
integer receivedPlayerIdx = llListFindList(newNames, [receivedPerilPlayer]);
|
||||
if (receivedPlayerIdx != -1 && receivedPlayerIdx < llGetListLength(newLivesCheck)) {
|
||||
integer receivedPlayerLives = llList2Integer(newLivesCheck, receivedPlayerIdx);
|
||||
if (receivedPlayerLives <= 0) {
|
||||
llOwnerSay("⚠️ [Game Manager] EARLY REJECTION: Invalid peril player update " + receivedPerilPlayer + " (player has 0 lives) - IGNORING entire message");
|
||||
return; // Reject the entire sync message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (llGetListLength(parts) < 4) {
|
||||
llOwnerSay("⚠️ [Game Manager] Incomplete sync message received, parts: " + (string)llGetListLength(parts) + " - IGNORING");
|
||||
return;
|
||||
} else {
|
||||
list newLives = llCSV2List(llList2String(parts, 0));
|
||||
|
||||
string picksDataStr = llList2String(parts, 1);
|
||||
|
|
@ -303,10 +343,20 @@ default {
|
|||
list newNames = llCSV2List(llList2String(parts, 3));
|
||||
string receivedPerilPlayer = llList2String(parts, 2);
|
||||
|
||||
// SAVE original peril player BEFORE any updates for Plot Twist detection
|
||||
string originalPerilPlayer = perilPlayer;
|
||||
|
||||
// Update peril player if Roll module sent a change
|
||||
// PROTECTION: Don't accept peril player updates for players that don't exist in the current game
|
||||
if (receivedPerilPlayer != "NONE" && receivedPerilPlayer != "" && receivedPerilPlayer != perilPlayer) {
|
||||
llOwnerSay("🎯 [Game Manager] Peril player updated from Roll module: " + perilPlayer + " -> " + receivedPerilPlayer);
|
||||
perilPlayer = receivedPerilPlayer;
|
||||
integer receivedPlayerExists = llListFindList(newNames, [receivedPerilPlayer]) != -1;
|
||||
if (receivedPlayerExists) {
|
||||
llOwnerSay("🎯 [Game Manager] Peril player updated from Roll module: " + perilPlayer + " -> " + receivedPerilPlayer);
|
||||
perilPlayer = receivedPerilPlayer;
|
||||
} else {
|
||||
llOwnerSay("⚠️ [Game Manager] REJECTING peril player update from Roll module: " + receivedPerilPlayer + " (player no longer exists)");
|
||||
// Keep current peril player instead of accepting the invalid update
|
||||
}
|
||||
}
|
||||
|
||||
// Handle elimination case - if current peril player was eliminated, find a new one
|
||||
|
|
@ -362,27 +412,57 @@ default {
|
|||
}
|
||||
}
|
||||
|
||||
llOwnerSay("🔍 [Game Manager] DEBUG - allPicksEmpty: " + (string)allPicksEmpty + ", perilPlayer: " + perilPlayer + ", roundStarted: " + (string)roundStarted);
|
||||
|
||||
// Check for win condition ONLY during active rounds, not during player registration
|
||||
// Check for win condition FIRST to prevent infinite loops
|
||||
if (roundStarted && llGetListLength(newNames) <= 1) {
|
||||
if (llGetListLength(newNames) == 1) {
|
||||
string winner = llList2String(newNames, 0);
|
||||
llOwnerSay("🏆 [Game Manager] Victory detected: " + winner + " wins!");
|
||||
// Reset round state to prevent loops
|
||||
roundStarted = FALSE;
|
||||
perilPlayer = "";
|
||||
// Let Main Controller handle the victory celebration and reset
|
||||
return;
|
||||
} else {
|
||||
llOwnerSay("💀 [Game Manager] No survivors remain!");
|
||||
// Reset round state to prevent loops
|
||||
roundStarted = FALSE;
|
||||
perilPlayer = "";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// STOP processing if game is over or peril player is invalid
|
||||
if (!roundStarted || perilPlayer == "" || perilPlayer == "NONE" || llGetListLength(newNames) <= 1) {
|
||||
// Game is ending or already ended, don't continue rounds
|
||||
return;
|
||||
}
|
||||
|
||||
// Only show debug and continue if game is actually active
|
||||
llOwnerSay("🔍 [Game Manager] DEBUG - allPicksEmpty: " + (string)allPicksEmpty + ", perilPlayer: " + perilPlayer + ", roundStarted: " + (string)roundStarted);
|
||||
|
||||
// If picks are empty, round started, and we have a valid peril player, continue to next round
|
||||
// This works for ALL outcomes: Direct Hit, No Shield, AND Plot Twist
|
||||
if (allPicksEmpty && roundStarted && perilPlayer != "" && perilPlayer != "NONE") {
|
||||
// PROTECTION: Prevent rapid consecutive calls to continueCurrentRound
|
||||
// ADDITIONAL PROTECTION: Verify peril player still exists in the game
|
||||
// CRITICAL FIX: Prevent double processing during Plot Twist scenarios
|
||||
integer perilPlayerExists = (perilPlayer != "" && perilPlayer != "NONE" && llListFindList(newNames, [perilPlayer]) != -1);
|
||||
if (allPicksEmpty && roundStarted && perilPlayerExists && llGetListLength(newNames) > 1 && !roundContinueInProgress) {
|
||||
// ADDITIONAL CHECK: Don't start new rounds if we just received a peril player update
|
||||
// This prevents double round starts during Plot Twist scenarios
|
||||
if (receivedPerilPlayer != "NONE" && receivedPerilPlayer != "" && receivedPerilPlayer != originalPerilPlayer) {
|
||||
llOwnerSay("🎯 [Game Manager] Plot Twist detected - peril player changed from " + originalPerilPlayer + " to " + perilPlayer + ", deferring round continuation");
|
||||
// Don't start new round immediately after Plot Twist - wait for next sync
|
||||
return;
|
||||
}
|
||||
|
||||
llOwnerSay("🎯 [Game Manager] Round complete - starting next round with peril player: " + perilPlayer);
|
||||
roundContinueInProgress = TRUE; // Set flag to prevent rapid calls
|
||||
llSleep(2.0); // Brief pause for dramatic effect
|
||||
continueCurrentRound(); // Use continueCurrentRound instead of startNextRound
|
||||
roundContinueInProgress = FALSE; // Clear flag after completion
|
||||
} else if (allPicksEmpty && roundStarted && !perilPlayerExists && llGetListLength(newNames) > 1) {
|
||||
llOwnerSay("⚠️ [Game Manager] Peril player " + perilPlayer + " no longer exists, but game continues with " + (string)llGetListLength(newNames) + " players");
|
||||
// Don't continue the round - let the elimination logic handle victory condition
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -753,6 +833,7 @@ default {
|
|||
currentPicker = NULL_KEY;
|
||||
roundStarted = FALSE;
|
||||
diceTypeProcessed = FALSE; // Reset for new game
|
||||
roundContinueInProgress = FALSE; // Reset protection flag
|
||||
llOwnerSay("🎯 Game Manager reset!");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -556,6 +556,9 @@ default {
|
|||
integer lives = (integer)llList2String(parts, 1);
|
||||
string profileUUID = llList2String(parts, 2);
|
||||
|
||||
// Debug: Show what data scoreboard received
|
||||
llOwnerSay("📊 Scoreboard received update: " + playerName + " has " + (string)lives + " hearts");
|
||||
|
||||
updatePlayerDisplay(playerName, lives, profileUUID);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -263,7 +263,9 @@ updateHelpers() {
|
|||
checkMemoryUsage("updateHelpers_start");
|
||||
|
||||
string perilForSync = "NONE";
|
||||
if (roundStarted) perilForSync = perilPlayer;
|
||||
if (perilPlayer != "" && perilPlayer != "NONE") {
|
||||
perilForSync = perilPlayer;
|
||||
}
|
||||
|
||||
string picksDataStr = "EMPTY";
|
||||
integer dataCount = llGetListLength(picksData);
|
||||
|
|
@ -588,11 +590,18 @@ default {
|
|||
if (idx != -1) {
|
||||
// FIRST: Set the player's lives to 0 and update scoreboard/floaters before removal
|
||||
lives = llListReplaceList(lives, [0], idx, idx);
|
||||
llOwnerSay("💀 Setting " + eliminatedPlayer + " to 0 hearts before elimination");
|
||||
|
||||
// Update scoreboard and floaters to show 0 hearts
|
||||
updateHelpers();
|
||||
llSleep(1.0); // Give time for the 0 hearts display to be visible
|
||||
llSleep(1.5); // Give extra time for the 0 hearts display to be visible
|
||||
|
||||
// Check if this will cause victory BEFORE removing player
|
||||
integer willCauseVictory = (llGetListLength(names) <= 2); // After removing one player
|
||||
|
||||
if (willCauseVictory) {
|
||||
// If this elimination will cause victory, give extra time for 0 hearts display
|
||||
llSleep(1.5); // Additional time for victory scenarios
|
||||
}
|
||||
|
||||
// THEN: Clean up and remove the player
|
||||
integer ch = llList2Integer(floaterChannels, idx);
|
||||
|
|
@ -604,7 +613,6 @@ default {
|
|||
picksData = llDeleteSubList(picksData, idx, idx);
|
||||
floaterChannels = llDeleteSubList(floaterChannels, idx, idx);
|
||||
|
||||
llOwnerSay("🗑️ Eliminated " + eliminatedPlayer + ". Remaining players: " + (string)llGetListLength(names));
|
||||
|
||||
// CHANGED: Send to scoreboard, which will handle leaderboard updates
|
||||
llMessageLinked(SCOREBOARD_LINK, MSG_GAME_LOST, eliminatedPlayer, NULL_KEY);
|
||||
|
|
@ -612,6 +620,33 @@ default {
|
|||
sendStatusMessage("Elimination");
|
||||
updateHelpers();
|
||||
|
||||
// CRITICAL: Update perilPlayer if the eliminated player was the peril player
|
||||
// This prevents sending stale sync messages in updateHelpers()
|
||||
if (perilPlayer == eliminatedPlayer) {
|
||||
// Find first remaining alive player to be new peril player
|
||||
string newPerilPlayer = "";
|
||||
integer k;
|
||||
for (k = 0; k < llGetListLength(names) && newPerilPlayer == ""; k++) {
|
||||
string candidateName = llList2String(names, k);
|
||||
integer candidateIdx = llListFindList(names, [candidateName]);
|
||||
if (candidateIdx != -1 && candidateIdx < llGetListLength(lives)) {
|
||||
integer candidateLives = llList2Integer(lives, candidateIdx);
|
||||
if (candidateLives > 0) {
|
||||
newPerilPlayer = candidateName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newPerilPlayer != "") {
|
||||
llOwnerSay("🎯 [Main Controller] Peril player eliminated - assigning new peril player: " + newPerilPlayer);
|
||||
perilPlayer = newPerilPlayer;
|
||||
} else {
|
||||
llOwnerSay("⚠️ [Main Controller] No valid peril player candidates found after elimination!");
|
||||
perilPlayer = "NONE";
|
||||
}
|
||||
}
|
||||
|
||||
// Check for victory condition AFTER the 0 hearts display AND removal
|
||||
if (llGetListLength(names) <= 1) {
|
||||
if (llGetListLength(names) == 1) {
|
||||
string winner = llList2String(names, 0);
|
||||
|
|
@ -662,6 +697,27 @@ default {
|
|||
string newLivesStr = llList2CSV(newLives);
|
||||
|
||||
string newPerilPlayerCheck = llList2String(parts, 2);
|
||||
list newNames = llCSV2List(llList2String(parts, 3));
|
||||
|
||||
// VALIDATION: Reject sync messages with invalid peril players to prevent loops
|
||||
if (newPerilPlayerCheck != "NONE" && newPerilPlayerCheck != "" && newPerilPlayerCheck != perilPlayer) {
|
||||
// Check if the peril player exists in the new names list
|
||||
integer perilPlayerExists = llListFindList(newNames, [newPerilPlayerCheck]) != -1;
|
||||
if (!perilPlayerExists) {
|
||||
llOwnerSay("⚠️ [Main Controller] REJECTING sync message with invalid peril player: " + newPerilPlayerCheck + " (player doesn't exist)");
|
||||
return; // Reject the entire sync message
|
||||
}
|
||||
|
||||
// Check if peril player has 0 lives (eliminated)
|
||||
integer perilPlayerIdx = llListFindList(newNames, [newPerilPlayerCheck]);
|
||||
if (perilPlayerIdx != -1 && perilPlayerIdx < llGetListLength(newLives)) {
|
||||
integer perilPlayerLives = llList2Integer(newLives, perilPlayerIdx);
|
||||
if (perilPlayerLives <= 0) {
|
||||
llOwnerSay("⚠️ [Main Controller] REJECTING sync message with eliminated peril player: " + newPerilPlayerCheck + " (0 lives)");
|
||||
return; // Reject the entire sync message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newPerilPlayerCheck == "NONE" && perilPlayer != "" && perilPlayer != "NONE") {
|
||||
integer perilStillInGame = llListFindList(names, [perilPlayer]) != -1;
|
||||
|
|
|
|||
18
README.md
18
README.md
|
|
@ -1,13 +1,13 @@
|
|||
# 🎲 Peril Dice — Professional Single Linkset Game System for Second Life
|
||||
|
||||
**Created by Rebecca Nod and Noose the Bunny**
|
||||
**Current Version: 2.8.1 - Display & Elimination Fixes**
|
||||
**Current Version: 2.8.2 - Scoreboard Spam & Display Fixes**
|
||||
|
||||
## 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.
|
||||
|
||||
**NEW in v2.8.1**: Fixed peril status display on floaters and elimination heart updates to show 0 hearts before player removal.
|
||||
**NEW in v2.8.2**: Fixed critical scoreboard spam bug caused by eliminated players, plus re-fixed peril status display on floaters and elimination heart updates to show 0 hearts before player removal.
|
||||
|
||||
**NEW in v2.8.0**: Game lockout security system, automatic reset functionality, and enhanced player management with kick/leave fixes for complete ownership control and stability.
|
||||
|
||||
|
|
@ -285,9 +285,17 @@ Dice type is automatically chosen to ensure at least 3 picks per player:
|
|||
|
||||
## Version
|
||||
|
||||
**Current Version**: 2.8.1
|
||||
**Last Updated**: August 14, 2025
|
||||
**Status**: Production Ready - Enhanced Display & Elimination Experience
|
||||
**Current Version**: 2.8.2
|
||||
**Last Updated**: August 21, 2025
|
||||
**Status**: Production Ready - Scoreboard Spam & Display Fixes
|
||||
|
||||
### Key Achievements in v2.8.2:
|
||||
- ✅ Fixed critical scoreboard spam bug caused by eliminated players
|
||||
- ✅ Enhanced peril player validation during elimination sequences
|
||||
- ✅ Re-fixed peril status display on floating HUDs during gameplay
|
||||
- ✅ Re-fixed elimination sequence to show 0 hearts before player removal
|
||||
- ✅ Improved sync message reliability to prevent stale data broadcasts
|
||||
- ✅ Enhanced elimination timing and coordination between display systems
|
||||
|
||||
### Key Achievements in v2.8.1:
|
||||
- ✅ Fixed peril status display on floating HUDs during gameplay
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
========================================================
|
||||
|
||||
CREATED BY REBECCA NOD AND NOOSE THE BUNNY
|
||||
CURRENT VERSION: 2.8.1 - DISPLAY & ELIMINATION FIXES
|
||||
CURRENT VERSION: 2.8.2 - SCOREBOARD SPAM & DISPLAY FIXES
|
||||
|
||||
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.
|
||||
|
||||
NEW IN V2.8.2: Fixed critical scoreboard spam bug caused by eliminated players, plus re-fixed peril status display on floaters and elimination heart updates to show 0 hearts before player removal.
|
||||
|
||||
KEY FEATURES
|
||||
============
|
||||
|
||||
|
|
@ -90,6 +92,37 @@ Player Count | Dice Type
|
|||
5–6 | d20
|
||||
7–10 | d30
|
||||
|
||||
RECENT IMPROVEMENTS (V2.8.2)
|
||||
============================
|
||||
|
||||
🔥 CRITICAL SCOREBOARD SPAM FIX
|
||||
- Eliminated Player Sync Loop: Fixed major bug where eliminated players caused continuous scoreboard update spam
|
||||
- Peril Player Validation: Enhanced peril player assignment during elimination sequences
|
||||
- Prevents stale sync messages containing eliminated player data from being broadcast repeatedly
|
||||
- Eliminates infinite scoreboard update loops that occurred when peril player was eliminated
|
||||
- Fixed root cause where Main Controller kept sending outdated peril player references
|
||||
|
||||
🎯 PERIL STATUS DISPLAY FIXES (RE-FIXED)
|
||||
- Enhanced Floater Peril Status: Re-implemented and improved peril status display on floating displays
|
||||
- Fixed peril status showing "waiting for game to start" during active gameplay (again)
|
||||
- Enhanced peril player detection logic in floater management
|
||||
- Improved sync message processing to ensure consistent peril status across all displays
|
||||
- Better handling of peril player transitions during plot twist scenarios
|
||||
|
||||
💖 ELIMINATION HEART DISPLAY FIXES (RE-FIXED)
|
||||
- 0 Hearts Before Elimination: Re-fixed elimination sequence to properly show 0 hearts before player removal
|
||||
- Enhanced Main Controller elimination logic to ensure 0 hearts display timing
|
||||
- Extended display delay to make 0 hearts clearly visible on both scoreboard and floaters
|
||||
- Improved coordination between heart updates and player cleanup processes
|
||||
- Fixed race conditions where players were removed before 0 hearts could be displayed
|
||||
|
||||
🛠️ TECHNICAL IMPROVEMENTS
|
||||
- Elimination Sequence Enhancement: Improved coordination between player removal and sync message broadcasting
|
||||
- Added peril player validation step before final updateHelpers() call
|
||||
- Enhanced elimination handler to prevent sync message corruption during player cleanup
|
||||
- Better synchronization between Main Controller state updates and helper script notifications
|
||||
- Display System Reliability: Strengthened display update mechanisms for consistent visual feedback
|
||||
|
||||
RECENT IMPROVEMENTS (V2.8.1)
|
||||
============================
|
||||
|
||||
|
|
@ -227,9 +260,9 @@ PREVIOUS IMPROVEMENTS (V2.4.0)
|
|||
|
||||
VERSION INFORMATION
|
||||
===================
|
||||
Current Version: 2.8.1
|
||||
Last Updated: August 14, 2025
|
||||
Status: Production Ready - Enhanced Display & Elimination Experience
|
||||
Current Version: 2.8.2
|
||||
Last Updated: August 21, 2025
|
||||
Status: Production Ready - Scoreboard Spam & Display Fixes
|
||||
|
||||
ORIGINAL GAME RULES CREDIT
|
||||
==========================
|
||||
|
|
|
|||
|
|
@ -326,10 +326,40 @@ default {
|
|||
llOwnerSay("💀 Elimination detected: " + perilPlayer + " has 0 hearts remaining");
|
||||
|
||||
llSay(0, "🐻 PUNISHMENT TIME! " + perilPlayer + " has been ELIMINATED!");
|
||||
// Remove eliminated player (send message to main controller)
|
||||
|
||||
// IMPORTANT: Update our local state to reflect the elimination
|
||||
// Remove the eliminated player from our names and lives lists to prevent stale data
|
||||
integer elimIdx = llListFindList(names, [perilPlayer]);
|
||||
if (elimIdx != -1) {
|
||||
names = llDeleteSubList(names, elimIdx, elimIdx);
|
||||
lives = llDeleteSubList(lives, elimIdx, elimIdx);
|
||||
// Also clean up their picks data
|
||||
integer pickIdx = -1;
|
||||
integer p;
|
||||
// LSL doesn't support break, so use a flag instead
|
||||
integer foundEntry = FALSE;
|
||||
for (p = 0; p < llGetListLength(picksData) && !foundEntry; p++) {
|
||||
string entry = llList2String(picksData, p);
|
||||
if (llSubStringIndex(entry, perilPlayer + "|") == 0) {
|
||||
pickIdx = p;
|
||||
foundEntry = TRUE;
|
||||
}
|
||||
}
|
||||
if (pickIdx != -1) {
|
||||
picksData = llDeleteSubList(picksData, pickIdx, pickIdx);
|
||||
}
|
||||
llOwnerSay("🔄 [Roll Module] Updated local state - removed " + perilPlayer + " from names/lives/picks");
|
||||
}
|
||||
|
||||
// Send message to main controller to handle elimination
|
||||
llMessageLinked(LINK_SET, 999, "ELIMINATE_PLAYER|" + perilPlayer, NULL_KEY);
|
||||
// The Main Controller will handle peril player reassignment and game flow
|
||||
// Don't continue processing this round since the player was eliminated
|
||||
|
||||
// CRITICAL: Don't send any sync messages after elimination
|
||||
// Let Main Controller handle all state sync and peril player reassignment
|
||||
llOwnerSay("🎯 [Roll Module] Elimination complete - letting Main Controller handle state sync");
|
||||
|
||||
// Clear roll protection after processing is complete
|
||||
rollInProgress = FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
219
WARP.md
Normal file
219
WARP.md
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
# WARP.md
|
||||
|
||||
This file provides guidance to WARP (warp.dev) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
**Peril Dice** is a multiplayer elimination game for Second Life, built using LSL (Linden Scripting Language). It's a professional-grade linkset system where players select numbers before dice rolls, with the peril player losing lives when their number comes up. The project features a single 74-prim linkset architecture with sophisticated inter-script communication.
|
||||
|
||||
**Current Version**: 2.8.2 - Scoreboard Spam & Display Fixes
|
||||
**Technology**: LSL (Linden Scripting Language) for Second Life virtual world
|
||||
**Architecture**: Single linkset with 16 modular LSL scripts communicating via `llMessageLinked()`
|
||||
|
||||
## Development Commands
|
||||
|
||||
### LSL Validation & Processing
|
||||
```bash
|
||||
# Validate single LSL file syntax
|
||||
python3 /home/richard/lsl-docs/tools/lsl_validator.py filename.lsl
|
||||
|
||||
# Validate all LSL files in project
|
||||
python3 /home/richard/lsl-docs/tools/lsl_validator.py .
|
||||
|
||||
# Preprocess LSL file (includes/macros)
|
||||
python3 /home/richard/lsl-docs/tools/lsl_preprocessor.py input.lsl processed_output.lsl
|
||||
```
|
||||
|
||||
### Jenkins CI/CD Pipeline
|
||||
The project uses automated CI/CD via `Jenkinsfile`:
|
||||
|
||||
```bash
|
||||
# CI pipeline automatically runs on push:
|
||||
# 1. LSL Validation - checks syntax and common errors
|
||||
# 2. Preprocessing - handles includes/macros (main/develop branches)
|
||||
# 3. Release Package Generation - creates versioned releases (main branch)
|
||||
# 4. Documentation Updates - generates function lists (main branch)
|
||||
```
|
||||
|
||||
### VS Code Development Tasks
|
||||
Use VS Code Command Palette (`Ctrl+Shift+P`) → "Tasks: Run Task":
|
||||
|
||||
- **Validate LSL File** - Check current file syntax
|
||||
- **Validate All LSL Files** - Check entire project
|
||||
- **Open LSL Documentation** - Browser reference at https://lsl-docs.richardf.us
|
||||
- **Search LSL Function** - Quick function lookup
|
||||
- **Preprocess LSL File** - Process includes/macros
|
||||
|
||||
### Git Workflow
|
||||
```bash
|
||||
# Standard development workflow
|
||||
git checkout -b feature/new-feature
|
||||
# ... make changes to .lsl files ...
|
||||
git add *.lsl README.md CHANGELOG.md
|
||||
git commit -m "feat: description of changes"
|
||||
git push origin feature/new-feature
|
||||
# Create pull request to develop, then merge to main for releases
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Single Linkset Design (v2.7.0+)
|
||||
The system uses a unified 74-prim linkset eliminating all external communication:
|
||||
|
||||
```
|
||||
Link 1: Main Controller (Root Prim)
|
||||
├── Links 2-24: Scoreboard (23 prims)
|
||||
│ ├── Link 2: Scoreboard Manager Script
|
||||
│ ├── Link 3: Background Prim
|
||||
│ ├── Link 4: Actions/Status Prim
|
||||
│ └── Links 5-24: Player Prims (20 slots with profile pics & hearts)
|
||||
├── Links 25-72: XyzzyText Leaderboard (48 prims across 4 banks)
|
||||
└── Links 73-74: Dice Display (2 prims for roll results)
|
||||
```
|
||||
|
||||
### Core Script Architecture
|
||||
**16 modular LSL scripts** with specific responsibilities:
|
||||
|
||||
**Core Controllers:**
|
||||
- `Main_Controller_Linkset.lsl` - Central game state and coordination
|
||||
- `Game_Manager.lsl` - Round management, pick validation, win conditions
|
||||
- `Controller_Memory.lsl` - Memory monitoring and optimization
|
||||
- `Controller_MessageHandler.lsl` - Message routing and communication
|
||||
|
||||
**Interface & Display:**
|
||||
- `Player_DialogHandler.lsl` - Player UI and input processing
|
||||
- `NumberPicker_DialogHandler.lsl` - Number picking interface
|
||||
- `Game_Scoreboard_Manager_Linkset.lsl` - Visual player display (Link 2)
|
||||
- `Floater_Manager.lsl` - Floating HUD displays for players
|
||||
- `PlayerStatus_Float.lsl` - Individual player status displays
|
||||
|
||||
**Game Mechanics:**
|
||||
- `Roll_ConfettiModule.lsl` - Dice rolling and particle effects
|
||||
- `Bot_Manager.lsl` - AI player behavior and automation
|
||||
- `Game_Calculator.lsl` - Dice type calculation and game math
|
||||
|
||||
**External Communication:**
|
||||
- `Leaderboard_Communication_Linkset.lsl` - XyzzyText bridge (Link 25)
|
||||
- `XyzzyText_Dice_Bridge_Linkset.lsl` - Roll result display (Link 73)
|
||||
|
||||
**Utilities:**
|
||||
- `System_Debugger.lsl` - Development debugging tools
|
||||
- `xyzzy_Master_script.lsl` - Legacy XyzzyText controller
|
||||
|
||||
### Communication Protocol
|
||||
**Link Messages Only** - No region chat or discovery:
|
||||
```lsl
|
||||
// Scoreboard messages (to link 2)
|
||||
integer MSG_GAME_STATUS = 3001;
|
||||
integer MSG_PLAYER_UPDATE = 3002;
|
||||
integer MSG_CLEAR_GAME = 3003;
|
||||
|
||||
// Leaderboard messages (to link 25)
|
||||
integer MSG_GAME_WON = 3010;
|
||||
integer MSG_RESET_LEADERBOARD = 3012;
|
||||
|
||||
// Dice messages (to link 73)
|
||||
integer MSG_DICE_ROLL = 3020;
|
||||
integer MSG_CLEAR_DICE = 3021;
|
||||
```
|
||||
|
||||
**Benefits of this architecture:**
|
||||
- **Zero Channel Conflicts** - Multiple game instances operate independently
|
||||
- **50%+ Performance Improvement** - Instant message delivery vs. region chat
|
||||
- **Bulletproof Reliability** - No discovery failures or timeouts
|
||||
- **One-Click Deployment** - Single linkset rez replaces 4-object positioning
|
||||
|
||||
### Game State Management
|
||||
**Critical synchronized data across scripts:**
|
||||
- `players[]` - Avatar keys of registered players
|
||||
- `names[]` - Display names of players
|
||||
- `lives[]` - Current life counts (3, 2, 1, 0)
|
||||
- `perilPlayer` - Current player in peril
|
||||
- `globalPickedNumbers[]` - Numbers chosen this round
|
||||
- `picksData[]` - Player pick history ("PlayerName|1,2,3")
|
||||
|
||||
**State Synchronization Pattern:**
|
||||
```lsl
|
||||
// In any script modifying game state:
|
||||
syncStateToMain(); // Updates Main Controller
|
||||
llMessageLinked(LINK_SET, MSG_SYNC_GAME_STATE, "", NULL_KEY); // Broadcast
|
||||
```
|
||||
|
||||
### Dynamic Dice Scaling
|
||||
Automatic dice selection ensures fair gameplay:
|
||||
- 1-2 players → d6 (6 numbers)
|
||||
- 3-4 players → d12 (12 numbers)
|
||||
- 5-6 players → d20 (20 numbers)
|
||||
- 7-10 players → d30 (30 numbers)
|
||||
|
||||
*Guarantees exactly 3 numbers per player available*
|
||||
|
||||
## Key Architectural Principles
|
||||
|
||||
### 1. Link Message Communication
|
||||
**All inter-script communication** uses `llMessageLinked()` for guaranteed delivery within the linkset. No external channels or discovery protocols.
|
||||
|
||||
### 2. Modular Script Responsibility
|
||||
Each script has **single responsibility** - Game Manager handles rounds, Scoreboard Manager handles display, etc. No cross-dependencies.
|
||||
|
||||
### 3. State Synchronization
|
||||
**Centralized state management** in Main Controller with broadcast synchronization to prevent data inconsistencies.
|
||||
|
||||
### 4. Race Condition Prevention
|
||||
**Duplicate registration protection**, **timing controls**, and **request deduplication** prevent common LSL concurrency issues.
|
||||
|
||||
### 5. Professional Error Handling
|
||||
**Comprehensive validation**, **graceful failures**, and **debug logging** ensure stable operation in Second Life's unpredictable environment.
|
||||
|
||||
## Important Implementation Details
|
||||
|
||||
### Display Name Handling
|
||||
```lsl
|
||||
string getPlayerName(key id) {
|
||||
string displayName = llGetDisplayName(id);
|
||||
if (displayName == "") {
|
||||
displayName = llKey2Name(id); // Fallback to legacy username
|
||||
}
|
||||
return displayName;
|
||||
}
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
Controller_Memory.lsl actively monitors script memory usage and triggers cleanup when thresholds are exceeded. Critical for long-running Second Life objects.
|
||||
|
||||
### Security Features (v2.8.0+)
|
||||
- **Game Lockout System** - Owner can restrict access to owner only
|
||||
- **Kick Player Functionality** - Remove disruptive players
|
||||
- **Automatic Reset on Startup** - Prevents stale data issues
|
||||
|
||||
### Critical Fixes (v2.8.2)
|
||||
- **Scoreboard Spam Elimination** - Fixed major bug where eliminated players caused infinite sync loops
|
||||
- **Peril Player Validation** - Enhanced elimination sequence to prevent stale sync messages
|
||||
- **Main Controller Fix** - Updates peril player variable immediately after elimination before final sync
|
||||
- **Re-Fixed Display Systems** - Peril status and 0 hearts display needed additional stabilization
|
||||
|
||||
### Enhanced Elimination Display (v2.8.1)
|
||||
- Players see **0 hearts before elimination** with 1-second display
|
||||
- **Real-time peril status updates** on floating displays
|
||||
- **Proper elimination sequence** with visual feedback
|
||||
|
||||
## File Naming Conventions
|
||||
|
||||
**Do not rename files** - LSL scripts have specific names expected by the linkset architecture. The `_Linkset` suffix indicates scripts designed for specific link numbers.
|
||||
|
||||
**Script-to-Link Mapping:**
|
||||
- `*_Linkset.lsl` → Specific link number scripts
|
||||
- `*_Manager.lsl` → Core system controllers
|
||||
- `*_Handler.lsl` → UI and input processors
|
||||
- `*_Module.lsl` → Specialized functionality (dice, confetti, etc.)
|
||||
|
||||
## Testing and Deployment
|
||||
|
||||
### Local Testing
|
||||
Use **Bot Manager** to add AI players for testing game mechanics without requiring multiple avatars.
|
||||
|
||||
### CI/CD Pipeline
|
||||
Jenkins automatically validates syntax and creates release packages on main branch pushes. Manual deployment to Second Life required.
|
||||
|
||||
### Version Management
|
||||
Versions follow semantic versioning (v2.8.2) with detailed changelogs in `CHANGELOG.md` and `README.md`. Recent releases show the iterative nature of complex system maintenance, including addressing regressions in display systems.
|
||||
Loading…
Reference in a new issue