To grab an InnerT00b and a working version of the launcher, you can go in-world to:
SLURL: http://slurl.com/secondlife/Suisun/213/17/56
Direct: secondlife://Suisun/213/17/56
(Go to the other corner and click the sign to teleport to the launcher).
Launcher Script:
CODE
//////////////////////////////////////////////////////////////////////////////
//
// Hugsy Penguin Enterprises
// Innertube Launcher
// Launch Script
//
// Version: 1.3
// Date: June 14, 2008
//
// (c) 2008 Hugsy Penguin
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
/////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------------
// Configuration
//---------------------------------------------------------------------------
//amount of force to push the innertube:
float IMPULSE = 150.0;
//name of the inventory item for the innertube:
string INNERTUBE = "InnerT00b";
//offset for rezzing the innertube
vector REZ_OFFSET = <0, -1.5, 0>;
//---------------------------------------------------------------------------
// Globals
//---------------------------------------------------------------------------
key gToucher;
key gTubeKey;
integer gDEBUG = FALSE;
integer gSendInfoAttempts;
integer gChannel;
//
// Launch the object with the given id.
//
Launch(key id)
{
DebugSay("Pushing object.");
vector eul = llRot2Euler(llGetRot());
vector p = <0.0, 0.0 - IMPULSE, 0.0>;
vector impulseVector = ArbitraryRotate(p, eul.z, <0,0,1>);
DebugSay("eul = " + (string)eul);
llPushObject(
id, //id
impulseVector, //impulse
<0.0, 0.0, 0.0>, //angular_impulse
FALSE); //local
DebugSay("Pushing complete.");
}
//
// Send a command to the tube.
//
SendTubeCommand(string command)
{
list info;
info += [gTubeKey];
info += [command];
llSay(1, llList2CSV(info));
}
//
// Pick a random channel to communicate on.
//
integer RandomChannel()
{
integer min = 1;
integer max = 2147483647;
integer rndchn = (integer)(llFrand(max - min) + min);
return rndchn;
}
//
// Rotate a point p by angle theta around an arbitrary axis r
// Return the rotated point.
// Positive angles are anticlockwise looking down the axis
// towards the origin.
// Assume right hand coordinate system.
//
// Credit:
//
// Written by Paul Bourke
// December 1992, Updated August 2002
// Base Link: http://local.wasp.uwa.edu.au/~pbourke/geometry/rotate/
// Code Link: http://local.wasp.uwa.edu.au/~pbourke/geometry/rotate/source.c
// Credit On: May 20, 2007
//
vector ArbitraryRotate(vector p, float theta, vector r)
{
vector q = ZERO_VECTOR;
float costheta;
float sintheta;
r = llVecNorm(r);
costheta = llCos(theta);
sintheta = llSin(theta);
q.x += (costheta + (1 - costheta) * r.x * r.x) * p.x;
q.x += ((1 - costheta) * r.x * r.y - r.z * sintheta) * p.y;
q.x += ((1 - costheta) * r.x * r.z + r.y * sintheta) * p.z;
q.y += ((1 - costheta) * r.x * r.y + r.z * sintheta) * p.x;
q.y += (costheta + (1 - costheta) * r.y * r.y) * p.y;
q.y += ((1 - costheta) * r.y * r.z - r.x * sintheta) * p.z;
q.z += ((1 - costheta) * r.x * r.z - r.y * sintheta) * p.x;
q.z += ((1 - costheta) * r.y * r.z + r.x * sintheta) * p.y;
q.z += (costheta + (1 - costheta) * r.z * r.z) * p.z;
return(q);
}
//
// Reset the script.
//
ResetScript()
{
DebugSay("Resetting script.");
llResetScript();
}
//
// Say to the owner (only if debugging).
//
DebugSay(string message)
{
if (gDEBUG)
{
llOwnerSay(message);
}
}
//############################################################################
//
// STATES
//
//############################################################################
//----------------------------------------------------------------------------
// state default
//----------------------------------------------------------------------------
default
{
state_entry()
{
llSetText("Click base to rez an innertube.", <0, 1, 0>, 1.0);
}
touch_start(integer total_number)
{
gToucher = llDetectedKey(0);
state rezzing_tube;
}
}
//----------------------------------------------------------------------------
// state rezzing_tube
//----------------------------------------------------------------------------
state rezzing_tube
{
state_entry()
{
llSetText("Rezzing innertube and waiting for data.",
<1, 1, 0>, 1.0);
gChannel = RandomChannel();
DebugSay("Waiting on channel " + (string)gChannel);
llListen(gChannel, "", "", "");
vector roteul = llRot2Euler(llGetRot());
vector posOffset = ArbitraryRotate(REZ_OFFSET, roteul.z, <0, 0, 1>);
roteul *= RAD_TO_DEG;
vector eul = <0, 0, roteul.z - 90>;
eul *= DEG_TO_RAD;
rotation quat = llEuler2Rot(eul);
llRezObject(
INNERTUBE,
llGetPos() + posOffset,
ZERO_VECTOR,
quat,
gChannel);
llSetTimerEvent(10);
}
timer()
{
DebugSay("Timed out.");
state borked;
}
listen(integer channel, string name, key id, string message)
{
llSetTimerEvent(0);
DebugSay(message);
gTubeKey = message;
state waiting_to_launch;
}
}
//----------------------------------------------------------------------------
// state waiting_to_launch
//----------------------------------------------------------------------------
state waiting_to_launch
{
state_entry()
{
llSetText("Innertube rezzed.\nSit on innertube.\nClick base to launch.",
<1, 1, 0>, 1.0);
llSetTimerEvent(30);
}
timer()
{
DebugSay("Timed out.");
state timed_out;
}
touch_start(integer total_number)
{
if (gToucher == llDetectedKey(0))
{
DebugSay("Launching...");
state launching;
}
}
}
//----------------------------------------------------------------------------
// state timed_out
//----------------------------------------------------------------------------
state timed_out
{
state_entry()
{
llSetText("Timed out.\nRemoving innertube.", <1, 0, 0>, 1.0);
SendTubeCommand("Die");
llSetTimerEvent(3);
}
timer()
{
ResetScript();
}
}
//----------------------------------------------------------------------------
// state launching
//----------------------------------------------------------------------------
state launching
{
state_entry()
{
gSendInfoAttempts = 0;
llSetText("Weeeeee!", <1,1,1>, 1.0);
llListen(2, "", "", "");
llSetTimerEvent(1);
SendTubeCommand("SendInfo");
}
listen(integer channel, string name, key id, string message)
{
DebugSay(message);
list info = llCSV2List(message);
key itKey = llList2String(info, 0);
key avKey = llList2String(info, 1);
DebugSay(avKey);
DebugSay(gToucher);
if (avKey == "00000000-0000-0000-0000-000000000000")
{
llWhisper(0, "You have to be sitting in the inner tube to launch."
+ " Resetting. Please try again.");
SendTubeCommand("Die");
ResetScript();
}
else if (avKey == gToucher)
{
Launch(itKey);
ResetScript();
}
}
timer()
{
if (gSendInfoAttempts < 10)
{
gSendInfoAttempts++;
SendTubeCommand("SendInfo");
}
else
{
state borked;
}
}
}
//----------------------------------------------------------------------------
// state borked
//----------------------------------------------------------------------------
state borked
{
state_entry()
{
llSetText("Something's borked. :-(\nResetting script.", <1,0,0>, 1.0);
SendTubeCommand("Die");
llSetTimerEvent(3);
}
timer()
{
ResetScript();
}
}
InnerT00b Script
CODE
//////////////////////////////////////////////////////////////////////////////
//
// Hugsy Penguin Enterprises
// Innertube Launcher
// Toob Script
//
// Version: 1.3
// Date: June 14, 2008
//
// (c) 2008 Hugsy Penguin
// All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
/////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------------
// Configuration
//---------------------------------------------------------------------------
// None.
//---------------------------------------------------------------------------
// Globals
//---------------------------------------------------------------------------
integer gDEBUG = FALSE;
//
// Reset the script.
//
ResetScript()
{
DebugSay("Resetting script.");
llResetScript();
}
//
// Say to the owner (only if debugging).
//
DebugSay(string message)
{
if (gDEBUG)
{
llOwnerSay(message);
}
}
//############################################################################
//
// STATES
//
//############################################################################
//----------------------------------------------------------------------------
// state default
//----------------------------------------------------------------------------
default
{
state_entry()
{
DebugSay("Rezzed and listening.");
llListen(1, "", "", "");
}
on_rez(integer start_param)
{
if (start_param > 0)
{
DebugSay((string)llGetKey() + " on channel " + (string)start_param);
llSay(start_param, llGetKey());
}
ResetScript();
}
listen(integer channel, string name, key id, string message)
{
DebugSay(message);
list info = llCSV2List(message);
key tubeKey = llList2String(info, 0);
string command = llList2String(info, 1);
if (tubeKey == llGetKey())
{
if (command == "SendInfo")
{
list info;
info += [llGetKey()];
info += [llAvatarOnSitTarget()];
llSay(2, llList2CSV(info));
DebugSay(llList2CSV(info));
}
else if (command == "Die")
{
llDie();
}
}
}
}
--Hugsy

