User:Allen Kerensky/Myriad Preview

From Second Life Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Myriad

Myriad and Myriad Lite Preview 1 June 2011

Myriad: A Universal RPG System

The Myriad RPG System was designed, written and illustrated by Ashok Desai Myriad is published under a Creative Commons License (Attribution 2.0 UK: England & Wales) http://creativecommons.org/licenses/by/2.0/uk/

Myriad: A Universal RPG System by Ashok Desai is freely downloadable as a PDF e-book from: http://www.lulu.com/product/file-download/myriad-rpg-system/307787 A purchasable "Myriad Special Extended Edition" is available from that site.

Myriad Lite RPG System (Preview 1)

The Myriad Lite RPG System was designed, written, and produced by Allen Kerensky (SL Avatar Name) The Myriad Lite software, scripts, and associated files below are published under the terms of the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported license http://creativecommons.org/licenses/by-nc-sa/3.0/ You must agree to the terms of this license before making any use of this software. If you do not agree to this license, simply delete these materials.

Introduction

The Myriad Lite project started as a quick weekend project to create the rudiments of a combat and roleplaying HUD/meter for virtual worlds, based on the freely and openly licensed Myriad RPG system. This kit represents a point-in-time snapshot of the initial working distribution of Myriad Lite, which I am making available freely to everyone to study, learn from, adapt, or contribute to. These scripts have been tested on SecondLife (http://secondlife.com) and OpenSim (on OSgrid http://osgrid.org).

The Myriad Lite Preview 1 Quick-start

Cut and paste all of the scripts below into your inventory, or download the kit in-world from SL Marketplace: [1]

Create an object to attach to your heads-up display. Drop the Myriad Lite script and default character sheet into the HUD attachment.

Create an armor attachment. Drop the Myriad Lite armor script into the attachment. The Myriad Lite meter should report the armor registration as a change in armor value.

Create a bullet object NOTE: It is best to do the bullet assembly in a parcel with scripts *disabled*. Create your bullet item. Drop in the bullet script *in a script-disabled area* Set the bullet object to "Physical" and "Temp On Rez" Quickly take your bullet into inventory before the temp on rez deletes it.

Create a target object. A "Noob" makes a perfectly useful target item. https://marketplace.secondlife.com/p/Art-Laxness-Noob-Pack/371307 Drop in the Target script.

Usage

Wear the HUD. Wear armor, which you should see reported in your chat window. Wear a firearm with a Myriad bullet in it.

Myriad Lite

<lsl> //============================================================================ // Myriad Lite v0.0.6 20110523 // Myriad Lite software Copyright (c) 2011 by Allen Kerensky (OSG/SL) // Myriad Lite is published under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported // The Myriad RPG System was designed, written, and illustrated by Ashok Desai // Myriad is published under the Creative Commons Attribution 2.0 UK: England and Wales. //============================================================================

key PLAYERID = NULL_KEY; string PLAYERNAME = "";

// Metadata string NAME = ""; string SPECIES = ""; // name of species template string BACKGROUND = ""; // name of background template string CAREER = ""; // name of career template

// Experience integer MINXP = 0; integer MAXXP = 2320; integer XP = 0; // 0-2320 integer MINLEVEL = 1; integer MAXLEVEL = 30; integer XPLEVEL = 1; // 1-30

// Attributes integer MINSTAT = 1; integer MAXSTAT = 5; integer POWER = 0; integer GRACE = 0; integer INTELLECT = 0; integer SPIRIT = 0;

// Resiliences integer MINRESILIENCE = 1; integer MAXRESILIENCE = 20; integer WOUNDS = 0; integer CURWOUNDS = 0; integer CRITICAL = 0; integer CURCRITICAL = 0; integer RESOLVE = 0; integer CURRESOLVE = 0;

// Boons integer MINBOON = 1; integer MAXBOON = 5; list BOONS = [];

// Flaws integer MINFLAW = 1; integer MAXFLAW = 5; list FLAWS = [];

// Skills [ string SkillName, integer SkillRank ] integer MINSKILL = 1; integer MAXSKILL = 5; list SKILLS = [];

// Special Effects (SFX) [ string EffectName, integer EffectRank ] integer MINEFFECT = 1; integer MAXEFFECT = 5; list EFFECTS = [];

// Stunts and Quotes list STUNTS = []; list QUOTES = [];

// Equipment [ string ItemName, integer NumberCarried ] integer MINEQUIPPED = 1; integer MAXEQUIPPED = 100; list EQUIPMENT = [];

// Notecard management runtimes string CARD = "Myriad Lite Character Sheet v0.0.2 20110521"; // name of character sheet notecard integer LINE = 0; // line number of notecard key QUERY = NULL_KEY; // to track notecard queries

// Channels - using HTCS defaults for now integer CHANMYRIAD = -999; // Messages sent to ALL Myriad players in region - CONSTANT integer HANDMYRIAD = 0; // Handle to close Myriad channel integer CHANPLAYER = 0; // Messages sent to one player - dynamic channel from player UUID integer HANDPLAYER = 0; // Handle to close player channel integer CHANOBJECT = 0; // Messages sent to one object - dynamic channel from object UUID integer HANDOBJECT = 0; // Handle to close object channel integer CHANCOMMAND = 5; // Messages sent by player to their meter - CONSTANT integer HANDCOMMAND = 0; // Handle to close command channel

// Melee and Ranged combat values integer MINDAMAGE = 1; integer MAXDAMAGE = 5; integer INCAPACITATED_FLAG = FALSE; string ANIM_INCAPACITATED = "incapacitated"; integer DEAD_FLAG = FALSE; string ANIM_DEAD = "dead";

// Armor integer MINATTACH = 1; integer MAXWEAR = 30; integer MAXATTACH = 38; list ATTACHPOINTS = ["INVALID","chest","head","left shoulder","right shoulder","left hand","right hand","left foot","right foot","back","pelvis","mouth","chin","left ear","right ear","left eye","right eye","nose","right upper arm","right lower arm","left upper arm","left lower arm","right hip","right upper leg","right lower leg","left hip","left upper leg","left lower leg","stomach","left pectoral","right pectoral","HUD Center 2","HUD Top Right","HUD Top","HUD Top Left","HUD Center","HUD Bottom Left","HUD Bottom","HUD Bottom Right" ]; integer MINARMOR = 1; integer MAXARMOR = 5; // list of armor amounts worn on all attach points list ARMOR = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; integer CURARMOR = 0;

string DIV="|"; // message field divider

ERROR(string message) {

   llSay(DEBUG_CHANNEL,"("+llKey2Name(llGetOwner())+") "+message);

}

// Wear a piece of armor WEARARMOR(integer waattachpoint,integer waamount) {

   if ( waattachpoint < MINATTACH || waattachpoint > MAXWEAR ) {
       ERROR("Invalid armor attachment point "+llList2String(ATTACHPOINTS,waattachpoint));
       return;
   }
   ARMOR = llListReplaceList(ARMOR,[waamount],waattachpoint,waattachpoint);
   RECALCULATE_ARMOR();

}

// Remove a piece of armor REMOVEARMOR(integer raattachpoint,integer raamount) {

   if ( raattachpoint < MINATTACH || raattachpoint > MAXWEAR ) {
       ERROR("Invalid armor detachment point "+llList2String(ATTACHPOINTS,raattachpoint));
       return;
   }
   ARMOR = llListReplaceList(ARMOR,[0],raattachpoint,raattachpoint);
   RECALCULATE_ARMOR();

}

// Find the highest armor value of all the armor worn RECALCULATE_ARMOR() {

   CURARMOR = 0;
   integer racount = llGetListLength(ARMOR);
   while (racount--) {
       integer rapoints = llList2Integer(ARMOR,racount);
       if ( rapoints > CURARMOR ) {
           CURARMOR = rapoints;
       }
   }
   llOwnerSay("New Armor Rating is "+(string)CURARMOR);

}

// Making A Damage Roll (Myriad p25, Myriad Special Edition p31) HIT(integer attackdice) {

   integer damagetaken = 0;
   while(attackdice--) { // roll a damage dice for each dice of attack
       integer dieroll = 1+(integer)llFrand(5.0); // hell of a way to have to roll a reasonable uniform d6
       // armor check
       if ( dieroll > CURARMOR ) {
           damagetaken++;
       }
   }
   // finished rolling hit dice, how did we do?
   if ( damagetaken > 0 ) {
       if ( CURARMOR > 0 ) {
           llOwnerSay("That attack penetrated your armor and you've been wounded!");
       } else {
           llOwnerSay("You've been wounded! Perhaps some armor would help, Conan?");
       }
       WOUNDED(damagetaken);
   } else {
       llOwnerSay("Your armor took the damage from that attack!");
   }

}

WOUNDED(integer amount) {

   while (amount--) {
       CURWOUNDS--;
       if ( CURWOUNDS < 1 ) { // incapacitated
           CURWOUNDS = 0;
           INCAPACITATED();
           CURCRITICAL--;
           if ( CURCRITICAL < 1 ) { // dead
               CURCRITICAL = 0;
               DEAD();
           }
       }
   }

}

INCAPACITATED() {

   INCAPACITATED_FLAG = TRUE;
   llStartAnimation(ANIM_INCAPACITATED);

}

DEAD() {

   DEAD_FLAG = TRUE;
   llStartAnimation(ANIM_DEAD);

}

// Get Attribute Value by Name integer GET_ATTRIB_BY_NAME(string attrib) {

   integer stat = 0;
   attrib = llToLower(attrib);
   if ( attrib == "POWER" ) stat = POWER;
   if ( attrib == "GRACE" ) stat = GRACE;
   if ( attrib == "INTELLECT" ) stat = INTELLECT;
   if ( attrib == "SPIRIT" ) stat = SPIRIT;
   if ( stat < 1 ) {
       ERROR("Invalid attribute for ability test: "+attrib);
       return 0;
   }
   return stat;

}

//============================================================= // GET_SKILL_RANK - find the current ranks (1-5) of a named skill // Requires: A case-sensitive string of the skill name to find // Returns: A zero for any skill the player does not possess, or the player's rank value 1-5 for the skill //============================================================= integer GET_SKILL_RANK(string askill) {

   integer atskill = 0; // set default to return zero as skill value if requested skill is not found in skill list
   integer whereskill = llListFindList(SKILLS,[askill]); // search the skill list for requested skill by name
   if ( whereskill >= 0 ) {
       integer atskill = llList2Integer(SKILLS,++whereskill); // get the skill rank in the next position after skill name in list
       if ( atskill >= MINSKILL && atskill <= MAXSKILL) return atskill; // if rank found is valid, return that as skill value
   }
   return 0; // no valid skill found, return nothing instead

}

// ABILITY TEST // Requires ATTRIBUTE NAME, SKILL NAME // Returns the ability test score for use by success fail, opposed rolls, etc integer ABILITY_TEST(integer attribute,integer skill) {

   integer highroll = 0;
   while( attribute-- ) {
       integer roll = 1+(integer)llFrand(5.0);
       if ( roll > highroll) highroll = roll;
   }
   return highroll + skill;

}

// An Unopposed Ability Test // 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);
   if ( check >= targetnum ) return TRUE;
   return FALSE;    

}

// An Opposed Ability Test // Requires Attacker Attribute Name, Attacker Skill Name, Defender Attribute Name, Defender Skill Name // Returns TRUE for Success, FALSE for failure integer OPPOSED_TEST(integer aattrib,integer askill,integer dattrib,integer dskill) {

   integer acheck = ABILITY_TEST(aattrib,askill);
   integer dcheck = ABILITY_TEST(dattrib,dskill);
   if ( acheck > dcheck ) return TRUE;
   return FALSE;

}

SETUP() {

   CREDITS();
   llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION);
   llOwnerSay("Loading character sheet... please wait.");
   if ( llGetInventoryName(INVENTORY_NOTECARD,0) == CARD ) { // check inventory for notecard
       QUERY = llGetNotecardLine(CARD,LINE++);
   } else {
       ERROR("Cannot locate character sheet notecard by name: "+CARD);
   }

}

CREDITS() {

   llOwnerSay("Myriad Lite software Copyright (c) 2011 by Allen Kerensky (OSG/SL)");
   llOwnerSay("Licensed under Creative Commons Attribution-Share Alike-Non-Commercial 3.0 Unported.");
   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.");

}

// Default State - load character sheet default {

   state_entry() {
       SETUP();
   }
   attach(key id) {
       SETUP();
   }
   
   run_time_permissions(integer perm) {
       if ( perm & PERMISSION_TAKE_CONTROLS ) {
           //llTakeControls(0xFFFFFFFF,TRUE,TRUE);
       }
       if ( perm & PERMISSION_TRIGGER_ANIMATION ) {
       }
   }
   
   dataserver(key queryid,string data) {
       if ( queryid == QUERY ) { // is this the line we asked for?
           if ( llGetSubString(data,0,0) == "#" ) { // is line a comment
               QUERY = llGetNotecardLine(CARD,LINE++); // trigger request for next line
               return; // exit early
           }
           if ( data != EOF ) {
               // Parse line
               list FIELDS = llParseString2List(data,["="],[]);
               string CMD = llStringTrim(llList2String(FIELDS,0),STRING_TRIM);
               string DATA = llStringTrim(llList2String(FIELDS,1),STRING_TRIM);
               list SUBFIELDS = llParseString2List(DATA,[","],[]);
               if ( CMD == "NAME" ) {
                   NAME = DATA;
               }
               if ( CMD == "SPECIES" ) {
                   SPECIES = DATA;
               }
               if ( CMD == "BACKGROUND" ) {
                   BACKGROUND = DATA;
               }
               if ( CMD == "CAREER" ) {
                   CAREER = DATA;
               }
               if ( CMD == "XP" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINXP && amount <= MAXXP ) {
                       XP = amount;
                   } else {
                       ERROR("XP amount out of allowed range: "+(string)MINXP+"-"+(string)MAXXP);
                   }
               }
               if ( CMD == "XPLEVEL" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINLEVEL && amount <= MAXLEVEL ) {
                       XPLEVEL = amount;
                   } else {
                       ERROR("XPLEVEL amount out of allowed range: "+(string)MINLEVEL+"-"+(string)MAXLEVEL);
                   }
               }
               if ( CMD == "POWER" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINSTAT && amount <= MAXSTAT ) {
                       POWER = amount;
                   } else {
                       ERROR("POWER amount out of allowed range: "+(string)MINSTAT+"-"+(string)MAXSTAT);
                   }
               }
               if ( CMD == "GRACE" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINSTAT && amount <= MAXSTAT ) {
                       GRACE = amount;
                   } else {
                       ERROR("GRACE amount out of allowed range: "+(string)MINSTAT+"-"+(string)MAXSTAT);
                   }
               }
               if ( CMD == "INTELLECT" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINSTAT && amount <= MAXSTAT ) {
                       INTELLECT = amount;
                   } else {
                       ERROR("INTELLECT amount out of allowed range: "+(string)MINSTAT+"-"+(string)MAXSTAT);
                   }
               }
               if ( CMD == "SPIRIT" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINSTAT && amount <= MAXSTAT ) {
                       SPIRIT = amount;
                   } else {
                       ERROR("SPIRIT amount out of allowed range: "+(string)MINSTAT+"-"+(string)MAXSTAT);
                   }
               }
               if ( CMD == "WOUNDS" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINRESILIENCE && amount <= MAXRESILIENCE ) {
                       WOUNDS = amount;
                       CURWOUNDS = amount;
                   } else {
                       ERROR("WOUNDS amount out of allowed range: "+(string)MINRESILIENCE+"-"+(string)MAXRESILIENCE);
                   }
               }
               if ( CMD == "CRITICAL" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINRESILIENCE && amount <= MAXRESILIENCE ) {
                       CRITICAL = amount;
                       CURCRITICAL = amount;
                   } else {
                       ERROR("CRITICAL amount out of allowed range: "+(string)MINRESILIENCE+"-"+(string)MAXRESILIENCE);
                   }
               }
               if ( CMD == "RESOLVE" ) {
                   integer amount = (integer)DATA;
                   if ( amount >= MINRESILIENCE && amount <= MAXRESILIENCE ) {
                       RESOLVE = (integer)DATA;
                   } else {
                       ERROR("RESOLVE amount out of allowed range: "+(string)MINRESILIENCE+"-"+(string)MAXRESILIENCE);
                   }
               }
               if ( CMD == "BOON" ) {
                   string boonname = llList2String(SUBFIELDS,0);
                   integer boonrank = llList2Integer(SUBFIELDS,1);
                   if ( boonrank >= MINBOON && boonrank <= MAXBOON ) {
                       BOONS = [boonname,boonrank] + BOONS;
                   } else {
                       ERROR("BOON rank out of allowed range: "+(string)MINBOON+"-"+(string)MAXBOON);
                   }
               }                
               if ( CMD == "FLAW" ) {
                   string flawname = llList2String(SUBFIELDS,0);
                   integer flawrank = llList2Integer(SUBFIELDS,1);
                   if ( flawrank >= MINFLAW && flawrank <= MAXFLAW ) {
                       FLAWS = [flawname,flawrank] + FLAWS;
                   } else {
                       ERROR("FLAW rank out of allowed range: "+(string)MINFLAW+"-"+(string)MAXFLAW);
                   }
               }
               if ( CMD == "SKILL" ) {
                   string skillname = llList2String(SUBFIELDS,0);
                   integer skillrank = llList2Integer(SUBFIELDS,1);
                   if ( skillrank >= MINSKILL && skillrank <= MAXSKILL ) {
                       SKILLS = [skillname,skillrank] + SKILLS;
                   } else {
                       ERROR("SKILL rank out of allowed range: "+(string)MINSKILL+"-"+(string)MAXSKILL);
                   }
               }
               if ( CMD == "EFFECT" ) {
                   string effectname = llList2String(SUBFIELDS,0);
                   integer effectrank = llList2Integer(SUBFIELDS,1);
                   if ( effectrank >= MINEFFECT && effectrank <= MAXEFFECT ) {
                       EFFECTS = [effectname,effectrank] + EFFECTS;
                   } else {
                       ERROR("EFFECT rank out of allowed range: "+(string)MINEFFECT+"-"+(string)MAXEFFECT);
                   }
               }
               if ( CMD == "STUNT" ) {
                   string stuntname = llList2String(SUBFIELDS,0);
                   STUNTS = [stuntname] + STUNTS;
               }
               if ( CMD == "QUOTE" ) {
                   string quotename = llList2String(SUBFIELDS,0);
                   QUOTES = [quotename] + QUOTES;
               }                
               if ( CMD == "EQUIPMENT" ) {
                   string equipmentname = llList2String(SUBFIELDS,0);
                   integer equipmentamount = llList2Integer(SUBFIELDS,1);
                   if ( equipmentamount >= MINEQUIPPED && equipmentamount <= MAXEQUIPPED ) {
                       EQUIPMENT = [equipmentname,equipmentamount] + EQUIPMENT;
                   } else {
                       ERROR("EQUIPMENT amount out of allowed range: "+(string)MINEQUIPPED+"-"+(string)MAXEQUIPPED);
                   }
               }
           } else { // end of notecard
               state running;
           }
           QUERY = llGetNotecardLine(CARD,LINE++); // trigger request for next line
       }
   }

}

state running {

   state_entry() {
       llOwnerSay("Character Sheet loaded. You are now ready to roleplay.");
       HANDMYRIAD = llListen(CHANMYRIAD,"",NULL_KEY,"");
       HANDCOMMAND = llListen(CHANCOMMAND,"",llGetOwner(),""); // listen to owner only on COMMAND
       CHANPLAYER = (integer)("0x"+llGetSubString((string)llGetOwner(),0,6));
       HANDPLAYER  = llListen(CHANPLAYER,"",NULL_KEY,"");
       llOwnerSay("Registering attachments...");
       llWhisper(CHANPLAYER,"REGISTERATTACHMENTS");
   }
   
   on_rez(integer rezparam) {
       llResetScript();
   }
   
   attach(key id) {
       llResetScript();
   }
   
   changed(integer changes) {
       if ( changes & CHANGED_INVENTORY ) {
           llOwnerSay("Inventory changed. Reloading.");
           llResetScript();
       }
   }
   listen(integer channel, string speakername, key speakerid, string message) {
       // calculate the dynamic channel of who is speaking in case we need to return commands
       CHANOBJECT = (integer)("0x"+llGetSubString((string)speakerid,0,6));
       list fields = llParseString2List(message,["|"],[]);
       string command = llList2String(fields,0);
       if ( channel == CHANMYRIAD ) { // handle Myriad system messages
           if ( command == "RPEVENT" ) {
               string oldname = llGetObjectName();
               llSetObjectName("Myriad RP Event");
               llOwnerSay(llList2String(fields,1));
               llSetObjectName(oldname);
           }
           return;
       }
       if ( channel == CHANCOMMAND ) { // handle player chat commands
           if ( command == "RESET" ) {
               llOwnerSay("Resetting on your command.");
               llResetScript();
           }
       }
       if ( channel == CHANPLAYER ) { // handle player dynamic commands
           if ( command == "ATTACHARMOR" ) { // player attached armor somewhere
               integer armorrating = llList2Integer(fields,1);
               integer attachpoint = llList2Integer(fields,2);
               string armorname = llList2String(fields,3);
               if ( armorrating >= MINARMOR && armorrating <= MAXARMOR ) {
                   llOwnerSay("Armor "+(string)armorrating+" attached to "+llList2String(ATTACHPOINTS,attachpoint));
                   WEARARMOR(attachpoint,armorrating);
               } else {
                   ERROR("ARMOR amount out of allowed range "+(string)MINARMOR+"-"+(string)MAXARMOR);
               }
               return;
           }
           if ( command == "DETACHARMOR" ) { // player attached armor somewhere
               integer armorrating = llList2Integer(fields,1);
               integer attachpoint = llList2Integer(fields,2);
               string armorname = llList2String(fields,3);
               if ( armorrating >= MINARMOR && armorrating <= MAXARMOR ) {
                   llOwnerSay("Armor "+(string)armorrating+" detached from "+llList2String(ATTACHPOINTS,attachpoint));
                   REMOVEARMOR(attachpoint,armorrating);
               } else {
                   ERROR("ARMOR amount out of allowed range "+(string)MINARMOR+"-"+(string)MAXARMOR);
               }
               return;
           }
           // If Your Bullet has hit, let's fire a hitcheck regionwide at targetplayer's channel
           if ( command == "TOHIT" ) {
               integer attdice = llList2Integer(fields,1);
               string hitwho = llList2String(fields,2);
               string bywho = llList2String(fields,3);
               string bywhat = llList2String(fields,4);
               integer victimchan = (integer)("0x"+llGetSubString(hitwho,0,6));
               integer attskill = GET_SKILL_RANK("Ranged Combat");
               llRegionSay(victimchan,"HITCHECK"+DIV+(string)POWER+DIV+(string)attskill+DIV+(string)attdice+DIV+bywho+DIV+bywhat);
           }
           // we've been hit and have to make a hit check
           if ( command == "HITCHECK" ) {
               integer attackstat = llList2Integer(fields,1);
               integer attackskill = llList2Integer(fields,2);
               integer attackdice = llList2Integer(fields,3); 
               key owner = llList2Key(fields,4);
               string item = llList2String(fields,5);               
               if ( attackstat < MINSTAT || attackstat > MAXSTAT ) {
                   ERROR("Attack stat value out of range: "+(string)MINSTAT+"-"+(string)MAXSTAT);
                   return;
               }
               if ( attackskill < MINSKILL || attackstat > MAXSKILL ) {
                   ERROR("Attack skill value out of range: "+(string)MINSKILL+"-"+(string)MAXSKILL);
                   return;
               }                
               if ( attackdice < MINDAMAGE || attackdice > MAXDAMAGE ) {
                   ERROR("Attack dice value out of range: "+(string)MINDAMAGE+"-"+(string)MAXDAMAGE);
               }
               integer rcskill = GET_SKILL_RANK("Ranged Combat");
               integer amihit = OPPOSED_TEST(attackstat,attackskill,GRACE,rcskill);
               if ( amihit == TRUE ) {
                   llOwnerSay("You've been hit by "+llKey2Name(owner)+"'s "+item+"!");
                   HIT(attackdice);                
               }
               return;
           }
       }
   }

} </lsl>

Myriad Lite Character Sheet

<lsl>

  1. =======================================================
  2. Myriad Lite Character Sheet v0.0.2 20110521
  3. =======================================================

NAME=Myriad Player SPECIES=Human BACKGROUND=Normal CAREER=None

  1. =======================================================
  2. Experience Points
  3. Example Format: XP=ExperiencePoints
  4. ExperiencePoints is an integer number 0-2320
  5. Example Format: XPLEVEL=Level
  6. Level is an integer number from 1-30
  7. =======================================================

XP=0 XPLEVEL=1

  1. =======================================================
  2. ATTRIBUTES
  3. Each Attribute is a single integer number 1-10
  4. Mortal Humans will range from 1-5
  5. Attributes greater than 5 are reserved for supernatural or superhuman monsters, aliens, deites, etc
  6. Example: POWER=1
  7. =======================================================

POWER=3 GRACE=3 INTELLECT=3 SPIRIT=3

  1. =======================================================
  2. RESILIENCES
  3. Each Resilience is a single integer number 1-20
  4. Example: WOUNDS=1
  5. =======================================================

WOUNDS=3 CRITICAL=2 RESOLVE=3

  1. =======================================================
  2. Boons
  3. Boon Lines have two subfields, separated by a comma
  4. Boon Name is a string of characters which do not contain a comma
  5. Boon Rank is an integer number 1-5
  6. Example Format: BOON = BoonName,BoonRank
  7. Example: BOON=Ally,1
  8. List one BOON line for each boon you have
  9. =======================================================

BOON=Ally,1

  1. =======================================================
  2. Flaws
  3. Flaw Lines have two subfields, separated by a comma
  4. Flaw Name is a string of characters which do not contain a comma
  5. Flaw Rank is an integer number 1-5
  6. Example Format: FLAW = FlawName,FlawRank
  7. Example: FLAW=Enemy,1
  8. List one FLAW line for each flaw you have
  9. =======================================================

FLAW=Enemy,1

  1. =======================================================
  2. SKILLS
  3. Skill Lines have two subfields, separated by a comma
  4. Skill Name is a string of characters which do not contain a comma
  5. Skill Rank is an integer number 1-5
  6. Example Format: SKILL = SkillName,SkillRank
  7. Example: SKILL=Arts and Crafts,1
  8. List one SKILL line for each skill you have
  9. =======================================================

SKILL=Ranged Combat,1

  1. =======================================================
  2. Effect lines have two subfields, separated by a comma
  3. Example Format: EFFECT=EffectName,EffectRank
  4. EffectName is a string of characters which do not contain a comma
  5. EffectRank is an integer number 1-5
  6. Effects which do not list or use ranks, will be EffectRank=1
  7. Example: EFFECT=Animal Call,1
  8. List one EFFECT line for each Special Effect you have
  9. =======================================================

EFFECT=Aura of Innocence,1

  1. =======================================================
  2. STUNTS
  3. Stunt lines are simple STUNT=stunttext
  4. =======================================================

STUNTS=

  1. =======================================================
  2. QUOTES
  3. Quote lines are simple QUOTE=quotetext
  4. =======================================================

QUOTE=

  1. =======================================================
  2. Equipment
  3. Equipment Liines have two subfields separated by a comma
  4. EquipmentName is a string of characters which do not contain a comma
  5. NumberCarried is an integer number 0 to whatever
  6. Example Format = EquipmentName,NumberCarried
  7. Example: EQUIPMENT=Lockpick Set,1
  8. List one EQUIPMENT line for each item you carry
  9. =======================================================

EQUIPMENT=ICS 45,1 EQUIPMENT=Body Armor,1 </lsl>

Myriad Lite Armor

<lsl> //============================================================================ // Myriad Lite Armor v0.0.1 20110519 // Copyright (c) 2011 By Allen Kerensky (OSG/SL) // The Myriad RPG System was designed, written, and illustrated by Ashok Desai // Myriad is published under a: // Creative Commons License (Attribution 2.0 UK: England and Wales) // Myriad Lite Armor is published under a: // Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported //============================================================================

key WEARER = NULL_KEY; integer ATTACHPOINT = 0; integer MINARMOR = 1; integer MAXARMOR = 5; // Archaic Armor Ratings // 1 Soft leather, heavy cloth // 2 Hardened leather, thick hide // 3 Chain mail, dragon hide // 4 Full plate mail, mithril chain // 5 Mithril plate mail // Modern Armor Ratings // 1 Leather jacket // 2 Bullet-proof vest // 3 SWAT tactical armor // 4 Advanced military armor // 5 Sci-fi powered battle armor integer ARMORRATING = 1; string DIV="|";

integer CHANPLAYER; integer HANDPLAYER;

default {

   state_entry() {
       CHANPLAYER = (integer)("0x"+llGetSubString((string)llGetOwner(),0,6));
       HANDPLAYER = llListen(CHANPLAYER,"",NULL_KEY,"");
   }
   attach(key id) {
       if ( id != NULL_KEY ) {
           WEARER = id;
           ATTACHPOINT = llGetAttached();
           integer dynchan = (integer)("0x"+llGetSubString((string)WEARER,0,6));
           llWhisper(dynchan,"ATTACHARMOR"+DIV+(string)ARMORRATING+DIV+(string)ATTACHPOINT+DIV+llGetObjectName());
       } else {
           integer dynchan = (integer)("0x"+llGetSubString((string)WEARER,0,6));
           if ( dynchan != 0 ) {
               llWhisper(dynchan,"DETACHARMOR"+DIV+(string)ARMORRATING+DIV+(string)ATTACHPOINT+DIV+llGetObjectName());
           } else {
               llSay(DEBUG_CHANNEL,"DETACH EVENT WITHOUT PREVIOUS ATTACH?");
           }
           WEARER = NULL_KEY;
           ATTACHPOINT = 0;
       }
   }
   listen(integer channel,string speakername,key speakerid,string message) {
       if ( message == "REGISTERATTACHMENTS" ) {
           WEARER = llGetOwner();
           ATTACHPOINT = llGetAttached();
           integer dynchan = (integer)("0x"+llGetSubString((string)WEARER,0,6));
           llWhisper(dynchan,"ATTACHARMOR"+DIV+(string)ARMORRATING+DIV+(string)ATTACHPOINT+DIV+llGetObjectName());
       }
   }

} </lsl>

Myriad Lite Bullet

<lsl> //============================================================================ // Myriad Lite Bullet v0.0.2 20110522 // Copyright (c) 2011 By Allen Kerensky (OSG/SL) // The Myriad RPG System was designed, written, and illustrated by Ashok Desai // Myriad is published under a: // Creative Commons License (Attribution 2.0 UK: England and Wales) // Myriad Lite Bullet is published under a: // Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported //============================================================================ // Davada Gallant (John Girard), WWIIOLers // Retrieved 2011-04-30 from http://wiki.secondlife.com/wiki/Bullet // Copyright (c) 2009 Linden Research, Inc. Licensed under Creative Commons Attribution-Share Alike 3.0 (CC-BY-SA 3.0) // Adapted to OSSL by Allen Kerensky (SL/OSG) // Includes Keknehv's Particle Script v1.2

//============================================================================ // Bullet Configuration //============================================================================ string RICOCHET = "nebs_smoke_particle_01"; // puff-of-smoke texture to show on bullet hits/ricochets - put this texture in bullet prim float BOUYANCY = 1.0; // how buoyant is the bullet for physics float TIMEOUT = 20.0; // control timer to force bullet to die

// Myriad config integer MINDAMAGE = 1; integer MAXDAMAGE = 5; integer DAMAGE = 1; string DIV = "|"; integer CHANMYRIAD = -999;

SETUP(integer type) {

   if ( llGetStatus(STATUS_PHYSICS) == FALSE ) { 
       llSetStatus(STATUS_PHYSICS, TRUE);
   }
   llSetStatus(STATUS_DIE_AT_EDGE, TRUE);
   llSetPrimitiveParams([PRIM_TEMP_ON_REZ,TRUE]);
   llSetBuoyancy(BOUYANCY); 
   if ( type >= MINDAMAGE && type <= MAXDAMAGE ) {
       DAMAGE = type;
   }
   llSetDamage((float)DAMAGE);
   llSetTimerEvent(TIMEOUT);

}

//============================================================================ // Keknehv's Particle Script v1.2 // Retrieved 2011-04-30 from http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryKeknehvParticles // 1.0 -- 5/30/05 // 1.1 -- 6/17/05 // 1.2 -- 9/22/05 (Forgot PSYS_SRC_MAX_AGE) // This script may be used in anything you choose, including and not limited to commercial products. // Just copy the MakeParticles() function; it will function without any other variables in a different script // ( You can, of course, rename MakeParticles() to something else, such as StartFlames() ) MAKEPARTICLES(string texture) { //This is the function that actually starts the particle system.

   llParticleSystem([                   //KPSv1.0  
       PSYS_PART_FLAGS , 0 //Comment out any of the following masks to deactivate them
   //| PSYS_PART_BOUNCE_MASK           //Bounce on object's z-axis
   | PSYS_PART_WIND_MASK             //Particles are moved by wind
   | PSYS_PART_INTERP_COLOR_MASK       //Colors fade from start to end
   | PSYS_PART_INTERP_SCALE_MASK       //Scale fades from beginning to end
   //| PSYS_PART_FOLLOW_SRC_MASK         //Particles follow the emitter
   //| PSYS_PART_FOLLOW_VELOCITY_MASK    //Particles are created at the velocity of the emitter
   //| PSYS_PART_TARGET_POS_MASK       //Particles follow the target
   | PSYS_PART_EMISSIVE_MASK           //Particles are self-lit (glow)
   //| PSYS_PART_TARGET_LINEAR_MASK    //Undocumented--Sends particles in straight line?
   ,
   
   //PSYS_SRC_TARGET_KEY , NULL_KEY,   //Key of the target for the particles to head towards
                                               //This one is particularly finicky, so be careful.
   //Choose one of these as a pattern:
   //PSYS_SRC_PATTERN_DROP                 Particles start at emitter with no velocity
   //PSYS_SRC_PATTERN_EXPLODE              Particles explode from the emitter
   //PSYS_SRC_PATTERN_ANGLE                Particles are emitted in a 2-D angle
   //PSYS_SRC_PATTERN_ANGLE_CONE           Particles are emitted in a 3-D cone
   //PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY     Particles are emitted everywhere except for a 3-D cone
   
   PSYS_SRC_PATTERN,           PSYS_SRC_PATTERN_EXPLODE
   
   ,PSYS_SRC_TEXTURE,           texture            //UUID of the desired particle texture, or inventory name
   ,PSYS_SRC_MAX_AGE,           1.0                //Time, in seconds, for particles to be emitted. 0 = forever
   ,PSYS_PART_MAX_AGE,          5.0                //Lifetime, in seconds, that a particle lasts
   ,PSYS_SRC_BURST_RATE,        0.02               //How long, in seconds, between each emission
   ,PSYS_SRC_BURST_PART_COUNT,  1                  //Number of particles per emission
   ,PSYS_SRC_BURST_RADIUS,      0.01                //Radius of emission
   ,PSYS_SRC_BURST_SPEED_MIN,   0.01                //Minimum speed of an emitted particle
   ,PSYS_SRC_BURST_SPEED_MAX,   1.0                //Maximum speed of an emitted particle
   ,PSYS_SRC_ACCEL,             <0.05,0.05,0.05>     //Acceleration of particles each second
   ,PSYS_PART_START_COLOR,      <1.0,1.0,1.0>      //Starting RGB color
   ,PSYS_PART_END_COLOR,        <1.0,1.0,1.0>      //Ending RGB color, if INTERP_COLOR_MASK is on 
   ,PSYS_PART_START_ALPHA,      0.9                //Starting transparency, 1 is opaque, 0 is transparent.
   ,PSYS_PART_END_ALPHA,        0.0                //Ending transparency
   ,PSYS_PART_START_SCALE,      <0.5,0.5,0.0>      //Starting particle size
   ,PSYS_PART_END_SCALE,        <1.0,1.0,0.0>      //Ending particle size, if INTERP_SCALE_MASK is on
   ,PSYS_SRC_ANGLE_BEGIN,       PI                 //Inner angle for ANGLE patterns
   ,PSYS_SRC_ANGLE_END,         PI                 //Outer angle for ANGLE patterns
   ,PSYS_SRC_OMEGA,             <0.0,0.0,0.0>       //Rotation of ANGLE patterns, similar to llTargetOmega()
           ]);

}

DIE() {

   while ( TRUE == TRUE ) {
       llDie();
   }

}

default {

   state_entry() {
       SETUP(DAMAGE);
   }
   
   on_rez(integer start_param) {
       SETUP(start_param);
   }
   
   collision_start(integer collisions) {
       while(collisions--) {
           
           integer dynchan = (integer)("0x"+llGetSubString((string)llGetOwner(),0,6));
           llRegionSay(dynchan,"TOHIT"+DIV+(string)DAMAGE+DIV+(string)llDetectedKey(collisions)+DIV+(string)llGetOwner()+DIV+llGetObjectName());
           
           key who = llDetectedKey(collisions);
           key owner = llList2Key(llGetObjectDetails(who,[OBJECT_OWNER]),0);
           if ( who == owner ) { // we hit an avatar
               llRegionSay(CHANMYRIAD,"RPEVENT"+DIV+llKey2Name(llGetOwner())+" shot "+llDetectedName(collisions)+"!");
           }
       }
       // Shrapnel?
       // Through and through?
       MAKEPARTICLES(RICOCHET);
       DIE();
   }
   
   land_collision_start( vector collisions) {
       MAKEPARTICLES(RICOCHET);
       DIE();
   }    
   
   timer() {
       DIE();
   }

} </lsl>

Myriad Lite Target

<lsl> //============================================================================ // Myriad Target v0.0.4 20110523 // Copyright (c) 2011 By Allen Kerensky (OSG/SL) // The Myriad RPG System was designed, written, and illustrated by Ashok Desai // Myriad is published under a: // Creative Commons License (Attribution 2.0 UK: England and Wales) // Myriad Lite Target is published under a: // Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported //============================================================================

integer CHANOBJECT; integer HANDOBJECT; integer MINSTAT = 1; integer MAXSTAT = 10; integer MINSKILL = 1; integer MAXSKILL = 5; integer MINDAMAGE = 1; integer MAXDAMAGE = 5;

ERROR(string errmsg) {

   llSay(DEBUG_CHANNEL,"ERROR: "+errmsg);

}

default {

   state_entry() {
       llSetPrimitiveParams([PRIM_PHANTOM, FALSE]);
       CHANOBJECT = (integer)("0x"+llGetSubString((string)llGetKey(),0,6));
       HANDOBJECT = llListen(CHANOBJECT,"",NULL_KEY,"");        
   }
   
   on_rez(integer rez_param) {
       llResetScript();
   }
   listen(integer channel,string speakername,key speakerid,string message) {
       list fields = llParseString2List(message,["|"],[]);
       string command = llList2String(fields,0);
       if ( channel == CHANOBJECT ) { // handle player dynamic commands        
           if ( command == "HITCHECK" ) {
               integer attackstat = llList2Integer(fields,1);
               integer attackskill = llList2Integer(fields,2);
               integer attackdice = llList2Integer(fields,3); 
               key owner = llList2Key(fields,4);
               string item = llList2String(fields,5);               
               if ( attackstat < MINSTAT || attackstat > MAXSTAT ) {
                   ERROR("Attack stat value out of range: "+(string)MINSTAT+"-"+(string)MAXSTAT);
                   return;
               }
               if ( attackskill < MINSKILL || attackstat > MAXSKILL ) {
                   ERROR("Attack skill value out of range: "+(string)MINSKILL+"-"+(string)MAXSKILL);
                   return;
               }                
               if ( attackdice < MINDAMAGE || attackdice > MAXDAMAGE ) {
                   ERROR("Attack dice value out of range: "+(string)MINDAMAGE+"-"+(string)MAXDAMAGE);
               }
               llSay(PUBLIC_CHANNEL,"/me hit by "+llKey2Name(owner)+"'s "+item+" for "+(string)attackdice+" attack dice!");
               return;
           }            
       }                
   }    

} </lsl>