CODE
//BeachHead Aerospace SimpleChute v.0.1. You may copy, modify, sell, verbally abuse
//this script. It is Not My Problem if this script damages your sim and causes it to run //amok and kill the Pope.
//all altitudes are in terms of Above Ground Level, AGL, and not absolute z position.
integer chuteHeight = 50; //the altitude (in m) at which the chute deploys
integer reserveHeight = 45; //the reserve chute's hardcoded trigger altitude
integer cutoffHeight = 3; //the altitude at which the
float pushStrength; //the nudge we give to slow the fall of the av wearing the chute
integer warned = FALSE;
float oldAltitude;
float currentAltitude;
float fudgeFactor = 0.3;
float waterTableTolerance = 0.5;//how close we have to be to the water surface to trigger a splash
//the parachute uses two timer intervals, a slow "dormant" interval when the av isn't in
//need of the chute, and a fast "active" interval once the chute realizes its wearer is falling.
float fastInterval = 0.1;
float timerInterval;
float slowInterval = 5.0;
integer splashActive = FALSE;
integer animSet;
string gAnimName = "hover_down"; //the animation to play once the chute deploys
integer version = 11;
splash() //the function that creates splash particles when water landing. Adapted from
//Ama Omega's fine work
{
//particle functions based off Ama Omega's unbeatable one.
integer glow = FALSE;
integer bounce = TRUE;
integer interpColor = TRUE;
integer interpSize = TRUE;
integer wind = FALSE;
integer followSource = FALSE;
integer followVel = FALSE;
integer pattern = PSYS_SRC_PATTERN_ANGLE_CONE;
key target = "";
float age = 3; // Life of each particle
float maxSpeed = 10; // Max speed each particle is spit out at
float minSpeed = 5; // Min speed each particle is spit out at
string texture; // Texture used for particles, default used if blank
float startAlpha = 0.7; // Start alpha (transparency) value
float endAlpha = 0.01; // End alpha (transparency) value
vector startColor = <0.5,0.5,1>; // Start color of particles <R,G,B>
vector endColor = <1,1,1>; // End color of particles <R,G,B> (if interpColor == TRUE)
vector startSize = <1,1,1>; // Start size of particles
vector endSize = <0.1,0.1,0.1>; // End size of particles (if interpSize == TRUE)
vector push = <0,0,-15>; // Force pushed on particles
float rate = .1; // How fast (rate) to emit particles
float radius = 0; // Radius to emit particles for BURST pattern
integer count = 100; // How many particles to emit per BURST
float outerAngle = 0.5; // Outer angle for all ANGLE patterns
float innerAngle = 0.5; // Inner angle for all ANGLE patterns
vector omega = <0,0,0>; // Rotation of ANGLE patterns around the source
float life = 0; // Life in seconds for the system to make particles
integer flags;
flags = 0;
if (target == "owner") target = llGetOwner();
if (target == "self") target = llGetKey();
if (glow) flags = flags | PSYS_PART_EMISSIVE_MASK;
if (bounce) flags = flags | PSYS_PART_BOUNCE_MASK;
if (interpColor) flags = flags | PSYS_PART_INTERP_COLOR_MASK;
if (interpSize) flags = flags | PSYS_PART_INTERP_SCALE_MASK;
if (wind) flags = flags | PSYS_PART_WIND_MASK;
if (followSource) flags = flags | PSYS_PART_FOLLOW_SRC_MASK;
if (followVel) flags = flags | PSYS_PART_FOLLOW_VELOCITY_MASK;
if (target != "") flags = flags | PSYS_PART_TARGET_POS_MASK;
llParticleSystem([ PSYS_PART_MAX_AGE,age,
PSYS_PART_FLAGS,flags,
PSYS_PART_START_COLOR, startColor,
PSYS_PART_END_COLOR, endColor,
PSYS_PART_START_SCALE,startSize,
PSYS_PART_END_SCALE,endSize,
PSYS_SRC_PATTERN, pattern,
PSYS_SRC_BURST_RATE,rate,
PSYS_SRC_ACCEL, push,
PSYS_SRC_BURST_PART_COUNT,count,
PSYS_SRC_BURST_RADIUS,radius,
PSYS_SRC_BURST_SPEED_MIN,minSpeed,
PSYS_SRC_BURST_SPEED_MAX,maxSpeed,
PSYS_SRC_TARGET_KEY,target,
PSYS_SRC_INNERANGLE,innerAngle,
PSYS_SRC_OUTERANGLE,outerAngle,
PSYS_SRC_OMEGA, omega,
PSYS_SRC_MAX_AGE, life,
PSYS_SRC_TEXTURE, texture,
PSYS_PART_START_ALPHA, startAlpha,
PSYS_PART_END_ALPHA, endAlpha
]);
}
bubbles() //the function to create bubbles AFTER a water landing.
{
//particle functions based off Ama Omega's unbeatable one.
integer glow = FALSE;
integer bounce = FALSE;
integer interpColor = TRUE;
integer interpSize = TRUE;
integer wind = FALSE;
integer followSource = FALSE;
integer followVel = FALSE;
integer pattern = PSYS_SRC_PATTERN_EXPLODE;
key target = "";
float age = 5; // Life of each particle
float maxSpeed = 0.5; // Max speed each particle is spit out at
float minSpeed = 0; // Min speed each particle is spit out at
string texture = "bubble"; // Texture used for particles, default used if blank
float startAlpha = 1; // Start alpha (transparency) value
float endAlpha = 0.01; // End alpha (transparency) value
vector startColor = <1,1,1>; // Start color of particles <R,G,B>
vector endColor = <1,1,1>; // End color of particles <R,G,B> (if interpColor == TRUE)
vector startSize = <0.1,0.1,0.1>; // Start size of particles
vector endSize = <1,1,1>; // End size of particles (if interpSize == TRUE)
vector push = <0,0,0.5>; // Force pushed on particles
float rate = .1; // How fast (rate) to emit particles
float radius = 0.5; // Radius to emit particles for BURST pattern
integer count = 4; // How many particles to emit per BURST
float outerAngle = 0.5; // Outer angle for all ANGLE patterns
float innerAngle = 0.5; // Inner angle for all ANGLE patterns
vector omega = <0,0,0>; // Rotation of ANGLE patterns around the source
float life = 0; // Life in seconds for the system to make particles
integer flags;
flags = 0;
if (target == "owner") target = llGetOwner();
if (target == "self") target = llGetKey();
if (glow) flags = flags | PSYS_PART_EMISSIVE_MASK;
if (bounce) flags = flags | PSYS_PART_BOUNCE_MASK;
if (interpColor) flags = flags | PSYS_PART_INTERP_COLOR_MASK;
if (interpSize) flags = flags | PSYS_PART_INTERP_SCALE_MASK;
if (wind) flags = flags | PSYS_PART_WIND_MASK;
if (followSource) flags = flags | PSYS_PART_FOLLOW_SRC_MASK;
if (followVel) flags = flags | PSYS_PART_FOLLOW_VELOCITY_MASK;
if (target != "") flags = flags | PSYS_PART_TARGET_POS_MASK;
llParticleSystem([ PSYS_PART_MAX_AGE,age,
PSYS_PART_FLAGS,flags,
PSYS_PART_START_COLOR, startColor,
PSYS_PART_END_COLOR, endColor,
PSYS_PART_START_SCALE,startSize,
PSYS_PART_END_SCALE,endSize,
PSYS_SRC_PATTERN, pattern,
PSYS_SRC_BURST_RATE,rate,
PSYS_SRC_ACCEL, push,
PSYS_SRC_BURST_PART_COUNT,count,
PSYS_SRC_BURST_RADIUS,radius,
PSYS_SRC_BURST_SPEED_MIN,minSpeed,
PSYS_SRC_BURST_SPEED_MAX,maxSpeed,
PSYS_SRC_TARGET_KEY,target,
PSYS_SRC_INNERANGLE,innerAngle,
PSYS_SRC_OUTERANGLE,outerAngle,
PSYS_SRC_OMEGA, omega,
PSYS_SRC_MAX_AGE, life,
PSYS_SRC_TEXTURE, texture,
PSYS_PART_START_ALPHA, startAlpha,
PSYS_PART_END_ALPHA, endAlpha
]);
}
//this script accepts input from an llDialog script in the same prim that allows for
//configuration of the trigger height, etc. This should be cut and dry.
message(integer sender_num, integer number, string message, key some_key)
{
if(llList2String(llParseString2List(message,[" "],[]),0) == "deployAltitude")
{
//llOwnerSay("Trigger set");
chuteHeight = llList2Integer(llParseString2List(message,[" "],[]),1);
llMessageLinked(LINK_ALL_OTHERS,chuteHeight, "", "");
}
if(llList2String(llParseString2List(message,[" "],[]),0) == "Launch")
{
//llOwnerSay("Trigger set");
integer pushStrength = llList2Integer(llParseString2List(message,[" "],[]),1);
llPushObject(llGetOwner(),<0,0,pushStrength*llGetMass()>,<0,0,0>,FALSE);
llOwnerSay("Launching!");
}
if (llList2String(llParseString2List(message,[" "],[]),0) == "Switch" && llList2String(llParseString2List(message,[" "],[]),1) == "On" )
{
llSetColor(<0.5,0.5,1>,ALL_SIDES); //set the chute backpack's color to grey when
//it is turned off
integer i;
for (i = 2 ; i <= llGetNumberOfPrims() ; i++ )
{
llSetLinkColor(i,<1,1,1>,ALL_SIDES);
}
llSetColor(<0.5,0.5,1>,ALL_SIDES);
state default;
}
if (llList2String(llParseString2List(message,[" "],[]),0) == "Switch" && llList2String(llParseString2List(message,[" "],[]),1) == "Off" )
{
llSetColor(<0.3,0.3,0.3>,ALL_SIDES);
integer i;
for (i = 1 ; i <= llGetNumberOfPrims() ; i++ )
{
llSetLinkColor(i,<0.3,0.3,0.3>,ALL_SIDES);
}
state off;
}
}
default
{
on_rez(integer foo)
{
llSetBuoyancy(0);
version = version + 1;//I increment the version on each rez of the chute for
//ease in debugging and rollback if necessary.
string ownerFullName = llKey2Name(llGetOwner()); //we store the owner's name
llSetObjectName(ownerFullName + "'s SimpleChute v."+(string)version);
llOffsetTexture(0 , 0.35, ALL_SIDES);//"Dormant"
llMessageLinked(LINK_ALL_OTHERS,0,"furl",""); //pack the chute canopy prims upon rez
}
state_entry()
{
llMessageLinked(LINK_ALL_OTHERS,0,"furl","");
llSetTimerEvent(slowInterval);
llSetBuoyancy(0);
llSetText("",<1,1,1>,1);
}
timer()
{
if(llGetAnimation(llGetOwner()) == "Falling Down" && timerInterval != fastInterval)
{
//then we're falling and need to start polling faster
llSetTimerEvent(fastInterval);
timerInterval = fastInterval;
llSetColor(<1,0.3,0.3>,ALL_SIDES);
llOffsetTexture(0 , 0.0, ALL_SIDES);//"Primed"
}
else if(timerInterval != slowInterval && llGetAnimation(llGetOwner()) != "Falling Down")
{
//then we're doing anything other than falling and we
//need to ease up on the server with fewer timer events
timerInterval = slowInterval;
llSetBuoyancy(0);
llSetTimerEvent(slowInterval);
llParticleSystem([]);
llSetColor(<0.5,0.5,1>,ALL_SIDES);
llOffsetTexture(0 , 0.35, ALL_SIDES);//"Dormant"
llMessageLinked(LINK_ALL_OTHERS,0,"furl","");
warned = FALSE;
}
vector position = llGetPos();
currentAltitude = position.z - llGround(<0,0,0>);//we determine AGL
vector velocity = llGetVel();
if( currentAltitude < chuteHeight && currentAltitude > cutoffHeight && llGetAnimation(llGetOwner()) == "Falling Down" && velocity.z < 0)
{
llMessageLinked(LINK_ALL_OTHERS, 1010101, "main", "");
state deployed;
}
//here we trigger the 'reserve' chute if by some "miracle" the main chute didn't deploy. This event should be logically impossible, but hey. ;)
if( currentAltitude < reserveHeight && currentAltitude > cutoffHeight && llGetAnimation(llGetOwner()) == "Falling Down" && velocity.z < 0)
{
llMessageLinked(LINK_ALL_OTHERS, 1010101, "reserve", "");
state deployed;
}
}
link_message(integer sender_num, integer number, string message, key some_key)
{
message(sender_num, number, message, some_key);
}
}
state deployed
{
state_entry()
{
llSetTimerEvent(fastInterval);
//animation elements from
//http://secondlife.com/badgeo/wakka.php?wakka=ExampleAnimationBasic
llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION); // ask the owner for permission to trigger animations
llStopAnimation("falldown");
llStartAnimation(gAnimName); // automatically trigger animation.
}
on_rez(integer param)
{
llResetScript(); // reset the script as soon as it starts (switches to default state)
}
attach(key id)
{
integer perm = llGetPermissions();
if (id != NULL_KEY) // make sure we're actually attached.
{
if (! (perm & PERMISSION_TRIGGER_ANIMATION)) // remember to use bitwise operators!
{
llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION); // request permissions from the owner.
}
}
else
{
if (perm & PERMISSION_TRIGGER_ANIMATION)
{
llStopAnimation(gAnimName); // stop the animation
}
}
}
timer()
{
vector position = llGetPos();
currentAltitude = position.z - llGround(<0,0,0>);
if( currentAltitude < cutoffHeight )
{//we're within a few m of the ground and can pack the chute
state default;
}
vector speed = llGetVel();
llSetBuoyancy(-speed.z * fudgeFactor);
//setting the buoyancy as a function of downward velocity seems to have a nice damping
//effect most of the time. Sometimes, it rockets you upwards. Not sure why.
if(!warned)
{
llMessageLinked(LINK_ALL_OTHERS,0,"unfurl","");
llOffsetTexture(0 , -0.37, ALL_SIDES);//"Active"
llSetColor(<0,1,0>,ALL_SIDES);
warned = TRUE;
}
if(llFabs((currentAltitude - llFabs((llWater(ZERO_VECTOR) - llGround(ZERO_VECTOR))))) < waterTableTolerance && llWater(ZERO_VECTOR) > llGround(ZERO_VECTOR) && llGetAnimation(llGetOwner()) == "Falling Down")
{
splash();
splashActive = TRUE;
llMessageLinked(LINK_ALL_OTHERS,0,"furl","");
}
else if(splashActive)
{
//llStopAnimation(animation);
splashActive = FALSE;
if(llGetAnimation(llGetOwner()) == "Falling Down")
{
bubbles();
llMessageLinked(LINK_ALL_OTHERS,0,"furl","");
}
}
}
link_message(integer sender_num, integer number, string message, key some_key)
{
message(sender_num, number, message, some_key);
}
state_exit()
{
llStopAnimation(gAnimName);
llOffsetTexture(0 , 0.35, ALL_SIDES);//"Dormant"
llSetColor(<0.5,0.5,1>,ALL_SIDES);
llParticleSystem([]);
}
}
state off
{
link_message(integer sender_num, integer number, string message, key some_key)
{
message(sender_num, number, message, some_key);
}
}