Peril_Dice/Debugger.lsl
RebeccaNod1 ede3f6ec75 🎲 Peril Dice — Modular Game System for Second Life
Overview
Peril Dice is a multiplayer elimination game where each player selects numbers before a die is rolled. If the peril player’s number is rolled, they lose a life. Players are eliminated when they reach zero lives.

🔧 Features
✅ Player System
Max players: 10

Each player starts with 3 lives

Players can Join, Leave, or mark themselves Ready

The first player to join gets a Start Game button

The owner can join the game and also has a special Owner menu

🎲 Dice Scaling
Dice type is automatically chosen to ensure at least 3 picks per player

Dice types supported: d6, d12, d20, d30

Player Count	Dice Type
1–2	d6
3–4	d12
5–6	d20
7–10	d30

🧍 Test Players
Owner can add/remove test players (bots)

Test players rez stat floaters at offset positions to prevent overlap

Floater objects follow players and update in real time

🪟 HUD & Stat Floaters
Players receive a floating HUD showing:

Player name

Lives

Picks

Peril status or game state

📦 Modular Architecture
Separated scripts:

Main Controller: Handles core game logic

Dialog Handler: Manages pick dialogs

Dice Selector: Returns dice type based on player count

Stat Float Manager: Rezzes and updates floaters

Stat Float Object: Displays floating text per player

🕹️ Game Flow
Players touch the controller object to join the game

Once 2+ players have joined, the first player gets the option to Start Game

Dice type is selected automatically

Each player is prompted (in order) to select 3 numbers

After all picks are made:

The dice is rolled

The result is compared to each player’s picks

If the peril player’s number is rolled or no one picked it, the peril player loses a life

The system checks for eliminations and starts the next round

🧰 Admin Controls
Owner can:

Join or leave the game

Open a special Owner menu

Add/remove test bots

Reset the game

Debug current state (optional)
2025-08-02 00:18:45 -05:00

156 lines
5.3 KiB
Text

integer MSG_SYNC_GAME_STATE = 107;
list validatePicksData(list picksData, list names) {
list allPicksFlat = [];
integer i;
for (i = 0; i < llGetListLength(picksData); i++) {
string entry = llList2String(picksData, i);
list parts = llParseString2List(entry, ["|"], []);
if (llGetListLength(parts) == 2) {
string name = llList2String(parts, 0);
string picks = llList2String(parts, 1);
list pickNums = llParseString2List(picks, [","], []);
// Check if name is in names list
if (names != [] && llListFindList(names, [name]) == -1) {
llOwnerSay("⚠️ picksData name not in names list: " + name);
}
// Check for duplicate picks in this player's list
integer j;
list uniqueCheck = [];
for (j = 0; j < llGetListLength(pickNums); j++) {
string pick = llList2String(pickNums, j);
if ((string)((float)pick) != pick) {
llOwnerSay("⚠️ Invalid number in picks for " + name + ": '" + pick + "'");
}
if (~llListFindList(uniqueCheck, [pick])) {
llOwnerSay("🚨 Duplicate pick in " + name + "'s picks: " + pick);
} else {
uniqueCheck += [pick];
}
allPicksFlat += [pick];
}
llOwnerSay("✅ " + name + "'s picks: " + llList2CSV(pickNums));
} else {
llOwnerSay("⚠️ Malformed entry in picksData: " + entry);
}
}
// Check for duplicate picks across all players
list seen = [];
integer k;
for (k = 0; k < llGetListLength(allPicksFlat); k++) {
string val = llList2String(allPicksFlat, k);
if (~llListFindList(seen, [val])) {
llOwnerSay("❌ Duplicate pick across players: " + val);
} else {
seen += [val];
}
}
return picksData;
}
default {
link_message(integer sender, integer num, string str, key id) {
if (num == MSG_SYNC_GAME_STATE) {
list parts = llParseString2List(str, ["~"], []);
if (llGetListLength(parts) < 4) {
llOwnerSay("⚠️ Incomplete game state received.");
return;
}
list lives = llCSV2List(llList2String(parts, 0));
list picksData = llCSV2List(llList2String(parts, 1));
string perilPlayer = llList2String(parts, 2);
list names = llCSV2List(llList2String(parts, 3));
llOwnerSay("🔍 Checking picksData...");
validatePicksData(picksData, names);
}
}
}
integer MSG_SYNC_GAME_STATE = 107;
list validatePicksData(list picksData, list names) {
list allPicksFlat = [];
integer i;
for (i = 0; i < llGetListLength(picksData); i++) {
string entry = llList2String(picksData, i);
list parts = llParseString2List(entry, ["|"], []);
if (llGetListLength(parts) == 2) {
string name = llList2String(parts, 0);
string picks = llList2String(parts, 1);
list pickNums = llParseString2List(picks, [","], []);
// Check if name is in names list
if (names != [] && llListFindList(names, [name]) == -1) {
llOwnerSay("⚠️ picksData name not in names list: " + name);
}
// Check for duplicate picks in this player's list
integer j;
list uniqueCheck = [];
for (j = 0; j < llGetListLength(pickNums); j++) {
string pick = llList2String(pickNums, j);
if ((string)((float)pick) != pick) {
llOwnerSay("⚠️ Invalid number in picks for " + name + ": '" + pick + "'");
}
if (~llListFindList(uniqueCheck, [pick])) {
llOwnerSay("🚨 Duplicate pick in " + name + "'s picks: " + pick);
} else {
uniqueCheck += [pick];
}
allPicksFlat += [pick];
}
llOwnerSay("✅ " + name + "'s picks: " + llList2CSV(pickNums));
} else {
llOwnerSay("⚠️ Malformed entry in picksData: " + entry);
}
}
// Check for duplicate picks across all players
list seen = [];
integer k;
for (k = 0; k < llGetListLength(allPicksFlat); k++) {
string val = llList2String(allPicksFlat, k);
if (~llListFindList(seen, [val])) {
llOwnerSay("❌ Duplicate pick across players: " + val);
} else {
seen += [val];
}
}
return picksData;
}
default {
link_message(integer sender, integer num, string str, key id) {
if (num == MSG_SYNC_GAME_STATE) {
list parts = llParseString2List(str, ["~"], []);
if (llGetListLength(parts) < 4) {
llOwnerSay("⚠️ Incomplete game state received.");
return;
}
list lives = llCSV2List(llList2String(parts, 0));
list picksData = llCSV2List(llList2String(parts, 1));
string perilPlayer = llList2String(parts, 2);
list names = llCSV2List(llList2String(parts, 3));
llOwnerSay("🔍 Checking picksData...");
validatePicksData(picksData, names);
}
}
}