Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

MMORPG Toolkit patch 0.2 -> 0.3: Healing Wand and Grenade Launcher added

Hugh Perkins
Junior Member
Join date: 26 Nov 2003
Posts: 25
11-30-2003 08:15
MMORPG Toolkit patch 0.2 -> 0.3: Healing Wand and Grenade Launcher added

New features this release:

- Healing Wand module added. You can use this to create a wand or magical baton that you can use to heal people!!!
- Grenade launcher added. Area affect projectile weapon
- monsters now show their name over them

To create a Healing Wand:

- create a magical staff/wand/baton looking object
- add the healing wand module (see below)

To create a Grenade Launcher:

- create a grenade-looking object
- add the Grenade module (see below)

- create a Grenade Launcher looking object
- add the Grenade Launcher module (see below)
- add the Grenade object you just made

To use the Healing Wand:

- just type "heal " and the first few letters of the name of the person you want to heal, eg "heal az"
- note: you must not be flying, and there is a recharge time of 10 seconds between cast
- each heal heals for 20 health

To use the Grenade Launcher:

- go into mouselook
- point upwards and generally in the direction you want to fire
- press fire (left mouse button)
- blast does 80 damage at epicentre, and goes up to 5 metres
- you must not be flying when you fire a grenade! (or it wont do anything)

Enjoy!

Please send me your bug reports and feature requests.

Hugh Perkins

Your rights to use this code:

You can freely use and derive from this code as long as you dont affect my ability or rights to do so myself.
Hugh Perkins
Junior Member
Join date: 26 Nov 2003
Posts: 25
HealingWand module
11-30-2003 08:18
HealingWand module

The HealingSpell module allows you to heal others

Just slot it into something batton, wand or stave-like and wear it, or give it out to players to wear, or sell it

To use, type "heal " and the first letters of the target, eg "heal az"

Your rights to use this code:

You can freely use and derive from this code as long as you dont affect my ability or rights to do so myself.

Hugh Perkins

CODE

// The HealingSpell module allows you to heal others
//
// Just slot it into something batton, wand or stave-like and wear it, or give it out to players to wear, or sell it
//
// To use, type "heal " and the first letters of the target, eg "heal azelda"
//
// Players will need in addition:
// - to be wearing a CombatSystems GRI object (eg appropriately scripting bracelet)
//
// Your rights to use this code:
// =============================
//
// You can freely use and derive from this code as long as you dont affect my ability or rights to do so myself.
//
// Hugh Perkins
//

integer ChannelWpn = 4;

string AttackType = "DirectDamage";
string AttackVector = "NOSAVE";
integer AttackPower = -30;
float CoolDown = 10.0;
integer MaxSpellRadius = 15;

string PlayerName;
key Playerid;

float LastAttack = 0;
//integer bWeaponStillWarm = FALSE;
integer have_permissions = FALSE;
integer Message2displayed = FALSE;
string gsTargetPrefix = "";

integer bArmed = FALSE;

vector GREEN = <0,4,0>;
vector RED = <4,0,0>;
vector ORANGE = <4,0.5,0>;
vector YELLOW = <4,4,0>;
vector BLUE = <0,0,4>;
vector CYAN = <0,0.5,1>;

SetText( string text, vector color )
{
llSetText( text, color,1.0 );
}

TellPlayer( string Message )
{
llWhisper(0,PlayerName + ", " + Message );
}

Debug( string message )
{
llWhisper( 0, llGetScriptName() + ": " + message );
}

TellOwner( string Message )
{
// llInstantMessage( Playerid, Message );
}

DoHealingParticleEffect( key Targetid )
{
llParticleSystem([
PSYS_PART_FLAGS, PSYS_PART_TARGET_POS_MASK,
PSYS_PART_START_COLOR, CYAN,
PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_EXPLODE,
PSYS_SRC_MAX_AGE, 3.0,
PSYS_SRC_TARGET_KEY, Targetid,
PSYS_SRC_BURST_SPEED_MIN, 10.0,
PSYS_SRC_BURST_PART_COUNT,5
]);}

GenericInit()
{
if( llGetAttached() != 0 )
{
bArmed = TRUE;
}
else
{
bArmed = FALSE;
}
Playerid = llGetOwner();
PlayerName = llKey2Name( Playerid );
PlayerName = llGetSubString( PlayerName, 0, llSubStringIndex( PlayerName, " ") );

TellPlayer( "Type 'heal <target>' to heal" );
TellPlayer( "eg 'heal azelda" );
TellPlayer( "You only need to type the first few letters of the target name" );
// llRequestPermissions(llGetOwner(),
// PERMISSION_TRIGGER_ANIMATION| PERMISSION_TAKE_CONTROLS);
// llPreloadSound( "swordhit" );
// llPreloadSound( "swing1" );

Message2displayed = FALSE;
llSetTimerEvent(1.0);
}

default
{
state_entry()
{
llListen( ChannelWpn, "","","" );
GenericInit();
llListen( 0, "","","" );
}
on_rez(integer startparam)
{
GenericInit();
}
listen( integer channel, string name, key id, string message )
{
if( id == Playerid )
{
// Debug( "[" + llToLower( llGetSubString( message, 0, llStringLength( "heal" ) - 1 ) ) + "]");
if( llToLower( llGetSubString( message, 0, llStringLength( "heal" ) - 1 ) ) == "heal" )
{
// Debug( "validating..." );
if (bArmed)
{
if( LastAttack < llGetTimeOfDay() - CoolDown )
{
if( (llGetAgentInfo(llGetOwner()) & AGENT_FLYING) == 0 )
{
LastAttack = llGetTimeOfDay();
gsTargetPrefix = llToLower( llGetSubString( message, llStringLength( "heal" ) + 1 , 1000));
// Debug( "[" + gsTargetPrefix + "]" );
llSensor( "","", ACTIVE|AGENT, MaxSpellRadius, PI );
}
else
{
llWhisper( 0, PlayerName + ", you cannot launch a spell whilst flying!" );
}
}
else
{
llWhisper( 0, "You must wait for spell to recharge, " + PlayerName );
}
}
else
{
llWhisper( 0, "You must be wearing the spell as an attachment, " + PlayerName );
}
}
}
}

timer()
{
// llSay(0, "Use me wisely, " + PlayerName + "!");
// llSetTimerEvent(.0);
Message2displayed = TRUE;
if( llAbs((integer)(llGetTimeOfDay() - LastAttack)) > CoolDown )
{
SetText( "Spell Ready", GREEN );
}
else
{
SetText( "Spell Recharging...", ORANGE );
}
}

attach(key attachedAgent)
{
if (attachedAgent != NULL_KEY)
{
Playerid = llGetOwner();
bArmed = TRUE;
}
else
{
bArmed = FALSE;
}
}

sensor(integer num_detected)
{
integer TargetFound = FALSE;
key Targetid;
string TargetName;

TargetFound = FALSE;
string SampleTargetPrefix;

integer i;
i = 0;
//TellPlayer( "sense event..." );
while( TargetFound == FALSE && i < num_detected )
{
//TellPlayer( llDetectedName(i) + " " + (string)llDetectedType(i) + " " + (string)SCRIPTED);
// if( ( ( llDetectedType(i) & SCRIPTED ) == SCRIPTED ) || ( ( llDetectedType(i) & AGENT ) == AGENT ) )
// {
SampleTargetPrefix = llToLower( llGetSubString( llDetectedName(i), 0, llStringLength( gsTargetPrefix ) - 1 ) );
//Debug( SampleTargetPrefix );
if( SampleTargetPrefix ==gsTargetPrefix )
{
//TellPlayer( "target found: " + llDetectedName(i) );
TargetFound = TRUE;
Targetid = llDetectedKey(i);
TargetName = llDetectedName(i);
}
i++;
}

if( TargetFound )
{
llWhisper( ChannelWpn, "ATTACK" + "-=-" + (string)Playerid + "-=-" + (string)Targetid + "-=-" + AttackType + "-=-" + AttackVector + "-=-" + (string)AttackPower + "-=-" + (string)CoolDown );
DoHealingParticleEffect( Targetid );
// llSleep(1.0);
// llParticleSystem([]);
}
}
}
Hugh Perkins
Junior Member
Join date: 26 Nov 2003
Posts: 25
Grenade module
11-30-2003 08:18
CODE

// Grenade module
//
// Create a grenade object with this, that you can load this into a grenade launcher attachment
//
// Your rights to use this code:
// =============================
//
// You can freely use and derive from this code as long as you dont affect my ability or rights to do so myself.
//
// Hugh Perkins
//

integer ChannelProjectile = 6;

integer BlastRadius = 5;
integer GroundZeroDamage = 80;

integer bArmed = FALSE;

Debug( string message )
{
llWhisper( 0, llGetScriptName() + ": " + message );
}

Explode()
{
llSensor( "","", ACTIVE | AGENT, BlastRadius, PI );
}

default
{
state_entry()
{
Debug( "Compile complete" );
}
on_rez(integer param)
{
llSetStatus(STATUS_DIE_AT_EDGE, TRUE);
//llSetBuoyancy(1.0);
if (param)
{
bArmed = TRUE;
}
}
sensor( integer num_detected )
{
integer i;
for( i = 0; i < num_detected; i++ )
{
integer Damage;
Damage = ( BlastRadius - (integer)llVecMag( llDetectedPos(i) - llGetPos() ) ) * GroundZeroDamage / BlastRadius;
// Debug( (string)Targetid );
llShout( ChannelProjectile, "AREATARGETSTRUCK-=-" + (string)llGetOwner() + "-=-" + (string)llDetectedKey(i) + "-=-" + (string)Damage );
}
}

collision_start(integer total_number)
{
if (bArmed)
{
Explode();
llSetTimerEvent(3.0);
}
}
land_collision_start(vector pos)
{
if (bArmed)
{
Explode();
llSetTimerEvent(3.0);
}
}
timer()
{
llDie();
}
}
Hugh Perkins
Junior Member
Join date: 26 Nov 2003
Posts: 25
GrenadeLauncher module
11-30-2003 08:19
CODE

// The Weapon module is responsible for responding to player commands to attack another player or monster
//
// This weapons module is optimized for grenade-style weapons.
//
// Players will need in addition:
// - to be wearing a CombatSystems GRI object (eg appropriately scripting bracelet)
// - other players to attack, or monsters
//
// Optional other items for plqyers:
// - shield object
//
// Roles and responsibilities:
// The Weapon module is responsible for:
// - responding to player commands asking it to attack something
// - definition of attack type, power and so on
// - enforcement of charge time, recharge time, and charge limitations, as required by weapon designer
//
// Parameters:
// ChannelWpn - make sure this is the same as what is on the SendDmg module of your CS GRI
//
// Public interface:
//
// Methods:
// Player controls weapon via attachment interface. No explicit methods
//
// Events:
//
// Attack:
// llWhisper( ChannelWpn, "ATTACK-=-<Target key>-=-<AttackType>-=-<AttackVector>-=-<Power>-=-<CoolDown>"
// Swords send this to the SendDmg module to attack other avatars or monsters
//
// (note <param> means "the value of parameter param")
//
//
// Detail on attacks
// =================
//
// - AttackType, AttackVector and Power are defined by the CS GRI REceiveDmg module. See ReceiveDmg module
// documentation for more info
// - Cooldown is used to enforce a delay between attacks with the weapon
// - Currently Cooldown is enforced by the weapon, but this will be migrated to the SendDmg module, in order
// to allow enforcement of the AttackSpeed stat
//

integer ChannelWpn = 4;
integer ChannelProjectile = 6;

string AttackType = "DirectDamage";
string AttackVector = "PROJECTILE";
float CoolDown = 0.5;
integer IdealProjectileSpeed = 8;

string ProjectileObjectName = "Grenade";

string PlayerName;
key Playerid;

float LastAttack = 0;
integer have_permissions = FALSE;
integer Message2displayed = FALSE;

float LauncherHeightOffset = 0.8;

TellPlayer( string Message )
{
llWhisper(0,PlayerName + ", " + Message );
}

Debug( string message )
{
llWhisper( 0, llGetScriptName() + ": " + message );
}

Fire()
{
rotation AvatarRot;
vector AvatarForwardVector;
vector LauncherPos;
vector ProjectileVelocity;

AvatarRot = llGetRot();
AvatarForwardVector = llRot2Fwd(AvatarRot);
LauncherPos = llGetPos() + AvatarForwardVector;
LauncherPos.z = LauncherPos.z + LauncherHeightOffset;
ProjectileVelocity = AvatarForwardVector * IdealProjectileSpeed;
llRezObject(ProjectileObjectName, LauncherPos, ProjectileVelocity, AvatarRot, TRUE);
}

GenericInit()
{
llReleaseControls();
Playerid = llGetOwner();
PlayerName = llKey2Name( Playerid );
PlayerName = llGetSubString( PlayerName, 0, llSubStringIndex( PlayerName, " ") );

TellPlayer( "Switch to mouselook to attack!" );
llRequestPermissions(llGetOwner(),
PERMISSION_TRIGGER_ANIMATION| PERMISSION_TAKE_CONTROLS);
// llPreloadSound( "swordhit" );
llPreloadSound( "shoot" );

Message2displayed = FALSE;
llSetTimerEvent(5.0);
}

default
{
state_entry()
{
Debug( "Compile completed" );
llListen( ChannelWpn, "","","" );
llListen( ChannelProjectile, "","","" );
GenericInit();
}
on_rez(integer startparam)
{
GenericInit();
}

timer()
{
llSay(0, "Use me wisely, " + PlayerName + "!");
llSetTimerEvent(0.0);
Message2displayed = TRUE;
}
run_time_permissions(integer perms)
{
if(perms & (PERMISSION_TAKE_CONTROLS))
{
llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT | CONTROL_UP | CONTROL_DOWN | CONTROL_ML_LBUTTON, TRUE, TRUE);
have_permissions = TRUE;
}
}

attach(key attachedAgent)
{
if (attachedAgent != NULL_KEY)
{
Playerid = llGetOwner();
llRequestPermissions(Playerid,
PERMISSION_TRIGGER_ANIMATION| PERMISSION_TAKE_CONTROLS);
}
else
{
if (have_permissions)
{
llReleaseControls();
have_permissions = FALSE;
}
}
}

control(key name, integer levels, integer edges)
{
if ( ((edges & CONTROL_ML_LBUTTON) == CONTROL_ML_LBUTTON)
&&((levels & CONTROL_ML_LBUTTON) == CONTROL_ML_LBUTTON) )
{
if( LastAttack < llGetTimeOfDay() - CoolDown )
{
LastAttack = llGetTimeOfDay();
Fire();
llPlaySound("shoot",1.0 );
}
}
}

listen( integer channel, string name, key id, string message )
{
if( channel == ChannelProjectile )
{
// Debug( "Struck received" );
list Arguments;
Arguments = llParseString2List( message, ["-=-"], [] );

string Command;
Command = llList2String( Arguments, 0 );

if( Command == "AREATARGETSTRUCK" )
{

key FirerId;
FirerId = (key)llList2String( Arguments, 1 );

if( FirerId == Playerid )
{

key Targetid;
Targetid = (key)llList2String( Arguments, 2 );

integer Damage;
Damage = (integer)llList2String( Arguments, 3 );

llWhisper( ChannelWpn, "ATTACK" + "-=-" + (string)Playerid + "-=-" + (string)Targetid + "-=-" + AttackType + "-=-" + AttackVector + "-=-" + (string)Damage + "-=-" + (string)CoolDown );
}
}
}
}
}
Hugh Perkins
Junior Member
Join date: 26 Nov 2003
Posts: 25
Patched module: stats module
11-30-2003 08:21
Please replace your old stats modules with this one in order to use the above weapons.

Main changes:
- monsters show monster name above them now, to enable targeting by spells

CODE

// The Stats module is responsible for storing stats for the Avatar, such as life, mana, and so on
//
// It forms part of the CombatSystems GRI (CS GRI) and should be combined with the other CombatSystems GRI modules
// into something like a bracelet that all game participants will wear
//
// You will need in addition:
// - a weapon object / magical stave / wand - make this using the Weapons module
// - other players to attack, or monsters
//
// The CombatSystems GRI modules are:
// - ReceiveDmg
// - SendDmg
// - SecureComms
// - Stats
//
// Roles and responsibilities:
// Stats is responsible for:
// - Storing current avatar stats
// - responding to stat update messages ("SETSTAT", "RAISESTAT")
// - Letting other CS GRI modules know when a stat has changed
// - Displaying stats to user
//
// Parameters:
// - no parameters, it learns everything from other modules
// - you can set initial values for avatar statistics here if you want
//
// Public interface:
//
// Methods:
//
// Modify statistics:
// llLinkedMessage( "RAISESTAT-=-<Stat Name>-=-<Amount to add to statistic>" ); // can be negative
// llLinkedMessage( "SETSTAT-=-<Stat Name>-=-<New value for stat>" ); // negative numbers will be floored to zero
// llLinkedMessage( "PINGSTATS" ); // asks stats module to send all known stats (in statupdate messages)
//
// Events:
//
// Stats update:
// llLinkedMessage( "STATUPDATE-=-<Stat Name>-=-<New value for stat>" ); // let other CS GRI modules know a stat
// has changed
//
// (note <param> means "the value of parameter param")
//
// Your rights to use this code:
// =============================
//
// You can freely use and derive from this code as long as you dont affect my ability or rights to do so myself.
//
// Hugh Perkins
//

integer Life = 100;
integer AttackSpeed = 100; // percent of norm
integer MoveSpeed = 100; // percent of norm
integer Mana = 100;
integer AttackRange = 100; // percent of norm
integer AttackPower = 100; // percent of norm

integer LifeCap = 100; // hardcoded

integer bIsAvatar = FALSE;

vector GREEN = <0,4,0>;
vector RED = <4,0,0>;
vector ORANGE = <4,0.5,0>;
vector YELLOW = <4,4,0>;
vector BLUE = <0,0,4>;

Debug( string message )
{
llWhisper( 0, llGetScriptName() + ": " + message );
}

CheckIfAvatar()
{
if( llGetAttached() == 0 )
{
bIsAvatar = FALSE;
}
else
{
bIsAvatar = TRUE;
}
}

SetText( string text, vector color )
{
llSetText( text, color,1.0 );
}

ShowLife()
{
string MessagePrefix = "";
if( bIsAvatar )
{
MessagePrefix = "";
}
else
{
MessagePrefix = llGetObjectName() + "\n";
}

if( Life > 50 )
{
SetText( MessagePrefix + "Life: " + (string)Life, GREEN );
}
else if( Life > 10 )
{
SetText( MessagePrefix + "Life: " + (string)Life, ORANGE );
}
else if( Life > 0 )
{
SetText( MessagePrefix + "Life: " + (string)Life, RED );
}
else
{
if( bIsAvatar )
{
SetText("-- " + llKey2Name(llGetOwner() ) + "'s Corpse --", RED );
}
else
{
SetText( "-- " + llGetObjectName() + "'s Corpse --", RED );

}
}
}

SendStat( string StatName )
{
if( StatName == "Life" )
{
llMessageLinked( LINK_SET, 0, "STATUPDATE-=-Life-=-" + (string)Life, "" );
}
else if( StatName == "AttackSpeed" )
{
llMessageLinked( LINK_SET, 0, "STATUPDATE-=-AttackSpeed-=-" + (string)AttackSpeed, "" );
}
else if( StatName == "MoveSpeed" )
{
llMessageLinked( LINK_SET, 0, "STATUPDATE-=-MoveSpeed-=-" + (string)MoveSpeed, "" );
}
else if( StatName == "Mana" )
{
llMessageLinked( LINK_SET, 0, "STATUPDATE-=-Mana-=-" + (string)Mana, "" );
}
else if( StatName == "AttackRange" )
{
llMessageLinked( LINK_SET, 0, "STATUPDATE-=-AttackRange-=-" + (string)AttackRange, "" );
}
else if( StatName == "AttackPower" )
{
llMessageLinked( LINK_SET, 0, "STATUPDATE-=-AttackPower-=-" + (string)AttackPower, "" );
}
}

BroadcastStats()
{
SendStat( "Life" );
SendStat( "AttackSpeed" );
SendStat( "MoveSpeed" );
SendStat( "Mana" );
SendStat( "AttackRange" );
}

integer GetStat( string StatName )
{
if( StatName == "Life" )
{
return Life;
}
else if( StatName == "AttackSpeed" )
{
return AttackSpeed;
}
else if( StatName == "MoveSpeed" )
{
return MoveSpeed;
}
else if( StatName == "Mana" )
{
return Mana;
}
else if( StatName == "AttackRange" )
{
return AttackRange;
}
else if( StatName == "AttackPower" )
{
return AttackRange;
}
return 0;
}

SetStat( string StatName, integer StatValue )
{
if( StatValue < 0 )
{
StatValue = 0;
}

if( StatName == "Life" )
{
if( StatValue > LifeCap )
{
StatValue = LifeCap;
}
Life = StatValue;
ShowLife();
}
else if( StatName == "AttackSpeed" )
{
AttackSpeed = StatValue;
}
else if( StatName == "MoveSpeed" )
{
MoveSpeed = StatValue;
}
else if( StatName == "Mana" )
{
Mana = StatValue;
}
else if( StatName == "AttackRange" )
{
AttackRange = StatValue;
}
else if( StatName == "AttackPower" )
{
AttackPower = StatValue;
}
SendStat( StatName );
}

default
{
state_entry()
{
Debug( "Compile completed" );
CheckIfAvatar();
ShowLife();
}
on_rez( integer param )
{
CheckIfAvatar();
ShowLife();
}
link_message( integer sendernum, integer num, string message, key id )
{
list Arguments;
Arguments = llParseString2List( message, ["-=-"], [] );

string Command;
Command = llList2String( Arguments, 0 );

string StatName;
StatName = llList2String( Arguments, 1 );

integer StatValue;
StatValue = (integer)llList2String( Arguments, 2 );

integer CurrentStat;

if( Command == "SETSTAT" )
{
SetStat( StatName, StatValue );
}
else if( Command == "RAISESTAT" )
{
CurrentStat = GetStat( StatName );
SetStat( StatName, CurrentStat + StatValue );
}
else if( Command == "MINSTAT" )
{
// MinStat( StatName, StatValue );
}
else if( Command == "MAXSTAT" )
{
// MaxStat( StatName, StatValue );
}
else if( Command == "PINGSTATS" )
{
BroadcastStats();
}
}
}
Hugh Perkins
Junior Member
Join date: 26 Nov 2003
Posts: 25
Patched module: ReceiveDmg
11-30-2003 08:24
Please replace your old REceiveDmg modules with this one if you wish to use the HealWand module above.

New features this patch:
- support for "NOSAVE" AttackVector type, good for Healing spells for example where you dont want to have to roll against AC or other armour
- you can type "stats" to see current protection stats

Bug fixes:
- monsters will no longer create PROTECTIONPING pings, nor listen for PROTECTIONRESPONSE replies

CODE

// The ReceiveDmg module is responsible for receiving and processing damage dealt by other avatars or by monsters
// attacking the player
//
// It forms part of the CombatSystems GRI and should be combined with the other CombatSystems GRI modules
// into something like a bracelet that all game participants will wear
//
// You will need in addition:
// - a weapon object / magical stave / wand - make this using the Weapons module
// - other players to attack, or monsters
//
// The CombatSystems GRI modules are:
// - ReceiveDmg
// - SendDmg
// - SecureComms
// - Stats
//
// Roles and responsibilities:
// ReceiveDmg is responsible for:
// - communicating with shield/protection objects to determine and instantiate current protection values
// - receiving attacks, via the SecureComms module, and applying them to the Avatar
// - enforcement of Death Condition
//
// Parameters:
// ChannelShield - make sure this is the same as what is on your shield modules
// DeathTime - length of time you will be dead for when you die
//
// Public interface:
//
// Methods:
//
// Attack methods:
// llLinkedMessage( "RECEIVEDSECURECOM-=-ATTACK-=-<Target key>-=-<AttackType>-=-<AttackVector>-=-<Power>" );
// This is an attack message, normally received via the SecureComms modulem from an attacking monster or avatar
//
// Shield commmunication methods;
// llWhisper( "PROTECTIONRESPONSE-=-<ShieldName>-=-<AC>-=-<MR>-=-<ProjArmour>" );
// This is a shield response message detailed its AC, MR and Projectile Armour
// llWhisper( "INVCHANGE" );
// Shields and protection items send this as they are attached or detached
//
// Stats update:
// llLinkedMessage( "STATUPDATE-=-Life-=-<Current Life>" );
//
// Events:
//
// DeathCondition event:
// llLinkedMessage( "DEATHCONDITIONON" ); // player is dead
// llLinkedMessage( "DEATHCONDITIONOFF" ); // player is alive again
//
// Damage instantiation:
// llLinkedMessage( "RAISESTAT-=-Life-=-<minus Damage>" ); // update Life when attacked
//
// Shield Communication:
// llWhisper( "PROTECTIONPING" ); // Ask shields and protection equipment for current stats
//
// (note <param> means "the value of parameter param")
//
//
// Detail on attacks
// =================
//
// Currently processes the following attack types:
// AttackType = "DirectDamage"
// AttackVector = {"MELEE" | "MAGIC" | "PROJECTILE | NOSAVE"} (any of these values)
//
// Power is modulated according to current protection values (AC, MR etc) according to
// the AttackVector. AC protects against Melee, MR protects against Magic, and Projectile protects against projectiles
//
// Damage = ( Power * 100 ) / ( 100 + <protectionvalue> )
//
// NOSAVE means no protection attributes applied. You can use this to make a heal spell for example
// (heal = DirectDamage, NOSAVE, and a negative AttackPower)
//
// Your rights to use this code:
// =============================
//
// You can freely use and derive from this code as long as you dont affect my ability or rights to do so myself.
//
// Hugh Perkins
//

integer ChannelShield = 5;
integer ChannelDead = 7;

integer DeathTime = 10;

integer AC = 0;
integer MR = 0;
integer ProjArmour = 0;

integer NewAC = 0;
integer NewMR = 0;
integer NewProjArmour = 0;

integer PingInProgress = FALSE;
integer PingSent = 0;
integer RedoPing = FALSE;

key OurKey = "";
integer bIsAvatar = FALSE;
integer bGotAnimPerms = FALSE;
integer bDeathConditionOn = FALSE;
integer TimeDied = 0;

TellPlayer( string Message )
{
llWhisper( 0, Message );
}

Debug( string message )
{
llWhisper( 0, llGetScriptName() + ": " + message );
}

GetKey()
{
if( llGetAttached() == 0 )
{
OurKey = llGetKey();
}
else
{
OurKey = llGetOwner();
}
}

GetPermsIfNeeded()
{
bGotAnimPerms = FALSE;
if( llGetAttached() == 0 )
{
bIsAvatar = FALSE;
}
else
{
bIsAvatar = TRUE;
}
if( bIsAvatar )
{
llRequestPermissions( llGetOwner(), PERMISSION_TRIGGER_ANIMATION );
}
}

PingProtection()
{
// Debug( "pingproection function" );
if( bIsAvatar )
{
if( !PingInProgress )
{
// Debug( "no ping in progress" );
PingSent = (integer)llGetWallclock();
NewAC = 0;
NewMR = 0;
NewProjArmour = 0;
llWhisper( ChannelShield, "PROTECTIONPING" );
PingInProgress = TRUE;
}
else
{
// Debug ("setting redo ping flag" );
RedoPing = TRUE;
}
}
}

ReduceStat( string StatName, integer Amount )
{
llMessageLinked( LINK_SET, 0, "RAISESTAT-=-" + StatName + "-=-" + (string)(-Amount), "" );
}

SetStat( string StatName, integer Value )
{
llMessageLinked( LINK_SET, 0, "SETSTAT-=-" + StatName + "-=-" + (string)Value, "" );
}

ProcessDirectDamage( string AttackVector, integer Power )
{
// Debug( "dd received" );
integer Damage;
if( AttackVector == "MELEE" )
{
Damage = ( Power * 100 ) / ( 100 + AC );
}
else if( AttackVector == "MAGIC" )
{
Damage = ( Power * 100 ) / ( 100 + MR );
}
else if( AttackVector == "PROJECTILE" )
{
Damage = ( Power * 100 ) / ( 100 + ProjArmour );
}
else if( AttackVector == "NOSAVE" )
{
// Debug( "no save received" );
Damage = Power;
}
ReduceStat( "Life", Damage );
}

ProcessAttack( string AttackType, string AttackVector, integer Power )
{
if( AttackType == "DirectDamage" )
{
ProcessDirectDamage( AttackVector, Power );
}
else if( AttackType == "ManaDamage" )
{
}else if( AttackType == "IncreaseMoveSpeed" )
{
}else if( AttackType == "IncreaseAttackSpeed" )
{
}else if( AttackType == "IncreaseAttackRange" )
{
}
}

StatsPing()
{
llMessageLinked( LINK_SET, 0, "PINGSTATS", "" );
}

Init()
{
GetKey();
GetPermsIfNeeded();
StatsPing();
RedoPing = FALSE;
PingProtection();
}

TellPlayerProtectionStats()
{
llWhisper( 0, "Protection stats: AC:" + (string)AC + " MR:" + (string)MR + " ProjArmour:" + (string)ProjArmour );
}

EnforceDeathCondition()
{
llShout( ChannelDead, (string)OurKey );
if( bIsAvatar )
{
TellPlayer( "You are dead. Please wait...");
// llShout( Channel, "KILLED" +"-=-" + (string)llFrand(1000.0) + "-=-" + (string)Attackerid + "-=-" + (string)Playerid );

llMessageLinked( LINK_SET, 0, "DEATHCONDITIONON", "" );
if( bGotAnimPerms )
{
llStartAnimation( "dead" );
}
llMoveToTarget( llGetPos(), 0.2 );

TimeDied = (integer)llGetWallclock();
bDeathConditionOn = TRUE;
}
else
{
llMoveToTarget( llGetPos(), 0.2 );
TimeDied = (integer)llGetWallclock();
bDeathConditionOn = TRUE;
llSleep( DeathTime );
llDie();
}
}

default
{
state_entry()
{
Debug( "Compile complete" );
llSetTimerEvent( 3.0 );
Init();
llListen( 0, "","","" );
llListen( ChannelShield, "", "","" );
}
on_rez( integer param )
{
Init();
}
listen( integer channel, string name, key id, string message )
{
if( bIsAvatar )
{
if( channel == ChannelShield )
{
list Arguments;
Arguments = llParseString2List( message, ["-=-"], [] );

string Command;
Command = llList2String( Arguments, 0 );

if( Command == "PROTECTIONRESPONSE" )
{
NewAC = NewAC + (integer)llList2String( Arguments, 2 );
NewMR = NewMR + (integer)llList2String( Arguments, 3 );
NewProjArmour = NewProjArmour + (integer)llList2String( Arguments, 4 );
}
else if( Command == "INVCHANGE" )
{
PingProtection();
}
}
else if( channel == 0 && bIsAvatar )
{
if( llToLower(message) == "stats" )
{
if( id == llGetOwner() )
{
TellPlayerProtectionStats();
}
}
}
}
}
timer()
{
if( PingInProgress )
{
if( llAbs( (integer)llGetWallclock() - PingSent ) >= 5 )
{
AC = NewAC;
MR = NewMR;
ProjArmour = NewProjArmour;
PingInProgress = 0;
if( RedoPing )
{
RedoPing = FALSE;
PingProtection();
}
}
}
else if( llAbs( (integer)llGetWallclock() - PingSent ) >= 60 )
{
PingProtection();
}

if( bDeathConditionOn )
{
if( llAbs((integer)llGetWallclock() - TimeDied ) > DeathTime )
{
SetStat( "Life", 100 );
llMessageLinked( LINK_SET, 0, "DEATHCONDITIONOFF", "" );
if( bGotAnimPerms )
{
llStopAnimation("dead");
}
llStopMoveToTarget();
bDeathConditionOn = FALSE;

TellPlayer( "Ressurection completed" );
// llShout( Channel, "RESURRECTED-=-" + (string)llFrand(1000.0) +"-=-" + (string)Playerid +"-=-" ) ;

}
else
{
llShout( ChannelDead, (string)OurKey );
}
}
}
link_message( integer sendernum, integer num, string message, key id )
{
list Arguments;
Arguments = llParseString2List( message, ["-=-"], [] );

string Command;
Command = llList2String( Arguments, 0 );

//Debug( "link message " + message + " " + Command );
if( Command == "RECEIVEDSECURECOM" )
{
if( llList2String( Arguments, 1 ) == "ATTACK" )
{
if( ! bDeathConditionOn )
{
key Target;
Target = (key)llList2String( Arguments, 2 );
// Debug( (string)Target + " " + (string)OurKey );
if( Target == OurKey )
{
string AttackType;
string AttackVector;
integer Power;

AttackType = llList2String( Arguments, 3 );
AttackVector = llList2String( Arguments, 4 );
Power = (integer)llList2String( Arguments, 5 );
ProcessAttack( AttackType, AttackVector, Power );
}
}
}
}
else if( Command == "STATUPDATE" )
{
if( llList2String( Arguments, 1 ) == "Life" )
{
if( (integer)llList2String( Arguments, 2 ) <= 0 )
{
if( !bDeathConditionOn )
{
EnforceDeathCondition();
}
}
}
}
}
run_time_permissions( integer perms )
{
bGotAnimPerms = TRUE;
}
}
Haney Linden
Senior Member
Join date: 3 Oct 2002
Posts: 990
11-30-2003 08:56
Let me know if anyone is trying out this system. I'd love to see it in action.
Ryen Jade
This is a takeover!
Join date: 21 Jun 2003
Posts: 1,329
11-30-2003 09:33
Hugh, you deserve ALOT more respect then you are getting for this, Id like to talk to you ingame.
Bonecrusher Slate
Registered User
Join date: 1 May 2003
Posts: 337
11-30-2003 11:22
Hugh,

This kit is incredible! Keep up the good work!

-Bone