User:Allen Kerensky/Myriad Lite Preview4/BAM Adventure Giver NPC v0.0.6 20110906
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
BAM Adventure Giver NPC v0.0.6 20110906
<lsl> // Baroun's Adventure Machine (BAM) Adventure Giver NPC v0.0.6 20110906 // 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 //============================================================================ // NPC-specific Info string MSG_NPCNAME = "BAM Adventure Giver NPC"; // hovertext name for NPC - I hate hovertext vector MSG_SETTEXT_COLOR = <1.0,1.0,1.0>; // color to display settext in float MSG_SETTEXT_ALPHA = 1.0; // alpha for hovertext. 0.0 = clear, 1.0 = solid.
// Adventure-specific Info string ADVNAME = "Red Salt"; // Adventure Name string ADVTEXT = "Find some red salt for luck."; // brief description string ADV_ATTRACT = "can you help me find some red salt?"; // hook to get player to play string MSG_OWNER_STARTADV = " has started Red Salt Adventure"; string ADV_ALL_TASKS = "101, 102"; // CSV list of task numbers that all have to be done for adventure to be complete example: "101, 102, 103" string MSG_ADV_INCOMPLETE = ", it looks like you still haven't found the red salt for me."; // prefixed by AVNAME string MSG_OWNER_DONEADV = " has completed the Red Salt Adventure"; // message to speak when task complete string ADVDONETEXT = "Thanks! I appreciate your help!"; string ADVDONEUUID = "f78027c9-e8bb-38f2-9b11-1d4e89ac10a4"; //object or sounds to give as a mission complete string PRIZENAME = "NONE"; // prize to give when adventure is complete
// Task-Specific Info // Task numbers are (AdvNum*100)+task, so they don't match up between adventures integer ADVTASKTDNUM = 101; // task number for the task THIS node hands out string ADVTASKTODO = "Find the Red Salt Mines"; // task description of what to do string ADVTASKTODOHINT = "Look in the other corner of the room"; // string
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 float SENSOR_RANGE = 3.0; // how close do you have to be to trigger the NPC float SENSOR_ARC = PI; // what is the sensor's sweep? float SENSOR_REPEAT = 10; // how often to repeat the sensor
//============================================================================ // MESSAGE FORMAT REFERENCE //============================================================================ // -1 OUT - [YES,NO,CLOSE] // -1 IN - YES // BAMCHAN OUT - InAdv? // BAMCHAN IN - InAdv|str NONE // BAMCHAN IN - InAdv|str AdventureName // BAMCHAN OUT - OfferAdv|str AdventureName|str AdventureText // BAMCHAN OUT - TaskCP? // BAMCHAN IN - AcceptAdv|str AdvName // BAMCHAN OUT - AddTask|int TaskNumber|str TaskToDo // BAMCHAN OUT - AddHint|int TaskNumber|str TaskHint // BAMCHAN IN - TaskCP| // BAMCHAN IN - TaskCP|str 999 // BAMCHAN OUT - DoneAdv|str AdventureName|str AdventureText|key AdventureDoneUUID
//============================================================================ // Global Constants //============================================================================ string CHAN_PREFIX = "0x"; // random chat channel prefix string CHAT_DIVIDER = ", "; // to comma-separate elements in emitted chat elements integer DEBUG_FLAG = FALSE; // set to true for debug messages string MSG_STARTUP = "Baroun's Adventure Machine is activating."; string DEBUG_LISTEN_CHANNEL= "BAM Listening on channel: "; // debug message to see picked channel string API_INADV_QUERY = "InAdv?"; // API trigger to check if in an adventure. float API_INADV_TIMEOUT = 3.0; // API timeout for an InAdv? request string API_TASKCP_QUERY = "TaskCP?"; // task complete? string API_INADV_RESPONSE = "InAdv"; // confirms player is already in an adventure string DIV1 = "|"; // divides fields of API messages string API_NONE = "NONE"; // magic text if player not in an adventure string API_OFFER_ADV = "OfferAdv"; // offer player an adventure string API_ACCEPT_ADV = "AcceptAdv"; // player accepts adventure string API_ADD_TASK = "AddTask"; // add a task to player string API_ADD_HINT = "AddHint"; // add a hint for the current task string API_TASKCP_RESPONSE = "TaskCP"; // task completed string API_DONEADV = "DoneAdv"; // adventure done
//============================================================================ // Runtime Globals //============================================================================ list Recent; // list of [UUID,unixtime] who recently collided with this goal list GotPrizes; // list of who got prizes [UUID,unixtime] key AVKEY; // UUID of the avatar we are interacting with string AVNAME; // String name of the avatar we are interacting with integer CHANBAM; // Channel we listen on integer CHANTARGET; // channel of thing we're talking to
//============================================================================ // DEFAULT STATE //============================================================================ default {
//------------------------------------------------------------------------ // STATE_ENTRY EVENT //------------------------------------------------------------------------ state_entry() { llParticleSystem([]); // shut off any running particles llSetText(MSG_NPCNAME,MSG_SETTEXT_COLOR,MSG_SETTEXT_ALPHA); llOwnerSay(MSG_STARTUP); // tell the owner we are initializing CHANBAM = (integer)(CHAN_PREFIX + llGetSubString((string)llGetKey(),-7,-1)); // calculate channel to listen on if (DEBUG_FLAG) llOwnerSay(DEBUG_LISTEN_CHANNEL+(string)CHANBAM); llListen(CHANBAM,"",NULL_KEY,""); // listen on channel for all messages from any name, name UUID, and any message llSetTimerEvent(EVENTTIMER); // fire off a timer event once an hour llSensorRepeat("",NULL_KEY,AGENT,SENSOR_RANGE,SENSOR_ARC,SENSOR_REPEAT); // start NPC looking for someone to help }
//------------------------------------------------------------------------ // TOUCH_START EVENT //------------------------------------------------------------------------ sensor(integer num_sensed) { while (num_sensed--) { // count down through all touches in this event AVKEY=llDetectedKey(num_sensed); // get the UUID of the toucher if ( llListFindList(Recent,[AVKEY]) == -1 ) { // player not in list of people recently completing the quest AVNAME=llDetectedName(num_sensed); // get the name of the toucher CHANTARGET = (integer)(CHAN_PREFIX + llGetSubString((string)AVKEY,-7,-1)); llSay(CHANTARGET, API_INADV_QUERY); // ask player if they are in adventure, must be within 10m for effect } } }
//------------------------------------------------------------------------ // 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 }
//------------------------------------------------------------------------ // LISTEN EVENT //------------------------------------------------------------------------ listen(integer chan, string name, key id, string msg) {
list tokens = llParseString2List(msg, [DIV1], []); // split incoming message apart using | string command = llList2String(tokens, 0); // the first part of the message is a command string data = llList2String(tokens, 1); // the second part is command-specific data
// if they answer they are in an adventure, react accordingly if ( command == API_INADV_RESPONSE ) { // In An Adventure Response if ( data == API_NONE && llListFindList(Recent,[llGetOwnerKey(id)]) == -1 ) { // responded with no current adventure llSay(PUBLIC_CHANNEL,AVNAME+CHAT_DIVIDER+ADV_ATTRACT); llSay(CHANTARGET,API_OFFER_ADV+DIV1+ADVNAME+DIV1+ADVTEXT); // offer one return; } if ( data == ADVNAME ) { // already in the current adventure llSay(CHANTARGET,API_TASKCP_QUERY); // so let's check if they have completed adventure? return; } }
// If they are accepting the adventure, hand them first task if ( command == API_ACCEPT_ADV ) { // accepting an adventure if ( data == ADVNAME ) { // accepting this nodes adventure llSay(PUBLIC_CHANNEL,ADVTEXT); llSay(CHANTARGET,API_ADD_TASK+DIV1+(string)ADVTASKTDNUM+DIV1+ADVTASKTODO); // give them first task llSay(CHANTARGET,API_ADD_HINT+DIV1+(string)ADVTASKTDNUM+DIV1+ADVTASKTODOHINT); // give them first task hint llInstantMessage(llGetOwner(),llKey2Name(llGetOwnerKey(id))+MSG_OWNER_STARTADV); // tell owner adventure begins return; // done with this chat command, exit early } }
if ( command == API_TASKCP_RESPONSE ) { // player sends TaskCP|task# to NPC string playertasks = llList2CSV(llListSort(llCSV2List(data),1,TRUE)); string alltasks = llList2CSV(llListSort(llCSV2List(ADV_ALL_TASKS),1,TRUE)); if ( playertasks == alltasks ) { // if all tasks are in done list, then adventure is done Recent = [ llGetOwnerKey(id), llGetUnixTime() + TRIGGERWAIT ] + Recent; // remember this player is done // tell player HUD that the adventure is done llSay(CHANTARGET,API_DONEADV+DIV1+ADVNAME+DIV1+ADVDONETEXT+DIV1+ADVDONEUUID); // tell player and public that adventure is done llSay(PUBLIC_CHANNEL,llKey2Name(llGetOwnerKey(id))+CHAT_DIVIDER+ADVDONETEXT); // give player the prize if one is defined if (PRIZENAME!="NONE" && llListFindList(GotPrizes,[llGetOwnerKey(id)]) == -1 ) { llGiveInventory(llGetOwnerKey(id),PRIZENAME); GotPrizes = [ llGetOwnerKey(id), (llGetUnixTime() + PRIZEWAIT) ] + GotPrizes; // remember who and when } // send message to quest OWNER that a player finished and got the prize llInstantMessage(llGetOwner(),llKey2Name(llGetOwnerKey(id))+MSG_OWNER_DONEADV); return; // exit early } // player has not completed last quest task, so tell them there is more to do llSay(PUBLIC_CHANNEL,llKey2Name(llList2String(llGetObjectDetails(id,[OBJECT_OWNER]),0))+MSG_ADV_INCOMPLETE); return; // exit early in case we add more chat commands } }
} //============================================================================ // END //============================================================================ </lsl>