Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Token Sequence Recogniser (With Example)

Mezzanine Peregrine
Senior Member
Join date: 14 Nov 2003
Posts: 113
01-05-2004 12:32
I guess I may as well post some of my scripts

Lets start with the Sequence Recogniser.

Example uses:
Recognising movement combos: (for example, in the
FWD,FWD,BACK,FWD,LEFT --> Activate main guns!)

Or any other sequence
A,B,C,D,A,F,G -> unlock door
1,9,4,3,2 -> do something
happy happy happy -> etc

code:

// Mezzanine Peregrine presents
// The sequence recogniser
// Feel free to use and modify.
// Please leave my name on it at
// the very least. Actually,
// forget that, I dont care,
// leave it on if you want to,
// or don't, whatever.

// Recognises a sequence of tokens
// causes events to be triggered when that movement command is sequenced.

// To use this, just drop it onto a thing that you want to be able to recog. sequences.

// only one per link set

// To use it, do the following on the script you want to listen for sequences
// NEVER MODIFY THIS SCRIPT, it doesnt need to be modified to work!
// first, clear the sequences (remember, these goe on the thing that you want
// to listen, not this script).
// llMessageLinked(LINK_SET,0,"recog,clear",NULL_KEY);
// then, add the sequences you'd like it to recognise. they can be anything.
// The first thing after the command is the NAME.
// llMessageLinked(LINK_SET,0,"recog,addseq,HADOKEN,back,back,forward,jump",NULL_KEY);
// llMessageLinked(LINK_SET,0,"recog,addseq,FLUFFY,happy,socks,lettuce,tape",NULL_KEY);
// llMessageLinked(LINK_SET,0,"recog,addseq,FIBBONACCI,1,1,2,3,5,8,13",NULL_KEY);
// Now, add a link_message(...) event
// Whenever a sequence is recognised, it will send the NAME.
// if (msg=="HADOKEN";) ... do stuff ... etc...!
// its that simple.
// commands
// recog,listsequences -- shows you what seqs are saved
// recog,reset -- resets the token watchers to zero (does not remove sequences)
// recog,clear -- removes all sequences
// recog,addsequence -- as above


list sequences;
list sequence_names;
list sequence_states;

integer sender_from = 0;

listsequences()
{
if (llGetListLength(sequences)==0)
{
llWhisper(0,"SQ: No sequences defined. Ignored.";);
return;
}

integer counter;
for (counter=0;counter < llGetListLength(sequences);counter++)
{
list currentsequence = llCSV2List(llList2String(sequences,counter));
llWhisper(0,"Sequence: " + llList2CSV(currentsequence));
}
}

addsequence(string sequencename,list sequencelist)
{
sequence_names += sequencename;
string sequence_string = llList2CSV(sequencelist);
sequences += [sequence_string];
sequence_states += [0];
}

FireSequence(integer which)
{
string sequencename = llList2String(sequence_names,which);
llMessageLinked(sender_from,0,sequencename,NULL_KE
Y);
}

ResetSequenceState(integer which)
{
// called when which failed to match.
// we need to change that list element to zero
sequence_states = llDeleteSubList(sequence_states,which,which);
sequence_states = llListInsertList(sequence_states,[0],which);
}

reset_sequences()
{
sequence_states = [];
integer counter;
for (counter=0;counter < llGetListLength(sequences);counter++)
{
sequence_states += [0];
}
}




IncrementSequenceState(integer which,integer sequence_length)
{
// called when a token matching the which'th sequence is accepted
// Did we just bump into the end of the sequence?
// get current position'

integer position = llList2Integer(sequence_states,which);

position = position + 1;

if (position == sequence_length)
{
// jackpot.
position = 0;
ResetSequenceState(which);
FireSequence(which);
}
else
{
sequence_states = llDeleteSubList(sequence_states,which,which);
sequence_states = llListInsertList(sequence_states,[position],which)
;
}

}


recognisetoken(string token)
{
if (llGetListLength(sequences)==0)
{
return;
}

integer counter;
for (counter=0;counter < llGetListLength(sequences);counter++)
{
list currentsequence = llCSV2List(llList2String(sequences,counter));
if (llGetListLength(currentsequence)!=0)
{
// Okay, we're in a sequence.
string expected_token = llList2String(currentsequence,llList2Integer(seque
nce_states,counter));
if (expected_token==token)
{

integer sequence_length = llGetListLength(currentsequence);
// match = trigger or continue.
IncrementSequenceState(counter,sequence_length);
}
else
{
// no match = reset
ResetSequenceState(counter);
// But does the sequence start with this token?
expected_token = llList2String(currentsequence,llList2Integer(seque
nce_states,counter));
if (expected_token==token)
{
integer sequence_length = llGetListLength(currentsequence);
// match = trigger or continue.
IncrementSequenceState(counter,sequence_length);
}
}
}
}
}


default
{

link_message(integer sender_num,integer num,string str,key thekey)
{
// lets parse the string
list stringlist;
stringlist = llParseString2List(str,[","],[]);
if (llList2String(stringlist,0)!="recog";) return;

sender_from = sender_num;

// pop it
stringlist = llDeleteSubList(stringlist,0,0);
string command = llList2String(stringlist,0);
// pop it
stringlist = llDeleteSubList(stringlist,0,0);

if (command=="clear";)
{
sequences = [];
sequence_states = [];
return;
}
if (command=="addseq";)
{
// then its the name
string sequencename = llList2String(stringlist,0);
stringlist = llDeleteSubList(stringlist,0,0);
addsequence(sequencename,stringlist);
return;

}
if (command=="token";)
{
// we recieved a token.
// check our token chain and match sequences
// if we match a sequence, we whisper to the last sender
recognisetoken(llList2String(stringlist,0));
}
if (command=="reset";)
{
reset_sequences();
}
if (command=="listsequences";)
{
listsequences();
}

}
}
Mezzanine Peregrine
Senior Member
Join date: 14 Nov 2003
Posts: 113
01-07-2004 17:05
Example of use:

Create another script on the parent object in the linked set(or the same object, even, anywhere else).

Drag and drop the sequence recogniser onto any part of the object set (including children, parents, same object, whatever). You only need ONE sequence recogniser ANYWHERE in the set for it to work. You never need to modify the recogniser for it to work, its a 'commander-troops' arrangement.

First, a utility to send tokens:

CODE

sendtoken(string tok)
{
string sendstring = "recog,token," + tok;
llMessageLinked(LINK_SET,0,sendstring,NULL_KEY);
}



... (and now, lets add some sequences). Put this on the script you want to command the sequence recogniser with:

CODE

// clear sequences
llMessageLinked(LINK_SET,0,"recog,clear",NULL_KEY);
// Add sequences
llMessageLinked(LINK_SET,0,"recog,addseq,ArmGuns,BACK,BACK,FWD",NULL_KEY);
llMessageLinked(LINK_SET,0,"recog,addseq,FireGuns,LEFT,RIGHT,FWD",NULL_KEY);
llMessageLinked(LINK_SET,0," recog,addseq,SuperEscapeMode,RIGHT,LEFT,FWD,JUMP,D
OWN",NULL_KEY);



... (and now, all thats left to do is to send the tokens at the appropriate moment and then act apon them when the sequences are recognised).

CODE

control(key which,integer level,integer edge)
{
if (edge & CONTROL_FWD)
{
if (level & CONTROL_FWD)
{
sendtoken("FWD");
}
}

if (edge & CONTROL_BACK)
{
if (level & CONTROL_BACK)
{
sendtoken("BACK");
}
}

// ... ETC for FWD,LEFT,JUMP,etc
}




(Finally, lets act apon sequence recognition)
CODE


link_message(integer sender,integer num,string str,key thekey)
{
if (str=="ArmGuns")
{
// do whatever
}
if (str=="FireGuns")
{
// do whatever
}
}
// etc




Why is the sequencer especially nifty?

- It is designed to recognise any sequence of any number of tokens (memory permitting)

- The actual recogniser never needs to be modified. Its a 'slave' to whatever 'commander' script sends it messages, and it reports back to the 'commander'.

- The recogniser can recieve tokens from any number of sources, and will report the match of a squence to the one who initially fed it the sequences (only).

- You only need one sequence recogniser in a linked set and it can contain many sequences.

- Can be used for adding more combos to movement, vehicles, games, whatever.

Notes

YES, you can do it all without the sequencer. But the point is it makes it neat and easy.