Clubmaster Server Version

From Fire And Ice Grid
Jump to navigation Jump to search


Clubmaster Introduction

Clubmaster is a widely used dance system, this Covey Mod allows it to also work with remotes reducing sim load when multiple dance balls are required on the same sim
Notecards have two extensions in this repository. .xml is for XML style notecards - but should still be copy/pasted as notecards inworld .txt is for a TEXT style notecard - just a notecard inworld
The full repository can be found on GitHub https://github.com/manwapastorelli/Clubmaster

Repository Branches

There are two branches, one contains the original Clubmaster code by Aine Caoimhe, with the Covey Modified version in the master branch.

Assembly From Scratch

  1. Make a prim and place the "~Clubmaster poseball v2.lsl" script into the prim.
  2. Take this prim to your inventory and call it "~club poseball" with the quotation marks
  3. Make a new prim which will be the main dance ball
  4. Add the "~club poseball" into the dance balls inventory along with all other scripts and notecards from this repository.

Upgrade Existing Clubmaster V2

  1. Replace the existing Clubmaster control script with this version
  2. Make a prim for the remote and add the remote script into the inventory

Clubmaster Remotes Script

1 default
2 {  
3     touch_start(integer any)
4     {
5         key toucher = llDetectedKey(0);
6         integer RemoteChannel = -741285681;
7         llRegionSay(RemoteChannel, (string)toucher);
8     }
9 }


Amended Clubmaster Script

   1 // PARAMOUR CLUBMASTER DANCE CONTROLLER (OSSL) v2.0
   2 // Aine Caoimhe Sept 2014 (v2.0 Jan 2016)
   3 // Minor modifications by Sara Payne August 2020 to allow remotes.
   4 // Provided under Creative Commons Attribution-Non-Commercial-ShareAlike 4.0 International license.
   5 // Please be sure you read and adhere to the terms of this license: https://creativecommons.org/licenses/by-nc-sa/4.0/
   6 //
   7 // *** THIS SCRIPT REQUIRES (AND WILL ONLY WORK) IN REGIONS WHERE THE SCRIPT OWNER HAS OSSL FUNCTION PERMISSIONS ***
   8 // See Read Me notecard for instructions
   9 //
  10 // ******************************************************************************
  11 // *                        BASIC USER VARIABLES                                *
  12 // ******************************************************************************
  13 // this section contains settings that you may wish to change for your use and requires little or no scripting knowledge
  14 string groupStyle="01 Unisex";                         // name of a singles dance style that you want to set as the group dance...will use 1st singles style if left blank or a non-existent style is specified
  15 integer errorCheck=FALSE;                               // TRUE: do full error-checking of name, animations, contents, etc on start-up (slow) or FALSE: skip all error-checking
  16 integer showFloatyText=TRUE;                            // TRUE allows text to be displayed or FALSE to hide all floaty text during operation
  17 string floatyText="Clubmaster Dance Machine v2.0";      // text above the main dance controller
  18 vector floatyTextColour=<0.941, 0.847, 0.459>;          // colour of the text above the main controller <R,G,B> where <0,0,0> is black, <1,1,1> is white
  19 integer randomizeSinglesOrder=TRUE;                     // when initializing, randomize the order of the dances within each singles dance style (style order is always displayed alphabetical) TRUE= yes, FALSE = no
  20 integer randomizeNpcOrder=FALSE;                        // when initializing, randomize the order of NPCs (otherwise it's the order found in inventory)
  21 float autoTimer=120.0;                                  // for group dance, singles dances, and couples in auto mode, how often (in seconds) to advance to the next animation
  22 float zGlobal=0.0001;                                   // global Z offset to apply to all couples dance positions ...for regions running 0.8.2 or earlier use 0.0001....for 0.9 or later try a value of -0.15
  23 //
  24 // ******************************************************************************
  25 // *                       ADVANCED USER VARIABLES                              *
  26 // ******************************************************************************
  27 // this section contains settings for slightly more advanced users but doesn't require much expertise
  28 string singlesNotecard="~Singles Data";                 // name of the notecard containing all of the singles dances data
  29 string animNotecard="~Couples Data";                    // name of the notecard containing all of the couples dances data
  30 string npcMatcherCard="!!NPC MATCHMAKER";               // name of the notecard (if any) containing NPC matchmaker data (see instructions)
  31 string poseballName="~club poseball";                   // name of the poseball to rez from inventory for couples - update if you rename the poseball for any reason
  32 string prefixM=".NPCM";                                 // NPCs for the male poseball have notecards with name that begin with this string
  33 string prefixF=".NPCF";                                 // NPCs for the female poseball have notecards with name that begin with this string
  34 integer ballTimeout=30;                                 // seconds until a couples ball should self-destruct (passed to ball on-rez) -- must be INTEGER type since it is compared to a UNIX timestamp
  35 float zStep=0.01;                                       // when couples zAdjust is enabled, vertical adjustment (in m) to make for the avatar with each press of the page up/page down keys
  36 list firstNameM=["Dance"];                              // list of first names to randomly choose from for the male NPC (if only one name is supplied it will always be used)
  37 list lastNameM=["Partner"];                             // list of last names to randomly choose from for the male NPC  (if only one name is supplied it will always be used)
  38 list firstNameF=["Dance"];                              // list of first names to randomly choose from for the female NPC (if only one name is supplied it will always be used)
  39 list lastNameF=["Partner"];                             // list of last names to randomly choose from for the female NPC  (if only one name is supplied it will always be used)
  40 list anDefault=["DEFAULT_STAND_WAITING","Waiting to Dance","Stand_f",<-0.3,-0.3,0>,<0,0,90>,"Stand_m",<0.3,0.3,0>,<0,0,-90>]; // default stand animation and positions when waiting for a partner or inital couples dance selection
  41 integer enableParticles=TRUE;                           // enable particle effects for the main controller and poseballs - FALSE if you move scripts to different controller object and/or use different poseballs that shouldn't use them
  42 vector sparkleStartColour=<1.0,0.2,0.2>;                // for main controller particle effect - start colour of sparkles
  43 vector sparkleEndColour=<0.941, 0.847, 0.459>;          // for main controller particle effect - end colour of sparkles
  44 float sparkleBurstSpeed=6.25;                           // for main controller particle effect - this affects how far out from center the sparkles go
  45 integer sparkleBurstCount=7;                            // for main controller particle effect - number of particles per burst
  46 float rpm=4.0;                                          // how rapidly to rotate the controller on its axis (in revolutions per minute) 0.0 disables rotation completely
  47 //
  48 // ******************************************************************************
  49 // *                       Extras for remote dance poles                        *
  50 // ******************************************************************************
  51 // this section contains some extra coms channels to make the main dance ball work with remotes
  52 integer RemoteChannel = -741285681;
  53 integer RemoteChannelListen;
  54 // ******************************************************************************
  55 // * DO NOT CHANGE ANYTHING BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING! *
  56 // ******************************************************************************
  57 list anData=[]; list styles=[]; integer anStride=8; list dancers=[]; integer dancerStride=15; integer B1USER=0; integer B1ID=1; integer B1AN=2; integer B1POS=3; integer B1ROT=4; integer B2USER=5; integer B2ID=6; integer B2AN=7; integer B2POS=8; integer B2ROT=9; integer BASEPOS=10; integer SWAPFLAG=11; integer STYLE=12; integer ANNAME=13; integer AUTO=14; integer nextBallID; list ballRezFor; list singlesDances; list currentDances; list singlesUsers; list singlesStyles; list groupUsers; string groupDance; string singlesStyleCount; string singlesDanceCount; string couplesDanceCount; integer handle; integer myChannel; string txtDia; list butDia; string myState; integer tickCouples=TRUE; list partnerF; list partnerM; integer indexNpcF; integer indexNpcM;integer osNpcObjectGroup=8; list npcMatch;
  58 
  59 startGroupDancing(key who) 
  60 {
  61     groupUsers=[]+groupUsers+[who];
  62     list anToStop=llGetAnimationList(who);
  63     osAvatarPlayAnimation(who,groupDance);
  64     integer stop=llGetListLength(anToStop);
  65     while (--stop>=0) { osAvatarStopAnimation(who,llList2String(anToStop,stop)); }
  66     if (!osIsNpc(who)) llRegionSayTo(who,0,"You've joined the group dance and will be in synch when it next changes. Touch the dance ball again to stop dancing");
  67     updateText();
  68 }
  69 
  70 showSinglesMenu(key who,integer page) 
  71 {
  72     txtDia="Pick a singles dance style to use\nQUIT to stop dancing";
  73     string curStyle=llList2String(singlesUsers,llListFindList(singlesUsers,[who])+1);
  74     if (curStyle!="NO_STYLE_SELECTED") txtDia+="\n\nYour current style is: "+curStyle;
  75     if (page==-1) {
  76         if (curStyle=="NO_STYLE_SELECTED") page=0;
  77         else page=llListFindList(singlesStyles,[curStyle])/9;
  78     }    
  79     butDia=[]+llList2List(singlesStyles,page*9,page*9+8);
  80     while (llGetListLength(butDia)<9) {butDia=[]+butDia+["*"];}
  81     while (llListFindList(butDia,["*","*","*"])>=0) {butDia=[]+llDeleteSubList(butDia,llListFindList(butDia,["*","*","*"]),llListFindList(butDia,["*","*","*"])+2);}
  82     if (page==0) butDia=[]+butDia+["*","QUIT"];
  83     else butDia=[]+butDia+["PAGE "+(string)page,"QUIT"];
  84     if (llGetListLength(singlesStyles)>((page*9)+9)) butDia=[]+butDia+["PAGE "+(string)(page+2)];
  85     else butDia=[]+butDia+["*"];
  86     llDialog(who,txtDia,llList2List(butDia,9,11)+llList2List(butDia,6,8)+llList2List(butDia,3,5)+llList2List(butDia,0,2),myChannel);
  87 }
  88 
  89 startSingles(key who, string currentSinglesStyle) 
  90 {
  91     list anToStop=llGetAnimationList(who);
  92     osAvatarPlayAnimation(who,llList2String(currentDances,llListFindList(currentDances,llList2String(singlesUsers,llListFindList(singlesUsers,[who])+1))+1));
  93     integer a=llGetListLength(anToStop);
  94     while(--a>=0) {osAvatarStopAnimation(who,llList2String(anToStop,a));}
  95     updateText();
  96 }
  97 
  98 nextSingles(key who, string currentSinglesStyle) 
  99 {
 100     string curD=llList2String(currentDances,llListFindList(currentDances,[currentSinglesStyle])+1);
 101     string nextD=llList2String(currentDances,llListFindList(currentDances,[currentSinglesStyle])+2);
 102     if(curD!=nextD) {
 103         osAvatarPlayAnimation(who,nextD);
 104         osAvatarStopAnimation(who,curD);
 105     }
 106 }
 107 
 108 stopSingles(key who, string currentSinglesStyle) 
 109 {
 110     osAvatarPlayAnimation(who,"stand");
 111     osAvatarStopAnimation(who,llList2String(currentDances,llListFindList(currentDances,[currentSinglesStyle])+1));
 112 }
 113 
 114 persistCurrent(integer anToUpdate) 
 115 {
 116     list ball1Params=osGetPrimitiveParams(llList2Key(dancers,B1ID),[PRIM_POSITION,PRIM_ROTATION]);
 117     list ball2Params=osGetPrimitiveParams(llList2Key(dancers,B2ID),[PRIM_POSITION,PRIM_ROTATION]);
 118     list newBall1AnData=llParseString2List(regToRel(llList2Vector(dancers,BASEPOS),ZERO_ROTATION,llList2Vector(ball1Params,0),llList2Rot(ball1Params,1)),["|"],[]);
 119     list newBall2AnData=llParseString2List(regToRel(llList2Vector(dancers,BASEPOS),ZERO_ROTATION,llList2Vector(ball2Params,0),llList2Rot(ball2Params,1)),["|"],[]);
 120     list newAnEntry=llList2List(anData,anToUpdate,anToUpdate+2)+newBall1AnData+[llList2String(anData,anToUpdate+5)]+newBall2AnData;
 121     anData=[]+llListReplaceList(anData,newAnEntry,anToUpdate,anToUpdate+anStride-1);
 122 }
 123 
 124 saveNotecard() 
 125 {
 126     integer l=llGetListLength(anData);
 127     if (l<anStride) {llOwnerSay("ERROR! Save notecard called with no animation data in memory. Aborting save."); return;}
 128     llRemoveInventory(animNotecard); llSleep(0.2);
 129     integer i;
 130     string data="";
 131     while (i<l) {data+=llDumpList2String(llList2List(anData,i,i+anStride-1),"|")+"\n"; i+=anStride;}
 132     osMakeNotecard(animNotecard,data);
 133     llOwnerSay("The new data has been stored to your notecard");
 134 }
 135 
 136 doSynch(key who) 
 137 {
 138     integer i=getPairIndex(who);
 139     osAvatarStopAnimation(llList2Key(dancers,i+B1USER),llList2String(dancers,i+B1AN));
 140     osAvatarPlayAnimation(llList2Key(dancers,i+B1USER),llList2String(dancers,i+B1AN));
 141     osAvatarStopAnimation(llList2Key(dancers,i+B2USER),llList2String(dancers,i+B2AN));
 142     osAvatarPlayAnimation(llList2Key(dancers,i+B2USER),llList2String(dancers,i+B2AN));
 143 }
 144 
 145 showMain(key who) 
 146 {
 147     txtDia="Please select a dance style\nor SYNCH to resynch current dance";
 148     if (llList2Integer(dancers,getPairIndex(who)+AUTO)) {
 149         butDia=[]+["MANUAL","SYNCH","QUIT"]+llList2List(styles,6,8)+llList2List(styles,3,5)+llList2List(styles,0,2);
 150         txtDia+="\nor MANUAL to return to manual dance selection mode";
 151     } else {
 152         butDia=[]+["AUTO","SYNCH","QUIT"]+llList2List(styles,6,8)+llList2List(styles,3,5)+llList2List(styles,0,2);
 153         txtDia+="\nor AUTO to enter auto dance mode";
 154     }
 155     llDialog(who,txtDia,butDia,myChannel);
 156 }
 157 
 158 showPickAn(key who, string styleName) {
 159     txtDia="Pick an animation to play or...\nSTYLES to select a different style\nSYNCH to resynch animation\nOPTIONS to access options menu";
 160     list ans=[];
 161     integer i=llListFindList(anData,[styleName]);
 162     while(llList2String(anData,i)==styleName){ans=[]+ans+[llList2String(anData,i+1)]; i+=anStride;}
 163     while (llGetListLength(ans)<9){ans=[]+ans+["~"];}
 164     butDia=[]+["STYLES","SYNCH","OPTIONS"]+llList2List(ans,6,8)+llList2List(ans,3,5)+llList2List(ans,0,2);
 165     llDialog(who,txtDia,butDia,myChannel);
 166 }
 167 
 168 showOptions(key who) {
 169     if (myState=="READY") {
 170         txtDia="Please select an action:\n\nBACK to return to previous menu\nSWAP positions with partner\nAUTO to change dances automatically\nMANUAL to go back to manual\n"+"Z ADJUST to turn on height adjust\nZ STOP ADJ to turn it off\nZ RESET to revert to default position\nNEW M and NEW F will randomly select another male or female NPC dance partner";
 171         butDia=[]+["BACK","SWAP"];
 172         if (llList2Integer(dancers,getPairIndex(who)+AUTO)) butDia=[]+butDia+["MANUAL","Z ADJUST","Z STOP ADJ","Z RESET","NEW M","NEW F"];
 173         else butDia=[]+butDia+["AUTO","Z ADJUST","Z STOP ADJ","Z RESET","NEW M","NEW F"];
 174         if (who==llGetOwner()) {
 175             if((llGetListLength(dancers)>dancerStride)||(llGetListLength(singlesUsers)>0)) txtDia+="\nCannot enter edit mode when there are other couples or singles dancers using the machine";
 176             else {
 177                 txtDia+="\nEDIT ON enters edit mode (only works when owner and partner are the only users";
 178                 butDia=[]+butDia+["QUIT","EDIT ON"];
 179             }
 180         } else butDia=[]+butDia+["QUIT"];
 181     } else if (myState=="EDIT") {
 182         txtDia="EDIT MODE\nEDIT OFF exit edit mode (does not save to card)\nSAVE changes to notecard\nREVERT this animation to stored value\n"+"SYNCH to resynch animation\nNEXT/PREV to change to next/previous animation (stores changes locally but not to notecard)";
 183         butDia=[]+["EDIT OFF","SAVE","REVERT","< PREV","SYNCH","NEXT >"];
 184     } else { llOwnerSay("ERROR! Attempting to show options menu but state was "+myState); return;}
 185     llDialog(who,txtDia,butDia,myChannel);
 186 }
 187 
 188 playAnimation(integer pairIndex, integer nextAnIndex) {
 189     list thisCouple=llList2List(dancers,pairIndex,pairIndex+dancerStride-1);
 190     list nextAnData=llList2List(anData,nextAnIndex,nextAnIndex+anStride-1);
 191     list nextCouple=llList2List(thisCouple,B1USER,B1ID);
 192     if (llList2Integer(thisCouple,SWAPFLAG)==1) nextCouple+=llList2List(nextAnData,5,7)+llList2List(thisCouple,B2USER,B2ID)+llList2List(nextAnData,2,4)+llList2List(thisCouple,BASEPOS,SWAPFLAG)+llList2List(nextAnData,0,1)+llList2List(thisCouple,AUTO,AUTO);
 193     else nextCouple+=llList2List(nextAnData,2,4)+llList2List(thisCouple,B2USER,B2ID)+llList2List(nextAnData,5,7)+llList2List(thisCouple,BASEPOS,SWAPFLAG)+llList2List(nextAnData,0,1)+llList2List(thisCouple,AUTO,AUTO);
 194     dancers=[]+llListReplaceList(dancers,nextCouple,pairIndex,pairIndex+dancerStride-1);
 195     if (agentPresent(llList2Key(nextCouple,B1USER))&& agentPresent(llList2Key(nextCouple,B2USER))&& objectPresent(llList2Key(nextCouple,B1ID))&& objectPresent(llList2Key(nextCouple,B2ID))) {
 196         osMessageObject(llList2Key(nextCouple,B1ID),"MOVE_BALL|"+relToReg(llList2Vector(nextCouple,BASEPOS),ZERO_ROTATION,llList2Vector(nextCouple,B1POS),llList2Vector(nextCouple,B1ROT)));
 197         osMessageObject(llList2Key(nextCouple,B2ID),"MOVE_BALL|"+relToReg(llList2Vector(nextCouple,BASEPOS),ZERO_ROTATION,llList2Vector(nextCouple,B2POS),llList2Vector(nextCouple,B2ROT)));
 198         osAvatarStopAnimation(llList2Key(thisCouple,B1USER),llList2String(thisCouple,B1AN));
 199         osAvatarStopAnimation(llList2Key(thisCouple,B2USER),llList2String(thisCouple,B2AN));
 200         osAvatarPlayAnimation(llList2Key(nextCouple,B1USER),llList2String(nextCouple,B1AN));
 201         osAvatarPlayAnimation(llList2Key(nextCouple,B2USER),llList2String(nextCouple,B2AN));
 202     } else {
 203         key keyToMessage=llList2Key(nextCouple,B1USER);
 204         if (!agentPresent(keyToMessage)) keyToMessage=llList2Key(nextCouple,B2USER);
 205         llRegionSayTo(keyToMessage,0,"Your animation selection won't begin to play until you have a seated partner but your selection has been stored.");
 206     }
 207 }
 208 
 209 integer getPairIndex(string find) 
 210 {
 211     return dancerStride*llFloor((float)llListFindList(dancers,[find])/(float)dancerStride);
 212 }
 213 
 214 string regToRel(vector basePos, rotation baseRot, vector regionPos,rotation regionRot) 
 215 {
 216     vector refPos=(regionPos - basePos) / baseRot;
 217     vector refRot=llRot2Euler((rotation)regionRot/ baseRot)*RAD_TO_DEG;
 218     string strToReturn="<"+trimF(refPos.x)+","+trimF(refPos.y)+","+trimF(refPos.z)+">"+"|<"+trimF(refRot.x)+","+trimF(refRot.y)+","+trimF(refRot.z)+">";
 219     return strToReturn;
 220 }
 221 
 222 string relToReg(vector basePos, rotation baseRot, vector refPos,vector refRot) {
 223     vector regionPos=refPos*baseRot+basePos;
 224     rotation regionRot=llEuler2Rot(refRot*DEG_TO_RAD)*baseRot;
 225     return ((string)regionPos+"|"+(string)regionRot);
 226 }
 227 
 228 string trimF(float value) 
 229 {
 230     integer newVal=llRound(value*10000);
 231     integer negFlag=FALSE;
 232     if (newVal<0) { negFlag=TRUE; newVal*=-1; }
 233     integer strLength;
 234     string retStr;
 235     if (newVal==0) retStr="0";
 236     else if (newVal<10) retStr="0.000"+(string)newVal;
 237     else if (newVal<100) retStr="0.00"+(string)newVal;
 238     else if (newVal<1000) retStr="0.0"+(string)newVal;
 239     else if (newVal<10000) retStr="0."+(string)newVal;
 240     else {
 241         retStr=(string)newVal;
 242         strLength=llStringLength(retStr);
 243         retStr=llGetSubString(retStr,0,strLength-5)+"."+llGetSubString(retStr,strLength-4,strLength-1);
 244     }
 245     while (llGetSubString(retStr,strLength,strLength)=="0") {retStr=llGetSubString(retStr,0,strLength-1); strLength-=1;}
 246     if (negFlag) retStr="-"+retStr;
 247     return retStr;
 248 }
 249 
 250 showFirst(key who) 
 251 {
 252     txtDia="How would you like to dance?\n\nSINGLES - pick a singles style\nGROUP - join the group dance style\nCOUPLES - dance with a friend\nNPC COUPLES - dance with a NPC\nOOPS I don't want to dance";
 253     butDia=["COUPLES","NPC COUPLES","OOPS","SINGLES","GROUP"];
 254     llDialog(who,txtDia,butDia,myChannel);
 255 }
 256 
 257 doInitialize() 
 258 {
 259     if(llGetInventoryType(poseballName)!=INVENTORY_OBJECT) 
 260     {
 261         llOwnerSay("ERROR! Unable to find the poseball "+poseballName+" in inventory");
 262         myState="ERROR";
 263         return;
 264     }
 265     if (llGetInventoryType(animNotecard)!=INVENTORY_NOTECARD) 
 266     {
 267         llOwnerSay("ERROR! Unable to find the animation data notecard");
 268         myState="ERROR";
 269         return;
 270     }
 271     string cardData=osGetNotecard(animNotecard);
 272     anData=[]+llParseString2List(cardData,["|","\n"],[]);
 273     if (llGetInventoryType(singlesNotecard)!=INVENTORY_NOTECARD)
 274     {
 275         llOwnerSay("ERROR! Unable to find the single data data notecard");
 276         myState="ERROR";
 277         return;
 278     }
 279     cardData=""+osGetNotecard(singlesNotecard);
 280     singlesDances=[]+llParseString2List(cardData,["|","\n"],[]);
 281     integer i;
 282     integer l=llGetListLength(singlesDances);
 283     singlesStyles=[];
 284     while(i<l) {
 285         if (errorCheck) {
 286             singlesDances=[]+llListReplaceList(singlesDances,[llStringTrim(llList2String(singlesDances,i),STRING_TRIM)],i,i);
 287             singlesDances=[]+llListReplaceList(singlesDances,[llStringTrim(llList2String(singlesDances,i+1),STRING_TRIM)],i+1,i+1);
 288         }
 289         if (llListFindList(singlesStyles,[llList2String(singlesDances,i)])<0) singlesStyles=[]+singlesStyles+llList2String(singlesDances,i);
 290         i+=2;
 291     }
 292     if (randomizeSinglesOrder) singlesDances=[]+llListRandomize(singlesDances,2);
 293     singlesDances=[]+llListSort(singlesDances,2,TRUE);
 294     singlesStyleCount=(string)llGetListLength(singlesStyles);
 295     singlesDanceCount=(string)(llGetListLength(singlesDances)/2);
 296     i=0; l=llGetListLength(singlesStyles);
 297     currentDances=[];
 298     while (i<l) {
 299         if(llListFindList(currentDances,[llList2String(singlesStyles,i)])<0) {
 300             integer f=llListFindList(singlesDances,[llList2String(singlesStyles,i)]);
 301             currentDances=[]+currentDances+llList2List(singlesDances,f,f+1);
 302             if (llList2String(singlesDances,f+2)==llList2String(singlesDances,f)) currentDances=[]+currentDances+[llList2String(singlesDances,f+3)];
 303             else currentDances=[]+currentDances+[llList2String(singlesDances,f+1)];
 304         }
 305         i++;
 306     }
 307     if (llListFindList(singlesStyles,[groupStyle])<0) 
 308     {
 309         integer gse;
 310         if (groupStyle=="") gse=TRUE;
 311         groupStyle=llList2String(singlesStyles,0);
 312         if (gse) llOwnerSay("NOTICE: Setting "+groupStyle+" as the group dance style because no style was specified in the settings");
 313         else llOwnerSay("NOTICE: Setting "+groupStyle+" as the group dance style because the specified style wasn't found");
 314     }
 315     groupDance=llList2String(singlesDances,llListFindList(singlesDances,[groupStyle])+1);
 316     if (errorCheck) 
 317     {
 318         i=0; l=llGetListLength(singlesDances);
 319         while(i<l) {
 320             if (llListFindList(singlesStyles,[llList2String(singlesDances,i+1)])>=0) 
 321             {
 322                 llOwnerSay("ERROR! A singles dance animation name is in conflict with one of the singles styles names. Style names must be unique! Conflict name is: "+llList2String(singlesDances,i+1));
 323                 myState="ERROR";
 324             }
 325             if (llGetInventoryType(llList2String(singlesDances,i+1))!=INVENTORY_ANIMATION) 
 326             {
 327                 llOwnerSay("ERROR! Unable to locate the singles dance animation \""+llList2String(singlesDances,i+1)+"\" in inventory.");
 328                 myState="ERROR";
 329             }
 330             i+=2;
 331         }
 332         if (myState=="ERROR") 
 333         {
 334             llOwnerSay("Errors detected during singles notecard data check. Please fix and restart");
 335             return;
 336         }
 337     }
 338     i=0; l=llGetListLength(anData);
 339     if (errorCheck) 
 340     {
 341         while(--l>=0) {anData=[]+llListReplaceList(anData,[llStringTrim(llList2String(anData,l),STRING_TRIM)],l,l);}
 342         l=llGetListLength(anData);
 343     }
 344     styles=[];
 345     while (i<l) 
 346     {
 347         if (errorCheck) 
 348         {
 349             if (llListFindList(singlesStyles,[llList2String(anData,i)])>=0) 
 350             {
 351                 llOwnerSay("ERROR! A doubles dance style name is in conflict with one of the singles styles names. Style names must be unique! Please correct this and restart.");
 352                 myState="ERROR";
 353                 return;
 354             }
 355         }
 356         if (llListFindList(styles,[llList2String(anData,i)])<0) styles=[]+styles+[llList2String(anData,i)];
 357         i+=anStride;
 358     }
 359     while(llGetListLength(styles)<9) 
 360     {
 361         styles=[]+styles+["-"];
 362     }
 363     if (llGetListLength(styles)>9) llOwnerSay("WARNING! Found "+(string)(llGetListLength(styles))+" different couples dance styles but only the first 9 can be shown. Please correct this (but this is a non-fatal error so the dance machine will still work)");
 364     while (llListFindList(styles,["-","-","-"])>=0) 
 365     {
 366         styles=[]+llDeleteSubList(styles,llListFindList(styles,["-","-","-"]),llListFindList(styles,["-","-","-"])+2);
 367     }
 368     if (errorCheck) 
 369     {
 370         i=0; l=llGetListLength(anData); integer anCount; string styleName; integer warned=FALSE;
 371         while (i<l) 
 372         {
 373             if (llList2String(anData,i)!=styleName) 
 374             {
 375                 styleName=llList2String(anData,i);
 376                 anCount=1;
 377                 warned=FALSE;
 378             } else {
 379                 anCount++;
 380                 if ((anCount>9) && !warned) 
 381                 {
 382                     warned=TRUE;
 383                     llOwnerSay("WARNING! Found more than 9 animations assigned to style "+styleName+" but only the first 9 can be shown. Please correct this (but this is a non-fatal error so the dance machine will still work)");
 384                 }
 385             }
 386             string name=llList2String(anData,i+1);
 387             if (llListFindList(anData,[name])<i) 
 388             {
 389                 llOwnerSay("ERROR! The name "+name+" is being used to identify an pair of animations but is in conflict with another name -- a style name, other pair name, or individual animation name that isn't part of that pair. Please resolve this error and reset the controller (see instructions for more details about name restrictions).");
 390                 myState="ERROR";
 391             }
 392             name= llList2String(anData,i+2);
 393             if (llGetInventoryType(name)!=INVENTORY_ANIMATION) 
 394             {
 395                 myState="ERROR"; llOwnerSay("ERROR! Unable to locate the animation "+name+" in inventory. Please either supply it or update the animation data notecard.");
 396             }
 397             name= llList2String(anData,i+5);
 398             if (llGetInventoryType(name)!=INVENTORY_ANIMATION) 
 399             {
 400                 myState="ERROR"; llOwnerSay("ERROR! Unable to locate the animation "+name+" in inventory. Please either supply it or update the animation data notecard.");
 401             }
 402             i+=anStride;
 403         }
 404     }
 405     couplesDanceCount=(string)(llGetListLength(anData)/anStride);
 406     if (errorCheck) {
 407         i=llGetInventoryNumber(INVENTORY_ANIMATION);
 408         while (--i>=0) {
 409             string anName=llGetInventoryName(INVENTORY_ANIMATION,i);
 410             if ((llListFindList(anData,[anName])<0) && (llListFindList(anDefault,[anName])<0) && (llListFindList(singlesDances,[anName])<0)) llOwnerSay("NOTE: found the animation "+anName+" in inventory but it is not used for either the singles or couples dances.");
 411         }
 412     }
 413     partnerM=[]; partnerF=[]; indexNpcM=0; indexNpcF=0; i=llGetInventoryNumber(INVENTORY_NOTECARD); integer lm=llStringLength(prefixM)-1; integer lf=llStringLength(prefixF)-1;
 414     while (--i>=0) {
 415         string note=llGetInventoryName(INVENTORY_NOTECARD,i);
 416         if (llGetSubString(note,0,lm)==prefixM) partnerM=[]+[note]+partnerM;
 417         else if (llGetSubString(note,0,lf)==prefixF) partnerF=[]+[note]+partnerF;
 418     }
 419     if (randomizeNpcOrder) 
 420     {
 421         partnerM=[]+llListRandomize(partnerM,1);
 422         partnerF=[]+llListRandomize(partnerF,1);
 423     }
 424     npcMatch=[];
 425     if (npcMatcherCard!="") 
 426     {
 427         if (llGetInventoryType(npcMatcherCard)!=INVENTORY_NOTECARD) llOwnerSay("WARNING: could not find the NPC matchmaker notecard \""+npcMatcherCard+"\" so no custom NPC assignments will be used");
 428         else {
 429             npcMatch=[]+llParseString2List(osGetNotecard(npcMatcherCard),["|","\n"],[]);
 430             i=0; l=llGetListLength(npcMatch);
 431             while (i<l) {
 432                 if (llGetInventoryType(llList2String(npcMatch,i+1))!=INVENTORY_NOTECARD) {
 433                     llOwnerSay("WARNING: NPC Matchmaker notecard calls for NPC \""+llList2String(npcMatch,i+1)+"\" but it isns't in inventory. Removing that entry");
 434                     npcMatch=[]+llDeleteSubList(npcMatch,i,i+1);
 435                     l-=2;
 436                 } else i+=2;
 437             }
 438         }
 439     }
 440     if (llGetListLength(partnerM)==0) {myState="ERROR"; llOwnerSay("ERROR! No notecards were found with the specified male NPC prefix: "+prefixM);}
 441     if (llGetListLength(firstNameM)==0) {myState="ERROR"; llOwnerSay("ERROR! No male NPC first names were supplied");}
 442     if (llGetListLength(lastNameM)==0) {myState="ERROR"; llOwnerSay("ERROR! No male NPC last names were supplied");}
 443     if (llGetListLength(partnerF)==0) {myState="ERROR"; llOwnerSay("ERROR! No notecards were found with the specified female NPC prefix: "+prefixF);}
 444     if (llGetListLength(firstNameF)==0) {myState="ERROR"; llOwnerSay("ERROR! No female NPC first names were supplied");}
 445     if (llGetListLength(lastNameF)==0) {myState="ERROR"; llOwnerSay("ERROR! No female NPC last names were supplied");}
 446 }//end to initilise
 447 
 448 setPart(integer on) 
 449 {
 450     if(on && enableParticles) llParticleSystem([PSYS_PART_MAX_AGE,0.7,PSYS_PART_FLAGS,0|PSYS_PART_EMISSIVE_MASK|PSYS_PART_INTERP_COLOR_MASK|PSYS_PART_INTERP_SCALE_MASK|PSYS_PART_FOLLOW_SRC_MASK|PSYS_PART_FOLLOW_VELOCITY_MASK|PSYS_PART_TARGET_POS_MASK,PSYS_PART_START_COLOR,sparkleStartColour,PSYS_PART_END_COLOR,sparkleEndColour,PSYS_PART_START_SCALE,<0.05,0.05,0>,PSYS_PART_END_SCALE,<0.1,0.1,0>,PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_EXPLODE,PSYS_SRC_BURST_RATE,0.1,PSYS_SRC_BURST_PART_COUNT,sparkleBurstCount,PSYS_SRC_BURST_RADIUS,2,PSYS_SRC_BURST_SPEED_MIN,sparkleBurstSpeed,PSYS_SRC_BURST_SPEED_MAX,sparkleBurstSpeed,PSYS_SRC_TARGET_KEY,llGetKey(),PSYS_SRC_ANGLE_BEGIN,1.55,PSYS_SRC_ANGLE_END,1.54,PSYS_PART_START_ALPHA,0.75,PSYS_PART_END_ALPHA,0.5]);
 451     else llParticleSystem([]);
 452 }
 453 setRot(integer on) 
 454 {
 455     llTargetOmega(<0.0,0.0,-rpm*(float)on/60>,TWO_PI,1.0);
 456 }
 457 updateText() 
 458 {
 459     if (myState=="READY") {
 460         setPart(TRUE);
 461         setRot(TRUE);
 462         string txt=floatyText+"\nTouch me to dance\n \nGroup Dance Style: "+groupStyle;
 463         if ((llGetListLength(singlesUsers)>0) || (llGetListLength(dancers)>0) || (llGetListLength(groupUsers)>0)) txt+="\nGroup dancers: "+(string)llGetListLength(groupUsers)+"\nSingles dancers: "+(string)(llGetListLength(singlesUsers)/2)+"\nCouples: "+(string)(llGetListLength(dancers)/dancerStride)+"\n";
 464         txt+=" \nDances Loaded\n"+singlesStyleCount+" singles styles, "+singlesDanceCount+" dances\nand "+couplesDanceCount+" couples dances";
 465         if (showFloatyText) llSetText(txt,floatyTextColour,1.0);
 466         else llSetText("",ZERO_VECTOR,0.0);
 467     } else {
 468         setPart(FALSE);
 469         setRot(FALSE);
 470         if (myState=="INITIALIZING") llSetText(floatyText+"\nInitializing...\nplease wait",<0,1,0>,1.0);
 471         else if (myState=="ERROR") llSetText(floatyText+"\nERROR...sorry\ntemporarily out of order",<1,0,0>,1.0);
 472         else if (myState=="EDIT") llSetText(floatyText+"\nEDIT MODE...\nplease wait",<1,1,0>,1.0);
 473     }
 474 }
 475 
 476 integer agentPresent(key who) 
 477 {
 478     if (who==NULL_KEY) return FALSE;
 479     else if (who=="") return FALSE;
 480     else if (!osIsUUID(who)) return FALSE;
 481     else if (llGetAgentSize(who)==ZERO_VECTOR) return FALSE;
 482     else return TRUE;
 483 }
 484 
 485 integer objectPresent(key what) 
 486 {
 487     if (what=="") return FALSE;
 488     else if (what==NULL_KEY) return FALSE;
 489     else if (!osIsUUID(what)) return FALSE;
 490     else if (llGetObjectDetails(what,[OBJECT_NAME])==[]) return FALSE;
 491     else return TRUE;
 492 }
 493 
 494 ProcessToucher(key toucher) //all this was in touch_start after the lldetectdkey.
 495 {//1
 496 if (myState=="INITIALIZING") llRegionSayTo(toucher,0,"Sorry, currently initializing the dance machine. Please wait until it is ready, then touch again");
 497 else if (myState=="ERROR") 
 498     {//2
 499     if (toucher!=llGetOwner()) llRegionSayTo(toucher,0,"Sorry, the controller has encountered an error and needs to be reset before it can resume working. Please inform the owner");
 500     else 
 501         {//3
 502         llOwnerSay("Attempting script reset");
 503         llResetScript();
 504         }//3
 505     }//2 
 506 else if (myState=="EDIT") 
 507     {//4
 508     if (toucher!=llGetOwner()) llRegionSayTo(toucher,0,"Sorry, the owner is currently editing positions...please wait until this is finished and the machine is reset");
 509     else showOptions(llGetOwner());
 510     }//4
 511 else if (myState=="READY") 
 512     {//5
 513     if (llListFindList(groupUsers,[toucher])>=0) 
 514         {//6
 515         integer indU=llListFindList(groupUsers,[toucher]);
 516         osAvatarPlayAnimation(toucher,"stand");
 517         osAvatarStopAnimation(toucher,groupDance);
 518         groupUsers=[]+llDeleteSubList(groupUsers,indU,indU);
 519         updateText();
 520         }//6
 521     else if (llListFindList(singlesUsers,[toucher])>=0) 
 522         {//7
 523         if (llGetListLength(singlesStyles)==1) 
 524             {//8
 525             integer indWho=llListFindList(singlesUsers,[toucher]);
 526             stopSingles(toucher,llList2String(singlesUsers,indWho+1));
 527             singlesUsers=[]+llDeleteSubList(singlesUsers,indWho,indWho+1);
 528             updateText();
 529             }//8 
 530         else showSinglesMenu(toucher,-1);
 531         }//7 
 532     else if (llListFindList(dancers,[toucher])>=0) showMain(toucher);
 533     else if (osIsNpc(toucher)) startGroupDancing(toucher);
 534     else showFirst(toucher);
 535     }//5
 536 }//1
 537 
 538 InitListeners()
 539 {
 540     myChannel= 0x80000000 | (integer)("0x"+(string)llGetKey());
 541     RemoteChannelListen = llListen(RemoteChannel, "", NULL_KEY, "");
 542     handle=llListen(myChannel,"",NULL_KEY,"");
 543     llListenControl(RemoteChannelListen, TRUE);
 544 }
 545 
 546 ProcessRemoteToucher(string message)
 547 {
 548     key toucher = (key)message;
 549     ProcessToucher(toucher);
 550 }
 551 
 552 default
 553 {
 554     changed (integer change)
 555     {
 556     if (change & CHANGED_OWNER) llResetScript();
 557     else if (change & CHANGED_REGION_START) llResetScript();
 558     }
 559 
 560     state_entry()
 561     {
 562         myState="INITIALIZING";
 563         llSetText(floatyText+"\nInitializing...\nplease wait",<0,1,0>,1.0);
 564         InitListeners();
 565         setPart(FALSE); setRot(FALSE);  
 566         autoTimer/=2;
 567         doInitialize();
 568         dancers=[]; singlesUsers=[]; ballRezFor=[];
 569         if (myState=="INITIALIZING") {
 570             myState="READY";
 571             updateText();
 572             llSetTimerEvent(autoTimer);
 573             llSay(0,"System reset and ready");
 574         } else if (myState=="ERROR") {
 575             llInstantMessage(llGetOwner(),"ERROR encountered during initialization!");
 576             updateText();
 577         } else llOwnerSay("Reached end of state_entry with unexpected state: "+myState);
 578     }
 579 
 580     link_message(integer sender_num, integer num, string msg, key id)
 581     {
 582         key toucher = (key)msg;
 583         ProcessToucher(toucher);
 584     }
 585     
 586     touch_start(integer num)
 587     {
 588     // -- key toucher = llDetectdKey(0);     Moved to the global variables so it can work with linked messages to. 
 589     key toucher=llDetectedKey(0);
 590     ProcessToucher(toucher); // ++ added by me as a new fuction so it can be shared with a linked message
 591     // -- lots of code removed here and moved to the ProcessToucher() function/
 592     }
 593         
 594     timer()
 595     {
 596         if (myState!="READY") 
 597         { 
 598             if (myState!="EDIT") llSetTimerEvent(0.0); return;
 599         }
 600         tickCouples=!tickCouples;
 601         integer i; integer t;
 602         if (tickCouples) 
 603         {
 604             integer l=llGetListLength(dancers);
 605             while (i<l) {
 606                 if (llList2Integer(dancers,i+AUTO)) {
 607                     string style=llList2String(dancers,i+STYLE);
 608                     string curAn=llList2String(dancers, i+ANNAME);
 609                     integer curInd=llListFindList(anData,[style,curAn]);
 610                     integer nextInd;
 611                     if (llListFindList(styles,[style])<0) nextInd=0;
 612                     else if ((curInd>-1) && (llList2String(anData,curInd+anStride)==style)) nextInd=curInd+anStride;
 613                     else nextInd=llListFindList(anData,[style]);
 614                     playAnimation(i,nextInd);
 615                 }
 616                 i+=dancerStride;
 617             }
 618         } 
 619         else 
 620         {
 621             integer l=llGetListLength(singlesUsers);
 622             while(i<l) {
 623                 if (llGetAgentSize(llList2Key(singlesUsers,i))==ZERO_VECTOR) {
 624                     singlesUsers=[]+llDeleteSubList(singlesUsers,i,i+1);
 625                     l-=2;
 626                 } else {
 627                     nextSingles(llList2Key(singlesUsers,i),llList2String(singlesUsers,i+1));
 628                     i+=2;
 629                 }
 630             }
 631             i=0;
 632             l=llGetListLength(currentDances);
 633             while(i<l) {
 634                 string thisStyle=llList2String(currentDances,i);
 635                 string moveToCurrent=llList2String(currentDances,i+2);
 636                 string newNextDance;
 637                 integer indexNewCurrent=llListFindList(singlesDances,[thisStyle,moveToCurrent]);
 638                 if(llList2String(singlesDances,indexNewCurrent+2)==thisStyle) newNextDance=llList2String(singlesDances,indexNewCurrent+3);
 639                 else newNextDance=llList2String(singlesDances,llListFindList(singlesDances,[thisStyle])+1);
 640                 currentDances=[]+llListReplaceList(currentDances,[thisStyle,moveToCurrent,newNextDance],i,i+2);
 641                 i+=3;
 642             }
 643             integer ngi=llListFindList(singlesDances,[groupStyle,groupDance])+2;
 644             if (llList2String(singlesDances,ngi)!=groupStyle) ngi=llListFindList(singlesDances,[groupStyle]);
 645             string nextGroupDance=llList2String(singlesDances,ngi+1);
 646             l=llGetListLength(groupUsers);
 647             while (--l>=0) {
 648                 if (llGetAgentSize(llList2Key(groupUsers,l))==ZERO_VECTOR) groupUsers=[]+llDeleteSubList(groupUsers,l,l);
 649                 else if (nextGroupDance!=groupDance) {
 650                     osAvatarPlayAnimation(llList2Key(groupUsers,l),nextGroupDance);
 651                     osAvatarStopAnimation(llList2Key(groupUsers,l),groupDance);
 652                 }
 653             }
 654             groupDance=nextGroupDance;
 655         }
 656         updateText();
 657     }
 658     on_rez(integer foo)
 659         {
 660         llResetScript();
 661         }
 662     
 663     dataserver (key ball, string data)
 664     {
 665         list message=llParseString2List(data,["|"],[]);
 666         string command=llList2String(message,0);
 667         if (command=="BALL_REZZED") {
 668             integer ballIndex=llListFindList(dancers,[("AWAITING_BALL_REZ_"+llList2String(message,1))]);
 669             if (ballIndex<0) { llOwnerSay("ERROR! A ball said "+data+" but when parsed I was unable to find an index for it using AWAITING_BALL_REZ_"+llList2String(message,1)); return;}
 670             dancers=[]+llListReplaceList(dancers,[ball],ballIndex,ballIndex);
 671             integer thisPair=getPairIndex(ball);
 672             if (thisPair<0) {llOwnerSay("ERROR! Unable to find an index when searching dancer list for the newly inserted ball UUID"); return;}
 673             vector basePos=llList2Vector(dancers,thisPair+BASEPOS);
 674             if (basePos==ZERO_VECTOR) {
 675                 llOwnerSay("ERROR! When attempting to retrieve the couple's base position to send a new ball the result returned ZERO_VECTOR.\n"+"The lookup for the couple index returned: "+(string)thisPair+"\nThe contents of the position field for that record is: "+llList2String(dancers,thisPair+BASEPOS));
 676                 return;
 677             }
 678             if ((llList2String(dancers,ballIndex-1)=="pending_f") || (llList2String(dancers,ballIndex-1)=="pending_npcf")) osMessageObject(ball,"MOVE_AND_SHOW_BALL|"+(string)(basePos+<-0.3, -0.3, 0.25>)+"|<0,0,0>|"+ (string)(ballTimeout*-1)+"|"+(string)zGlobal+"|"+(string)enableParticles);
 679             else if ((llList2String(dancers,ballIndex-1)=="pending_m") || (llList2String(dancers,ballIndex-1)=="pending_npcm")) osMessageObject(ball,"MOVE_AND_SHOW_BALL|"+(string)(basePos+<0.3, 0.3, 0.25>)+"|<0,0,0>|"+ (string)ballTimeout+"|"+(string)zGlobal+"|"+(string)enableParticles);
 680             else llOwnerSay("ERROR...BALL_REZZED dataserver error unable to locate record with that rez ID");
 681         } else if (command=="KILL_BALL_CALLED") {
 682             string reason=llList2String(message,1);
 683             if ((reason=="NO_USER_SAT") || (reason=="USER_STOOD_TIMEOUT") ) {
 684                 integer i=getPairIndex(ball);
 685                 if (i<0) return;
 686                 key userToMessage=NULL_KEY;
 687                 key ballToKill=NULL_KEY;
 688                 string anToStop;
 689                 if (ball==llList2Key(dancers,i+B1ID)) {
 690                     userToMessage=llList2Key(dancers,i+B2USER);
 691                     ballToKill=llList2Key(dancers,i+B2ID);
 692                     anToStop=llList2String(dancers,i+B2AN);
 693                 } else if (ball==llList2Key(dancers,i+B2ID)) {
 694                     userToMessage=llList2Key(dancers,i+B1USER);
 695                     ballToKill=llList2Key(dancers,i+B1ID);
 696                     anToStop=llList2String(dancers,i+B1AN);
 697                 } else llOwnerSay("ERROR! When handling kill ball on "+reason+" unable to find the relevant ball which should be impossible");
 698                 if(agentPresent(userToMessage)) llRegionSayTo(userToMessage,0,"Sorry, your partner's danceball has timed out and has been removed. Yours must be removed as well. Please start again when you're both ready to dance.");
 699                 if(objectPresent(ballToKill))  osMessageObject(ballToKill,"KILL_BALL");
 700                 if(agentPresent(userToMessage)) osAvatarStopAnimation(userToMessage,anToStop);
 701                 integer p=llListFindList(dancers,ball)-1;
 702                 if (agentPresent(llList2Key(dancers,p))) osAvatarStopAnimation(llList2Key(dancers,p),llList2String(dancers,p+2));
 703                 dancers=[]+llDeleteSubList(dancers,i,i+dancerStride-1);
 704                 updateText();
 705             } else {
 706                 myState="ERROR";
 707                 llSetTimerEvent(0.0);
 708                 updateText();
 709                 llShout(0,"ERROR! Sorry, the controller experienced an error and will attempt to reset. You can attempt to use it again once the system is ready. We are sorry for the inconvenience");
 710                 llInstantMessage(llGetOwner(),"Encountered error due to poseball self-destruct with the following error condition:\n"+reason);
 711                 integer l=llGetListLength(dancers);
 712                 integer i;
 713                 while (i<l) {
 714                     if (objectPresent(llList2Key(dancers,i+B1ID))) osMessageObject(llList2Key(dancers,i+B1ID),"KILL_BALL");
 715                     if (agentPresent(llList2Key(dancers,i+B1USER))) {
 716                         if (osIsNpc(llList2Key(dancers,i+B1USER))) osNpcRemove(llList2Key(dancers,i+B1USER));
 717                         else osAvatarStopAnimation(llList2Key(dancers,i+B1USER),llList2String(dancers,i+B1AN));
 718                     }
 719                     if (objectPresent(llList2Key(dancers,i+B2ID))) osMessageObject(llList2Key(dancers,i+B2ID),"KILL_BALL");
 720                     if (agentPresent(llList2Key(dancers,i+B2USER))) {
 721                         if (osIsNpc(llList2Key(dancers,i+B2USER))) osNpcRemove(llList2Key(dancers,i+B2USER));
 722                         else osAvatarStopAnimation(llList2Key(dancers,i+B2USER),llList2String(dancers,i+B2AN));
 723                     }
 724                     i+=dancerStride;
 725                 }
 726                 i=0;
 727                 l=llGetListLength(singlesUsers);
 728                 while (i<l) { stopSingles(llList2Key(singlesUsers,i),llList2String(singlesUsers,i+1)); i+=2;}
 729                 l=llGetListLength(groupUsers);
 730                 while (--l>=0) {
 731                     osAvatarPlayAnimation(llList2Key(groupUsers,l),"stand");
 732                     osAvatarStopAnimation(llList2Key(groupUsers,l),groupDance);
 733                 }
 734                 groupUsers=[];
 735                 llResetScript();
 736             }
 737         } else if (command=="USER_SAT") {
 738             key uID=llList2Key(message,1);
 739             if (llListFindList(singlesUsers,[uID])>-1) {
 740                 singlesUsers=[]+llDeleteSubList(singlesUsers,llListFindList(singlesUsers,uID),llListFindList(singlesUsers,uID)+1);
 741                 updateText();
 742             }
 743             else if (llListFindList(groupUsers,[uID])>-1) {
 744                 groupUsers=[]+llDeleteSubList(groupUsers,llListFindList(groupUsers,[uID]),llListFindList(groupUsers,[uID]));
 745                 updateText();
 746             }
 747             if (llListFindList(ballRezFor,[uID])>=0) ballRezFor=[]+llDeleteSubList(ballRezFor,llListFindList(ballRezFor,[uID]),llListFindList(ballRezFor,[uID])+1);
 748             integer i=llListFindList(dancers,[ball])-1;
 749             dancers=[]+llListReplaceList(dancers,[uID],i,i);
 750             osAvatarPlayAnimation(uID,llList2String(dancers,i+2));
 751             if (objectPresent(llList2Key(dancers,i+1))) osMessageObject(llList2Key(dancers,i+1),"MOVE_BALL|"+relToReg(llList2Vector(dancers,getPairIndex(uID)+BASEPOS),ZERO_ROTATION,llList2Vector(dancers,i+3),llList2Vector(dancers,i+4)));
 752             if (osIsNpc(uID)) return;
 753             integer thisPair=getPairIndex(uID);
 754             if (thisPair<0) return;
 755             if (llList2String(dancers,thisPair+B1USER)=="pending_npcf") {
 756                 string npcToRez;
 757                 if (llListFindList(npcMatch,[uID])>=0) npcToRez=llList2String(npcMatch,llListFindList(npcMatch,[uID])+1);
 758                 else {
 759                     indexNpcF++;
 760                     if (indexNpcF>=llGetListLength(partnerF)) indexNpcF=0;
 761                     npcToRez=llList2String(partnerF,indexNpcF);
 762                 }
 763                 key npc=osNpcCreate(llList2String(firstNameF,llFloor(llFrand(llGetListLength(firstNameF)))),llList2String(lastNameF,llFloor(llFrand(llGetListLength(lastNameF)))),(llList2Vector(dancers,thisPair+BASEPOS)+<0,0,2>),npcToRez,osNpcObjectGroup);
 764                 dancers=[]+llListReplaceList(dancers,["pending_npcf_"+(string)npc],thisPair+B1USER,thisPair+B1USER);
 765                 osNpcSit(npc,llList2Key(dancers,thisPair+B1ID),OS_NPC_SIT_NOW);
 766             } else if (llList2String(dancers,getPairIndex(uID)+B2USER)=="pending_npcm") {
 767                 string npcToRez;
 768                 if (llListFindList(npcMatch,[uID])>=0) npcToRez=llList2String(npcMatch,llListFindList(npcMatch,[uID])+1);
 769                 else {
 770                     indexNpcM++;
 771                     if (indexNpcM>=llGetListLength(partnerM)) indexNpcM=0;
 772                     npcToRez=llList2String(partnerM,indexNpcM);
 773                 }
 774                 key npc=osNpcCreate(llList2String(firstNameM,llFloor(llFrand(llGetListLength(firstNameM)))),llList2String(lastNameM,llFloor(llFrand(llGetListLength(lastNameM)))),(llList2Vector(dancers,thisPair+BASEPOS)+<0,0,2>),npcToRez,osNpcObjectGroup);
 775                 dancers=[]+llListReplaceList(dancers,["pending_npcm_"+(string)npc],thisPair+B2USER,thisPair+B2USER);
 776                 osNpcSit(npc,llList2Key(dancers,thisPair+B2ID),OS_NPC_SIT_NOW);
 777             }
 778             showMain(uID);
 779         } else if (command=="USER_STOOD") {
 780             key aviThatStood=llList2Key(message,1);
 781             integer indexAviThatStood=llListFindList(dancers,[aviThatStood]);
 782             osAvatarStopAnimation(aviThatStood,llList2String(dancers,indexAviThatStood+2));
 783             integer indexPair=getPairIndex(aviThatStood);
 784             integer indexPartner;
 785             string anToStartPartner;
 786             vector posPartner;
 787             vector rotPartner;
 788             if (indexPair==indexAviThatStood) {
 789                 indexPartner=indexPair+B2USER;
 790                 anToStartPartner=llList2String(anDefault,5);
 791                 posPartner=llList2Vector(anDefault,6);
 792                 rotPartner=llList2Vector(anDefault,7);
 793             } else {
 794                 indexPartner=indexPair;
 795                 anToStartPartner=llList2String(anDefault,2);
 796                 posPartner=llList2Vector(anDefault,3);
 797                 rotPartner=llList2Vector(anDefault,4);
 798             }
 799             key keyPartner=llList2Key(dancers,indexPartner);
 800             if (osIsUUID(keyPartner) && (keyPartner!=NULL_KEY)) {
 801                 dancers=[]+llListReplaceList(dancers,["avatar stood"],indexAviThatStood,indexAviThatStood);
 802                 dancers=[]+llListReplaceList(dancers,[0],indexPair+AUTO,indexPair+AUTO);
 803                 if (myState=="EDIT") {
 804                     myState="READY";
 805                     if (objectPresent(llList2Key(dancers,indexPartner+1))) osMessageObject(llList2Key(dancers,indexPartner+1),"HIDE_BALL");
 806                     llOwnerSay("WARNING!!! Either you or your partner stood (or crashed?) while in edit mode. Machine will immediately exit edit mode.\nChanges to the current animation ARE NOT stored.\nAny changes you've made to other animations ARE stored.\nThese will now be saved automatically to notecard to prevent their loss.\nYour dialog (if any) is now invalid so press any button to get a valid one");
 807                     saveNotecard();
 808                 }
 809                 if (osIsNpc(keyPartner)) { osNpcRemove(keyPartner); return;}
 810                 if (objectPresent(llList2Key(dancers,indexPartner+1))) osMessageObject(llList2Key(dancers,indexPartner+1),"MOVE_BALL|"+relToReg(llList2Vector(dancers,indexPair+BASEPOS),ZERO_ROTATION,posPartner,rotPartner));
 811                 osAvatarStopAnimation(keyPartner,llList2String(dancers,indexPartner+2));
 812                 osAvatarPlayAnimation(keyPartner,anToStartPartner);
 813                 llRegionSayTo(keyPartner,0,"Your partner is no longer dancing. If the ball is not re-occupied in the next "+(string)ballTimeout+" seconds both balls will be removed");
 814             } else {
 815                 if (llSubStringIndex(keyPartner,"pending_npc")==0) {
 816                     string killThis=llGetSubString(keyPartner,13,-1);
 817                     if (agentPresent((key)killThis)) osNpcRemove((key)killThis);
 818                 }
 819                 if (objectPresent(llList2Key(dancers,indexPartner+1))) osMessageObject(llList2Key(dancers,indexPartner+1),"KILL_BALL");
 820                 if (objectPresent(ball)) osMessageObject(ball,"KILL_BALL");
 821                 dancers=[]+llDeleteSubList(dancers,indexPair,indexPair+dancerStride-1);
 822                 updateText();
 823             }
 824         }
 825     }
 826     listen (integer channel, string name, key who, string message)
 827     {
 828         if (channel == RemoteChannel && llGetOwner() == llGetOwnerKey(who))
 829         {
 830             ProcessRemoteToucher(message);
 831         }
 832         else if (myState=="ERROR") 
 833         {
 834             if (who!=llGetOwner()) llRegionSayTo(who,0,"Sorry, the controller has encountered an error and needs to be reset before it can resume working. Please inform the owner");
 835             else 
 836             {
 837                 llOwnerSay("Attempting script reset");
 838                 llResetScript();
 839             }
 840         } 
 841         else if (myState=="INITIALIZING") llRegionSayTo(who,0,"Sorry, the controller is re-initializing. You will need to start dancing again once it has finished doing so");
 842         else if (myState=="EDIT") 
 843         {
 844             if (who!=llGetOwner()) { llRegionSayTo(who,0,"Sorry, the controller has been switched into edit mode will be reset once the owner has finished making changes. Then you'll be able to dance"); return;}
 845             if (message=="SYNCH") doSynch(who);
 846             else if (message=="< PREV") {
 847                 integer indexAn=llListFindList(anData,llList2List(dancers,STYLE,ANNAME));
 848                 persistCurrent(indexAn);
 849                 indexAn-=anStride;
 850                 if (indexAn<0) indexAn=llGetListLength(anData)-anStride;
 851                 playAnimation(0,indexAn);
 852                 llOwnerSay("Changes (if any) stored locally. Now editing\n    Style: "+llList2String(anData,indexAn)+"\n    Anim Name: "+llList2String(anData,indexAn+1));
 853             } else if (message=="NEXT >") {
 854                 integer indexAn=llListFindList(anData,llList2List(dancers,STYLE,ANNAME));
 855                 persistCurrent(indexAn);
 856                 indexAn+=anStride;
 857                 if (indexAn>llGetListLength(anData)) indexAn=0;
 858                 playAnimation(0,indexAn);
 859                 llOwnerSay("Changes (if any) stored locally. Now editing\n    Style: "+llList2String(anData,indexAn)+"\n    Anim Name: "+llList2String(anData,indexAn+1));
 860             } else if (message=="REVERT") {
 861                 integer indexAn=llListFindList(anData,llList2List(dancers,STYLE,ANNAME));
 862                 playAnimation(0,indexAn);
 863                 llOwnerSay("Reverted to original position. Now editing\n    Style: "+llList2String(anData,indexAn)+"\n    Anim Name: "+llList2String(anData,indexAn+1));
 864             } else if (message=="SAVE") {
 865                 integer indexAn=llListFindList(anData,llList2List(dancers,STYLE,ANNAME));
 866                 persistCurrent(indexAn);
 867                 saveNotecard();
 868             } else if (message=="EDIT OFF") {
 869                 integer indexAn=llListFindList(anData,llList2List(dancers,STYLE,ANNAME));
 870                 persistCurrent(indexAn);
 871                 myState="READY";
 872                 updateText();
 873                 osMessageObject(llList2Key(dancers,B1ID),"HIDE_BALL");
 874                 osMessageObject(llList2Key(dancers,B2ID),"HIDE_BALL");
 875             }
 876             showOptions(who);
 877         } 
 878         else if (myState=="READY") 
 879         {
 880             if (message=="OOPS") return;
 881             else if (message=="GROUP") startGroupDancing(who);
 882             else if (message=="SINGLES") 
 883             {
 884                 if (llGetListLength(singlesStyles)==1) 
 885                 {
 886                     singlesUsers=[]+singlesUsers+[who,llList2String(singlesStyles,0)];
 887                     startSingles(who,llList2String(singlesStyles,0));
 888                     llRegionSayTo(who,0,"You will start to dance momentarily...please touch me again to stop");
 889                 } 
 890                 else 
 891                 {
 892                     singlesUsers=[]+singlesUsers+[who,"NO_STYLE_SELECTED"];
 893                     showSinglesMenu(who,0);
 894                 }
 895                 return;
 896             } 
 897             else if ((message=="COUPLES") || (message=="NPC COUPLES")) 
 898             {
 899                 if (llListFindList(singlesUsers,who)>=0) {
 900                     llRegionSayTo(who,0,"Sorry, I seem to have you in my list of singles dancers. Please quit dancing first, then request a new couples dance");
 901                     showSinglesMenu(who,-1); return;
 902                 }
 903                 if (llListFindList(dancers,[who])>=0) {
 904                     llRegionSayTo(who,0,"Sorry, I already seem to have you in my list of couples dancers so I can't rez a new pair of danceballs for you. Please QUIT and inform the owner if this error continues to occur");
 905                     showMain(who); return;
 906                 }
 907                 vector toucherPos=llList2Vector(llGetObjectDetails(who,[OBJECT_POS]),0);
 908                 if (toucherPos==ZERO_VECTOR) {
 909                     llOwnerSay("ERROR! Toucher detected with ZERO_VECTOR as their location!");
 910                     llRegionSayTo(who,0,"Sorry, there appears to have been an error detecting your current location so I cannot rez any poseballs for you"); return;
 911                 }
 912                 if (llListFindList(ballRezFor,[who])>-1) {
 913                     integer indexBRF=llListFindList(ballRezFor,[who]);
 914                     if (llGetUnixTime()-llList2Integer(ballRezFor,indexBRF+1)<10) {
 915                         llRegionSayTo(who,0,"I think I have already rezzed a pair of balls for you within the last 10 seconds. If they failed to rez for some reason or you are unable to see them please wait a few more moments and try again (perhaps I detected a double-click in error)"); return;
 916                     }
 917                     else ballRezFor=[]+llDeleteSubList(ballRezFor,indexBRF,indexBRF+1);
 918                 }
 919                 if (message=="COUPLES") {
 920                     dancers=[] + dancers + ["pending_f",("AWAITING_BALL_REZ_"+(string)(nextBallID+1))] + llList2List(anDefault,2,4) + ["pending_m",("AWAITING_BALL_REZ_"+(string)(nextBallID+2))] + llList2List(anDefault,5,7) + [toucherPos, 0] + llList2List(anDefault,0,1) + [0];
 921                     llRegionSayTo(who,0,"Rezzing a pair of dance balls near you for you and your partner to sit on.");
 922                 } else {
 923                     dancers=[] + dancers + ["pending_npcf",("AWAITING_BALL_REZ_"+(string)(nextBallID+1))] + llList2List(anDefault,2,4) + ["pending_npcm",("AWAITING_BALL_REZ_"+(string)(nextBallID+2))] + llList2List(anDefault,5,7) + [toucherPos, 0] + llList2List(anDefault,0,1) + [0];
 924                     llRegionSayTo(who,0,"Rezzing a pair of dance balls. Your NPC partner will join you once you select one.");
 925                 }
 926                 llRezObject(poseballName,llGetPos(),ZERO_VECTOR,ZERO_ROTATION,(nextBallID+1));
 927                 llRezObject(poseballName,llGetPos(),ZERO_VECTOR,ZERO_ROTATION,(nextBallID+2));
 928                 nextBallID+=2;
 929                 ballRezFor=[]+ballRezFor + [who,llGetUnixTime()];
 930                 updateText();
 931             }
 932             else if ((llListFindList(dancers,[who])<0) && (llListFindList(singlesUsers,[who])<0) && (llListFindList(groupUsers,[who])<0) ) llRegionSayTo(who,0,"Sorry, you don't appear to be in my list of current dancers any more.");
 933             else if (message=="-") showMain(who);
 934             else if (message=="*") showSinglesMenu(who,-1);
 935             else if (message=="~") {
 936                 integer thisPair=getPairIndex(who);
 937                 if (llList2Integer(dancers,thisPair+AUTO)) showMain(who);
 938                 else {
 939                     string backToStyle=llList2String(dancers,thisPair+STYLE);
 940                     if (llListFindList(styles,backToStyle)<0) showMain(who);
 941                     else showPickAn(who,backToStyle);
 942                 }
 943             } else if (message=="EDIT ON") {
 944                 if ((llGetListLength(dancers)>dancerStride) || (llGetListLength(singlesUsers)>0)) {
 945                     llOwnerSay("Sorry, it appears that someone else is using the controller now so you cannot enter edit mode until they quit.");
 946                     showOptions(who);
 947                 } else {
 948                     myState="EDIT";
 949                     updateText();
 950                     osMessageObject(llList2Key(dancers,B1ID),"EDIT_BALL");
 951                     osMessageObject(llList2Key(dancers,B2ID),"EDIT_BALL");
 952                     integer indexAn=llListFindList(anData,llList2List(dancers,STYLE,ANNAME));
 953                     dancers=[]+llListReplaceList(dancers,[0],SWAPFLAG,SWAPFLAG);
 954                     playAnimation(0,indexAn);
 955                     llOwnerSay("Entering edit mode.\nVERY IMPORTANT!!!! Any changes are only stored in live memory. To remember them for future you must click SAVE before the next time the system is reset to save them to notecard.\n\nNow editing\nStyle: "+llList2String(anData,indexAn)+"\nAnim Name: "+llList2String(anData,indexAn+1));
 956                     showOptions(who);
 957                 }
 958             } else if (message=="BACK") {
 959                 string backToStyle=llList2String(dancers,getPairIndex(who)+STYLE);
 960                 if (llListFindList(styles,backToStyle)<0) showMain(who);
 961                 else showPickAn(who,backToStyle);
 962             } else if (message=="SWAP") {
 963                 integer thisPair=getPairIndex(who);
 964                 integer nextAnIndex=llListFindList(anData,llList2List(dancers,thisPair+STYLE,thisPair+ANNAME));
 965                 if (nextAnIndex<0) llRegionSayTo(who,0,"Sorry, I am unable to swap positions for the current animation");
 966                 else {
 967                     if (llList2Integer(dancers,thisPair+SWAPFLAG)==0) dancers=[]+llListReplaceList(dancers,[1],thisPair+SWAPFLAG,thisPair+SWAPFLAG);
 968                     else dancers=[]+llListReplaceList(dancers,[0],thisPair+SWAPFLAG,thisPair+SWAPFLAG);
 969                     playAnimation(thisPair,nextAnIndex);
 970                 }
 971                 showOptions(who);
 972             } else if (message=="AUTO") {
 973                 integer thisPair=getPairIndex(who);
 974                 dancers=[]+llListReplaceList(dancers,[1],thisPair+AUTO,thisPair+AUTO);
 975                 string txtToSay="Your couple is now in Auto dance mode.\nHappy dancing!";
 976                 llRegionSayTo(llList2Key(dancers,thisPair+B1USER),0,txtToSay);
 977                 llRegionSayTo(llList2Key(dancers,thisPair+B2USER),0,txtToSay);
 978                 if (llListFindList(anData,[llList2String(dancers,thisPair+STYLE)])<0) playAnimation(thisPair,0);
 979                 showMain(who);
 980             } else if (message=="MANUAL") {
 981                 integer thisPair=getPairIndex(who);
 982                 dancers=[]+llListReplaceList(dancers,[0],thisPair+AUTO,thisPair+AUTO);
 983                 string txtToSay="Your couple is now in Manual dance mode.";
 984                 llRegionSayTo(llList2Key(dancers,thisPair+B1USER),0,txtToSay);
 985                 llRegionSayTo(llList2Key(dancers,thisPair+B2USER),0,txtToSay);
 986                 showMain(who);
 987             } else if (message=="Z ADJUST") {
 988                 if (objectPresent(llList2Key(dancers,llListFindList(dancers,[who])+1))) osMessageObject(llList2Key(dancers,llListFindList(dancers,[who])+1),"ENABLE_Z|"+(string)zStep);
 989                 llRegionSayTo(who,0,"Z-Adjust enabled. Use your keyboard's PAGE UP and PAGE DOWN keys to adjust your height off the floor (this only changes your position, your partner may need to make a similar adjustment)\nThe adjustments you make will apply to all future dances you select. Use \"Z STOP ADJ\" to turn off the adjustment controls and keep your current setting, or \"Z RESET\" to return to the default position.");
 990                 showOptions(who);
 991             } else if (message=="Z STOP ADJ") {
 992                 if (objectPresent(llList2Key(dancers,llListFindList(dancers,[who])+1))) osMessageObject(llList2Key(dancers,llListFindList(dancers,[who])+1),"DISABLE_Z");
 993                 llRegionSayTo(who,0,"Z-Adjust disabled but your current adjustment will apply to any other dances you select. Press \"Z RESET\" at any time if you want to clear it");
 994                 showOptions(who);
 995             } else if (message=="Z RESET") {
 996                 if (objectPresent(llList2Key(dancers,llListFindList(dancers,[who])+1))) osMessageObject(llList2Key(dancers,llListFindList(dancers,[who])+1),"UNSET_Z");
 997                 llRegionSayTo(who,0,"Your current z-adjustment has been reset to zero");
 998                 showOptions(who);
 999             } else if ((message=="NEW M") || (message=="NEW F")) {
1000                 integer thisPair=getPairIndex(who);
1001                 key keyToChange=llList2Key(dancers,thisPair+B1USER);
1002                 if (keyToChange==who) keyToChange=llList2Key(dancers,thisPair+B2USER);
1003                 if (osIsNpc(keyToChange)) {
1004                     if (message=="NEW M") {
1005                         indexNpcM++;
1006                         if (indexNpcM>=llGetListLength(partnerM)) indexNpcM=0;
1007                         osNpcLoadAppearance(keyToChange,llList2String(partnerM,indexNpcM));
1008                     } else {
1009                         indexNpcF++;
1010                         if (indexNpcF>=llGetListLength(partnerF)) indexNpcF=0;
1011                         osNpcLoadAppearance(keyToChange,llList2String(partnerF,indexNpcF));
1012                     }
1013                 } else llRegionSayTo(who,0,"Can't change your partner's appearance...they aren't a NPC.");
1014                 showOptions(who);
1015             } else if (message=="STYLES") showMain(who);
1016             else if (message=="SYNCH") {
1017                 doSynch(who);
1018                 integer thisPair=getPairIndex(who);
1019                 if (llList2Integer(dancers,thisPair+AUTO)) showMain(who);
1020                 else {
1021                     string backToStyle=llList2String(dancers,thisPair+STYLE);
1022                     if (llListFindList(styles,backToStyle)<0) showMain(who);
1023                     else showPickAn(who,backToStyle);
1024                 }
1025             } else if (message=="OPTIONS") showOptions(who);
1026             else if (message=="QUIT") {
1027                 if (llListFindList(singlesUsers,[who])>=0) {
1028                     integer indWho=llListFindList(singlesUsers,[who]);
1029                     stopSingles(who,llList2String(singlesUsers,indWho+1));
1030                     singlesUsers=[]+llDeleteSubList(singlesUsers,indWho,indWho+1);
1031                 } else {
1032                     integer thisPair=getPairIndex(who);
1033                     string txtToSay="One of the couple has chosen to quit dancing";
1034                     if (objectPresent(llList2Key(dancers,thisPair+B1ID))) osMessageObject(llList2Key(dancers,thisPair+B1ID),"KILL_BALL");
1035                     if (osIsNpc(llList2Key(dancers,thisPair+B1USER))) osNpcRemove(llList2Key(dancers,thisPair+B1USER));
1036                     else if (osIsUUID(llList2Key(dancers,thisPair+B1USER))) {
1037                         osAvatarStopAnimation(llList2Key(dancers,thisPair+B1USER),llList2String(dancers,thisPair+B1AN));
1038                         llRegionSayTo(llList2Key(dancers,thisPair+B1USER),0,txtToSay);
1039                     } else if (llSubStringIndex(llList2Key(dancers,thisPair+B1USER),"pending_")>=0) {
1040                         string killNpcPendingF=llGetSubString(llList2String(dancers,thisPair+B1USER),13,-1);
1041                         if (osIsUUID(killNpcPendingF)) { if (llGetAgentSize(killNpcPendingF)!=ZERO_VECTOR) osNpcRemove((key)killNpcPendingF); }
1042                     }
1043                     if (objectPresent(llList2Key(dancers,thisPair+B2ID))) osMessageObject(llList2Key(dancers,thisPair+B2ID),"KILL_BALL");
1044                     if (osIsNpc(llList2Key(dancers,thisPair+B2USER))) osNpcRemove(llList2Key(dancers,thisPair+B2USER));
1045                     else if (osIsUUID(llList2Key(dancers,thisPair+B2USER))) {
1046                         osAvatarStopAnimation(llList2Key(dancers,thisPair+B2USER),llList2String(dancers,thisPair+B2AN));
1047                         llRegionSayTo(llList2Key(dancers,thisPair+B2USER),0,txtToSay);
1048                     } else if (llSubStringIndex(llList2Key(dancers,thisPair+B2USER),"pending_")>=0) {
1049                         string killNpcPendingM=llGetSubString(llList2String(dancers,thisPair+B2USER),13,-1);
1050                         if (osIsUUID(killNpcPendingM)) { if (llGetAgentSize(killNpcPendingM)!=ZERO_VECTOR) osNpcRemove((key)killNpcPendingM); }
1051                     }
1052                     dancers=[]+llDeleteSubList(dancers,thisPair,thisPair+dancerStride-1);
1053                 }
1054                 updateText();
1055             } else if ((message=="< PREV") || (message=="NEXT >") || (message=="SAVE") || (message=="REVET") || (message=="EDIT OFF")) showMain(who);
1056             else if (llListFindList(singlesUsers,[who])>=0) {
1057                 integer page=-1;
1058                 integer uInd=llListFindList(singlesUsers,[who]);
1059                 if (llSubStringIndex(message,"PAGE ")>=0) page=(integer)llGetSubString(message,5,-1)-1;
1060                 else if (message!=llList2String(singlesUsers,uInd+1)) {
1061                     singlesUsers=[]+llListReplaceList(singlesUsers,[message],uInd+1,uInd+1);
1062                     startSingles(who,message);
1063                 }
1064                 showSinglesMenu(who,page);
1065             } else if (llListFindList(styles,[message])>-1) {
1066                 integer thisPair=getPairIndex(who);
1067                 if (llList2Integer(dancers,thisPair+AUTO)) {
1068                     string txtToSay="New auto dance style selected by your couple: "+message;
1069                     if (osIsUUID(llList2Key(dancers,thisPair+B1USER))) llRegionSayTo(llList2Key(dancers,thisPair+B1USER),0,txtToSay);
1070                     if (osIsUUID(llList2Key(dancers,thisPair+B2USER))) llRegionSayTo(llList2Key(dancers,thisPair+B2USER),0,txtToSay);
1071                     dancers=[]+llListReplaceList(dancers,[message],thisPair+STYLE,thisPair+STYLE);
1072                     playAnimation(thisPair,llListFindList(anData,[message]));
1073                     showMain(who);
1074                 } else showPickAn(who,message);
1075             } else if (llListFindList(anData,[message])>-1) {
1076                 integer thisPair=getPairIndex(who);
1077                 if (llList2Integer(dancers,thisPair+AUTO)) {
1078                     string txtToSay="A dance was manually selected...switching your couple to manual dance mode";
1079                     if (osIsUUID(llList2Key(dancers,thisPair+B1USER))) llRegionSayTo(llList2Key(dancers,thisPair+B1USER),0,txtToSay);
1080                     if (osIsUUID(llList2Key(dancers,thisPair+B2USER))) llRegionSayTo(llList2Key(dancers,thisPair+B2USER),0,txtToSay);
1081                     dancers=[]+llListReplaceList(dancers,[0],thisPair+AUTO,thisPair+AUTO);
1082                 }
1083                 integer selectedDanceIndex=llListFindList(anData,[message])-1;
1084                 playAnimation(thisPair,selectedDanceIndex);
1085                 showPickAn(who,llList2String(anData,selectedDanceIndex));
1086             } else llOwnerSay("ERROR! Received a dialog response in READY state but it failed to match a button name and was neither a style nor animation name. This shouldn't be possible!");
1087         }
1088     }
1089 }

Syntax Highlighting

GeShi syntax highlighting is enabled on this wiki. <be>

When using the tabs described in the link, change the language part to "lsl". Eg.
syntaxhighlight lang="lsl" line
inside angled brackets <>