User:Allen Kerensky/Myriad Lite/Myriad Lite-v0.1.12-20121219.lsl
From OpenSimulator
< User:Allen Kerensky | Myriad Lite
Revision as of 15:55, 19 December 2012 by Allen Kerensky (Talk | contribs)
Myriad_Lite_v0.1.12-20121219.lsl
// Myriad_Lite-v01.1.12-20121219.lsl // Copyright (c) 2012 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"; // base name of this script without version or date string VERSION = "0.1.12"; // Allen Kerensky's script version string VERSIONDATE = "20121219"; // Allen Kerensky's script yyyymmdd string TRUENAME; // name to reset item to after talker/emoter use integer MINSTAT = 1; // min value for statistics integer MAXSTAT = 5; // max human value for a statistic/attribute integer MINRESILIENCE = 1; // min value for resilience integer MAXRESILIENCE = 20; // max value for resilience integer MINSKILL = 1; // min value for skill rank integer MAXSKILL = 5; // max value for skill rank integer CHANMYRIAD = -999; // chat sent to ALL Myriad players in region integer CHANCOMMAND = 5; // chat sent by player to their meter string DIV = "|"; // message field divider string CHAN_PREFIX = "0x"; // channel prefix for calculating dynamic channels integer MAXARMOR = 5; // max legal armor rating integer ALLOW_PHYS_BULLETS = FALSE; // use physics or Myriad Bullets? FALSE = Myriad Skill-based bullets. // Module to Module Messaging Constants integer MODULE_HUD = -1; //integer MODULE_CHARSHEET = -2; //integer MODULE_ARMOR = -3; //integer MODULE_BAM = -4; //integer MODULE_RUMORS = -5; //integer MODULE_CLOSE = -6; //integer MODULE_RANGED = -7; //integer MODULE_RESILIENCE = -8; //integer MODULE_PROGRESS = -9; //integer MODULE_WELL = -10; //integer MODULE_METER = -11; //integer MODULE_GOON = -12; integer LM_SENDTOATTACHMENT = 0x80000000; // RUNTIME GLOBALS - CAN CHANGE DURING RUN integer FLAG_DEBUG; // see debug messages? key PLAYERID = NULL_KEY; // cached player UUID string PLAYERNAME = ""; // cached player name string NAME = ""; // character name string SPECIES = ""; // character species string BACKGROUND = ""; // character childhood history string CAREER = ""; // character career or faction list STATISTICS = []; list RESILIENCES = []; list CURRENT_RESILIENCES = []; list SKILLS = []; // skills [ string SkillName, integer SkillRank ] integer HANDMYRIAD = 0; // Myriad channel handle integer CHANPLAYER = 0; // dynamic channel to one player's UUID integer HANDPLAYER = 0; // player channel handle integer CHANOBJECT = 0; // dynamic channel to one object's UUID integer CHANHUD = 0; // dyname channel to HUD object UUID integer HANDHUD = 0; // HUD channel handle integer HANDCOMMAND = 0; // command channel handle integer HANDATTACH = 0; // attachment channel handle integer CHANATTACH = 0; // dynamic channel for attachments integer CHANBAM = 0; // dynamic channel for BAM quests integer HANDBAM = 0; // BAM channel update // Talker/Emoter integer CHANNEL_OOCCHAT = 22; integer CHANNEL_OOCEMOTE = 23; integer CHANNEL_ICCHAT = 44; integer CHANNEL_ICTHINK = 45; integer CHANNEL_ICEMOTE = 66; integer CHANNEL_NARRATE = 88; integer HANDLE_OOCCHAT; // callback handle for llListen integer HANDLE_OOCEMOTE; // callback handle for llListen integer HANDLE_ICCHAT; // callback handle for llListen integer HANDLE_ICTHINK; // callback handle for llListen integer HANDLE_ICEMOTE; // callback handle for llListen integer HANDLE_NARRATE; // callback handle for llListen string OOCPREFIX="(("; // what to put before OOC messages string OOCSUFFIX="))"; // what to put after OOC messages integer FLAG_ANIMATE; // integer FLAG_INCAPACITATED; // incapacitated by wounds? integer FLAG_DEAD; // killed by critical wounds? integer CURARMOR = 0; // highest armor value worn out of all armor worn, not a total // ABILITY TEST // Requires ATTRIBUTE NAME, SKILL NAME // Returns the ability test score for use by success fail, opposed rolls, etc // See Myriad PDF page 18, Myriad Special Edition page 24 integer ABILITY_TEST(integer attribute,integer skill) { integer highroll = 0; // clear out the highest roll while( attribute-- ) { // roll a dice for each point of the attribute integer roll = 1+(integer)llFrand(5.0); // roll this d6 if ( roll > highroll) highroll = roll; // if this is highest roll so far, remember it } // finished rolling a dice for each point of the base attribute return highroll + skill; // now, return the total of highest dice roll + skill value } // CHECK AMMO CHECKAMMO() { llWhisper(CHANATTACH,"CHECKAMMO"); } // COMBATOFF - turn off fist fighter COMBATOFF() { llMessageLinked(LINK_THIS,MODULE_HUD,"COMBATOFF",llGetOwner()); } // COMBATON - turn on fist fighter COMBATON() { llMessageLinked(LINK_THIS,MODULE_HUD,"COMBATON",llGetOwner()); } // COMMAND - process chat and link message commands together COMMAND(string msg) { // break down the commands and messages into units we can work with list fields = llParseString2List(msg,[DIV],[]); // break into list of fields based on DIVider string command = llToLower(llStringTrim(llList2String(fields,0),STRING_TRIM)); // assume the first field is a Myriad Lite command if ( command == "checkammo" ) { CHECKAMMO(); return;} // check ammo in weapons if ( command == "combatoff") { COMBATOFF(); return; } // turn off fist fighter if ( command == "combaton" ) { COMBATON(); return; } // turn on the fist fighter if ( command == "credits" ) { CREDITS(); return;} // show the credits including version number if ( command == "debugoff" ) { DEBUGOFF(); return; } // player turn off debugging if ( command == "debugon" ) { DEBUGON(); return;} // player turn on debugging if ( command == "drawboth" ) { DRAW("both"); return; } // draw both weapons if ( command == "drawleft" ) { DRAW("left"); return; } // draw weapon in left hand if ( command == "drawright" ) { DRAW("right"); return; } // draw weapon using right hand if ( command == "holsterboth" ) { HOLSTER("both"); return; } // holster both weapons if ( command == "holsterleft" ) { HOLSTER("left"); return; } // holster weapon in left hand if ( command == "holsterright" ) { HOLSTER("right"); return; } // holster weapon in right hand if ( command == "quest" ) { QUEST(); return; } // check our current quest status if ( command == "reload" ) { RELOAD(); return;} // reload weapons if ( command == "reset" ) { RESET(); return;} // reset HUD //if ( command == "rumor" ) { RUMOR(msg); return;} // rumors if ( command == "safetyoff" ) { SAFETYOFF(); return;} // unsafe the weapons if ( command == "safetyon" ) { SAFETYON(); return;} // safe the weapons if ( command == "sheatheboth" ) { SHEATHE("both"); return; } // sheathe both weapons if ( command == "sheatheleft" ) { SHEATHE("left"); return; } // sheathe weapon in left hand if ( command == "sheatheright" ) { SHEATHE("right"); return; } // sheathe weapon in right hand if ( command == "version" ) { CREDITS(); return;} // show the credits including version number if ( command == "incapacitated" ) { FLAG_INCAPACITATED = TRUE; return; } if ( command == "dead" ) { FLAG_DEAD = TRUE; return; } if ( command == "alive" ) { FLAG_DEAD = FALSE; return; } if ( command == "revived" ) { FLAG_INCAPACITATED = FALSE; return; } if ( llGetSubString(llStringTrim(llToLower(command),STRING_TRIM),0,4) == "armor" ) { SENDTOMODULE(msg,PLAYERID); return; } if ( llGetSubString(llStringTrim(llToLower(command),STRING_TRIM),0,4) == "rumor" ) { RUMOR(msg); return; } if ( llGetSubString(llStringTrim(llToLower(command),STRING_TRIM),0,3) == "roll" ) { ROLL(msg); return; } // roll dice } // CREDITS comply with Myriad RPG Creative Common-Attribution legal requirement CREDITS() { llOwnerSay("The Myriad RPG System was designed, written, and illustrated by Ashok Desai."); llOwnerSay("RPG System licensed under the Creative Commons Attribution 2.0 UK: England and Wales."); llOwnerSay("Myriad Lite v"+VERSION+" "+VERSIONDATE+" Copyright (c) 2011 by Allen Kerensky (OSG/SL)"); llOwnerSay("Licensed under Creative Commons Attribution-Share Alike-Non-Commercial 3.0 Unported."); llMessageLinked(LINK_THIS,MODULE_HUD,"VERSION",llGetOwner()); } // DEBUG - show debug chat with wearer name for sorting DEBUG(string dmessage) { if ( FLAG_DEBUG == TRUE ) { // are we debugging? llSay(DEBUG_CHANNEL,"("+llKey2Name(PLAYERID)+") HUD: "+dmessage); } } // DEBUGOFF - turn off the DEBUG flag DEBUGOFF() { FLAG_DEBUG = FALSE; // set debug flag to FALSE llOwnerSay("Debug Mode Deactivated"); llMessageLinked(LINK_THIS,MODULE_HUD,"DEBUGOFF",llGetOwner()); } // DEBUGON - turn on the DEBUG flag DEBUGON() { FLAG_DEBUG = TRUE; // set debug flag TRUE llOwnerSay("Debug Mode Activated"); llMessageLinked(LINK_THIS,MODULE_HUD,"DEBUGON",llGetOwner()); } // DRAW weapons DRAW(string hand) { if ( hand == "left" ) { llWhisper(CHANATTACH,"DRAWLEFT"); return; } // draw left-hand weapon if ( hand == "right" ) { llWhisper(CHANATTACH,"DRAWRIGHT"); return; } // draw right-hand weapon if ( hand == "both" ) { llWhisper(CHANATTACH,"DRAWBOTH"); return; } // draw both weapons } // ERROR - show errors on debug channel with wearer name for sorting ERROR(string emessage) { llSay(DEBUG_CHANNEL,"ERROR ("+llKey2Name(PLAYERID)+"): "+emessage); } // HOLSTER weapons HOLSTER(string hand) { if ( hand == "left" ) { llWhisper(CHANATTACH,"HOLSTERLEFT"); return; } // holster left-hand weapon if ( hand == "right" ) { llWhisper(CHANATTACH,"HOLSTERRIGHT"); return; } // holster right-hand weapon if ( hand == "both" ) { llWhisper(CHANATTACH,"HOLSTERBOTH"); return; } // holster both weapons } // METER - update a hovertext health meter or HUD bar graph METER() { llMessageLinked(LINK_THIS,MODULE_HUD,"METER",PLAYERID); } // QUEST STATUS QUEST() { llMessageLinked(LINK_THIS,MODULE_HUD,"BAMSTATUS",PLAYERID); // send a status request to BAM Modules } // RELOAD RELOAD() { llWhisper(CHANATTACH,"RELOAD"); } // RESET - shut down running animations then reset the script to reload character sheet RESET() { if ( FLAG_DEAD == TRUE || FLAG_INCAPACITATED == TRUE ) { // don't allow reset if already on respawn timer llOwnerSay("Cannot reset while incapacitated or dead. You will respawn in a few moments."); return; } llOwnerSay("Resetting Myriad Lite. Please wait..."); // stop all running animations if ( FLAG_ANIMATE == TRUE ) { // do we have permission to animate? list anims = llGetAnimationList(PLAYERID); // 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 } } llMessageLinked(LINK_THIS,MODULE_HUD,"RESET",PLAYERID); // send reset to modules llResetScript(); // now reset this script } // ROLL DICE ROLL(string message) { list input = llParseString2List(message, [" ","d"],[] ); string command = llList2String(input,0); integer numberOfDice = llList2Integer(input,1); integer numberOfSides = llList2Integer(input,2); string output = ""; integer total = 0; if ( command == "roll" ) { if ( numberOfDice >= 1 && numberOfDice <= 20 ) { if ( numberOfSides > 1 && numberOfSides <= 100 ) { integer index; for( index = 1; index <= numberOfDice; index++) { integer roll = (integer)((llFrand(1.0) * numberOfSides)+1); output += (string)roll; output += ", "; total += roll; } string objname = llGetObjectName(); llSetObjectName("(("+llKey2Name(llGetOwner())); llWhisper(PUBLIC_CHANNEL,"/me rolls "+(string)numberOfDice+"d"+(string)numberOfSides+" resulting in "+output+" totalling "+(string)total+".))"); llSetObjectName(objname); return; } } llOwnerSay("To roll, say /5 roll #d# or /5 roll #d#. For example, saying /5 roll 1d20 in chat rolls one 20-sided dice.\""); } } // RPEVENT RPEVENT(string rpevent) { string oldname = llGetObjectName(); // save the current object name llSetObjectName("Myriad RP Event"); // change the object name to llOwnerSay(rpevent); // now tell the owner the rest of the RPEVENT| message //llRegionSay(CHANMYRIAD,"RPEVENT|"+NAME+" ("+PLAYERNAME+") "+rpevent); llSetObjectName(oldname); // restore the HUD back to its original name } // RUMOR CONTROL RUMOR(string cmdrumor) { DEBUG("Sending to rumor module: "+cmdrumor); llMessageLinked(LINK_THIS,MODULE_HUD,cmdrumor,PLAYERID); // relay rumor commands to module } // SAFETY OFF SAFETYOFF() { llWhisper(CHANATTACH, "SAFETYOFF"); } // SAFETY ON SAFETYON() { llWhisper(CHANATTACH, "SAFETYON"); } // SENDTOATTACHMENT SENDTOATTACHMENT(string msg) { DEBUG("SENDTOATTACHMENT("+msg+")"); llWhisper(CHANATTACH,msg); } // SENDTOMODULE SENDTOMODULE(string msg,key speaker) { DEBUG("SENDTOMODULE("+msg+")"); llMessageLinked(LINK_THIS,MODULE_HUD,msg,speaker); } // SETUP - begin bringing the HUD online SETUP() { FLAG_DEBUG = FALSE; CREDITS(); // show Myriad credits as required by the Creative Commons - Attribution license PLAYERID = llGetOwner(); // remember the owner's UUID PLAYERNAME = llKey2Name(PLAYERID); // remember the owner's legacy name llSetText("",<0,0,0>,0); // clear any previous hovertext // Talker/Emoter setup TRUENAME = BASENAME + " " + VERSION + " " + VERSIONDATE; // put together full item name for talker/emoter llSetObjectName(TRUENAME); // force object title back if the talker/emoter messed it up //llOwnerSay("Character Sheet loaded. You are now ready to roleplay."); if ( HANDMYRIAD != 0 ) llListenRemove(HANDMYRIAD); HANDMYRIAD = llListen(CHANMYRIAD,"",NULL_KEY,""); // setup listener for Myriad RP events if ( HANDCOMMAND != 0 ) llListenRemove(HANDCOMMAND); HANDCOMMAND = llListen(CHANCOMMAND,"",PLAYERID,""); // listen to chat commands from owner CHANHUD = (integer)("0x"+llGetSubString((string)llGetKey(),0,6)); // calculate a player-specfic dynamic chat channel if ( HANDHUD != 0 ) llListenRemove(HANDHUD); HANDHUD = llListen(CHANHUD,"",NULL_KEY,""); // listen on the HUD object dynamic chat channel CHANPLAYER = (integer)("0x"+llGetSubString((string)PLAYERID,0,6)); // calculate a player-specfic dynamic chat channel if ( HANDPLAYER != 0 ) llListenRemove(HANDPLAYER); HANDPLAYER = llListen(CHANPLAYER,"",NULL_KEY,""); // listen on the player dynamic chat channel CHANATTACH = (integer)("0x"+llGetSubString((string)PLAYERID,1,7)); // attachment-specific channel if ( HANDATTACH != 0 ) llListenRemove(HANDATTACH); HANDATTACH = llListen(CHANATTACH,"",NULL_KEY,""); // listen for messages from attachments CHANBAM = (integer)(CHAN_PREFIX + llGetSubString((string)PLAYERID,-7,-1)); if ( HANDBAM != 0 ) llListenRemove(HANDBAM); HANDBAM = llListen(CHANBAM,"",NULL_KEY,""); // start listener with listenremove handle // Talker/Emoter if ( HANDLE_OOCCHAT != 0 ) llListenRemove(HANDLE_OOCCHAT); HANDLE_OOCCHAT = llListen(CHANNEL_OOCCHAT,"",PLAYERID,""); if ( HANDLE_OOCEMOTE != 0 ) llListenRemove(HANDLE_OOCEMOTE); HANDLE_OOCEMOTE = llListen(CHANNEL_OOCEMOTE,"",PLAYERID,""); if ( HANDLE_ICCHAT != 0 ) llListenRemove(HANDLE_ICCHAT); HANDLE_ICCHAT = llListen(CHANNEL_ICCHAT,"",PLAYERID,""); if ( HANDLE_ICTHINK != 0 ) llListenRemove(HANDLE_ICTHINK); HANDLE_ICTHINK = llListen(CHANNEL_ICTHINK,"",PLAYERID,""); if ( HANDLE_ICEMOTE != 0 ) llListenRemove(HANDLE_ICEMOTE); HANDLE_ICEMOTE = llListen(CHANNEL_ICEMOTE,"",PLAYERID,""); if ( HANDLE_NARRATE != 0 ) llListenRemove(HANDLE_NARRATE); HANDLE_NARRATE = llListen(CHANNEL_NARRATE,"",PLAYERID,""); llOwnerSay("Registering any Myriad Lite-compatible attachments..."); llWhisper(CHANATTACH,"REGISTERATTACHMENTS"); // ask for attachments on their dynamic channel llRequestPermissions(PLAYERID,PERMISSION_TRIGGER_ANIMATION); // request perms to run stop all animation code if needed METER(); // update hovertext QUEST(); // update the BAM Module llOwnerSay("Myriad Lite HUD startup complete."); } // SHEATHE weapons SHEATHE(string hand) { if ( hand == "left" ) { llWhisper(CHANATTACH,"SHEATHELEFT"); return; } // sheathe left-hand weapon if ( hand == "right" ) { llWhisper(CHANATTACH,"SHEATHERIGHT"); return; } // sheathe right-hand weapon if ( hand == "both" ) { llWhisper(CHANATTACH,"SHEATHEBOTH"); return; } // sheathe both weapons } // An Unopposed Ability Test - Myriad PDF p. 19, Myriad Special Edition p. 25 // Requires TargetNumber, Attribute Name, Skill Name // Returns TRUE for Success and False for Fail integer UNOPPOSED_TEST(integer targetnum,integer tattribute,integer tskill ) { integer check = ABILITY_TEST(tattribute,tskill); // calculate the player's ability test value if ( check >= targetnum ) return TRUE; // player won the ability test return FALSE; // player lost the ability test } // DEFAULT STATE - load character sheet default { // ATTACH - logged in with meter or worn from inventory/ground while running attach(key id) { if ( id != NULL_KEY ) { RESET(); } } // COLLISION_START collision_start(integer num_detected) { if ( ALLOW_PHYS_BULLETS == FALSE ) return; // skip phys bullet code if ( FLAG_DEAD == TRUE ) return; // can't take more damage when dead, but you can when incapacitated while ( num_detected-- ) { // loop through all hits this server frame float impactspeed = llVecMag(llDetectedVel(num_detected)); if ( impactspeed > 15.0 && impactspeed <= 255.0 ) { // hit by something moving between 15.0 and 255.0 m/s integer impact = llRound( (impactspeed - 15.0) / 5.0 ) + 1; // calculate 1-5 range bands of damage from 0.0 to 240.0 speed // RANGEDCOMBAT|attackdice (1-5)|hitwho (my UUID here)|hitbywho (shooter UUID)|hitbywhat (objectname) string impactmsg = "RANGEDCOMBAT"+DIV+(string)impact+DIV+(string)llGetOwner()+DIV+(string)llGetOwnerKey(llDetectedKey(num_detected))+DIV+llDetectedName(num_detected); llMessageLinked(LINK_THIS,MODULE_HUD,impactmsg,llDetectedKey(num_detected)); } } } // CHANGED - triggered for many changes to the avatar // TODO reload sim-specific settings on region change changed(integer changes) { if ( changes & CHANGED_INVENTORY ) { // inventory changed somehow? llOwnerSay("Inventory changed. Reloading character sheet."); RESET(); // saved a new character sheet? - reset and re-read it. } if ( changes & CHANGED_REGION || changes & CHANGED_TELEPORT ) { llRequestPermissions(PLAYERID,PERMISSION_TRIGGER_ANIMATION); METER(); // update the meter after a shift } } // LINK MESSAGE - commands to and from other prims in HUD link_message(integer sender,integer sending_module,string str, key id) { if ( sending_module == MODULE_HUD ) return; // ignore our own link messages DEBUG("EVENT: link_message("+(string)sender+","+(string)sending_module+","+str+","+(string)id+")"); list fields = llParseString2List(str,[DIV],[]); // break into list of fields based on DIVider string command = llToLower(llStringTrim(llList2String(fields,0),STRING_TRIM)); // assume the first field is a Myriad Lite command string data = llStringTrim(llList2String(fields,1),STRING_TRIM); // field one is the data list subfields = llParseString2List(data,["="],[]); // break data field into comma-delimited subfields if needed if ( command == "set_name" ) { NAME = llList2String(subfields,1); // set the name return; } if ( command == "set_species" ) { SPECIES = llList2String(subfields,1); // set the species; return; } if ( command == "set_background" ) { BACKGROUND = llList2String(subfields,1); // set the species; return; } if ( command == "set_career" ) { CAREER = llList2String(subfields,1); // set the species; return; } if ( command == "set_statistic" ) { string statname = llList2String(subfields,0); // find the boon name integer statrank = llList2Integer(subfields,1); // find the boon rank value // TODO how to verify stat names are valid? if ( statrank >= MINSTAT && statrank <= MAXSTAT ) { // rank valid? STATISTICS = [statname,statrank] + STATISTICS; // add statistic to list } else { // invalid, report it ERROR("STATISTIC "+statname+" rank "+(string)statrank+" value out of allowed range: "+(string)MINSTAT+"-"+(string)MAXSTAT); } return; } if ( command == "set_resilience" ) { string resname = llList2String(subfields,0); // find the boon name integer resrank = llList2Integer(subfields,1); // find the boon rank value // TODO how to verify resilience names are valid? if ( resrank >= MINRESILIENCE && resrank <= MAXRESILIENCE ) { // rank valid? RESILIENCES = [resname,resrank] + RESILIENCES; // add resilience to list CURRENT_RESILIENCES = [resname,resrank] + CURRENT_RESILIENCES; // add to current list too } else { // invalid, report it ERROR("RESILIENCE "+resname+" rank "+(string)resrank+" value out of allowed range: "+(string)MINRESILIENCE+"-"+(string)MAXRESILIENCE); } return; } if ( command == "set_skill" ) { string skillname = llList2String(subfields,0); // find the skill name integer skillrank = llList2Integer(subfields,1); // find the skill rank // TODO how to verify skill names are valid? if ( skillrank >= MINSKILL && skillrank <= MAXSKILL ) { // skill rank valid? SKILLS = [skillname,skillrank] + SKILLS; // add skill to list } else { // invalid, report it ERROR("SKILL "+skillname+" rank "+(string)skillrank+" value out of allowed range: "+(string)MINSKILL+"-"+(string)MAXSKILL); } return; } if ( command == "character_loaded" ) { METER(); return; // we're out of notecard, so character sheet is loaded - start playing } if ( command == "armorcurrent" ) { // ARMORCURRENT|integer newcurrentarmor integer rating = llList2Integer(fields,1); if ( rating >= 0 && rating <= MAXARMOR ) { CURARMOR = rating; } return; } if ( llGetSubString(command,0,4) == "armor" ) { SENDTOATTACHMENT(str); return; } // process armor messages if ( sending_module == LM_SENDTOATTACHMENT ) { SENDTOATTACHMENT(str); return; } // send module messages to attachments if ( command == "rpevent" ) { RPEVENT(llList2String(fields,1)); return; } COMMAND(str); // send to shared command processor for chat and link messages return; } // LISTEN - the main Myriad Lite message processor for RP events and player commands listen(integer channel, string speakername, key speakerid, string message) { DEBUG("HUD Listen: channel=["+(string)channel+"] name=["+speakername+"] id=["+(string)speakerid+"] message=["+message+"]"); speakername = ""; // LSLINT // calculate the dynamic channel of who is speaking in case we need to return commands CHANOBJECT = (integer)(CHAN_PREFIX+llGetSubString((string)speakerid,0,6)); // break down the commands and messages into units we can work with list fields = llParseString2List(message,[DIV],[]); // break into list of fields based on DIVider string command = llList2String(fields,0); // assume the first field is a Myriad Lite command // --- PLAYER COMMAND CHANNEL if ( channel == CHANCOMMAND ) { // handle player chat commands COMMAND(message); // send to shared command processor for chat and link messages return; } // end of if channel == player commands // --- BAM CHANNEL if ( channel == CHANBAM ) { SENDTOMODULE(message,speakerid); // send BAM to Module return; } // end if channel BAMCHAN // --- Myriad Lite regionwide messages if ( channel == CHANMYRIAD ) { // handle Myriad system messages if ( command == "RPEVENT" ) { // Myriad Lite RPEVENT - roleplay events everyone might find interesting RPEVENT(llList2String(fields,1)); return; } // end if RPEVENT return; } // end if channel == CHANMYRIAD // --- ATTACHMENT CHANNEL if ( channel == CHANATTACH ) { // handle the attachment commands if ( FLAG_DEAD == TRUE || FLAG_INCAPACITATED == TRUE ) return; // can't mess with attachments while down if ( llToLower(llGetSubString(llStringTrim(command,STRING_TRIM),0,4)) == "armor" ) { SENDTOMODULE(message,PLAYERID); return; } // process armor messages if ( command == "ATTACHMELEE" || command == "ATTACHRANGED" ) { // holding a weapon rather than using fists? llMessageLinked(LINK_THIS,MODULE_HUD,message,PLAYERID); return; } if ( command == "DETACHMELEE" || command == "DETACHRANGED" ) { // are we going back to fists? llMessageLinked(LINK_THIS,MODULE_HUD,message,PLAYERID); return; } if ( command == "ATTACHMETER" || command == "DETACHMETER" ) { llMessageLinked(LINK_THIS,MODULE_HUD,message,PLAYERID); //METERWORN = TRUE; // we need to send meter events //METER(); // send update return; } } // --- CHANHUD - get region settings messages if ( channel == CHANHUD ) { llMessageLinked(LINK_THIS,MODULE_HUD,message,speakerid); return; // done with the HUD dynamic channel message processing, return } // --- CHANPLAYER if ( channel == CHANPLAYER ) { // handle player dynamic commands if ( command == "RPEVENT" ) { // Myriad Lite RPEVENT - roleplay events everyone might find interesting string oldname = llGetObjectName(); // save the current object name llSetObjectName("Myriad RP Event (Private)"); // change the object name to llOwnerSay(llList2String(fields,1)); // now tell the owner the rest of the RPEVENT| message llSetObjectName(oldname); // restore the HUD back to its original name return; } // end if RPEVENT // incoming message from rumor server? if ( llGetSubString(llToLower(llStringTrim(command,STRING_TRIM)),0,4) == "rumor" ) { llMessageLinked(LINK_THIS,MODULE_HUD,message,speakerid); // send message and key of speaker to rumors return; } if ( command == "UNOPPOSED_CHECK" ) { // object in sim wants a simple skill check integer targetnum = llList2Integer(fields,1); // what is unopposed check target num? integer tattrib = llList2Integer(fields,2); // target attribute integer tskill = llList2Integer(fields,3); // target skill UNOPPOSED_TEST(targetnum,tattrib,tskill); return; } if ( (command == "CLOSECOMBAT" || command == "RANGEDCOMBAT") && (FLAG_DEAD == TRUE || FLAG_INCAPACITATED == TRUE ) ) return; // can't fight when dead // The last action of the PLAYER CHAN processing is to put the message on the link-message bus // the speakerid is sent as the uuid field in case the modules need to send a message back out to another dynamic channel object // Incoming messages that go onto the bus to get handled by modules include: // CLOSEHIT - we've been hit and have to make an opposed ability test to avoid it // RANGEDHIT - mortal combat ranged combat attack message // HEALPARTIAL - heal some number of boxes of resilience // HEALFULL - heal 100 boxes of resilience // DUMP_PROGRESS - request from character builder to dump progress since last character build/progress session // GET_XP // SET_XP // GET_XPLEVEL // SET_XPLEVEL // GET_STAT // GET_RESILIENCE // GET_MAXRESILIENCE // SET_RESILIENCE llMessageLinked(LINK_THIS,MODULE_HUD,message,speakerid); // passthru incoming messages including Myriad Bullets return; // done with the player channel message processing, return } // end of if channel CHANPLAYER // Handle Out-Of-Character speaking if ( channel == CHANNEL_OOCCHAT ) { llSetObjectName(OOCPREFIX+PLAYERNAME); llSay(PUBLIC_CHANNEL,"/me says, \""+message+"\""+OOCSUFFIX); llSetObjectName(TRUENAME); return; } // Handle Out-Of-Character emotes if ( channel == CHANNEL_OOCEMOTE ) { llSetObjectName(OOCPREFIX+PLAYERNAME); llSay(PUBLIC_CHANNEL,"/me "+message+OOCSUFFIX); llSetObjectName(TRUENAME); return; } // Handle In-Character speaking if ( channel == CHANNEL_ICCHAT ) { llSetObjectName(NAME); llSay(PUBLIC_CHANNEL,"/me says, \""+message+"\""); llSetObjectName(TRUENAME); return; } // Handle In-Character thinking if ( channel == CHANNEL_ICTHINK ) { llSetObjectName(NAME); llSay(PUBLIC_CHANNEL,"/me thinks, \'"+message+"\'"); llSetObjectName(TRUENAME); return; } // Handle In-Character emotes if ( channel == CHANNEL_ICEMOTE ) { llSetObjectName(NAME); llSay(PUBLIC_CHANNEL,"/me "+message); llSetObjectName(TRUENAME); return; } // Handle Narration if ( channel == CHANNEL_NARRATE ) { llSetObjectName(""); llSay(PUBLIC_CHANNEL,"/me "+message); llSetObjectName(TRUENAME); return; } } // end listen // ON_REZ - logged in with meter, or worn from inventory while running on_rez(integer param) { param = 0; // LSLINT RESET(); // a reset to reload character } // STATE ENTRY state_entry() { SETUP(); } // TOUCH_START - touch HUD for adventure update touch_start(integer total_number) { total_number = 0; // LSLINT string action = llGetLinkName(llDetectedLinkNumber(0)); // get name of prim clicked in link set if ( action != "" && action != llGetObjectName() ) { // someone clicked a named button prim on this linkset COMMAND(action); // try that prim name as a command return; } METER(); QUEST(); } } // end state running // END