// Myriad_Lite_Module_WELL-v0.0.4-20131025.lsl // Copyright (c) 2013 by 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/ // CONSTANTS - DO NOT CHANGE DURING RUN string BASENAME = "Myriad Lite Module WELL"; string VERSION = "0.0.4"; // Allen Kerensky's script version string VERSIONDATE = "20131025"; // Allen Kerensky's script yyyymmdd // Module to Module Messaging Constants integer MODULE_WELL = -10; integer LM_SENDTOATTACHMENT = 0x80000000; integer RENDEZVOUS1 = -999; string ANIM_INCAPACITATED = "sleep"; // FIXME WELL anim when incapacitated string ANIM_DEAD = "dead"; // FIXME WELL anim when dead vector MOVELOCK = <0,0,0>; // FIXME WELL movelock position when incapacitated or dead float TAU = 0.05; // FIXME WELL movelock tau // Particle system presets // name, length of list for name, list of rules data ready to pass to llParticleSystem list PRESETS = [ "Ruth2", 39, PSYS_PART_FLAGS, 0, // color interp true, glow true, size interp true, followsrc true, followtarget true PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_ANGLE_CONE, PSYS_SRC_INNERANGLE, PI, PSYS_SRC_OUTERANGLE, 0.0, PSYS_PART_START_SCALE, <.8,1,1>, PSYS_PART_END_SCALE, <0.02, 0.02, 0.02>, PSYS_PART_START_ALPHA, 1.0, PSYS_PART_END_ALPHA, 0.0, PSYS_PART_START_COLOR, <1,1,1>, PSYS_PART_END_COLOR, <1,1,1>, PSYS_PART_MAX_AGE, 3.0, PSYS_SRC_MAX_AGE, 0.0, PSYS_SRC_BURST_RATE, 0.020, PSYS_SRC_BURST_PART_COUNT, 1, PSYS_SRC_BURST_RADIUS, 1.0, PSYS_SRC_BURST_SPEED_MAX, 1, PSYS_SRC_BURST_SPEED_MIN, .1, PSYS_SRC_TEXTURE, "e50ed3cf-6fab-4afe-ac37-187a7d7ab0b8", // ruth cloud particle PSYS_SRC_OMEGA, <0,0,0>, PSYS_SRC_ACCEL, <0,0,0> ]; ////////////////////////////////////////////////////////////////////////////// // PPMA FUNCTIONS string KEY_NOT_FOUND = "[KEY_NOT_FOUND]"; string GET_VAL(string dbkey,string field) { //llOwnerSay("GET_VAL KEY=["+dbkey+"] FIELD=["+field+"]"); string out = KEY_NOT_FOUND; integer i; string name; string desc; for ( i = 2; i <= llGetNumberOfPrims(); i++ ) { name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0); desc = llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0); if ( llToLower(name) == llToLower(dbkey) && llToLower(desc) == llToLower(field) ) { out = llList2String(llGetLinkPrimitiveParams(i,[PRIM_TEXT]),0); //DEBUG("GET_VAL RETURN=["+out+"]"); return out; // bail on first match? } } //llOwnerSay("GET_VAL RETURN=["+out+"]"); return out; } // GET_FLAG - DEBUG // LMIM: SET_FLAG|<name>=<TRUE|FALSE> // PPMA: FLAG,<flagname>,<TRUE|FALSE> // LMOUT: FLAG|<flagname>=<TRUE|FALSE> // LMERR: FIXME integer GET_FLAG(string flag) { string val = GET_VAL("FLAG",llToUpper(flag)); if ( val == KEY_NOT_FOUND ) { ERROR(MODULE_WELL,"Flag ["+flag+"] does not exist."); } if ( val != "0" && val != "1") { ERROR(MODULE_WELL,"Flag: "+flag+" invalid value ["+val+"]"); } integer bool = (integer)val; //llMessageLinked(LINK_THIS,MODULE_WELL,"FLAG|"+flag+"="+val,llGetOwner()); // FIXME remove? return bool; } // // PPMA GET_NAME - returns player firstname or nickname for Talker/Emoter // string GET_NAME() { string defaultname = "Myriad Player"; string name = GET_VAL("CHARACTER","NAME"); list tokens = llParseString2List(name,[" ",".","_"],[]); string firstname = llList2String(tokens,0); string lastname = llList2String(tokens,1); string nickname = GET_VAL("CHARACTER","NICKNAME"); if ( name == KEY_NOT_FOUND && nickname == KEY_NOT_FOUND ) return defaultname; if ( name != KEY_NOT_FOUND && nickname == KEY_NOT_FOUND ) return name; if ( name == KEY_NOT_FOUND && nickname != KEY_NOT_FOUND ) return nickname; if ( name != KEY_NOT_FOUND && nickname != KEY_NOT_FOUND ) return firstname+" \""+nickname+"\" "+lastname; return defaultname; } // // DEBUG // list modules = [ "none","Core","Character Sheet","Armor","BAM","Rumors","Close Combat","Ranged Combat","Resilience","Progress","WELL","Meter","NPC","Notecards","Social Combat","RLV" ]; string LAST_DEBUG_MSG; integer LAST_DEBUG_MOD; DEBUG(integer modnum,string debugmsg) { if ( GET_FLAG("DEBUG") == TRUE ) { if ( modnum == LAST_DEBUG_MOD && debugmsg == LAST_DEBUG_MSG ) return; // suppress duplicate debug messages to cut down on spam LAST_DEBUG_MOD = modnum; // remember this one LAST_DEBUG_MSG = debugmsg; // remember this one modnum *= -1; // convert negative module constants to positive number string modname = llList2String(modules,modnum); string objname = llGetObjectName(); llSetObjectName("⚙"); string ownername = llList2String(llParseString2List(llKey2Name(llGetOwner()),["@"],[]),0); // strip @where from HG names llSay(PUBLIC_CHANNEL,"/me ("+ownername+") Mod "+modname+": "+debugmsg); llSetObjectName(objname); } } // // ERROR // integer LAST_ERROR_MOD; string LAST_ERROR_MSG; ERROR(integer modnum,string errmsg) { if ( modnum == LAST_ERROR_MOD && errmsg == LAST_ERROR_MSG ) return; // suppress duplicate debug messages to cut down on spam LAST_ERROR_MOD = modnum; // remember this one LAST_ERROR_MSG = errmsg; // remember this one modnum *= -1; // convert negative module constants to positive number string modname = llList2String(modules,modnum); string objname = llGetObjectName(); llSetObjectName("⚠"); string ownername = llList2String(llParseString2List(llKey2Name(llGetOwner()),["@"],[]),0); // strip @where from HG names llSay(PUBLIC_CHANNEL,"/me ("+ownername+") Mod "+modname+": "+errmsg); llSetObjectName(objname); } // MEMORY GET_MEMORY() { OWNERSAY(MODULE_WELL,BASENAME+" free memory: "+(string)llGetFreeMemory()); // show this module's free memory info } // GETVERSION GET_VERSION() { OWNERSAY(MODULE_WELL,BASENAME+" v"+VERSION+"-"+VERSIONDATE); // show this module's version info } // // HELP // integer LAST_HELP_MOD; string LAST_HELP_MSG; HELP(integer modnum,string help) { if ( modnum == LAST_HELP_MOD && help == LAST_HELP_MSG) return; // suppress duplicate debug messages to cut down spam string objname = llGetObjectName(); llSetObjectName("⎗"); llOwnerSay("/me "+help); // now tell the owner the help message llSetObjectName(objname); } // // OWNERSAY - sent messages to player only // string modcodes = " ▶☐♞☩◊⚔➤❤♦⛃▚♟▤☑☍"; integer LAST_OWNSAY_MOD; string LAST_OWNSAY_MSG; OWNERSAY(integer modnum,string message) { if ( modnum == LAST_OWNSAY_MOD && message == LAST_OWNSAY_MSG ) return; // suppress duplicate debug messages to cut down on spam LAST_OWNSAY_MOD = modnum; // remember this one LAST_OWNSAY_MSG = message; // remember this one modnum *= -1; // convert negative module constants to positive number string unicode = llGetSubString(modcodes,modnum,modnum); string objname = llGetObjectName(); llSetObjectName(unicode); llOwnerSay("/me "+message); llSetObjectName(objname); } //============================================================================ // RESET - do any final cleanup work here then reset //============================================================================ RESET() { STOP_ALL(); // stop all running animations llResetScript(); } // // RPEVENT // string LAST_RP_MSG; integer LAST_RP_MOD; RPEVENT(integer rpmod,string rpevent) { if ( rpmod == LAST_RP_MOD && rpevent == LAST_RP_MSG ) return; // ignore duplicates LAST_RP_MOD = rpmod; // remember this one LAST_RP_MSG = rpevent; // remember this one string objname = llGetObjectName(); llSetObjectName("★"); //llOwnerSay("/me "+rpevent); // now tell the owner the rest of the RPEVENT| message llSetObjectName(objname); string sendername = llList2String(llParseString2List(llKey2Name(llGetOwner()),["@"],[]),0); // strip @where from HG names llRegionSay(RENDEZVOUS1,"RPEVENT|"+GET_NAME()+" ("+sendername+") "+rpevent); } //============================================================================ // SETUP //============================================================================ SETUP() { llRequestPermissions(llGetOwner(),PERMISSION_TRIGGER_ANIMATION); OWNERSAY(MODULE_WELL,"WELL module active."); } // // STOP_ALL - stop all animations STOP_ALL() { if ( ( llGetPermissions() & PERMISSION_TRIGGER_ANIMATION ) != TRUE ) { ERROR(MODULE_WELL,"Unable to stop all animations due to lack of granted permission."); return; } // stop all running animations list anims = llGetAnimationList(llGetOwner()); // get list of current animations for owner integer animcount = llGetListLength(anims); // count the number of animations in the list while (animcount--) { // step from end of animation list to beginning llStopAnimation(llList2String(anims,animcount)); // stopping each animation } } //============================================================================ // DEFAULT STATE //============================================================================ default { //------------------------------------------------------------------------ // CHANGED EVENT //------------------------------------------------------------------------ changed(integer change) { if ( change & CHANGED_REGION || change & CHANGED_TELEPORT ) { DEBUG(MODULE_WELL,"Region Change or Teleport detected. Re-requesting permissions again."); llRequestPermissions(llGetOwner(),PERMISSION_TRIGGER_ANIMATION); } } //------------------------------------------------------------------------ // LINK_MESSAGE EVENT //------------------------------------------------------------------------ link_message(integer sender_num,integer num,string str,key id) { if ( num == MODULE_WELL || num == LM_SENDTOATTACHMENT ) return; // ignore our own link messages //DEBUG(MODULE_WELL,"EVENT: link_message("+(string)sender_num+","+(string)num+","+str+","+(string)id+")"); // Break down incoming command list tokens = llParseString2List(str,["|"],[]); integer fields = llGetListLength(tokens); string cmd = llToLower(llStringTrim(llList2String(tokens,0),STRING_TRIM)); // // Utility Output // // DEBUG|<debug_message> if ( cmd == "debug" ) { DEBUG(num,llList2String(tokens,1)); return; } // DEBUG|<debug_message> if ( cmd == "error" ) { ERROR(num,llList2String(tokens,1)); return; } // ERROR|<error_message> if ( cmd == "help" ) { HELP(num,llList2String(tokens,1)); return; } // HELP|<help_message> if ( cmd == "memory" ) { GET_MEMORY(); return;} // show memory info if ( cmd == "ownersay" ) { OWNERSAY(num,llList2String(tokens,1)); return; } // OWNERSAY|<ownersay_message> if ( cmd == "rpevent" ) { RPEVENT(num,llList2String(tokens,1)); return; } // RPEVENT|<rp_event_message> if ( cmd == "reset" ) { RESET(); return; } // RESET if ( cmd == "version" ) { GET_VERSION(); return; } // VERSION // WHISPER|CHANNEL=###|MESSAGE=... // SAY|CHANNEL=###|MESSAGE=... // SHOUT|CHANNEL=###|MESSAGE=... // REGIONSAY|CHANNEL=###|MESSAGE=... if ( cmd == "whisper" || cmd == "say" || cmd == "shout" || cmd == "regionsay" ) { integer channel = DEBUG_CHANNEL; string message = ""; while ( fields-- ) { string attrib = llToLower(llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),0)); if ( attrib == "channel" ) channel = llList2Integer(llParseString2List(llList2String(tokens,fields),["="],[]),1); if ( attrib == "message" ) message = llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),1); } if ( channel != DEBUG_CHANNEL && message != "" ) { if ( cmd == "whisper" ) llWhisper(channel,message); if ( cmd == "say" ) llSay(channel,message); if ( cmd == "shout" ) llShout(channel,message); if ( cmd == "regionsay") llRegionSay(channel,message); } else { ERROR(MODULE_WELL,"Invalid "+cmd+" Command Received"); } return; } // INSTANTMESSAGE|USER=uuid|MESSAGE=... if ( cmd == "instantmessage" ) { key user = NULL_KEY; string message = ""; while ( fields-- ) { string attrib = llToLower(llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),0)); if ( attrib == "user" ) user = llList2Key(llParseString2List(llList2String(tokens,fields),["="],[]),1); if ( attrib == "message" ) message = llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),1); } if ( user != NULL_KEY && message != "" ) { llInstantMessage(user,message); } else { ERROR(MODULE_WELL,"Invalid INSTANTMESSAGE Command Received"); } return; } // STARTANIMATION|ANIMATION=uuid or name... if ( cmd == "startanimation" && fields == 2 ) { string animation = ""; while ( fields-- ) { string attrib = llToLower(llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),0)); if ( attrib == "animation" ) animation = llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),1); } if ( animation != "" ) { llStartAnimation(animation); // FIXME Permissions? Track list of running? } else { ERROR(MODULE_WELL,"Invalid STARTANIMATION Command Received"); } return; } // STOPANIMATION|ANIMATION=uuid or name in inventory or all if ( cmd == "stopanimation" && fields == 2 ) { string animation = ""; while ( fields-- ) { string attrib = llToLower(llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),0)); if ( attrib == "animation" ) animation = llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),1); } if ( llToLower(animation) == "all" ) { STOP_ALL(); return; } else if ( animation != "" ) { llStopAnimation(animation); // FIXME Permissions? Track list of running? } else { ERROR(MODULE_WELL,"Invalid STOPANIMATION Command Received"); } return; } // PLAYSOUND|SOUND=...|VOLUME=#.# - attached - does not play inworld from HUD if ( cmd == "playsound" && fields == 3 ) { string sound = ""; float volume = 0.0; while ( fields-- ) { string attrib = llToLower(llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),0)); if ( attrib == "sound" ) sound = llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),1); if ( attrib == "volume" ) volume = llList2Float(llParseString2List(llList2String(tokens,fields),["="],[]),1); } if ( sound != "" && volume != 0.0 ) { llPlaySound(sound,volume); } else { ERROR(MODULE_WELL,"Invalid PLAYSOUND Command Received"); } return; } // TRIGGERSOUND|SOUND=...|VOLUME=#.# - unattached, can play inworld from HUD if ( cmd == "triggersound" && fields == 3 ) { string sound = ""; float volume = 0.0; while ( fields-- ) { string attrib = llToLower(llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),0)); if ( attrib == "sound" ) sound = llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),1); if ( attrib == "volume" ) volume = llList2Float(llParseString2List(llList2String(tokens,fields),["="],[]),1); } if ( sound != "" && volume != 0.0 ) { llTriggerSound(sound,volume); } else { ERROR(MODULE_WELL,"Invalid TRIGGERSOUND Command Received"); } return; } // LOOPSOUND|SOUND=...|VOLUME=#.# - does not play inworld from HUD if ( cmd == "loopsound" && fields == 3 ) { string sound = ""; float volume = 0.0; while ( fields-- ) { string attrib = llToLower(llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),0)); if ( attrib == "sound" ) sound = llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),1); if ( attrib == "volume" ) volume = llList2Float(llParseString2List(llList2String(tokens,fields),["="],[]),1); } if ( sound != "" && volume != 0.0 ) { llLoopSound(sound,volume); } else { ERROR(MODULE_WELL,"Invalid LOOPSOUND Command Received"); } return; } // STOPSOUND if ( cmd == "stopsound" ) { llStopSound(); return; } // PARTICLEPRESET|NAME=presetname... if ( cmd == "particlepreset" && fields == 2 ) { string name = ""; while (fields--) { string attrib = llToLower(llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),0)); if ( attrib == "name" ) name = llList2String(llParseString2List(llList2String(tokens,fields),["="],[]),1); } if ( name != "" ) { // found preset integer start = llListFindList(PRESETS,[name]) + 2; integer end = start + llList2Integer(PRESETS,start - 1); llParticleSystem(llList2List(PRESETS,start,end)); } else { ERROR(MODULE_WELL,"Invalid PARTICLEPRESET Command Received."); } return; } // PARTICLES|whoanelly // PARTICLESOFF if ( cmd == "particlesoff" ) { llParticleSystem([]); return; } // MOVELOCK if ( cmd == "stopmovelock" ) { llStopMoveToTarget(); MOVELOCK = <0,0,0>; return; } if ( cmd == "startmovelock" ) { if ( MOVELOCK == <0,0,0> ) MOVELOCK = llGetPos(); llMoveToTarget(MOVELOCK,TAU); return; } } //------------------------------------------------------------------------ // RUN_TIME_PERMISSIONS EVENT //------------------------------------------------------------------------ run_time_permissions(integer perm) { if ( perm & PERMISSION_TRIGGER_ANIMATION) { DEBUG(MODULE_WELL,"PERMISSION_TRIGGER_ANIMATION granted."); } } //------------------------------------------------------------------------ // STATE_ENTRY EVENT //------------------------------------------------------------------------ state_entry() { SETUP(); } } // END