diff --git a/Experience_Admin_HUD.lsl b/Experience_Admin_HUD.lsl new file mode 100644 index 0000000..1ff3980 --- /dev/null +++ b/Experience_Admin_HUD.lsl @@ -0,0 +1,138 @@ +// ============================================================================ +// Experience Admin HUD +// ============================================================================ +// Instructions: +// 1. Create a new box, put this script inside. +// 2. DO NOT FORGET to check "Use Experience" and select Final Girlz I.N.C! +// 3. Attach it to your HUD or click it if it's rezzed. +// +// Commands (type in local chat): +// /99 keys - Lists all keys currently in the entire database +// /99 get [Key] - Reads and displays the data inside a specific key +// /99 del [Key] - Deletes a specific key from the database +// ============================================================================ + +key requestKeys; +key requestRead; +key requestDelete; +key requestWrite; +key lastUser; +string pendingSetKey; +string pendingSetValue; + +default { + state_entry() { + lastUser = llGetOwner(); + llRegionSayTo(lastUser, 0, "šŸ”§ Experience Admin Terminal Ready."); + llRegionSayTo(lastUser, 0, "šŸ’¬ Type commands in local chat:"); + llRegionSayTo(lastUser, 0, " /99 keys"); + llRegionSayTo(lastUser, 0, " /99 get key_name"); + llRegionSayTo(lastUser, 0, " /99 set key_name=Hello World"); + llRegionSayTo(lastUser, 0, " /99 del key_name"); + llListen(99, "", NULL_KEY, ""); + } + + listen(integer channel, string name, key id, string msg) { + // SECURITY CHECK: Strictly whitelist authorized Admin usernames! + string uname = llStringTrim(llToLower(llGetUsername(id)), STRING_TRIM); + if (id != llGetOwner() && uname != "djmusica28" && uname != "finalgirlzbot") { + llRegionSayTo(id, 0, "āŒ Access Denied: You are not on the authorized Administrator whitelist for this database."); + return; + } + lastUser = id; + msg = llStringTrim(msg, STRING_TRIM); + + if (msg == "keys") { + llRegionSayTo(lastUser, 0, "šŸ” Requesting list of database keys (up to 100)..."); + requestKeys = llKeysKeyValue(0, 100); + } + else if (llGetSubString(msg, 0, 3) == "get ") { + string targetKey = llStringTrim(llGetSubString(msg, 4, -1), STRING_TRIM); + llRegionSayTo(lastUser, 0, "šŸ” Reading key: " + targetKey + "..."); + requestRead = llReadKeyValue(targetKey); + } + else if (llGetSubString(msg, 0, 3) == "set ") { + string payload = llStringTrim(llGetSubString(msg, 4, -1), STRING_TRIM); + integer equalSign = llSubStringIndex(payload, "="); + if (equalSign != -1) { + pendingSetKey = llStringTrim(llGetSubString(payload, 0, equalSign - 1), STRING_TRIM); + pendingSetValue = llStringTrim(llGetSubString(payload, equalSign + 1, -1), STRING_TRIM); + llRegionSayTo(lastUser, 0, "šŸ’¾ Writing key: " + pendingSetKey + "..."); + requestWrite = llUpdateKeyValue(pendingSetKey, pendingSetValue, FALSE, ""); + } else { + llRegionSayTo(lastUser, 0, "āŒ Format: /99 set key=value"); + } + } + else if (llGetSubString(msg, 0, 3) == "del ") { + string targetKey = llStringTrim(llGetSubString(msg, 4, -1), STRING_TRIM); + llRegionSayTo(lastUser, 0, "šŸ—‘ļø Deleting key: " + targetKey + "..."); + requestDelete = llDeleteKeyValue(targetKey); + } + } + + dataserver(key queryid, string data) { + // llKeysKeyValue returns data as CSV: + // Success: 1,keyname1,keyname2... + // Failure: 0,error_code + if (queryid == requestKeys) { + list result = llCSV2List(data); + if (llList2Integer(result, 0) == 1) { + // Success + integer numKeys = llGetListLength(result) - 1; + llRegionSayTo(lastUser, 0, "āœ… Found " + (string)numKeys + " keys in database:"); + + integer i; + for(i = 1; i < llGetListLength(result); i++) { + llRegionSayTo(lastUser, 0, " šŸ”‘ " + llList2String(result, i)); + } + } else if (llList2Integer(result, 1) == 3) { + llRegionSayTo(lastUser, 0, "šŸ“­ The database is completely empty! No keys exist."); + } else { + llRegionSayTo(lastUser, 0, "āŒ Failed to read keys (Error " + llList2String(result, 1) + ")"); + } + } + + // llReadKeyValue returns data as: status,value + else if (queryid == requestRead) { + integer comma = llSubStringIndex(data, ","); + string status = llGetSubString(data, 0, comma - 1); + string val = llGetSubString(data, comma + 1, -1); + + if (status == "1") { + llRegionSayTo(lastUser, 0, "šŸ“„ Content:\n" + val); + } else if (status == "3") { + llRegionSayTo(lastUser, 0, "āŒ That key doesn't exist!"); + } else { + llRegionSayTo(lastUser, 0, "āŒ Read failed (Status: " + status + ")"); + } + } + + // llDeleteKeyValue dataserver logic + else if (queryid == requestDelete) { + integer comma = llSubStringIndex(data, ","); + string status = llGetSubString(data, 0, comma - 1); + + if (status == "1") { + llRegionSayTo(lastUser, 0, "āœ… Key successfully deleted!"); + } else if (status == "3") { + llRegionSayTo(lastUser, 0, "āŒ Key didn't exist to delete."); + } else { + llRegionSayTo(lastUser, 0, "āŒ Delete failed (Status: " + status + ")"); + } + } + + // Write logic + else if (queryid == requestWrite) { + integer comma = llSubStringIndex(data, ","); + string status = llGetSubString(data, 0, comma - 1); + if (status == "1") { + llRegionSayTo(lastUser, 0, "āœ… Key saved successfully!"); + } else if (status == "3") { + // Key didn't exist to update, manually create it! + requestWrite = llCreateKeyValue(pendingSetKey, pendingSetValue); + } else { + llRegionSayTo(lastUser, 0, "āŒ Write failed (Status: " + status + ")"); + } + } + } +} diff --git a/Game_Manager.lsl b/Game_Manager.lsl index e7af904..1ea7cb8 100644 --- a/Game_Manager.lsl +++ b/Game_Manager.lsl @@ -92,7 +92,15 @@ reportMemoryUsage(string scriptName) { } // Verbose logging control - toggled by owner +#define DEBUG_LOGS 0 // Set to 1 to enable logs, 0 to STRIP from memory completely +#if DEBUG_LOGS +#define dbg(msg) dbg(msg) integer VERBOSE_LOGGING = FALSE; +#else +#define dbg(msg) +#define VERBOSE_LOGGING 0 +#endif +// Original VERBOSE_LOGGING definition removed // Message constants #define MSG_SHOW_DIALOG 101 @@ -118,30 +126,30 @@ continueCurrentRound() { if (continuePlayerIdx != -1 && continuePlayerIdx < llGetListLength(lives)) { integer continuePlayerLives = llList2Integer(lives, continuePlayerIdx); if (continuePlayerLives <= 0) { - llOwnerSay("šŸ›‘ [Game Manager] continueCurrentRound: Found eliminated player " + continueName + " with " + (string)continuePlayerLives + " lives - aborting round start"); + dbg("šŸ›‘ [Game Manager] continueCurrentRound: Found eliminated player " + continueName + " with " + (string)continuePlayerLives + " lives - aborting round start"); return; } } } if (perilPlayer == "" || perilPlayer == "NONE") { - llOwnerSay("šŸ›‘ [Game Manager] continueCurrentRound: Invalid peril player (" + perilPlayer + ") - aborting round start"); + dbg("šŸ›‘ [Game Manager] continueCurrentRound: Invalid peril player (" + perilPlayer + ") - aborting round start"); return; } // Verify peril player exists and has lives integer perilIdx = llListFindList(names, [perilPlayer]); if (perilIdx == -1) { - llOwnerSay("šŸ›‘ [Game Manager] continueCurrentRound: Peril player " + perilPlayer + " not found in names list - aborting round start"); + dbg("šŸ›‘ [Game Manager] continueCurrentRound: Peril player " + perilPlayer + " not found in names list - aborting round start"); return; } if (perilIdx >= llGetListLength(lives)) { - llOwnerSay("šŸ›‘ [Game Manager] continueCurrentRound: Peril player " + perilPlayer + " index out of bounds - aborting round start"); + dbg("šŸ›‘ [Game Manager] continueCurrentRound: Peril player " + perilPlayer + " index out of bounds - aborting round start"); return; } integer perilLives = llList2Integer(lives, perilIdx); if (perilLives <= 0) { - llOwnerSay("šŸ›‘ [Game Manager] continueCurrentRound: Peril player " + perilPlayer + " has " + (string)perilLives + " lives - aborting round start"); + dbg("šŸ›‘ [Game Manager] continueCurrentRound: Peril player " + perilPlayer + " has " + (string)perilLives + " lives - aborting round start"); return; } @@ -149,7 +157,7 @@ continueCurrentRound() { // globalPickedNumbers will be cleared when first player picks picksData = []; - llOwnerSay("šŸ”„ [Game Manager] continueCurrentRound: All validation passed, starting fresh round with " + (string)llGetListLength(names) + " players"); + dbg("šŸ”„ [Game Manager] continueCurrentRound: All validation passed, starting fresh round with " + (string)llGetListLength(names) + " players"); // Set round as started for the new round roundStarted = TRUE; @@ -165,7 +173,7 @@ continueCurrentRound() { } currentPickerIdx = 0; - llOwnerSay("šŸŽÆ [Game Manager] Pick queue created: " + llList2CSV(pickQueue) + ", requesting dice type"); + dbg("šŸŽÆ [Game Manager] Pick queue created: " + llList2CSV(pickQueue) + ", requesting dice type"); // Request dice type directly from Calculator for the new round llMessageLinked(LINK_SET, MSG_GET_DICE_TYPE, (string)llGetListLength(names), NULL_KEY); @@ -176,12 +184,12 @@ continueCurrentRound() { startNextRound() { // Prevent multiple calls to start round if (roundStarted) { - llOwnerSay("āš ļø Round already started, ignoring duplicate start request"); + dbg("āš ļø Round already started, ignoring duplicate start request"); return; } if (llGetListLength(names) < 2) { - llOwnerSay("āš ļø Need at least 2 players to start the game."); + dbg("āš ļø Need at least 2 players to start the game."); return; } @@ -200,7 +208,7 @@ startNextRound() { return; } - llOwnerSay("šŸŽÆ Game Manager starting new round..."); + dbg("šŸŽÆ Game Manager starting new round..."); // Set roundStarted immediately to prevent duplicate calls roundStarted = TRUE; @@ -216,7 +224,7 @@ startNextRound() { llMessageLinked(12, 3005, perilPlayer, NULL_KEY); // MSG_UPDATE_PERIL_PLAYER // Sync state to floater manager first, then update floaters to show new peril player immediately - llOwnerSay("šŸ”„ [Game Manager] Syncing state and updating floaters for new peril player: " + perilPlayer); + dbg("šŸ”„ [Game Manager] Syncing state and updating floaters for new peril player: " + perilPlayer); syncStateToMain(); // Sync the peril player to all modules first llSleep(0.1); // Brief delay to ensure sync propagates integer startJ; @@ -230,7 +238,7 @@ startNextRound() { // globalPickedNumbers will be cleared when first player picks // Create pick queue with peril player first - llOwnerSay("šŸŽÆ Debug - Creating pickQueue. names: " + llList2CSV(names) + ", perilPlayer: " + perilPlayer); + dbg("šŸŽÆ Debug - Creating pickQueue. names: " + llList2CSV(names) + ", perilPlayer: " + perilPlayer); pickQueue = [perilPlayer]; integer k; for (k = 0; k < llGetListLength(names); k++) { @@ -240,11 +248,11 @@ startNextRound() { } } currentPickerIdx = 0; - llOwnerSay("šŸŽÆ Debug - Created pickQueue: " + llList2CSV(pickQueue) + ", currentPickerIdx: " + (string)currentPickerIdx); + dbg("šŸŽÆ Debug - Created pickQueue: " + llList2CSV(pickQueue) + ", currentPickerIdx: " + (string)currentPickerIdx); // Request dice type for this round llMessageLinked(LINK_SET, MSG_GET_DICE_TYPE, (string)llGetListLength(names), NULL_KEY); - llOwnerSay("šŸŽÆ Game Manager round setup complete, requesting dice type..."); + dbg("šŸŽÆ Game Manager round setup complete, requesting dice type..."); } showNextPickerDialog() { @@ -254,40 +262,40 @@ showNextPickerDialog() { // Clear globalPickedNumbers if this is the first picker of a new round if (currentPickerIdx == 0 && llGetListLength(picksData) == 0) { globalPickedNumbers = []; - llOwnerSay("šŸ”„ [Game Manager] Cleared globalPickedNumbers at start of new round"); + dbg("šŸ”„ [Game Manager] Cleared globalPickedNumbers at start of new round"); } if (diceType <= 0) { - llOwnerSay("āŒ Cannot show picker dialog: diceType not set (" + (string)diceType + ")"); + dbg("āŒ Cannot show picker dialog: diceType not set (" + (string)diceType + ")"); return; } if (currentPickerIdx >= llGetListLength(pickQueue)) { - llOwnerSay("āŒ Cannot show picker dialog: currentPickerIdx (" + (string)currentPickerIdx + ") >= pickQueue length (" + (string)llGetListLength(pickQueue) + ")"); + dbg("āŒ Cannot show picker dialog: currentPickerIdx (" + (string)currentPickerIdx + ") >= pickQueue length (" + (string)llGetListLength(pickQueue) + ")"); return; } string firstName = llList2String(pickQueue, currentPickerIdx); if (firstName == "") { - llOwnerSay("āŒ Cannot show picker dialog: empty player name at index " + (string)currentPickerIdx); + dbg("āŒ Cannot show picker dialog: empty player name at index " + (string)currentPickerIdx); return; } // CRITICAL: Verify this player is still alive and in the game integer showPlayerIdx = llListFindList(names, [firstName]); if (showPlayerIdx == -1) { - llOwnerSay("āŒ Cannot show picker dialog: player " + firstName + " not found in current game"); + dbg("āŒ Cannot show picker dialog: player " + firstName + " not found in current game"); return; } if (showPlayerIdx >= llGetListLength(lives)) { - llOwnerSay("āŒ Cannot show picker dialog: player " + firstName + " index out of bounds for lives list"); + dbg("āŒ Cannot show picker dialog: player " + firstName + " index out of bounds for lives list"); return; } integer showPlayerLives = llList2Integer(lives, showPlayerIdx); if (showPlayerLives <= 0) { - llOwnerSay("āŒ Cannot show picker dialog: player " + firstName + " has been eliminated (" + (string)showPlayerLives + " lives)"); + dbg("āŒ Cannot show picker dialog: player " + firstName + " has been eliminated (" + (string)showPlayerLives + " lives)"); return; } @@ -299,7 +307,7 @@ showNextPickerDialog() { string existingPicks = llGetSubString(llList2String(picksData, showIdx), llStringLength(firstName) + 1, -1); if (existingPicks != "") { alreadyHasPicks = TRUE; - llOwnerSay("šŸŽÆ Game Manager: " + firstName + " already has picks (" + existingPicks + "), advancing to next player"); + dbg("šŸŽÆ Game Manager: " + firstName + " already has picks (" + existingPicks + "), advancing to next player"); } } } @@ -319,7 +327,7 @@ showNextPickerDialog() { integer nameIdx = llListFindList(names, [firstName]); if (nameIdx == -1) { - llOwnerSay("āŒ Cannot show picker dialog: player " + firstName + " not found in names list"); + dbg("āŒ Cannot show picker dialog: player " + firstName + " not found in names list"); return; } @@ -337,7 +345,7 @@ showNextPickerDialog() { string existingBotPicks = llGetSubString(llList2String(picksData, showJ), llStringLength(firstName) + 1, -1); if (existingBotPicks != "") { botAlreadyHasPicks = TRUE; - llOwnerSay("āš ļø [Game Manager] Bot " + firstName + " already has picks, skipping bot command: " + existingBotPicks); + dbg("āš ļø [Game Manager] Bot " + firstName + " already has picks, skipping bot command: " + existingBotPicks); } } } @@ -354,9 +362,9 @@ showNextPickerDialog() { list showCompleteAvoidList = buildCompleteAvoidanceList(); string showAvoidListStr = llList2CSV(showCompleteAvoidList); string botCommand = "BOT_PICK:" + firstName + ":" + (string)showPicksNeeded + ":" + (string)diceType + ":" + showAvoidListStr; - llOwnerSay("šŸŽÆ [Game Manager] Sending bot command with complete avoid list (" + (string)llGetListLength(showCompleteAvoidList) + " numbers): " + showAvoidListStr); + dbg("šŸŽÆ [Game Manager] Sending bot command with complete avoid list (" + (string)llGetListLength(showCompleteAvoidList) + " numbers): " + showAvoidListStr); llMessageLinked(LINK_SET, -9999, botCommand, NULL_KEY); - llOwnerSay("šŸ¤– " + firstName + " is automatically picking " + (string)showPicksNeeded + " numbers..."); + dbg("šŸ¤– " + firstName + " is automatically picking " + (string)showPicksNeeded + " numbers..."); } else { // Bot already has picks, advance to next player immediately currentPickerIdx++; @@ -382,7 +390,7 @@ showNextPickerDialog() { string humanAvoidListStr = llList2CSV(humanCompleteAvoidList); string dialogPayload = firstName + "|" + (string)diceType + "|" + (string)humanPicksNeeded + "|" + humanAvoidListStr; - llOwnerSay("šŸŽÆ Showing pick dialog for " + firstName); + dbg("šŸŽÆ Showing pick dialog for " + firstName); llSleep(0.5); // Brief delay to prevent spam // Send dialog request through Player_RegistrationManager (it has the correct player keys) @@ -403,7 +411,7 @@ syncStateToMain() { default { state_entry() { reportMemoryUsage("Game Manager"); - llOwnerSay("šŸŽÆ Game Manager initializing..."); + dbg("šŸŽÆ Game Manager initializing..."); // Initialize/reset all game state variables players = []; @@ -424,12 +432,12 @@ default { lastBotPickMessage = ""; lastProcessTime = 0; - llOwnerSay("šŸŽÆ Game Manager ready!"); + dbg("šŸŽÆ Game Manager ready!"); } on_rez(integer start_param) { reportMemoryUsage("Game Manager"); - llOwnerSay("šŸ”„ Game Manager rezzed - reinitializing..."); + dbg("šŸ”„ Game Manager rezzed - reinitializing..."); // Reset all game state variables on rez players = []; @@ -450,7 +458,7 @@ default { lastBotPickMessage = ""; lastProcessTime = 0; - llOwnerSay("āœ… Game Manager reset complete after rez!"); + dbg("āœ… Game Manager reset complete after rez!"); } link_message(integer sender, integer num, string str, key id) { @@ -528,7 +536,7 @@ default { } if (livesChanged && newPerilPlayer != "" && newPerilPlayer != "NONE" && roundStarted && allPicksEmpty) { - llOwnerSay("šŸŽÆ Post-roll state update detected - continuing round"); + dbg("šŸŽÆ Post-roll state update detected - continuing round"); continueCurrentRound(); } } @@ -538,21 +546,21 @@ default { // Receive legacy game state updates from main controller (simplified version) if (num == 9071) { - llOwnerSay("šŸ”§ [Game Manager] Received sync: " + str); + dbg("šŸ”§ [Game Manager] Received sync: " + str); list parts = llParseString2List(str, ["~"], []); - llOwnerSay("šŸ”§ [Game Manager] Parsed into " + (string)llGetListLength(parts) + " parts"); + dbg("šŸ”§ [Game Manager] Parsed into " + (string)llGetListLength(parts) + " parts"); // MEMORY OPTIMIZED: Skip heavy validation that causes sync rejections // Trust that Main Controller sends valid data // Handle special RESET sync message if (llGetListLength(parts) >= 5 && llList2String(parts, 0) == "RESET") { - llOwnerSay("šŸ”„ [Game Manager] Received reset sync - ignoring during reset"); + dbg("šŸ”„ [Game Manager] Received reset sync - ignoring during reset"); return; } if (llGetListLength(parts) < 4) { - llOwnerSay("āš ļø [Game Manager] Incomplete sync message received, parts: " + (string)llGetListLength(parts) + " - IGNORING"); + dbg("āš ļø [Game Manager] Incomplete sync message received, parts: " + (string)llGetListLength(parts) + " - IGNORING"); return; } { @@ -588,14 +596,14 @@ default { } } - llOwnerSay("šŸŽÆ [Game Manager] Updated: " + (string)llGetListLength(names) + " players (minimal parsing)"); + dbg("šŸŽÆ [Game Manager] Updated: " + (string)llGetListLength(names) + " players (minimal parsing)"); } // Update peril player string receivedPerilPlayer = llList2String(parts, 2); if (receivedPerilPlayer != "NONE" && receivedPerilPlayer != "") { perilPlayer = receivedPerilPlayer; - llOwnerSay("šŸŽÆ [Game Manager] Peril player updated to: " + perilPlayer); + dbg("šŸŽÆ [Game Manager] Peril player updated to: " + perilPlayer); } // MEMORY OPTIMIZED: Skip all other complex processing @@ -608,26 +616,26 @@ default { list newPickQueue = llCSV2List(str); string senderStr = (string)sender; string queueLenStr = (string)llGetListLength(newPickQueue); - llOwnerSay("šŸ” [Game Manager] Received pickQueue sync from sender " + senderStr + ": '" + str + "' (" + queueLenStr + " items)"); + dbg("šŸ” [Game Manager] Received pickQueue sync from sender " + senderStr + ": '" + str + "' (" + queueLenStr + " items)"); // STRONGEST PROTECTION: Never accept empty pickQueues during any active round if (roundStarted && llGetListLength(pickQueue) > 0 && (str == "" || llGetListLength(newPickQueue) == 0)) { - llOwnerSay("šŸ” [Game Manager] REJECTING empty/invalid pickQueue sync during active round - keeping: " + llList2CSV(pickQueue)); + dbg("šŸ” [Game Manager] REJECTING empty/invalid pickQueue sync during active round - keeping: " + llList2CSV(pickQueue)); return; } // Additional protection: Don't accept pickQueue syncs if we just created a valid one if (llGetListLength(pickQueue) > 0 && (str == "" || llGetListLength(newPickQueue) == 0)) { - llOwnerSay("šŸ” [Game Manager] REJECTING empty pickQueue sync - keeping valid queue: " + llList2CSV(pickQueue)); + dbg("šŸ” [Game Manager] REJECTING empty pickQueue sync - keeping valid queue: " + llList2CSV(pickQueue)); return; } // Only accept valid non-empty pickQueues if (llGetListLength(newPickQueue) > 0) { pickQueue = newPickQueue; - llOwnerSay("šŸ” [Game Manager] pickQueue updated to: " + llList2CSV(pickQueue)); + dbg("šŸ” [Game Manager] pickQueue updated to: " + llList2CSV(pickQueue)); } else { - llOwnerSay("šŸ” [Game Manager] Ignoring invalid pickQueue sync - keeping current: " + llList2CSV(pickQueue)); + dbg("šŸ” [Game Manager] Ignoring invalid pickQueue sync - keeping current: " + llList2CSV(pickQueue)); } return; } @@ -636,13 +644,13 @@ default { if (num == MSG_DICE_TYPE_RESULT) { // Prevent duplicate processing of dice type results if (diceTypeProcessed) { - llOwnerSay("šŸŽ² Ignoring duplicate dice type result: " + str); + dbg("šŸŽ² Ignoring duplicate dice type result: " + str); return; } diceType = (integer)str; diceTypeProcessed = TRUE; - llOwnerSay("šŸŽ² Game Manager received dice type: d" + str + " from Calculator"); + dbg("šŸŽ² Game Manager received dice type: d" + str + " from Calculator"); llSleep(0.3); // Brief delay // Start dialog if round has been started and we have a queue @@ -662,7 +670,7 @@ default { } if (!alreadyHasPicks) { - llOwnerSay("šŸŽÆ Starting picks for " + currentPlayerName); + dbg("šŸŽÆ Starting picks for " + currentPlayerName); llSleep(0.5); showNextPickerDialog(); } @@ -679,7 +687,7 @@ default { string playerName = llList2String(parts, 1); string picksStr = llList2String(parts, 2); - llOwnerSay("šŸ‘¤ HUMAN: " + playerName + " picking " + picksStr + " (global has: " + llList2CSV(globalPickedNumbers) + ")"); + dbg("šŸ‘¤ HUMAN: " + playerName + " picking " + picksStr + " (global has: " + llList2CSV(globalPickedNumbers) + ")"); // Check if this player already has picks to prevent duplicate processing integer alreadyHasPicks = FALSE; @@ -689,7 +697,7 @@ default { if (llSubStringIndex(llList2String(picksData, m), playerName + "|") == 0) { string existingPicks = llGetSubString(llList2String(picksData, m), llStringLength(playerName) + 1, -1); if (existingPicks != "") { - llOwnerSay("āš ļø [Game Manager] " + playerName + " already has picks: " + existingPicks + ", ignoring duplicate HUMAN_PICKED"); + dbg("āš ļø [Game Manager] " + playerName + " already has picks: " + existingPicks + ", ignoring duplicate HUMAN_PICKED"); alreadyHasPicks = TRUE; } } @@ -706,7 +714,7 @@ default { list duplicatePicks = []; integer i; - llOwnerSay("šŸ” [Game Manager] Validating " + playerName + "'s picks against complete avoid list (" + (string)llGetListLength(completeAvoidList) + " numbers): " + llList2CSV(completeAvoidList)); + dbg("šŸ” [Game Manager] Validating " + playerName + "'s picks against complete avoid list (" + (string)llGetListLength(completeAvoidList) + " numbers): " + llList2CSV(completeAvoidList)); for (i = 0; i < llGetListLength(newPicks); i++) { string pick = llStringTrim(llList2String(newPicks, i), STRING_TRIM); @@ -721,7 +729,7 @@ default { } if (llGetListLength(duplicatePicks) > 0) { - llOwnerSay("āŒ DUPLICATE PICKS REJECTED: " + playerName + " tried to pick: " + llList2CSV(duplicatePicks)); + dbg("āŒ DUPLICATE PICKS REJECTED: " + playerName + " tried to pick: " + llList2CSV(duplicatePicks)); integer idx = llListFindList(names, [playerName]); if (idx != -1) { llRegionSayTo(llList2Key(players, idx), 0, "āŒ Some picks were already taken. Please pick again."); @@ -736,7 +744,7 @@ default { } } // Re-show the dialog with updated globally picked numbers - llOwnerSay("āš ļø [Game Manager] Re-showing pick dialog for " + playerName + " with updated picks"); + dbg("āš ļø [Game Manager] Re-showing pick dialog for " + playerName + " with updated picks"); // Calculate picks needed based on peril player's lives integer perilIdx = llListFindList(names, [perilPlayer]); @@ -771,7 +779,7 @@ default { } else { picksData = llListReplaceList(picksData, [newEntry], picksIdx, picksIdx); } - llOwnerSay("🟢 " + playerName + " picks saved: " + picksStr); + dbg("🟢 " + playerName + " picks saved: " + picksStr); llSay(0, "šŸŽÆ " + playerName + " stakes their life on numbers: " + picksStr + " šŸŽ²"); @@ -797,19 +805,19 @@ default { currentPickerIdx++; if (currentPickerIdx < llGetListLength(pickQueue)) { - llOwnerSay("šŸ” [Game Manager] More players in queue, showing next dialog"); + dbg("šŸ” [Game Manager] More players in queue, showing next dialog"); showNextPickerDialog(); } else { // All picked, show roll dialog - llOwnerSay("šŸŽÆ [Game Manager] All players have picked! Showing roll dialog to " + perilPlayer); + dbg("šŸŽÆ [Game Manager] All players have picked! Showing roll dialog to " + perilPlayer); // CRITICAL: Sync the updated picks data to all modules before roll phase - llOwnerSay("šŸ”„ [Game Manager] Syncing final picks data before roll phase..."); + dbg("šŸ”„ [Game Manager] Syncing final picks data before roll phase..."); syncStateToMain(); llSleep(1.0); // Longer delay to ensure sync propagates to all modules // Send roll dialog through Player_RegistrationManager - llOwnerSay("šŸŽÆ [Game Manager] Sending roll dialog request for: " + perilPlayer); + dbg("šŸŽÆ [Game Manager] Sending roll dialog request for: " + perilPlayer); string rollRequest = "SHOW_ROLL_DIALOG|" + perilPlayer + "|" + perilPlayer; llMessageLinked(LINK_SET, MSG_DIALOG_FORWARD_REQUEST, rollRequest, NULL_KEY); } @@ -820,13 +828,13 @@ default { // Handle bot picks if (num == -9997 && llSubStringIndex(str, "BOT_PICKED:") == 0) { - llOwnerSay("šŸ” [Game Manager] BOT_PICKED message received: " + str); + dbg("šŸ” [Game Manager] BOT_PICKED message received: " + str); list parts = llParseString2List(str, [":"], []); if (llGetListLength(parts) >= 3) { string playerName = llList2String(parts, 1); string picksStr = llList2String(parts, 2); - llOwnerSay("šŸ¤– BOT: " + playerName + " picking " + picksStr + " (global had: " + llList2CSV(globalPickedNumbers) + ")"); + dbg("šŸ¤– BOT: " + playerName + " picking " + picksStr + " (global had: " + llList2CSV(globalPickedNumbers) + ")"); // Check if this bot has already made picks this round to prevent duplicates integer existingPicksIdx = -1; @@ -835,7 +843,7 @@ default { if (llSubStringIndex(llList2String(picksData, m), playerName + "|") == 0) { string existingPicks = llGetSubString(llList2String(picksData, m), llStringLength(playerName) + 1, -1); if (existingPicks != "") { - llOwnerSay("āš ļø [Game Manager] Ignoring duplicate BOT_PICKED for " + playerName + " (already has picks: " + existingPicks + ")"); + dbg("āš ļø [Game Manager] Ignoring duplicate BOT_PICKED for " + playerName + " (already has picks: " + existingPicks + ")"); // IMPORTANT: Even though this is a duplicate, check if all players have now picked // Count how many players have picks @@ -857,15 +865,15 @@ default { // If all players have picks, advance to roll phase if (playersWithPicks >= llGetListLength(names)) { - llOwnerSay("šŸŽÆ [Game Manager] All players have picks! Moving to roll phase..."); + dbg("šŸŽÆ [Game Manager] All players have picks! Moving to roll phase..."); // CRITICAL: Sync the updated picks data to all modules before roll phase - llOwnerSay("šŸ”„ [Game Manager] Syncing final picks data before roll phase..."); + dbg("šŸ”„ [Game Manager] Syncing final picks data before roll phase..."); syncStateToMain(); llSleep(1.0); // Longer delay to ensure sync propagates to all modules // Force close any active number picker dialogs - llOwnerSay("🚫 [Game Manager] Sending CLOSE_ALL_DIALOGS command"); + dbg("🚫 [Game Manager] Sending CLOSE_ALL_DIALOGS command"); llMessageLinked(LINK_SET, -9999, "CLOSE_ALL_DIALOGS", NULL_KEY); // Send roll dialog through Player_RegistrationManager @@ -881,8 +889,8 @@ default { // VALIDATE: Check for duplicate picks before saving if (picksStr != "" && llListFindList(globalPickedNumbers, [picksStr]) != -1) { - llOwnerSay("āŒ [Game Manager] Bot " + playerName + " tried to pick duplicate number: " + picksStr + " - REJECTING"); - llOwnerSay("šŸ™„ [Game Manager] Sending new pick command to Bot Manager for " + playerName); + dbg("āŒ [Game Manager] Bot " + playerName + " tried to pick duplicate number: " + picksStr + " - REJECTING"); + dbg("šŸ™„ [Game Manager] Sending new pick command to Bot Manager for " + playerName); // Calculate picks needed for bot retry integer perilIdx = llListFindList(names, [perilPlayer]); @@ -896,14 +904,14 @@ default { list completeAvoidList = buildCompleteAvoidanceList(); string avoidListStr = llList2CSV(completeAvoidList); string botCommand = "BOT_PICK:" + playerName + ":" + (string)picksNeeded + ":" + (string)diceType + ":" + avoidListStr; - llOwnerSay("šŸŽÆ [Game Manager] Sending retry bot command with complete avoid list (" + (string)llGetListLength(completeAvoidList) + " numbers): " + avoidListStr); + dbg("šŸŽÆ [Game Manager] Sending retry bot command with complete avoid list (" + (string)llGetListLength(completeAvoidList) + " numbers): " + avoidListStr); llMessageLinked(LINK_SET, -9999, botCommand, NULL_KEY); return; // Don't save this pick } // Update picks data integer idx = llListFindList(names, [playerName]); - llOwnerSay("šŸ”§ [Game Manager] Looking for bot " + playerName + " in names list: " + llList2CSV(names) + " (idx: " + (string)idx + ")"); + dbg("šŸ”§ [Game Manager] Looking for bot " + playerName + " in names list: " + llList2CSV(names) + " (idx: " + (string)idx + ")"); if (idx != -1) { integer picksIdx = -1; integer k; @@ -963,19 +971,19 @@ default { } } - llOwnerSay("šŸ” [Game Manager] Bot pick complete - players with picks: " + (string)playersWithPicks + "/" + (string)llGetListLength(names)); + dbg("šŸ” [Game Manager] Bot pick complete - players with picks: " + (string)playersWithPicks + "/" + (string)llGetListLength(names)); // If all players have picks, advance to roll phase if (playersWithPicks >= llGetListLength(names)) { - llOwnerSay("šŸŽÆ [Game Manager] All players have picks! Moving to roll phase..."); + dbg("šŸŽÆ [Game Manager] All players have picks! Moving to roll phase..."); // CRITICAL: Sync the updated picks data to all modules before roll phase - llOwnerSay("šŸ”„ [Game Manager] Syncing final picks data before roll phase..."); + dbg("šŸ”„ [Game Manager] Syncing final picks data before roll phase..."); syncStateToMain(); llSleep(0.2); // Brief delay to ensure sync propagates // Force close any active number picker dialogs - llOwnerSay("🚫 [Game Manager] Sending CLOSE_ALL_DIALOGS command"); + dbg("🚫 [Game Manager] Sending CLOSE_ALL_DIALOGS command"); llMessageLinked(LINK_SET, -9999, "CLOSE_ALL_DIALOGS", NULL_KEY); // Send roll dialog through Player_RegistrationManager @@ -995,12 +1003,12 @@ default { // Handle continue round requests from Main Controller if (num == MSG_CONTINUE_ROUND) { - llOwnerSay("šŸŽÆ [Game Manager] Received continue round request with peril player: '" + str + "'"); + dbg("šŸŽÆ [Game Manager] Received continue round request with peril player: '" + str + "'"); // Update peril player from the continue message if provided if (str != "" && str != "NONE") { perilPlayer = str; - llOwnerSay("šŸŽÆ [Game Manager] Updated peril player to: " + perilPlayer); + dbg("šŸŽÆ [Game Manager] Updated peril player to: " + perilPlayer); // Reset round state and continue with existing peril player roundStarted = FALSE; @@ -1012,7 +1020,7 @@ default { continueCurrentRound(); } else { // Empty peril player means this is initial game start - use startNextRound() - llOwnerSay("šŸŽÆ [Game Manager] Empty peril player - starting initial game round"); + dbg("šŸŽÆ [Game Manager] Empty peril player - starting initial game round"); // Reset round state roundStarted = FALSE; @@ -1030,11 +1038,13 @@ default { if (num == 9011 && llSubStringIndex(str, "VERBOSE_LOGGING|") == 0) { list parts = llParseString2List(str, ["|"], []); if (llGetListLength(parts) >= 2) { + #if DEBUG_LOGS VERBOSE_LOGGING = (integer)llList2String(parts, 1); +#endif if (VERBOSE_LOGGING) { - llOwnerSay("šŸ” [Game Manager] Verbose logging ON"); + dbg("šŸ” [Game Manager] Verbose logging ON"); } else { - llOwnerSay("šŸ” [Game Manager] Verbose logging OFF"); + dbg("šŸ” [Game Manager] Verbose logging OFF"); } } return; @@ -1051,13 +1061,13 @@ default { diceTypeProcessed = FALSE; // Reset for new game roundContinueInProgress = FALSE; // Reset protection flag lastSyncProcessTime = 0; // Reset sync timing - llOwnerSay("šŸŽÆ Game Manager reset - ready for new game!"); + dbg("šŸŽÆ Game Manager reset - ready for new game!"); return; } // Handle emergency state reset (for when game gets stuck) if (num == -99998 && str == "EMERGENCY_RESET") { - llOwnerSay("🚨 [Game Manager] Emergency reset triggered!"); + dbg("🚨 [Game Manager] Emergency reset triggered!"); roundStarted = FALSE; perilPlayer = ""; currentPickerIdx = 0; @@ -1065,7 +1075,7 @@ default { diceTypeProcessed = FALSE; roundContinueInProgress = FALSE; lastSyncProcessTime = 0; // Reset sync timing - llOwnerSay("šŸ”’ [Game Manager] Emergency state reset complete"); + dbg("šŸ”’ [Game Manager] Emergency state reset complete"); return; } } diff --git a/Game_Scoreboard_Manager_Linkset.lsl b/Game_Scoreboard_Manager_Linkset.lsl index 52ac584..8066944 100644 --- a/Game_Scoreboard_Manager_Linkset.lsl +++ b/Game_Scoreboard_Manager_Linkset.lsl @@ -7,7 +7,15 @@ // ============================================================================= // Verbose logging control -integer VERBOSE_LOGGING = FALSE; // Global flag for verbose debug logs - DISABLED to save memory +#define DEBUG_LOGS 0 // Set to 1 to enable, 0 to STRIP all logs from memory + +#if DEBUG_LOGS + #define dbg(msg) llOwnerSay(msg) + integer VERBOSE_LOGGING = FALSE; +#else + #define dbg(msg) + #define VERBOSE_LOGGING 0 +#endif #define MSG_TOGGLE_VERBOSE_LOGS 9998 // Message to toggle verbose logging // Message constants for link communication @@ -919,7 +927,11 @@ updatePlayerDisplay(string playerName, integer lives, string profileUUID) { } default { + on_rez(integer start_param) { + llResetScript(); // Fixes Z-fighting and alignment glitches on rez + } state_entry() { + llListen(1, "", llGetOwner(), ""); // Listen on channel 1 for local owner testing commands reportMemoryUsage("Scoreboard Manager"); if (VERBOSE_LOGGING) { llOwnerSay("šŸ“ˆ Scoreboard Manager ready! (Linkset Version)"); @@ -938,6 +950,8 @@ default { // Load persistent leaderboard data from KVP Experience database loadLeaderboardData(); + // Set a timer to passively auto-refresh the global scoreboard every 5 minutes + llSetTimerEvent(300.0); // NOTE: generateLeaderboardText() will be triggered by dataserver automatically when data arrives // No need to generate it randomly before data arrives @@ -954,6 +968,7 @@ default { link_message(integer sender, integer num, string str, key id) { // Handle verbose logging toggle +#if DEBUG_LOGS if (num == MSG_TOGGLE_VERBOSE_LOGS) { VERBOSE_LOGGING = !VERBOSE_LOGGING; if (VERBOSE_LOGGING) { @@ -963,6 +978,7 @@ default { } return; } +#endif // Only listen to messages from the main controller (link 1) if (sender != 1) return; @@ -1124,7 +1140,7 @@ default { string status = llGetSubString(data, 0, comma - 1); string val = llGetSubString(data, comma + 1, -1); - if (status == "0") { + if (status == "1") { leaderboardNames = []; leaderboardWins = []; leaderboardLosses = []; @@ -1165,7 +1181,7 @@ default { if (status == "3") { // Update failed because key didn't exist yet! Create it. llCreateKeyValue("Peril_LB_Top50", pendingSerialize); - } else if (status == "0") { + } else if (status == "1") { if (VERBOSE_LOGGING) { llOwnerSay("āœ… Global scoreboard synced successfully."); } @@ -1183,4 +1199,32 @@ default { llOwnerSay(" HTTP requests pending: " + (string)(llGetListLength(httpRequests) / 2)); } } + + timer() { + if (VERBOSE_LOGGING) { + llOwnerSay("ā±ļø Auto-refreshing Global Scoreboard Data..."); + } + loadLeaderboardData(); + } + + listen(integer channel, string name, key id, string message) { + string msg = llToLower(llStringTrim(message, STRING_TRIM)); + if (msg == "testx") { + llOwnerSay("Testing X overlays on all 10 player slots..."); + integer i; + for (i = 0; i < 10; i++) { + integer overlayIdx = getOverlayPrimLink(i); + if (overlayIdx >= FIRST_OVERLAY_PRIM && overlayIdx <= LAST_OVERLAY_PRIM) { + llSetLinkPrimitiveParamsFast(overlayIdx, [ + PRIM_TEXTURE, ALL_SIDES, TEXTURE_ELIMINATED_X, <1,1,0>, <0,0,0>, 0.0, + PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 1.0>, 1.0 + ]); + } + } + } + else if (msg == "clearx") { + llOwnerSay("Refreshing display to clear test X overlays..."); + refreshPlayerDisplay(); + } + } } diff --git a/Leaderboard_Communication_Linkset.lsl b/Leaderboard_Communication_Linkset.lsl index f137fe5..b1c1ac0 100644 --- a/Leaderboard_Communication_Linkset.lsl +++ b/Leaderboard_Communication_Linkset.lsl @@ -115,6 +115,9 @@ distributeToBank(string text, list linkNumbers) { } default { + on_rez(integer start_param) { + llResetScript(); // Fixes Z-fighting and alignment glitches on rez + } state_entry() { if (VERBOSE_LOGGING) { llOwnerSay("šŸ“‹ Leaderboard Communication Script ready! (Linkset Version)"); diff --git a/Main_Controller_Linkset.lsl b/Main_Controller_Linkset.lsl index 65bfdd2..5f8f079 100644 --- a/Main_Controller_Linkset.lsl +++ b/Main_Controller_Linkset.lsl @@ -19,6 +19,13 @@ string getPlayerName(key id) { // LINKSET COMMUNICATION CONSTANTS // ============================================================================= +#define DEBUG_LOGS 0 // Set to 1 to enable logs, 0 to STRIP them from bytecode and recover memory +#if DEBUG_LOGS +#define dbg(msg) dbg(msg) +#else +#define dbg(msg) +#endif + // Target link numbers (UPDATED after overlay prim insertion) #define SCOREBOARD_LINK 12 // Scoreboard manager cube #define LEADERBOARD_LINK 35 // Leaderboard manager (first XyzzyText prim) @@ -343,7 +350,7 @@ resetGame() { llMessageLinked(SCOREBOARD_LINK, MSG_UPDATE_WINNER, "", NULL_KEY); // Clear winner glow llMessageLinked(DICE_LINK, MSG_CLEAR_DICE, "", NULL_KEY); - llOwnerSay("šŸŽ® Game reset! All state cleared (including scoreboard)."); + dbg("šŸŽ® Game reset! All state cleared (including scoreboard)."); statusTimer = 0; lastStatus = ""; @@ -365,7 +372,7 @@ resetGame() { default { state_entry() { reportMemoryUsage("Main Controller"); - llOwnerSay("šŸŽ® Main Controller ready! (Linkset Version)"); + dbg("šŸŽ® Main Controller ready! (Linkset Version)"); // Initialize lockout system gameOwner = llGetOwner(); @@ -377,12 +384,12 @@ default { // Reset the game on startup to ensure clean state resetGame(); - llOwnerSay("āœ… Main Controller initialization complete!"); + dbg("āœ… Main Controller initialization complete!"); } on_rez(integer start_param) { reportMemoryUsage("Main Controller"); - llOwnerSay("šŸ”„ Main Controller rezzed - resetting game state..."); + dbg("šŸ”„ Main Controller rezzed - resetting game state..."); // Re-initialize lockout system gameOwner = llGetOwner(); @@ -394,7 +401,7 @@ default { // Reset the game to ensure clean state when rezzed resetGame(); - llOwnerSay("āœ… Main Controller reset complete after rez!"); + dbg("āœ… Main Controller reset complete after rez!"); } touch_start(integer total_number) { @@ -475,11 +482,11 @@ default { } if (toucher == llGetOwner()) { - llOwnerSay("šŸ” [DEBUG] Owner touched - idx: " + (string)idx + ", players list: " + llList2CSV(players)); + dbg("šŸ” [DEBUG] Owner touched - idx: " + (string)idx + ", players list: " + llList2CSV(players)); if (idx == -1) { // Owner is not in game - show join/admin choice if (llListFindList(pendingRegistrations, [toucher]) != -1) { - llOwnerSay("ā³ Registration already in progress for " + getPlayerName(toucher)); + dbg("ā³ Registration already in progress for " + getPlayerName(toucher)); return; } @@ -521,7 +528,7 @@ default { string playerName = getPlayerName(toucher); if (playerName != "") { if (llListFindList(pendingRegistrations, [toucher]) != -1) { - llOwnerSay("ā³ Registration already in progress for " + playerName); + dbg("ā³ Registration already in progress for " + playerName); return; } @@ -538,7 +545,7 @@ default { } llMessageLinked(LINK_SET, MSG_SHOW_MENU, "player|" + (string)isStarter, toucher); } else { - llOwnerSay("āš ļø Could not get name for toucher: " + (string)toucher); + dbg("āš ļø Could not get name for toucher: " + (string)toucher); } } } @@ -567,8 +574,8 @@ default { integer existingPlayerIdx = llListFindList(players, [id]); if (existingPlayerIdx != -1) { - llOwnerSay("āš ļø [Main Controller] DUPLICATE PLAYER KEY DETECTED - Player: " + newName + " (" + (string)id + ") already exists!"); - llOwnerSay("āš ļø [Main Controller] Players list length: " + (string)llGetListLength(players) + ", Names list length: " + (string)llGetListLength(names)); + dbg("āš ļø [Main Controller] DUPLICATE PLAYER KEY DETECTED - Player: " + newName + " (" + (string)id + ") already exists!"); + dbg("āš ļø [Main Controller] Players list length: " + (string)llGetListLength(players) + ", Names list length: " + (string)llGetListLength(names)); return; // Skip adding duplicate } @@ -585,8 +592,8 @@ default { } // That's it! Player_RegistrationManager already sent sync and scoreboard updates - llOwnerSay("āœ… Player added to master lists: " + newName + " (" + (string)llGetFreeMemory() + " bytes free)"); - llOwnerSay("šŸ” [DEBUG] Updated lists - Players: " + (string)llGetListLength(players) + ", Names: " + (string)llGetListLength(names)); + dbg("āœ… Player added to master lists: " + newName + " (" + (string)llGetFreeMemory() + " bytes free)"); + dbg("šŸ” [DEBUG] Updated lists - Players: " + (string)llGetListLength(players) + ", Names: " + (string)llGetListLength(names)); } return; } @@ -625,7 +632,7 @@ default { // SEND WINNER GLOW to scoreboard and trigger floater update llMessageLinked(SCOREBOARD_LINK, MSG_UPDATE_WINNER, potentialWinner, NULL_KEY); llMessageLinked(LINK_SET, MSG_UPDATE_FLOAT, potentialWinner, NULL_KEY); // Update winner's floater - llOwnerSay("šŸ† [Main Controller] Pre-victory winner glow sent for: " + potentialWinner); + dbg("šŸ† [Main Controller] Pre-victory winner glow sent for: " + potentialWinner); } } @@ -718,7 +725,7 @@ default { // ENHANCED: Give eliminated player's floater time to show eliminated status // before declaring victory and cleaning up - llOwnerSay("ā³ [Main Controller] Final elimination detected - allowing display time before victory"); + dbg("ā³ [Main Controller] Final elimination detected - allowing display time before victory"); llSleep(2.0); // Give final eliminated player time to show red eliminated status // CRITICAL: Set victory flag immediately to prevent sync processing @@ -750,7 +757,7 @@ default { llMessageLinked(SCOREBOARD_LINK, MSG_GAME_WON, winner, NULL_KEY); // Use timer instead of llSleep to avoid immediate reset - llOwnerSay("šŸ† [Main Controller] Winner glow applied - starting victory delay timer"); + dbg("šŸ† [Main Controller] Winner glow applied - starting victory delay timer"); victoryDelayTimer = llGetUnixTime(); currentTimerMode = TIMER_VICTORY_DELAY; llSetTimerEvent(1.0); // Check every second @@ -800,7 +807,7 @@ default { // Handle emergency reset for stuck games if (num == -99998 && str == "EMERGENCY_RESET") { - llOwnerSay("🚨 [Main Controller] Emergency reset triggered - sending emergency reset to all scripts"); + dbg("🚨 [Main Controller] Emergency reset triggered - sending emergency reset to all scripts"); // Signal all scripts to emergency reset llMessageLinked(LINK_SET, -99998, "EMERGENCY_RESET", NULL_KEY); llSleep(0.5); @@ -857,7 +864,7 @@ default { integer idx = llListFindList(names, [playerName]); if (idx != -1) { if (llSubStringIndex(playerName, "Bot") == 0) { - llOwnerSay("šŸ¤– Bots are always ready and cannot change state"); + dbg("šŸ¤– Bots are always ready and cannot change state"); return; } @@ -971,12 +978,12 @@ default { } if (newPerilPlayer != "") { - llOwnerSay("šŸŽÆ [Main Controller] Peril player left - assigning new peril player: " + newPerilPlayer); + dbg("šŸŽÆ [Main Controller] Peril player left - assigning new peril player: " + newPerilPlayer); perilPlayer = newPerilPlayer; // Send peril player update to scoreboard for glow effect llMessageLinked(SCOREBOARD_LINK, 3005, newPerilPlayer, NULL_KEY); // MSG_UPDATE_PERIL_PLAYER } else { - llOwnerSay("āš ļø [Main Controller] No valid peril player candidates found after player left!"); + dbg("āš ļø [Main Controller] No valid peril player candidates found after player left!"); perilPlayer = "NONE"; // Clear peril player glow on scoreboard llMessageLinked(SCOREBOARD_LINK, MSG_UPDATE_PERIL_PLAYER, "", NULL_KEY); @@ -1006,7 +1013,7 @@ default { // Check if we should reset the game (no players left) if (llGetListLength(names) == 0) { - llOwnerSay("šŸ”„ [Main Controller] All players left - resetting game"); + dbg("šŸ”„ [Main Controller] All players left - resetting game"); // Force clear any remaining game state before reset roundStarted = FALSE; gameStarting = FALSE; @@ -1018,7 +1025,7 @@ default { // Skip updateHelpers to prevent memory crashes during player removal // Scoreboard was already updated with MSG_REMOVE_PLAYER above - llOwnerSay("āœ… [Main Controller] Synchronized removal of " + leavingName); + dbg("āœ… [Main Controller] Synchronized removal of " + leavingName); } } return; @@ -1029,7 +1036,7 @@ default { if (id == gameOwner && str == "LOCK_GAME") { isLocked = TRUE; updateFloatingText(); - llOwnerSay("šŸ”’ [Main Controller] Game has been LOCKED - Floating text updated"); + dbg("šŸ”’ [Main Controller] Game has been LOCKED - Floating text updated"); } return; } @@ -1038,7 +1045,7 @@ default { if (id == gameOwner && str == "UNLOCK_GAME") { isLocked = FALSE; updateFloatingText(); - llOwnerSay("šŸ”“ [Main Controller] Game has been UNLOCKED - Floating text updated"); + dbg("šŸ”“ [Main Controller] Game has been UNLOCKED - Floating text updated"); } return; } @@ -1059,13 +1066,13 @@ default { // Handle memory monitor messages if (num == MSG_EMERGENCY_CLEANUP) { // Removed emergencyMemoryCleanup call to save memory - llOwnerSay("Emergency cleanup disabled to prevent crashes"); + dbg("Emergency cleanup disabled to prevent crashes"); return; } // Handle reset requests from other scripts (like Game_Manager) if (num == -99998 && str == "REQUEST_GAME_RESET") { - llOwnerSay("šŸ”„ [Main Controller] Reset requested by " + (string)sender + ", executing..."); + dbg("šŸ”„ [Main Controller] Reset requested by " + (string)sender + ", executing..."); resetGame(); return; } @@ -1076,7 +1083,7 @@ default { if (channel == rollDialogChannel) { if (msg == "Start Next Round" || msg == "BEGIN KILLING GAME") { if (roundStarted) { - llOwnerSay("āš ļø Round already in progress, ignoring duplicate round start from roll dialog"); + dbg("āš ļø Round already in progress, ignoring duplicate round start from roll dialog"); return; } @@ -1124,23 +1131,23 @@ default { if (msg == "Reset Leaderboard") { // CHANGED: Send to scoreboard, which will handle leaderboard reset llMessageLinked(SCOREBOARD_LINK, MSG_RESET_LEADERBOARD, "", NULL_KEY); - llOwnerSay("šŸ† Leaderboard scores reset - game wins cleared!"); + dbg("šŸ† Leaderboard scores reset - game wins cleared!"); return; } if (msg == "Reset All") { resetGame(); llMessageLinked(SCOREBOARD_LINK, MSG_RESET_LEADERBOARD, "", NULL_KEY); - llOwnerSay("šŸ”„ Complete reset - game and leaderboard cleared!"); + dbg("šŸ”„ Complete reset - game and leaderboard cleared!"); return; } if (msg == "Memory Stats") { // Removed reportMemoryStats call to save memory - llOwnerSay("Memory stats reporting disabled to prevent crashes"); + dbg("Memory stats reporting disabled to prevent crashes"); return; } if (msg == "Add Test Player") { if (llGetListLength(players) >= MAX_PLAYERS) { - llOwnerSay("āš ļø Cannot add test player; the game is full (max " + (string)MAX_PLAYERS + ")."); + dbg("āš ļø Cannot add test player; the game is full (max " + (string)MAX_PLAYERS + ")."); return; } @@ -1161,11 +1168,11 @@ default { // Don't show menu immediately - let the player touch the board again // This avoids timing issues where the menu is shown before registration completes - llOwnerSay("āœ… " + testName + " registration sent - touch the board again to refresh menu"); + dbg("āœ… " + testName + " registration sent - touch the board again to refresh menu"); return; } if (msg == "Force Floaters") { - llOwnerSay("šŸ”§ Forcing floater creation for all " + (string)llGetListLength(names) + " players..."); + dbg("šŸ”§ Forcing floater creation for all " + (string)llGetListLength(names) + " players..."); integer i; for (i = 0; i < llGetListLength(names); i++) { string playerName = llList2String(names, i); @@ -1173,7 +1180,7 @@ default { llMessageLinked(LINK_SET, MSG_REZ_FLOAT, playerName, playerKey); llSleep(0.3); } - llOwnerSay("āœ… Floater creation requests sent for all players!"); + dbg("āœ… Floater creation requests sent for all players!"); // After forcing floaters, show appropriate menu based on owner registration status integer ownerIdx = llListFindList(players, [llGetOwner()]); @@ -1205,7 +1212,7 @@ default { integer playerCount = llGetListLength(players); integer nameCount = llGetListLength(names); if (playerCount < 2) { - llOwnerSay("āš ļø Need at least 2 players to start the game."); + dbg("āš ļø Need at least 2 players to start the game."); return; } @@ -1220,7 +1227,7 @@ default { } if (starterName == "") { - llOwnerSay("āš ļø Only the game starter can start the game."); + dbg("āš ļø Only the game starter can start the game."); return; } @@ -1236,7 +1243,7 @@ default { } if (llGetListLength(notReadyPlayers) > 0) { - llOwnerSay("āš ļø Cannot start game. These players are not ready: " + llList2CSV(notReadyPlayers)); + dbg("āš ļø Cannot start game. These players are not ready: " + llList2CSV(notReadyPlayers)); return; } @@ -1269,7 +1276,7 @@ default { lastStatus = ""; // CHANGED: Use link message instead of llRegionSay llMessageLinked(SCOREBOARD_LINK, MSG_GAME_STATUS, "Title", NULL_KEY); - llOwnerSay("šŸ“¢ Status cleared - reverted to Title"); + dbg("šŸ“¢ Status cleared - reverted to Title"); currentTimerMode = TIMER_IDLE; llSetTimerEvent(0); } @@ -1278,7 +1285,7 @@ default { if (victoryDelayTimer > 0) { integer elapsed = llGetUnixTime() - victoryDelayTimer; if (elapsed >= (integer)(STATUS_DISPLAY_TIME * 3.0)) { // 24 seconds - llOwnerSay("šŸ† [Main Controller] Victory display time complete - executing game reset"); + dbg("šŸ† [Main Controller] Victory display time complete - executing game reset"); victoryDelayTimer = 0; currentTimerMode = TIMER_IDLE; llSetTimerEvent(0); diff --git a/Player_DialogHandler.lsl b/Player_DialogHandler.lsl index 2cecc1a..c4d8eff 100644 --- a/Player_DialogHandler.lsl +++ b/Player_DialogHandler.lsl @@ -1,3 +1,10 @@ +#define DEBUG_LOGS 0 // Set to 1 to enable logs, 0 to STRIP from memory completely +#if DEBUG_LOGS +#define dbg(msg) dbg(msg) +#else +#define dbg(msg) +#endif + // === Dialog Handler (Owner & Player) with unified Ready/Leave menu and join support === // Helper function to get display name with fallback to username @@ -51,11 +58,11 @@ initializeChannels() { DICE_DATA_CHANNEL = calculateChannel(8); // ~-85000 range // Report channel to owner for debugging - llOwnerSay("šŸ”§ [Owner/Player Dialog] Dynamic channels initialized:"); - llOwnerSay(" Main Dialog: " + (string)MAIN_DIALOG_CHANNEL); - llOwnerSay(" Scoreboard: " + (string)SCOREBOARD_DATA_CHANNEL); - llOwnerSay(" Leaderboard: " + (string)LEADERBOARD_DATA_CHANNEL); - llOwnerSay(" Dice: " + (string)DICE_DATA_CHANNEL); + dbg("šŸ”§ [Owner/Player Dialog] Dynamic channels initialized:"); + dbg(" Main Dialog: " + (string)MAIN_DIALOG_CHANNEL); + dbg(" Scoreboard: " + (string)SCOREBOARD_DATA_CHANNEL); + dbg(" Leaderboard: " + (string)LEADERBOARD_DATA_CHANNEL); + dbg(" Dice: " + (string)DICE_DATA_CHANNEL); } integer DIALOG_CHANNEL; // Legacy variable, will be set dynamically @@ -165,7 +172,7 @@ showTroubleshootingMenu(key id) { showReadyLeaveMenu(key id, integer isStarter, integer isOwner) { // Check for timeout of previous request if (pendingMenuPlayer != NULL_KEY && (llGetTime() - pendingMenuTimestamp) > MENU_REQUEST_TIMEOUT) { - llOwnerSay("ā° Previous menu request timed out, clearing pending state"); + dbg("ā° Previous menu request timed out, clearing pending state"); pendingMenuPlayer = NULL_KEY; } @@ -176,7 +183,7 @@ showReadyLeaveMenu(key id, integer isStarter, integer isOwner) { // If there's a pending request for a different player, warn about it but proceed if (pendingMenuPlayer != NULL_KEY && pendingMenuPlayer != id) { - llOwnerSay("āš ļø [Debug] Overriding pending request for " + (string)pendingMenuPlayer + " with new request for " + (string)id); + dbg("āš ļø [Debug] Overriding pending request for " + (string)pendingMenuPlayer + " with new request for " + (string)id); } pendingMenuPlayer = id; @@ -291,7 +298,7 @@ showKickPlayerMenu(key id, list playerNames) { string buttonLabel = "šŸ‘¢ " + kickDisplayName; // Debug: Check button length - llOwnerSay("šŸ” Debug kick button: '" + buttonLabel + "' = " + (string)llStringLength(buttonLabel) + " chars"); + dbg("šŸ” Debug kick button: '" + buttonLabel + "' = " + (string)llStringLength(buttonLabel) + " chars"); kickOptions += [buttonLabel]; kickDisplayNames += [buttonLabel]; // Store the full button label @@ -363,14 +370,14 @@ default { leaderboardHandle = llListen(LEADERBOARD_DATA_CHANNEL, "", "", ""); diceHandle = llListen(DICE_DATA_CHANNEL, "", "", ""); - llOwnerSay("šŸŽ­ Owner and Player Dialog Handler ready with lockout system!"); - llOwnerSay("šŸ”“ Game is UNLOCKED - All players can access menus"); + dbg("šŸŽ­ Owner and Player Dialog Handler ready with lockout system!"); + dbg("šŸ”“ Game is UNLOCKED - All players can access menus"); } on_rez(integer start_param) { reportMemoryUsage("šŸŽ­ Player Dialog"); - llOwnerSay("šŸ”„ Player Dialog Handler rezzed - reinitializing..."); + dbg("šŸ”„ Player Dialog Handler rezzed - reinitializing..."); // Re-initialize dynamic channels initializeChannels(); @@ -408,7 +415,7 @@ default { leaderboardHandle = llListen(LEADERBOARD_DATA_CHANNEL, "", "", ""); diceHandle = llListen(DICE_DATA_CHANNEL, "", "", ""); - llOwnerSay("āœ… Player Dialog Handler reset complete after rez!"); + dbg("āœ… Player Dialog Handler reset complete after rez!"); } link_message(integer sender, integer num, string str, key id) { @@ -424,14 +431,14 @@ default { currentPickList = []; currentPickTarget = ""; currentPickLimit = 3; - llOwnerSay("šŸŽ­ Owner and Player Dialog Handler reset!"); + dbg("šŸŽ­ Owner and Player Dialog Handler reset!"); return; } if (num == MSG_SHOW_MENU) { list args = llParseString2List(str, ["|"], []); if (llGetListLength(args) < 2) { - llOwnerSay("āš ļø Invalid message format: " + str); + dbg("āš ļø Invalid message format: " + str); return; } string targetType = llList2String(args, 0); @@ -468,7 +475,7 @@ default { if (pendingMenuPlayer == id && responseRequestID == pendingMenuRequestID) { // Check for timeout if ((llGetTime() - pendingMenuTimestamp) > MENU_REQUEST_TIMEOUT) { - llOwnerSay("ā° Menu request timed out, ignoring response"); + dbg("ā° Menu request timed out, ignoring response"); pendingMenuPlayer = NULL_KEY; return; } @@ -479,20 +486,20 @@ default { pendingMenuRequestID = 0; } } else { - llOwnerSay("āš ļø Invalid ready state result format - expected 4 parts, got " + (string)llGetListLength(parts)); + dbg("āš ļø Invalid ready state result format - expected 4 parts, got " + (string)llGetListLength(parts)); } return; } else if (num == MSG_PLAYER_LIST_RESULT) { list playerNames = llParseString2List(str, [","], []); - llOwnerSay("šŸ“‹ Fetching list of players for pick management..."); + dbg("šŸ“‹ Fetching list of players for pick management..."); showPickManageMenu(id, playerNames); } // Handle player list result for kick functionality else if (num == 8009) { - llOwnerSay("šŸ” [Dialog Handler] Received kick player list string: '" + str + "'"); + dbg("šŸ” [Dialog Handler] Received kick player list string: '" + str + "'"); list rawNames = llParseString2List(str, [","], []); - llOwnerSay("šŸ” [Dialog Handler] Raw parsed into " + (string)llGetListLength(rawNames) + " names: " + llList2CSV(rawNames)); + dbg("šŸ” [Dialog Handler] Raw parsed into " + (string)llGetListLength(rawNames) + " names: " + llList2CSV(rawNames)); // Filter out any command strings that might have gotten mixed in list playerNames = []; @@ -506,11 +513,11 @@ default { llSubStringIndex(name, "MSG_") != 0) { playerNames += [name]; } else { - llOwnerSay("āš ļø [Dialog Handler] Filtered out invalid name: '" + name + "'"); + dbg("āš ļø [Dialog Handler] Filtered out invalid name: '" + name + "'"); } } - llOwnerSay("šŸ” [Dialog Handler] Filtered to " + (string)llGetListLength(playerNames) + " valid names: " + llList2CSV(playerNames)); + dbg("šŸ” [Dialog Handler] Filtered to " + (string)llGetListLength(playerNames) + " valid names: " + llList2CSV(playerNames)); showKickPlayerMenu(id, playerNames); } else if (num == MSG_PICK_LIST_RESULT) { @@ -518,11 +525,11 @@ default { string returnedName = llList2String(parts, 0); string picks = llList2String(parts, 1); if (llStringTrim(returnedName, STRING_TRIM) == llStringTrim(currentPickTarget, STRING_TRIM)) { - llOwnerSay("āœ… Matched pick list for: " + returnedName); + dbg("āœ… Matched pick list for: " + returnedName); currentPickList = llCSV2List(picks); llMessageLinked(LINK_THIS, MSG_LIFE_LOOKUP, currentPickTarget, id); } else { - llOwnerSay("āŒ Name mismatch: got " + returnedName + " but expected " + currentPickTarget); + dbg("āŒ Name mismatch: got " + returnedName + " but expected " + currentPickTarget); } } else if (num == MSG_LIFE_LOOKUP) { @@ -546,7 +553,7 @@ default { if (pendingMenuPlayer == id && responseRequestID == pendingMenuRequestID) { // Check for timeout if ((llGetTime() - pendingMenuTimestamp) > MENU_REQUEST_TIMEOUT) { - llOwnerSay("ā° Owner status query timed out, ignoring response"); + dbg("ā° Owner status query timed out, ignoring response"); pendingMenuPlayer = NULL_KEY; return; } @@ -554,13 +561,13 @@ default { // Decide which menu to show based on registration status if (isRegistered) { // Owner is registered - show ready/leave menu with Owner button - llOwnerSay("šŸ” [Debug] Owner is registered, isStarter=" + (string)isStarter + ", showing ready/leave menu"); - llOwnerSay("šŸ” [Debug] About to call showReadyLeaveMenu with id=" + (string)id + ", isStarter=" + (string)isStarter + ", isOwner=TRUE"); + dbg("šŸ” [Debug] Owner is registered, isStarter=" + (string)isStarter + ", showing ready/leave menu"); + dbg("šŸ” [Debug] About to call showReadyLeaveMenu with id=" + (string)id + ", isStarter=" + (string)isStarter + ", isOwner=TRUE"); // DON'T reset pending state here - showReadyLeaveMenu needs it! // The ready state handler will reset it when the dialog is shown showReadyLeaveMenu(id, isStarter, TRUE); - llOwnerSay("šŸ” [Debug] showReadyLeaveMenu call completed"); + dbg("šŸ” [Debug] showReadyLeaveMenu call completed"); } else if (isPending) { llRegionSayTo(id, 0, "ā³ Registration already in progress for " + ownerName); // Reset pending state for non-registered responses @@ -576,10 +583,10 @@ default { pendingMenuRequestID = 0; } } else { - llOwnerSay("āš ļø Owner status response mismatch - ignoring"); + dbg("āš ļø Owner status response mismatch - ignoring"); } } else { - llOwnerSay("āš ļø Invalid owner status result format - expected 5 parts, got " + (string)llGetListLength(parts)); + dbg("āš ļø Invalid owner status result format - expected 5 parts, got " + (string)llGetListLength(parts)); } return; } @@ -603,7 +610,7 @@ default { isLocked = TRUE; // Notify Main Controller to update floating text llMessageLinked(LINK_SET, 9001, "LOCK_GAME", id); - llOwnerSay("šŸ”’ Game has been LOCKED - Only owner can access any features"); + dbg("šŸ”’ Game has been LOCKED - Only owner can access any features"); llSay(0, "šŸ”’ Game has been locked by the owner. Only the owner can access any features."); showOwnerMenu(id); // Refresh the owner menu } else { @@ -615,7 +622,7 @@ default { isLocked = FALSE; // Notify Main Controller to update floating text llMessageLinked(LINK_SET, 9002, "UNLOCK_GAME", id); - llOwnerSay("šŸ”“ Game has been UNLOCKED - All players can access menus"); + dbg("šŸ”“ Game has been UNLOCKED - All players can access menus"); llSay(0, "šŸ”“ Game has been unlocked by the owner. All features are now available."); showOwnerMenu(id); // Refresh the owner menu } else { @@ -676,25 +683,25 @@ default { } else if (msg == "Cleanup Floaters") { // Universal floater cleanup that works even after script resets - llOwnerSay("🧩 Force cleaning ALL possible floater channels..."); + dbg("🧩 Force cleaning ALL possible floater channels..."); llMessageLinked(LINK_SET, MSG_CLEANUP_ALL_FLOATERS, "", NULL_KEY); } else if (msg == "Force Floaters") { // Force creation of floaters for all registered players - send as dialog response to Main Controller - llOwnerSay("šŸ”§ Requesting floater creation for all registered players..."); + dbg("šŸ”§ Requesting floater creation for all registered players..."); // This will be handled by Main Controller's dialog listener // No need to forward via link_message - the Main Controller is already listening on DIALOG_CHANNEL } else if (msg == "šŸ” Toggle Verbose Logs") { // Toggle verbose logging system-wide - llOwnerSay("šŸ” Toggling verbose logging system-wide..."); + dbg("šŸ” Toggling verbose logging system-wide..."); llMessageLinked(LINK_SET, 9010, "TOGGLE_VERBOSE_LOGS", id); // Return to troubleshooting menu after toggling showTroubleshootingMenu(id); } else if (msg == "šŸ”„ Check for Updates") { // Trigger update check via Update_Receiver script - llOwnerSay("šŸ”„ Checking GitHub for Peril Dice updates..."); + dbg("šŸ”„ Checking GitHub for Peril Dice updates..."); llMessageLinked(LINK_SET, 2100, "CHECK_UPDATES_REQUEST", id); // Return to troubleshooting menu showTroubleshootingMenu(id); @@ -704,7 +711,7 @@ default { } else if (llSubStringIndex(msg, "šŸ›  ") == 0) { currentPickTarget = llStringTrim(llDeleteSubString(msg, 0, 1), STRING_TRIM); - llOwnerSay("šŸŽÆ Pick target set to: " + currentPickTarget); + dbg("šŸŽÆ Pick target set to: " + currentPickTarget); currentPickList = []; llMessageLinked(LINK_THIS, 206, currentPickTarget, id); } @@ -731,7 +738,7 @@ default { // Send kick message to Controller_MessageHandler (not sync channel 107!) llMessageLinked(LINK_SET, 8007, "KICK_PLAYER|" + playerToKick + "|" + (string)id, NULL_KEY); } else { - llOwnerSay("āš ļø Could not find original name for kick selection: " + msg); + dbg("āš ļø Could not find original name for kick selection: " + msg); } // Return to player management menu showPlayerManagementMenu(id); @@ -739,19 +746,19 @@ default { // Forward numeric picks to the game logic else if ((integer)msg > 0) { if (llGetListLength(currentPickList) >= currentPickLimit) { - llOwnerSay("āš ļø Reached pick limit of " + (string)currentPickLimit + " for " + currentPickTarget); + dbg("āš ļø Reached pick limit of " + (string)currentPickLimit + " for " + currentPickTarget); showPickListMenu(id); return; } if (llListFindList(currentPickList, [msg]) != -1) { - llOwnerSay("āš ļø Pick already exists: " + msg); + dbg("āš ļø Pick already exists: " + msg); showPickListMenu(id); return; } integer i; for (i = 0; i < llGetListLength(currentPickList); i++) { if (llList2String(currentPickList, i) == msg) { - llOwnerSay("āš ļø Duplicate pick detected."); + dbg("āš ļø Duplicate pick detected."); return; } } @@ -779,9 +786,9 @@ default { // Store display info: [type, offset, rotation, ...] foundDisplays += [object_type, offset, rel_rot]; - llOwnerSay("āœ… Found " + object_type + " display at position " + (string)object_pos); - llOwnerSay(" Config: " + object_type + "_offset=" + (string)offset); - llOwnerSay(" Rotation: " + object_type + "_rotation=" + (string)rel_rot); + dbg("āœ… Found " + object_type + " display at position " + (string)object_pos); + dbg(" Config: " + object_type + "_offset=" + (string)offset); + dbg(" Rotation: " + object_type + "_rotation=" + (string)rel_rot); } } // Note: Automatic auto-config requests are now handled by Controller_Discovery.lsl @@ -795,18 +802,18 @@ default { integer numDisplays = llGetListLength(foundDisplays) / 3; // 3 items per display (type, offset, rotation) if (numDisplays == 0) { - llOwnerSay("\nāš ļø No follower displays found within 20 meters."); - llOwnerSay("šŸ“ Make sure your displays have the follower script and are close enough."); - llOwnerSay("šŸ”„ Check that they use the same dynamic channel system as this controller."); + dbg("\nāš ļø No follower displays found within 20 meters."); + dbg("šŸ“ Make sure your displays have the follower script and are close enough."); + dbg("šŸ”„ Check that they use the same dynamic channel system as this controller."); } else { - llOwnerSay("\nšŸŽ‰ Position scan complete! Found " + (string)numDisplays + " display(s)."); - llOwnerSay("\nšŸ“„ CONFIG UPDATE METHODS:"); - llOwnerSay("1ļøāƒ£ MANUAL: Copy the config lines above to each display's 'config' notecard"); - llOwnerSay("2ļøāƒ£ AUTOMATIC: The displays should move to their new positions automatically!"); - llOwnerSay("\nšŸ“† The new positions are now saved and will be remembered when objects are rezzed."); + dbg("\nšŸŽ‰ Position scan complete! Found " + (string)numDisplays + " display(s)."); + dbg("\nšŸ“„ CONFIG UPDATE METHODS:"); + dbg("1ļøāƒ£ MANUAL: Copy the config lines above to each display's 'config' notecard"); + dbg("2ļøāƒ£ AUTOMATIC: The displays should move to their new positions automatically!"); + dbg("\nšŸ“† The new positions are now saved and will be remembered when objects are rezzed."); // Send position update commands to displays (future enhancement) - llOwnerSay("šŸ”„ Broadcasting position updates to all found displays..."); + dbg("šŸ”„ Broadcasting position updates to all found displays..."); // Broadcast updates to each found display integer i; @@ -822,18 +829,18 @@ default { else if (displayType == "dice") updateChannel = DICE_DATA_CHANNEL; else { // Skip unknown display types - llOwnerSay("āš ļø Unknown display type: " + displayType); + dbg("āš ļø Unknown display type: " + displayType); } // Only send update if we found a valid channel if (displayType == "scoreboard" || displayType == "leaderboard" || displayType == "dice") { string updateMsg = "POSITION_UPDATE|" + displayType + "|" + (string)displayOffset + "|" + (string)displayRotation; llRegionSay(updateChannel, updateMsg); - llOwnerSay("āœ… Sent position update to " + displayType + " display"); + dbg("āœ… Sent position update to " + displayType + " display"); } } - llOwnerSay("\n✨ Position reset complete! Your displays should now be in the correct positions."); + dbg("\n✨ Position reset complete! Your displays should now be in the correct positions."); } } } diff --git a/XyzzyText_Dice_Bridge_Linkset.lsl b/XyzzyText_Dice_Bridge_Linkset.lsl index eb16c24..b1ad138 100644 --- a/XyzzyText_Dice_Bridge_Linkset.lsl +++ b/XyzzyText_Dice_Bridge_Linkset.lsl @@ -46,6 +46,9 @@ displayDiceText(string text) { } default { + on_rez(integer start_param) { + llResetScript(); // Fixes Z-fighting and alignment glitches on rez + } state_entry() { if (VERBOSE_LOGGING) { llOwnerSay("šŸŽ² Dice Display Bridge ready! (Linkset Version)");