unpacked files

This commit is contained in:
Fred Beckhusen
2023-02-14 12:08:06 -06:00
parent 73c782d47e
commit 169fb179da
77 changed files with 19171 additions and 0 deletions

21
TGLM/MENUITEMS.Test.txt Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}
}
}