Difference between revisions of "Builders Buddy v1"
Jump to navigation
Jump to search
Huney Jewell (talk | contribs) (→The Component Script: updated to version 1.9) |
Huney Jewell (talk | contribs) |
||
Line 5: | Line 5: | ||
Due to a number of people confused by the copyright wording, here's a recap: '''Use this script any way you want. SELL IT EVEN! Just make sure I am given credit as the creator.''' That's the only restriction. | Due to a number of people confused by the copyright wording, here's a recap: '''Use this script any way you want. SELL IT EVEN! Just make sure I am given credit as the creator.''' That's the only restriction. | ||
== The Base Script ==/////////////////////////////////////////////////////////////////////////////// | == The Base Script == | ||
// Builders' Buddy | /////////////////////////////////////////////////////////////////////////////// | ||
// by Newfie Pendragon, March 2006 | // Builders' Buddy 1.8 (Base Script) | ||
// | // by Newfie Pendragon, March 2006 | ||
// This script is distributed with permission that it may be used in | // | ||
// any way, or may be further modified/included in resale items. | // This script is distributed with permission that it may be used in | ||
// HOWEVER, if this script is used as part of a for-sale product, | // any way, or may be further modified/included in resale items. | ||
// it is required that appropriate credit be given to Newfie for | // HOWEVER, if this script is used as part of a for-sale product, | ||
// the script (or portions used in derivatives). That's a fair price | // it is required that appropriate credit be given to Newfie for | ||
// in exchange for unlimited use of this script, dontcha think? | // the script (or portions used in derivatives). That's a fair price | ||
// | // in exchange for unlimited use of this script, dontcha think? | ||
// SL Forum thread and new versions found here: | // | ||
// http://forums.secondlife.com/showthread.php?t=96792 | // SL Forum thread and new versions found here: | ||
/////////////////////////////////////////////////////////////////////////////// | // http://forums.secondlife.com/showthread.php?t=96792 | ||
// | /////////////////////////////////////////////////////////////////////////////// | ||
// Script Purpose & Use | // | ||
// | // Script Purpose & Use | ||
// Functions are dependent on the "component script" | // | ||
// | // Functions are dependent on the "component script" | ||
// QUICK USE: | // | ||
// - Drop this script in the Base. | // QUICK USE: | ||
// - Drop the "Component" Script in each building part. | // - Drop this script in the Base. | ||
// - Touch your Base, and choose RECORD | // - Drop the "Component" Script in each building part. | ||
// - Take all building parts into inventory | // - Touch your Base, and choose RECORD | ||
// - Drag building parts from inventory into Base Prim | // - Take all building parts into inventory | ||
// - Touch your base and choose BUILD | // - 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 | // OTHER COMMANDS from the Touch menu | ||
// - To lock into position (removes scripts) choose DONE | // - To reposition, move/rotate Base Prim choose POSITION | ||
// - To delete building pieces: choose CLEAN | // - To lock into position (removes scripts) choose DONE | ||
// | // - To delete building pieces: choose CLEAN | ||
/////////////////////////////////////////////////////////////////////////////// | // | ||
// | /////////////////////////////////////////////////////////////////////////////// | ||
// History | // | ||
// | // History | ||
// v1.0 - 20060328 - Newfie Pendragon | // | ||
// - Original Version | // v1.0 - 20060328 - Newfie Pendragon | ||
// v1.1 - 20060331 - Kalidor Lazarno | // - Original Version | ||
// - Added a Dialog Engine to the base script | // v1.1 - 20060331 - Kalidor Lazarno | ||
// v1.5 - 20060612 - Androclese Antonelli | // - Added a Dialog Engine to the base script | ||
// - Added a random number generator to the dialog engine to elimintate | // v1.5 - 20060612 - Androclese Antonelli | ||
// problems with multiple BB boxes cross-talking | // - Added a random number generator to the dialog engine to elimintate | ||
// - Added a timer to the listen command to put it asleep after 10sec. | // problems with multiple BB boxes cross-talking | ||
// - Added a Menu Description | // - Added a timer to the listen command to put it asleep after 10sec. | ||
// - Added n "creator" flag so the owner could use the same object with full | // - Added a Menu Description | ||
// menu options and only a single flag change | // - Added n "creator" flag so the owner could use the same object with full | ||
// - Added an "ingroup" flag to enable/disable the same group use function | // menu options and only a single flag change | ||
// - Non-Admin usage cleans the inventory items as they spawn | // - Added an "ingroup" flag to enable/disable the same group use function | ||
// v1.6 - 20060624 - Newfie Pendragon | // - Non-Admin usage cleans the inventory items as they spawn | ||
// - Added active repositioning (building moves as the base piece moves) | // v1.6 - 20060624 - Newfie Pendragon | ||
// - Added "Reset" Option to unlink parts from base temporarily | // - Added active repositioning (building moves as the base piece moves) | ||
// - Modified creator flag to automatically set based if owner is creator | // - Added "Reset" Option to unlink parts from base temporarily | ||
// - Minor changes to improve code readability (for those learning LSL) | // - Modified creator flag to automatically set based if owner is creator | ||
// v1.8 - 20070429 - Newfie Pendragon | // - Minor changes to improve code readability (for those learning LSL) | ||
// - Added a variable to allow a user to tweak how long a listener is open, | // v1.8 - 20070429 - Newfie Pendragon | ||
// and changed the default to 30 seconds. | // - Added a variable to allow a user to tweak how long a listener is open, | ||
// | // and changed the default to 30 seconds. | ||
// | /////////////////////////////////////////////////////////////////////////////// | ||
// | // User Variables | ||
// | /////////////////////////////////////////////////////////////////////////////// | ||
// | |||
// | |||
// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
//// | // 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; | |||
//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"; | |||
// | //Menu option descriptions | ||
string descRecord = " : Record the position of all parts\n"; | |||
string descReset = " : Forgets the position of all parts\n"; | |||
string descBuild = " : Spawn 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 make the parts permanent.\n"; | |||
// | //How long to listen for a menu response before shutting down the listener | ||
float fListenTime = 30.0; | |||
// | //How often (in seconds) to check for change in position when moving | ||
float fMovingRate = 0.25; | |||
//How long to | //How long to sit still before exiting active mode | ||
float | float fStoppedTime = 30.0; | ||
// | //Minimum amount of time (in seconds) between movement updates | ||
float | float fShoutRate = 0.25; | ||
// | // 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 PRIMCHAN = -19730611; | |||
// | /////////////////////////////////////////////////////////////////////////////// | ||
// DO NOT EDIT BELOW THIS LINE.... NO.. NOT EVEN THEN | |||
integer | /////////////////////////////////////////////////////////////////////////////// | ||
integer MENU_CHANNEL; | |||
integer MENU_HANDLE; | |||
key agent; | |||
key objectowner; | |||
integer group; | |||
string title = ""; | |||
list optionlist = []; | |||
integer bMoving; | |||
vector vLastPos; | |||
rotation rLastRot; | |||
integer iListenTimeout = 0; | |||
// | //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() | |||
{ | |||
llShout(PRIMCHAN, "MOVE " + llDumpList2String([ llGetPos(), llGetRot() ], "|")); | |||
llResetTime(); //Reset our throttle | |||
vLastPos = llGetPos(); | |||
rLastRot = llGetRot(); | |||
return; | |||
} | |||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||
// | /////////////////////////////////////////////////////////////////////////////// | ||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||
default { | |||
/////////////////////////////////////////////////////////////////////////////// | |||
changed(integer change) { | |||
if(change & CHANGED_OWNER) | |||
llResetScript(); | |||
} | |||
/////////////////////////////////////////////////////////////////////////////// | |||
state_entry () { | |||
//Use which menu? | |||
if ( llGetCreator() == llGetOwner() ) { | |||
//Display all options | |||
optionlist = [optPos, optClean, optDone, optRecord, optReset, optBuild]; | |||
title = optRecord + descRecord; | title = optRecord + descRecord; | ||
title += optReset + descReset; | title += optReset + descReset; | ||
Line 205: | Line 163: | ||
title += optDone + descDone; | title += optDone + descDone; | ||
} | } | ||
//Record our position | //Record our position | ||
vLastPos = llGetPos(); | vLastPos = llGetPos(); | ||
rLastRot = llGetRot(); | rLastRot = llGetRot(); | ||
} | } | ||
Line 224: | Line 181: | ||
MENU_HANDLE = llListen(MENU_CHANNEL,"","",""); | MENU_HANDLE = llListen(MENU_CHANNEL,"","",""); | ||
llDialog(agent, title, optionlist, MENU_CHANNEL); | llDialog(agent, title, optionlist, MENU_CHANNEL); | ||
llSetTimerEvent(fShoutRate); | |||
} | } | ||
} | } | ||
Line 232: | Line 189: | ||
if ( message == optRecord ) { | if ( message == optRecord ) { | ||
llOwnerSay("Recording positions..."); | llOwnerSay("Recording positions..."); | ||
llShout(PRIMCHAN, "RECORD " + llDumpList2String([ llGetPos(), llGetRot() ], "|")); | |||
return; | return; | ||
} | } | ||
Line 241: | Line 198: | ||
} | } | ||
if ( message == optBuild ) { | if ( message == optBuild ) { | ||
vector vThisPos = llGetPos(); | |||
rotation rThisRot = llGetRot(); | |||
integer i; | |||
integer iCount = llGetInventoryNumber(INVENTORY_OBJECT); | |||
//Loop through backwards (safety precaution in case of inventory change) | |||
llOwnerSay("Rezzing build pieces..."); | |||
for( i = iCount - 1; i >= 0; i-- ) | |||
{ | |||
llRezObject(llGetInventoryName(INVENTORY_OBJECT, i), vThisPos, ZERO_VECTOR, rThisRot, PRIMCHAN); | |||
if ( llGetCreator() != llGetOwner() ) | |||
llRemoveInventory(llGetInventoryName(INVENTORY_OBJECT, i)); | |||
} | |||
llOwnerSay("Positioning"); | |||
llShout(PRIMCHAN, "MOVE " + llDumpList2String([ vThisPos, rThisRot ], "|")); | |||
return; | return; | ||
} | } | ||
if ( message == optPos ) { | if ( message == optPos ) { | ||
llOwnerSay("Positioning"); | |||
vector vThisPos = llGetPos(); | vector vThisPos = llGetPos(); | ||
rotation rThisRot = llGetRot(); | rotation rThisRot = llGetRot(); | ||
llShout(PRIMCHAN, "MOVE " + llDumpList2String([ vThisPos, rThisRot ], "|")); | |||
return; | return; | ||
} | } | ||
if ( message == optClean ) { | if ( message == optClean ) { | ||
llShout(PRIMCHAN, "CLEAN"); | |||
return; | return; | ||
} | } | ||
if ( message == optDone ) { | if ( message == optDone ) { | ||
llShout(PRIMCHAN, "DONE"); | |||
//llDie(); | |||
llOwnerSay("Removing mover scripts."); | |||
return; | return; | ||
} | } | ||
} | } | ||
Line 271: | Line 241: | ||
{ | { | ||
bMoving = TRUE; | bMoving = TRUE; | ||
// | llSetTimerEvent(0.0); //Resets the timer if already running | ||
llSetTimerEvent(fMovingRate); | |||
announce_moved(); | announce_moved(); | ||
} | } | ||
} | } | ||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||
timer() { | timer() { | ||
// | //Were we moving? | ||
if( | if( bMoving ) | ||
{ | { | ||
if( llGetTime() > | //Did we change position/rotation? | ||
if( (llGetRot() != rLastRot) || (llGetPos() != vLastPos) ) | |||
{ | |||
if( llGetTime() > fShoutRate ) { | |||
announce_moved(); | |||
} | |||
} | } | ||
} else { | |||
//Have we been sitting long enough to consider ourselves stopped? | |||
if( llGetTime() > fStoppedTime ) | |||
bMoving = FALSE; | |||
} | } | ||
//Open listener? | //Open listener? | ||
if( iListenTimeout != 0 ) | if( iListenTimeout != 0 ) | ||
Line 326: | Line 274: | ||
llListenRemove(MENU_HANDLE); | llListenRemove(MENU_HANDLE); | ||
} | } | ||
} | |||
//Stop the timer? | |||
if( (iListenTimeout == 0) && ( !bMoving ) ) | |||
{ | |||
llOwnerSay("Stopping Timer"); | |||
llSetTimerEvent(0.0); | |||
} | } | ||
} | } | ||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||
on_rez(integer iStart) | on_rez(integer iStart) | ||
Line 335: | Line 290: | ||
llResetScript(); | llResetScript(); | ||
} | } | ||
} | } | ||
/////////////////////////////////////////////////////////////////////////////// | |||
// Builders' Buddy 1. | == The Component Script == | ||
// by Newfie Pendragon, March 2006 | /////////////////////////////////////////////////////////////////////////////// | ||
// | // Builders' Buddy 1.7 (Component Pieces) | ||
// This script is distributed with permission that it may be used in | // | ||
// any way, or may be further modified/included in resale items. | // by Newfie Pendragon, March 2006 | ||
// HOWEVER, if this script is used as part of a for-sale product, | // | ||
// it is required that appropriate credit be given to Newfie for | // This script is distributed with permission that it may be used in | ||
// the script (or portions used in derivatives). That's a fair price | // any way, or may be further modified/included in resale items. | ||
// in exchange for unlimited use of this script, dontcha think? | // HOWEVER, if this script is used as part of a for-sale product, | ||
// | // it is required that appropriate credit be given to Newfie for | ||
// SL Forum thread and new versions found here: | // the script (or portions used in derivatives). That's a fair price | ||
// http://forums.secondlife.com/showthread.php?t=96792 | // in exchange for unlimited use of this script, dontcha think? | ||
// | |||
// SL Forum thread and new versions found here: | |||
// http://forums.secondlife.com/showthread.php?t=96792 | |||
/////////////////////////////////////////////////////////////////////////////// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////// | // INSTRUCTIONS | ||
// | // This is the *Component Piece* half of the Builders' Buddy system. | ||
// Drop it into each 'piece' of the building. Drop the Base Prim Script | |||
// into the prim that will be the container/box that will be used to | |||
// store the building once completed. It can be in each individual | |||
// prim, but if you link as much as possible (and put the script in the link | |||
// set), it'll be much more neighbourly and less strain on the sim. | |||
// | |||
// 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 | |||
// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
// History | |||
// | |||
// v1.0 - 20060328 - Newfie Pendragon - Original Version | |||
// v1.5 - 20060612 - Androclese Antonelli | |||
// - (See base script for details) | |||
// v1.6 - 20060624 - Newfie Pendragon | |||
// - Added active repositioning (pieces move as the base piece moves) | |||
// - Pieces use WarpPos technique to instantanetly move large distances | |||
// - Pieces no longer move until the the "Record" option has been used | |||
// at least once | |||
// - Pieces will not move if base is not same owner as the pieces | |||
// - Pieces no longer 'bounce' when hitting the ground | |||
// v1.7 - 20060821 - Correction for non-zero rotation (thanks Ed44 Gupta!) | |||
/////////////////////////////////////////////////////////////////////////////// | |||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
// | // Configurable Settings | ||
float fTimerInterval = 0.25; //Time in seconds between movement 'ticks' | |||
integer PRIMCHAN = -19730611; //Channel used by Base Prim to talk to Component Prims; | |||
integer | // 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 bRecorded = FALSE; | |||
//////////////////////////////////////////////////////////////////////////////// | |||
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? | //Found it? | ||
if( pos >= 1 ) | if( pos >= 1 ) | ||
Line 414: | Line 372: | ||
else | else | ||
return In_String; | 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 | |||
// the an empty string. | |||
if( Token == "" ) Token = " "; | |||
integer pos = llSubStringIndex(In_String, Token); | |||
//Found it? | //Found it? | ||
if( pos >= 1 ) | if( pos >= 1 ) | ||
Line 431: | Line 389: | ||
else | else | ||
return ""; | return ""; | ||
} | } | ||
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||
do_move() | do_move() | ||
{ | { | ||
integer i = 0; | integer i = 0; | ||
vector vLastPos = ZERO_VECTOR; | vector vLastPos = ZERO_VECTOR; | ||
Line 470: | Line 428: | ||
i++; | i++; | ||
} | } | ||
//Set rotation | //Set rotation | ||
llSetRot(rDestRot); | llSetRot(rDestRot); | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
default | default | ||
{ | { | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
state_entry() | state_entry() | ||
Line 487: | Line 445: | ||
llListen(PRIMCHAN, "", NULL_KEY, ""); | llListen(PRIMCHAN, "", NULL_KEY, ""); | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
on_rez(integer iStart) | on_rez(integer iStart) | ||
Line 498: | Line 456: | ||
} | } | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
listen(integer iChan, string sName, key kID, string sText) | listen(integer iChan, string sName, key kID, string sText) | ||
Line 517: | Line 475: | ||
return; | return; | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
if( sCmd == "MOVE" ) | if( sCmd == "MOVE" ) | ||
Line 523: | Line 481: | ||
//Don't move if we've not yet recorded a position | //Don't move if we've not yet recorded a position | ||
if( !bRecorded ) return; | if( !bRecorded ) return; | ||
//Also ignore commands from bases with a different owner than us | //Also ignore commands from bases with a different owner than us | ||
//(Anti-hacking measure) | //(Anti-hacking measure) | ||
if( llGetOwner() != llGetOwnerKey(kID) ) return; | if( llGetOwner() != llGetOwnerKey(kID) ) return; | ||
//Calculate our destination position | //Calculate our destination position | ||
sText = other_words(sText, " "); | sText = other_words(sText, " "); | ||
Line 534: | Line 492: | ||
vector vBase = (vector)llList2String(lParams, 0); | vector vBase = (vector)llList2String(lParams, 0); | ||
rotation rBase = (rotation)llList2String(lParams, 1); | rotation rBase = (rotation)llList2String(lParams, 1); | ||
//Calculate our destination position | //Calculate our destination position | ||
vDestPos = (vOffset * rBase) + vBase; | vDestPos = (vOffset * rBase) + vBase; | ||
rDestRot = rRotation * rBase; | rDestRot = rRotation * rBase; | ||
//Turn on our timer to perform the move? | //Turn on our timer to perform the move? | ||
Line 554: | Line 505: | ||
return; | return; | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
if( sCmd == "DONE" ) | if( sCmd == "DONE" ) | ||
Line 562: | Line 513: | ||
return; | return; | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
if( sCmd == "CLEAN" ) | if( sCmd == "CLEAN" ) | ||
Line 570: | Line 521: | ||
return; | return; | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
if( sCmd == "RESET" ) | if( sCmd == "RESET" ) | ||
Line 577: | Line 528: | ||
} | } | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
timer() | timer() | ||
Line 583: | Line 534: | ||
//Turn ourselves off | //Turn ourselves off | ||
llSetTimerEvent(0.0); | llSetTimerEvent(0.0); | ||
//Do we need to move? | //Do we need to move? | ||
if( bNeedMove ) | if( bNeedMove ) | ||
Line 593: | Line 544: | ||
return; | return; | ||
} | } | ||
} | } | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
state reset_listeners | state reset_listeners | ||
{ | { | ||
////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////// | ||
state_entry() | state_entry() | ||
Line 605: | Line 556: | ||
state default; | state default; | ||
} | } | ||
} | } |
Revision as of 21:03, 28 August 2007
Builder's Buddy
This is a repost of the current Builder's Buddy scripts, as originally released on the prior LSL wiki. There are two scripts; One goes in a "base" prim, which is the piece that is moved/rotated/etc. The component script goes into each linked set that makes up the rest of the large build. In short, only one base script, many component scripts. Got it?
Note to Sellers!
Due to a number of people confused by the copyright wording, here's a recap: Use this script any way you want. SELL IT EVEN! Just make sure I am given credit as the creator. That's the only restriction.
The Base Script
/////////////////////////////////////////////////////////////////////////////// // Builders' Buddy 1.8 (Base Script) // by Newfie Pendragon, March 2006 // // This script is distributed with permission that it may be used in // any way, or may be further modified/included in resale items. // HOWEVER, if this script is used as part of a for-sale product, // it is required that appropriate credit be given to Newfie for // the script (or portions used in derivatives). That's a fair price // in exchange for unlimited use of this script, dontcha think? // // SL Forum thread and new versions found here: // http://forums.secondlife.com/showthread.php?t=96792 /////////////////////////////////////////////////////////////////////////////// // // 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 // /////////////////////////////////////////////////////////////////////////////// // // History // // v1.0 - 20060328 - Newfie Pendragon // - Original Version // v1.1 - 20060331 - Kalidor Lazarno // - Added a Dialog Engine to the base script // v1.5 - 20060612 - Androclese Antonelli // - Added a random number generator to the dialog engine to elimintate // problems with multiple BB boxes cross-talking // - Added a timer to the listen command to put it asleep after 10sec. // - Added a Menu Description // - Added n "creator" flag so the owner could use the same object with full // menu options and only a single flag change // - Added an "ingroup" flag to enable/disable the same group use function // - Non-Admin usage cleans the inventory items as they spawn // v1.6 - 20060624 - Newfie Pendragon // - Added active repositioning (building moves as the base piece moves) // - Added "Reset" Option to unlink parts from base temporarily // - Modified creator flag to automatically set based if owner is creator // - Minor changes to improve code readability (for those learning LSL) // v1.8 - 20070429 - Newfie Pendragon // - Added a variable to allow a user to tweak how long a listener is open, // and changed the default to 30 seconds. /////////////////////////////////////////////////////////////////////////////// // User Variables /////////////////////////////////////////////////////////////////////////////// // 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; //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"; //Menu option descriptions string descRecord = " : Record the position of all parts\n"; string descReset = " : Forgets the position of all parts\n"; string descBuild = " : Spawn 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 make the parts permanent.\n"; //How long to listen for a menu response before shutting down the listener float fListenTime = 30.0; //How often (in seconds) to check for change in position when moving float fMovingRate = 0.25; //How long to sit still before exiting active mode float fStoppedTime = 30.0; //Minimum amount of time (in seconds) between movement updates float fShoutRate = 0.25; // 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 PRIMCHAN = -19730611; /////////////////////////////////////////////////////////////////////////////// // DO NOT EDIT BELOW THIS LINE.... NO.. NOT EVEN THEN /////////////////////////////////////////////////////////////////////////////// integer MENU_CHANNEL; integer MENU_HANDLE; key agent; key objectowner; integer group; string title = ""; list optionlist = []; integer bMoving; vector vLastPos; rotation rLastRot; integer iListenTimeout = 0; //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() { llShout(PRIMCHAN, "MOVE " + llDumpList2String([ llGetPos(), llGetRot() ], "|")); llResetTime(); //Reset our throttle vLastPos = llGetPos(); rLastRot = llGetRot(); return; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// default { /////////////////////////////////////////////////////////////////////////////// changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } /////////////////////////////////////////////////////////////////////////////// state_entry () { //Use which menu? if ( llGetCreator() == llGetOwner() ) { //Display all options optionlist = [optPos, optClean, optDone, optRecord, optReset, optBuild]; title = optRecord + descRecord; title += optReset + descReset; title += optBuild + descBuild; title += optPos + descPos; title += optClean + descClean; title += optDone + descDone; } else { //Display limited options optionlist = [optBuild, optPos, optDone]; title = optBuild + descBuild; title += optPos + descPos; title += optDone + descDone; } //Record our position vLastPos = llGetPos(); rLastRot = llGetRot(); } /////////////////////////////////////////////////////////////////////////////// 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)); MENU_HANDLE = llListen(MENU_CHANNEL,"","",""); llDialog(agent, title, optionlist, MENU_CHANNEL); llSetTimerEvent(fShoutRate); } } /////////////////////////////////////////////////////////////////////////////// listen(integer channel, string name, key id, string message) { if ( message == optRecord ) { llOwnerSay("Recording positions..."); llShout(PRIMCHAN, "RECORD " + llDumpList2String([ llGetPos(), llGetRot() ], "|")); return; } if( message == optReset ) { llOwnerSay("Forgetting positions..."); llShout(PRIMCHAN, "RESET"); return; } if ( message == optBuild ) { vector vThisPos = llGetPos(); rotation rThisRot = llGetRot(); integer i; integer iCount = llGetInventoryNumber(INVENTORY_OBJECT); //Loop through backwards (safety precaution in case of inventory change) llOwnerSay("Rezzing build pieces..."); for( i = iCount - 1; i >= 0; i-- ) { llRezObject(llGetInventoryName(INVENTORY_OBJECT, i), vThisPos, ZERO_VECTOR, rThisRot, PRIMCHAN); if ( llGetCreator() != llGetOwner() ) llRemoveInventory(llGetInventoryName(INVENTORY_OBJECT, i)); } llOwnerSay("Positioning"); llShout(PRIMCHAN, "MOVE " + llDumpList2String([ vThisPos, rThisRot ], "|")); return; } if ( message == optPos ) { llOwnerSay("Positioning"); vector vThisPos = llGetPos(); rotation rThisRot = llGetRot(); llShout(PRIMCHAN, "MOVE " + llDumpList2String([ vThisPos, rThisRot ], "|")); return; } if ( message == optClean ) { llShout(PRIMCHAN, "CLEAN"); return; } if ( message == optDone ) { llShout(PRIMCHAN, "DONE"); //llDie(); llOwnerSay("Removing mover scripts."); return; } } /////////////////////////////////////////////////////////////////////////////// moving_start() { if( !bMoving ) { bMoving = TRUE; llSetTimerEvent(0.0); //Resets the timer if already running llSetTimerEvent(fMovingRate); announce_moved(); } } /////////////////////////////////////////////////////////////////////////////// timer() { //Were we moving? if( bMoving ) { //Did we change position/rotation? if( (llGetRot() != rLastRot) || (llGetPos() != vLastPos) ) { if( llGetTime() > fShoutRate ) { announce_moved(); } } } else { //Have we been sitting long enough to consider ourselves stopped? if( llGetTime() > fStoppedTime ) bMoving = FALSE; } //Open listener? if( iListenTimeout != 0 ) { //Past our close timeout? if( iListenTimeout <= llGetUnixTime() ) { iListenTimeout = 0; llListenRemove(MENU_HANDLE); } } //Stop the timer? if( (iListenTimeout == 0) && ( !bMoving ) ) { llOwnerSay("Stopping Timer"); llSetTimerEvent(0.0); } } /////////////////////////////////////////////////////////////////////////////// on_rez(integer iStart) { //Reset ourselves llResetScript(); } }
The Component Script
/////////////////////////////////////////////////////////////////////////////// // Builders' Buddy 1.7 (Component Pieces) // // by Newfie Pendragon, March 2006 // // This script is distributed with permission that it may be used in // any way, or may be further modified/included in resale items. // HOWEVER, if this script is used as part of a for-sale product, // it is required that appropriate credit be given to Newfie for // the script (or portions used in derivatives). That's a fair price // in exchange for unlimited use of this script, dontcha think? // // SL Forum thread and new versions found here: // http://forums.secondlife.com/showthread.php?t=96792 /////////////////////////////////////////////////////////////////////////////// // INSTRUCTIONS // This is the *Component Piece* half of the Builders' Buddy system. // Drop it into each 'piece' of the building. Drop the Base Prim Script // into the prim that will be the container/box that will be used to // store the building once completed. It can be in each individual // prim, but if you link as much as possible (and put the script in the link // set), it'll be much more neighbourly and less strain on the sim. // // 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 // /////////////////////////////////////////////////////////////////////////////// // History // // v1.0 - 20060328 - Newfie Pendragon - Original Version // v1.5 - 20060612 - Androclese Antonelli // - (See base script for details) // v1.6 - 20060624 - Newfie Pendragon // - Added active repositioning (pieces move as the base piece moves) // - Pieces use WarpPos technique to instantanetly move large distances // - Pieces no longer move until the the "Record" option has been used // at least once // - Pieces will not move if base is not same owner as the pieces // - Pieces no longer 'bounce' when hitting the ground // v1.7 - 20060821 - Correction for non-zero rotation (thanks Ed44 Gupta!) /////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // Configurable Settings float fTimerInterval = 0.25; //Time in seconds between movement 'ticks' integer PRIMCHAN = -19730611; //Channel used by Base Prim to talk to Component Prims; // 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 bRecorded = FALSE; //////////////////////////////////////////////////////////////////////////////// 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 // the 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); } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// default { ////////////////////////////////////////////////////////////////////////////////////////// state_entry() { //Open up the listener llListen(PRIMCHAN, "", NULL_KEY, ""); } ////////////////////////////////////////////////////////////////////////////////////////// on_rez(integer iStart) { //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 == "RECORD" ) { sText = other_words(sText, " "); list lParams = llParseString2List(sText, [ "|" ], []); vector vBase = (vector)llList2String(lParams, 0); rotation rBase = (rotation)llList2String(lParams, 1); vOffset = (llGetPos() - vBase) / rBase; rRotation = llGetRot() / rBase; bRecorded = TRUE; llOwnerSay("Recorded position."); return; } ////////////////////////////////////////////////////////////////////////////////////////// if( sCmd == "MOVE" ) { //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 sText = other_words(sText, " "); list lParams = llParseString2List(sText, [ "|" ], []); vector vBase = (vector)llList2String(lParams, 0); rotation rBase = (rotation)llList2String(lParams, 1); //Calculate our destination position vDestPos = (vOffset * rBase) + vBase; rDestRot = rRotation * rBase; //Turn on our timer to perform the move? if( !bNeedMove ) { llSetTimerEvent(fTimerInterval); bNeedMove = TRUE; } return; } ////////////////////////////////////////////////////////////////////////////////////////// if( sCmd == "DONE" ) { //We are done, remove script 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(); bNeedMove = FALSE; } return; } } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// state reset_listeners { ////////////////////////////////////////////////////////////////////////////////////////// state_entry() { state default; } }