From 00c849c2085ec291ee63e005cd9f922cac227aa3 Mon Sep 17 00:00:00 2001 From: RebeccaNod1 Date: Tue, 12 Aug 2025 06:28:53 -0500 Subject: [PATCH] removing files that are not needed anymore --- AUTOMATIC_REZ_POSITIONING.md | 175 -------------- Controller_Discovery.lsl | 203 ---------------- FINAL_LINKSET_PLAN.md | 220 ----------------- FIXES_TODO.md | 108 --------- Follower_Script.lsl | 412 -------------------------------- Position_Controller_Timer.lsl | 75 ------ Position_Reset_Instructions.txt | 54 ----- Position_Reset_Tool.lsl | 105 -------- dice | 0 main | 0 scoreboard | 0 11 files changed, 1352 deletions(-) delete mode 100644 AUTOMATIC_REZ_POSITIONING.md delete mode 100644 Controller_Discovery.lsl delete mode 100644 FINAL_LINKSET_PLAN.md delete mode 100644 FIXES_TODO.md delete mode 100644 Follower_Script.lsl delete mode 100644 Position_Controller_Timer.lsl delete mode 100644 Position_Reset_Instructions.txt delete mode 100644 Position_Reset_Tool.lsl delete mode 100644 dice delete mode 100644 main delete mode 100644 scoreboard diff --git a/AUTOMATIC_REZ_POSITIONING.md b/AUTOMATIC_REZ_POSITIONING.md deleted file mode 100644 index 39fb388..0000000 --- a/AUTOMATIC_REZ_POSITIONING.md +++ /dev/null @@ -1,175 +0,0 @@ -# Automatic Rez-Time Position Detection đŸŽ¯ - -## Yes! Displays automatically detect their positions at rez! - -The Peril Dice Game now features **fully automatic position detection** - no config files required, no manual scanning needed. Just rez your displays and they automatically configure themselves! - -## How It Works - -### ✨ **At Rez Time:** -1. Display rez without config notecard -2. Display immediately broadcasts: "I'm a [scoreboard/leaderboard/dice] at position X" -3. Controller receives the request and calculates the relative position -4. Controller responds: "Your offset is Y, your rotation is Z" -5. Display configures itself and announces: "Ready!" - -**Total time: ~1-2 seconds after rez** ⚡ - -### 🔄 **Automatic Retry System:** -- If no controller response in 5 seconds → retry request -- If still no response in 10 seconds → retry again -- Continues until controller found or manually configured - -## Three Positioning Methods - -### 🚀 **Method 1: Automatic Rez Detection (NEW!)** -**Zero interaction required!** -- Rez displays anywhere near controller -- They auto-configure instantly -- **No config files needed** -- **No menu interactions needed** - -### đŸ› ī¸ **Method 2: Manual Position Reset (Enhanced)** -- Position displays manually where you want them -- Owner Menu → đŸ› ī¸ Troubleshooting → Reset Follower Positions -- Automatically updates all display positions -- Still works if auto-rez detection fails - -### 📝 **Method 3: Traditional Config (Legacy)** -- Create config notecard with position values -- Still supported for advanced users -- Overrides automatic detection - -## Technical Implementation - -### Follower Display Side -```lsl -// At rez/state_entry: -if (no_config_notecard) { - // Broadcast auto-config request - llRegionSay(DATA_CHANNEL, "AUTO_CONFIG_REQUEST|scoreboard||"); - // Set retry timer - llSetTimerEvent(5.0); -} - -// When controller responds: -llRegionSay(DATA_CHANNEL, "AUTO_CONFIG_RESPONSE|scoreboard||"); -// Configure self automatically -MY_OFFSET = received_offset; -MY_ROTATION = received_rotation; -``` - -### Controller Side -```lsl -// Listen for auto-config requests -if (msg starts with "AUTO_CONFIG_REQUEST") { - // Calculate relative position - vector offset = (display_pos - controller_pos) / controller_rot; - rotation rel_rot = display_rot / controller_rot; - - // Send response back - llRegionSay(display_channel, "AUTO_CONFIG_RESPONSE|" + type + "|" + offset + "|" + rotation); -} -``` - -## User Experience - -### 🎮 **For Game Owners:** -- **Rez and forget** - displays auto-configure -- See automatic configuration messages in chat -- Manual reset still available if needed -- Works with multiple displays simultaneously - -### 🔧 **For Display Setup:** -- Set `DISPLAY_TYPE = "scoreboard"` in follower script -- Rez display near controller (within ~96 meters) -- Watch it auto-configure in 1-2 seconds -- No config notecard required - -## Configuration Messages - -You'll see messages like: -``` -🎆 Auto-configured scoreboard display at rez! - Position: <128.1, 45.7, 22.0> - Calculated offset: <0.0, 3.0, 0.5> - Calculated rotation: <0.0, 0.0, 0.0, 1.0> -``` - -On display side: -``` -🎆 scoreboard auto-configured successfully! -Auto-detected offset: <0.0, 3.0, 0.5> -Auto-detected rotation: <0.0, 0.0, 0.0, 1.0> -đŸŸĸ Ready and listening for controller movement... -``` - -## Compatibility & Fallbacks - -### ✅ **Multi-Instance Safe** -- Each game table has unique channels -- No interference between multiple setups -- Works with owner-specific dynamic channels - -### đŸ›Ąī¸ **Robust Fallback Chain** -1. **Auto-detection at rez** (preferred) -2. **Manual position reset** (if auto fails) -3. **Config notecard** (traditional method) -4. **Default positions** (as last resort) - -### 🔄 **Migration Friendly** -- Existing config-based displays continue working -- New displays use auto-detection -- Mixed setups supported -- Gradual migration possible - -## Troubleshooting - -### "No controller response - retrying" -- **Cause**: Controller too far away or not running -- **Solution**: Move display closer or ensure controller is active -- **Range**: Typically works within ~50-100 meters - -### Display doesn't auto-configure -- Check `DISPLAY_TYPE` is set correctly in follower script -- Verify controller has Owner Dialog Handler with auto-config support -- Ensure both use same dynamic channel system -- Try manual position reset as backup - -### Multiple displays configure incorrectly -- Auto-detection uses current positions at rez time -- Position displays where you want them BEFORE rezzing -- Use manual reset to adjust positions later - -## Benefits Summary - -### đŸŽ¯ **User Benefits** -- **Zero configuration** - just rez and play -- **Instant setup** - no waiting or manual steps -- **Error-free** - no manual config editing mistakes -- **Intuitive** - works as users expect - -### 🔧 **Technical Benefits** -- **Self-documenting** - positions are automatically calculated -- **Consistent** - eliminates configuration drift -- **Scalable** - works with any number of displays -- **Reliable** - multiple fallback methods - -### 🚀 **Operational Benefits** -- **Faster deployment** - no setup time -- **Reduced support** - fewer configuration issues -- **Better UX** - seamless experience -- **Future-proof** - extensible architecture - ---- - -## The Complete Automation Journey - -**Phase 1** ✅: Manual config files (traditional) -**Phase 2** ✅: Integrated position reset tool (manual scan) -**Phase 3** ✅: Automatic position updates (no manual config editing) -**Phase 4** ✅: **Automatic rez-time detection (zero interaction)** - -**We've achieved full automation!** 🎉 - -Just rez your displays and they work - no config files, no menus, no manual steps required. diff --git a/Controller_Discovery.lsl b/Controller_Discovery.lsl deleted file mode 100644 index 15bb2a8..0000000 --- a/Controller_Discovery.lsl +++ /dev/null @@ -1,203 +0,0 @@ -// === Controller Discovery Helper === -// Handles all controller discovery functionality for the Main Controller -// Also handles automatic position configuration for newly rezzed displays -// Communicates with other scripts via link messages - -// ============================================================================= -// DYNAMIC CHANNEL & DISCOVERY SYSTEM -// ============================================================================= - -// Fixed discovery channel for client objects to find controller -integer DISCOVERY_CHANNEL = -77000; - -// Base channel offset - should match other controller scripts -integer CHANNEL_BASE = -77000; - -// Calculate channels dynamically to avoid hardcoded conflicts -integer calculateChannel(integer offset) { - // Use BOTH owner's key AND object's key to make channels unique per game instance - string ownerStr = (string)llGetOwner(); - string objectStr = (string)llGetKey(); - string combinedStr = ownerStr + objectStr; - - // Create a more unique hash using both keys - string hashStr = llMD5String(combinedStr, 0); - integer hash1 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 0, 0)); - integer hash2 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 1, 1)); - integer combinedHash = hash1 * 16 + hash2; // Creates 0-255 range - - return CHANNEL_BASE - (offset * 1000) - combinedHash; -} - -// Dynamic channel variables for auto-config communication -integer SCOREBOARD_DATA_CHANNEL; -integer LEADERBOARD_DATA_CHANNEL; -integer DICE_DATA_CHANNEL; - -// Client connection tracking -list connectedClients = []; // List of client object keys that have connected -list expectedClientTypes = ["scoreboard", "leaderboard", "dice"]; // Expected client types -integer discoveryBroadcastActive = TRUE; -float DISCOVERY_BROADCAST_INTERVAL = 30.0; // Broadcast availability every 30 seconds - -// Message constants for inter-script communication -integer MSG_DISCOVERY_START = 5001; -integer MSG_DISCOVERY_STOP = 5002; -integer MSG_CLIENT_CONNECTED = 5003; -integer MSG_DISCOVERY_STATUS = 5004; - -// Channel initialization function -initializeChannels() { - SCOREBOARD_DATA_CHANNEL = calculateChannel(6); // ~-83000 range - LEADERBOARD_DATA_CHANNEL = calculateChannel(7); // ~-84000 range - DICE_DATA_CHANNEL = calculateChannel(8); // ~-85000 range - - // Report channels for debugging - llOwnerSay("🔧 [Discovery] Auto-config channels initialized:"); - llOwnerSay(" Scoreboard: " + (string)SCOREBOARD_DATA_CHANNEL); - llOwnerSay(" Leaderboard: " + (string)LEADERBOARD_DATA_CHANNEL); - llOwnerSay(" Dice: " + (string)DICE_DATA_CHANNEL); -} - -default { - state_entry() { - llOwnerSay("📡 [Discovery] Controller Discovery Helper ready!"); - - // Initialize auto-config channels - initializeChannels(); - - // Listen on discovery channel for external objects seeking controller - llListen(DISCOVERY_CHANNEL, "", "", ""); - - // Listen on data channels for auto-config requests - llListen(SCOREBOARD_DATA_CHANNEL, "", "", ""); - llListen(LEADERBOARD_DATA_CHANNEL, "", "", ""); - llListen(DICE_DATA_CHANNEL, "", "", ""); - - // Start broadcasting controller availability - discoveryBroadcastActive = TRUE; - llOwnerSay("đŸ“ē [Discovery] Broadcasting controller availability..."); - llRegionSay(DISCOVERY_CHANNEL, "CONTROLLER_AVAILABLE|" + (string)llGetKey()); // Use controller object key - - // Set timer to periodically announce availability - llSetTimerEvent(DISCOVERY_BROADCAST_INTERVAL); - - // Notify main controller that discovery is active - llMessageLinked(LINK_SET, MSG_DISCOVERY_STATUS, "ACTIVE|" + (string)llGetListLength(connectedClients), NULL_KEY); - } - - listen(integer channel, string name, key id, string msg) { - if (channel == DISCOVERY_CHANNEL) { - if (llSubStringIndex(msg, "FIND_CONTROLLER|") == 0) { - list parts = llParseString2List(msg, ["|"], []); - string objectType = llList2String(parts, 1); - string controllerKey = (string)llGetKey(); // Use actual controller object key - - llOwnerSay("📡 [Discovery] Request from " + objectType + " (" + (string)id + ")"); - llRegionSayTo(id, DISCOVERY_CHANNEL, "CONTROLLER_FOUND|" + controllerKey); - - llOwnerSay("📡 [Discovery] Sent controller key to " + objectType + ": " + controllerKey); - } - else if (llSubStringIndex(msg, "CLIENT_CONNECTED|") == 0) { - // Handle client connection notifications - list parts = llParseString2List(msg, ["|"], []); - if (llGetListLength(parts) >= 3) { - string clientType = llList2String(parts, 1); - key clientKey = (key)llList2String(parts, 2); - - // Track connected client - if (llListFindList(connectedClients, [clientKey]) == -1) { - connectedClients += [clientKey]; - llOwnerSay("✅ [Discovery] " + clientType + " connected (" + (string)clientKey + ")"); - llOwnerSay("🔗 [Discovery] Connected clients: " + (string)llGetListLength(connectedClients)); - - // Notify main controller of connection - llMessageLinked(LINK_SET, MSG_CLIENT_CONNECTED, clientType + "|" + (string)clientKey, NULL_KEY); - - // Check if we should stop broadcasting - if (llGetListLength(connectedClients) >= llGetListLength(expectedClientTypes)) { - llOwnerSay("đŸŽ¯ [Discovery] All expected clients connected - stopping broadcasts"); - discoveryBroadcastActive = FALSE; - llSetTimerEvent(0.0); - - // Notify main controller that discovery is complete - llMessageLinked(LINK_SET, MSG_DISCOVERY_STATUS, "COMPLETE|" + (string)llGetListLength(connectedClients), NULL_KEY); - } else { - // Update status - llMessageLinked(LINK_SET, MSG_DISCOVERY_STATUS, "ACTIVE|" + (string)llGetListLength(connectedClients), NULL_KEY); - } - } - } - } - } - // Handle automatic configuration requests from newly rezzed displays - else if ((channel == SCOREBOARD_DATA_CHANNEL || channel == LEADERBOARD_DATA_CHANNEL || channel == DICE_DATA_CHANNEL) && - llSubStringIndex(msg, "AUTO_CONFIG_REQUEST|") == 0) { - - list parts = llParseString2List(msg, ["|"], []); - if (llGetListLength(parts) >= 4) { - string requestType = llList2String(parts, 1); - vector displayPos = (vector)llList2String(parts, 2); - rotation displayRot = (rotation)llList2String(parts, 3); - - // Calculate offset and rotation relative to controller - vector controller_current_pos = llGetPos(); - rotation controller_current_rot = llGetRot(); - - vector calculatedOffset = (displayPos - controller_current_pos) / controller_current_rot; - rotation calculatedRotation = displayRot / controller_current_rot; - - // Send auto-config response back to the display on the correct channel - integer responseChannel; - if (requestType == "scoreboard") responseChannel = SCOREBOARD_DATA_CHANNEL; - else if (requestType == "leaderboard") responseChannel = LEADERBOARD_DATA_CHANNEL; - else if (requestType == "dice") responseChannel = DICE_DATA_CHANNEL; - else return; // Unknown display type - - string responseMsg = "AUTO_CONFIG_RESPONSE|" + requestType + "|" + - (string)calculatedOffset + "|" + (string)calculatedRotation; - llRegionSay(responseChannel, responseMsg); - - llOwnerSay("🎆 [Discovery] Auto-configured " + requestType + " display at rez!"); - llOwnerSay(" Position: " + (string)displayPos); - llOwnerSay(" Calculated offset: " + (string)calculatedOffset); - llOwnerSay(" Calculated rotation: " + (string)calculatedRotation); - } - } - } - - timer() { - if (discoveryBroadcastActive) { - // Broadcast controller availability - llRegionSay(DISCOVERY_CHANNEL, "CONTROLLER_AVAILABLE|" + (string)llGetKey()); - llSetTimerEvent(DISCOVERY_BROADCAST_INTERVAL); - } else { - llSetTimerEvent(0.0); - } - } - - link_message(integer sender, integer num, string str, key id) { - if (num == MSG_DISCOVERY_START) { - // Restart discovery broadcasts - discoveryBroadcastActive = TRUE; - llOwnerSay("đŸ“ē [Discovery] Restarting broadcasts"); - llRegionSay(DISCOVERY_CHANNEL, "CONTROLLER_AVAILABLE|" + (string)llGetKey()); - llSetTimerEvent(DISCOVERY_BROADCAST_INTERVAL); - } - else if (num == MSG_DISCOVERY_STOP) { - // Stop discovery broadcasts - discoveryBroadcastActive = FALSE; - llSetTimerEvent(0.0); - llOwnerSay("âšī¸ [Discovery] Broadcasts stopped"); - } - else if (num == -99999 && str == "FULL_RESET") { - // Handle full game reset - connectedClients = []; - discoveryBroadcastActive = TRUE; - llOwnerSay("🔄 [Discovery] Reset - restarting broadcasts"); - llRegionSay(DISCOVERY_CHANNEL, "CONTROLLER_AVAILABLE|" + (string)llGetKey()); - llSetTimerEvent(DISCOVERY_BROADCAST_INTERVAL); - llMessageLinked(LINK_SET, MSG_DISCOVERY_STATUS, "ACTIVE|0", NULL_KEY); - } - } -} diff --git a/FINAL_LINKSET_PLAN.md b/FINAL_LINKSET_PLAN.md deleted file mode 100644 index 7985e89..0000000 --- a/FINAL_LINKSET_PLAN.md +++ /dev/null @@ -1,220 +0,0 @@ -# Peril Dice - Single Linkset Conversion ✅ COMPLETED - -**Implementation Date: August 12, 2025** -**Status: FULLY OPERATIONAL** - -## Current Setup -- **Controller**: 1 prim (all game scripts) -- **Scoreboard**: 23 prims (1 root + 1 backboard + 1 actions + 20 player prims) -- **Leaderboard**: ~48 prims (XyzzyText display) -- **Dice Display**: 2 prims - -## Linking Process (Correct SL Order) - -### Selection Order: -1. **Select Dice Display FIRST** → Gets highest link numbers (end of chain) -2. **Select Leaderboard SECOND** → Gets middle link numbers -3. **Select Scoreboard THIRD** → Gets lower link numbers -4. **Select Controller LAST** → Becomes ROOT PRIM (Link 1) - -### Resulting Link Structure: -``` -Link 1: Controller (Root) ← Last selected -├── Links 2-24: Scoreboard ← Third selected (23 prims) -│ ├── Link 2: Scoreboard root (script here) -│ ├── Link 3: Background prim -│ ├── Link 4: Actions/Status prim -│ └── Links 5-24: Player prims (20 prims - 2 per player) -├── Links 25-72: Leaderboard ← Second selected (~48 prims) -└── Links 73-74: Dice Display ← First selected (2 prims) -``` - -## Script Placement & Communication - -### Controller Scripts (Link 1 - Root) -**Keep ALL existing game scripts here:** -- `Main_Controller.lsl` -- `Game_Manager.lsl` -- `Bot_Manager.lsl` -- `Controller_Memory.lsl` -- All other controller scripts... - -**Communication changes in controller scripts:** -```lsl -// OLD (cross-object): -llRegionSay(SCOREBOARD_CHANNEL_1, "GAME_STATUS|Victory"); -llRegionSay(SCOREBOARD_CHANNEL_2, "PLAYER_UPDATE|John|3|uuid"); -llRegionSay(SCOREBOARD_CHANNEL_3, "DICE_ROLL|John|5"); - -// NEW (link messages): -llMessageLinked(2, MSG_GAME_STATUS, "Victory", NULL_KEY); // To scoreboard -llMessageLinked(2, MSG_PLAYER_UPDATE, "John|3|uuid", NULL_KEY); // To scoreboard -llMessageLinked(73, MSG_DICE_ROLL, "John|5", NULL_KEY); // To dice display -llMessageLinked(25, MSG_GAME_WON, "John", NULL_KEY); // To leaderboard -``` - -### Scoreboard Manager (Link 2) -**Modified `Game_Scoreboard_Manager.lsl`:** - -**Critical Update Required - Prim Index Mapping:** -```lsl -// OLD prim indices (when scoreboard was standalone): -integer BACKGROUND_PRIM = 2; // Was link 2 -integer ACTIONS_PRIM = 3; // Was link 3 -integer FIRST_PLAYER_PRIM = 4; // Was link 4 -// integer LAST_PLAYER_PRIM = 23; // Was link 23 (last of 20 player prims) - -// NEW prim indices (when scoreboard is part of larger linkset): -integer BACKGROUND_PRIM = 3; // Now link 3 (2+1) -integer ACTIONS_PRIM = 4; // Now link 4 (3+1) -integer FIRST_PLAYER_PRIM = 5; // Now link 5 (4+1) -integer LAST_PLAYER_PRIM = 24; // Now link 24 (5+19, last of 20 player prims) -// Player prims now span links 5-24 instead of 4-23 -``` - -```lsl -default { - state_entry() { - // No need for setupPlayerGrid() - prims already positioned from linking - loadLeaderboardData(); - llOwnerSay("📊 Scoreboard ready - managing prims " + (string)FIRST_PLAYER_PRIM + "-" + (string)LAST_PLAYER_PRIM); - } - - link_message(integer sender, integer num, string str, key id) { - if (sender != 1) return; // Only listen to controller - - if (num == MSG_GAME_STATUS) { - updateActionsPrim(str); - } - else if (num == MSG_PLAYER_UPDATE) { - list parts = llParseString2List(str, ["|"], []); - string name = llList2String(parts, 0); - integer lives = (integer)llList2String(parts, 1); - key uuid = (key)llList2String(parts, 2); - updatePlayerDisplay(name, lives, uuid); - } - else if (num == MSG_CLEAR_GAME) { - clearAllPlayers(); - updateActionsPrim("Title"); - } - } -} -``` - -### Leaderboard Manager (Link 25) -**Modified `Leaderboard_Communication_Clean.lsl`:** -```lsl -default { - state_entry() { - // Initialize XyzzyText on links 25-72 - initializeLeaderboard(); - } - - link_message(integer sender, integer num, string str, key id) { - if (sender != 1) return; // Only from controller - - if (num == MSG_GAME_WON) { - handleGameWon(str); - } - else if (num == MSG_GAME_LOST) { - handleGameLost(str); - } - else if (num == MSG_RESET_LEADERBOARD) { - resetLeaderboard(); - } - } -} -``` - -### Dice Display Manager (Link 71) -**Modified `XyzzyText_Dice_Bridge.lsl`:** -```lsl -default { - state_entry() { - // Initialize dice display on links 71-72 - initializeDiceDisplay(); - } - - link_message(integer sender, integer num, string str, key id) { - if (sender != 1) return; // Only from controller - - if (num == MSG_DICE_ROLL) { - list parts = llParseString2List(str, ["|"], []); - string player = llList2String(parts, 0); - integer value = (integer)llList2String(parts, 1); - showDiceRoll(player, value); - } - else if (num == MSG_CLEAR_DICE) { - clearDiceDisplay(); - } - } -} -``` - -## Message Constants (Add to ALL scripts) -```lsl -// Scoreboard messages (to link 2) -integer MSG_GAME_STATUS = 3001; -integer MSG_PLAYER_UPDATE = 3002; -integer MSG_CLEAR_GAME = 3003; - -// Leaderboard messages (to link 25) -integer MSG_GAME_WON = 3010; -integer MSG_GAME_LOST = 3011; -integer MSG_RESET_LEADERBOARD = 3012; - -// Dice messages (to link 73) -integer MSG_DICE_ROLL = 3020; -integer MSG_CLEAR_DICE = 3021; -``` - -## Code Removal (From ALL display scripts) -**Remove these completely:** -- âœ‚ī¸ Controller discovery system (`startControllerDiscovery()`, etc.) -- âœ‚ī¸ Dynamic channel calculations (`calculateChannel()`, etc.) -- âœ‚ī¸ All `llListen()` and `listen()` handlers -- âœ‚ī¸ Channel variables (`SCOREBOARD_CHANNEL`, etc.) -- âœ‚ī¸ Discovery timers and retry logic -- âœ‚ī¸ `llRegionSay()` responses - -## Benefits Summary - -✅ **50%+ Performance Improvement**: Link messages vs region chat -✅ **Zero Channel Conflicts**: No channel management needed -✅ **Single Object Deployment**: One object to rez/position -✅ **Bulletproof Reliability**: No discovery failures -✅ **Easier Maintenance**: All components linked together -✅ **Reduced Memory Usage**: Remove discovery & channel code -✅ **Simplified Setup**: No positioning multiple objects - -## Implementation Results ✅ COMPLETED - -**Final Testing Results:** -- ✅ Game starts with multiple players -- ✅ Scoreboard shows player hearts correctly -- ✅ Leaderboard updates with wins/losses -- ✅ Dice display shows rolls correctly -- ✅ Status messages appear on scoreboard -- ✅ Game reset clears all displays -- ✅ All floater HUDs still work -- ✅ Bot players function normally -- ✅ Dice type synchronization fixed -- ✅ Win condition loops resolved -- ✅ Communication architecture stable - -## Additional Improvements Implemented -- **Dice Type Synchronization**: Fixed race conditions between Game Manager and Roll Module -- **Targeted Calculator Responses**: Calculator now responds only to requesting module -- **Win Loop Prevention**: Game properly stops when only one player remains -- **Module Independence**: Clean separation of responsibilities between components -- **Enhanced Game Flow**: Improved round completion detection and continuation logic - -## Final Timeline (Actual) -- **Architecture Planning**: 4 hours -- **Script modifications**: 6 hours (expanded scope) -- **Physical linking**: 30 minutes -- **Testing & debugging**: 3 hours -- **Bug fixes & refinements**: 4 hours -- **Total**: ~17.5 hours - -**Result**: The game system is now significantly more robust, professional, and reliable than the original multi-object design! diff --git a/FIXES_TODO.md b/FIXES_TODO.md deleted file mode 100644 index ded2976..0000000 --- a/FIXES_TODO.md +++ /dev/null @@ -1,108 +0,0 @@ -# PERIL DICE GAME - REMAINING FIXES TODO - -## ✅ COMPLETED -- [x] **Listen Handle Leaks** - Fixed in all scripts with proper cleanup and management -- [x] **Timer Event Conflicts** - Fixed in Main.lsl with unified timer system using TIMER_IDLE, TIMER_STATUS, TIMER_TIMEOUT states -- [x] **Race Condition in Dialog Recovery** - Fixed in Owner and Player Dialog Handler.lsl with request ID tracking, timeout validation, and stale response detection -- [x] **Bot Validation Logic Gaps** - Fixed in Bot Manager.lsl with improved algorithm, availability calculation, graceful degradation, and memory monitoring -- [x] **Memory Usage Monitoring** - Implemented in Main.lsl with memory checks at critical points, warnings at 80%, emergency cleanup at 90%, and owner-accessible memory stats -- [x] **Channel Number Conflicts** - Implemented dynamic channel configuration in Main.lsl with owner-unique channels, collision avoidance, and backward compatibility - -## ✅ ALL CRITICAL FIXES COMPLETED - -### 📡 LATEST ADDITION (v2.6.0) - Advanced Channel Management & Debug Cleanup ✅ **COMPLETED** -**Files:** ALL major scripts (`Main.lsl`, `Bot_Manager.lsl`, `Floater_Manager.lsl`, etc.) -**Was:** Potential channel conflicts between multiple instances + verbose debug output spam -**Fixed:** -- **Enhanced Dynamic Channel System**: Implemented sophisticated per-instance channel calculation - - Uses combined hash of owner key + object key for complete uniqueness - - Prevents interference between multiple game tables owned by same person - - MD5-based hash generation creates 0-255 range distribution across all channel ranges - - Each component gets isolated channel space (~-78000 to ~-86000 ranges) -- **Professional Debug Output Cleanup**: Removed verbose debug messages causing console spam - - Main Controller: Eliminated touch event and dice result debug logging - - Floater Manager: Removed picks data, cleanup confirmations, and sync debug messages - - Preserved essential error reporting while eliminating noise - - Professional-grade logging suitable for production deployment -- **Multi-Instance Production Ready**: Game system now supports multiple concurrent deployments -- **Channel Debugging Tools**: Detailed channel assignments reported to owner on startup - ---- - -### 5. ~~Memory Usage Concerns~~ ✅ **COMPLETED** -**Files:** `Main.lsl` -**Was:** Large lists stored without memory monitoring -**Fixed:** -- Added `llGetUsedMemory()` checks in critical functions (`updateHelpers`, `player_registration`) -- Memory warnings at 80% usage with 60-second intervals to prevent spam -- Emergency cleanup at 90% usage with list optimization and garbage collection -- Owner-accessible "Memory Stats" command in dialog system -- Comprehensive memory reporting showing usage by data structure - ---- - -### 6. ~~Channel Number Conflicts~~ ✅ **COMPLETED** ⭐ **MULTI-INSTANCE SAFE** -**Files:** `Main.lsl`, `ChannelConfig.lsl`, `Bot Manager.lsl`, `Roll Confetti Module.lsl`, `Game Manager.lsl`, `Owner and Player Dialog Handler.lsl`, `Number Picker Dialog Handler.lsl`, `Helper.lsl`, `Game_Scoreboard_Manager.lsl` -**Was:** Hard-coded channels could conflict with other LSL objects AND multiple instances by same owner would interfere -**Fixed:** -- Implemented **ENHANCED** dynamic channel calculation using BOTH owner key AND object key hashing for complete per-instance uniqueness across ALL scripts -- Created centralized channel configuration system in ChannelConfig.lsl -- Updated Main.lsl to use dynamic channels for all communications: - - Sync, Dialog, Roll Dialog, Bot Commands (calculated ranges ~-77100 to ~-77500) - - Scoreboard channels (3 separate channels for different message types) - - Floater base channels with dynamic indexing -- Updated ALL supporting scripts with dynamic channel configuration: - - Bot Manager: Dynamic bot command channel (~-77500 range) - - Roll Confetti Module: Dynamic scoreboard channels for status/dice display - - Owner/Player Dialog Handler: Dynamic main dialog channel (~-77400 range) - - Number Picker Dialog Handler: Dynamic number pick channel (~-77200 range) - - Game_Scoreboard_Manager: All 3 scoreboard channels dynamically configured - - Helper: Removed hardcoded dialog usage, delegated to proper handlers -- Added collision avoidance through owner-specific hash offsets -- Maintained backward compatibility with legacy channel variables where needed -- Added comprehensive channel reporting for debugging across all scripts -- **COMPREHENSIVE SCAN COMPLETED**: All hardcoded channels eliminated from critical scripts - ---- - -## đŸŽ¯ IMPLEMENTATION ORDER - -### Phase 1: Critical Functionality (✅ COMPLETED) -1. ✅ **Timer Event Conflicts** - COMPLETED -2. ✅ **Dialog Race Conditions** - COMPLETED - -### Phase 2: Edge Case Handling (✅ COMPLETED) -3. ✅ **Bot Validation Logic** - COMPLETED -4. ✅ **Memory Usage Monitoring** - COMPLETED - -### Phase 3: Compatibility (✅ COMPLETED) -5. ✅ **Channel Number Conflicts** - COMPLETED - ---- - -## 📋 TESTING CHECKLIST - -After each fix, test: -- [ ] Game starts properly with 2-10 players -- [ ] Status messages display and clear correctly -- [ ] Dialogs show to correct players -- [ ] Bots pick appropriate numbers of picks -- [ ] Memory usage stays reasonable during long games -- [ ] No channel conflicts with other objects -- [ ] Game resets work properly -- [ ] All error conditions handled gracefully - ---- - -## 🚨 NOTES - -- **Backup all scripts before making changes** -- **Test each fix individually before moving to next** -- **Monitor error logs during testing** -- **Check memory usage with `llGetUsedMemory()` during testing** -- **Test with maximum players (10) to stress test** - ---- - -*Created: 2025-01-08* -*Status: Ready for implementation* diff --git a/Follower_Script.lsl b/Follower_Script.lsl deleted file mode 100644 index 7ecdad7..0000000 --- a/Follower_Script.lsl +++ /dev/null @@ -1,412 +0,0 @@ -// Peril Game Display Follower Script - Config Version -// This script reads position settings from a "config" notecard -// Change DISPLAY_TYPE below to match your display object - -string DISPLAY_TYPE = "scoreboard"; // Change to: "scoreboard", "leaderboard", or "dice" - -// ============================================================================= -// CONTROLLER DISCOVERY SYSTEM -// ============================================================================= - -// Fixed discovery channel for finding controller -integer DISCOVERY_CHANNEL = -77000; - -// Base channel offset - should match Main.lsl -integer CHANNEL_BASE = -77000; - -// Controller discovery state -key CONTROLLER_KEY = NULL_KEY; -integer DISCOVERY_ATTEMPTS = 0; -integer MAX_DISCOVERY_ATTEMPTS = 10; -integer AUTO_CONFIG_ATTEMPTS = 0; -integer MAX_AUTO_CONFIG_ATTEMPTS = 5; -integer INITIALIZED = FALSE; // Flag to prevent multiple initializations - -// Calculate channels dynamically using controller key for consistency -integer calculateChannelWithController(integer offset, key controllerKey) { - // Use owner's key AND CONTROLLER's object key to ensure all objects use same channels - // This should match the calculateChannel method in Controller_Discovery.lsl - string ownerStr = (string)llGetOwner(); - string controllerObjStr = (string)controllerKey; // This is the controller object key - string combinedStr = ownerStr + controllerObjStr; - - // Create a more unique hash using both keys - string hashStr = llMD5String(combinedStr, 0); - integer hash1 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 0, 0)); - integer hash2 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 1, 1)); - integer combinedHash = hash1 * 16 + hash2; // Creates 0-255 range - - return CHANNEL_BASE - (offset * 1000) - combinedHash; -} - -// Legacy function for backward compatibility (uses own key) -integer calculateChannel(integer offset) { - string ownerStr = (string)llGetOwner(); - string objectStr = (string)llGetKey(); - string combinedStr = ownerStr + objectStr; - - string hashStr = llMD5String(combinedStr, 0); - integer hash1 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 0, 0)); - integer hash2 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 1, 1)); - integer combinedHash = hash1 * 16 + hash2; - - return CHANNEL_BASE - (offset * 1000) - combinedHash; -} - -// Channel mapping for different display types (with controller discovery) -integer getDataChannelForType(string displayType) { - if (CONTROLLER_KEY != NULL_KEY) { - // Use controller-based channels for consistency - if (displayType == "scoreboard") return calculateChannelWithController(6, CONTROLLER_KEY); // SCOREBOARD_CHANNEL_1 - else if (displayType == "leaderboard") return calculateChannelWithController(7, CONTROLLER_KEY); // SCOREBOARD_CHANNEL_2 - else if (displayType == "dice") return calculateChannelWithController(8, CONTROLLER_KEY); // SCOREBOARD_CHANNEL_3 - else return calculateChannelWithController(1, CONTROLLER_KEY); // Default to sync channel - } else { - // Fallback to legacy calculation during discovery - if (displayType == "scoreboard") return calculateChannel(6); // SCOREBOARD_CHANNEL_1 - else if (displayType == "leaderboard") return calculateChannel(7); // SCOREBOARD_CHANNEL_2 - else if (displayType == "dice") return calculateChannel(8); // SCOREBOARD_CHANNEL_3 - else return calculateChannel(1); // Default to sync channel - } -} - -// Controller discovery function -startControllerDiscovery() { - llOwnerSay("📡 [" + DISPLAY_TYPE + "] Starting controller discovery..."); - - // Listen on discovery channel - llListen(DISCOVERY_CHANNEL, "", "", ""); - - // Broadcast discovery request - llRegionSay(DISCOVERY_CHANNEL, "FIND_CONTROLLER|" + DISPLAY_TYPE); - - // Reset discovery attempts - DISCOVERY_ATTEMPTS = 0; - - // Set timer for retry if needed - llSetTimerEvent(5.0); -} - -// These will be loaded from config notecard -vector MY_OFFSET; -rotation MY_ROTATION; -integer MY_CHANNEL; -integer MY_DATA_CHANNEL; - -// Controller tracking -key master_key; -vector last_master_pos; -rotation last_master_rot; - -// Config reading -integer config_line = 0; -key config_query; - -// Function to initialize channels and config after controller discovery -initializeAfterDiscovery() { - if (CONTROLLER_KEY != NULL_KEY) { - llOwnerSay("🆗 [" + DISPLAY_TYPE + "] Controller found! Initializing channels..."); - } else { - llOwnerSay("âš ī¸ [" + DISPLAY_TYPE + "] Initializing in legacy mode (no controller found)..."); - } - - // Update channels with controller key (or legacy channels if NULL) - if (CONTROLLER_KEY != NULL_KEY) { - MY_CHANNEL = calculateChannelWithController(1, CONTROLLER_KEY); // Position sync channel - MY_DATA_CHANNEL = getDataChannelForType(DISPLAY_TYPE); - } else { - // Use legacy channels when no controller found - MY_CHANNEL = calculateChannel(1); // Position sync channel - MY_DATA_CHANNEL = getDataChannelForType(DISPLAY_TYPE); // This will use legacy calculation - } - - llOwnerSay("🔧 [" + DISPLAY_TYPE + "] Dynamic channels initialized:"); - llOwnerSay(" Position sync: " + (string)MY_CHANNEL); - llOwnerSay(" Data channel: " + (string)MY_DATA_CHANNEL); - - // Start reading config notecard or use auto-detection - if (llGetInventoryType("config") == INVENTORY_NOTECARD) { - llOwnerSay("📜 Reading config notecard..."); - config_query = llGetNotecardLine("config", 0); - config_line = 0; - } else if (CONTROLLER_KEY != NULL_KEY) { - // Only try auto-detection if we have a controller - llOwnerSay("âš ī¸ No 'config' notecard found - using auto-detection mode!"); - llOwnerSay("📍 Looking for controller to auto-configure position..."); - - // Set up listeners for auto-detection with correct channels - llListen(MY_CHANNEL, "", "", ""); // Position sync channel - llListen(MY_DATA_CHANNEL, "", "", ""); // Data/scan channel - - // Request auto-configuration from controller - llRegionSay(MY_DATA_CHANNEL, "AUTO_CONFIG_REQUEST|" + DISPLAY_TYPE + "|" + - (string)llGetPos() + "|" + (string)llGetRot()); - - // Reset auto-config retry counter - AUTO_CONFIG_ATTEMPTS = 0; - - // Set a timer to retry if no response - llSetTimerEvent(5.0); - } else { - // No controller and no config - just set up basic listeners in legacy mode - llOwnerSay("âš ī¸ [" + DISPLAY_TYPE + "] No controller or config found - legacy mode with default positioning"); - - // Set up listeners for legacy mode - llListen(MY_CHANNEL, "", "", ""); // Position sync channel - llListen(MY_DATA_CHANNEL, "", "", ""); // Data/scan channel - - // Set default positioning values - MY_OFFSET = <0.0, 0.0, 0.0>; - MY_ROTATION = <0.0, 0.0, 0.0, 1.0>; - - llOwnerSay("🔄 [" + DISPLAY_TYPE + "] Ready in legacy mode - listening for position updates"); - } - - // Mark as initialized to prevent repeated initialization - INITIALIZED = TRUE; -} - -default { - state_entry() { - llOwnerSay("🎮 Starting " + DISPLAY_TYPE + " follower - discovering controller..."); - - // Start controller discovery first - startControllerDiscovery(); - } - - dataserver(key query_id, string data) { - if (query_id == config_query) { - if (data == EOF) { - // Finished reading config - llOwnerSay("🔧 [" + DISPLAY_TYPE + " Follower] Dynamic channels initialized:"); - llOwnerSay(" Position sync: " + (string)MY_CHANNEL); - llOwnerSay(" Data channel: " + (string)MY_DATA_CHANNEL); - llOwnerSay(DISPLAY_TYPE + " config loaded. Listening for controller..."); - llListen(MY_CHANNEL, "", "", ""); // Position sync channel - llListen(MY_DATA_CHANNEL, "", "", ""); // Data/scan channel - llRegionSay(MY_CHANNEL, "FOLLOWER_READY|" + DISPLAY_TYPE); - } else if (data != "") { - // Parse config line - data = llStringTrim(data, STRING_TRIM); - if (llGetSubString(data, 0, 0) != "#") { // Skip comments - integer eq_pos = llSubStringIndex(data, "="); - if (eq_pos != -1) { - string config_key = llStringTrim(llGetSubString(data, 0, eq_pos - 1), STRING_TRIM); - string value = llStringTrim(llGetSubString(data, eq_pos + 1, -1), STRING_TRIM); - - - // Load values for this display type - if (config_key == DISPLAY_TYPE + "_offset") { - MY_OFFSET = (vector)value; - } else if (config_key == DISPLAY_TYPE + "_rotation") { - MY_ROTATION = (rotation)value; - } else if (config_key == DISPLAY_TYPE + "_channel") { - if (value == "DYNAMIC") { - MY_CHANNEL = calculateChannel(1); // Position sync channel - } else { - MY_CHANNEL = (integer)value; // Legacy hardcoded channel - } - } else if (config_key == DISPLAY_TYPE + "_data_channel") { - if (llSubStringIndex(value, "DYNAMIC") == 0) { - MY_DATA_CHANNEL = getDataChannelForType(DISPLAY_TYPE); - } else { - MY_DATA_CHANNEL = (integer)value; // Legacy hardcoded channel - } - } - } - } - - // Read next line - config_line++; - config_query = llGetNotecardLine("config", config_line); - } else { - // Read next line even if this one is empty - config_line++; - config_query = llGetNotecardLine("config", config_line); - } - } - } - - listen(integer channel, string name, key id, string msg) { - // Handle controller discovery responses - if (channel == DISCOVERY_CHANNEL) { - if (llSubStringIndex(msg, "CONTROLLER_FOUND|") == 0) { - list parts = llParseString2List(msg, ["|"], []); - CONTROLLER_KEY = (key)llList2String(parts, 1); - - llOwnerSay("✅ [" + DISPLAY_TYPE + "] Controller discovered: " + (string)CONTROLLER_KEY); - - // Cancel discovery timer - llSetTimerEvent(0.0); - - // Initialize with controller key - initializeAfterDiscovery(); - return; - } - else if (llSubStringIndex(msg, "CONTROLLER_AVAILABLE|") == 0) { - // Handle broadcast availability messages - but only if not already initialized - if (INITIALIZED) { - // Already initialized, ignore repeated availability messages - return; - } - - list parts = llParseString2List(msg, ["|"], []); - CONTROLLER_KEY = (key)llList2String(parts, 1); - - llOwnerSay("✅ [" + DISPLAY_TYPE + "] Controller available: " + (string)CONTROLLER_KEY); - - // Cancel discovery timer - llSetTimerEvent(0.0); - - // Initialize with controller key - initializeAfterDiscovery(); - return; - } - } - - if (channel == MY_CHANNEL) { - if (llSubStringIndex(msg, "CONTROLLER_MOVE|") == 0) { - list parts = llParseString2List(msg, ["|"], []); - master_key = (key)llList2String(parts, 1); - vector master_pos = (vector)llList2String(parts, 2); - rotation master_rot = (rotation)llList2String(parts, 3); - - // Calculate new position - vector new_pos = master_pos + (MY_OFFSET * master_rot); - rotation new_rot = MY_ROTATION * master_rot; - - llSetPos(new_pos); - llSetRot(new_rot); - - last_master_pos = master_pos; - last_master_rot = master_rot; - } - } else if (channel == MY_DATA_CHANNEL) { - if (llSubStringIndex(msg, "POSITION_SCAN|") == 0) { - // Respond to position scan for reset tool - llRegionSay(MY_DATA_CHANNEL, "POSITION_RESPONSE|" + DISPLAY_TYPE + "|" + - (string)llGetPos() + "|" + (string)llGetRot()); - } - else if (llSubStringIndex(msg, "POSITION_UPDATE|") == 0) { - // Handle automatic position updates from integrated reset tool - list parts = llParseString2List(msg, ["|"], []); - if (llGetListLength(parts) >= 4) { - string updateType = llList2String(parts, 1); - if (updateType == DISPLAY_TYPE) { - vector newOffset = (vector)llList2String(parts, 2); - rotation newRotation = (rotation)llList2String(parts, 3); - - // Update our stored offset and rotation - MY_OFFSET = newOffset; - MY_ROTATION = newRotation; - - llOwnerSay("✨ " + DISPLAY_TYPE + " position updated automatically!"); - llOwnerSay("New offset: " + (string)MY_OFFSET); - llOwnerSay("New rotation: " + (string)MY_ROTATION); - - // If we have a master position, update our position immediately - if (master_key != NULL_KEY) { - vector new_pos = last_master_pos + (MY_OFFSET * last_master_rot); - rotation new_rot = MY_ROTATION * last_master_rot; - llSetPos(new_pos); - llSetRot(new_rot); - llOwnerSay("đŸŽĨ Moved to new position!"); - } - - // Cancel retry timer if we got a successful update - llSetTimerEvent(0.0); - } - } - } - else if (llSubStringIndex(msg, "AUTO_CONFIG_RESPONSE|") == 0) { - // Handle automatic configuration response from controller - list parts = llParseString2List(msg, ["|"], []); - if (llGetListLength(parts) >= 4) { - string responseType = llList2String(parts, 1); - if (responseType == DISPLAY_TYPE) { - vector autoOffset = (vector)llList2String(parts, 2); - rotation autoRotation = (rotation)llList2String(parts, 3); - - // Set our position values from auto-detection - MY_OFFSET = autoOffset; - MY_ROTATION = autoRotation; - - llOwnerSay("🎆 " + DISPLAY_TYPE + " auto-configured successfully!"); - llOwnerSay("Auto-detected offset: " + (string)MY_OFFSET); - llOwnerSay("Auto-detected rotation: " + (string)MY_ROTATION); - llOwnerSay("đŸŸĸ Ready and listening for controller movement..."); - - // Cancel retry timer - llSetTimerEvent(0.0); - - // Announce readiness - llRegionSay(MY_CHANNEL, "FOLLOWER_READY|" + DISPLAY_TYPE); - } - } - } - } - } - - timer() { - if (CONTROLLER_KEY == NULL_KEY) { - // Still in controller discovery phase - DISCOVERY_ATTEMPTS++; - - if (DISCOVERY_ATTEMPTS <= MAX_DISCOVERY_ATTEMPTS) { - llOwnerSay("🔄 [" + DISPLAY_TYPE + "] Retrying controller discovery (attempt " + - (string)DISCOVERY_ATTEMPTS + "/" + (string)MAX_DISCOVERY_ATTEMPTS + ")..."); - - // Retry controller discovery - llRegionSay(DISCOVERY_CHANNEL, "FIND_CONTROLLER|" + DISPLAY_TYPE); - - // Set timer for next retry (exponential backoff) - float retryDelay = 5.0 * DISCOVERY_ATTEMPTS; // 5s, 10s, 15s, etc. - llSetTimerEvent(retryDelay); - } else { - llOwnerSay("❌ [" + DISPLAY_TYPE + "] Controller discovery failed after " + - (string)MAX_DISCOVERY_ATTEMPTS + " attempts"); - llOwnerSay(" Operating in legacy mode with owner-based channels"); - - // Stop timer and initialize with legacy channels - llSetTimerEvent(0.0); - initializeAfterDiscovery(); // This will use legacy channels since CONTROLLER_KEY is NULL - } - } else { - // Controller found, retry auto-configuration request with limit - AUTO_CONFIG_ATTEMPTS++; - - if (AUTO_CONFIG_ATTEMPTS <= MAX_AUTO_CONFIG_ATTEMPTS) { - llOwnerSay("🔄 [" + DISPLAY_TYPE + "] No auto-config response - retrying (" + - (string)AUTO_CONFIG_ATTEMPTS + "/" + (string)MAX_AUTO_CONFIG_ATTEMPTS + ")..."); - - if (MY_DATA_CHANNEL != 0) { - llRegionSay(MY_DATA_CHANNEL, "AUTO_CONFIG_REQUEST|" + DISPLAY_TYPE + "|" + - (string)llGetPos() + "|" + (string)llGetRot()); - } else { - llOwnerSay("âš ī¸ [" + DISPLAY_TYPE + "] Data channel not initialized yet!"); - } - - // Set timer for next retry (10 seconds) - llSetTimerEvent(10.0); - } else { - llOwnerSay("❌ [" + DISPLAY_TYPE + "] Auto-config failed after " + (string)MAX_AUTO_CONFIG_ATTEMPTS + " attempts"); - llOwnerSay("🔄 [" + DISPLAY_TYPE + "] Using default position - ready for manual configuration"); - - // Stop timer and set default positioning - llSetTimerEvent(0.0); - - // Set default positioning values - MY_OFFSET = <0.0, 0.0, 0.0>; - MY_ROTATION = <0.0, 0.0, 0.0, 1.0>; - - // Announce readiness with default positioning - llRegionSay(MY_CHANNEL, "FOLLOWER_READY|" + DISPLAY_TYPE); - llOwnerSay("đŸ›Ģ [" + DISPLAY_TYPE + "] Ready and listening for controller movement (default position)"); - } - } - } - - on_rez(integer start_param) { - llResetScript(); - } -} diff --git a/Position_Controller_Timer.lsl b/Position_Controller_Timer.lsl deleted file mode 100644 index 55822fb..0000000 --- a/Position_Controller_Timer.lsl +++ /dev/null @@ -1,75 +0,0 @@ -// Position Controller - Master Object -// Add this to your controller object -// When it moves, all follower objects will maintain relative positions - -// ============================================================================= -// DYNAMIC CHANNEL CONFIGURATION -// ============================================================================= - -// Base channel offset - should match Main.lsl -integer CHANNEL_BASE = -77000; - -// Calculate channels dynamically to avoid hardcoded conflicts -integer calculateChannel(integer offset) { - // Use BOTH owner's key AND object's key to make channels unique per game instance - // This prevents interference when same owner has multiple game tables - string ownerStr = (string)llGetOwner(); - string objectStr = (string)llGetKey(); - string combinedStr = ownerStr + objectStr; - - // Create a more unique hash using both keys - string hashStr = llMD5String(combinedStr, 0); - integer hash1 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 0, 0)); - integer hash2 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 1, 1)); - integer combinedHash = hash1 * 16 + hash2; // Creates 0-255 range - - return CHANNEL_BASE - (offset * 1000) - combinedHash; -} - -integer SYNC_CHANNEL; -vector lastPos; -rotation lastRot; - -default { - state_entry() { - // Initialize dynamic channels - SYNC_CHANNEL = calculateChannel(1); // ~-78000 range - - llOwnerSay("🔧 [Position Controller] Dynamic channel initialized: " + (string)SYNC_CHANNEL); - llOwnerSay("Position Controller active - other objects will follow when this moves"); - lastPos = llGetPos(); - lastRot = llGetRot(); - llSetTimerEvent(0.5); // Check position every 0.5 seconds - } - - moving_start() { - // Optional: notify when starting to move - llOwnerSay("Moving game system..."); - } - - moving_end() { - // When movement stops, broadcast new position - vector pos = llGetPos(); - rotation rot = llGetRot(); - llRegionSay(SYNC_CHANNEL, "CONTROLLER_MOVE|" + (string)llGetKey() + "|" + (string)pos + "|" + (string)rot); - llOwnerSay("Game system repositioned"); - } - - timer() { - vector currentPos = llGetPos(); - rotation currentRot = llGetRot(); - - // Check if position or rotation has changed significantly - if (llVecDist(currentPos, lastPos) > 0.01 || - llAngleBetween(currentRot, lastRot) > 0.01) { - - lastPos = currentPos; - lastRot = currentRot; - llRegionSay(SYNC_CHANNEL, "CONTROLLER_MOVE|" + (string)llGetKey() + "|" + (string)currentPos + "|" + (string)currentRot); - } - } - - on_rez(integer start_param) { - llResetScript(); - } -} diff --git a/Position_Reset_Instructions.txt b/Position_Reset_Instructions.txt deleted file mode 100644 index 990976d..0000000 --- a/Position_Reset_Instructions.txt +++ /dev/null @@ -1,54 +0,0 @@ -PERIL GAME POSITION RESET KIT -============================= - -If your leaderboard, scoreboard, or dice display gets knocked out of position, -use this simple tool to recalibrate them. - -WHAT'S INCLUDED: -- Position_Reset_Tool.lsl (temporary calibration script) -- config (updated configuration notecard) - -HOW TO RECALIBRATE POSITIONS: -============================ - -1. POSITION YOUR DISPLAYS - - Move each display object to where you want it positioned - - Make sure they're all within 20 meters of the controller - -2. DROP RESET TOOL IN CONTROLLER - - Put Position_Reset_Tool.lsl into your controller object - -3. SCAN POSITIONS - - Click the controller object - - It will scan and give you new config values like: - scoreboard_offset=<1.234, 5.678, 0.000> - leaderboard_offset=<-2.345, 0.000, 1.500> - dice_offset=<3.456, 0.000, 0.000> - -4. UPDATE CONFIG NOTECARDS - - Edit the "config" notecard in each display object - - Replace the old offset values with the new ones - - Save the notecard - -5. CLEAN UP - - Remove Position_Reset_Tool.lsl from your controller - - Your displays will automatically move to the new positions! - -EXAMPLE: -======= -If the reset tool says: -scoreboard_offset=<0.500, 2.800, 0.100> - -Then in your scoreboard's config notecard, change: -scoreboard_offset=<0.000, 3.000, 0.000> -to: -scoreboard_offset=<0.500, 2.800, 0.100> - -TROUBLESHOOTING: -=============== -- Make sure displays are within 20 meters during scanning -- The config notecard must be named exactly "config" (lowercase) -- After editing config, the objects should move automatically -- If they don't move, try resetting the display objects - -That's it! No script editing required - just update the config values! diff --git a/Position_Reset_Tool.lsl b/Position_Reset_Tool.lsl deleted file mode 100644 index e254fc2..0000000 --- a/Position_Reset_Tool.lsl +++ /dev/null @@ -1,105 +0,0 @@ -// Position Reset Tool for Peril Game Display Objects -// Drop this script in your CONTROLLER object and click it -// This will generate config values for your notecard - -// ============================================================================= -// DYNAMIC CHANNEL CONFIGURATION -// ============================================================================= - -// Base channel offset - should match Main.lsl -integer CHANNEL_BASE = -77000; - -// Calculate channels dynamically to avoid hardcoded conflicts -integer calculateChannel(integer offset) { - // Use BOTH owner's key AND object's key to make channels unique per game instance - // This prevents interference when same owner has multiple game tables - string ownerStr = (string)llGetOwner(); - string objectStr = (string)llGetKey(); - string combinedStr = ownerStr + objectStr; - - // Create a more unique hash using both keys - string hashStr = llMD5String(combinedStr, 0); - integer hash1 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 0, 0)); - integer hash2 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 1, 1)); - integer combinedHash = hash1 * 16 + hash2; // Creates 0-255 range - - return CHANNEL_BASE - (offset * 1000) - combinedHash; -} - -key controller_key; -vector controller_pos; -rotation controller_rot; - -// Dynamic channels -integer SCOREBOARD_DATA_CHANNEL; -integer LEADERBOARD_DATA_CHANNEL; -integer DICE_DATA_CHANNEL; - -// Listen handle management -integer scoreboardHandle = -1; -integer leaderboardHandle = -1; -integer diceHandle = -1; - -default { - state_entry() { - // Initialize dynamic channels - SCOREBOARD_DATA_CHANNEL = calculateChannel(6); // ~-83000 range - LEADERBOARD_DATA_CHANNEL = calculateChannel(7); // ~-84000 range - DICE_DATA_CHANNEL = calculateChannel(8); // ~-85000 range - - controller_key = llGetKey(); - llOwnerSay("🔧 [Position Reset Tool] Dynamic channels initialized:"); - llOwnerSay(" Scoreboard: " + (string)SCOREBOARD_DATA_CHANNEL); - llOwnerSay(" Leaderboard: " + (string)LEADERBOARD_DATA_CHANNEL); - llOwnerSay(" Dice: " + (string)DICE_DATA_CHANNEL); - llOwnerSay("Position Reset Tool ready - Click to scan for display objects"); - - // Clean up any existing listeners - if (scoreboardHandle != -1) llListenRemove(scoreboardHandle); - if (leaderboardHandle != -1) llListenRemove(leaderboardHandle); - if (diceHandle != -1) llListenRemove(diceHandle); - - // Set up managed listeners with dynamic channels - scoreboardHandle = llListen(SCOREBOARD_DATA_CHANNEL, "", "", ""); - leaderboardHandle = llListen(LEADERBOARD_DATA_CHANNEL, "", "", ""); - diceHandle = llListen(DICE_DATA_CHANNEL, "", "", ""); - } - - touch_start(integer total_number) { - if (llDetectedKey(0) == llGetOwner()) { - controller_pos = llGetPos(); - controller_rot = llGetRot(); - - llOwnerSay("Scanning for display objects within 20 meters..."); - - // Send scan messages on all data channels to find display objects - llRegionSay(SCOREBOARD_DATA_CHANNEL, "POSITION_SCAN|" + (string)controller_key); - llRegionSay(LEADERBOARD_DATA_CHANNEL, "POSITION_SCAN|" + (string)controller_key); - llRegionSay(DICE_DATA_CHANNEL, "POSITION_SCAN|" + (string)controller_key); - llSetTimerEvent(3.0); // Wait 3 seconds for responses - } - } - - listen(integer channel, string name, key id, string msg) { - if ((channel == SCOREBOARD_DATA_CHANNEL || channel == LEADERBOARD_DATA_CHANNEL || channel == DICE_DATA_CHANNEL) && - llSubStringIndex(msg, "POSITION_RESPONSE|") == 0) { - list parts = llParseString2List(msg, ["|"], []); - string object_type = llList2String(parts, 1); - vector object_pos = (vector)llList2String(parts, 2); - rotation object_rot = (rotation)llList2String(parts, 3); - - // Calculate offset and relative rotation - vector offset = (object_pos - controller_pos) / controller_rot; - rotation rel_rot = object_rot / controller_rot; - - llOwnerSay("\n=== " + llToUpper(object_type) + " CONFIG ==="); - llOwnerSay(object_type + "_offset=" + (string)offset); - llOwnerSay(object_type + "_rotation=" + (string)rel_rot); - } - } - - timer() { - llSetTimerEvent(0.0); - llOwnerSay("\nScan complete. Copy values to your 'config' notecard."); - } -} diff --git a/dice b/dice deleted file mode 100644 index e69de29..0000000 diff --git a/main b/main deleted file mode 100644 index e69de29..0000000 diff --git a/scoreboard b/scoreboard deleted file mode 100644 index e69de29..0000000