// === Player Status Float - Enhanced Display === // Helper function to get display name with fallback to username string getPlayerName(key id) { string displayName = llGetDisplayName(id); if (displayName == "") { // Fallback to legacy username if display name is unavailable displayName = llKey2Name(id); } return displayName; } key target; string displayText; string myName; // Listen handle management integer listenHandle = -1; #define MSG_SYNC_GAME_STATE 107 list lives; list picksData; string perilPlayer; list names; // Memory reporting function reportMemoryUsage(string scriptName) { integer used = llGetUsedMemory(); integer free = llGetFreeMemory(); integer total = used + free; float percentUsed = ((float)used / (float)total) * 100.0; llOwnerSay("🧠 [" + scriptName + "] Memory: " + (string)used + " used, " + (string)free + " free (" + llGetSubString((string)percentUsed, 0, 4) + "% used)"); } list getPicksFor(string nameInput) { integer i; for (i = 0; i < llGetListLength(picksData); i++) { string entry = llList2String(picksData, i); list parts = llParseString2List(entry, ["|"], []); if (llGetListLength(parts) >= 2 && llList2String(parts, 0) == nameInput) { string picks = llList2String(parts, 1); if (picks == "") { return []; } // Check for corruption markers (^ symbols that shouldn't be in picks) if (llSubStringIndex(picks, "^") != -1) { return []; } // Convert semicolons back to commas, then parse picks = llDumpList2String(llParseString2List(picks, [";"], []), ","); return llParseString2List(picks, [","], []); } } return []; } default { state_entry() { // Get player name from object description if available string playerName = llGetObjectDesc(); if (playerName == "" || playerName == "(No Description)") { playerName = "Unknown"; } reportMemoryUsage("šŸ“± Player Float (" + playerName + ")"); llSetText("ā³ Waiting...", <1,1,1>, 1.0); llSetTimerEvent(1.0); } on_rez(integer start_param) { // Clean up any existing listeners if (listenHandle != -1) { llListenRemove(listenHandle); } // Set up managed listener listenHandle = llListen(start_param, "", NULL_KEY, ""); // Initialize myName to empty - will be set when SET_NAME message is received myName = ""; // Don't report memory immediately - wait for proper name to be set // PlayerStatus_Float ready and listening } listen(integer channel, string name, key id, string message) { if (llSubStringIndex(message, "FLOAT:") == 0) { list parts = llParseString2List(message, ["|"], []); if (llGetListLength(parts) >= 2) { target = (key)llGetSubString(llList2String(parts, 0), 6, -1); displayText = llList2String(parts, 1); // Extract life count from the display text to set heart texture // Look for "Lives: X" pattern in the text integer livesPos = llSubStringIndex(displayText, "Lives: "); if (livesPos != -1) { string livesStr = llGetSubString(displayText, livesPos + 7, livesPos + 7); integer lifeCount = (integer)livesStr; string heartTexture = (string)lifeCount + "_hearts"; // Set heart texture based on current life count llSetTexture(heartTexture, 1); // Face 1 (right side) llSetTexture(heartTexture, 2); // Face 2 (back) llSetTexture(heartTexture, 3); // Face 3 (left side) llSetTexture(heartTexture, 4); // Face 4 (front) // IMPROVED: Special visual treatment for elimination (0 hearts) if (lifeCount == 0) { // Make 0 hearts more prominent with red glow llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_GLOW, ALL_SIDES, 0.3, PRIM_COLOR, ALL_SIDES, <1.0, 0.0, 0.0>, 1.0 ]); // Modify display text to show elimination status displayText = llDumpList2String(llParseString2List(displayText, ["\n"], []), "\n") + "\nšŸ’€ ELIMINATED! šŸ’€"; } else { // Check for winner status first (highest priority) integer isWinner = FALSE; if (llSubStringIndex(displayText, "✨ ULTIMATE VICTORY!") != -1 || llSubStringIndex(displayText, "ULTIMATE SURVIVOR") != -1) { isWinner = TRUE; } // Check if this player is in peril for yellow glow integer isInPeril = FALSE; if (llSubStringIndex(displayText, "⚔ YOU ARE IN PERIL! ⚔") != -1) { isInPeril = TRUE; } if (isWinner) { // Green glow for winner (overrides peril) llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_GLOW, ALL_SIDES, 0.3, PRIM_COLOR, ALL_SIDES, <0.0, 1.0, 0.0>, 1.0 // Green tint ]); } else if (isInPeril) { // Yellow glow for peril player llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_GLOW, ALL_SIDES, 0.2, PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 0.0>, 1.0 // Yellow tint ]); } else { // Normal colors for living players - remove glow llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_GLOW, ALL_SIDES, 0.0, PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 1.0>, 1.0 ]); llSetColor(<0.2, 0.2, 0.2>, 0); // Dark gray for top llSetColor(<0.2, 0.2, 0.2>, 5); // Dark gray for bottom } } // Remove "Lives: X" from display text since hearts show it list lines = llParseString2List(displayText, ["\n"], []); list filteredLines = []; integer i; for (i = 0; i < llGetListLength(lines); i++) { string line = llList2String(lines, i); if (llSubStringIndex(line, "Lives: ") != 0) { filteredLines += [line]; } } displayText = llDumpList2String(filteredLines, "\n"); } llSetText(displayText, <1,1,1>, 1.0); } } else if (message == "CLEANUP") { llOwnerSay("🪟 Cleaning up..."); llDie(); } else if (llSubStringIndex(message, "SET_NAME:") == 0) { myName = llGetSubString(message, 9, -1); // Name successfully received and set // Update the object description as well for consistency llSetObjectDesc(myName); // Now report memory with the proper player name reportMemoryUsage("šŸ“± " + myName); } } link_message(integer sender, integer num, string str, key id) { if (num == MSG_SYNC_GAME_STATE) { list parts = llParseString2List(str, ["~"], []); if (llGetListLength(parts) < 4) return; lives = llCSV2List(llList2String(parts, 0)); // Use ^ delimiter for picksData to match the main system string picksDataStr = llList2String(parts, 1); if (picksDataStr == "" || picksDataStr == "EMPTY") { picksData = []; } else { picksData = llParseString2List(picksDataStr, ["^"], []); } string receivedPeril = llList2String(parts, 2); if (receivedPeril == "NONE") { perilPlayer = ""; // Convert placeholder back to empty } else { perilPlayer = receivedPeril; } names = llCSV2List(llList2String(parts, 3)); integer nameIdx = llListFindList(names, [myName]); if (nameIdx == -1) return; list picks = getPicksFor(myName); integer lifeCount = llList2Integer(lives, nameIdx); string perilDisplay; // If the perilPlayer string is empty or contains a comma (indicating // multiple names), treat the game as not yet started. This avoids // showing multiple players as the peril player before the first // round begins. Once a single peril player is assigned, it will // not contain a comma and will be displayed normally. if (perilPlayer == "" || llSubStringIndex(perilPlayer, ",") != -1) { perilDisplay = "Waiting for game to start..."; } else { perilDisplay = perilPlayer; } string picksDisplay = llList2CSV(picks); // IMPROVED: Set heart texture and handle elimination display string heartTexture = (string)lifeCount + "_hearts"; llSetTexture(heartTexture, 1); // Face 1 (right side) llSetTexture(heartTexture, 2); // Face 2 (back) llSetTexture(heartTexture, 3); // Face 3 (left side) llSetTexture(heartTexture, 4); // Face 4 (front) string txt; if (lifeCount == 0) { // Special treatment for elimination - red glow and elimination message llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_GLOW, ALL_SIDES, 0.3, PRIM_COLOR, ALL_SIDES, <1.0, 0.0, 0.0>, 1.0 ]); txt = "šŸŽ² Peril Dice\nšŸ‘¤ " + myName + "\nšŸ’€ ELIMINATED! šŸ’€\nšŸ”¢ Final Picks: " + picksDisplay; // Set text to red color as well for extra visibility llSetText(txt, <1.0, 0.2, 0.2>, 1.0); return; // Skip normal text setting below } else { // Check if this is the winner (highest priority) - happens when only 1 player left integer isWinner = (llGetListLength(names) <= 1 && myName != "" && llListFindList(names, [myName]) != -1); // Check if this player is the peril player for yellow glow integer isInPeril = (myName == perilPlayer && perilPlayer != "" && llSubStringIndex(perilPlayer, ",") == -1); if (isWinner) { // Green glow for winner (overrides peril) llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_GLOW, ALL_SIDES, 0.3, PRIM_COLOR, ALL_SIDES, <0.0, 1.0, 0.0>, 1.0 // Green tint ]); } else if (isInPeril) { // Yellow glow for peril player llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_GLOW, ALL_SIDES, 0.2, PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 0.0>, 1.0 // Yellow tint ]); } else { // Normal colors for living players - remove glow llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_GLOW, ALL_SIDES, 0.0, PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 1.0>, 1.0 ]); llSetColor(<0.2, 0.2, 0.2>, 0); // Dark gray for top llSetColor(<0.2, 0.2, 0.2>, 5); // Dark gray for bottom } txt = "šŸŽ² Peril Dice\nšŸ‘¤ " + myName + "\nšŸ¢ Peril: " + perilDisplay + "\nšŸ”¢ Picks: " + picksDisplay; } llSetText(txt, <1,1,1>, 1.0); } } timer() { if (target != NULL_KEY && getPlayerName(target) != "") { vector pos = llList2Vector(llGetObjectDetails(target, [OBJECT_POS]), 0) + <1,0,1>; llSetRegionPos(pos); } } }