Here is the main script:
Code: Select all
///////////////////////////////////////////////////////////////////////////////
// Builders' Buddy 1.10 (Base Script)
// by Newfie Pendragon, 2006-2008
//
// Updated by Brayla Sana 2020
//
///////////////////////////////////////////////////////////////////////////////
//
// Script Purpose & Use
// Functions are dependent on the "component script"
//
// QUICK USE:
// - Copy this entire notecard and place it in a script. Name it "BB Base".
// - Drop this script in the Base.
// - Drop the "Component" Script in each building part.
// - Touch your Base, and choose RECORD
// - Take all building parts into inventory
// - Drag building parts from inventory into Base Prim
// - Touch your base and choose BUILD
//
// OTHER COMMANDS from the Touch menu
// - To reposition, move/rotate Base Prim choose POSITION
// - To lock into position (removes scripts) choose DONE
// - To delete building pieces: choose CLEAN
///////////////////////////////////////////////////////////////////////////////
// This script is copyrighted material, and has a few (minor) restrictions.
// For complete details, including a revision history, please see
// http://wiki.secondlife.com/wiki/Builders_Buddy
///////////////////////////////////////////////////////////////////////////////
// Channel used by Base Prim to talk to Component Prims
// This channel must be the same one in the component script
// A negative channel is used because it elimited accidental activations
// by an Avatar talking on obscure channels
integer DefaultPRIMCHAN = -192567; // Default channel to use
//integer PRIMCHAN = DefaultPRIMCHAN; // Channel used by Base Prim to talk to Component Prims;
integer PRIMCHAN = -192567; // OpenSim Modification - also comment out the previous line for OpenSim
// ***THIS MUST MATCH IN BOTH SCRIPTS!***
///////////////////////////////////////////////////////////////////////////////
// Variables for Positioning limits within the sim
//
// Change these values if your using Megaregions or want to limit otherwise.
float vDestPosXMIN = 0.0;
float vDestPosXMAX = 2048.0; //2048 for Varregions
float vDestPosYMIN = 0.0;
float vDestPosYMAX = 2048.0; //2048 for Varregions
float vDestPosZMAX = 10000.0;
//The UUID of the creator of the object
//Leave this as "" unless SL displays wrong name in object properties
key creatorUUID = "";
// Set to TRUE to allow group members to use the dialog menu
// Set to FALSE to disallow group members from using the dialog menu
integer ingroup = TRUE;
// Set to TRUE to delete piece from inventory when rezzed
// (WARNING) If set to FALSE, user will be able to rez multiple copies
integer deleteOnRez = FALSE;
// Allow non-creator to use CLEAN command?
// (WARNING) If set to TRUE, it is recommended to set
// deleteOnRez to FALSE, or user could lose entire building
integer allowClean = TRUE;
//When user selects CLEAN, delete the base prim too?
integer dieOnClean = FALSE;
// Set to TRUE to record piece's location based on sim
// coordinates instead of relationship to base prim
integer recordSimLocation = FALSE;
// Set to TRUE to rez all building pieces before positioning,
// or FALSE to do (slower?) one at a time
integer bulkBuild = TRUE;
//Set to FALSE if you dont want the script to say anything while 'working'
integer chatty = TRUE;
//How long to listen for a menu response before shutting down the listener
float fListenTime = 30.0;
//How often (in seconds) to perform any timed checks
float fTimerRate = 0.25;
//How long to sit still before exiting active mode
float fStoppedTime = 30.0;
//SL sometimes blocks rezzing to prevent "gray goo" attacks
//How long we wait (seconds) before we assume SL blocked our rez attempt
integer iRezWait = 10;
//Specify which Menu Options will be displayed
//FALSE will restrict full options to creator
//TRUE will offer full options to anyone
integer fullOptions = FALSE;
//Set to TRUE if you want ShapeGen channel support
// (Last 4 digits of channel affected)
integer SGCompatible = FALSE;
///////////////////////////////////////////////////////////////////////////////
//Part of KEYPAD CODE BY Andromeda Quonset....More added below in seevral places
list Menu2 = [ "-", "0","enter","7","8","9","4","5","6","1","2","3"];
string Input = "";
string Sign = "+";
string SignInput = " ";
string Caption = "Enter a number, include any leading 0's: ";
///////////////////////////////////////////////////////////////////////////////
// DO NOT EDIT BELOW THIS LINE.... NO.. NOT EVEN THEN
///////////////////////////////////////////////////////////////////////////////
//Name each option-these names will be your button names.
string optRecord = "Record";
string optReset = "Reset";
string optBuild = "Build";
string optPos = "Position";
string optClean = "Clean";
string optDone = "Done";
string optChannel = "Channel";
//Menu option descriptions
string descRecord = ": Record the position of all parts\n";
string descReset = ": Forgets the position of all parts\n";
string descBuild = ": Rez inv. items and position them\n";
string descPos = ": Reposition the parts to a new location\n";
string descClean = ": De-Rez all pieces\n";
string descDone = ": Remove all BB scripts and freeze parts in place.\n";
string descChannel = ": Change Channel used on base and parts.\n";
integer MENU_CHANNEL;
integer MENU2_CHANNEL;
integer MENU_HANDLE;
integer MENU2_HANDLE;
key agent;
key objectowner;
integer group;
string title = "";
list optionlist = [];
integer bMoving;
vector vLastPos;
rotation rLastRot;
integer bRezzing;
integer iListenTimeout = 0;
integer iLastRez = 0;
integer iRezIndex;
InvertSign()
{
if(Sign == "+")
Sign = "-";
else
Sign = "+";
}
//To avoid flooding the sim with a high rate of movements
//(and the resulting mass updates it will bring), we used
// a short throttle to limit ourselves
announce_moved()
{
llRegionSay(PRIMCHAN, "MOVE " + llDumpList2String([ llGetPos(), llGetRot() ], "|"));
llResetTime(); //Reset our throttle
vLastPos = llGetPos();
rLastRot = llGetRot();
return;
}
rez_object()
{
//Rez the object indicated by iRezIndex
llRezObject(llGetInventoryName(INVENTORY_OBJECT, iRezIndex), llGetPos(), ZERO_VECTOR, llGetRot(), PRIMCHAN);
iLastRez = llGetUnixTime();
llSleep(2);
if(!bRezzing) {
bRezzing = TRUE;
//timer_on();
}
llSay(PRIMCHAN, "SET_LIMITS " + (string)vDestPosXMIN + " " + (string)vDestPosXMAX + " " + (string)vDestPosYMIN + " " + (string)vDestPosYMAX + " " + (string)vDestPosZMAX );
}
post_rez_object()
{
if ( creatorUUID != llGetOwner() ) {
if(deleteOnRez) llRemoveInventory(llGetInventoryName(INVENTORY_OBJECT, iRezIndex));
}
}
heard(integer channel, string name, key id, string message)
{
if( channel == PRIMCHAN ) {
if( message == "READYTOPOS" ) {
//New prim ready to be positioned
vector vThisPos = llGetPos();
rotation rThisRot = llGetRot();
llRegionSay(PRIMCHAN, "MOVESINGLE " + llDumpList2String([ vThisPos, rThisRot ], "|"));
} else if( message == "ATDEST" ) {
//Rez the next in the sequence (if any)
iRezIndex--;
if(iRezIndex >= 0) {
//Attempt to rez it
rez_object();
} else {
//We are done building, reset our listeners
iLastRez = 0;
bRezzing = FALSE;
state reset_listeners;
}
}
return;
} else if( channel == MENU_CHANNEL ) { //Process input from original menu
if ( message == optRecord ) {
PRIMCHAN = DefaultPRIMCHAN;
llOwnerSay("Recording positions...");
if(recordSimLocation) {
//Location in sim
llRegionSay(PRIMCHAN, "RECORDABS " + llDumpList2String([ llGetPos(), llGetRot() ], "|"));
} else {
//Location relative to base
llRegionSay(PRIMCHAN, "RECORD " + llDumpList2String([ llGetPos(), llGetRot() ], "|"));
}
return;
}
if( message == optReset ) {
llOwnerSay("Forgetting positions...");
llShout(PRIMCHAN, "RESET");
return;
}
if ( message == optBuild ) {
if(chatty) llOwnerSay("Rezzing build pieces...");
//If rezzing/positioning one at a time, we need
// to listen for when they've reached their dest
if(!bulkBuild) {
llListen(PRIMCHAN, "", NULL_KEY, "READYTOPOS");
llListen(PRIMCHAN, "", NULL_KEY, "ATDEST");
}
//Start rezzing, last piece first
iRezIndex = llGetInventoryNumber(INVENTORY_OBJECT) - 1;
rez_object();
return;
}
if ( message == optPos ) {
if(chatty) llOwnerSay("Positioning");
vector vThisPos = llGetPos();
rotation rThisRot = llGetRot();
llRegionSay(PRIMCHAN, "MOVE " + llDumpList2String([ vThisPos, rThisRot ], "|"));
return;
}
if ( message == optClean ) {
llRegionSay(PRIMCHAN, "CLEAN");
if(dieOnClean) llDie();
return;
}
if ( message == optDone ) {
llRegionSay(PRIMCHAN, "DONE");
if(chatty) llOwnerSay("Removing Builder's Buddy scripts.");
return;
}
if ( message == optChannel ) {
Sign = "+"; //default is a positive number
Input = "";
llDialog( agent, Caption, Menu2, MENU2_CHANNEL );
}
} else if ( channel == MENU2_CHANNEL ) { //process input from MENU2
// if a valid choice was made, implement that choice if possible.
// (llListFindList returns -1 if Choice is not in the menu list.)
if ( llListFindList( Menu2, [ message ]) != -1 ) {
if( llListFindList(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], [message]) != -1) {
Input += message;
SignInput = Sign + Input;
llDialog( agent, Caption + SignInput, Menu2, MENU2_CHANNEL );
} else if( message == "-" ) {
InvertSign();
SignInput = Sign + Input;
llDialog( agent, Caption + SignInput, Menu2, MENU2_CHANNEL );
} else if( message == "enter" ) { //terminate input from menu2
string CalcChan = Input;
//Apply ShapeGen compatibility?
if(SGCompatible) {
//new assign channel number, forcing last 4 digits to 0000
integer ChanSize = llStringLength(Input); //determine number of digits (chars)
if(ChanSize > 5) {
CalcChan = llGetSubString(Input, 0, 4); //Shorten to 5 digits
}
CalcChan += "0000"; //append 0000
if(Sign == "-")
CalcChan = Sign + CalcChan;
}
PRIMCHAN = (integer)CalcChan; //assign channel number
llOwnerSay("Channel set to " + (string)PRIMCHAN + ".");
}
} else {
llDialog( agent, Caption, Menu2, MENU2_CHANNEL );
}
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
default {
///////////////////////////////////////////////////////////////////////////////
changed(integer change) {
if(change & CHANGED_OWNER)
llResetScript();
}
///////////////////////////////////////////////////////////////////////////////
state_entry () {
//Determine the creator UUID
if(creatorUUID == "") creatorUUID = llGetCreator();
//Use which menu?
if (creatorUUID == llGetOwner() || fullOptions) {
//Display all options
optionlist = [optPos, optClean, optDone, optRecord, optReset, optBuild, optChannel];
title = optRecord + descRecord;
title += optReset + descReset;
title += optBuild + descBuild;
title += optPos + descPos;
title += optClean + descClean;
title += optDone + descDone;
title += optChannel + descChannel;
} else {
//Display limited options
if(allowClean) {
optionlist = [optBuild, optPos, optClean, optDone];
title = optBuild + descBuild;
title += optPos + descPos;
title += optClean + descClean;
title += optDone + descDone;
} else {
optionlist = [optBuild, optPos, optDone];
title = optBuild + descBuild;
title += optPos + descPos;
title += optDone + descDone;
}
}
//Record our position
vLastPos = llGetPos();
rLastRot = llGetRot();
llSetTimerEvent(fTimerRate);
}
///////////////////////////////////////////////////////////////////////////////
touch_start (integer total_number) {
group = llDetectedGroup(0); // Is the Agent in the objowners group?
agent = llDetectedKey(0); // Agent's key
objectowner = llGetOwner(); // objowners key
// is the Agent = the owner OR is the agent in the owners group
if ( (objectowner == agent) || ( group && ingroup ) ) {
iListenTimeout = llGetUnixTime() + llFloor(fListenTime);
MENU_CHANNEL = llFloor(llFrand(-99999.0 - -100));
MENU2_CHANNEL = MENU_CHANNEL + 1;
MENU_HANDLE = llListen(MENU_CHANNEL,"","","");
MENU2_HANDLE = llListen(MENU2_CHANNEL,"","","");
if ( creatorUUID == llGetOwner() || fullOptions) {
llDialog(agent,title + "Now on Channel " + (string)PRIMCHAN, optionlist, MENU_CHANNEL); //display channel number if authorized
} else {
llDialog(agent, title, optionlist, MENU_CHANNEL);
}
//timer_on();
}
}
///////////////////////////////////////////////////////////////////////////////
listen(integer channel, string name, key id, string message) {
heard(channel, name, id, message);
return;
}
///////////////////////////////////////////////////////////////////////////////
moving_start()
{
if( !bMoving )
{
bMoving = TRUE;
//timer_on();
announce_moved();
}
}
///////////////////////////////////////////////////////////////////////////////
object_rez(key id) {
//The object rezzed, perform any post-rez processing
post_rez_object();
//Rezzing it all before moving?
if(bulkBuild) {
//Move on to the next object
//Loop through backwards (safety precaution in case of inventory change)
iRezIndex--;
if(iRezIndex >= 0) {
//Attempt to rez it
rez_object();
} else {
//Rezzing complete, now positioning
iLastRez = 0;
bRezzing = FALSE;
if(chatty) llOwnerSay("Positioning");
llRegionSay(PRIMCHAN, "MOVE " + llDumpList2String([ llGetPos(), llGetRot() ], "|"));
}
}
}
///////////////////////////////////////////////////////////////////////////////
timer() {
//Did we change position/rotation?
if( (llGetRot() != rLastRot) || (llGetPos() != vLastPos) )
{
if( llGetTime() > fTimerRate ) {
announce_moved();
}
}
//Are we rezzing?
if(bRezzing) {
//Did the last one take too long?
if((llGetUnixTime() - iLastRez) >= iRezWait) {
//Yes, retry it
if(chatty) llOwnerSay("Reattempting rez of most recent piece");
rez_object();
}
}
//Open listener?
if( iListenTimeout != 0 )
{
//Past our close timeout?
if( iListenTimeout <= llGetUnixTime() )
{
iListenTimeout = 0;
llListenRemove(MENU_HANDLE);
}
}
}
///////////////////////////////////////////////////////////////////////////////
on_rez(integer iStart)
{
//Reset ourselves
llResetScript();
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
state reset_listeners
{
//////////////////////////////////////////////////////////////////////////////////////////
state_entry()
{
state default;
}
}
And Here is the Component:
Code: Select all
///////////////////////////////////////////////////////////////////////////////
// Builders' Buddy 1.10 (Component Script)
// by Newfie Pendragon, 2006-2008
//
// Updated by Brayla Sana 2020
//
///////////////////////////////////////////////////////////////////////////////
//
// Script Purpose & Use
// Functions are dependent on the "component script"
//
// QUICK USE:
// - Drop this script in the Base.
// - Drop the "Component" Script in each building part.
// - Touch your Base, and choose RECORD
// - Take all building parts into inventory
// - Drag building parts from inventory into Base Prim
// - Touch your base and choose BUILD
//
// OTHER COMMANDS from the Touch menu
// - To reposition, move/rotate Base Prim choose POSITION
// - To lock into position (removes scripts) choose DONE
// - To delete building pieces: choose CLEAN
///////////////////////////////////////////////////////////////////////////////
// This script is copyrighted material, and has a few (minor) restrictions.
// For complete details, including a revision history, please see
// http://wiki.secondlife.com/wiki/Builders_Buddy
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Added a Memory datastorage for opensim using osMakeNotecard
///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Configurable Settings
float fTimerInterval = 0.25; // Time in seconds between movement 'ticks'
integer DefaultChannel = -192567; // Andromeda Quonset's default channel
//integer PRIMCHAN = DefaultChannel; // Channel used by Base Prim to talk to Component Prims;
integer PRIMCHAN = -192567; // OpenSim Modification - also comment out the previous line for OpenSim
// ***THIS MUST MATCH IN BOTH SCRIPTS!***
//////////////////////////////////////////////////////////////////////////////////////////
// Runtime Variables (Dont need to change below here unless making a derivative)
vector vOffset;
rotation rRotation;
integer bNeedMove;
vector vDestPos;
rotation rDestRot;
integer bMovingSingle = FALSE;
integer bAbsolute = FALSE;
integer bRecorded = FALSE;
list record_mem = []; // Memory to be stored
key g_quary_nc; //for reading our memory notecard
integer nc_line; //what line are we reading
integer iStartValue;
//////////////////////////////////////////////////////////////////////////////////////////
// Variables for Positioninglimits within the sim
float vDestPosXMIN = 0.0;
float vDestPosXMAX = 2048.0;
float vDestPosYMIN = 0.0;
float vDestPosYMAX = 2048.0;
float vDestPosZMAX = 10000.0;
////////////////////////////////////////////////////////////////////////////////
string first_word(string In_String, string Token)
{
//This routine searches for the first word in a string,
// and returns it. If no word boundary found, returns
// the whole string.
if(Token == "") Token = " ";
integer pos = llSubStringIndex(In_String, Token);
//Found it?
if( pos >= 1 )
return llGetSubString(In_String, 0, pos - 1);
else
return In_String;
}
////////////////////////////////////////////////////////////////////////////////
string other_words(string In_String, string Token)
{
//This routine searches for the other-than-first words in a string,
// and returns it. If no word boundary found, returns
// an empty string.
if( Token == "" ) Token = " ";
integer pos = llSubStringIndex(In_String, Token);
//Found it?
if( pos >= 1 )
return llGetSubString(In_String, pos + 1, llStringLength(In_String));
else
return "";
}
////////////////////////////////////////////////////////////////////////////////
do_move()
{
integer i = 0;
vector vLastPos = ZERO_VECTOR;
while( (i < 5) && (llGetPos() != vDestPos) )
{
list lParams = [];
//If we're not there....
if( llGetPos() != vDestPos )
{
//We may be stuck on the ground...
//Did we move at all compared to last loop?
if( llGetPos() == vLastPos )
{
//Yep, stuck...move straight up 10m (attempt to dislodge)
lParams = [ PRIM_POSITION, llGetPos() + <0, 0, 10.0> ];
//llSetPos(llGetPos() + <0, 0, 10.0>);
} else {
//Record our spot for 'stuck' detection
vLastPos = llGetPos();
}
}
//Try to move to destination
//Upgraded to attempt to use the llSetPrimitiveParams fast-move hack
//(Newfie, June 2006)
integer iHops = llAbs(llCeil(llVecDist(llGetPos(), vDestPos) / 10.0));
integer x;
for( x = 0; x < iHops; x++ ) {
lParams += [ PRIM_POSITION, vDestPos ];
}
llSetPrimitiveParams(lParams);
//llSleep(0.1);
i++;
}
//Set rotation
llSetRot(rDestRot);
}
start_move(string sText, key kID)
{
//Don't move if we've not yet recorded a position
if( !bRecorded ) return;
//Also ignore commands from bases with a different owner than us
//(Anti-hacking measure)
if( llGetOwner() != llGetOwnerKey(kID) ) return;
//Calculate our destination position relative to base?
if(!bAbsolute) {
//Relative position
//Calculate our destination position
sText = other_words(sText, " ");
list lParams = llParseString2List(sText, [ "|" ], []);
vector vBase = (vector)llList2String(lParams, 0);
rotation rBase = (rotation)llList2String(lParams, 1);
vDestPos = (vOffset * rBase) + vBase;
rDestRot = rRotation * rBase;
} else {
//Sim position
vDestPos = vOffset;
rDestRot = rRotation;
}
//Make sure our calculated position is within the sim
if(vDestPos.x < vDestPosXMIN) vDestPos.x = vDestPosXMIN;
if(vDestPos.x > vDestPosXMAX) vDestPos.x = vDestPosXMAX;
if(vDestPos.y < vDestPosYMIN) vDestPos.y = vDestPosYMIN;
if(vDestPos.y > vDestPosYMAX) vDestPos.y = vDestPosYMAX;
if(vDestPos.z > vDestPosZMAX) vDestPos.z = vDestPosZMAX;
//Turn on our timer to perform the move?
if( !bNeedMove )
{
llSetTimerEvent(fTimerInterval);
bNeedMove = TRUE;
}
return;
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
default
{
//////////////////////////////////////////////////////////////////////////////////////////
state_entry()
{
//Open up the listener
llListen(PRIMCHAN, "", NULL_KEY, "");
llRegionSay(PRIMCHAN, "READYTOPOS");
}
//////////////////////////////////////////////////////////////////////////////////////////
on_rez(integer iStart)
{
iStartValue = iStart;
if(llGetInventoryType("Builders Buddy Memory") != -1)
{
nc_line = 0;
g_quary_nc = llGetNotecardLine("Builders Buddy Memory", nc_line);
}
else
{
//Set the channel to what's specified
if( iStart != 0 )
{
PRIMCHAN = iStart;
state reset_listeners;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
listen(integer iChan, string sName, key kID, string sText)
{
string sCmd = llToUpper(first_word(sText, " "));
if( sCmd == "SET_LIMITS" )
{
list lParams = llParseString2List(sText, [ " " ], []);
vDestPosXMIN = llList2Float(lParams, 1);
vDestPosXMAX = llList2Float(lParams, 2);
vDestPosYMIN = llList2Float(lParams, 3);
vDestPosYMAX = llList2Float(lParams, 4);
vDestPosZMAX = llList2Float(lParams, 5);
}
else if( sCmd == "RECORD" )
{
record_mem = [];
//Record position relative to base prim
sText = other_words(sText, " ");
list lParams = llParseString2List(sText, [ "|" ], []);
vector vBase = (vector)llList2String(lParams, 0);
rotation rBase = (rotation)llList2String(lParams, 1);
vOffset = (llGetPos() - vBase) / rBase;
record_mem += "vOffset|" +(string)vOffset ;
rRotation = llGetRot() / rBase;
record_mem += "rRotation|" +(string)rRotation ;
bAbsolute = FALSE;
record_mem += "bAbsolute|" +(string)bAbsolute ;
bRecorded = TRUE;
record_mem += "bRecorded|" +(string)bRecorded ;
if(llGetInventoryType("Builders Buddy Memory") != -1)
{
llRemoveInventory("Builders Buddy Memory");
}
osMakeNotecard( "Builders Buddy Memory", record_mem );
llOwnerSay("Recorded position.");
return;
}
if( sCmd == "RECORDABS" )
{
record_mem = [];
//Record absolute position
rRotation = llGetRot();
record_mem += "rRotation|" +(string)rRotation ;
vOffset = llGetPos();
record_mem += "vOffset|" +(string)vOffset ;
bAbsolute = TRUE;
record_mem += "bAbsolute|" +(string)bAbsolute ;
bRecorded = TRUE;
record_mem += "bRecorded|" +(string)bRecorded ;
if(llGetInventoryType("Builders Buddy Memory") != -1)
{
llRemoveInventory("Builders Buddy Memory");
}
osMakeNotecard( "Builders Buddy Memory", record_mem );
llOwnerSay("Recorded sim position.");
return;
}
//////////////////////////////////////////////////////////////////////////////////////////
if( sCmd == "MOVE" )
{
start_move(sText, kID);
return;
}
if( sCmd == "MOVESINGLE" )
{
//If we haven't gotten this before, position ourselves
if(!bMovingSingle) {
//Record that we are a single-prim move
bMovingSingle = TRUE;
//Now move it
start_move(sText, kID);
return;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
if( sCmd == "DONE" )
{
//We are done, remove script
if(llGetInventoryType("Builders Buddy Memory") != -1)
{
llRemoveInventory("Builders Buddy Memory");
}
llRemoveInventory(llGetScriptName());
return;
}
//////////////////////////////////////////////////////////////////////////////////////////
if( sCmd == "CLEAN" )
{
//Clean up
llDie();
return;
}
//////////////////////////////////////////////////////////////////////////////////////////
if( sCmd == "RESET" )
{
llResetScript();
}
}
//////////////////////////////////////////////////////////////////////////////////////////
timer()
{
//Turn ourselves off
llSetTimerEvent(0.0);
//Do we need to move?
if( bNeedMove )
{
//Perform the move and clean up
do_move();
//If single-prim move, announce to base we're done
if(bMovingSingle) {
llRegionSay(PRIMCHAN, "ATDEST");
}
//Done moving
bNeedMove = FALSE;
}
return;
}
dataserver(key queryid, string data)
{
if ( queryid == g_quary_nc)
{
if (data != EOF)
{
list n = llParseString2List(data, ["|"], []);
if(llList2String(n, 0) == "vOffset")
{
vOffset = llList2Vector(n, 1);
}
else if(llList2String(n, 0) == "rRotation")
{
rRotation = llList2Rot(n, 1);
}
else if(llList2String(n, 0) == "bAbsolute")
{
bAbsolute = (integer)llList2String(n, 1);
}
else if(llList2String(n, 0) == "bRecorded")
{
bRecorded = (integer)llList2String(n, 1);
}
nc_line++;
g_quary_nc = llGetNotecardLine("Builders Buddy Memory", nc_line);
}
else
{
//Set the channel to what's specified
if( iStartValue != 0 )
{
PRIMCHAN = iStartValue;
state reset_listeners;
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
state reset_listeners
{
//////////////////////////////////////////////////////////////////////////////////////////
state_entry()
{
state default;
}
}