some floater and scoreboard fixes

This commit is contained in:
RebeccaNod1 2025-08-13 14:32:26 -05:00
parent f06108d99a
commit b28970ea8e
6 changed files with 156 additions and 70 deletions

View file

@ -31,10 +31,6 @@ integer BOT_COMMAND_CHANNEL;
// Channel initialization function
initializeChannels() {
BOT_COMMAND_CHANNEL = calculateChannel(5); // ~-77500 range to match Main.lsl
// Report channel to owner for debugging
llOwnerSay("🔧 [Bot Manager] Dynamic channel initialized:");
llOwnerSay(" Bot Command: " + (string)BOT_COMMAND_CHANNEL);
}
// Configuration
@ -197,20 +193,15 @@ doBotRoll(string botName, integer diceMax) {
default {
state_entry() {
// Initialize dynamic channels
initializeChannels();
LISTEN_CHANNEL = BOT_COMMAND_CHANNEL;
// Clean up any existing listeners
if (listenHandle != -1) {
llListenRemove(listenHandle);
}
// Set up managed listener with dynamic channel
listenHandle = llListen(LISTEN_CHANNEL, "", NULL_KEY, "");
llOwnerSay("[Bot Manager] Ready and listening on channel " + (string)LISTEN_CHANNEL);
llOwnerSay("[Bot Manager] My key: " + (string)llGetKey());
llOwnerSay("[Bot Manager] My position: " + (string)llGetPos());
llOwnerSay("🤖 Bot Manager ready!");
}
link_message(integer sender, integer num, string str, key id) {

View file

@ -39,13 +39,6 @@ integer FLOATER_BASE_CHANNEL;
// Channel initialization function
initializeChannels() {
FLOATER_BASE_CHANNEL = calculateChannel(9); // ~-86000 range base for floaters
// Report channel to owner for debugging
llOwnerSay("🔧 [Floater Manager] Dynamic channels initialized:");
llOwnerSay(" Floater Base: " + (string)FLOATER_BASE_CHANNEL);
llOwnerSay(" Player 0 channel: " + (string)(FLOATER_BASE_CHANNEL + 0));
llOwnerSay(" Player 1 channel: " + (string)(FLOATER_BASE_CHANNEL + 1));
llOwnerSay(" Player 9 channel: " + (string)(FLOATER_BASE_CHANNEL + 9));
}
// Maximum number of players allowed in the game
@ -108,12 +101,8 @@ string getNameFromKey(key id) {
// Main event handler
default {
state_entry() {
// Initialize dynamic channels
initializeChannels();
// Verify channel consistency with Main Controller
llOwnerSay("📦 Floater Manager ready!");
llOwnerSay("📦 Using FLOATER_BASE_CHANNEL: " + (string)FLOATER_BASE_CHANNEL);
}
link_message(integer sender, integer num, string str, key id) {
@ -139,6 +128,13 @@ default {
list info = llParseString2List(str, ["|"], []);
string name = llList2String(info, 0);
key avKey = llList2Key(info, 1);
// Check if this player is already registered to prevent duplicate floaters
if (llListFindList(players, [avKey]) != -1) {
llOwnerSay("⚠️ Player " + name + " is already registered, ignoring duplicate registration");
return;
}
names += [name];
players += [avKey];
lives += [3]; // Initialize with 3 lives for new players
@ -267,6 +263,12 @@ default {
// IMPORTANT: Also sync the names list to prevent desynchronization
string namesStr = llList2String(parts, 3);
names = llCSV2List(namesStr);
// Sync players list if available (5th part)
if (llGetListLength(parts) >= 5) {
string playersStr = llList2String(parts, 4);
players = llCSV2List(playersStr);
}
// After synchronizing the game state, update all existing floats so
// they reflect the current peril status. Without this, floats

View file

@ -281,10 +281,6 @@ syncStateToMain() {
default {
state_entry() {
llOwnerSay("🎯 Game Manager ready!");
// Reset game on startup to ensure clean state when core logic is updated
llOwnerSay("🔄 [Game Manager] Requesting game reset on startup...");
llMessageLinked(LINK_SET, -99998, "REQUEST_GAME_RESET", NULL_KEY);
}
link_message(integer sender, integer num, string str, key id) {

View file

@ -53,6 +53,8 @@ integer MSG_TOGGLE_READY = 202;
integer MSG_QUERY_READY_STATE = 210;
integer MSG_READY_STATE_RESULT = 211;
integer MSG_CLEANUP_ALL_FLOATERS = 212;
integer MSG_QUERY_OWNER_STATUS = 213;
integer MSG_OWNER_STATUS_RESULT = 214;
integer MSG_SHOW_ROLL_DIALOG = 301;
integer MSG_GET_CURRENT_DIALOG = 302;
integer MSG_PLAYER_WON = 551;
@ -176,10 +178,6 @@ initializeChannels() {
rollDialogChannel = ROLLDIALOG_CHANNEL;
DIALOG_CHANNEL = MAIN_DIALOG_CHANNEL;
llOwnerSay("🔧 [Main Controller] Channels initialized for external communication:");
llOwnerSay(" Dialog: " + (string)MAIN_DIALOG_CHANNEL);
llOwnerSay(" Roll: " + (string)ROLLDIALOG_CHANNEL);
llOwnerSay(" Floater Base: " + (string)FLOATER_BASE_CHANNEL);
}
// Clean up listen handles
@ -274,7 +272,7 @@ updateHelpers() {
checkMemoryUsage("updateHelpers_after_picks_processing");
}
// Send core game state to internal scripts
// Send core game state to internal scripts (include players list for floater management)
string syncMessage = llList2CSV(lives) + "~" + picksDataStr + "~" + perilForSync + "~" + llList2CSV(names) + "~" + llList2CSV(players);
llMessageLinked(LINK_SET, MSG_SYNC_GAME_STATE, syncMessage, NULL_KEY);
@ -319,8 +317,15 @@ updateFloatingText() {
resetGame() {
cleanupListeners();
// Only clean up channels that actually have active floaters
integer i;
for (i = 0; i < MAX_PLAYERS; i++) {
for (i = 0; i < llGetListLength(floaterChannels); i++) {
integer ch = llList2Integer(floaterChannels, i);
llMessageLinked(LINK_SET, MSG_CLEANUP_FLOAT, (string)ch, NULL_KEY);
}
// Also send a few cleanup messages to common channel ranges in case of orphaned floaters
for (i = 0; i < llGetListLength(names); i++) {
integer ch = FLOATER_BASE_CHANNEL + i;
llMessageLinked(LINK_SET, MSG_CLEANUP_FLOAT, (string)ch, NULL_KEY);
}
@ -364,8 +369,6 @@ resetGame() {
default {
state_entry() {
llOwnerSay("🎮 Main Controller ready! (Linkset Version)");
llOwnerSay("🎮 Main Controller key: " + (string)llGetKey());
llOwnerSay("🎮 Main Controller position: " + (string)llGetPos());
// Initialize lockout system
gameOwner = llGetOwner();
@ -375,10 +378,8 @@ default {
initializeChannels();
// Reset the game on startup to ensure clean state
llOwnerSay("🔄 Resetting game state on startup...");
resetGame();
llOwnerSay("📡 Linkset communication active - no discovery needed!");
llOwnerSay("✅ Main Controller initialization complete!");
}
@ -690,6 +691,9 @@ default {
perilPlayer = newPerilPlayer;
names = newNames;
// Update scoreboard and other helpers with the new game state
updateHelpers();
integer allPicksEmpty = TRUE;
integer i;
for (i = 0; i < llGetListLength(newPicksData) && allPicksEmpty; i++) {
@ -766,6 +770,45 @@ default {
return;
}
// Handle owner status queries
if (num == MSG_QUERY_OWNER_STATUS) {
list queryParts = llParseString2List(str, ["|"], []);
string ownerName;
integer requestID = 0;
if (llGetListLength(queryParts) >= 2) {
ownerName = llList2String(queryParts, 0);
requestID = (integer)llList2String(queryParts, 1);
} else {
ownerName = str;
}
// Check if owner is registered
integer ownerIdx = llListFindList(players, [id]);
integer isRegistered = (ownerIdx != -1);
integer isPending = (llListFindList(pendingRegistrations, [id]) != -1);
integer isStarter = FALSE;
if (isRegistered) {
// Calculate starter status if registered
isStarter = TRUE;
integer k;
for (k = 0; k < ownerIdx && isStarter; k++) {
string existingName = llList2String(names, k);
if (llSubStringIndex(existingName, "Bot") != 0) {
isStarter = FALSE;
}
}
if (ownerIdx == 0) {
isStarter = TRUE;
}
}
string result = ownerName + "|" + (string)isRegistered + "|" + (string)isPending + "|" + (string)isStarter + "|" + (string)requestID;
llMessageLinked(LINK_SET, MSG_OWNER_STATUS_RESULT, result, id);
return;
}
// Handle aggressive floater cleanup
if (num == MSG_CLEANUP_ALL_FLOATERS) {
integer i;
@ -906,19 +949,9 @@ default {
}
}
// Handle owner choice menu
// Handle owner choice menu - "Join Game" is handled by Player_DialogHandler
if (id == llGetOwner()) {
if (msg == "Join Game") {
// Owner wants to join as a player
string ownerName = getPlayerName(id);
pendingRegistrations += [id];
llMessageLinked(LINK_SET, MSG_REGISTER_PLAYER, ownerName + "|" + (string)id, NULL_KEY);
// After registration, they'll get the appropriate player menu
// The registration handler will call updateHelpers() and show menu
return;
}
else if (msg == "Owner Menu") {
if (msg == "Owner Menu") {
// Owner wants admin functions without joining - use admin targetType
llMessageLinked(LINK_SET, MSG_SHOW_MENU, "admin|0", id);
return;

View file

@ -84,6 +84,8 @@ integer MSG_TOGGLE_READY = 202;
integer MSG_QUERY_READY_STATE = 210;
integer MSG_READY_STATE_RESULT = 211;
integer MSG_CLEANUP_ALL_FLOATERS = 212;
integer MSG_QUERY_OWNER_STATUS = 213;
integer MSG_OWNER_STATUS_RESULT = 214;
integer MSG_GET_CURRENT_DIALOG = 302;
// Categorized owner menu system
@ -155,9 +157,15 @@ showReadyLeaveMenu(key id, integer isStarter, integer isOwner) {
}
// Generate unique request ID and store pending menu state
// New requests always override previous ones for the same player
currentRequestID++;
if (currentRequestID > 1000000) currentRequestID = 1; // Prevent overflow
// 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);
}
pendingMenuPlayer = id;
pendingMenuIsStarter = isStarter;
pendingMenuIsOwner = isOwner;
@ -167,7 +175,7 @@ showReadyLeaveMenu(key id, integer isStarter, integer isOwner) {
string playerName = getPlayerName(id);
// Include request ID in the query to track responses
string queryData = playerName + "|" + (string)currentRequestID;
llMessageLinked(LINK_SET, MSG_QUERY_READY_STATE, queryData, id);
llMessageLinked(LINK_SET, MSG_QUERY_READY_STATE, queryData, id);
}
// Internal function to show the menu once we have ready state
@ -337,6 +345,9 @@ default {
if (targetType == "owner") {
// Both starter and non-starter owners get ready/leave menu with Owner button
showReadyLeaveMenu(id, isStarter, TRUE);
} else if (targetType == "registered_owner") {
// Registered owner gets ready/leave menu with Owner button
showReadyLeaveMenu(id, isStarter, TRUE);
} else if (targetType == "player") {
showReadyLeaveMenu(id, isStarter, FALSE);
} else if (targetType == "admin") {
@ -363,7 +374,7 @@ default {
}
showReadyLeaveMenuWithState(pendingMenuPlayer, pendingMenuIsStarter, pendingMenuIsOwner, isReady, isBot);
// Reset pending state
// Reset pending state ONLY after successfully showing the dialog
pendingMenuPlayer = NULL_KEY;
pendingMenuRequestID = 0;
}
@ -421,6 +432,57 @@ default {
showPickListMenu(id);
}
}
else if (num == MSG_OWNER_STATUS_RESULT) {
// Parse owner status response and show appropriate menu
list parts = llParseString2List(str, ["|"], []);
if (llGetListLength(parts) >= 5) {
string ownerName = llList2String(parts, 0);
integer isRegistered = (integer)llList2String(parts, 1);
integer isPending = (integer)llList2String(parts, 2);
integer isStarter = (integer)llList2String(parts, 3);
integer responseRequestID = (integer)llList2String(parts, 4);
// Validate that this response matches our pending request
if (pendingMenuPlayer == id && responseRequestID == pendingMenuRequestID) {
// Check for timeout
if ((llGetTime() - pendingMenuTimestamp) > MENU_REQUEST_TIMEOUT) {
llOwnerSay("⏰ Owner status query timed out, ignoring response");
pendingMenuPlayer = NULL_KEY;
return;
}
// 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");
// 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");
} else if (isPending) {
llRegionSayTo(id, 0, "⏳ Registration already in progress for " + ownerName);
// Reset pending state for non-registered responses
pendingMenuPlayer = NULL_KEY;
pendingMenuRequestID = 0;
} else {
// Owner is not registered - show join/admin choice menu
list options = ["Join Game", "Owner Menu"];
string menuText = "👑 Owner Options:\n\n🎮 Join Game - Register as a player\n🔧 Owner Menu - Admin functions without joining";
llDialog(id, menuText, options, DIALOG_CHANNEL);
// Reset pending state for non-registered responses
pendingMenuPlayer = NULL_KEY;
pendingMenuRequestID = 0;
}
} else {
llOwnerSay("⚠️ Owner status response mismatch - ignoring");
}
} else {
llOwnerSay("⚠️ Invalid owner status result format - expected 5 parts, got " + (string)llGetListLength(parts));
}
return;
}
}
listen(integer channel, string name, key id, string msg) {
@ -474,9 +536,22 @@ default {
showOwnerMenu(id);
}
else if (msg == "⬅️ Back to Game") {
// Return to the owner's ready/leave menu
// Need to determine if owner is starter
llMessageLinked(LINK_SET, MSG_SHOW_MENU, "owner|1", id); // Assume starter for now, will be corrected by main controller
// Intelligently determine what menu to show based on owner's registration status
if (id == gameOwner) {
// Query the Main Controller about the owner's registration status
string ownerName = getPlayerName(id);
// Generate unique request ID for tracking
currentRequestID++;
if (currentRequestID > 1000000) currentRequestID = 1;
// Store pending owner query state
pendingMenuPlayer = id;
pendingMenuRequestID = currentRequestID;
pendingMenuTimestamp = llGetTime();
string queryData = ownerName + "|" + (string)currentRequestID;
llMessageLinked(LINK_SET, MSG_QUERY_OWNER_STATUS, queryData, id);
}
}
// Owner joins the game: register and rez a float for them
else if (msg == "Join Game") {

View file

@ -287,8 +287,7 @@ default {
llSay(0, "⚡ PLOT TWIST! " + newPeril + " picked " + resultStr + " (rolled on d" + (string)diceType + ") and is now in ULTIMATE PERIL! ⚡");
perilPlayer = newPeril;
// Send Plot Twist status to scoreboard
llRegionSay(SCOREBOARD_CHANNEL_1, "GAME_STATUS|Plot Twist");
// Plot Twist status will be sent by Main Controller via link messages
// Add delay to let status display before next phase
llSleep(2.0);
@ -300,14 +299,8 @@ default {
integer currentLives = llList2Integer(lives, pidx);
lives = llListReplaceList(lives, [currentLives - 1], pidx, pidx);
// Immediately send updated heart count to scoreboard
integer newLives = currentLives - 1;
key perilKey = NULL_KEY; // We don't have player keys in this module, use NULL_KEY
if (pidx < llGetListLength(names)) {
string updateMsg = "PLAYER_UPDATE|" + perilPlayer + "|" + (string)newLives + "|" + (string)perilKey;
llRegionSay(SCOREBOARD_CHANNEL_1, updateMsg);
llOwnerSay("💗 Immediate scoreboard update: " + perilPlayer + " now has " + (string)newLives + " lives");
}
// Player update will be sent by Main Controller via sync message and updateHelpers()
llOwnerSay("💗 Player lives updated: " + perilPlayer + " now has " + (string)(currentLives - 1) + " lives");
// Check if peril player picked the rolled number
list perilPicks = getPicksFor(perilPlayer);
@ -315,14 +308,12 @@ default {
if (perilPickedIt) {
llSay(0, "🩸 DIRECT HIT! " + perilPlayer + " picked their own doom - the d" + (string)diceType + " landed on " + resultStr + "! 🩸");
// Send Direct Hit status to scoreboard
llRegionSay(SCOREBOARD_CHANNEL_1, "GAME_STATUS|Direct Hit");
// Direct Hit status will be sent by Main Controller via link messages
// Add delay to let status display before next phase
llSleep(2.0);
} else {
llSay(0, "🩸 NO SHIELD! Nobody picked " + resultStr + " - " + perilPlayer + " takes the hit from the d" + (string)diceType + "! 🩸");
// Send No Shield status to scoreboard
llRegionSay(SCOREBOARD_CHANNEL_1, "GAME_STATUS|No Shield");
// No Shield status will be sent by Main Controller via link messages
// Add delay to let status display before next phase
llSleep(2.0);
}
@ -331,10 +322,8 @@ default {
// Check for elimination
if (currentLives - 1 <= 0) {
// Show 0 hearts on scoreboard before elimination message
string eliminationUpdateMsg = "PLAYER_UPDATE|" + perilPlayer + "|0|" + (string)NULL_KEY;
llRegionSay(SCOREBOARD_CHANNEL_1, eliminationUpdateMsg);
llOwnerSay("💀 Elimination update: " + perilPlayer + " now shows 0 hearts");
// Player elimination will be handled by Main Controller via sync and elimination messages
llOwnerSay("💀 Elimination detected: " + perilPlayer + " has 0 hearts remaining");
llSay(0, "🐻 PUNISHMENT TIME! " + perilPlayer + " has been ELIMINATED!");
// Remove eliminated player (send message to main controller)