448 lines
11 KiB
Plaintext
448 lines
11 KiB
Plaintext
//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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|