feat: implement blinking #1 rank highlight and add authenticated global leaderboard wipe functionality

This commit is contained in:
RebeccaNod1 2026-04-06 18:52:46 -06:00
parent 1297b99e2c
commit 0974d19f12
4 changed files with 91 additions and 9 deletions

View file

@ -1,6 +1,10 @@
#include "Peril_Constants.lsl"
string leftText = "";
string firstName = "";
integer blinkState = 0;
integer canBlink = 0;
// Distribute text to the FURWARE "Leaderboard" boxes
distributeFullText(string text) {
@ -10,7 +14,33 @@ distributeFullText(string text) {
if (llGetListLength(parts) >= 3) {
// Distribute each column to its virtual box
llMessageLinked(LINK_SET, 0, llList2String(parts, 0), (key)"fw_data:LB_Rank");
llMessageLinked(LINK_SET, 0, llList2String(parts, 1), (key)"fw_data:LB_Name");
// Distribute Name column (Split first line for blinking)
string nameText = llList2String(parts, 1);
integer firstLineEnd = llSubStringIndex(nameText, "\n");
if (firstLineEnd != -1) {
firstName = llGetSubString(nameText, 0, firstLineEnd - 1);
string remainingNames = llGetSubString(nameText, firstLineEnd + 1, -1);
llMessageLinked(LINK_SET, 0, firstName, (key)"fw_data:LB_Name_Top");
llMessageLinked(LINK_SET, 0, remainingNames, (key)"fw_data:LB_Name");
} else {
firstName = nameText;
llMessageLinked(LINK_SET, 0, firstName, (key)"fw_data:LB_Name_Top");
llMessageLinked(LINK_SET, 0, "", (key)"fw_data:LB_Name");
}
// Check if we should blink (#1 spot on first page only)
integer offset = (integer)llList2String(parts, 5);
if (offset == 0) {
canBlink = TRUE;
llSetTimerEvent(0.5);
} else {
canBlink = FALSE;
llSetTimerEvent(0.0);
// Ensure name is visible on non-blinking pages
llMessageLinked(LINK_SET, 0, firstName, (key)"fw_data:LB_Name_Top");
}
llMessageLinked(LINK_SET, 0, llList2String(parts, 2), (key)"fw_data:LB_WL");
// Route Navigation Arrows to dedicated button boxes
@ -41,8 +71,13 @@ default {
// Registering virtual columns + Navigation buttons
// Coordinates: x, y, width, height (0-indexed)
// border=lr added to create vertical separators between columns
llMessageLinked(LINK_SET, 0, "", (key)"fw_addbox:LB_Rank:Leaderboard:0,1,4,10:");
llMessageLinked(LINK_SET, 0, "", (key)"fw_addbox:LB_Name:Leaderboard:4,1,20,10:");
// Split Name into Top (for blinking) and Body
llMessageLinked(LINK_SET, 0, "", (key)"fw_addbox:LB_Name_Top:Leaderboard:4,1,20,1:border=lr");
llMessageLinked(LINK_SET, 0, "", (key)"fw_addbox:LB_Name:Leaderboard:4,2,20,9:border=lr");
llMessageLinked(LINK_SET, 0, "", (key)"fw_addbox:LB_WL:Leaderboard:24,1,8,10:");
// Navigation Row (Shifted down to Y=11)
@ -58,6 +93,22 @@ default {
// Trigger Leaderboard Manager to download from KVP Database
llMessageLinked(LINK_SET, MSG_RESET_LEADERBOARD, "START_SYNC", NULL_KEY);
// Start Blink Timer (0.5s intervals)
llSetTimerEvent(0.5);
}
timer() {
if (!canBlink) {
llSetTimerEvent(0.0);
return;
}
blinkState = !blinkState;
if (blinkState) {
llMessageLinked(LINK_SET, 0, firstName, (key)"fw_data:LB_Name_Top");
} else {
llMessageLinked(LINK_SET, 0, "", (key)"fw_data:LB_Name_Top");
}
}
touch_start(integer _n) {

View file

@ -149,6 +149,8 @@ startUpdateSequence(string pName, string pResult) {
}
default {
on_rez(integer _p) { llResetScript(); }
state_entry() {
REPORT_MEMORY();
dbg("⏳ [Leaderboard] Startup: Handshake link active.");
@ -343,7 +345,7 @@ default {
}
string _p = " "; if (_offset > 0) _p = "[ < PREV ]";
string _n = " "; if (_offset + 10 < _globalTotal) _n = "[ NEXT > ]";
llMessageLinked(LINK_SET, MSG_DISPLAY_LEADERBOARD, "COLUMNS|" + _rankCol + "|" + _nameCol + "|" + _statsCol + "|" + _p + "|" + _n, NULL_KEY);
llMessageLinked(LINK_SET, MSG_DISPLAY_LEADERBOARD, "COLUMNS|" + _rankCol + "|" + _nameCol + "|" + _statsCol + "|" + _p + "|" + _n + "|" + (string)_offset, NULL_KEY);
}
else if (num == MSG_LB_PAGE_NEXT) {
integer _maxEntries = llGetListLength(leaderboardData) / 3;
@ -367,6 +369,18 @@ default {
if (str == "START_SYNC") {
loadLBPage(1);
}
else if (str == "WIPE" || str == "HARD_RESET") {
if (id != (key)GLOBAL_ADMIN) {
llOwnerSay("🚫 [Security] Unauthorized WIPE attempt blocked from: " + (string)id);
return;
}
// Soft Wipe: Clear all shards to empty in world datastore
integer _i;
for (_i = 1; _i <= MAX_LB_PAGES; _i++) {
llUpdateKeyValue(LB_KEY_PREFIX + (string)_i, "", FALSE, "");
}
dbg("🚫 [Leaderboard Manager] GLOBAL WIPE: All 10 datastore shards have been set to empty.");
}
else if (str == "DEBUG_GENERATE" && llGetOwner() == llGetCreator()) {
generateShardedData();
}

View file

@ -1127,15 +1127,30 @@ default {
return;
}
if (msg == "Reset Leaderboard") {
// CHANGED: Send to scoreboard, which will handle leaderboard reset
llMessageLinked(LINK_SCOREBOARD, MSG_RESET_LEADERBOARD, "", NULL_KEY);
dbg("🏆 Leaderboard scores reset - game wins cleared!");
llDialog(id, "⚠️ WARNING: This will PERMANENTLY WIPE the World Ranking database (all 10 shards). Are you sure?", ["YES, WIPE LB", "NO, CANCEL"], DIALOG_CHANNEL);
return;
}
if (msg == "YES, WIPE LB") {
if (id != (key)GLOBAL_ADMIN) {
llRegionSayTo(id, 0, "🚫 Access Denied: Only the Global Admin can perform this action.");
return;
}
llMessageLinked(LINK_SCOREBOARD, MSG_RESET_LEADERBOARD, "WIPE", id); // Use 'id' to pass user key
llOwnerSay("🏆 GLOBAL LEADERBOARD WIPE confirmed and executed.");
return;
}
if (msg == "Reset All") {
llDialog(id, "⚠️ WARNING: This will factory reset the game AND permanently wipe the leaderboard. Are you sure?", ["YES, RESET ALL", "NO, CANCEL"], DIALOG_CHANNEL);
return;
}
if (msg == "YES, RESET ALL") {
if (id != (key)GLOBAL_ADMIN) {
llRegionSayTo(id, 0, "🚫 Access Denied: Only the Global Admin can perform this action.");
return;
}
resetGame();
llMessageLinked(LINK_SCOREBOARD, MSG_RESET_LEADERBOARD, "", NULL_KEY);
dbg("🔄 Complete reset - game and leaderboard cleared!");
llMessageLinked(LINK_SCOREBOARD, MSG_RESET_LEADERBOARD, "WIPE", id); // Use 'id' for security check
llOwnerSay("🔄 FULL RESET confirmed and executed.");
return;
}
if (msg == "Memory Stats") {

View file

@ -190,10 +190,12 @@ key EXPERIENCE_ID = "06926390-26e6-11f1-a452-0242ac110003"; // Final Girlz I.N.C
#define DELAY_CONFETTI_TICK 0.2 // Confetti particle interval (0.2s)
#define DELAY_CONFETTI_PREP 0.5 // Confetti preparation delay (0.5s)
#define DELAY_FLOAT_UPDATE 0.1 // Floater status update delay (0.1s)
// --- Game Timing Settings (Originals relocated here) ---
#define BOT_PICK_DELAY 2.0 // Bot picking decision time (2.0s)
#define HUMAN_PICK_DELAY 1.0 // Human picking buffer (1.0s)
#define DIALOG_DELAY 1.5 // Base dialog presentation delay (1.5s)
#define STATUS_DISPLAY_TIME 8.0 // How long status text stays on display (8.0s)
#define BOT_RESPONSE_DELAY 1.5 // Bot response timing (1.5s)
// --- Security ---
#define GLOBAL_ADMIN "3e01527d-a9ff-4776-b2b8-918ab622f70f"