updated to useing preprocesser in firestorm, saveing space in memory, changed to new experience database
This commit is contained in:
parent
991b478e01
commit
5c3eb15c16
7 changed files with 387 additions and 175 deletions
138
Experience_Admin_HUD.lsl
Normal file
138
Experience_Admin_HUD.lsl
Normal file
|
|
@ -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 + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
166
Game_Manager.lsl
166
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)");
|
||||
|
|
|
|||
Loading…
Reference in a new issue