unpacked files
This commit is contained in:
21
TGLM/MENUITEMS.Test.txt
Normal file
21
TGLM/MENUITEMS.Test.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
// Single Person Animations
|
||||
|
||||
MENU Single | ALL | WHITE
|
||||
POSE Sleep Back | sleeping-onback
|
||||
POSE Sleep Front | sleeping-stomach
|
||||
POSE Breakfast | breakfastinbed
|
||||
POSE Read | read-a-book-onstomach
|
||||
POSE Meditate | meditate
|
||||
SWAP
|
||||
STOP
|
||||
BACK
|
||||
|
||||
MENU Cuddles | ALL | BLUE | PINK
|
||||
POSE Memories | makingmemories-m | makingmemories-f
|
||||
POSE Cuddle 03 | Cuddle 03M | Cuddle 03F
|
||||
POSE Cuddle 04 | Cuddle KM | Cuddle KF
|
||||
POSE Cuddle 05 | Cuddle LM | Cuddle LF
|
||||
SWAP
|
||||
STOP
|
||||
BACK
|
||||
74
TGLM/MENUITEMS.txt
Normal file
74
TGLM/MENUITEMS.txt
Normal file
@@ -0,0 +1,74 @@
|
||||
POSE stand | stand | stand | stand //pose before starting and when stopping
|
||||
POSE default | sit_ground | sit_ground | sit_ground //default pose when no animation entered
|
||||
|
||||
MENUORDER // use new (sane) menu button order -- same as in files. Omit this for WELM compatibility.
|
||||
// NORELOAD // inhibit reload on rez -- use for worn item, but "Menu Reset" if you make a copy!
|
||||
|
||||
|
||||
MENU MAIN MENU | ALL
|
||||
|
||||
// link-message button. LINKMSG buttonname | parms
|
||||
// where parms is a comma-separated list: menu,primnum,lm-num-arg,lm-str-arg
|
||||
// menu is 1 if the LM will cause a menu, or 0 if not (to avoid menu stacking if remenu is on).
|
||||
// primnum is the primitive number (see llMessageLinked() docs)
|
||||
// lm-num-arg is the 'num' arg in the LM. If sending to same prim as WELM, avoid -100 to 100 range.
|
||||
// lm-str-arg is the 'str' arg in the LM
|
||||
// The menu user's key is passed as the LM 'key' arg.
|
||||
//
|
||||
// Example (commented out):
|
||||
// LINKMSG Show/Hide | 0,-4,-100,show-hide
|
||||
// -- inhibits remenu and calls llMessageLinked(-4, 100, "textures", toucherKey)
|
||||
|
||||
TOMENU - // 10 (total) blank spaces for modular configs. Unused entries are automatically deleted.
|
||||
TOMENU -
|
||||
TOMENU -
|
||||
TOMENU -
|
||||
TOMENU -
|
||||
TOMENU -
|
||||
TOMENU -
|
||||
TOMENU -
|
||||
TOMENU -
|
||||
TOMENU -
|
||||
STOP //remove poseballs
|
||||
TOMENU OPTIONS // options menu
|
||||
|
||||
|
||||
MENU OPTIONS | OWNER //this menu can be accessed by the OWNER only (other options: GROUP / ALL)
|
||||
|
||||
BALLUSERS BallUsers | ALL //switches who can sit on the poseballs: ALL/GROUP (set default)
|
||||
MENUUSERS MenuUsers | ALL //switches who access main menu: ALL/GROUP/OWNER (set default)
|
||||
|
||||
ADJUST Adjust Pos //changes poseballs into transparant beams easy to select for moving
|
||||
DUMP Dump Pos //lists all positions stored in memory, copy/paste into .POSITIONS for backup
|
||||
SAVE Save Pos //saves the poseball positions of the currently selected pose into memory
|
||||
|
||||
TOMENU Height
|
||||
LINKMSG Dump Props | 0,-4,1,DUMPPROPS // dump all prop configs
|
||||
LINKMSG Save Prop | 0,-4,1,SAVEPROP // save position/rotation for a prop
|
||||
|
||||
CHAT Chat Info | ON //switches chat info: ON/OFF (set default)
|
||||
TOMENU ShutDown...
|
||||
BACK
|
||||
|
||||
//REDO RedoMenu | ON //switches if menu reappears automatically: ON/OFF (set default)
|
||||
//INVISIBLE Invisible //make the main object invisible/visible (usefull if it's worn)
|
||||
//SHOW //put this in some menu in case you want an option to show/hide the balls
|
||||
//HIDE //(usually not needed, as the balls are created and removed in a click)
|
||||
|
||||
MENU Height | OWNER
|
||||
Z+1 //adjust Z = height offset in cm - use any integer to set the step size
|
||||
Z+5 // (note: the Z-buttons are deactivated for other users)
|
||||
Z+25
|
||||
Z-1
|
||||
Z-5
|
||||
Z-25
|
||||
BACK
|
||||
|
||||
|
||||
MENU ShutDown... | OWNER
|
||||
RELOAD Pos Reset // use after changing *.POSITIONS* or *.PROPS* files
|
||||
RESTART Restart // solves any problem but stack/heap collision (tools->reset scripts for that)
|
||||
CHECK ConfigCheck // check config consistency. NOTE: does a Pos Reset when done!
|
||||
RESET Menu Reset // use after changing *.MENUITEMS* files
|
||||
OFF ShutDown! //(note: only the owner can Shutdown/Startup, even if menu set to ALL)
|
||||
BACK
|
||||
9
TGLM/POSITIONS.txt
Normal file
9
TGLM/POSITIONS.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
{Sleep Back} <-0.445,1.354,0.629> <-4.8,0.2,176.6>
|
||||
{Sleep Front} <-0.282,1.373,0.632> <0.0,0.0,178.0>
|
||||
{Breakfast} <-0.786,2.144,0.675> <-4.2,-7.0,-92.0>
|
||||
{Read} <-0.820,1.179,0.537> <0.0,0.0,178.0>
|
||||
{Meditate} <-0.783,2.230,0.561> <-14.1,-7.7,-62.0>
|
||||
{Memories} <0.697,1.242,0.723> <-2.4,16.1,177.9> <-0.076,1.240,0.706> <-1.8,5.7,178.0>
|
||||
{Cuddle 03} <-0.783,2.230,0.467> <-14.1,-7.7,-62.0> <0.783,2.357,0.439> <-17.9,6.4,-109.0>
|
||||
{Cuddle 04} <-0.783,2.230,0.467> <-14.1,-7.7,-62.0> <0.783,2.357,0.439> <-17.9,6.4,-109.0>
|
||||
{Cuddle 05} <-0.783,2.230,0.467> <-14.1,-7.7,-62.0> <0.783,2.357,0.439> <-17.9,6.4,-109.0>
|
||||
358
TGLM/memory.lsl
Normal file
358
TGLM/memory.lsl
Normal file
@@ -0,0 +1,358 @@
|
||||
//MPLV2 Version 2.2 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
// v2.2 - rotate all poses, cleaner dump
|
||||
|
||||
integer Checking = FALSE; // whether doing consistency check
|
||||
|
||||
integer line;
|
||||
integer PosCount;
|
||||
list Poses; // list of pose names
|
||||
|
||||
// indexed by same index as Poses, entry contains text string of pos/rot pairs, one for each ball in pose
|
||||
|
||||
// list Positions;
|
||||
|
||||
list Positions0;
|
||||
list Positions1;
|
||||
list Positions2;
|
||||
list Positions3;
|
||||
|
||||
|
||||
vector Pos1;
|
||||
vector Pos2;
|
||||
vector Pos3;
|
||||
vector Pos4;
|
||||
vector Pos5;
|
||||
vector Pos6;
|
||||
vector Rot1;
|
||||
vector Rot2;
|
||||
vector Rot3;
|
||||
vector Rot4;
|
||||
vector Rot5;
|
||||
vector Rot6;
|
||||
integer Ballcount;
|
||||
|
||||
announce()
|
||||
{
|
||||
llOwnerSay((string)PosCount
|
||||
+ " positions stored ("
|
||||
+ llGetScriptName()
|
||||
+ ": "
|
||||
+ (string)llGetFreeMemory()
|
||||
+ " bytes free)");
|
||||
}
|
||||
|
||||
getPosePos(string pdata) {
|
||||
list plist = llParseString2List(pdata,[" "],[]);
|
||||
|
||||
Ballcount = llGetListLength(plist) / 2;
|
||||
|
||||
Pos1 = (vector)llList2String(plist, 0);
|
||||
Rot1 = (vector)llList2String(plist, 1);
|
||||
Pos2 = (vector)llList2String(plist, 2);
|
||||
Rot2 = (vector)llList2String(plist, 3);
|
||||
Pos3 = (vector)llList2String(plist, 4);
|
||||
Rot3 = (vector)llList2String(plist, 5);
|
||||
Pos4 = (vector)llList2String(plist, 6);
|
||||
Rot4 = (vector)llList2String(plist, 7);
|
||||
Pos5 = (vector)llList2String(plist, 8);
|
||||
Rot5 = (vector)llList2String(plist, 8);
|
||||
Pos6 = (vector)llList2String(plist, 10);
|
||||
Rot6 = (vector)llList2String(plist, 11);
|
||||
}
|
||||
|
||||
|
||||
string adjust(integer doOffset, vector pos, vector erot, vector amt) {
|
||||
if (doOffset) {
|
||||
pos += amt/100.;
|
||||
return (vround(pos) + " " + vround(erot));
|
||||
}
|
||||
|
||||
rotation amount = llEuler2Rot(amt * DEG_TO_RAD);
|
||||
erot *= DEG_TO_RAD;
|
||||
|
||||
rotation oldrot = llEuler2Rot(erot);
|
||||
rotation newrot = oldrot / amount;
|
||||
|
||||
erot = llRot2Euler(newrot) * RAD_TO_DEG;
|
||||
pos = pos / amount;
|
||||
return(vround(pos) + " " + vround(erot));
|
||||
}
|
||||
|
||||
adjust_all(integer doOffset, vector amt) {
|
||||
integer ix;
|
||||
integer bx;
|
||||
string data;
|
||||
for (ix = 0; ix < PosCount; ++ix) {
|
||||
data = get_pose_by_index(ix);
|
||||
getPosePos(data);
|
||||
|
||||
list parms = [ Pos1, Rot1, Pos2, Rot2, Pos3, Rot3, Pos4, Rot4, Pos5, Rot5, Pos6, Rot6 ];
|
||||
|
||||
data = adjust(doOffset, Pos1, Rot1, amt);
|
||||
integer ballix = 1;
|
||||
while (ballix < Ballcount) {
|
||||
string stuff = adjust(doOffset, llList2Vector(parms, 2*ballix), llList2Vector(parms, 2*ballix+1), amt);
|
||||
data += " " + stuff;
|
||||
++ballix;
|
||||
}
|
||||
store_pose(data, ix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string get_pose_data(string name) {
|
||||
integer ix = llListFindList(Poses, [name]);
|
||||
|
||||
// if not found, use default positions
|
||||
if (ix == -1) {
|
||||
ix = 0;
|
||||
}
|
||||
|
||||
return (get_pose_by_index(ix));
|
||||
}
|
||||
|
||||
|
||||
string get_pose_by_index(integer ix) {
|
||||
if ((ix & 3) == 0) {
|
||||
return llList2String(Positions0, ix>>2);
|
||||
} else if ((ix & 3) == 1) {
|
||||
return llList2String(Positions1, ix>>2);
|
||||
} else if ((ix & 3) == 2) {
|
||||
return llList2String(Positions2, ix>>2);
|
||||
}
|
||||
return llList2String(Positions3, ix>>2);
|
||||
}
|
||||
|
||||
store_pose(string data, integer ix) {
|
||||
if ((ix & 3) == 0) {
|
||||
Positions0 = llListReplaceList(Positions0,[ data ],ix>>2,ix>>2);
|
||||
} else if ((ix & 3) == 1) {
|
||||
Positions1 = llListReplaceList(Positions1,[ data ],ix>>2,ix>>2);
|
||||
} else if ((ix & 3) == 2) {
|
||||
Positions2 = llListReplaceList(Positions2,[ data ],ix>>2,ix>>2);
|
||||
} else if ((ix & 3) == 3) {
|
||||
Positions3 = llListReplaceList(Positions3,[ data ],ix>>2,ix>>2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
save_pose(string name, string data) {
|
||||
integer ix = llListFindList(Poses, [name]);
|
||||
if (ix == -1) {
|
||||
add_pose(name, data);
|
||||
} else {
|
||||
store_pose(data, ix);
|
||||
}
|
||||
}
|
||||
|
||||
add_pose(string name, string data) {
|
||||
integer ix = llListFindList(Poses, (list)name);
|
||||
if (ix != -1) {
|
||||
llOwnerSay("===> WARNING: Multiple .POSITIONS* entries for '" + name + "'");
|
||||
} else {
|
||||
Poses = [] + Poses + (list) name;
|
||||
ix = ++PosCount;
|
||||
}
|
||||
store_pose(data, ix-1);
|
||||
}
|
||||
|
||||
check_pose(string name) {
|
||||
integer ix;
|
||||
|
||||
// if this is the last pose, report results
|
||||
if (name == "CHECK2") {
|
||||
string name1;
|
||||
for (ix = 0; ix < llGetListLength(Poses); ++ix) {
|
||||
name1 = llList2String(Poses, ix);
|
||||
if (get_pose_data(name1) != "") {
|
||||
if (name1 != "default" && name1 != "stand") {
|
||||
llOwnerSay("No .MENUITEMS* entry for '" + name1 + "'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
llOwnerSay("Checks complete, resetting.");
|
||||
llResetScript();
|
||||
}
|
||||
|
||||
ix = llListFindList(Poses, [name]);
|
||||
if (ix == -1) {
|
||||
llOwnerSay("No .POSITIONS* entry for '" + name + "'.");
|
||||
return;
|
||||
}
|
||||
save_pose(name, "");
|
||||
}
|
||||
|
||||
|
||||
string vround(vector vec) {
|
||||
return ("<"+round(vec.x, 3)+","+round(vec.y, 3)+","+round(vec.z, 3)+">");
|
||||
}
|
||||
|
||||
string round(float number, integer places) {
|
||||
float shifted;
|
||||
integer rounded;
|
||||
string s;
|
||||
shifted = number * llPow(10.0,(float)places);
|
||||
rounded = llRound(shifted);
|
||||
s = (string)((float)rounded / llPow(10.0,(float)places));
|
||||
s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
|
||||
return s;
|
||||
}
|
||||
|
||||
dashes() {
|
||||
llOwnerSay("_______________________________________________________________________________");
|
||||
llOwnerSay("");
|
||||
}
|
||||
|
||||
|
||||
// Globals for reading card config
|
||||
integer ConfigLineIndex;
|
||||
list ConfigCards; // list of names of config cards
|
||||
string ConfigCardName; // name of card being read
|
||||
integer ConfigCardIndex; // index of next card to read
|
||||
key ConfigQueryId;
|
||||
|
||||
integer next_card()
|
||||
{
|
||||
if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
|
||||
ConfigCards = [];
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
ConfigLineIndex = 0;
|
||||
ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
|
||||
ConfigCardIndex++;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
|
||||
llOwnerSay("Reading " + ConfigCardName);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
string item;
|
||||
ConfigCards = [];
|
||||
integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
|
||||
while (n-- > 0) {
|
||||
item = llGetInventoryName(INVENTORY_NOTECARD, n);
|
||||
if (llSubStringIndex(item, ".POSITIONS") != -1) {
|
||||
ConfigCards = [] + ConfigCards + (list) item;
|
||||
}
|
||||
}
|
||||
|
||||
ConfigCardIndex = 0;
|
||||
ConfigCards = llListSort(ConfigCards, 1, TRUE);
|
||||
next_card();
|
||||
}
|
||||
|
||||
dataserver(key query_id, string data) {
|
||||
if (query_id != ConfigQueryId) {
|
||||
return;
|
||||
}
|
||||
if (data == EOF) {
|
||||
if (next_card()) {
|
||||
return;
|
||||
}
|
||||
state on;
|
||||
}
|
||||
if (llGetSubString(data,0,0) != "/") { // skip comments
|
||||
integer ix = llSubStringIndex(data, "{"); //split name from positions, remove junk
|
||||
integer jx = llSubStringIndex(data, "} <");
|
||||
if (ix != -1 && jx != -1) {
|
||||
add_pose(llGetSubString(data, ix+1, jx-1), llGetSubString(data, jx+2, -1));
|
||||
}
|
||||
}
|
||||
++ConfigLineIndex;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of positions notecard
|
||||
}
|
||||
|
||||
state_exit() {
|
||||
if (PosCount < 1) {
|
||||
add_pose("stand", "<-0.7,0.0,0.9> <0.0,0.0,0.0> <0.7,0.0,0.9> <0.0,0.0,-180.0>");
|
||||
}
|
||||
if (PosCount < 2) {
|
||||
add_pose("default", "<-0.7,0.0,0.7> <0.0,0.0,0.0> <0.7,0.0,0.7> <0.0,0.0,-180.0>");
|
||||
}
|
||||
|
||||
// do one save to indicate actual amount of available memory
|
||||
string position = llList2String(Positions1, 0);
|
||||
Positions1 = llListReplaceList(Positions1, [position],0,0);
|
||||
|
||||
if (llGetInventoryType("~props") == INVENTORY_SCRIPT) {
|
||||
llSetScriptState("~props", TRUE);
|
||||
llResetOtherScript("~props");
|
||||
llSleep(1.0); // give props a chance to run -- doesn't really matter if not enough
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
state on {
|
||||
state_entry() {
|
||||
llMessageLinked(LINK_THIS, 2, "OK", (key)""); //msg to menu, in case it's waiting for loading
|
||||
announce();
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string str, key dkey) {
|
||||
if (str == "PRIMTOUCH" || num < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == 0 && str == "POSEB") {
|
||||
string name = (string)dkey;
|
||||
if (name == "CHECK1") {
|
||||
Checking = TRUE;
|
||||
} else if (Checking) {
|
||||
check_pose((string)dkey);
|
||||
} else {
|
||||
llMessageLinked(LINK_THIS, 0, "POSEPOS", (key)get_pose_data((string)dkey)); // to ~pos
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (str == "OK?") { //question from menu, before loading menu
|
||||
llMessageLinked(from, 2, "OK", (key)""); //answer to menu
|
||||
} else if (str == "DUMP") {
|
||||
dashes();
|
||||
llOwnerSay("Copy to .POSITIONS; delete any other *.POSITIONS* cards");
|
||||
dashes();
|
||||
string name1 = llGetObjectName();
|
||||
llSetObjectName("");
|
||||
|
||||
integer ix;
|
||||
for (ix = 0; ix < PosCount; ++ix) {
|
||||
string name2 = llList2String(Poses, ix);
|
||||
llOwnerSay("{" + name2 + "} " + get_pose_data(name2));
|
||||
}
|
||||
|
||||
llSetObjectName(name1);
|
||||
dashes();
|
||||
} else if (llSubStringIndex(str, "REORIENT=") == 0) {
|
||||
// Reorient command (LINKMENU command from .MENUITEMS file)
|
||||
// str format: REORIENT=OFF=<x,y,z> or REORIENT=ROT=<x,y,z> (in degrees)
|
||||
list parms = llParseString2List(str, ["="], []);
|
||||
vector amount = (vector)llList2String(parms, 2);
|
||||
llWhisper(0, "Adjusting Poses, please wait");
|
||||
|
||||
if (llList2String(parms, 1) == "OFF") {
|
||||
adjust_all(TRUE, amount);
|
||||
} else {
|
||||
adjust_all(FALSE, amount);
|
||||
}
|
||||
llMessageLinked(LINK_THIS, 0, "AGAIN", (key)"");
|
||||
llWhisper(0, "Pose adjustment complete");
|
||||
} else {
|
||||
if (llGetSubString((string)dkey, 0, 0) == "<") { //SAVE
|
||||
save_pose(str, (string)dkey);
|
||||
announce();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
47
TGLM/~MLPT-AutoZhao.lsl
Normal file
47
TGLM/~MLPT-AutoZhao.lsl
Normal file
@@ -0,0 +1,47 @@
|
||||
// MLPV2.2 Add-On example.
|
||||
// Use a script like this to support xcite, chains, etc.
|
||||
// This one supports AutoZhao, whic h is a ZHAO variant that turns off
|
||||
// automatically when you sit.
|
||||
|
||||
// LM parameters:
|
||||
//
|
||||
// num = 0 and msg = "POSEB": new pose
|
||||
// id = is pose name
|
||||
//
|
||||
// num = -11000: avatar sits
|
||||
// msg = ball number (0,1,...), as a string
|
||||
// id = avatar who
|
||||
//
|
||||
// num = -11001: avatar unsits
|
||||
// msg = ball number (0,1,...), as a string
|
||||
// id = avatar who
|
||||
|
||||
integer AutoZhaoChan = -4200;
|
||||
|
||||
string Pose;
|
||||
string Avname;
|
||||
key Avkey;
|
||||
|
||||
default
|
||||
{
|
||||
link_message(integer from, integer num, string msg, key id) {
|
||||
if (msg == "POSEB") {
|
||||
Pose = (string)msg;
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == -11000) {
|
||||
// av hopped on, so turn ZHAO off
|
||||
llWhisper(AutoZhaoChan, "ZHAO_AOOFF");
|
||||
Avkey = id;
|
||||
Avname = llKey2Name(id);
|
||||
} else if (num == -11001) {
|
||||
// av hopped off, so turn ZHAO on
|
||||
llWhisper(AutoZhaoChan, "ZHAO_AOON");
|
||||
Avkey = NULL_KEY;
|
||||
Avname = "";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
358
TGLM/~memory.lsl
Normal file
358
TGLM/~memory.lsl
Normal file
@@ -0,0 +1,358 @@
|
||||
//MPLV2 Version 2.2 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
// v2.2 - rotate all poses, cleaner dump
|
||||
|
||||
integer Checking = FALSE; // whether doing consistency check
|
||||
|
||||
integer line;
|
||||
integer PosCount;
|
||||
list Poses; // list of pose names
|
||||
|
||||
// indexed by same index as Poses, entry contains text string of pos/rot pairs, one for each ball in pose
|
||||
|
||||
// list Positions;
|
||||
|
||||
list Positions0;
|
||||
list Positions1;
|
||||
list Positions2;
|
||||
list Positions3;
|
||||
|
||||
|
||||
vector Pos1;
|
||||
vector Pos2;
|
||||
vector Pos3;
|
||||
vector Pos4;
|
||||
vector Pos5;
|
||||
vector Pos6;
|
||||
vector Rot1;
|
||||
vector Rot2;
|
||||
vector Rot3;
|
||||
vector Rot4;
|
||||
vector Rot5;
|
||||
vector Rot6;
|
||||
integer Ballcount;
|
||||
|
||||
announce()
|
||||
{
|
||||
llOwnerSay((string)PosCount
|
||||
+ " positions stored ("
|
||||
+ llGetScriptName()
|
||||
+ ": "
|
||||
+ (string)llGetFreeMemory()
|
||||
+ " bytes free)");
|
||||
}
|
||||
|
||||
getPosePos(string pdata) {
|
||||
list plist = llParseString2List(pdata,[" "],[]);
|
||||
|
||||
Ballcount = llGetListLength(plist) / 2;
|
||||
|
||||
Pos1 = (vector)llList2String(plist, 0);
|
||||
Rot1 = (vector)llList2String(plist, 1);
|
||||
Pos2 = (vector)llList2String(plist, 2);
|
||||
Rot2 = (vector)llList2String(plist, 3);
|
||||
Pos3 = (vector)llList2String(plist, 4);
|
||||
Rot3 = (vector)llList2String(plist, 5);
|
||||
Pos4 = (vector)llList2String(plist, 6);
|
||||
Rot4 = (vector)llList2String(plist, 7);
|
||||
Pos5 = (vector)llList2String(plist, 8);
|
||||
Rot5 = (vector)llList2String(plist, 8);
|
||||
Pos6 = (vector)llList2String(plist, 10);
|
||||
Rot6 = (vector)llList2String(plist, 11);
|
||||
}
|
||||
|
||||
|
||||
string adjust(integer doOffset, vector pos, vector erot, vector amt) {
|
||||
if (doOffset) {
|
||||
pos += amt/100.;
|
||||
return (vround(pos) + " " + vround(erot));
|
||||
}
|
||||
|
||||
rotation amount = llEuler2Rot(amt * DEG_TO_RAD);
|
||||
erot *= DEG_TO_RAD;
|
||||
|
||||
rotation oldrot = llEuler2Rot(erot);
|
||||
rotation newrot = oldrot / amount;
|
||||
|
||||
erot = llRot2Euler(newrot) * RAD_TO_DEG;
|
||||
pos = pos / amount;
|
||||
return(vround(pos) + " " + vround(erot));
|
||||
}
|
||||
|
||||
adjust_all(integer doOffset, vector amt) {
|
||||
integer ix;
|
||||
integer bx;
|
||||
string data;
|
||||
for (ix = 0; ix < PosCount; ++ix) {
|
||||
data = get_pose_by_index(ix);
|
||||
getPosePos(data);
|
||||
|
||||
list parms = [ Pos1, Rot1, Pos2, Rot2, Pos3, Rot3, Pos4, Rot4, Pos5, Rot5, Pos6, Rot6 ];
|
||||
|
||||
data = adjust(doOffset, Pos1, Rot1, amt);
|
||||
integer ballix = 1;
|
||||
while (ballix < Ballcount) {
|
||||
string stuff = adjust(doOffset, llList2Vector(parms, 2*ballix), llList2Vector(parms, 2*ballix+1), amt);
|
||||
data += " " + stuff;
|
||||
++ballix;
|
||||
}
|
||||
store_pose(data, ix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string get_pose_data(string name) {
|
||||
integer ix = llListFindList(Poses, [name]);
|
||||
|
||||
// if not found, use default positions
|
||||
if (ix == -1) {
|
||||
ix = 0;
|
||||
}
|
||||
|
||||
return (get_pose_by_index(ix));
|
||||
}
|
||||
|
||||
|
||||
string get_pose_by_index(integer ix) {
|
||||
if ((ix & 3) == 0) {
|
||||
return llList2String(Positions0, ix>>2);
|
||||
} else if ((ix & 3) == 1) {
|
||||
return llList2String(Positions1, ix>>2);
|
||||
} else if ((ix & 3) == 2) {
|
||||
return llList2String(Positions2, ix>>2);
|
||||
}
|
||||
return llList2String(Positions3, ix>>2);
|
||||
}
|
||||
|
||||
store_pose(string data, integer ix) {
|
||||
if ((ix & 3) == 0) {
|
||||
Positions0 = llListReplaceList(Positions0,[ data ],ix>>2,ix>>2);
|
||||
} else if ((ix & 3) == 1) {
|
||||
Positions1 = llListReplaceList(Positions1,[ data ],ix>>2,ix>>2);
|
||||
} else if ((ix & 3) == 2) {
|
||||
Positions2 = llListReplaceList(Positions2,[ data ],ix>>2,ix>>2);
|
||||
} else if ((ix & 3) == 3) {
|
||||
Positions3 = llListReplaceList(Positions3,[ data ],ix>>2,ix>>2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
save_pose(string name, string data) {
|
||||
integer ix = llListFindList(Poses, [name]);
|
||||
if (ix == -1) {
|
||||
add_pose(name, data);
|
||||
} else {
|
||||
store_pose(data, ix);
|
||||
}
|
||||
}
|
||||
|
||||
add_pose(string name, string data) {
|
||||
integer ix = llListFindList(Poses, (list)name);
|
||||
if (ix != -1) {
|
||||
llOwnerSay("===> WARNING: Multiple .POSITIONS* entries for '" + name + "'");
|
||||
} else {
|
||||
Poses = [] + Poses + (list) name;
|
||||
ix = ++PosCount;
|
||||
}
|
||||
store_pose(data, ix-1);
|
||||
}
|
||||
|
||||
check_pose(string name) {
|
||||
integer ix;
|
||||
|
||||
// if this is the last pose, report results
|
||||
if (name == "CHECK2") {
|
||||
string name1;
|
||||
for (ix = 0; ix < llGetListLength(Poses); ++ix) {
|
||||
name1 = llList2String(Poses, ix);
|
||||
if (get_pose_data(name1) != "") {
|
||||
if (name1 != "default" && name1 != "stand") {
|
||||
llOwnerSay("No .MENUITEMS* entry for '" + name1 + "'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
llOwnerSay("Checks complete, resetting.");
|
||||
llResetScript();
|
||||
}
|
||||
|
||||
ix = llListFindList(Poses, [name]);
|
||||
if (ix == -1) {
|
||||
llOwnerSay("No .POSITIONS* entry for '" + name + "'.");
|
||||
return;
|
||||
}
|
||||
save_pose(name, "");
|
||||
}
|
||||
|
||||
|
||||
string vround(vector vec) {
|
||||
return ("<"+round(vec.x, 3)+","+round(vec.y, 3)+","+round(vec.z, 3)+">");
|
||||
}
|
||||
|
||||
string round(float number, integer places) {
|
||||
float shifted;
|
||||
integer rounded;
|
||||
string s;
|
||||
shifted = number * llPow(10.0,(float)places);
|
||||
rounded = llRound(shifted);
|
||||
s = (string)((float)rounded / llPow(10.0,(float)places));
|
||||
s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
|
||||
return s;
|
||||
}
|
||||
|
||||
dashes() {
|
||||
llOwnerSay("_______________________________________________________________________________");
|
||||
llOwnerSay("");
|
||||
}
|
||||
|
||||
|
||||
// Globals for reading card config
|
||||
integer ConfigLineIndex;
|
||||
list ConfigCards; // list of names of config cards
|
||||
string ConfigCardName; // name of card being read
|
||||
integer ConfigCardIndex; // index of next card to read
|
||||
key ConfigQueryId;
|
||||
|
||||
integer next_card()
|
||||
{
|
||||
if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
|
||||
ConfigCards = [];
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
ConfigLineIndex = 0;
|
||||
ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
|
||||
ConfigCardIndex++;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
|
||||
llOwnerSay("Reading " + ConfigCardName);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
string item;
|
||||
ConfigCards = [];
|
||||
integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
|
||||
while (n-- > 0) {
|
||||
item = llGetInventoryName(INVENTORY_NOTECARD, n);
|
||||
if (llSubStringIndex(item, ".POSITIONS") != -1) {
|
||||
ConfigCards = [] + ConfigCards + (list) item;
|
||||
}
|
||||
}
|
||||
|
||||
ConfigCardIndex = 0;
|
||||
ConfigCards = llListSort(ConfigCards, 1, TRUE);
|
||||
next_card();
|
||||
}
|
||||
|
||||
dataserver(key query_id, string data) {
|
||||
if (query_id != ConfigQueryId) {
|
||||
return;
|
||||
}
|
||||
if (data == EOF) {
|
||||
if (next_card()) {
|
||||
return;
|
||||
}
|
||||
state on;
|
||||
}
|
||||
if (llGetSubString(data,0,0) != "/") { // skip comments
|
||||
integer ix = llSubStringIndex(data, "{"); //split name from positions, remove junk
|
||||
integer jx = llSubStringIndex(data, "} <");
|
||||
if (ix != -1 && jx != -1) {
|
||||
add_pose(llGetSubString(data, ix+1, jx-1), llGetSubString(data, jx+2, -1));
|
||||
}
|
||||
}
|
||||
++ConfigLineIndex;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of positions notecard
|
||||
}
|
||||
|
||||
state_exit() {
|
||||
if (PosCount < 1) {
|
||||
add_pose("stand", "<-0.7,0.0,0.9> <0.0,0.0,0.0> <0.7,0.0,0.9> <0.0,0.0,-180.0>");
|
||||
}
|
||||
if (PosCount < 2) {
|
||||
add_pose("default", "<-0.7,0.0,0.7> <0.0,0.0,0.0> <0.7,0.0,0.7> <0.0,0.0,-180.0>");
|
||||
}
|
||||
|
||||
// do one save to indicate actual amount of available memory
|
||||
string position = llList2String(Positions1, 0);
|
||||
Positions1 = llListReplaceList(Positions1, [position],0,0);
|
||||
|
||||
if (llGetInventoryType("~props") == INVENTORY_SCRIPT) {
|
||||
llSetScriptState("~props", TRUE);
|
||||
llResetOtherScript("~props");
|
||||
llSleep(1.0); // give props a chance to run -- doesn't really matter if not enough
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
state on {
|
||||
state_entry() {
|
||||
llMessageLinked(LINK_THIS, 2, "OK", (key)""); //msg to menu, in case it's waiting for loading
|
||||
announce();
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string str, key dkey) {
|
||||
if (str == "PRIMTOUCH" || num < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == 0 && str == "POSEB") {
|
||||
string name = (string)dkey;
|
||||
if (name == "CHECK1") {
|
||||
Checking = TRUE;
|
||||
} else if (Checking) {
|
||||
check_pose((string)dkey);
|
||||
} else {
|
||||
llMessageLinked(LINK_THIS, 0, "POSEPOS", (key)get_pose_data((string)dkey)); // to ~pos
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (str == "OK?") { //question from menu, before loading menu
|
||||
llMessageLinked(from, 2, "OK", (key)""); //answer to menu
|
||||
} else if (str == "DUMP") {
|
||||
dashes();
|
||||
llOwnerSay("Copy to .POSITIONS; delete any other *.POSITIONS* cards");
|
||||
dashes();
|
||||
string name1 = llGetObjectName();
|
||||
llSetObjectName("");
|
||||
|
||||
integer ix;
|
||||
for (ix = 0; ix < PosCount; ++ix) {
|
||||
string name2 = llList2String(Poses, ix);
|
||||
llOwnerSay("{" + name2 + "} " + get_pose_data(name2));
|
||||
}
|
||||
|
||||
llSetObjectName(name1);
|
||||
dashes();
|
||||
} else if (llSubStringIndex(str, "REORIENT=") == 0) {
|
||||
// Reorient command (LINKMENU command from .MENUITEMS file)
|
||||
// str format: REORIENT=OFF=<x,y,z> or REORIENT=ROT=<x,y,z> (in degrees)
|
||||
list parms = llParseString2List(str, ["="], []);
|
||||
vector amount = (vector)llList2String(parms, 2);
|
||||
llWhisper(0, "Adjusting Poses, please wait");
|
||||
|
||||
if (llList2String(parms, 1) == "OFF") {
|
||||
adjust_all(TRUE, amount);
|
||||
} else {
|
||||
adjust_all(FALSE, amount);
|
||||
}
|
||||
llMessageLinked(LINK_THIS, 0, "AGAIN", (key)"");
|
||||
llWhisper(0, "Pose adjustment complete");
|
||||
} else {
|
||||
if (llGetSubString((string)dkey, 0, 0) == "<") { //SAVE
|
||||
save_pose(str, (string)dkey);
|
||||
announce();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
511
TGLM/~menu.lsl
Normal file
511
TGLM/~menu.lsl
Normal file
@@ -0,0 +1,511 @@
|
||||
// MLPV2 Version 2.3, by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
// 15-color balls by Lizz Silverstar
|
||||
|
||||
// 2.3: sequences
|
||||
// 6 avs
|
||||
// Adjusting state
|
||||
|
||||
integer MAX_BALLS = 6;
|
||||
|
||||
string Version = "WELM v1.0";
|
||||
|
||||
integer b;
|
||||
integer b0;
|
||||
integer ballusers;
|
||||
list BallColors;
|
||||
integer ch;
|
||||
integer chat = 1;
|
||||
integer group;
|
||||
integer i;
|
||||
integer menu;
|
||||
integer menuusers;
|
||||
integer redo = 1;
|
||||
integer swap;
|
||||
integer visible;
|
||||
integer BallCount;
|
||||
integer SaneMenuOrder;
|
||||
integer ReloadOnRez;
|
||||
|
||||
integer Adjusting;
|
||||
string LastPose;
|
||||
|
||||
integer BallsNeeded;
|
||||
|
||||
float alpha;
|
||||
string cmd;
|
||||
string pose;
|
||||
string Posemsg; // for 'AGAIN'
|
||||
key owner;
|
||||
key user;
|
||||
key user0;
|
||||
list buttons;
|
||||
list buttonindex;
|
||||
list commands;
|
||||
list menus;
|
||||
list balls;
|
||||
list users;
|
||||
|
||||
list SoundNames;
|
||||
list Sounds;
|
||||
list LMButtons;
|
||||
list LMParms;
|
||||
list MenuStack = [0]; // indices to previous menus, for "BACK" command
|
||||
|
||||
integer MenuPage; // which page of current menu we're on, 0 for first
|
||||
|
||||
stop() {
|
||||
sendStand(); //msg to pos/pose
|
||||
llMessageLinked(LINK_THIS, 1, "STOP", (key)"");
|
||||
llSleep(0.2);
|
||||
killBalls();
|
||||
swap = 0;
|
||||
Adjusting = FALSE;
|
||||
}
|
||||
|
||||
|
||||
check_poses() {
|
||||
llOwnerSay("Checking configs");
|
||||
llMessageLinked(LINK_THIS,0,"POSEB", (key)"CHECK1"); //msg to memory
|
||||
integer ix;
|
||||
string name;
|
||||
for (ix = 0; ix < llGetListLength(buttons); ++ix) {
|
||||
name = llList2String(buttons, ix);
|
||||
if (((integer)llList2String(commands, ix)) != 0) {
|
||||
llMessageLinked(LINK_THIS,0,"POSEB", (key)name); //msg to memory
|
||||
}
|
||||
}
|
||||
llMessageLinked(LINK_THIS,0,"POSEB", (key)"CHECK2"); //msg to memory
|
||||
}
|
||||
|
||||
// Return a channel number that's based on the prim's key -- unique per object
|
||||
integer channel() {
|
||||
return (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1));
|
||||
}
|
||||
|
||||
|
||||
// setup for a pose based on menu characteristics
|
||||
setup_pose() {
|
||||
if (BallsNeeded) { // if submenu includes balls:
|
||||
if (BallCount != BallsNeeded) {
|
||||
rezBalls(); // if not enough balls present: create balls
|
||||
llSleep(0.5);
|
||||
}
|
||||
integer ix;
|
||||
for (ix = 0; ix < BallsNeeded; ++ix) {
|
||||
llSay(ch + ix, llList2String(BallColors, ix) // to ball: color, ballnum, adjusting
|
||||
+ "|" + (string) ix
|
||||
+ "|" + (string) Adjusting);
|
||||
}
|
||||
if (ballusers) setBalls("GROUP"); //if group access only
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unauth(string button, string who) {
|
||||
llDialog(user0, "\n" + button + " button allowed only for " + who, ["OK"], -1);
|
||||
}
|
||||
|
||||
continMenu(string str) {
|
||||
llDialog(user0, "\n"+str+llKey2Name(user)+" is using the menu, continue?", ["Yes","Cancel"], ch - 1);
|
||||
}
|
||||
|
||||
mainMenu() {
|
||||
MenuPage = 0;
|
||||
menu = 0;
|
||||
doMenu(FALSE);
|
||||
}
|
||||
|
||||
//menu partly based on Menu Engine by Zonax Delorean (BSD License)
|
||||
//llDialog(user, menuname, buttons(from index to nextindex-1), channel)
|
||||
doMenu(integer inhibit_showing) {
|
||||
integer colors = llList2Integer(balls,menu);
|
||||
integer ix;
|
||||
integer mask = 0xf;
|
||||
integer shift = 0;
|
||||
BallsNeeded = 0;
|
||||
BallColors = [];
|
||||
for (ix = 0; ix < MAX_BALLS; ++ix) {
|
||||
integer bc = (colors & mask) >> ix*4;
|
||||
BallColors += (list)bc;
|
||||
if (bc) {
|
||||
BallsNeeded += 1;
|
||||
}
|
||||
mask = mask << 4;
|
||||
}
|
||||
|
||||
if (inhibit_showing) {
|
||||
return;
|
||||
}
|
||||
|
||||
b0 = llList2Integer(buttonindex, menu); //position of first butt on for this (sub)menu
|
||||
b = llList2Integer(buttonindex, menu+1); //position of first button for next (sub)menu
|
||||
|
||||
b0 += MenuPage * 12;
|
||||
if (b - b0 > 12) {
|
||||
b = b0 + 12;
|
||||
}
|
||||
|
||||
list buttons1 = llList2List(buttons, b0, b - 1);
|
||||
if (SaneMenuOrder) {
|
||||
buttons1 =
|
||||
llList2List(buttons1, -3, -1)
|
||||
+ llList2List(buttons1, -6, -4)
|
||||
+ llList2List(buttons1, -9, -7)
|
||||
+ llList2List(buttons1, -12, -10);
|
||||
}
|
||||
llDialog(user, Version + "\n\n" + llList2String(menus,menu), buttons1, ch - 1);
|
||||
llResetTime();
|
||||
}
|
||||
|
||||
say(string str) {
|
||||
if (menuusers) llWhisper(0,str);
|
||||
else llOwnerSay(str);
|
||||
}
|
||||
|
||||
killBalls() {
|
||||
integer ix;
|
||||
for (ix = 0; ix < MAX_BALLS; ++ix) {
|
||||
llSay(ch + ix, "DIE"); //msg to balls
|
||||
}
|
||||
BallCount = 0;
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
setBalls(string cmd) {
|
||||
integer ix;
|
||||
for (ix = 0; ix < BallCount; ++ix) {
|
||||
llSay(ch + ix, cmd); //msg to balls
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rezBalls() {
|
||||
integer current = BallCount;
|
||||
|
||||
if (BallsNeeded == BallCount) return;
|
||||
|
||||
if (BallCount == 0) {
|
||||
killBalls(); // for reinitialization, if old balls are around
|
||||
}
|
||||
|
||||
while (BallCount > BallsNeeded) {
|
||||
--BallCount;
|
||||
llSay(ch + BallCount, "DIE");
|
||||
}
|
||||
|
||||
while (BallCount < BallsNeeded) {
|
||||
llRezObject("~ball",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,ch+BallCount);
|
||||
++BallCount;
|
||||
}
|
||||
|
||||
// Only do this if there were no balls
|
||||
if (! current) {
|
||||
llMessageLinked(LINK_THIS,0,"REPOS",(key)""); //msg to pos
|
||||
}
|
||||
|
||||
llSetTimerEvent(60.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
sendStand() {
|
||||
llMessageLinked(LINK_THIS,0,"POSE","0,"+(string)BallCount); //msg to pos/pose
|
||||
llMessageLinked(LINK_THIS,0,"POSEB", "stand");
|
||||
}
|
||||
|
||||
touched(integer same_group) {
|
||||
if (user0 == owner || (menuusers == 1 && same_group) || menuusers == 2) { //0=owner 1=group 2=all
|
||||
if (user0 != user) {
|
||||
if (llGetTime() < 60.0 && user != (key)"") {
|
||||
continMenu("");
|
||||
return;
|
||||
}
|
||||
user = user0;
|
||||
group = same_group;
|
||||
}
|
||||
mainMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// return TRUE if caller should do menu
|
||||
integer handle_cmd(string button, integer sequenced) {
|
||||
b = llListFindList(buttons, (list) button); //find position of cmd
|
||||
string cmd = llList2String(commands,b); //get command
|
||||
|
||||
if (cmd == "TOMENU") {
|
||||
integer newmenu = llListFindList(menus,[ button ]); //find submenu
|
||||
if (newmenu == -1) return FALSE;
|
||||
if (sequenced) {
|
||||
integer oldmenu = menu;
|
||||
menu = newmenu;
|
||||
doMenu(TRUE);
|
||||
setup_pose();
|
||||
menu = oldmenu;
|
||||
return FALSE;
|
||||
}
|
||||
i = llList2Integer(users, newmenu);
|
||||
if (user == owner || (i == 1 && group) || i == 2) { //0=owner 1=group 2=all
|
||||
MenuStack = [] + (list)menu + MenuStack;
|
||||
MenuPage = 0;
|
||||
menu = newmenu;
|
||||
doMenu(sequenced);
|
||||
return FALSE;
|
||||
}
|
||||
if (i == 1) unauth(button, "group");
|
||||
else unauth(button, "owner");
|
||||
return FALSE;
|
||||
} else if (cmd == "BACK") {
|
||||
if (MenuPage) {
|
||||
--MenuPage;
|
||||
doMenu(sequenced);
|
||||
return FALSE;
|
||||
}
|
||||
menu = llList2Integer(MenuStack,0);
|
||||
MenuStack = llList2List(MenuStack,1,-1);
|
||||
doMenu(sequenced);
|
||||
return FALSE;
|
||||
} else if (cmd == "MORE") {
|
||||
++MenuPage;
|
||||
doMenu(sequenced);
|
||||
return FALSE;
|
||||
} else if (cmd == "CHECK") {
|
||||
check_poses();
|
||||
} else if ((integer)cmd > 0) { //POSE
|
||||
if (Adjusting && button != pose) {
|
||||
llMessageLinked(LINK_THIS,0,"SAVE",pose); //msg to pos/pose
|
||||
llSleep(5.);
|
||||
}
|
||||
setup_pose();
|
||||
Posemsg = cmd + "," + (string) BallCount;
|
||||
llMessageLinked(LINK_THIS,0,"POSE", Posemsg); //msg to pose
|
||||
llMessageLinked(LINK_THIS,0,"POSEB", (key)button); //msg to memory
|
||||
if (chat) say(button);
|
||||
pose = button;
|
||||
} else if (cmd == "SWAP") {
|
||||
swap += 1;
|
||||
llMessageLinked(LINK_THIS,0,"SWAP",(key)((string)swap)); //msg to pos/pose
|
||||
} else if (cmd == "STAND") {
|
||||
sendStand(); //msg to pos/pose
|
||||
if (chat) say(button);
|
||||
pose = "stand";
|
||||
} else if (cmd == "STOP") {
|
||||
if (chat) say(button);
|
||||
stop();
|
||||
return FALSE;
|
||||
} else if (cmd == "ADJUST") {
|
||||
Adjusting = ! Adjusting;
|
||||
setBalls("ADJUST|" + (string)Adjusting);
|
||||
} else if (cmd == "HIDE") {
|
||||
setBalls("0");
|
||||
} else if (cmd == "SHOW") {
|
||||
setBalls("SHOW");
|
||||
} else if (cmd == "DUMP") {
|
||||
llMessageLinked(LINK_THIS,1,"DUMP",(key)"");
|
||||
} else if (cmd == "INVISIBLE") {
|
||||
visible = !visible;
|
||||
llSetAlpha((float)visible*alpha, ALL_SIDES);
|
||||
} else if (cmd == "REDO") {
|
||||
redo = !redo;
|
||||
if (redo) say(button+" ON"); else say(button+" OFF");
|
||||
} else if (cmd == "CHAT") {
|
||||
chat = !chat;
|
||||
if (chat) say(button+" ON"); else say(button+" OFF");
|
||||
} else if (cmd == "BALLUSERS") {
|
||||
ballusers = !ballusers;
|
||||
if (ballusers) {
|
||||
llOwnerSay(button+" GROUP");
|
||||
setBalls("GROUP");
|
||||
} else {
|
||||
llOwnerSay(button+" ALL");
|
||||
setBalls("ALL");
|
||||
}
|
||||
} else if (cmd == "MENUUSERS") {
|
||||
if (user == owner) {
|
||||
if (!menuusers) {
|
||||
menuusers = 1;
|
||||
llOwnerSay(button+" GROUP");
|
||||
} else if (menuusers == 1) {
|
||||
menuusers = 2;
|
||||
llOwnerSay(button+" ALL");
|
||||
} else if (menuusers == 2) {
|
||||
menuusers = 0;
|
||||
llOwnerSay(button+" OWNER");
|
||||
}
|
||||
} else unauth(button, "owner");
|
||||
} else if (cmd == "RESET" || cmd == "RELOAD" || cmd == "RESTART") {
|
||||
stop();
|
||||
if (chat) say(button);
|
||||
if (cmd == "RESET") {
|
||||
llResetScript();
|
||||
} else {
|
||||
llResetOtherScript("~memory");
|
||||
if (cmd == "RESTART") {
|
||||
llResetScript();
|
||||
}
|
||||
}
|
||||
} else if (cmd == "OFF") {
|
||||
sendStand(); //msg to pos/pose
|
||||
stop();
|
||||
if (user == owner) {
|
||||
llOwnerSay(button);
|
||||
llResetOtherScript("~run");
|
||||
llResetScript();
|
||||
}
|
||||
unauth(button, "owner");
|
||||
return FALSE;
|
||||
} else if (llGetSubString(cmd, 0, 0) == "Z" || (cmd == "SAVE")) { //SAVE or Z-adjust
|
||||
llMessageLinked(LINK_THIS,0,cmd,pose); //msg to pos/pose
|
||||
doMenu(sequenced);
|
||||
return FALSE;
|
||||
} else if (cmd == "LINKMSG") {
|
||||
// menu button to send LM to a non-MLPV2 script
|
||||
integer ix = llListFindList(LMButtons, [button]);
|
||||
if (ix != -1) {
|
||||
list lmparms = llCSV2List(llList2String(LMParms, ix));
|
||||
llMessageLinked(
|
||||
llList2Integer(lmparms, 1), // destination link#
|
||||
llList2Integer(lmparms, 2), // 'num' arg
|
||||
llList2String(lmparms, 3), // 'str' arg
|
||||
user0); // key arg
|
||||
if (llList2Integer(lmparms,0)) { // inhibit remenu?
|
||||
return FALSE; // yes, bug out
|
||||
}
|
||||
}
|
||||
} else if (cmd == "SOUND") {
|
||||
integer ix = llListFindList(SoundNames, (list)button);
|
||||
if (ix >= 0) {
|
||||
llPlaySound(llList2String(Sounds, ix), 1.);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
ch = channel();
|
||||
killBalls();
|
||||
llSleep(2.0); // give ~run a chance to shut us down
|
||||
llResetOtherScript("~menucfg");
|
||||
llResetOtherScript("~pos");
|
||||
llResetOtherScript("~pose");
|
||||
llResetOtherScript("~poser");
|
||||
llResetOtherScript("~poser 1");
|
||||
llResetOtherScript("~poser 2");
|
||||
llResetOtherScript("~poser 3");
|
||||
llResetOtherScript("~poser 4");
|
||||
llResetOtherScript("~poser 5");
|
||||
alpha = llGetAlpha(0); //store object transparancy (alpha)
|
||||
if (alpha < 0.1) alpha = 0.5; else visible = 1; //if invisibl e store a visible alpha
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string str, key id) {
|
||||
if (from != llGetLinkNumber()) { return; }
|
||||
if (num >= 0) { return;}
|
||||
|
||||
// LMs from ~memory, passing configuration
|
||||
if (num == -1) {
|
||||
buttons = llCSV2List(str);
|
||||
} else if (num == -2) {
|
||||
commands = llCSV2List(str);
|
||||
} else if (num == -3) {
|
||||
menus = llCSV2List(str);
|
||||
} else if (num == -4) {
|
||||
buttonindex = llCSV2List(str);
|
||||
} else if (num == -5) {
|
||||
balls = llCSV2List(str);
|
||||
} else if (num == -6) {
|
||||
users = llCSV2List(str);
|
||||
} else if (num == -7) {
|
||||
LMButtons = llCSV2List(str);
|
||||
} else if (num == -8) {
|
||||
LMParms = llParseStringKeepNulls(str, ["|"], []);
|
||||
} else if (num == -9) {
|
||||
SoundNames = llCSV2List(str);
|
||||
} else if (num == -10) {
|
||||
Sounds = llCSV2List(str);
|
||||
} else if (num == -20) {
|
||||
list args = llCSV2List(str);
|
||||
redo = llList2Integer(args,0);
|
||||
chat = llList2Integer(args,1);
|
||||
ballusers = llList2Integer(args,2);
|
||||
menuusers = llList2Integer(args,3);
|
||||
SaneMenuOrder = llList2Integer(args,4);
|
||||
ReloadOnRez = llList2Integer(args,5);
|
||||
|
||||
state on;
|
||||
}
|
||||
}
|
||||
|
||||
state_exit() {
|
||||
llOwnerSay("("+llGetScriptName()+": "+(string)llGetFreeMemory()+" bytes free)");
|
||||
llWhisper(0, Version + ": READY");
|
||||
}
|
||||
}
|
||||
|
||||
state re_on {
|
||||
state_entry() {
|
||||
state on;
|
||||
}
|
||||
}
|
||||
|
||||
state on {
|
||||
state_entry() {
|
||||
ch = channel();
|
||||
owner = llGetOwner();
|
||||
llListen(ch - 1, "", NULL_KEY, ""); //listen for pressed buttons
|
||||
// llWhisper(0, "Channel: " + (string)ch);
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
if (ReloadOnRez) {
|
||||
llResetScript();
|
||||
}
|
||||
BallCount = 0;
|
||||
llSetTimerEvent(0.0);
|
||||
state re_on;
|
||||
}
|
||||
|
||||
touch_start(integer tcount) {
|
||||
user0 = llDetectedKey(0);
|
||||
touched(llDetectedGroup(0));
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string button) {
|
||||
if (id != user) {
|
||||
if (button == "Yes") {
|
||||
user = id;
|
||||
group = llSameGroup(user0);
|
||||
mainMenu();
|
||||
} else if (button != "Cancel") {
|
||||
continMenu("Selection cancelled because ");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (handle_cmd(button, FALSE) && redo) doMenu(FALSE);
|
||||
}
|
||||
|
||||
|
||||
link_message(integer from, integer num, string str, key id) {
|
||||
if (str == "PRIMTOUCH") {
|
||||
user0 = id;
|
||||
touched(num);
|
||||
return;
|
||||
}
|
||||
if (num == 0 && str == "AGAIN") {
|
||||
llMessageLinked(LINK_THIS,0,"POSE", Posemsg); //msg to pose
|
||||
llMessageLinked(LINK_THIS,0,"POSEB", (key)pose); //msg to memory
|
||||
return;
|
||||
}
|
||||
if (num == -12002) {
|
||||
handle_cmd(str, TRUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
timer() {
|
||||
setBalls("LIVE"); //msg to balls: stay alive
|
||||
}
|
||||
}
|
||||
272
TGLM/~menucfg.lsl
Normal file
272
TGLM/~menucfg.lsl
Normal file
@@ -0,0 +1,272 @@
|
||||
// MLPV2 Version 2.2, by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
// 15-color balls by Lizz Silverstar
|
||||
// autoback, multi-contin menu fixed
|
||||
|
||||
integer MAX_BALLS = 6;
|
||||
|
||||
// Multicolor ball patch by Lizz Silverstar
|
||||
// The colors var used to store the color values is a 32 bit integer (0x00000000)
|
||||
// This is broken up into 8 nibbles of which we will currently use the lower 4 nibbles
|
||||
// the first ball color is in the lower 4 bits, the second in the next 4 bits, etc
|
||||
// Masks and shifting are used to store and extract the data.
|
||||
// 4 bits gives us 15 colors. 0 = no ball, 1-15 = color
|
||||
// these index values are then used by the ~ball code to set the correct color
|
||||
// 1st ball mask is 0x0000000F, no shift
|
||||
// 2nd ball mask is 0x000000F0, shift of 4
|
||||
// 3rd ball mask is 0x00000F00, shift of 8
|
||||
// 4th ball mask is 0x0000F000, shift of 12
|
||||
|
||||
list Colornames = [
|
||||
"HIDE", "PINK", "BLUE", "PINK2",
|
||||
"BLUE2", "GREEN", "MAGENTA", "RED",
|
||||
"ORANGE", "WHITE", "BLACK", "YELLOW",
|
||||
"CYAN", "RED2", "TEAL", "GREEN2"];
|
||||
|
||||
|
||||
integer PoseIx;
|
||||
|
||||
integer CurButtonIx; // index of current button
|
||||
integer b0; // index of current button from start of current menu
|
||||
|
||||
integer AutoBack;
|
||||
integer chat = TRUE;
|
||||
integer redo = TRUE;
|
||||
integer menuusers;
|
||||
integer group;
|
||||
integer ballusers;
|
||||
integer SaneMenuOrder;
|
||||
integer ReloadOnRez = FALSE;
|
||||
|
||||
string cmd;
|
||||
string pose;
|
||||
string pose0;
|
||||
|
||||
list buttons;
|
||||
list buttonindex;
|
||||
list commands;
|
||||
list menus;
|
||||
list balls;
|
||||
list users;
|
||||
|
||||
list SoundNames;
|
||||
list Sounds;
|
||||
list LMButtons;
|
||||
list LMParms;
|
||||
|
||||
|
||||
// Globals for reading card config
|
||||
integer ConfigLineIndex;
|
||||
list ConfigCards; // list of names of config cards
|
||||
string ConfigCardName; // name of card being read
|
||||
integer ConfigCardIndex; // index of next card to read
|
||||
key ConfigQueryId;
|
||||
|
||||
integer next_card()
|
||||
{
|
||||
if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
|
||||
ConfigCards = [];
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
ConfigLineIndex = 0;
|
||||
ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
|
||||
ConfigCardIndex++;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
|
||||
llOwnerSay("Reading " + ConfigCardName);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
// ch = (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
llMessageLinked(LINK_THIS,1,"OK?",(key)""); //msg to memory: ask if ready
|
||||
}
|
||||
link_message(integer from, integer num, string str, key id) {
|
||||
if (num == 2 && str == "OK") state load; //memory ready
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
state load {
|
||||
state_entry() {
|
||||
string item;
|
||||
ConfigCards = [];
|
||||
integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
|
||||
while (n-- > 0) {
|
||||
item = llGetInventoryName(INVENTORY_NOTECARD, n);
|
||||
if (llSubStringIndex(item, ".MENUITEMS") != -1) {
|
||||
ConfigCards = [] + ConfigCards + (list)item;
|
||||
}
|
||||
}
|
||||
|
||||
ConfigCardIndex = 0;
|
||||
ConfigCards = llListSort(ConfigCards, 1, TRUE);
|
||||
next_card();
|
||||
}
|
||||
|
||||
dataserver(key query_id, string data) {
|
||||
if (query_id != ConfigQueryId) {
|
||||
return;
|
||||
}
|
||||
if (data == EOF) {
|
||||
if (next_card()) {
|
||||
return;
|
||||
}
|
||||
state on;
|
||||
}
|
||||
|
||||
integer ix = llSubStringIndex(data,"//"); //remove comments
|
||||
if (ix != -1) {
|
||||
if (ix == 0) data = "";
|
||||
else data = llGetSubString(data, 0, ix - 1);
|
||||
}
|
||||
|
||||
data = llStringTrim(data, STRING_TRIM_TAIL);
|
||||
if (data != "") {
|
||||
ix = llSubStringIndex(data," ");
|
||||
cmd = data;
|
||||
if (ix != -1) { //split command from data
|
||||
cmd = llGetSubString(data, 0, ix - 1);
|
||||
data = llGetSubString(data, ix+1, -1);
|
||||
}
|
||||
list ldata = llParseStringKeepNulls(data,[" | "," | "," | "," | "," |","| ","|"],[]);
|
||||
string arg1 = llList2String(ldata, 0);
|
||||
//llSay(0, cmd + ":" + data);
|
||||
if (cmd == "MENU") {
|
||||
integer auth;
|
||||
|
||||
if (PoseIx < 2) {
|
||||
llOwnerSay("warning: first two items in .MENUITEMS must be: POSE stand / POSE default");
|
||||
}
|
||||
llOwnerSay("loading '"+arg1+"' menu");
|
||||
if (llList2String(ldata, 1) == "GROUP") auth = 1; //access to submenus
|
||||
else if (llList2String(ldata, 1) != "OWNER") auth = 2; //0=owner 1=group 2=all
|
||||
|
||||
integer colors;
|
||||
string ball_color;
|
||||
integer colorIx;
|
||||
integer ix1;
|
||||
for (ix1=0; ix1 < MAX_BALLS; ++ix1) { // for each possible ball
|
||||
ball_color = llList2String(ldata, ix1 + 2); // get next color name from config
|
||||
colorIx = llListFindList(Colornames, (list)ball_color);
|
||||
if (colorIx != -1) {
|
||||
colors += (colorIx << (4 * ix1)); // 4 = bits per color (16 colors)
|
||||
}
|
||||
}
|
||||
menus = [] + menus + (list) arg1;
|
||||
balls = [] + balls + (list) colors;
|
||||
buttonindex = [] + buttonindex + (list) CurButtonIx;
|
||||
users = [] + users + (list) auth;
|
||||
if (llListFindList(buttons, (list)arg1) == -1) {
|
||||
integer jx = llListFindList(buttons, (list) "-");
|
||||
if (jx != -1) {
|
||||
buttons = llListReplaceList(buttons, (list)arg1, jx, jx);
|
||||
// "TOMENU" is already in commands list from the 'TOMENU -'
|
||||
} else if (CurButtonIx > 2) {
|
||||
llOwnerSay("No unused 'TOMENU -' for " + arg1);
|
||||
}
|
||||
}
|
||||
|
||||
b0 = 0;
|
||||
} else if (cmd == "AUTOBACK") {
|
||||
AutoBack = (arg1 != "0");
|
||||
} else if (cmd == "NORELOAD") {
|
||||
ReloadOnRez = (arg1 != "0"); // whether to reload menu on rez
|
||||
} else if (cmd == "MENUORDER") {
|
||||
SaneMenuOrder = (arg1 != "0"); // keep menu buttons in same order as in file
|
||||
} else {
|
||||
|
||||
// automatic menu extension (don't do for main menu)
|
||||
if (b0 == 12 && llGetListLength(menus) > 1) {
|
||||
// Add a "more" button before last item
|
||||
integer ix1 = -1;
|
||||
if (AutoBack) {
|
||||
ix1 = -2;
|
||||
// Add a "BACK" button
|
||||
buttons = llListInsertList(buttons, (list)"BACK", ix1);
|
||||
commands = llListInsertList(commands, (list)"BACK", ix1);
|
||||
++CurButtonIx;
|
||||
}
|
||||
buttons = llListInsertList(buttons, (list)"More-->", ix1);
|
||||
commands = llListInsertList(commands, (list)"MORE", ix1);
|
||||
++CurButtonIx;
|
||||
b0 = -ix1;
|
||||
}
|
||||
if (cmd == "POSE") {
|
||||
llMessageLinked(LINK_THIS,9+PoseIx,data, (key)"");
|
||||
if (!PoseIx) pose0 = arg1;
|
||||
cmd = (string)PoseIx;
|
||||
++PoseIx;
|
||||
} else if (cmd == "REDO") {
|
||||
if (llList2String(ldata, 1) != "OFF") redo = 1;
|
||||
} else if (cmd == "CHAT") {
|
||||
if (llList2String(ldata, 1) != "OFF") chat = 1;
|
||||
} else if (cmd == "BALLUSERS") {
|
||||
if (llList2String(ldata, 1) == "GROUP") ballusers = 1;
|
||||
} else if (cmd == "MENUUSERS") {
|
||||
if (llList2String(ldata, 1) == "GROUP") menuusers = 1;
|
||||
else if (llList2String(ldata, 1) != "OWNER") menuusers = 2;
|
||||
} else if (cmd == "LINKMSG") {
|
||||
LMButtons = [] + LMButtons + arg1;
|
||||
LMParms = [] + LMParms + llList2String(ldata, 1);
|
||||
} else if (cmd == "SOUND") {
|
||||
SoundNames += (list) arg1;
|
||||
Sounds += (list) llList2String(ldata, 1);
|
||||
}
|
||||
commands = [] + commands + (list) cmd;
|
||||
buttons = [] + buttons + (list) arg1;
|
||||
++CurButtonIx;
|
||||
++b0;
|
||||
}
|
||||
}
|
||||
++ConfigLineIndex;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of menuitems notecard
|
||||
}
|
||||
state_exit() {
|
||||
buttonindex = [] + buttonindex + (list) CurButtonIx; //enter last buttonindex
|
||||
commands = [] + commands + (list) ""; //empty command for undefined buttons (-1)
|
||||
|
||||
integer ix;
|
||||
integer count;
|
||||
while ((ix = llListFindList(buttons, (list)"-")) != -1) {
|
||||
++count;
|
||||
buttons = llDeleteSubList(buttons, ix, ix);
|
||||
commands = llDeleteSubList(commands, ix, ix);
|
||||
}
|
||||
if (count) {
|
||||
for (ix = 1; ix < llGetListLength(buttonindex); ++ix) {
|
||||
buttonindex = llListReplaceList(buttonindex,
|
||||
(list)(llList2Integer(buttonindex, ix) - count), ix, ix);
|
||||
}
|
||||
}
|
||||
// llMessageLinked(LINK_THIS,1,"LOADED",(string)PoseIx); //msg to memory
|
||||
llMessageLinked(LINK_THIS,9+PoseIx,"LOADED",(key)""); //msg to pose
|
||||
}
|
||||
}
|
||||
|
||||
state on {
|
||||
state_entry() {
|
||||
// llSay(0, llList2CSV(buttons));
|
||||
llMessageLinked(LINK_THIS, -3, llList2CSV(menus), (key)""); menus = [];
|
||||
llMessageLinked(LINK_THIS, -4, llList2CSV(buttonindex), (key)""); buttonindex = [];
|
||||
llMessageLinked(LINK_THIS, -5, llList2CSV(balls), (key)""); balls = [];
|
||||
llMessageLinked(LINK_THIS, -6, llList2CSV(users), (key)""); users = [];
|
||||
llMessageLinked(LINK_THIS, -7, llList2CSV(LMButtons), (key)""); LMButtons = [];
|
||||
|
||||
llMessageLinked(LINK_THIS, -8, llDumpList2String(LMParms, "|"), (key)""); LMParms = [];
|
||||
|
||||
llMessageLinked(LINK_THIS, -9, llList2CSV(SoundNames), (key)""); SoundNames = [];
|
||||
llMessageLinked(LINK_THIS, -10, llList2CSV(Sounds), (key)""); Sounds = [];
|
||||
|
||||
llMessageLinked(LINK_THIS, -2, llList2CSV(commands), (key)""); commands = [];
|
||||
llMessageLinked(LINK_THIS, -1, llList2CSV(buttons), (key)""); buttons = [];
|
||||
|
||||
|
||||
// finally, scalars (signals 'done' as well)
|
||||
llMessageLinked(LINK_THIS, -20,
|
||||
llList2CSV([ redo, chat, ballusers, menuusers, SaneMenuOrder, ReloadOnRez ]), (key)"");
|
||||
|
||||
llOwnerSay((string)CurButtonIx+" menuitems loaded ("+llGetScriptName()+": "+(string)llGetFreeMemory()+" bytes free)");
|
||||
}
|
||||
}
|
||||
102
TGLM/~pos.lsl
Normal file
102
TGLM/~pos.lsl
Normal file
@@ -0,0 +1,102 @@
|
||||
// MLPV2 Version 2.3j, by Learjeff Innis, based o n
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
integer MAX_BALLS = 6;
|
||||
|
||||
integer ch;
|
||||
integer swap;
|
||||
integer BallCount;
|
||||
|
||||
string pr1;
|
||||
string pr2;
|
||||
|
||||
integer Zoffset;
|
||||
|
||||
vector RefPos;
|
||||
rotation RefRot;
|
||||
|
||||
getRefPos() { //reference position
|
||||
RefPos = llGetPos();
|
||||
RefRot = llGetRot();
|
||||
Zoffset = (integer)llGetObjectDesc();
|
||||
RefPos.z += (float) Zoffset / 100.;
|
||||
}
|
||||
|
||||
list Pdata;
|
||||
|
||||
getPosNew(string pdata) {
|
||||
Pdata = llParseString2List(pdata, [" "],[]);
|
||||
}
|
||||
|
||||
setPos() {
|
||||
pr1 = (string)((vector)llList2String(Pdata, 0) * RefRot + RefPos);
|
||||
pr2 = (string)((vector)llList2String(Pdata, 2) * RefRot + RefPos);
|
||||
pr1 += (string)(llEuler2Rot((vector)llList2String(Pdata, 1) * DEG_TO_RAD) * RefRot);
|
||||
pr2 += (string)(llEuler2Rot((vector)llList2String(Pdata, 3) * DEG_TO_RAD) * RefRot);
|
||||
if (BallCount > 1) {
|
||||
llSay(ch+swap,pr1); //msg to ball1/2
|
||||
llSay(ch+!swap,pr2);
|
||||
} else {
|
||||
llSay(ch,pr1); //msg to ball1/2
|
||||
}
|
||||
|
||||
integer ix;
|
||||
for (ix = 2; ix < BallCount; ++ix) {
|
||||
llSay(ch + ix, (string)((vector)llList2String(Pdata, 2*ix) * RefRot + RefPos)
|
||||
+ (string)(llEuler2Rot((vector)llList2String(Pdata, 2*ix + 1) * DEG_TO_RAD) * RefRot));
|
||||
}
|
||||
}
|
||||
|
||||
getChan() {
|
||||
ch = (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
getRefPos();
|
||||
getChan();
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
getRefPos();
|
||||
getChan();
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string cmd, key pkey) {
|
||||
if (cmd == "PRIMTOUCH"){
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == 1 && cmd == "STOP") {
|
||||
swap = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (num) return;
|
||||
|
||||
if (cmd == "POSE") {
|
||||
list parms = llCSV2List((string)pkey);
|
||||
BallCount = llList2Integer(parms,1);
|
||||
return;
|
||||
} else if (cmd == "POSEPOS") {
|
||||
// p = (integer)((string)pkey
|
||||
getPosNew((string)pkey);
|
||||
setPos();
|
||||
} else if (cmd == "SWAP") {
|
||||
swap = (integer)((string)pkey) & 1;
|
||||
llSay(ch+swap,pr1); //msg to ball1/2
|
||||
llSay(ch+!swap,pr2);
|
||||
} else if (cmd == "REPOS") {
|
||||
getRefPos();
|
||||
} else if (llGetSubString(cmd, 0, 0) == "Z") {
|
||||
integer change = (integer)llGetSubString(cmd, 1, -1);
|
||||
Zoffset += change;
|
||||
RefPos.z += (float)change/100.;
|
||||
setPos();
|
||||
llOwnerSay("Height Adjustment: change by " + (string) change + "cm, new offset: " + (string)Zoffset + "cm");
|
||||
llSetObjectDesc((string)Zoffset);
|
||||
} else if (cmd == "GETREFPOS") {
|
||||
llMessageLinked(LINK_THIS,8,(string)RefPos,(string)RefRot); //send reference position to pose
|
||||
}
|
||||
}
|
||||
}
|
||||
213
TGLM/~pose.lsl
Normal file
213
TGLM/~pose.lsl
Normal file
@@ -0,0 +1,213 @@
|
||||
//MPLV2 Version 2.1, Lear Cale, from:
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
integer MAX_AVS = 6;
|
||||
|
||||
integer a;
|
||||
integer ch;
|
||||
integer i;
|
||||
integer swap;
|
||||
string an1;
|
||||
string an2;
|
||||
string an3;
|
||||
string an4;
|
||||
string an5;
|
||||
string an6;
|
||||
string pose;
|
||||
|
||||
list PRs; // pos/rot pairs for Save
|
||||
|
||||
list anims; // strided list of anims, indexed by pose*6
|
||||
vector pos;
|
||||
rotation rot;
|
||||
integer BallCount; // number of balls
|
||||
integer UpdateCount; // number of balls we've heard from, for save
|
||||
|
||||
string prStr(string str) {
|
||||
i = llSubStringIndex(str,">");
|
||||
vector p = ((vector)llGetSubString(str,0,i) - pos) / rot;
|
||||
vector r = llRot2Euler((rotation)llGetSubString(str,i+1,-1) / rot)*RAD_TO_DEG;
|
||||
return "<"+round(p.x, 3)+","+round(p.y, 3)+","+round(p.z, 3)+"> <"+round(r.x, 1)+","+round(r.y, 1)+","+round(r.z, 1)+">";
|
||||
}
|
||||
|
||||
string round(float number, integer places) {
|
||||
float shifted;
|
||||
integer rounded;
|
||||
string s;
|
||||
shifted = number * llPow(10.0,(float)places);
|
||||
rounded = llRound(shifted);
|
||||
s = (string)((float)rounded / llPow(10.0,(float)places));
|
||||
s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
|
||||
return s;
|
||||
}
|
||||
|
||||
check_anim(string aname) {
|
||||
if (aname == "") {
|
||||
return;
|
||||
}
|
||||
if ( aname != "PINK"
|
||||
&& aname != "BLUE"
|
||||
&& aname != "stand"
|
||||
&& aname != "sit_ground") {
|
||||
|
||||
// ignore expression suffix of "*" or "::nnn"
|
||||
if (llGetSubString(aname, -1, -1) == "*") {
|
||||
aname = llGetSubString(aname, 0, -2);
|
||||
} else {
|
||||
integer ix = llSubStringIndex(aname, "::");
|
||||
if (ix != -1) {
|
||||
aname = llGetSubString(aname, 0, ix-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (llGetInventoryType(aname) != INVENTORY_ANIMATION) {
|
||||
llSay(0,"animation '"
|
||||
+ aname
|
||||
+ "' not in inventory (ok for build-in animations, otherwise check)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getChan() {
|
||||
ch = (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
}
|
||||
|
||||
default {
|
||||
|
||||
link_message(integer from, integer num, string data, key id) {
|
||||
if (num != 9+a) return;
|
||||
|
||||
if (data == "LOADED") state on;
|
||||
|
||||
list ldata = llParseString2List(data,[" | "," | "," | "," | "," |","| ","|"],[]);
|
||||
|
||||
an1 = llList2String(ldata,1);
|
||||
an2 = llList2String(ldata,2);
|
||||
an3 = llList2String(ldata,3);
|
||||
an4 = llList2String(ldata,4);
|
||||
an5 = llList2String(ldata,5);
|
||||
an6 = llList2String(ldata,6);
|
||||
|
||||
if (a>1) {
|
||||
check_anim(an1);
|
||||
check_anim(an2);
|
||||
check_anim(an3);
|
||||
check_anim(an4);
|
||||
check_anim(an5);
|
||||
check_anim(an6);
|
||||
} else if (a) { //pose1: set default
|
||||
if (an1 == "") an1 = "sit_ground";
|
||||
if (an2 == "") an2 = "sit_ground";
|
||||
if (an3 == "") an3 = "sit_ground";
|
||||
if (an4 == "") an4 = "sit_ground";
|
||||
if (an5 == "") an5 = "sit_ground";
|
||||
if (an6 == "") an6 = "sit_ground";
|
||||
} else { //pose0: set stand
|
||||
if (an1 == "") an1 = "stand";
|
||||
if (an2 == "") an2 = "stand";
|
||||
if (an3 == "") an3 = "stand";
|
||||
if (an4 == "") an4 = "stand";
|
||||
if (an5 == "") an5 = "stand";
|
||||
if (an6 == "") an6 = "stand";
|
||||
}
|
||||
anims = [] + anims + [an1] + [an2] + [an3] + [an4] + [an5] + [an6];
|
||||
++a;
|
||||
}
|
||||
state_exit() {
|
||||
llOwnerSay((string)a+" poses loaded ("+llGetScriptName()+": "+(string)llGetFreeMemory()+" bytes free)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
state on {
|
||||
state_entry() {
|
||||
getChan();
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
getChan();
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string cmd, key akey) {
|
||||
if (cmd == "PRIMTOUCH"){
|
||||
return;
|
||||
}
|
||||
if (num) return;
|
||||
if (cmd == "POSE") {
|
||||
list parms = llCSV2List((string)akey);
|
||||
BallCount = llList2Integer(parms,1);
|
||||
a = llList2Integer(parms,0) * 6;
|
||||
an1 = llList2String(anims, a);
|
||||
an2 = llList2String(anims, a+1);
|
||||
an3 = llList2String(anims, a+2);
|
||||
an4 = llList2String(anims, a+3);
|
||||
an5 = llList2String(anims, a+4);
|
||||
an6 = llList2String(anims, a+5);
|
||||
} else if (cmd == "SWAP") {
|
||||
swap = !swap;
|
||||
} else if (cmd == "SAVE") {
|
||||
pose = (string)akey;
|
||||
state save;
|
||||
} else return;
|
||||
llMessageLinked(LINK_THIS,ch+swap, an1,(key)""); //msg to poser 1/2
|
||||
llMessageLinked(LINK_THIS,ch+!swap,an2,(key)"");
|
||||
llMessageLinked(LINK_THIS,ch+2, an3,(key)""); //msg to poser 3
|
||||
llMessageLinked(LINK_THIS,ch+3, an4,(key)""); //msg to poser 4
|
||||
llMessageLinked(LINK_THIS,ch+4, an5,(key)""); //msg to poser 4
|
||||
llMessageLinked(LINK_THIS,ch+5, an6,(key)""); //msg to poser 4
|
||||
}
|
||||
}
|
||||
|
||||
state save {
|
||||
state_entry() {
|
||||
llMessageLinked(LINK_THIS,0,"GETREFPOS",""); //msg to pos: ask ref position
|
||||
integer ix;
|
||||
PRs = [ "", "", "", "", "", "" ];
|
||||
|
||||
for (ix = 0; ix < MAX_AVS; ++ix) {
|
||||
llListen(ch+16+ix, "", NULL_KEY, "");
|
||||
llSay(ch+ix,"SAVE"); //msg to balls
|
||||
}
|
||||
llSetTimerEvent(3);
|
||||
UpdateCount = 0;
|
||||
}
|
||||
|
||||
|
||||
listen(integer channel, string name, key id, string pr) {
|
||||
channel -= (ch + 16);
|
||||
|
||||
if (channel == 0) {
|
||||
channel = channel + swap;
|
||||
} else if (channel == 1) {
|
||||
channel = channel - swap;
|
||||
}
|
||||
|
||||
PRs = llListReplaceList(PRs, (list)pr, channel, channel);
|
||||
|
||||
if (++UpdateCount == BallCount) {
|
||||
pr = "";
|
||||
integer ix;
|
||||
for (ix = 0; ix < BallCount; ++ix) {
|
||||
pr += prStr(llList2String(PRs, ix)) + " ";
|
||||
}
|
||||
|
||||
llOwnerSay("{"+pose+"} "+pr);
|
||||
llMessageLinked(LINK_THIS,1,pose,pr); //write to memory
|
||||
state on;
|
||||
}
|
||||
}
|
||||
link_message(integer from, integer num, string posstr, key rotkey) {
|
||||
if (posstr == "PRIMTOUCH"){
|
||||
return;
|
||||
}
|
||||
if (num != 8) return;
|
||||
pos = (vector)posstr; //revtrieve reference position from pos
|
||||
rot = (rotation)((string)rotkey);
|
||||
}
|
||||
timer() {
|
||||
state on;
|
||||
}
|
||||
state_exit() {
|
||||
llSetTimerEvent(0);
|
||||
}
|
||||
}
|
||||
198
TGLM/~poser 1.lsl
Normal file
198
TGLM/~poser 1.lsl
Normal file
@@ -0,0 +1,198 @@
|
||||
// MPLV2 2.3 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V 1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
integer ch;
|
||||
string animation = "stand";
|
||||
key avatar;
|
||||
|
||||
integer ExprEnabled = TRUE;
|
||||
string Expression;
|
||||
float ExprTimer;
|
||||
|
||||
integer BallNum;
|
||||
|
||||
list Expressions = [
|
||||
""
|
||||
, "express_open_mouth" // 1
|
||||
, "express_surprise_emote" // 2
|
||||
, "express_tongue_out" // 3
|
||||
, "express_smile" // 4
|
||||
, "express_toothsmile" // 5
|
||||
, "express_wink_emote" // 6
|
||||
, "express_cry_emote" // 7
|
||||
, "express_kiss" // 8
|
||||
, "express_laugh_emote" // 9
|
||||
, "express_disdain" // 10
|
||||
, "express_repulsed_emote" // 11
|
||||
, "express_anger_emote" // 12
|
||||
, "express_bored_emote" // 13
|
||||
, "express_sad_emote" // 14
|
||||
, "express_embarrassed_emote" // 15
|
||||
, "express_frown" // 16
|
||||
, "express_shrug_emote" // 17
|
||||
, "express_afraid_emote" // 18
|
||||
, "express_worry_emote" // 19
|
||||
, "SLEEP" // 20
|
||||
];
|
||||
|
||||
|
||||
stopAnim() {
|
||||
key id = llGetPermissionsKey();
|
||||
list anims = llGetAnimationList(id);
|
||||
integer ix;
|
||||
for (ix = 0; ix < llGetListLength(anims); ++ix) {
|
||||
string anim = llList2String(anims, ix);
|
||||
if (anim != "") {
|
||||
llStopAnimation(anim);
|
||||
}
|
||||
}
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
startAnim(string anim) {
|
||||
if (Expression != "") {
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
if (ExprEnabled) {
|
||||
llSetTimerEvent(ExprTimer);
|
||||
}
|
||||
} else {
|
||||
stopAnim();
|
||||
}
|
||||
if (anim != "") {
|
||||
llStartAnimation(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// Animation names with a "*" suffix get open mouth
|
||||
// Those with a suffix of "::" followed by a number
|
||||
// get the expression associated with that number.
|
||||
// This can optionally be followed by another "::" delim,
|
||||
// with a timer value following.
|
||||
// Return the anim name without the suffix.
|
||||
string getExpression(string anim) {
|
||||
if (llGetSubString(anim,-1,-1) == "*") {
|
||||
Expression = llList2String(Expressions, 1);
|
||||
ExprTimer = 0.5;
|
||||
return llGetSubString(anim, 0, -2);
|
||||
}
|
||||
integer ix = llSubStringIndex(anim, "::");
|
||||
if (ix == -1) {
|
||||
Expression = "";
|
||||
ExprTimer = 0.5;
|
||||
return anim;
|
||||
}
|
||||
|
||||
list parms = llParseString2List(anim, ["::"], []);
|
||||
anim = llList2String(parms, 0);
|
||||
integer exprIx = (integer) llList2String(parms, 1);
|
||||
Expression = llList2String(Expressions, exprIx);
|
||||
ExprTimer = (float) llList2String(parms,2);
|
||||
|
||||
if (ExprTimer <= 0.0) {
|
||||
ExprTimer = 0.5;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
getChan() {
|
||||
BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
|
||||
ch = BallNum
|
||||
+ (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
state s_on;
|
||||
}
|
||||
}
|
||||
|
||||
state s_on {
|
||||
state_entry() {
|
||||
getChan();
|
||||
llListen(ch+8,"",NULL_KEY,"");
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
state default;
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string an, key id) { //an animation is set
|
||||
if (an == "PRIMTOUCH") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != ch) return;
|
||||
an = getExpression(an); // get & save expression, and return unadorned anim
|
||||
|
||||
if (avatar == llGetPermissionsKey()
|
||||
&& avatar != NULL_KEY
|
||||
&& animation != "") {
|
||||
llStopAnimation(animation);
|
||||
llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, llGetPermissionsKey());
|
||||
startAnim(an);
|
||||
}
|
||||
animation = an;
|
||||
}
|
||||
|
||||
timer() { // timer to keep mouth open
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else if (Expression != "") {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string str) {
|
||||
if (str == "ALIVE" || str == "DIE") {
|
||||
llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
|
||||
if (str == "DIE") {
|
||||
avatar = NULL_KEY;
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
|
||||
if (avatar == NULL_KEY) {
|
||||
if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
}
|
||||
// llReleaseControls();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatar != llGetPermissionsKey()
|
||||
|| ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
|
||||
ExprEnabled = TRUE;
|
||||
llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
|
||||
} else {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
}
|
||||
}
|
||||
|
||||
run_time_permissions(integer perm) {
|
||||
if (avatar != llGetPermissionsKey()) {
|
||||
llWhisper(DEBUG_CHANNEL, "avatar != perm key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (perm & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
} else {
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
198
TGLM/~poser 2.lsl
Normal file
198
TGLM/~poser 2.lsl
Normal file
@@ -0,0 +1,198 @@
|
||||
// MPLV2 2.3 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - C opyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
integer ch;
|
||||
string animation = "stand";
|
||||
key avatar;
|
||||
|
||||
integer ExprEnabled = TRUE;
|
||||
string Expression;
|
||||
float ExprTimer;
|
||||
|
||||
integer BallNum;
|
||||
|
||||
list Expressions = [
|
||||
""
|
||||
, "express_open_mouth" // 1
|
||||
, "express_surprise_emote" // 2
|
||||
, "express_tongue_out" // 3
|
||||
, "express_smile" // 4
|
||||
, "express_toothsmile" // 5
|
||||
, "express_wink_emote" // 6
|
||||
, "express_cry_emote" // 7
|
||||
, "express_kiss" // 8
|
||||
, "express_laugh_emote" // 9
|
||||
, "express_disdain" // 10
|
||||
, "express_repulsed_emote" // 11
|
||||
, "express_anger_emote" // 12
|
||||
, "express_bored_emote" // 13
|
||||
, "express_sad_emote" // 14
|
||||
, "express_embarrassed_emote" // 15
|
||||
, "express_frown" // 16
|
||||
, "express_shrug_emote" // 17
|
||||
, "express_afraid_emote" // 18
|
||||
, "express_worry_emote" // 19
|
||||
, "SLEEP" // 20
|
||||
];
|
||||
|
||||
|
||||
stopAnim() {
|
||||
key id = llGetPermissionsKey();
|
||||
list anims = llGetAnimationList(id);
|
||||
integer ix;
|
||||
for (ix = 0; ix < llGetListLength(anims); ++ix) {
|
||||
string anim = llList2String(anims, ix);
|
||||
if (anim != "") {
|
||||
llStopAnimation(anim);
|
||||
}
|
||||
}
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
startAnim(string anim) {
|
||||
if (Expression != "") {
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
if (ExprEnabled) {
|
||||
llSetTimerEvent(ExprTimer);
|
||||
}
|
||||
} else {
|
||||
stopAnim();
|
||||
}
|
||||
if (anim != "") {
|
||||
llStartAnimation(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// Animation names with a "*" suffix get open mouth
|
||||
// Those with a suffix of "::" followed by a number
|
||||
// get the expression associated with that number.
|
||||
// This can optionally be followed by another "::" delim,
|
||||
// with a timer value following.
|
||||
// Return the anim name without the suffix.
|
||||
string getExpression(string anim) {
|
||||
if (llGetSubString(anim,-1,-1) == "*") {
|
||||
Expression = llList2String(Expressions, 1);
|
||||
ExprTimer = 0.5;
|
||||
return llGetSubString(anim, 0, -2);
|
||||
}
|
||||
integer ix = llSubStringIndex(anim, "::");
|
||||
if (ix == -1) {
|
||||
Expression = "";
|
||||
ExprTimer = 0.5;
|
||||
return anim;
|
||||
}
|
||||
|
||||
list parms = llParseString2List(anim, ["::"], []);
|
||||
anim = llList2String(parms, 0);
|
||||
integer exprIx = (integer) llList2String(parms, 1);
|
||||
Expression = llList2String(Expressions, exprIx);
|
||||
ExprTimer = (float) llList2String(parms,2);
|
||||
|
||||
if (ExprTimer <= 0.0) {
|
||||
ExprTimer = 0.5;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
getChan() {
|
||||
BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
|
||||
ch = BallNum
|
||||
+ (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
state s_on;
|
||||
}
|
||||
}
|
||||
|
||||
state s_on {
|
||||
state_entry() {
|
||||
getChan();
|
||||
llListen(ch+8,"",NULL_KEY,"");
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
state default;
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string an, key id) { //an animation is set
|
||||
if (an == "PRIMTOUCH") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != ch) return;
|
||||
an = getExpression(an); // get & save expression, and return unadorned anim
|
||||
|
||||
if (avatar == llGetPermissionsKey()
|
||||
&& avatar != NULL_KEY
|
||||
&& animation != "") {
|
||||
llStopAnimation(animation);
|
||||
llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, llGetPermissionsKey());
|
||||
startAnim(an);
|
||||
}
|
||||
animation = an;
|
||||
}
|
||||
|
||||
timer() { // timer to keep mouth open
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else if (Expression != "") {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string str) {
|
||||
if (str == "ALIVE" || str == "DIE") {
|
||||
llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
|
||||
if (str == "DIE") {
|
||||
avatar = NULL_KEY;
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
|
||||
if (avatar == NULL_KEY) {
|
||||
if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
}
|
||||
// llReleaseControls();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatar != llGetPermissionsKey()
|
||||
|| ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
|
||||
ExprEnabled = TRUE;
|
||||
llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
|
||||
} else {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
}
|
||||
}
|
||||
|
||||
run_time_permissions(integer perm) {
|
||||
if (avatar != llGetPermissionsKey()) {
|
||||
llWhisper(DEBUG_CHANNEL, "avatar != perm key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (perm & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
} else {
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
198
TGLM/~poser 3.lsl
Normal file
198
TGLM/~poser 3.lsl
Normal file
@@ -0,0 +1,198 @@
|
||||
// MPLV2 2.3 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
integer ch;
|
||||
string animation = "stand";
|
||||
key avatar;
|
||||
|
||||
integer ExprEnabled = TRUE;
|
||||
string Expression;
|
||||
float ExprTimer;
|
||||
|
||||
integer BallNum;
|
||||
|
||||
list Expressions = [
|
||||
""
|
||||
, "express_open_mouth" // 1
|
||||
, "express_surprise_emote" // 2
|
||||
, "express_tongue_out" // 3
|
||||
, "express_smile" // 4
|
||||
, "express_toothsmile" // 5
|
||||
, "express_wink_emote" // 6
|
||||
, "express_cry_emote" // 7
|
||||
, "express_kiss" // 8
|
||||
, "express_laugh_emote" // 9
|
||||
, "express_disdain" // 10
|
||||
, "express_repulsed_emote" // 11
|
||||
, "express_anger_emote" // 12
|
||||
, "express_bored_emote" // 13
|
||||
, "express_sad_emote" // 14
|
||||
, "express_embarrassed_emote" // 15
|
||||
, "express_frown" // 16
|
||||
, "express_shrug_emote" // 17
|
||||
, "express_afraid_emote" // 18
|
||||
, "express_worry_emote" // 19
|
||||
, "SLEEP" // 20
|
||||
];
|
||||
|
||||
|
||||
stopAnim() {
|
||||
key id = llGetPermissionsKey();
|
||||
list anims = llGetAnimationList(id);
|
||||
integer ix;
|
||||
for (ix = 0; ix < llGetListLength(anims); ++ix) {
|
||||
string anim = llList2String(anims, ix);
|
||||
if (anim != "") {
|
||||
llStopAnimation(anim);
|
||||
}
|
||||
}
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
startAnim(string anim) {
|
||||
if (Expression != "") {
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
if (ExprEnabled) {
|
||||
llSetTimerEvent(ExprTimer);
|
||||
}
|
||||
} else {
|
||||
stopAnim();
|
||||
}
|
||||
if (anim != "") {
|
||||
llStartAnimation(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// Animation names with a "*" suffix get open mouth
|
||||
// Those with a suffix of "::" followed by a number
|
||||
// get the expression associated with that number.
|
||||
// This can optionally be followed by another "::" delim,
|
||||
// with a timer value following.
|
||||
// Return the anim name without the suffix.
|
||||
string getExpression(string anim) {
|
||||
if (llGetSubString(anim,-1,-1) == "*") {
|
||||
Expression = llList2String(Expressions, 1);
|
||||
ExprTimer = 0.5;
|
||||
return llGetSubString(anim, 0, -2);
|
||||
}
|
||||
integer ix = llSubStringIndex(anim, "::");
|
||||
if (ix == -1) {
|
||||
Expression = "";
|
||||
ExprTimer = 0.5;
|
||||
return anim;
|
||||
}
|
||||
|
||||
list parms = llParseString2List(anim, ["::"], []);
|
||||
anim = llList2String(parms, 0);
|
||||
integer exprIx = (integer) llList2String(parms, 1);
|
||||
Expression = llList2String(Expressions, exprIx);
|
||||
ExprTimer = (float) llList2String(parms,2);
|
||||
|
||||
if (ExprTimer <= 0.0) {
|
||||
ExprTimer = 0.5;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
getChan() {
|
||||
BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
|
||||
ch = BallNum
|
||||
+ (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
state s_on;
|
||||
}
|
||||
}
|
||||
|
||||
state s_on {
|
||||
state_entry() {
|
||||
getChan();
|
||||
llListen(ch+8,"",NULL_KEY,"");
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
state default;
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string an, key id) { //an animation is set
|
||||
if (an == "PRIMTOUCH") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != ch) return;
|
||||
an = getExpression(an); // get & save expression, and return unadorned anim
|
||||
|
||||
if (avatar == llGetPermissionsKey()
|
||||
&& avatar != NULL_KEY
|
||||
&& animation != "") {
|
||||
llStopAnimation(animation);
|
||||
llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, llGetPermissionsKey());
|
||||
startAnim(an);
|
||||
}
|
||||
animation = an;
|
||||
}
|
||||
|
||||
timer() { // timer to keep mouth open
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else if (Expression != "") {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string str) {
|
||||
if (str == "ALIVE" || str == "DIE") {
|
||||
llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
|
||||
if (str == "DIE") {
|
||||
avatar = NULL_KEY;
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
|
||||
if (avatar == NULL_KEY) {
|
||||
if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
}
|
||||
// llReleaseControls();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatar != llGetPermissionsKey()
|
||||
|| ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
|
||||
ExprEnabled = TRUE;
|
||||
llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
|
||||
} else {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
}
|
||||
}
|
||||
|
||||
run_time_permissions(integer perm) {
|
||||
if (avatar != llGetPermissionsKey()) {
|
||||
llWhisper(DEBUG_CHANNEL, "avatar != perm key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (perm & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
} else {
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
198
TGLM/~poser 4.lsl
Normal file
198
TGLM/~poser 4.lsl
Normal file
@@ -0,0 +1,198 @@
|
||||
// MPLV2 2.3 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
integer ch;
|
||||
string animation = "stand";
|
||||
key avatar;
|
||||
|
||||
integer ExprEnabled = TRUE;
|
||||
string Expression;
|
||||
float ExprTimer;
|
||||
|
||||
integer BallNum;
|
||||
|
||||
list Expressions = [
|
||||
""
|
||||
, "express_open_mouth" // 1
|
||||
, "express_surprise_emote" // 2
|
||||
, "express_tongue_out" // 3
|
||||
, "express_smile" // 4
|
||||
, "express_toothsmile" // 5
|
||||
, "express_wink_emote" // 6
|
||||
, "express_cry_emote" // 7
|
||||
, "express_kiss" // 8
|
||||
, "express_laugh_emote" // 9
|
||||
, "express_disdain" // 10
|
||||
, "express_repulsed_emote" // 11
|
||||
, "express_anger_emote" // 12
|
||||
, "express_bored_emote" // 13
|
||||
, "express_sad_emote" // 14
|
||||
, "express_embarrassed_emote" // 15
|
||||
, "express_frown" // 16
|
||||
, "express_shrug_emote" // 17
|
||||
, "express_afraid_emote" // 18
|
||||
, "express_worry_emote" // 19
|
||||
, "SLEEP" // 20
|
||||
];
|
||||
|
||||
|
||||
stopAnim() {
|
||||
key id = llGetPermissionsKey();
|
||||
list anims = llGetAnimationList(id);
|
||||
integer ix;
|
||||
for (ix = 0; ix < llGetListLength(anims); ++ix) {
|
||||
string anim = llList2String(anims, ix);
|
||||
if (anim != "") {
|
||||
llStopAnimation(anim);
|
||||
}
|
||||
}
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
startAnim(string anim) {
|
||||
if (Expression != "") {
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
if (ExprEnabled) {
|
||||
llSetTimerEvent(ExprTimer);
|
||||
}
|
||||
} else {
|
||||
stopAnim();
|
||||
}
|
||||
if (anim != "") {
|
||||
llStartAnimation(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// Animation names with a "*" suffix get open mouth
|
||||
// Those with a suffix of "::" followed by a number
|
||||
// get the expression associated with that number.
|
||||
// This can optionally be followed by another "::" delim,
|
||||
// with a timer value following.
|
||||
// Return the anim name without the suffix.
|
||||
string getExpression(string anim) {
|
||||
if (llGetSubString(anim,-1,-1) == "*") {
|
||||
Expression = llList2String(Expressions, 1);
|
||||
ExprTimer = 0.5;
|
||||
return llGetSubString(anim, 0, -2);
|
||||
}
|
||||
integer ix = llSubStringIndex(anim, "::");
|
||||
if (ix == -1) {
|
||||
Expression = "";
|
||||
ExprTimer = 0.5;
|
||||
return anim;
|
||||
}
|
||||
|
||||
list parms = llParseString2List(anim, ["::"], []);
|
||||
anim = llList2String(parms, 0);
|
||||
integer exprIx = (integer) llList2String(parms, 1);
|
||||
Expression = llList2String(Expressions, exprIx);
|
||||
ExprTimer = (float) llList2String(parms,2);
|
||||
|
||||
if (ExprTimer <= 0.0) {
|
||||
ExprTimer = 0.5;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
getChan() {
|
||||
BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
|
||||
ch = BallNum
|
||||
+ (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
state s_on;
|
||||
}
|
||||
}
|
||||
|
||||
state s_on {
|
||||
state_entry() {
|
||||
getChan();
|
||||
llListen(ch+8,"",NULL_KEY,"");
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
state default;
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string an, key id) { //an animation is set
|
||||
if (an == "PRIMTOUCH") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != ch) return;
|
||||
an = getExpression(an); // get & save expression, and return unadorned anim
|
||||
|
||||
if (avatar == llGetPermissionsKey()
|
||||
&& avatar != NULL_KEY
|
||||
&& animation != "") {
|
||||
llStopAnimation(animation);
|
||||
llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, llGetPermissionsKey());
|
||||
startAnim(an);
|
||||
}
|
||||
animation = an;
|
||||
}
|
||||
|
||||
timer() { // timer to keep mouth open
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else if (Expression != "") {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string str) {
|
||||
if (str == "ALIVE" || str == "DIE") {
|
||||
llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
|
||||
if (str == "DIE") {
|
||||
avatar = NULL_KEY;
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
|
||||
if (avatar == NULL_KEY) {
|
||||
if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
}
|
||||
// llReleaseControls();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatar != llGetPermissionsKey()
|
||||
|| ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
|
||||
ExprEnabled = TRUE;
|
||||
llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
|
||||
} else {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
}
|
||||
}
|
||||
|
||||
run_time_permissions(integer perm) {
|
||||
if (avatar != llGetPermissionsKey()) {
|
||||
llWhisper(DEBUG_CHANNEL, "avatar != perm key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (perm & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
} else {
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
198
TGLM/~poser 5.lsl
Normal file
198
TGLM/~poser 5.lsl
Normal file
@@ -0,0 +1,198 @@
|
||||
// MPLV2 2.3 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
integer ch;
|
||||
string animation = "stand";
|
||||
key avatar;
|
||||
|
||||
integer ExprEnabled = TRUE;
|
||||
string Expression;
|
||||
float ExprTimer;
|
||||
|
||||
integer BallNum;
|
||||
|
||||
list Expressions = [
|
||||
""
|
||||
, "express_open_mouth" // 1
|
||||
, "express_surprise_emote" // 2
|
||||
, "express_tongue_out" // 3
|
||||
, "express_smile" // 4
|
||||
, "express_toothsmile" // 5
|
||||
, "express_wink_emote" // 6
|
||||
, "express_cry_emote" // 7
|
||||
, "express_kiss" // 8
|
||||
, "express_laugh_emote" // 9
|
||||
, "express_disdain" // 10
|
||||
, "express_repulsed_emote" // 11
|
||||
, "express_anger_emote" // 12
|
||||
, "express_bored_emote" // 13
|
||||
, "express_sad_emote" // 14
|
||||
, "express_embarrassed_emote" // 15
|
||||
, "express_frown" // 16
|
||||
, "express_shrug_emote" // 17
|
||||
, "express_afraid_emote" // 18
|
||||
, "express_worry_emote" // 19
|
||||
, "SLEEP" // 20
|
||||
];
|
||||
|
||||
|
||||
stopAnim() {
|
||||
key id = llGetPermissionsKey();
|
||||
list anims = llGetAnimationList(id);
|
||||
integer ix;
|
||||
for (ix = 0; ix < llGetListLength(anims); ++ix) {
|
||||
string anim = llList2String(anims, ix);
|
||||
if (anim != "") {
|
||||
llStopAnimation(anim);
|
||||
}
|
||||
}
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
startAnim(string anim) {
|
||||
if (Expression != "") {
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
if (ExprEnabled) {
|
||||
llSetTimerEvent(ExprTimer);
|
||||
}
|
||||
} else {
|
||||
stopAnim();
|
||||
}
|
||||
if (anim != "") {
|
||||
llStartAnimation(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// Animation names with a "*" suffix get open mouth
|
||||
// Those with a suffix of "::" followed by a number
|
||||
// get the expression associated with that number.
|
||||
// This can optionally be followed by another "::" delim,
|
||||
// with a timer value following.
|
||||
// Return the anim name without the suffix.
|
||||
string getExpression(string anim) {
|
||||
if (llGetSubString(anim,-1,-1) == "*") {
|
||||
Expression = llList2String(Expressions, 1);
|
||||
ExprTimer = 0.5;
|
||||
return llGetSubString(anim, 0, -2);
|
||||
}
|
||||
integer ix = llSubStringIndex(anim, "::");
|
||||
if (ix == -1) {
|
||||
Expression = "";
|
||||
ExprTimer = 0.5;
|
||||
return anim;
|
||||
}
|
||||
|
||||
list parms = llParseString2List(anim, ["::"], []);
|
||||
anim = llList2String(parms, 0);
|
||||
integer exprIx = (integer) llList2String(parms, 1);
|
||||
Expression = llList2String(Expressions, exprIx);
|
||||
ExprTimer = (float) llList2String(parms,2);
|
||||
|
||||
if (ExprTimer <= 0.0) {
|
||||
ExprTimer = 0.5;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
getChan() {
|
||||
BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
|
||||
ch = BallNum
|
||||
+ (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
state s_on;
|
||||
}
|
||||
}
|
||||
|
||||
state s_on {
|
||||
state_entry() {
|
||||
getChan();
|
||||
llListen(ch+8,"",NULL_KEY,"");
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
state default;
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string an, key id) { //an animation is set
|
||||
if (an == "PRIMTOUCH") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != ch) return;
|
||||
an = getExpression(an); // get & save expression, and return unadorned anim
|
||||
|
||||
if (avatar == llGetPermissionsKey()
|
||||
&& avatar != NULL_KEY
|
||||
&& animation != "") {
|
||||
llStopAnimation(animation);
|
||||
llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, llGetPermissionsKey());
|
||||
startAnim(an);
|
||||
}
|
||||
animation = an;
|
||||
}
|
||||
|
||||
timer() { // timer to keep mouth open
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else if (Expression != "") {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string str) {
|
||||
if (str == "ALIVE" || str == "DIE") {
|
||||
llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
|
||||
if (str == "DIE") {
|
||||
avatar = NULL_KEY;
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
|
||||
if (avatar == NULL_KEY) {
|
||||
if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
}
|
||||
// llReleaseControls();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatar != llGetPermissionsKey()
|
||||
|| ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
|
||||
ExprEnabled = TRUE;
|
||||
llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
|
||||
} else {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
}
|
||||
}
|
||||
|
||||
run_time_permissions(integer perm) {
|
||||
if (avatar != llGetPermissionsKey()) {
|
||||
llWhisper(DEBUG_CHANNEL, "avatar != perm key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (perm & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, llGetPermissionsKey());
|
||||
startAnim(animation);
|
||||
} else {
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
198
TGLM/~poser.lsl
Normal file
198
TGLM/~poser.lsl
Normal file
@@ -0,0 +1,198 @@
|
||||
// MPLV2 2.3 by Learjeff Innis, ba sed on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
integer ch;
|
||||
string animation = "stand";
|
||||
key avatar;
|
||||
|
||||
integer ExprEnabled = TRUE;
|
||||
string Expression;
|
||||
float ExprTimer;
|
||||
|
||||
integer BallNum;
|
||||
|
||||
list Expressions = [
|
||||
""
|
||||
, "express_open_mouth" // 1
|
||||
, "express_surprise_emote" // 2
|
||||
, "express_tongue_out" // 3
|
||||
, "express_smile" // 4
|
||||
, "express_toothsmile" // 5
|
||||
, "express_wink_emote" // 6
|
||||
, "express_cry_emote" // 7
|
||||
, "express_kiss" // 8
|
||||
, "express_laugh_emote" // 9
|
||||
, "express_disdain" // 10
|
||||
, "express_repulsed_emote" // 11
|
||||
, "express_anger_emote" // 12
|
||||
, "express_bored_emote" // 13
|
||||
, "express_sad_emote" // 14
|
||||
, "express_embarrassed_emote" // 15
|
||||
, "express_frown" // 16
|
||||
, "express_shrug_emote" // 17
|
||||
, "express_afraid_emote" // 18
|
||||
, "express_worry_emote" // 19
|
||||
, "SLEEP" // 20
|
||||
];
|
||||
|
||||
|
||||
stopAnim() {
|
||||
key id = llGetPermissionsKey();
|
||||
list anims = llGetAnimationList(id);
|
||||
integer ix;
|
||||
for (ix = 0; ix < llGetListLength(anims); ++ix) {
|
||||
string anim = llList2String(anims, ix);
|
||||
if (anim != "") {
|
||||
llStopAnimation(anim);
|
||||
}
|
||||
}
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
startAnim(string anim) {
|
||||
if (Expression != "") {
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
if (ExprEnabled) {
|
||||
llSetTimerEvent(ExprTimer);
|
||||
}
|
||||
} else {
|
||||
stopAnim();
|
||||
}
|
||||
if (anim != "") {
|
||||
llStartAnimation(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// Animation names with a "*" suffix get open mouth
|
||||
// Those with a suffix of "::" followed by a number
|
||||
// get the expression associated with that number.
|
||||
// This can optionally be followed by another "::" delim,
|
||||
// with a timer value following.
|
||||
// Return the anim name without the suffix.
|
||||
string getExpression(string anim) {
|
||||
if (llGetSubString(anim,-1,-1) == "*") {
|
||||
Expression = llList2String(Expressions, 1);
|
||||
ExprTimer = 0.5;
|
||||
return llGetSubString(anim, 0, -2);
|
||||
}
|
||||
integer ix = llSubStringIndex(anim, "::");
|
||||
if (ix == -1) {
|
||||
Expression = "";
|
||||
ExprTimer = 0.5;
|
||||
return anim;
|
||||
}
|
||||
|
||||
list parms = llParseString2List(anim, ["::"], []);
|
||||
anim = llList2String(parms, 0);
|
||||
integer exprIx = (integer) llList2String(parms, 1);
|
||||
Expression = llList2String(Expressions, exprIx);
|
||||
ExprTimer = (float) llList2String(parms,2);
|
||||
|
||||
if (ExprTimer <= 0.0) {
|
||||
ExprTimer = 0.5;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
getChan() {
|
||||
BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
|
||||
ch = BallNum
|
||||
+ (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
state s_on;
|
||||
}
|
||||
}
|
||||
|
||||
state s_on {
|
||||
state_entry() {
|
||||
getChan();
|
||||
llListen(ch+8,"",NULL_KEY,"");
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
state default;
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string an, key id) { //an animation is set
|
||||
if (an == "PRIMTOUCH") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != ch) return;
|
||||
an = getExpression(an); // get & save expression, and return unadorned anim
|
||||
|
||||
if (avatar == llGetPermissionsKey()
|
||||
&& avatar != NULL_KEY
|
||||
&& animation != "") {
|
||||
llStopAnimation(animation);
|
||||
llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, avatar);
|
||||
startAnim(an);
|
||||
}
|
||||
animation = an;
|
||||
}
|
||||
|
||||
timer() { // timer to keep mouth open
|
||||
if (Expression == "SLEEP") {
|
||||
llStartAnimation("express_disdain");
|
||||
llStartAnimation("express_smile");
|
||||
} else if (Expression != "") {
|
||||
llStartAnimation(Expression);
|
||||
}
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string str) {
|
||||
if (str == "ALIVE" || str == "DIE") {
|
||||
llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
|
||||
if (str == "DIE") {
|
||||
avatar = NULL_KEY;
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
|
||||
if (avatar == NULL_KEY) {
|
||||
if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
|
||||
}
|
||||
// llReleaseControls();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatar != llGetPermissionsKey()
|
||||
|| ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
|
||||
ExprEnabled = TRUE;
|
||||
llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
|
||||
} else {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
|
||||
startAnim(animation);
|
||||
}
|
||||
}
|
||||
|
||||
run_time_permissions(integer perm) {
|
||||
if (avatar != llGetPermissionsKey()) {
|
||||
llWhisper(DEBUG_CHANNEL, "avatar != perm key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (perm & PERMISSION_TRIGGER_ANIMATION) {
|
||||
stopAnim();
|
||||
llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
|
||||
startAnim(animation);
|
||||
} else {
|
||||
llMessageLinked(LINK_SET, -11001, (string)BallNum, avatar);
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
383
TGLM/~props.lsl
Normal file
383
TGLM/~props.lsl
Normal file
@@ -0,0 +1,383 @@
|
||||
//MPLV2 Version 2.3 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
|
||||
|
||||
// v2.2 - rotate all props
|
||||
|
||||
// This script handles props (object rezzed for a given pose)
|
||||
|
||||
integer Checking = FALSE; // whether doing consistency check
|
||||
|
||||
integer Line;
|
||||
integer PoseCount;
|
||||
list Poses; // name of each pose with a prop
|
||||
list Positions; // position of prop, indexed as Poses
|
||||
list Props; // name of each prop object, indexed as Poses
|
||||
|
||||
string Pose; // current pose name
|
||||
|
||||
integer ChatChan; // chan for talking to object
|
||||
|
||||
init()
|
||||
{
|
||||
ChatChan = - 1 - (integer)llFrand(-DEBUG_CHANNEL);
|
||||
getRefPos();
|
||||
}
|
||||
|
||||
vector RefPos;
|
||||
rotation RefRot;
|
||||
|
||||
getRefPos() { //reference position
|
||||
RefPos = llGetPos();
|
||||
RefRot = llGetRot();
|
||||
integer z = (integer)llGetObjectDesc();
|
||||
RefPos.z = RefPos.z + (float)z/100.0;
|
||||
}
|
||||
|
||||
string plural(string singular, string plural, integer count) {
|
||||
if (count != 1) {
|
||||
return plural;
|
||||
}
|
||||
return singular;
|
||||
}
|
||||
|
||||
announce()
|
||||
{
|
||||
llOwnerSay((string)PoseCount
|
||||
+ plural(" pose", " poses", PoseCount)
|
||||
+ " with props ("
|
||||
+ llGetScriptName()
|
||||
+ ": "
|
||||
+ (string)llGetFreeMemory()
|
||||
+ " bytes free)");
|
||||
}
|
||||
|
||||
string adjust(integer doOffset, vector pos, vector erot, vector amt) {
|
||||
if (doOffset) {
|
||||
pos = pos + amt/100.;
|
||||
return (vround(pos) + "/" + vround(erot));
|
||||
}
|
||||
rotation amount = llEuler2Rot(amt * DEG_TO_RAD);
|
||||
erot *= DEG_TO_RAD;
|
||||
|
||||
rotation oldrot = llEuler2Rot(erot);
|
||||
rotation newrot = oldrot / amount;
|
||||
|
||||
erot = llRot2Euler(newrot) * RAD_TO_DEG;
|
||||
pos = pos / amount;
|
||||
return(vround(pos) + "/" + vround(erot));
|
||||
}
|
||||
|
||||
|
||||
adjust_all(integer doOffset, vector amt) {
|
||||
integer ix;
|
||||
integer bx;
|
||||
string data;
|
||||
list ldata;
|
||||
vector pos;
|
||||
vector erot;
|
||||
|
||||
|
||||
for (ix = 0; ix < llGetListLength(Poses); ++ix) {
|
||||
data = llList2String(Positions, ix);
|
||||
ldata = llParseString2List(data, ["/"], []);
|
||||
pos = (vector)llList2String(ldata, 0);
|
||||
erot = (vector)llList2String(ldata, 1);
|
||||
|
||||
data = adjust(doOffset, pos, erot, amt);
|
||||
Positions = llListReplaceList(Positions, (list)data, ix, ix);
|
||||
}
|
||||
llOwnerSay("Prop rotation complete");
|
||||
}
|
||||
|
||||
|
||||
|
||||
string roundData(string data) {
|
||||
list ldata = llParseString2List(data, ["/"], []);
|
||||
return (vround((vector)llList2String(ldata, 0)) + "/" + vround((vector)llList2String(ldata, 1)));
|
||||
}
|
||||
|
||||
// round a vector's components and return as vector value string
|
||||
string vround(vector vec) {
|
||||
return ("<"+round(vec.x, 3)+","+round(vec.y, 3)+","+round(vec.z, 3)+">");
|
||||
}
|
||||
|
||||
string round(float number, integer places) {
|
||||
float shifted;
|
||||
integer rounded;
|
||||
string s;
|
||||
shifted = number * llPow(10.0,(float)places);
|
||||
rounded = llRound(shifted);
|
||||
s = (string)((float)rounded / llPow(10.0,(float)places));
|
||||
s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
add_prop(string pose, string prop, string data) {
|
||||
if (llListFindList(Props, (list)pose) != -1) {
|
||||
llOwnerSay("Multiple *.PROPS* entries for pose '" + pose + "'");
|
||||
}
|
||||
if (llGetInventoryType(prop) != INVENTORY_OBJECT) {
|
||||
llOwnerSay("Warning: can't find prop '" + prop + "' in inventory");
|
||||
}
|
||||
Poses = [] + Poses + (list) pose;
|
||||
Props = [] + Props + (list) prop;
|
||||
Positions = [] + Positions + (list)roundData(data);
|
||||
++PoseCount;
|
||||
}
|
||||
|
||||
string get_pose_data(string pose) {
|
||||
integer ix = llListFindList(Poses, (list)pose);
|
||||
|
||||
if (ix == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return llList2String(Positions, ix);
|
||||
}
|
||||
|
||||
save_prop(string pose, string prop, string data) {
|
||||
integer ix = llListFindList(Poses, [pose]);
|
||||
if (ix == -1) {
|
||||
// llSay(0, "new pose");
|
||||
add_prop(pose, prop, data); // don't expect this to happen
|
||||
return;
|
||||
}
|
||||
|
||||
// if the prop object name doesn't match, ignore it -- assume it's noise
|
||||
if (llList2String(Props, ix) != prop) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Data is the change in position since we rezzed it, in global coords
|
||||
// Convert delta to local axes
|
||||
|
||||
list ldata = llParseString2List(data, ["/"], []);
|
||||
vector pos = (vector) llList2String(ldata, 0);
|
||||
rotation rot = (rotation)llList2String(ldata, 1);
|
||||
|
||||
pos = pos / RefRot;
|
||||
vector erot = llRot2Euler(rot/RefRot) * RAD_TO_DEG;
|
||||
|
||||
// Now add to saved data (since it was a delta)
|
||||
ldata = llParseStringKeepNulls(llList2String(Positions, ix), ["/"], []);
|
||||
vector oldpos = (vector)llList2String(ldata, 0);
|
||||
|
||||
pos = pos + oldpos;
|
||||
data = vround(pos) + "/" + vround(erot);
|
||||
|
||||
Props = llListReplaceList(Props, (list)prop, ix, ix);
|
||||
Positions = llListReplaceList(Positions, (list)data, ix, ix);
|
||||
|
||||
string name = llGetObjectName();
|
||||
llSetObjectName("");
|
||||
llOwnerSay("| " + pose + " | " + prop + " | " + data);
|
||||
llSetObjectName(name);
|
||||
}
|
||||
|
||||
rez_prop(string pose) {
|
||||
llSay(ChatChan, "DIE");
|
||||
integer ix = llListFindList(Poses, [pose]);
|
||||
if (ix == -1) {
|
||||
Pose = "";
|
||||
llSetTimerEvent(0.0);
|
||||
return;
|
||||
}
|
||||
string prop = llList2String(Props, ix);
|
||||
string data = llList2String(Positions, ix);
|
||||
list ldata = llParseString2List(data, ["/"], []);
|
||||
vector pos = (vector)llList2String(ldata, 0);
|
||||
vector erot = (vector)llList2String(ldata, 1);
|
||||
|
||||
pos = pos * RefRot + RefPos;
|
||||
rotation rot = llEuler2Rot(erot*DEG_TO_RAD) * RefRot;
|
||||
|
||||
// llSay(0, "rezzing '" + prop + "' at " + (string) pos);
|
||||
llRezAtRoot(prop, pos, <0.,0.,0.>, rot, ChatChan);
|
||||
llSetTimerEvent(60.0);
|
||||
Pose = pose;
|
||||
}
|
||||
|
||||
|
||||
dashes() {
|
||||
llOwnerSay("_______________________________________________________________________________");
|
||||
llOwnerSay("");
|
||||
}
|
||||
|
||||
|
||||
// Globals for reading card config
|
||||
integer ConfigLineIndex;
|
||||
list ConfigCards; // list of names of config cards
|
||||
string ConfigCardName; // name of card being read
|
||||
integer ConfigCardIndex; // index of next card to read
|
||||
key ConfigQueryId;
|
||||
|
||||
integer next_card()
|
||||
{
|
||||
if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
|
||||
ConfigCards = [];
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
ConfigLineIndex = 0;
|
||||
ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
|
||||
ConfigCardIndex++;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
|
||||
llOwnerSay("Reading " + ConfigCardName);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
llSleep(0.25); // give ~run a chance to shut us down
|
||||
string item;
|
||||
ConfigCards = [];
|
||||
integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
|
||||
while (n-- > 0) {
|
||||
item = llGetInventoryName(INVENTORY_NOTECARD, n);
|
||||
if (llSubStringIndex(item, ".PROPS") != -1) {
|
||||
ConfigCards = [] + ConfigCards + (list) item;
|
||||
}
|
||||
}
|
||||
|
||||
ConfigCardIndex = 0;
|
||||
ConfigCards = llListSort(ConfigCards, 1, TRUE);
|
||||
next_card();
|
||||
}
|
||||
|
||||
dataserver(key query_id, string data) {
|
||||
if (query_id != ConfigQueryId) {
|
||||
return;
|
||||
}
|
||||
if (data == EOF) {
|
||||
if (next_card()) {
|
||||
return;
|
||||
}
|
||||
state on;
|
||||
}
|
||||
|
||||
data = llStringTrim(data, STRING_TRIM);
|
||||
if (llGetSubString(data,0,0) != "/" && llStringLength(data)) { // skip comments and blank lines
|
||||
|
||||
list ldata = llParseStringKeepNulls(data, [" | "," | "," | "," | "," |","| ","|"], []);
|
||||
if (llGetListLength(ldata) != 4) {
|
||||
llOwnerSay(llGetScriptName() + ": error in " + ConfigCardName + ":" + (string)ConfigLineIndex
|
||||
+ " - need exactly 3 vertical bars - line ignored");
|
||||
} else {
|
||||
string pose = llList2String(ldata, 1);
|
||||
string prop = llList2String(ldata, 2);
|
||||
string data1 = llStringTrim(llList2String(ldata, 3), STRING_TRIM);
|
||||
if (data1 == "") {
|
||||
data1 = "<0,0,1>/<0,0,0>";
|
||||
}
|
||||
add_prop(pose, prop, data1);
|
||||
}
|
||||
}
|
||||
++ConfigLineIndex;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of positions notecard
|
||||
}
|
||||
|
||||
state_exit() {
|
||||
// do one save to indicate actual amount of available memory
|
||||
string position = llList2String(Positions, 0);
|
||||
Positions = llListReplaceList(Positions, [position],0,0);
|
||||
|
||||
llMessageLinked(LINK_THIS, 2, "OK", (key)""); //msg to menu, in case it's waiting for loading
|
||||
announce();
|
||||
}
|
||||
}
|
||||
|
||||
state re_on
|
||||
{
|
||||
state_entry() {
|
||||
state on;
|
||||
}
|
||||
}
|
||||
|
||||
state on {
|
||||
state_entry() {
|
||||
init();
|
||||
llListen(ChatChan, "", NULL_KEY, "");
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
state re_on;
|
||||
}
|
||||
|
||||
listen(integer chan, string name, key id, string msg) {
|
||||
// llSay(0, name + ": " + msg);
|
||||
if (Pose == "") {
|
||||
return;
|
||||
}
|
||||
save_prop(Pose, name, msg);
|
||||
announce();
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string str, key dkey) {
|
||||
|
||||
if (str == "PRIMTOUCH" || num < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == 0) {
|
||||
if (str == "POSEB") {
|
||||
rez_prop((string)dkey);
|
||||
return;
|
||||
}
|
||||
if (str == "REPOS") {
|
||||
getRefPos();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (num != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (str == "STOP") {
|
||||
llSay(ChatChan, "DIE");
|
||||
Pose = "";
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
if (str == "DUMPPROPS") {
|
||||
dashes();
|
||||
llOwnerSay("Copy to .PROPS; delete any other *.PROPS* cards");
|
||||
dashes();
|
||||
string name = llGetObjectName();
|
||||
llSetObjectName("");
|
||||
|
||||
integer ix;
|
||||
for (ix = 0; ix < PoseCount; ++ix) {
|
||||
string pose = llList2String(Poses, ix);
|
||||
string prop = llList2String(Props, ix);
|
||||
llOwnerSay("| " + pose + " | " + prop + " | " + get_pose_data(pose));
|
||||
}
|
||||
llSetObjectName(name);
|
||||
dashes();
|
||||
} else if (llSubStringIndex(str, "REORIENT=") == 0) {
|
||||
// Reorient command (LINKMENU command from .MENUITEMS file)
|
||||
// str format: REORIENT=OFF=<x,y,z> or REORIENT=ROT=<x,y,z> (in degrees)
|
||||
list parms = llParseString2List(str, ["="], []);
|
||||
vector amount = (vector)llList2String(parms, 2);
|
||||
llWhisper(0, "Adjusting props, please wait");
|
||||
|
||||
if (llList2String(parms, 1) == "OFF") {
|
||||
adjust_all(TRUE, amount);
|
||||
} else {
|
||||
adjust_all(FALSE, amount);
|
||||
}
|
||||
llMessageLinked(LINK_THIS, 0, "AGAIN", (key)"");
|
||||
llWhisper(0, "Prop adjustment complete");
|
||||
} else if (str == "SAVEPROP") {
|
||||
llSay(ChatChan, "SAVE");
|
||||
}
|
||||
}
|
||||
|
||||
timer() {
|
||||
llSay(ChatChan, "LIVE");
|
||||
}
|
||||
|
||||
}
|
||||
190
TGLM/~run.lsl
Normal file
190
TGLM/~run.lsl
Normal file
@@ -0,0 +1,190 @@
|
||||
//MLPV2 Version 2.3 - Learjeff Innis, from
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 20 06, by Miffy Fluffy (BSD License)
|
||||
//To donate, go to my profile (Search - People - Miffy Fluffy) and use the "Pay..." button, thanks!
|
||||
//You can also find the link to the latest version here.
|
||||
|
||||
integer MAX_AVS = 6;
|
||||
integer ResetOnOwnerChange = FALSE;
|
||||
|
||||
// DESCRIPTION OF THE SCRIPTS
|
||||
//
|
||||
// ~run:
|
||||
// Default: sets other scripts to not running.
|
||||
// When the object is touched it will start all scrips.
|
||||
//
|
||||
// ~memory:
|
||||
// Here the positions are stored permanently. Information is still kept when the script is
|
||||
// not running or when everything is placed in inventory. The information will be lost only
|
||||
// when the ~memory script is reset.
|
||||
// A backup can be made on the .POSITIONS notecard, when the memory is empty, it will start
|
||||
// reading the .POSITIONS notecard automatically.
|
||||
//
|
||||
// ~menu:
|
||||
// 1.loading: reads the .MENUITEMS notecard and builds the menu.
|
||||
// When it reads a "POSE": - the animations are stored in ~pose
|
||||
// - their matching positions are looked up in ~memory and stored
|
||||
// in ~pos.
|
||||
// 2.ready:
|
||||
// When the object is touched: - shows the main menu
|
||||
// - listens for menu selections.
|
||||
//
|
||||
// When a submenu is selected: - shows the submenu
|
||||
// - when balls are defined for this submenu it will rez
|
||||
// balls (if not already there) and set their colors.
|
||||
//
|
||||
// When a pose is selected: - ~pose will send the animations to ~pose1 and ~pose2,
|
||||
// they will set the animations to the avatars
|
||||
// - ~pos wil send the matching positions to each ball.
|
||||
//
|
||||
// When a position is saved: - ~pose will ask the balls for their position
|
||||
// - the positions are saved in ~memory ("permanent")
|
||||
// - the positions are updated in ~pos
|
||||
//
|
||||
// When "STOP" is selected: - will hide the balls
|
||||
// - will stop the pose
|
||||
// When "STOP" is selected again (or if no pose is started yet):
|
||||
// - will remove the balls (derez/die)
|
||||
//
|
||||
// ~pos:
|
||||
// - loads the positions from ~memory and stores them (until shutdown/restart)
|
||||
// - sends positions for the selected pose to the balls
|
||||
//
|
||||
// ~pose:
|
||||
// - loads the animations from the .MENUITEMS notecard and stores them (until shutdown/restart)
|
||||
// - sends animations for the selected pose to ~pose1 and ~pose2
|
||||
// - when saving a position: will ask balls for their position and sends it to ~pos and ~memory
|
||||
// (~pos would be a more logical place to handle this, but ~pose has more free memory).
|
||||
//
|
||||
// ~poser, ~poser 1, ~poser 2, ~poser 3 (one for each ball):
|
||||
// - will ask permission to animate the avatar on ball
|
||||
// - will set the animations to avatar
|
||||
//
|
||||
// ~ball
|
||||
// - when balls are defined for a submenu (in .MENUITEMS), ~menu will rez copies of ~ball
|
||||
// - each will receive a unique communication channel from ~menu
|
||||
// - the color for each ball is set by ~menu
|
||||
// - the position of each ball is set by ~pos
|
||||
// - when an avatar selects to sit on a ball, the avatar info is sent to the appropriate; they
|
||||
// will ask permission and set the animation directly to the avatar (not via the ball)
|
||||
// - balls will commit suicide when they don't hear a "LIVE" message each minute (from ~menu).
|
||||
//
|
||||
// have fun!
|
||||
|
||||
//Note: if you make a revised version, please mention something like this:
|
||||
//"MLP - alternative version by ... .... - Revision 1 (based on MLP V1.2 by Miffy Fluffy)
|
||||
|
||||
key Owner;
|
||||
|
||||
list Scripts = [
|
||||
"~menucfg"
|
||||
, "~pos"
|
||||
, "~pose"
|
||||
, "~poser"
|
||||
, "~poser 1"
|
||||
, "~poser 2"
|
||||
, "~poser 3"
|
||||
, "~poser 4"
|
||||
, "~poser 5"
|
||||
];
|
||||
|
||||
list OptionalScripts = [
|
||||
"~props"
|
||||
, "~sequencer"
|
||||
];
|
||||
|
||||
setRunning(integer st) {
|
||||
integer ix;
|
||||
list scripts = Scripts;
|
||||
string script;
|
||||
|
||||
for (ix = 0; ix < 100; ++ix) {
|
||||
integer jx;
|
||||
|
||||
// try to stop any remaining scripts in the list
|
||||
for (jx = llGetListLength(scripts) - 1; jx >= 0; --jx) {
|
||||
script = llList2String(scripts, jx);
|
||||
if (llGetInventoryType(script) == INVENTORY_SCRIPT) {
|
||||
llSetScriptState(script, st);
|
||||
scripts = llDeleteSubList(scripts, jx, jx);
|
||||
--jx;
|
||||
}
|
||||
}
|
||||
|
||||
// got them all yet?
|
||||
if (llGetListLength(scripts) == 0) {
|
||||
// Yes -- handle key ones
|
||||
llSetScriptState("~memory", st);
|
||||
llSetScriptState("~menu", st);
|
||||
if (st) {
|
||||
llResetOtherScript("~memory");
|
||||
llResetOtherScript("~menu");
|
||||
}
|
||||
|
||||
// start/stop optional scripts if present
|
||||
for (jx = llGetListLength(OptionalScripts) - 1; jx >= 0; --jx) {
|
||||
script = llList2String(OptionalScripts, jx);
|
||||
if (llGetInventoryType(script) == INVENTORY_SCRIPT) {
|
||||
llSetScriptState(script, st);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
llSleep(0.1);
|
||||
}
|
||||
|
||||
llOwnerSay("missing scripts: " + llList2CSV(scripts));
|
||||
}
|
||||
|
||||
setBalls(string cmd) {
|
||||
integer ch = channel();
|
||||
integer ix;
|
||||
|
||||
for (ix = 0; ix < MAX_AVS; ++ix) {
|
||||
llSay(ch + ix, cmd); //msg to balls
|
||||
}
|
||||
}
|
||||
|
||||
integer channel() {
|
||||
return (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1));
|
||||
}
|
||||
|
||||
default {
|
||||
|
||||
state_entry() {
|
||||
setBalls("DIE");
|
||||
Owner = llGetOwner();
|
||||
setRunning(FALSE);
|
||||
llOwnerSay("OFF (touch to switch on)");
|
||||
}
|
||||
|
||||
touch_start(integer i) {
|
||||
if (llDetectedKey(0) == llGetOwner()) state run;
|
||||
}
|
||||
|
||||
// Waits for another script to send a link message.
|
||||
link_message(integer sender_num, integer num, string str, key id) {
|
||||
if (str == "PRIMTOUCH" && id == llGetOwner()) {
|
||||
state run;
|
||||
}
|
||||
}
|
||||
|
||||
changed(integer change) {
|
||||
if (change & CHANGED_OWNER && Owner != llGetOwner()) {
|
||||
llResetScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state run {
|
||||
state_entry() {
|
||||
setRunning(TRUE);
|
||||
}
|
||||
changed(integer change) {
|
||||
if (ResetOnOwnerChange
|
||||
&& (change & CHANGED_OWNER)
|
||||
&& Owner != llGetOwner()) {
|
||||
llResetScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
447
TGLM/~sequencer.lsl
Normal file
447
TGLM/~sequencer.lsl
Normal file
@@ -0,0 +1,447 @@
|
||||
//MPLV2 Version 2.3 by Learjeff Innis, based on
|
||||
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Mi ffy Fluffy (BSD License)
|
||||
|
||||
// Allow programmed sequences of poses
|
||||
|
||||
// This script resets whenever any of its config cards change.
|
||||
|
||||
integer MAX_AVS = 6;
|
||||
|
||||
list SeqNames; // name of each sequence
|
||||
list SeqSteps; // CSV of steps for each seq, indexed as SeqNames
|
||||
list CurSeqSteps;
|
||||
|
||||
string CurSeqName;
|
||||
integer CurSeqStepIx;
|
||||
string CurMenu;
|
||||
string CurPose;
|
||||
|
||||
// debugs:
|
||||
// 1 = sequence start/stop
|
||||
// 2 = echo each step as executed
|
||||
// 4 = av hop on/off
|
||||
// 8 = avwait check
|
||||
// 0x10 = debug config
|
||||
|
||||
|
||||
integer Debug;
|
||||
|
||||
list DELIMS = [" | "," | "," | "," | "," |","| ","|"];
|
||||
|
||||
list COMMANDS = [
|
||||
"MENU"
|
||||
, "POSE"
|
||||
, "WAIT"
|
||||
, "REPEAT"
|
||||
, "LABEL"
|
||||
, "GOTO"
|
||||
, "STOP"
|
||||
, "WHISPER"
|
||||
, "SAY"
|
||||
, "AVWAIT"
|
||||
];
|
||||
|
||||
config_init() {
|
||||
SeqNames = [];
|
||||
SeqSteps = [];
|
||||
Debug = 0;
|
||||
}
|
||||
|
||||
config_done() {
|
||||
seq_save(); // save last sequence, if any
|
||||
debug(0x10, "Names: " + llList2CSV(SeqNames));
|
||||
}
|
||||
|
||||
parse_config_line(string data) {
|
||||
if (llGetSubString(data,0,0) == "/" || llStringLength(data) == 0) { // skip comments and blank lines
|
||||
return;
|
||||
}
|
||||
|
||||
list ldata = llParseStringKeepNulls(data, DELIMS, []);
|
||||
string cmd = llList2String(ldata, 0);
|
||||
string arg1 = llList2String(ldata, 1);
|
||||
string arg2 = llList2String(ldata, 2);
|
||||
string arg3 = llList2String(ldata, 3);
|
||||
|
||||
if (cmd == "SEQUENCE") {
|
||||
seq_save(); // save previous sequence, if any
|
||||
CurSeqName = arg1;
|
||||
CurSeqSteps = [];
|
||||
} else if (llListFindList(COMMANDS, (list)cmd) >= 0) {
|
||||
if (cmd == "LABEL") {
|
||||
CurSeqSteps += (list) (cmd + "|" + arg1);
|
||||
} else {
|
||||
CurSeqSteps += (list) (cmd + "|" + arg1 + "|" + arg2 + "|" + arg3);
|
||||
}
|
||||
} else if (cmd == "debug") {
|
||||
Debug += (integer)arg1;
|
||||
} else {
|
||||
llWhisper(0, "Unknown sequence command: '" + cmd + "' - ignoring");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
list Avnames; // one for each ball
|
||||
integer Avwait;
|
||||
list AvwaitBalls;
|
||||
|
||||
// List of avatar names per ball: adding/removing/checking
|
||||
|
||||
addAv(string name, integer ballIx) {
|
||||
Avnames = llListReplaceList(Avnames, (list)name, ballIx, ballIx);
|
||||
if (Avwait && avs_seated()) {
|
||||
Avwait = FALSE;
|
||||
llSetTimerEvent(0.1);
|
||||
}
|
||||
}
|
||||
|
||||
removeAv(integer ballIx) {
|
||||
addAv("", ballIx);
|
||||
}
|
||||
|
||||
integer avs_seated() {
|
||||
integer ix;
|
||||
integer ball;
|
||||
for (ix = llGetListLength(AvwaitBalls) - 1; ix >= 0; --ix) {
|
||||
ball = llList2Integer(AvwaitBalls, ix);
|
||||
if (llList2String(Avnames, ball) == "") {
|
||||
debug(8, "Nobody on ball " + (string) ball);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
debug(8, "All avs seated");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// In 'src', replace 'target' string with 'replacement' string,
|
||||
// and return the result.
|
||||
|
||||
string replace_text(string src, string target, string replacement)
|
||||
{
|
||||
string text = src;
|
||||
integer ix;
|
||||
|
||||
ix = llSubStringIndex(src, target);
|
||||
|
||||
if (ix >= 0) {
|
||||
text = llDeleteSubString(text, ix, ix + llStringLength(target) - 1);
|
||||
text = llInsertString(text, ix, replacement);
|
||||
}
|
||||
|
||||
return (text);
|
||||
}
|
||||
|
||||
string firstname(string name) {
|
||||
return llList2String(llParseString2List(name, [" "], []), 0);
|
||||
}
|
||||
|
||||
string customize(string src) {
|
||||
integer avix;
|
||||
string avname;
|
||||
for (avix = 0; avix < MAX_AVS; ++avix) {
|
||||
avname = firstname(llList2String(Avnames, avix));
|
||||
if (avname == "") avname = "somebody";
|
||||
src = replace_text(src, "/"+(string)avix, avname);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
|
||||
send_cmd(string cmd) {
|
||||
llMessageLinked(LINK_THIS, -12002, cmd, (key)"");
|
||||
}
|
||||
|
||||
|
||||
seq_save() {
|
||||
if (CurSeqName == "") {
|
||||
return;
|
||||
}
|
||||
SeqNames += CurSeqName;
|
||||
SeqSteps += llList2CSV(CurSeqSteps);
|
||||
}
|
||||
|
||||
seq_start(string name) {
|
||||
Avwait = FALSE;
|
||||
integer ix = llListFindList(SeqNames, (list)name);
|
||||
if (ix < 0) {
|
||||
llWhisper(0, "No such sequence: '" + name + "'");
|
||||
CurSeqSteps = [];
|
||||
CurSeqStepIx = -1;
|
||||
return;
|
||||
}
|
||||
debug(1, "Start sequence " + name);
|
||||
|
||||
CurSeqStepIx = 0;
|
||||
CurSeqSteps = llCSV2List(llList2String(SeqSteps, ix));
|
||||
seq_execute();
|
||||
}
|
||||
|
||||
seq_advance() {
|
||||
if (++CurSeqStepIx >= llGetListLength(CurSeqSteps)) {
|
||||
seq_stop();
|
||||
}
|
||||
}
|
||||
|
||||
seq_execute() {
|
||||
list step;
|
||||
string cmd;
|
||||
string arg1;
|
||||
string arg2;
|
||||
string arg3;
|
||||
|
||||
while (CurSeqStepIx >= 0) {
|
||||
step = llParseString2List(llList2String(CurSeqSteps, CurSeqStepIx), DELIMS, []);
|
||||
cmd = llList2String(step, 0);
|
||||
arg1 = llList2String(step, 1);
|
||||
arg2 = llList2String(step, 2);
|
||||
arg3 = llList2String(step, 3);
|
||||
|
||||
debug(2, cmd + "|" + arg1);
|
||||
|
||||
if (cmd == "MENU") {
|
||||
CurMenu = arg1;
|
||||
send_cmd(CurMenu);
|
||||
seq_advance();
|
||||
} else if (cmd == "POSE") {
|
||||
// llSleep(.5);
|
||||
CurPose = arg1;
|
||||
send_cmd(arg1);
|
||||
if (arg3 != "") {
|
||||
llWhisper((integer)arg2, customize(arg3));
|
||||
}
|
||||
seq_advance();
|
||||
} else if (cmd == "WAIT") {
|
||||
llSetTimerEvent((float) arg1);
|
||||
seq_advance();
|
||||
return;
|
||||
} else if (cmd == "REPEAT") {
|
||||
CurSeqStepIx = 0;
|
||||
} else if (cmd == "LABEL") {
|
||||
seq_advance();
|
||||
} else if (cmd == "GOTO") {
|
||||
CurSeqStepIx = llListFindList(CurSeqSteps, (list)("LABEL|" + arg1));
|
||||
if (CurSeqStepIx < 0) {
|
||||
llWhisper(0, "No such sequence label: '" + arg1 + "'");
|
||||
seq_stop();
|
||||
return;
|
||||
}
|
||||
} else if (cmd == "WHISPER") {
|
||||
llWhisper((integer)arg1, customize(arg2));
|
||||
seq_advance();
|
||||
} else if (cmd == "SAY") {
|
||||
llSay((integer)arg1, customize(arg2));
|
||||
seq_advance();
|
||||
} else if (cmd == "AVWAIT") {
|
||||
integer argix;
|
||||
integer ballix;
|
||||
AvwaitBalls = [];
|
||||
list balls = llParseString2List(arg1, [" "], []);
|
||||
for (argix = llGetListLength(balls) - 1; argix >= 0; --argix) {
|
||||
ballix = (integer)llList2String(balls, argix);
|
||||
AvwaitBalls += (list)(ballix);
|
||||
}
|
||||
|
||||
seq_advance();
|
||||
if (! avs_seated()) {
|
||||
llSetTimerEvent(0.); // just to be sure
|
||||
if (arg2 != "") {
|
||||
llWhisper(0, arg2);
|
||||
}
|
||||
Avwait = TRUE;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
send_cmd(cmd);
|
||||
seq_advance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seq_stop() {
|
||||
Avwait = FALSE;
|
||||
debug(1, "stopping sequence");
|
||||
CurSeqStepIx = -1;
|
||||
llSetTimerEvent(0.);
|
||||
}
|
||||
|
||||
debug(integer level, string txt) {
|
||||
if (Debug & level) {
|
||||
llWhisper(0, llGetScriptName() + ": " + txt);
|
||||
}
|
||||
}
|
||||
|
||||
string plural(string singular, string plural, integer count) {
|
||||
if (count != 1) {
|
||||
return plural;
|
||||
}
|
||||
return singular;
|
||||
}
|
||||
|
||||
announce()
|
||||
{
|
||||
integer count = llGetListLength(SeqNames);
|
||||
llOwnerSay((string)count
|
||||
+ plural(" sequence (", " sequences (", count)
|
||||
+ llGetScriptName()
|
||||
+ ": "
|
||||
+ (string)llGetFreeMemory()
|
||||
+ " bytes free)");
|
||||
}
|
||||
|
||||
|
||||
// Globals for reading card config
|
||||
integer ConfigLineIndex;
|
||||
list ConfigCards; // list of names of config cards
|
||||
string ConfigCardName; // name of card being read
|
||||
integer ConfigCardIndex; // index of next card to read
|
||||
key ConfigQueryId;
|
||||
string ConfigCardKeys; // to see if anything changed
|
||||
|
||||
string get_cards() {
|
||||
ConfigCards = [];
|
||||
string keys = "";
|
||||
string item;
|
||||
|
||||
integer ix = llGetInventoryNumber(INVENTORY_NOTECARD);
|
||||
while (ix-- > 0) {
|
||||
item = llGetInventoryName(INVENTORY_NOTECARD, ix);
|
||||
if (llSubStringIndex(item, ".SEQUENCES") >= 0) {
|
||||
ConfigCards += (list) item;
|
||||
keys += (string)llGetInventoryKey(item);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
integer next_card()
|
||||
{
|
||||
if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
|
||||
ConfigCards = [];
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
ConfigLineIndex = 0;
|
||||
ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
|
||||
ConfigCardIndex++;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
|
||||
llOwnerSay("Reading " + ConfigCardName);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
ConfigCardKeys = get_cards();
|
||||
ConfigCardIndex = 0;
|
||||
ConfigCards = llListSort(ConfigCards, 1, TRUE);
|
||||
if (! next_card()) {
|
||||
state on;
|
||||
}
|
||||
}
|
||||
|
||||
dataserver(key query_id, string data) {
|
||||
if (query_id != ConfigQueryId) {
|
||||
return;
|
||||
}
|
||||
if (data == EOF) {
|
||||
if (next_card()) {
|
||||
return;
|
||||
}
|
||||
state on;
|
||||
}
|
||||
|
||||
parse_config_line(llStringTrim(data, STRING_TRIM));
|
||||
++ConfigLineIndex;
|
||||
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of positions notecard
|
||||
}
|
||||
|
||||
state_exit() {
|
||||
config_done();
|
||||
announce();
|
||||
}
|
||||
}
|
||||
|
||||
state re_on
|
||||
{
|
||||
state_entry() {
|
||||
state on;
|
||||
}
|
||||
}
|
||||
|
||||
state on {
|
||||
state_entry() {
|
||||
Avnames = [];
|
||||
integer ix;
|
||||
for (ix = 0; ix < MAX_AVS; ++ix) {
|
||||
Avnames += (list)"";
|
||||
}
|
||||
}
|
||||
|
||||
on_rez(integer arg) {
|
||||
state re_on;
|
||||
}
|
||||
|
||||
link_message(integer from, integer num, string str, key dkey) {
|
||||
|
||||
if (str == "PRIMTOUCH") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == 0 && str == "POSEB") {
|
||||
if ((string)dkey != CurPose) {
|
||||
seq_stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == 1 && str == "STOP") {
|
||||
seq_stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == -11000) {
|
||||
// av hopped on
|
||||
list parms = llParseStringKeepNulls(str, ["|"], []);
|
||||
integer ballnum = (integer)llList2String(parms, 0);
|
||||
// string anim = llList2String(parms, 1); // anim name parameter, if desired
|
||||
debug(4, llKey2Name(dkey) + ": on ball " + (string)ballnum);
|
||||
addAv(llKey2Name(dkey), ballnum);
|
||||
return;
|
||||
|
||||
} else if (num == -11001) {
|
||||
// av hopped off
|
||||
debug(4, llKey2Name(dkey) + ": off ball " + str);
|
||||
removeAv((integer)str);
|
||||
return;
|
||||
|
||||
} else if (num != -12001) {
|
||||
return;
|
||||
}
|
||||
|
||||
list ldata = llParseString2List(str, [" "], []);
|
||||
string cmd = llList2String(ldata, 0);
|
||||
if (cmd == "SEQUENCE") {
|
||||
seq_start(llList2String(ldata, 1));
|
||||
} else if (cmd == "PAUSE") {
|
||||
debug(1, "pausing");
|
||||
llSetTimerEvent(0.);
|
||||
} else if (cmd == "RESUME") {
|
||||
debug(1, "resuming");
|
||||
llSetTimerEvent(.1);
|
||||
}
|
||||
}
|
||||
|
||||
timer() {
|
||||
seq_execute();
|
||||
}
|
||||
|
||||
changed(integer change) {
|
||||
if (change & CHANGED_INVENTORY) {
|
||||
if (get_cards() != ConfigCardKeys) {
|
||||
llResetScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
39
TGLM/~timeout.lsl
Normal file
39
TGLM/~timeout.lsl
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
float Timeout = 3600.;
|
||||
key Owner;
|
||||
|
||||
default
|
||||
{
|
||||
state_entry() {
|
||||
Owner = llGetOwner();
|
||||
}
|
||||
|
||||
link_message(integer sender, integer num, string str, key id) {
|
||||
|
||||
if (str == "PRIMTOUCH") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == 0 && str == "POSEB") {
|
||||
llSetTimerEvent(Timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == 1 && str == "STOP") {
|
||||
llSetTimerEvent(0.);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
timer() {
|
||||
llMessageLinked(LINK_THIS, -12002, "STOP", (key)"");
|
||||
llSetTimerEvent(0.);
|
||||
}
|
||||
|
||||
changed(integer change) {
|
||||
if ((change & CHANGED_OWNER) && llGetOwner() != Owner) {
|
||||
Owner = llGetOwner();
|
||||
llSetScriptState(llGetScriptName(), FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user