User:Allen Kerensky/Myriad Lite/BAM Location Goal-Preview6.lsl
From OpenSimulator
< User:Allen Kerensky | Myriad Lite
Revision as of 07:04, 12 August 2012 by Allen Kerensky (Talk | contribs)
BAM_Location_Goal-Preview6.lsl
// Baroun's Adventure Machine BAM_Location_Goal-v0.0.8-20120704.lsl // Copyright (c) 2012 by Baroun Tardis and Allen Kerensky (OSG/SL) All Rights Reserved. // This work is dual-licensed under // Creative Commons Attribution (CC BY) 3.0 Unported // http://creativecommons.org/licenses/by/3.0/ // - or - // Modified BSD License (3-clause) // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of Myriad Lite nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN // NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Myriad RPG System was designed, written, and illustrated by Ashok Desai // Myriad RPG System licensed under: // Creative Commons Attribution (CC BY) 2.0 UK: England and Wales // http://creativecommons.org/licenses/by/2.0/uk/ string VERSION = "0.0.8"; // version number string VERDATE = "20120704"; // version date //============================================================================ // Adventure-Specific Configuration // Task numbers are (AdvNum*100)+task, so they don't overlap between adventures //============================================================================ // NPC or object specific info float SCAN_RANGE = 3.0; float SCAN_REPEAT = 3.0; // Adventure-specific info string ADVNAME="Red Salt"; // Adventure Name // Current Task-specific info integer ADVGOAL=101; string TASKDONETEXT = "You've found the red salt mines!"; string RUMOR_TASK_DONE = " found the red salt mines."; string TASKDONEUUID = "f78027c9-e8bb-38f2-9b11-1d4e89ac10a4"; string PRIZENAME = "NONE"; // Next Task-specific info integer ADVTASKTDNUM=102; string ADVTASKTODO="Find some processed salt inside the mine"; string ADVTASKTODOHINT="Checking casks might be a good idea"; // string 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 //============================================================================ float SCAN_ARC; // the sensor arc to scan for people in list RECENT; // list of [UUID,unixtime] who recently collided with 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 integer CHAN_REGION = -999; integer HAND_RUMOR; integer CHAN_RUMOR; string API_RUMOR_FIND = "RUMOR_SERVER_FIND"; string API_RUMOR_FOUND = "RUMOR_SERVER_FOUND"; string API_RUMOR_PUT = "RUMOR_PUT"; integer FLAG_DEBUG; //============================================================================ // DEBUG //============================================================================ DEBUG(string debugmsg) { if ( FLAG_DEBUG == TRUE ) llInstantMessage(llGetOwnerKey(llGetKey()),"DEBUG: "+debugmsg); } //============================================================================ // DEFAULT STATE //============================================================================ default { //------------------------------------------------------------------------ // LISTEN EVENT //------------------------------------------------------------------------ listen(integer chan, string name, key id, string msg) { chan = 0; // LSLINT name = ""; // LSLINT // Rumor server found, save its channel number if ( msg == API_RUMOR_FOUND ) { CHAN_RUMOR = (integer)(CHAN_PREFIX + llGetSubString((string)id,0,6)); return; } // 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 DEBUG(llKey2Name(llGetOwnerKey(id))+" (adventure "+ADVNAME+"): finished task "+(string)ADVGOAL+" ("+TASKDONETEXT+")."); // Send a rumor that the player progressed in the quest if ( CHAN_RUMOR != 0 ) { string who = llKey2Name(llGetOwnerKey(id)); string rumor = API_RUMOR_PUT+API_DIVIDER+who+API_DIVIDER+who+RUMOR_TASK_DONE; llRegionSay(CHAN_RUMOR,rumor); } // 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 DEBUG(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 DEBUG(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 } //------------------------------------------------------------------------ // SENSOR EVENT //------------------------------------------------------------------------ sensor (integer things_sensed) { while (things_sensed--) { // count down through all things sensed AVKEY = llDetectedKey(things_sensed); // get UUID of thing AVNAME = llDetectedName(things_sensed); // get name of thing if ( llListFindList(RECENT,[AVKEY]) == -1 ) { // is UUID in recent list? RECENT = [AVKEY] + RECENT; // no, so add it to recent list } // calculate BAM dynamic channel for sensed player TARGET= (integer)(CHAN_PREFIX + llGetSubString((string)AVKEY,-7,-1)); llSay(TARGET,API_INADV_QUERY); // ask player if they are in an adventure } } //------------------------------------------------------------------------ // STATE_ENTRY EVENT //------------------------------------------------------------------------ state_entry() { FLAG_DEBUG=FALSE; DEBUG(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 if ( HAND_RUMOR != 0 ) llListenRemove(HAND_RUMOR); CHAN_RUMOR = (integer)(CHAN_PREFIX + llGetSubString((string)llGetKey(),0,6)); HAND_RUMOR = llListen(CHAN_RUMOR,"",NULL_KEY,""); llRegionSay(CHAN_REGION,API_RUMOR_FIND); // send request for rumor server channel SCAN_ARC = 2 * PI; // setup sensor to scan full sphere llSensorRepeat("",NULL_KEY,AGENT,SCAN_RANGE,SCAN_ARC,SCAN_REPEAT); // start repeating sensor 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? DEBUG("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 } } //============================================================================ // END //============================================================================