Av-Sitter To PMAC Converter.

From Fire And Ice Grid
Revision as of 23:41, 6 June 2020 by Admindiamond (talk | contribs) (Created page with "== AV-Sitter2 to PMAC conversion script – Introduction == The Covey AV-Sitter2 to PMAC conversion script reads AV-Sitter position cards and converts them to PMAC menus. AV-S...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

AV-Sitter2 to PMAC conversion script – Introduction

The Covey AV-Sitter2 to PMAC conversion script reads AV-Sitter position cards and converts them to PMAC menus. AV-Sitter uses 2 scripts per avatar and another for setting up pose positions. PMAC, written Aine Caoimhe is a single script. AV-Sitter has a few features PMAC does not support and can be used in Second Life.

About PMAC

The Paramour Multi-Animation Controller (PMAC) is a no pose ball script system. Use PMAC in almost any piece of furniture to animate multiple avatars simultaneously. PMAC reads notecards directly and uses significantly fewer resources than AV-Sitter, map or many others.

AV-Sitter2 to PMAC conversion script – Instructions

Add the conversion script to a prim containing an AV-Sitter positions notecard (AVpos). Script status is in local chat and so is a finish notice. New PMAC menu cards are in the item inventory. Next add the PMAC core script, default animation and configuration notecard.

Important – Work on a copy

Please work on a copy, this script does not convert all AV-Sitter features to PMAC

Single Menus

PMAC handles singles differently to AV-Sitter. When a singles menu is used only one sitter is enabled. To try and work around this, the script looks for singles poses with matching button names from each sitter. If found it will turn the two or more matching singles poses into a set of 2 or more that work like Av-Sitter SYNCS (Couples poses). If a name has no match, it is a single menu.entry.

Menu And Button Names

AV-Sitter can have many configurations. Animations are grouped by menu and button names. In each sitter, the Menu Name must match. When matching menu names are found, it drops down to line by line checking, only pairing matching button names.

Also available on GitHub and on the Fire And Ice Grid at the Covey Stores And Welcome Region.

  1 integer menuCardNumber = 2; //used at the end when writing the new menu cards
  2 string AvPosCardName = "AVpos"; //name of the Av-sitter positions card
  3 integer debug = FALSE; //turns this on to see debug output, this generates a LOT of local chat output
  4 //if you use the debug option it's suggested you comment them out section by sec
  5    
  6 ConvertRotations()
  7 {   //AvSitter uses x,y,z rotations, PMAC uses quaternion rotations, so convert them. 
  8     list tempList = [];
  9     integer lineNumber;
 10     integer notecardLines = osGetNumberOfNotecardLines(AvPosCardName);
 11     for (lineNumber = 0; lineNumber < notecardLines; lineNumber++)
 12     {   //loops through each line of the notecard
 13         string initial = osGetNotecardLine(AvPosCardName, lineNumber);
 14         string noTimes = RemoveTimes(initial);
 15         integer braceIndex = llSubStringIndex(noTimes, "}");
 16         string fixedRotation;
 17         if (braceIndex != -1)
 18         {   //only deal with lines wich contain a } (pos/rot line)
 19             fixedRotation = ConvertLineToRotations(noTimes); //convert this line to real rotations
 20         }
 21         else 
 22         {   //only deal with lines that do not contain a } (pos/rot line)
 23             fixedRotation = noTimes;
 24         }
 25         tempList += fixedRotation; //add the line to the temp list
 26     }
 27     //write the temp list to a notecard
 28     WriteNotecard("FixedRotations", tempList);
 29 } 
 30 WriteNotecard(string name, list contents)
 31 {   //writes a notecard with the supplied name and contents
 32     /*
 33     The conversion script relies on the contents of notecards, Ensure the notecards are deleted and saved before continuing.   
 34     */
 35     integer inventoryType;
 36     if (llGetInventoryType(name) == INVENTORY_NOTECARD)
 37     {
 38         llRemoveInventory(name);
 39         inventoryType = llGetInventoryType(name);
 40         while (inventoryType > -1) //-1 means it doesn't exist 
 41         {   //wait to make sure the removal is complete before going on
 42             inventoryType = llGetInventoryType(name);
 43         }
 44     }
 45     osMakeNotecard(name, contents);
 46     inventoryType = llGetInventoryType(name);
 47     while (inventoryType != INVENTORY_NOTECARD)
 48     {   //wait for the write to finish before going on
 49         inventoryType = llGetInventoryType(name);
 50     }
 51 }
 52 DebugOwnerSayListContents(string name, list toDisplay)
 53 {   //outputs the contents of a list nicely to local chat for the owner.
 54     string output = "Debug:ListContents:" + "\n" + "ListName: " + name;
 55     llOwnerSay(output);
 56     integer index;
 57     for (index = 0; index < llGetListLength(toDisplay); index++)
 58     {   //loop through every line of the list outputting to local chat
 59         llOwnerSay(llList2String(toDisplay, index));  
 60     }
 61 }
 62 list ReverseListOrder(list inputList)
 63 {   //reverses the order of a list. 
 64     list reverseList;
 65     integer index;
 66     for (index = llGetListLength(inputList)-1; index >= 0 ; index--)
 67     {   //loops through the list backwards, adding each line to a new list
 68         reverseList += llList2String(inputList, index);
 69     }
 70     return reverseList;
 71 }
 72 string ConvertLineToRotations (string inputString)
 73 {   //takes in the AVpos format and outputs PMAC format
 74     string name = "{"+ NameFromPositionsLine(inputString) + "}";
 75     vector posVec = (vector)PosFromPositionsLine(inputString);
 76     vector rotVec = (vector)RotFromPositionsLine (inputString);
 77     rotation rotRot = llEuler2Rot(rotVec * DEG_TO_RAD); //the actual conversion
 78     string fixedString = name + (string)posVec + (string)rotRot;
 79     return fixedString;
 80 }
 81 list GetSpecificNotecardCards (string searchString)
 82 {   //uses a partial name string to return all matching notecards from the items inventory
 83     list sitterNotecards;
 84     integer numOfNotecards = llGetInventoryNumber(INVENTORY_NOTECARD);
 85     integer index;
 86     for (index = 0; index < numOfNotecards; index++)
 87     {   //loops through every notecard in the inventory
 88         string notecardName = llGetInventoryName(INVENTORY_NOTECARD, index);
 89         string testName = llGetSubString(notecardName, 0, llStringLength(searchString)-1);
 90         if (testName == searchString)
 91         {   //if we find a match add it to the list
 92             sitterNotecards += notecardName;
 93         }
 94     }
 95     return sitterNotecards;
 96 }
 97 string MenuNameFromMenuLine(string inputString)
 98 {
 99     integer spaceChar = llSubStringIndex(inputString, " ");//find the space character
100     string menuName = llStringTrim(llGetSubString(inputString, spaceChar +1, -1), STRING_TRIM); //remove everythign before the space
101     return menuName;
102 }
103 string NameFromPositionsLine(string inputString)
104 {
105     integer charBracket = llSubStringIndex(inputString, "}"); //find the } character
106     string nValue = llGetSubString(inputString, 1, charBracket-1); //remove curley brackets and position data
107     return nValue;
108 }
109 string PosFromPositionsLine(string inputString)
110 {
111     integer charLess = llSubStringIndex (inputString, "<"); // find the first < character
112     integer charMore = llSubStringIndex (inputString, ">"); // find the first > character
113     string vValue = llGetSubString (inputString, charLess, charMore); // removed everything except the vector
114     return vValue; 
115 }
116 string RotFromPositionsLine (string inputString)
117 {
118     integer charMore = llSubStringIndex (inputString, ">"); // find the first > character
119     string rotValue = llGetSubString (inputString, charMore+1, -1); //remove everything except the rotation vector
120     return rotValue; 
121 }
122 string RemoveTimes(string inputString)
123 {
124     integer charStart = llSubStringIndex(inputString, "◆");//find the position of the real start of the line and discard all before it
125     string trimed = llGetSubString(inputString, charStart+1, -1); //remove everything before the "◆"
126     return trimed;
127 }
128 string GetPoseName (string inputString)
129 {
130     integer charLine = llSubStringIndex(inputString,"|"); //find the | seperator character
131     string lValue = llGetSubString (inputString, 0, charLine-1); // remove everything after the |
132     return lValue;
133 }
134 string GetAnimName (string inputString)
135 {
136     integer charLine = llSubStringIndex(inputString, "|"); // find the | seperator
137     string lValue = llGetSubString(inputString, charLine+1, -1); //remove everythign before the |
138     return lValue;
139 }
140 string GetSitterNumberFromMenuCardName(string menuCardName)
141 {
142     list elements = llParseStringKeepNulls(menuCardName, "_", ""); //make a list seperated by underscores
143     string sitterNumber = llList2String(elements, 2); //retrieve the sitter number from the list
144     return sitterNumber;
145 }
146 string GetMenuNameFromMenuCardName(string menuCardName)
147 {
148     list elements = llParseStringKeepNulls(menuCardName, "_", "");//make a list seperated by underscores
149     string name = llList2String(elements, 3);//retrieve the name number from the list
150     return name;
151 }
152 string GetButtonNameFromPmacLine(string inputString)
153 {
154     integer barIndex = llSubStringIndex(inputString, "|");// find the | seperator
155     string name = llGetSubString(inputString, 0, barIndex-1); //remove everything after the |
156     return name;
157 }
158 SplitIntoSitters()
159 {   //splits the AVpos card down into individual sitters
160     list tempSitterList;
161     integer sitterCount = -1; //start at -1 so that we don't save contents before the first SITTER line
162     integer lineNumber;
163     integer notecardLines = osGetNumberOfNotecardLines("FixedRotations");
164     for (lineNumber = 0; lineNumber < notecardLines; lineNumber++)
165     {   //loop through ever line of the AVpos notecard
166         string currentLine1 = osGetNotecardLine("FixedRotations", lineNumber);
167         if (currentLine1 != "")
168         {   //ignore blank lines
169             string test = llGetSubString(currentLine1, 0, 3);
170             string test2 = llGetSubString(currentLine1, 0, 0);
171             if (test == "SITT")
172             {   //do something for SITTER line found
173                 if (sitterCount > -1)
174                 {   //if we find a new SITTER line write the contents of the temp list to a notecard
175                     WriteNotecard("Sitter" + (string)sitterCount, tempSitterList);               
176                     tempSitterList = [];//clear the list ready to start again
177                 }
178                 sitterCount++;
179             }
180             else if (test == "MENU" || test == "POSE" || test == "SYNC" || test2 == "{")
181             {   //only deal with the menus, poses, syncs and pos/rot lines
182                 tempSitterList += currentLine1; //add info to the new list
183             }
184                         
185         }
186     }
187     //write a notecard containing all needed information for this sitter
188     WriteNotecard("Sitter" + (string)sitterCount, tempSitterList);
189 }
190 list GetSitterSyncsAndMenus(string notecardName)
191 {   //loops through the named notecard looking for lines which start with SYNC, MENU or { (pos/rot lines)
192     //adds them to the new list as they are found
193     list sitterSyncsAndMenus;
194     list poseNames;
195     integer lineNumber;
196     for (lineNumber = 0; lineNumber < osGetNumberOfNotecardLines(notecardName); lineNumber++)
197     {   //loops through every line of the notecard
198         string currentLine2 = osGetNotecardLine(notecardName, lineNumber);
199         string testPose = llGetSubString(currentLine2, 0, 3);
200         string testAnimData = llGetSubString(currentLine2, 0, 0);
201         string testPoseName; 
202         if (testPose == "SYNC")
203         {   //for every SYNC line remove the word SYNC and the space, retrieve the pose name from the remainder
204             //and add the pose name to the list of pose names
205             string withoutTitle = llStringTrim(llGetSubString(currentLine2, 5, -1), STRING_TRIM); 
206             sitterSyncsAndMenus += withoutTitle;
207             testPoseName = GetPoseName(withoutTitle);
208             poseNames += testPoseName;
209         }
210         else if (testPose == "MENU")
211         {   //add ever Menu line to the list
212             sitterSyncsAndMenus += currentLine2;
213         }
214         else if (testAnimData == "{")
215         {   //come here for every pos/rot line, check the name and if it matches
216             //add it to the list
217             integer closeBraceIndex = llSubStringIndex(currentLine2, "}");
218             string lineAnimName = llGetSubString(currentLine2, 1, closeBraceIndex-1);
219             if(~llListFindList(poseNames, (list)lineAnimName))
220             {   //if the name matches any of the ones added to the pose list earlier, add the line
221                 //to the main list. 
222                 sitterSyncsAndMenus += currentLine2;
223             }
224         }
225     }
226     return sitterSyncsAndMenus;
227 }
228 list GetSitterPOSEs(string notecardName)
229 {   //loop through the supplied notecard name saving just pose names and related pos/rot lines
230     list sitterPoses;
231     list poseNames;
232     integer lineNumber;
233     for (lineNumber = 0; lineNumber < osGetNumberOfNotecardLines(notecardName); lineNumber++)
234     {   //loops through every line in the notecard
235         string currentLine2 = osGetNotecardLine(notecardName, lineNumber);
236         string testPose = llGetSubString(currentLine2, 0, 3);
237         string testAnimData = llGetSubString(currentLine2, 0, 0);
238         string testPoseName; 
239         if (testPose == "POSE")
240         {   //checks each pose line, retrieves the name then adds the name to the poses list
241             string withoutTitle = llStringTrim(llGetSubString(currentLine2, 5, -1), STRING_TRIM); 
242             sitterPoses += withoutTitle;
243             testPoseName = GetPoseName(withoutTitle);
244             poseNames += testPoseName;
245         }
246         else if (testAnimData == "{")
247         {   //checks every pos/rot line, if the name matches one save earlier add it to the list
248             integer closeBraceIndex = llSubStringIndex(currentLine2, "}");
249             string lineAnimName = llGetSubString(currentLine2, 1, closeBraceIndex-1);
250             if(~llListFindList(poseNames, (list)lineAnimName))
251             {   //if the lines name matches one in the pose list add the whole line to the main list
252                 sitterPoses += currentLine2;
253             }
254         }
255     }
256     return sitterPoses;
257 }
258 FixAndCombineSinglePoses()
259 {   //makes new notecards with the sync and poses seperated 
260     //along with their related pos/rot information. 
261     SeperatePoseNamesAndData();
262     CreateNewSyncSetFromPoses();
263 }
264 SeperatePoseNamesAndData()
265 {   //loops through every sitter card making new serpate cards for poses (not syncs) and their related pos/rot 
266     list sitterNotecards = GetSpecificNotecardCards("Sitter");
267     integer sitterCardIndex;
268     for(sitterCardIndex = 0; sitterCardIndex < llGetListLength(sitterNotecards); sitterCardIndex++)
269     {   //loops through every sitter notecard
270         string cardName = llList2String(sitterNotecards, sitterCardIndex);
271         list sitterPoses = GetSitterPOSEs(cardName);
272         list sitterPosRotData;
273         integer lineIndex;
274         for (lineIndex = llGetListLength(sitterPoses)-1; lineIndex >=0; lineIndex--)
275         {   //add all lines with braces to the sitte pos/rot list and remove from sitter poses list
276             string currentLine3 = llList2String(sitterPoses, lineIndex);
277             integer hasBraces = llSubStringIndex(currentLine3, "}");
278             if (hasBraces > -1)
279             {   //takes every pos/rot line and adds it to the pos/rot line list
280                 if (debug) llOwnerSay("Debug:BracesLine: " + currentLine3);
281                 sitterPosRotData += currentLine3;
282                 sitterPoses = llDeleteSubList(sitterPoses, lineIndex, lineIndex);
283             }
284         }
285         //write out both cards, reversing the order of the pos/rot card so it matches the order of the menu card. 
286         WriteNotecard("Poses " + cardName, sitterPoses);
287         sitterPosRotData = ReverseListOrder(sitterPosRotData);
288         WriteNotecard("DataPoses " + cardName, sitterPosRotData);
289     }
290 }
291 GeneratePoseToSyncCards(list poseCards, list newSyncNames)
292 {   //loops through all pose cards line by line, looking for names with the same button names
293     //assumes these are supposed to be paied up and makes new SYNC menus from them. 
294     list newSyncPoses;
295     list newSyncData;
296     integer poseCardIndex;
297     for (poseCardIndex = 0; poseCardIndex < llGetListLength(poseCards); poseCardIndex++)
298     {   //loops through each card
299         string cardName = "Poses Sitter" + (string)poseCardIndex;
300         integer cardLength = osGetNumberOfNotecardLines(cardName);
301         if(debug) llOwnerSay("Debug:ReadingCard: " + cardName);
302         integer lineIndex;
303         newSyncPoses = [];
304         newSyncData = [];
305         string menu = "MENU Social-A";
306         newSyncPoses += menu;
307         for (lineIndex = 0; lineIndex < cardLength; lineIndex++)
308         {   //loops through each line in the given notecard
309             string posesLine = osGetNotecardLine("Poses Sitter" + (string)poseCardIndex, lineIndex);
310             string dataLine = osGetNotecardLine("DataPoses Sitter" + (string)poseCardIndex,lineIndex);
311             string poseName = GetPoseName (posesLine);
312             if (debug) llOwnerSay("Debug:CheckingPoseName: " + poseName);
313             if (~llListFindList(newSyncNames, (list)poseName))
314             {   //come here if the current pose name is found in the new sync names list
315                 if (debug) llOwnerSay("Debug:Found" + poseName);
316                 string newPoseLine = "SYNC " + posesLine;
317                 newSyncPoses += newPoseLine;
318                 newSyncData += dataLine;
319             }
320         }
321         list combinedList = newSyncPoses + newSyncData;
322         WriteNotecard("PoseToSyncSitter" + (string)poseCardIndex, combinedList);    
323     }
324 }
325 CreateNewSyncSetFromPoses()
326 {   //loops though every pose card and attempts to find pairs which should be used together. 
327     //then makes a list of real single only poses and pairs to treat as syncs, pmac singles
328     //don't allow others to sit, so better to pair them up when possible. 
329     list posesCards = GetSpecificNotecardCards("Poses Sitter");
330     integer posesCardIndex;
331     list poseNamesSitter0;
332     list newSyncNames;
333     list newSinglesNames;
334     if (debug) DebugOwnerSayListContents("list of poses cards", posesCards);
335     //loop through all cards checking for duplicate pose names, store them in newSyncNames
336     for (posesCardIndex = 0; posesCardIndex < llGetListLength(posesCards); posesCardIndex++)
337     {   //loops through each card, checking against sitter 0
338         integer lineIndex;
339         string notecardName = llList2String(posesCards, posesCardIndex);
340         integer notecardLength = osGetNumberOfNotecardLines(notecardName);
341         for (lineIndex = 0; lineIndex < notecardLength; lineIndex++)
342         {
343             string currnetLine = osGetNotecardLine(notecardName, lineIndex);
344             string poseName = GetPoseName (currnetLine);
345             if (posesCardIndex == 0)
346             {
347                 poseNamesSitter0 += poseName;
348             }
349             else
350             {
351                 if(~llListFindList(poseNamesSitter0, (list)poseName))
352                 { //come here if poseName is found in sitter0
353                     if (!(~llListFindList(newSyncNames, (list)poseName)))
354                     {   //come here only if the pose is not already in the new sync names
355                         newSyncNames += poseName;
356                     }
357                 }
358                 else
359                 {   //come here if the pose is not found in sitter 0
360                     if (!(~llListFindList(newSinglesNames, (list)poseName)))
361                     {   //come here only if the pose is not already in the new sync names
362                         newSinglesNames += poseName;
363                     }
364                 }
365             }
366         }
367     }
368     GenerateNewSinglesCard(newSyncNames);
369     GeneratePoseToSyncCards(posesCards, newSyncNames);
370     CombinePoseToSyncCardsWithSiterCards();
371 }
372 CombinePoseToSyncCardsWithSiterCards()
373 {   //takes the new sync cards (made from pair poses) and combines
374     //these new menus with the original sitter cards ready for sync set processing
375     list sitterCards = GetSpecificNotecardCards ("Sitter");
376     integer sitterCardIndex;
377     for (sitterCardIndex = 0; sitterCardIndex < llGetListLength(sitterCards); sitterCardIndex++)
378     {
379         list newSitterCard;
380         string currentLine;
381         string CardName = "Sitter" + (string)sitterCardIndex;
382         newSitterCard += AllLinesWithOrWithoutBraces (CardName, FALSE);
383         CardName = "PoseToSyncSitter" + (string)sitterCardIndex;
384         newSitterCard += AllLinesWithOrWithoutBraces (CardName, FALSE);
385         CardName = "Sitter" + (string)sitterCardIndex;
386         newSitterCard += AllLinesWithOrWithoutBraces (CardName, TRUE);
387         CardName = "Sitter" + (string)sitterCardIndex;
388         newSitterCard += AllLinesWithOrWithoutBraces (CardName, TRUE);
389         if (debug) DebugOwnerSayListContents("New Sitter " + (string)sitterCardIndex +  " card", newSitterCard);
390         WriteNotecard("Sitter" + (string)sitterCardIndex, newSitterCard);
391     }
392 }
393 list AllLinesWithOrWithoutBraces(string cardName, integer with)
394 {   //loops through the given notecard name, if the "with" integer is TRUE
395     //adds all lines with braces to a list. If the "with" is FALSE all lines
396     //without braces are added to the list. 
397     list newList;
398     integer CardLength = osGetNumberOfNotecardLines(cardName);
399     integer lineNumber;
400     //add lines without braces from the sitter card
401     for (lineNumber = 0; lineNumber < CardLength; lineNumber++)
402     {   //loops through the whole notecards
403         string currentLine = osGetNotecardLine(cardName, lineNumber);
404         integer hasBraces = llSubStringIndex(currentLine, "{");
405         if(with)
406         {   //we want all lines with braces
407             if (hasBraces > -1) 
408             {
409                 newList += currentLine;
410             }
411         }
412         else
413         {   //we want all lines without braces
414             if (hasBraces == -1)
415             {
416                 newList += currentLine;
417             }
418         }
419     }
420     return newList;
421 }
422 GenerateNewSinglesCard(list newSyncNames)
423 {   //loops through all poses in all the sitter cards, checks to see if they have matching
424     //entries in the newSyncNames list, if they don't ass them to a list of real single 
425     //poses and writes the note card when the list is complelete
426     if (debug) llOwnerSay("Debug:GenerateNewSinglesCard: Entered");
427     integer posesSitter0Line;
428     list posesCards = GetSpecificNotecardCards("Poses Sitter");
429     if (debug) DebugOwnerSayListContents("posesCards", posesCards);
430     if (debug) DebugOwnerSayListContents("sync names list", newSyncNames);
431     list newSinglePoses;
432     list newSinglePosesData;
433     integer posesCardIndex; 
434     for (posesCardIndex = 0; posesCardIndex < llGetListLength(posesCards); posesCardIndex++)
435     {   //loops through each poses card card
436         integer lineIndex;
437         string notecardName = llList2String(posesCards, posesCardIndex);
438         if (debug) llOwnerSay("Debug:CheckingCard: " + notecardName);
439         integer notecardLength = osGetNumberOfNotecardLines(notecardName);
440         for (lineIndex = 0; lineIndex < notecardLength; lineIndex++)
441         {   //loops through every line of the current poses card
442             string currentLine4 = osGetNotecardLine(notecardName, lineIndex);
443             string poseName = GetPoseName (currentLine4);
444             if (debug) llOwnerSay("Debug: checking pose name: " + poseName);
445             integer matchFound = FALSE;
446             integer newSyncNamesIndex = 0;
447             //now check this line against every line of new sync names
448             while (!matchFound && newSyncNamesIndex < llGetListLength(newSyncNames))
449             {   //loops through the sync poses checking for a match, keeps going until it finishes withou
450                 //a result or finds a match
451                 string newSyncNamesLine = llList2String(newSyncNames, newSyncNamesIndex);
452                 if(debug) llOwnerSay("Debug:Checking:" + currentLine4 + " against " + newSyncNamesLine);
453                 if (poseName == newSyncNamesLine)
454                 {   //come here if a a match has been found, stop the loop 
455                     if(debug) llOwnerSay("Debug:MatchFound");
456                     matchFound = TRUE;
457                 }
458                 newSyncNamesIndex++;
459             }
460             if (!matchFound)
461             {   //loop though the sync cards has ended, no match found, add this item to the singles list
462                 //add the data from the same animations and button names to to another list. 
463                 if (debug) llOwnerSay("Debug: Not Found");
464                 string newSinglePosesLine = osGetNotecardLine("Poses Sitter" + (string)posesCardIndex, lineIndex);
465                 string newSinglePosesDataLine = osGetNotecardLine("DataPoses Sitter" + (string)posesCardIndex, lineIndex);
466                 newSinglePoses += newSinglePosesLine; 
467                 newSinglePosesData += newSinglePosesDataLine;
468             } 
469         }
470     }
471     if (debug)
472     {
473         DebugOwnerSayListContents("newSinglePoses", newSinglePoses);
474         DebugOwnerSayListContents("newSinglePosesData", newSinglePosesData);
475     }
476     //now turn the two new lists above into a menu card for PMAC
477     integer newSinglePosesIndex;
478     list newSinglesMenu; //list to hold the new singles menu
479     for (newSinglePosesIndex = 0; newSinglePosesIndex < llGetListLength(newSinglePoses); newSinglePosesIndex++)
480     {   //loops through each of the new singles poses entries, makes the PMAC line and adds to the list ready for writing
481         string lineFromPoses = llList2String(newSinglePoses, newSinglePosesIndex);
482         string lineFromData = llList2String(newSinglePosesData, newSinglePosesIndex);
483         if (debug) llOwnerSay("Debug:LineFromPoses: " + lineFromPoses);
484         if (debug) llOwnerSay("Debug:LineFromPosesData: " + lineFromData);
485         string buttonname = GetPoseName (lineFromPoses);
486         if (debug) llOwnerSay("Debug:ButtonName: " + buttonname);
487         string animName =  GetAnimName (lineFromPoses);
488         string position = PosFromPositionsLine(lineFromData);
489         string rot = RotFromPositionsLine (lineFromData); //this is already a rotation just reusing a method.
490         string newEntry =  buttonname + "|NO COM|" + animName + "|" + position + "|" + rot;
491         if(debug) llOwnerSay("Debug:AddedToSingleMenu: " + newEntry);
492         newSinglesMenu += newEntry;
493     }
494     if (debug) DebugOwnerSayListContents("new singels menu", newSinglesMenu);
495     //everything added, write the notecard. 
496     WriteNotecard(".menu001A Singles", newSinglesMenu);
497 }
498 RemovePosesAndPoseDataFromSitters()
499 {
500     //now the poses have bene converted to syncs or written to their own PMAC menu
501     //remove them from the SITTER cards so they can be processed as just sync's
502     list sitterCards = GetSpecificNotecardCards ("Sitter");
503     integer sitterCardIndex;
504     for (sitterCardIndex = 0; sitterCardIndex < llGetListLength(sitterCards); sitterCardIndex++)
505     {   //loop through each sitter card, inside each one remove any pose related lines
506         string cardName = llList2String(sitterCards, sitterCardIndex);
507         list sitterWithNoPoses = GetSitterSyncsAndMenus(cardName);
508         if (debug) DebugOwnerSayListContents("newSitter" + (string)sitterCardIndex, sitterWithNoPoses);
509         WriteNotecard(cardName, sitterWithNoPoses);
510     }
511 }
512 list SitterWithNoEmptyMenus (string cardName)
513 {   //loop through the card name provided, create a new list which contains
514     //non of the menus which only make up a menu structure, keep the ones which
515     //contain animation buttons. 
516     list newList;
517     integer lineIndex;
518     integer cardLength = osGetNumberOfNotecardLines(cardName);
519     for (lineIndex = 0; lineIndex < cardLength; lineIndex++)
520     {   //loops through each line of the notecard
521         string thisLine = osGetNotecardLine(cardName, lineIndex);
522         string testMenu = llGetSubString(thisLine, 0, 3);
523         string testBraces = llGetSubString(thisLine, 0, 0);
524         string testPoseName; 
525         if (testMenu == "MENU")
526         {   //come here only if the line starts with MENU
527             if (debug) llOwnerSay("Debug: Menu Line Found");
528             string nextLine = osGetNotecardLine(cardName, lineIndex + 1);
529             string nextLineMenuTest = llGetSubString(nextLine, 0, 3);
530             if (nextLineMenuTest != "MENU")
531             {   //if the next line is not also MENU add this line
532                 newList += thisLine;
533             }
534         }
535         else if (testBraces = "{")
536         {   //keep everything which is not a Menu line
537             newList += thisLine;
538         }
539     }
540     return newList;
541 }
542 RemoveEmptyMenusFromSitterCards()
543 {   //removes all the menu structure, preseving just the ones which directly deliver animation buttons
544     list sitterCards = GetSpecificNotecardCards ("Sitter");
545     integer sitterCardIndex;
546     for (sitterCardIndex = 0; sitterCardIndex < llGetListLength(sitterCards); sitterCardIndex++)
547     {
548         string cardName = llList2String(sitterCards, sitterCardIndex);
549         list SitterNoEmptyMenus = SitterWithNoEmptyMenus(cardName);
550         if (debug) DebugOwnerSayListContents("newSitter" + (string)sitterCardIndex, SitterNoEmptyMenus);
551         WriteNotecard(cardName, SitterNoEmptyMenus);
552     }
553 }
554 RemoveTempCards()
555 {   //loops though the inventory removing any temp notecards created during the conversion
556     list testStrings = ["DataPoses Sitter", "FixedRotations", "Poses Sitter", "PoseToSyncSitter", "Data_Sitter", "Menu_Sitter", "MenuData_Sitter", "Sitter"];
557     list testResults;
558     integer numOfNotecards = llGetInventoryNumber(INVENTORY_NOTECARD);
559     integer notecardIndex;
560     for (notecardIndex = numOfNotecards -1; notecardIndex >=0; notecardIndex--)
561     {   //loops through the inventory
562         string notecardName = llGetInventoryName(INVENTORY_NOTECARD, notecardIndex);
563         integer testIndex;
564         for (testIndex = 0; testIndex < llGetListLength(testStrings);testIndex++)
565         {   //checks each name against the ones in the list to remove
566             string testString = llList2String(testStrings,testIndex);
567             string testResult = llGetSubString(notecardName, 0, llStringLength(testString)-1);
568             if (testString == testResult)
569             {   //when a match is found, remove it. 
570                 if (debug) llOwnerSay("Debug:RemoveTempCards:Removed: " + notecardName);
571                 llRemoveInventory(notecardName);
572             }
573         }
574     }
575 }
576 list GetMenuLinePositions(string sitterCard)
577 {   //loops through the sitter card, making list of all line positions containing MENU lines
578     integer sitterCardLength = osGetNumberOfNotecardLines(sitterCard);
579     integer lineIndex;
580     list menuLinePositions;
581     integer dataStartLine;
582     for(lineIndex = 0; lineIndex < sitterCardLength; lineIndex++)
583     {   //loops through each line of the sittercard
584         string currentLine = osGetNotecardLine(sitterCard, lineIndex);
585         string menuTest = "MENU";
586         string testResult = llGetSubString(currentLine, 0, llStringLength(menuTest)-1);
587         if (menuTest == testResult)
588         {   //add this line number to the list
589             menuLinePositions += lineIndex;
590         }
591     }
592     if (debug) llOwnerSay("Debug:GetMenuLinePositions:List: " + llList2CSV(menuLinePositions));
593     return menuLinePositions;
594 }
595 GenerateMenuCardsForSyncs()
596 {   //goes through each sitter card making invidiual menu notecards for every sitter
597     list sitterCards = GetSpecificNotecardCards ("Sitter");
598     integer sitterCardIndex;
599     for (sitterCardIndex = 0; sitterCardIndex < llGetListLength(sitterCards); sitterCardIndex++)
600     {   //loops through each sitter card
601         string sitterCardName = llList2String(sitterCards, sitterCardIndex);
602         list menuLinePositions = GetMenuLinePositions(sitterCardName);
603         list newMenuCardLines;
604         integer menuIndex;
605         
606         for (menuIndex = 0; menuIndex < llGetListLength(menuLinePositions); menuIndex++)
607         {   //loops through each menu entry for this sitter
608             newMenuCardLines = []; 
609             integer menuStartLine = llList2Integer(menuLinePositions, menuIndex) +1; //+1 avoids adding the actual menu line which is no longer required
610             integer menuEndLine;
611             if(menuIndex != llGetListLength(menuLinePositions)-1)
612             {   //if its not the last entry, the end point is the start of the next menu
613                 menuEndLine = llList2Integer(menuLinePositions, menuIndex+1);
614             }
615             else
616             {   //if this is the last menu, set the end to the end of the notecard
617                 menuEndLine = osGetNumberOfNotecardLines(sitterCardName)-1; //-1 to ensure we stop at the bottom of the card
618             }
619             integer menuLineIndex;
620             for (menuLineIndex = menuStartLine; menuLineIndex < menuEndLine; menuLineIndex++)
621             {   //add each line that forms part of this menu to the new menu card
622                 newMenuCardLines;
623                 string currentLine = osGetNotecardLine(sitterCardName, menuLineIndex);
624                 integer isData = llSubStringIndex(currentLine, "}");
625                 if (isData == -1)
626                 {
627                     newMenuCardLines += currentLine;
628                 } 
629             }
630             string menuName = MenuNameFromMenuLine(osGetNotecardLine(sitterCardName,menuStartLine-1)) ; //-1 to get the actual menu line
631             string newCardName = "Menu_Sitter_" + (string)sitterCardIndex + "_" + menuName;
632             WriteNotecard(newCardName, newMenuCardLines);
633         }
634     }
635 }
636 string FindMatchingDataLine(string buttonName, string sitterNumber)
637 {   //loops through the Sitter card for the sitter number provided
638     //looking for the button name provided inside the pos/rot lines
639     //if one is found, return it
640     string dataLine;
641     string sitterCardName = "Sitter" + sitterNumber;
642     integer cardLength = osGetNumberOfNotecardLines(sitterCardName);
643     integer lineIndex = cardLength-1;
644     integer matchFound = FALSE;
645     while (!matchFound && lineIndex >= 0)
646     {   //start from the bottom and loop until a match is found, positions are always at the bottom of the card
647         string currentLine = osGetNotecardLine(sitterCardName, lineIndex);
648         integer isPosRot = llSubStringIndex(currentLine, "}");
649         if (isPosRot)
650         {   //only look at pos/rot lines
651             string lineName = NameFromPositionsLine(currentLine);
652             if (lineName == buttonName)
653             {   //if a match is found add it to the list
654                 dataLine = currentLine;
655                 matchFound = TRUE;
656             }
657         }
658         lineIndex--;
659     }
660     return dataLine;
661 }
662 GenerateDataCardsForSyncs()
663 {   //loops through all the temp menu cards, for each one it loops through every 
664     //line and then retrieves the matching pos/rot line in the appropriate sitter card 
665     //using this to make a dedicated pos/rot DATA card for the menu being processed. 
666     list menuCards = GetSpecificNotecardCards ("Menu_");
667     integer menuCardIndex;
668     list dataLines;
669     for (menuCardIndex = 0; menuCardIndex < llGetListLength(menuCards); menuCardIndex++)
670     {
671         dataLines = []; //clear this to make a new one each time
672         string cardName = llList2String(menuCards, menuCardIndex);
673         string sitterNumber = GetSitterNumberFromMenuCardName(cardName);
674         string menuName = GetMenuNameFromMenuCardName(cardName);
675         integer cardLength = osGetNumberOfNotecardLines(cardName);
676         integer cardLineIndex;
677         for (cardLineIndex = 0; cardLineIndex < cardLength; cardLineIndex++)
678         {   //loops through the current menu card line by line
679             string cardLine = osGetNotecardLine(cardName, cardLineIndex);
680             string buttonname = GetPoseName (cardLine);
681             string dataLine = FindMatchingDataLine(buttonname, sitterNumber);
682             dataLines += dataLine;
683         }
684         string newCardName = "Data_Sitter_" + sitterNumber + "_" + menuName ;
685         WriteNotecard(newCardName, dataLines);
686     }
687 }
688 list GetCombinedSitter0MenuData(string menuCardName, string dataCardName)
689 {   //takes the supplied names, retrieves the data from both and combines it line by line.
690     //the returned list will make a MenuData temp notecard.
691     list combinedMenuDataCard;
692     integer menuCardLength = osGetNumberOfNotecardLines(menuCardName);
693     integer dataCardLength = osGetNumberOfNotecardLines(dataCardName);
694     integer menuCardLineIndex;
695     integer dataCardLineIndex;
696     for (menuCardLineIndex = 0; menuCardLineIndex < menuCardLength; menuCardLineIndex++)
697     {   //loops through each line of the menu card
698         string menuCardLine = osGetNotecardLine(menuCardName, menuCardLineIndex);
699         string menuButtonName = GetPoseName (menuCardLine);
700         string animName = GetAnimName (menuCardLine);
701         integer dataSitter0CardIndex = 0;
702         integer matchFound = FALSE;
703         while (!matchFound && dataSitter0CardIndex < dataCardLength)
704         {
705             string dataCardLine = osGetNotecardLine(dataCardName, dataSitter0CardIndex);
706             string dataButtonName = NameFromPositionsLine(dataCardLine);
707             if (menuButtonName == dataButtonName)
708             {
709                 matchFound = TRUE;
710                 string dataPos = PosFromPositionsLine(dataCardLine);
711                 string dataRot = RotFromPositionsLine (dataCardLine);
712                 string toAdd = menuButtonName + "|NO COM|" + animName + "|" + dataPos + "|" + dataRot;
713                 combinedMenuDataCard += toAdd;
714             }
715             dataSitter0CardIndex++;
716         }
717     }
718     return combinedMenuDataCard;
719 }
720 CombineSitter0MenuAndDataCards()
721 {   //gets a list of all Menu cards and all Data cards then passes them in 
722     //pairs to the combine method. 
723     list menuSitter0Cards = GetSpecificNotecardCards ("Menu_Sitter_0");
724     list dataDitter0Cards = GetSpecificNotecardCards ("Data_Sitter_0");
725     integer menuSitter0CardIndex;
726     for (menuSitter0CardIndex = 0; menuSitter0CardIndex < llGetListLength(menuSitter0Cards); menuSitter0CardIndex++)
727     {
728         string sitter0MenuCardName = llList2String(menuSitter0Cards, menuSitter0CardIndex);
729         string sitter0DataCardName = llList2String(dataDitter0Cards, menuSitter0CardIndex);
730         string menuName = GetMenuNameFromMenuCardName(sitter0MenuCardName);
731         list combinedSitter0MenuData = GetCombinedSitter0MenuData(sitter0MenuCardName, sitter0DataCardName);
732         WriteNotecard("MenuData_Sitter_0_" + menuName, combinedSitter0MenuData);
733         if (debug) DebugOwnerSayListContents("sitter0MenuData_" + menuName, combinedSitter0MenuData);
734     }
735 }
736 list GetRelatedMenuSitterCards(string menuName)
737 {   //finds all temp menu cards related to the supplied name and returns the list
738     list menuSitterCards = GetSpecificNotecardCards ("Menu_Sitter");
739     list relatedMenuCards;
740     integer menuCardIndex;
741     for (menuCardIndex = 0; menuCardIndex < llGetListLength(menuSitterCards); menuCardIndex++)
742     {   //start loop at 0 incase there is only 1 entry, but ignore the first first loop as we do not want sitter 0
743             string currentCardName = llList2String(menuSitterCards, menuCardIndex);
744             string currentMenuName = GetMenuNameFromMenuCardName(currentCardName);
745             string sitterNumber = GetSitterNumberFromMenuCardName(currentCardName);
746             if (currentMenuName == menuName && sitterNumber != "0")
747             {   //ignore sitter 0 since it is the one we are working from, don't duplicate it. 
748                 relatedMenuCards += currentCardName;
749             }
750     }
751     return relatedMenuCards;
752 }
753 string GetAnimNameFromRelatedMenuCard(string relatedMenuCardName, string buttonName)
754 {   //All card entries can be out of order, so search through every line until a match is found and return the information. 
755     string animName = "";
756     integer cardLength = osGetNumberOfNotecardLines(relatedMenuCardName);
757     integer cardIndex = 0;
758     integer matchFound = FALSE;
759     while (!matchFound && cardIndex < cardLength)
760     {
761         string cardLine = osGetNotecardLine(relatedMenuCardName, cardIndex);
762         string poseName = GetPoseName (cardLine);
763         if (poseName == buttonName)
764         {
765             animName = GetAnimName (cardLine);
766             matchFound = TRUE;
767         }
768         cardIndex++;
769     }
770     return animName;
771 }
772 string GetPosRotFromRelatedDataCard(string relatedDataCardName, string buttonName)
773 {   //All card entries can be out of order, so search through every line until a match is found and return the information. 
774     string posRotData = "";
775     integer cardLength = osGetNumberOfNotecardLines(relatedDataCardName);
776     integer cardIndex = 0;
777     integer matchFound = FALSE;
778     while (!matchFound && cardIndex < cardLength)
779     {
780         string cardLine = osGetNotecardLine(relatedDataCardName, cardIndex);
781         string poseName = NameFromPositionsLine(cardLine);
782         if (poseName == buttonName)
783         {
784             string pos = PosFromPositionsLine(cardLine);
785             string rot = RotFromPositionsLine (cardLine);
786             posRotData = pos + "|" + rot;
787             matchFound = TRUE;
788         }
789         cardIndex++;
790     }
791     return posRotData;
792 }
793  
794 CombineMenuDataCardWithRelatedCards(string menuDataCard, string menuName, list relatedMenuCards)
795 {   //take every line in the menuData card, find its corresponding line in each related card and combine the information. 
796     //then add the combined line to a list, at the end return the list. 
797     list pmcaMenuCard;
798     integer cardLength = osGetNumberOfNotecardLines(menuDataCard);
799     integer cardLineIndex;
800     for (cardLineIndex = 0; cardLineIndex < cardLength; cardLineIndex++)
801     {
802         string currentLine = osGetNotecardLine(menuDataCard, cardLineIndex);
803         string buttonName = GetButtonNameFromPmacLine(currentLine);
804         integer relatedCardsIndex;
805         string newLine = currentLine;
806         for (relatedCardsIndex = 0; relatedCardsIndex < llGetListLength(relatedMenuCards); relatedCardsIndex++)
807         {
808             string relatedMenuCardName = llList2String(relatedMenuCards, relatedCardsIndex);
809             string relatedCardSitter = GetSitterNumberFromMenuCardName(relatedMenuCardName);
810             string relatedDataCardName = "Data_Sitter_" + relatedCardSitter + "_" + menuName;
811             string animName = GetAnimNameFromRelatedMenuCard(relatedMenuCardName, buttonName);
812             string posRot = GetPosRotFromRelatedDataCard(relatedDataCardName, buttonName);
813             string extraToAdd = "|" + animName + "|" + posRot;
814             newLine += extraToAdd;
815         }
816         pmcaMenuCard += newLine;
817     }
818     string pmacMenuCardName = ".menu" + "022A " + menuName;
819     WriteNotecard(pmacMenuCardName, pmcaMenuCard);
820 }
821 CombineMenuAndDataCards()
822 {   //loop through each of the MenuData cards, find the related cards and pass them one by one to the 
823     //combine card method.
824     menuCardNumber = 2; 
825     CombineSitter0MenuAndDataCards();
826     list menuDataSitter0Cards = GetSpecificNotecardCards ("MenuData_Sitter_0");
827     integer cardIndex;
828     for (cardIndex = 0; cardIndex < llGetListLength(menuDataSitter0Cards); cardIndex++)
829     {
830         string currentCardName = llList2String(menuDataSitter0Cards, cardIndex);
831         string menuName = GetMenuNameFromMenuCardName(currentCardName);
832         list releatedMenuSitterCards = GetRelatedMenuSitterCards(menuName);
833         if  (debug) llOwnerSay("Debug:CombineMenuAndDataCards:ProcessingMenu: " + menuName);
834         if (debug) DebugOwnerSayListContents(menuName + " related cards: ", releatedMenuSitterCards);
835         CombineMenuDataCardWithRelatedCards(currentCardName, menuName, releatedMenuSitterCards);
836     }
837 }
838 default
839 {
840     state_entry()
841     {
842         if (llGetInventoryType("AVpos") != INVENTORY_NOTECARD)
843         {
844             llOwnerSay("AVpos card not found, aborting");
845         }
846         else
847         {
848             llOwnerSay("Conversion Started");
849             ConvertRotations();
850             SplitIntoSitters();
851             llOwnerSay("Sorting singles poses");
852             FixAndCombineSinglePoses();
853             RemovePosesAndPoseDataFromSitters();
854             llOwnerSay("Preparing to convert SYNC's");
855             RemoveEmptyMenusFromSitterCards();
856             llOwnerSay("Creating Temp Menu cards");
857             GenerateMenuCardsForSyncs();
858             llOwnerSay("Creating Temp Position/Rotation cards");
859             GenerateDataCardsForSyncs();
860             llOwnerSay("Creating PMAC menu cards");
861             CombineMenuAndDataCards();
862             llOwnerSay("Clearing up temporary notecards");
863             RemoveTempCards();
864             llOwnerSay("Finished! You should find your new PMAC menu cards inside");
865         }
866         
867     }
868 }