User:Allen Kerensky/Myriad Lite Preview4/BAM Touch Goal v0.0.7 20110902

From Second Life Wiki
Jump to navigation Jump to search

BAM Touch Goal v0.0.7 20110902

<lsl> // Baroun's Adventure Machine (BAM) Touch Goal v0.0.7 20110902 // Copyright (c) 2008-2011 Baroun Tardis (SL) and Allen Kerensky (OSG/SL) // Baroun's Adventure Machine licensed under the // Creative Commons Attribution-Share Alike-Non-Commercial 3.0 Unported // http://creativecommons.org/licenses/by-nc-sa/3.0/

//============================================================================ // Adventure-Specific Configuration // Task numbers are (AdvNum*100)+task, so they don't overlap between adventures //============================================================================

// NPC or object-specific info string MSG_SETTEXT = "Processed Red Salt Cask"; vector MSG_SETTEXT_COLOR = <0,0,1>; float MSG_SETTEXT_ALPHA = 1.0;

// Adventure-specific info string AdvName = "Red Salt"; // Adventure Name

// Current Task-specific info integer AdvGoal = 102; // current goal string TaskDoneText = "You've found the salt!"; // Mission complete message string TaskDoneUUID = "f78027c9-e8bb-38f2-9b11-1d4e89ac10a4"; // sound byte to play string PrizeName = "NONE"; // prize to give when mission complete

// Next Task-specific info integer AdvTaskTDNum = 103; // next task to hand out when task is done string AdvTaskToDo = "Return the salt to the baker"; // the next goal message string AdvTaskToDoHint = "He's where you first met him"; // hint for the next goal

float TOUCH_RANGE = 1.5; // in meters, how close to be for touch to work arms & legs = 1.5m integer TRIGGERWAIT = 60; // seconds to remember players to prevent re-triggering task? integer PRIZEWAIT = 3600; // seconds to remember players who got prize? float EVENTTIMER = 15.0; // seconds between running memory and list cleanup timed events

//============================================================================ // MESSAGE FORMAT REFERENCE //============================================================================ // Ask a player HUD if the player is in an adventure - InAdv?

// Player responds: // Yes in an adventure - InAdv | String AdventureName // No, not in adventure - InAdv | NONE

// Task In Progress Query - Ask player what their current goal is // NPC/Object Send Example: TaskIP?

// Task In Progress Response - The player Responds with current task in progress // Player Send Example: TaskIP | AdventureGoal

// Task Done - Tell player they have achieved their current goal // NPC Object Send Example: DoneTask | GoalText | TaskDone Text | PlayerUUID

// Add a task to the Player HUD - AddTask | TaskNumber | String Describing Task // Add a hint for a task to the Player HUD - AddHint | TaskNumber | String Hint

//============================================================================ // GLOBAL CONSTANTS //============================================================================ string MSG_STARTUP = "Baroun's Adventure Machine is activating"; string CHAN_PREFIX = "0x"; // prefix for calculating dynamic channels from UUIDs string API_DIVIDER = "|"; // The field divider within BAM packets string API_INADV_QUERY = "InAdv?"; // ask a player HUD if the player is in an adventure? string API_INADV_RESPONSE = "InAdv"; // player response to in adventure request string API_TASKIP_QUERY = "TaskIP?"; // what is player task-in-progress? string API_TASKIP_RESPONSE = "TaskIP"; // player says current task-in-progress string API_DONETASK = "DoneTask"; // tell player the task is done string API_NONE = "NONE"; // magic value for no current adventure, or no prize string API_ADDTASK = "AddTask"; // add a task to player HUD string API_ADDHINT = "AddHint"; // add a task hint to player HUD

//============================================================================ // GLOBAL RUNTIME //============================================================================ list Recent; // list people who recently checked this goal list GotPrizes; // list of who got prizes [UUID,unixtime] key AvKey; // key of player string AvName; // name of player integer BAM; // Channel we listen on integer Target; //channel of thing we're talking to integer HANDLE; // hold a handle for the open listener

//============================================================================ // DEFAULT STATE //============================================================================ default {

   //------------------------------------------------------------------------
   // STATE_ENTRY EVENT
   //------------------------------------------------------------------------
   state_entry() {
       llOwnerSay(MSG_STARTUP);
       // calculate our dynamic channel
       BAM= (integer)(CHAN_PREFIX + llGetSubString((string)llGetKey(),-7,-1));
       HANDLE = llListen(BAM,"",NULL_KEY,""); // start a listener with llremove handle
       llSetTimerEvent(EVENTTIMER); // set a timer to manage the recent list
   }
   //------------------------------------------------------------------------
   // TIMER EVENT
   //------------------------------------------------------------------------
   timer() {
       // on timer, check memory left and clear recent list if needed
       integer freemem = llGetFreeMemory(); // how much memory free?
       if ( freemem < 1024 ) { // is it too little?
           llInstantMessage(llGetOwnerKey(llGetKey()),"Memory low for "+llGetObjectName()+" in "+llGetRegionName()+". Resetting RECENT list.");
           Recent=[]; // clear the recent list
           GotPrizes=[]; // clear the gotPrizes list
           return; // exit timer event, no sense in processing lists further since we just emptied them
       }
       // check to see if entries in Recent list have expired
       integer i; // temporary index number into list
       list temprecent = []; // temporary list to hold entries we want to keep
       key who; // temporary place to keep the keys we process in the lists
       integer time; // temporary place to keep the time we process in the lists
       for (i = 0; i < llGetListLength(Recent); i += 2) { // step through strided list from begin to end
           who = llList2Key(Recent,i); // get the UUID for this list stride
           time = llList2Integer(Recent,i+1); // get the integer time for this list stride
           if ( llGetUnixTime() < time ) temprecent = [who,time] + temprecent; // non expired, keep this entry
       }
       Recent = temprecent; // now, replace the Recent list with the pruned version
       // check to see if entries in GotPrizes list have expired
       temprecent = []; // clear the temp list again
       for (i = 0; i < llGetListLength(GotPrizes); i += 2) { // step through next strided list
           who = llList2Key(GotPrizes,i); // get the uuid for this list stride
           time = llList2Integer(GotPrizes,i+1); // get the integer time for this list stride
           if ( llGetUnixTime() < time ) temprecent = [who,time] + temprecent; // non expired, keep this entry
       }
       GotPrizes = temprecent; // replace the gotprizes list with the pruned one        
   }
   //------------------------------------------------------------------------
   // TOUCH EVENT
   //------------------------------------------------------------------------
   touch_start(integer times_touched) {
       while (times_touched--) { // count down through all touches in this event
           AvKey=llDetectedKey(times_touched); // get the UUID of the toucher
           AvName=llDetectedName(times_touched); // get the name of the toucher
           float dist = llVecDist(llGetPos(),llList2Vector(llGetObjectDetails(AvKey,[OBJECT_POS]),0)); // find distance between item and toucher
           if ( dist <= TOUCH_RANGE ) { // is toucher within arms reach?
               if ( llListFindList(Recent,[AvKey]) == -1 ) { // is player in recent list?
                   Recent = [AvKey] + Recent; // no, add player to list
               }
               // calculate player-specific BAM dynamic channel
               Target= (integer)(CHAN_PREFIX + llGetSubString((string)AvKey,-7,-1));
               llSay(Target, API_INADV_QUERY); // ask player if they are in adventure, must be within 10m for effect
           }
       }
   }
   //------------------------------------------------------------------------
   // LISTEN EVENT
   //------------------------------------------------------------------------
   listen(integer chan, string name, key id, string msg) {
       // calculate the BAM dynamic channel of the person interacting with us
       Target= (integer)(CHAN_PREFIX + llGetSubString((string)llGetOwnerKey(id),-7,-1));
       list tokens = llParseString2List(msg, [API_DIVIDER], []); // split message apart around | symbols
       string command = llList2String(tokens, 0); // assign first item in list as BAM command
       string data    = llList2String(tokens, 1); // assign second item in list as BAM data for command
       // if they answer with the current adventure, then react accordingly
       if ( command == API_INADV_RESPONSE ) { // player responded they are in an adventure
           if ( data == AdvName ) { // are they in THIS adventure?
               llSay(Target,API_TASKIP_QUERY); // if so, ask which task in this adventure they are working on
               return; // exit early to save processing
           }
           return; // done processing "in adventure" responses, exit listen early
       }
       if ( command == API_TASKIP_RESPONSE ) { // player responded with their task in progress
           if ( data == (string)AdvGoal ) { // its the task for THIS object - player has found the goal
               // tell player HUD the task is done! - DoneTask|(num)|(text)|UUID
               llSay(Target, API_DONETASK + API_DIVIDER + (string)AdvGoal+ API_DIVIDER +TaskDoneText+ API_DIVIDER+ TaskDoneUUID);
               // now tell GM the task is done
               llInstantMessage(llGetOwnerKey(llGetKey()),llKey2Name(llGetOwnerKey(id))+" (adventure "+AdvName+"): finished task "+(string)AdvGoal+" ("+TaskDoneText+").");
               // The Task is Done, Distribute the Prize, if any
               if ( PrizeName != API_NONE && llListFindList(GotPrizes,[llGetOwnerKey(id)]) == -1 ) { // is there a prize at this step?
                   llGiveInventory(llGetOwnerKey(id),PrizeName); // give it over
                   GotPrizes = [ llGetOwnerKey(id), (llGetUnixTime() + PRIZEWAIT) ] + GotPrizes; // remember who and when
                   // tell the GM
                   llInstantMessage(llGetOwnerKey(llGetKey()),llKey2Name(llGetOwnerKey(id))+" (adventure "+AdvName+") prize given: "+PrizeName);
               }
               // Does finishing this task trigger a new task? If so, add it and a hint to the HUD
               if ( AdvTaskTDNum != 0 ) { // there is a "TODO" task too
                   // assign the next task to the player HUD
                   llSay(Target, API_ADDTASK + API_DIVIDER +(string)AdvTaskTDNum + API_DIVIDER + AdvTaskToDo);
                   // assign the next task HINT to the player HUD
                   llSay(Target, API_ADDHINT + API_DIVIDER +(string)AdvTaskTDNum + API_DIVIDER + AdvTaskToDoHint);
                   // tell the GM the player is on the next task
                   llInstantMessage(llGetOwnerKey(llGetKey()),llKey2Name(llGetOwnerKey(id))+" (adventure "+AdvName+"): Assigning next task "+(string)AdvTaskTDNum+" ("+AdvTaskToDo+")");
               }
               return; // we're done with API_TASKIP_RESPONSE, so exit listen early in case we add more commands later
           } // if data = AdvGoal
           return; // return early since we are done with TASKIP responses, in case we add more later
       } // end if command equal TASKIP reponse
   }

} //============================================================================ // END //============================================================================ </lsl>