Duchy of Darkmere

Blingtardia Delenda Est


It is currently Sat Nov 07, 2009 11:44 pm

All times are UTC



Welcome
Welcome to <strong>Duchy of Darkmere</strong>.

You are currently viewing our boards as a guest, which gives you limited access to view most discussions and access our other features. By joining our free community, you will have access to post topics, communicate privately with other members (PM), respond to polls, upload content, and access many other special features. Registration is fast, simple, and absolutely free, so please, <a href="/profile.php?mode=register">join our community today</a>!


Post new topic Reply to topic  [ 19 posts ] 
Author Message
 Post subject: The SkirtSitter script finds a new home.
PostPosted: Wed Oct 10, 2007 2:26 pm 
Offline
Friend of Darkmere
User avatar

Joined: Sat Aug 18, 2007 3:44 am
Posts: 756
Some of you may remember I posted a "SkirtSitter" script to the SC Tech forums, just before I headed overseas and SC subsequently collapsed. (Coincidence? I think not. :D )

Pea has very kindly made the DoD Teki Wiki forum readable to the public, so I'm about to post the SkirtSitter script and documentation text file here. I apologise in advance for their length, particularly the tedious history section of the documentation. At SC I tried to contribute to the Tech Forum as much as I could, and I'd like to try to continue that here at DoD.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 10, 2007 2:31 pm 
Offline
Friend of Darkmere
User avatar

Joined: Sat Aug 18, 2007 3:44 am
Posts: 756
Code:
DOCUMENTATION FOR THE "SKIRTSITTER.LSL" SCRIPT


Contents:
   A) Script Purpose  (aka "what is this thing anyway?")
   B) Instructions on use  (please read thoroughly)
   C) Script development/release history (optional reading)


(A) Script Purpose:

"SkirtSitter" is a script that is added to an attachment, and can then record the attachment's position/rotation on an AV when requested, for any animation state (standing, walking, sitting, etc). Once this data is stored, the script then moves the attachment into the stored attachment position/rotation automatically as the AV stands, walks, sits, etc.

As the name suggests, what motivated me to write it is the horribly annoying default behaviour of prim-skirts: when you sit, the skirt remains vertical (often flowing through a chair :-) ), rather than falling naturally around the legs. That said, there is nothing particular to skirts in the script itself, and if you want a top-hat that lifts from the head slightly when the AV is falling, this should work for that too.


(B) Instructions on use:

B.1) Prequisite: you will need a mod-skirt to be able to place the "SkirtSitter" script inside it.

B.2) If possible, make a backup copy of your prim-skirt.

B.3) Stand-up, and have no other animations playing. If necessary, adjust the position of the skirt using the standard edit controls.

B.4) Edit the skirt, and place the "SkirtSitter" script inside it.

B.5) Touch the skirt once to activate it. Touching the skirt again will bring up a menu - for the moment just close it.

B.6) Go into a desired pose - here we'll use the example of sitting.

B.7) Using the standard edit controls, position the skirt into a sensible position for the seated AV.

B.8) When you're happy with the positioning, touch the skirt to bring up the menu, and chose "Record". Note that if you're selling attachments that use SkirtSitter, you can do this positioning yourself before placing the item up for sale, sparing potential customers the effort.

B.9) You will now find that when you stand up, your skirt returns to its standing position/rotation, and when you sit it returns to its seated position/rotation. You may repeat steps (6) to (8) for any other poses you wish.

B.10) There are several other useful menu commands.

B.10.1) "Turn Off" temporarily deactivates the script. To turn it on again, just touch the skirt. Important note: many pose and dance balls work by having you *sit* on them, whereupon they make your AV lay down in a hammock, do the Time-Warp, or whatever. Despite what you see on-screen, as far as the internals of SL are concerned, your AV is still "seated", and SkirtSitter still repositions attachments accordingly. So, if you are going dancing and you sit on a pink ball to do this, its advisable to turn SkirtSitter off first. :-)

B.10.2) The current skirt positioning can be reset, or deleted (to save memory space), via the "Delete" and "Reset" commands.

B.10.3) "Status" provides a list of the position data recorded, and "Help", well, you know :-) .


(C) Script development/release history:

As I write (Oct-10, 2007) there are at least four similarly purposed scripts out there, and the net being what it is there's a reasonable chance that at some point somone will point at someone else and scream "he/she copied!". The following describes how SkirtSitter came to be developed and released, and its (non)relationship with the other scripts. If push came to shove I could possibly provide at least partial proof for this section (for example, there are people who saw SkirtSitter in action over six months ago), but ultimately you'll have to make up your own mind. There's also an independent (of me at least :-) )write-up of the release of the three first publically available scripts of this type at: http://www.slnn.com/index.php/article/about/sitting-pretty-deux/page/1.html.

As I mentioned in (A), the default behaviour of prim-skirts in SL had driven me around the twist for ages, and in January 2007 I decided to do something about it. I date all my scripts, and, since it is by no means a particularly complex one, it would have been finished at the latest by February. I've used it pretty much continually since, and have demoed it or given copies to friends over that time.

In terms of commercial exploitation, I did nothing for a few months, then produced a "demo pack" which I sent out, completely unsolicited, to one designer (most definitely *not* one of the designers involved with the current other scripts), and got a "I'll look at it and get back to you" response, which never happened. I had no problem with this of course. I also gave the demo pack to a friend of a friend (literally) who said she had many contacts in the fashion world. I never heard anything back from her subsequently.

Its rather an understatement to say that I'm not the most commercially driven person in SL. :-) So, while I continued to use it, I forgot about any commerical exploitation for a couple of months, while focussing on newer, shinier projects. :-) Eventually a couple of friends suggested that I really should be selling the thing, one even making dedicated space available in his shop. I knew that any decent scripter would be able to recreate the functionality of SkirtSitter in a couple of hours, so my plan was to sell it *cheap*, say at $20 L for a no-mod/no-trans/copy perm version. This would reduce the incentive for copy-cat creations, and I hoped I'd sell enough volume to make a little shopping change. But, whilst scripting is fun, writing/designing/placing adds, setting up a store, etc still seemed too much like "work" to me, and my complete mastery of procastination ensured that even the $20 L plan never eventuated. :-)

Then, in early-mid September, Nyte Caligari of Nyte'N'Day released her "SensiDress", which I discovered via my usual perusal of Linden LifeStyles. And, incredibly, this happened the day before I was off to Europe (I'm an Aussie) for a four week holiday. I read both the LL and N'N'D blogs, and (rather belatedly) saw the enthusiasm that was out there for such a script. Having had SkirtSitter sit on my drive for months, I decided the only way a lazy sod like myself would ever get around to making it publically available was simply to distribute it free. I hurriedly posted the instructions and the script itself up on the Second Citizen forums that night, and posted about its availability on a couple of blogs. The reasons for the rush were:

i) I am not ego-less, and I did not want to be accused of being a mere copy-cat, which seemed to me to be more likely if SkirtSitter had appeared a month after alternative commercial products were released.

ii) Having seen the blog enthusiasm, I did not want a month to go by with people thinking that their *only* option was to purchase this sort of script. This is in no way intended as a criticism of the commerical offerings - to this day I have not seen them in action, and it may very well be that they have extra features, ease of use, and support that justifies every last $L of their purchase price and more. But choice is always good too. :-)

The unlikely series of events continued, when the Second Citizen forums imploded whilst I was overseas. To make SkirtSitter publically available once more, I'm uploading it to the Duchy of Darkmere SL Technical forum at ***give URL here**.

========

Enough words I think. :-)

Unless you're a freebie reseller, I hope that SkirtSitter performs well for you in whatever purpose you chose to apply it to. If you do receive SkirtSitter via some commercial transaction, please remember, I'm not making a brass razoo out of this - contact the seller for support. :-)

Cale Vinson.




Code:
// "SkirtSitter.lsl"
//
// Cale Vinson, Jan-2007
//
//   "BAS" = "Basic Animation State", the simplest description of the AV's posture.
//   Examples include 'Walking', and 'Sitting'. For each BAS we store its name, and
//   the position and rotation that the attachment had when that BAS was playing.


string gAnimState;
string gAnimStateOld;
string gBAS_FREE;
list gBAS_Name;
integer gBAS_MAX_NUMBER;
list gBAS_Pos;
list gBAS_Rot;
integer gCHANNEL;
float gDialogPlayingTime;
float gDIALOG_TIMEOUT;
vector gINITIAL_POS;
rotation gINITIAL_ROT;
integer gListenHandle;
float gTICK_RATE;
string gTmpString;


ApplyBAS(string bas)
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [bas]);
   
   if ( basIndex == -1 )  // No data for this BAS, so just take the defaults.
   {
      llSetPos(gINITIAL_POS);
      llSetRot(gINITIAL_ROT);
   }
   else
   {
      llSetPos(llList2Vector(gBAS_Pos, basIndex));
      llSetRot(llList2Rot(gBAS_Rot, basIndex));
   }
}


InitBAS()
{
   integer i;
   
   gBAS_Name = [];
   gBAS_Pos = [];
   gBAS_Rot = [];
   
   for ( i = 0; i < gBAS_MAX_NUMBER; i++ )
   {
      gBAS_Name += [gBAS_FREE];
      gBAS_Pos  += [ZERO_VECTOR];
      gBAS_Rot  += [ZERO_ROTATION];
   }
}


InitOnce()
{
   gTICK_RATE = 1.0;

   gBAS_FREE = "empty";
   gBAS_MAX_NUMBER = 10;
   gCHANNEL = 666;
   gDIALOG_TIMEOUT = 60.0;
   
   InitBAS();
   
   gINITIAL_POS = llGetLocalPos();
   gINITIAL_ROT = llGetLocalRot();
}


InitOnRez()
{
   gAnimStateOld = llGetAnimation(llGetOwner());
   ApplyBAS(llGetAnimation(llGetOwner()));
}


ListenDelete()
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [gAnimState]);
   
   if ( basIndex > -1 )
   {
      gBAS_Name = llListReplaceList(gBAS_Name, [gBAS_FREE], basIndex, basIndex);
      gBAS_Pos  = llListReplaceList(gBAS_Pos,  [ZERO_VECTOR], basIndex, basIndex);
      gBAS_Rot  = llListReplaceList(gBAS_Rot,  [ZERO_ROTATION], basIndex, basIndex);
   }
   
   ApplyBAS(gAnimState);
   
   llOwnerSay("BAS data for this animation state has been deleted.");
}


ListenHelp()
{
   llOwnerSay("Summary of Commands >>>");
   llOwnerSay("<Delete>   Delete the positioning data for this animation-state.");
   llOwnerSay("<Record>   Record the positioning data for this animation-state.");
   llOwnerSay("<Reset>    Set the positioning data for this animation-state to default values.");
   llOwnerSay("<Status>   Give a list of positioning data for each animation-state recorded.");
}


ListenRecord()
{
   UpdateBAS(gAnimState, llGetLocalPos(), llGetLocalRot());
   llOwnerSay("BAS data for this animation state recorded.");
}


ListenReset()
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [gAnimState]);
   
   if ( basIndex > -1 )
   {
      gBAS_Pos  = llListReplaceList(gBAS_Pos,  [gINITIAL_POS], basIndex, basIndex);
      gBAS_Rot  = llListReplaceList(gBAS_Rot,  [gINITIAL_ROT], basIndex, basIndex);
   }
   
   ApplyBAS(gAnimState);
   
   llOwnerSay("BAS data for this animation state has been reset to default values.");
}


ListenStatus()
{
   integer i;
   
   llOwnerSay("Currently stored BAS are >>>     (name, pos, rot)");
   for ( i = 0; i < llGetListLength(gBAS_Name); i++ )
      if ( llList2String(gBAS_Name, i) != gBAS_FREE )
      {
         gTmpString  = llList2String(gBAS_Name, i) + " / ";
         gTmpString += (string)llList2Vector(gBAS_Pos, i) + " / ";
         gTmpString += (string)llList2Rot(gBAS_Rot, i);
         llOwnerSay(gTmpString);
      }
}


MakeDialog()
{
   list buttons;
   
   gDialogPlayingTime = 0.0;  // Start recording how long the listen channel is open.
   
   buttons = ["Help", "Record", "Reset", "Status", "Delete", "Turn Off"];
   llDialog(llGetOwner(), " ", buttons, gCHANNEL);
   
   llListenRemove(gListenHandle);
   gListenHandle = llListen(gCHANNEL, "", llGetOwner(), "");
}


UpdateBAS(string bas, vector pos, rotation rot)
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [bas]);
   
   if ( basIndex == -1 )  // A new BAS request.
   {
      basIndex = llListFindList(gBAS_Name, [gBAS_FREE]);
      
      if ( basIndex == -1 )  // No Free slots available
      {
         gTmpString    = "No free BAS slots available. Please delete one currently in use ";
         gTmpString += "and try again.";
         llOwnerSay(gTmpString);
         return;         
      }
   }
   
   gBAS_Name = llListReplaceList(gBAS_Name, [bas], basIndex, basIndex);
   gBAS_Pos  = llListReplaceList(gBAS_Pos,  [pos], basIndex, basIndex);
   gBAS_Rot  = llListReplaceList(gBAS_Rot,  [rot], basIndex, basIndex);
}


//==============================================================================================
//   "default" state
//
//==============================================================================================

default
{
   on_rez(integer start_param)
   {
      llResetScript();
   }
   
   
   state_entry()
   {
      InitOnce();
      InitOnRez();
      
      llOwnerSay("Initialised, touch attachment to proceed.");
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
      state on;      
   }
}


//==============================================================================================
//   "off" state
//
//==============================================================================================

state off
{
   state_entry()
   {
      llSetPos(gINITIAL_POS);
      llSetRot(gINITIAL_ROT);

      llSetTimerEvent(0.0);
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
      llOwnerSay("Activated.");
      InitOnRez();
      state on;
   }
}


//==============================================================================================
//   "on" state
//
//==============================================================================================

state on
{
   listen(integer channel, string name, key id, string message)
   {
      string lcMsg;
      
      lcMsg = llToLower(message);
      
      if ( lcMsg == "delete" )
         ListenDelete();
      else if ( lcMsg == "help" )
         ListenHelp();
      else if ( lcMsg == "record" )
         ListenRecord();
      else if (lcMsg == "reset" )
         ListenReset();
      else if ( lcMsg == "status" )
         ListenStatus();
      else if ( lcMsg == "turn off" )
      {
         llOwnerSay("Deactivated. Touch the attachment to re-activate.");
         state off;
      }
      
      llListenRemove(gListenHandle);  // Only have a listen open when required.
   }
   
   
   on_rez(integer start_param)
   {
      InitOnRez();
   }
   
   
   state_entry()
   {
      llSetTimerEvent(gTICK_RATE);
   }
   
   
   state_exit()
   {
      llSetTimerEvent(0.0);
   }
   
   
   timer()
   {
      
//      Clean up any unused listeners.
      
      gDialogPlayingTime += gTICK_RATE;
      if ( gDialogPlayingTime > gDIALOG_TIMEOUT )
      {
         gDialogPlayingTime = -1.0E+20;
         llListenRemove(gListenHandle);
      }
   
      gAnimState = llGetAnimation(llGetOwner());
      
      if ( gAnimState != gAnimStateOld )
      {
         ApplyBAS(gAnimState);
         gAnimStateOld = gAnimState;
      }
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
//      We are only polling the BAS every so often, we may have to wait for the current state to be polled.
      
      if ( gAnimState != llGetAnimation(llGetOwner()) )
      {
         gTmpString = "Animation state not yet updated. Please wait a moment and try again.";
         llOwnerSay(gTmpString);
         return;
      }
      
      MakeDialog();
   }
}



Top
 Profile  
 
 Post subject: Re: The SkirtSitter script finds a new home.
PostPosted: Wed Oct 10, 2007 2:55 pm 
Offline
Teh Mean
User avatar

Joined: Thu Aug 16, 2007 2:28 pm
Posts: 1595
Cale Vinson wrote:
the tedious history section of the documentation.


I thought that was the best bit. :bounce:

_________________
Image


Top
 Profile  
 
 Post subject: Re: The SkirtSitter script finds a new home.
PostPosted: Wed Oct 10, 2007 3:03 pm 
Offline
Friend of Darkmere
User avatar

Joined: Sat Aug 18, 2007 3:44 am
Posts: 756
Peasan Kuu wrote:
Cale Vinson wrote:
the tedious history section of the documentation.


I thought that was the best bit. :bounce:


You don't actually expect me to believe that you read it, do you? :P


Top
 Profile  
 
 Post subject: Re: The SkirtSitter script finds a new home.
PostPosted: Wed Oct 10, 2007 3:16 pm 
Offline
Duke of Darkmere
User avatar

Joined: Wed Aug 15, 2007 6:43 pm
Posts: 2451
Location: Darkmere
Highscores: 12
Cale Vinson wrote:
Peasan Kuu wrote:
Cale Vinson wrote:
the tedious history section of the documentation.


I thought that was the best bit. :bounce:


You don't actually expect me to believe that you read it, do you? :P


You posted in green...


of course she read it. :P


Top
 Profile  
 
 Post subject: Re: The SkirtSitter script finds a new home.
PostPosted: Wed Oct 10, 2007 3:20 pm 
Offline
Friend of Darkmere
User avatar

Joined: Sat Aug 18, 2007 3:44 am
Posts: 756
Lucifer wrote:
Cale Vinson wrote:
Peasan Kuu wrote:
Cale Vinson wrote:
the tedious history section of the documentation.


I thought that was the best bit. :bounce:


You don't actually expect me to believe that you read it, do you? :P


You posted in green...


of course she read it. :P


My smiley-fu is very weak - do we have a Doh! smiley here? :D


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 10, 2007 3:33 pm 
Offline
Darkmerese
User avatar

Joined: Fri Aug 17, 2007 12:43 am
Posts: 2275
:woohoo: Cale is back! :dancingbanana:

How was the trip? Where's the delightful posts describing your journey?

:tacklehug:

_________________
Curt Guyette, Detroit Metro Times News Editor wrote:
Get out the butter because the Kwamster is toast.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 11, 2007 2:01 am 
Offline
Darkmerese
User avatar

Joined: Thu Aug 16, 2007 6:32 am
Posts: 498
Location: WoW
Did you know someone is selling your script on SLExchange for L$900?

_________________
Originally Posted by RedCedar:
Uhhh, hello! You have plate and like 10k armor. I am wearing a damn bath robe, a pair of sweat pants, and some slippers!!!!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 11, 2007 2:12 am 
Offline
Friend of Darkmere

Joined: Mon Aug 20, 2007 7:48 am
Posts: 1220
Location: not fucking here
welcome back

DMCA those fuckers, cale!

_________________
And when the cops came through
Me and Dre stood next to a burnt down house
Wit a can full of gas and a hand full of matches
And still weren't found out


http://mulched.blogspot.com/

The Play is the Thing...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 11, 2007 3:27 am 
Offline
Friend of Darkmere
User avatar

Joined: Sat Aug 18, 2007 3:44 am
Posts: 756
sansarya wrote:
Did you know someone is selling your script on SLExchange for L$900?


No, I didn't. The slnn link I gave above suggested that it had been resold on SLEX, but when I checked, the (alleged) reseller and product was no longer there.

Do you have a link handy for me to check this out?

Prospero wrote:
welcome back

DMCA those fuckers, cale!


Thanks for the welcome back, person who is definitely-not-mulch-at-all-no-sirree. :D

DMCA? Didn't you read my 10,000 word history essay above? If I'm too lazy to bother setting up a store to sell my stuff, what makes you think I could possibly find the effort to learn about and lodge a DMCA? :D

If anyone releases a full-perm anything, you have to expect that bottom-feeders will try to sell it. The most I might do in response is to send SLEX the script as a full-perm freebie, and note this in any SLEX discussions. I'd only bother to do this if I was convinced that bottom-feeders were actually selling my script. As I and others have said previously, the script is not rocket-science, and any decent scripter could reproduce its functionality, without stealing my code.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 11, 2007 4:23 am 
Offline
Darkmerese
User avatar

Joined: Thu Aug 16, 2007 6:32 am
Posts: 498
Location: WoW
I went and looked for the SkirtFix again, but it looks like it's been removed. When I first saw it, I bought a copy and compared it to yours (I can show it to you in world when I log in again), and it's exactly the same. I left a comment on the seller's page telling people not to buy it since it was a freebie on SC, but then SC came down :(, and I didn't look for it again on SLEx. Glad you're back, hope your trip was great :)

_________________
Originally Posted by RedCedar:
Uhhh, hello! You have plate and like 10k armor. I am wearing a damn bath robe, a pair of sweat pants, and some slippers!!!!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 11, 2007 4:45 am 
Offline
Friend of Darkmere
User avatar

Joined: Sat Aug 18, 2007 3:44 am
Posts: 756
sansarya wrote:
I went and looked for the SkirtFix again, but it looks like it's been removed. When I first saw it, I bought a copy and compared it to yours (I can show it to you in world when I log in again), and it's exactly the same. I left a comment on the seller's page telling people not to buy it since it was a freebie on SC, but then SC came down :(, and I didn't look for it again on SLEx. Glad you're back, hope your trip was great :)


Many thanks for that Sans, both for your actions at the time, and for checking again now. :wub:

Added in Edit:

Eek - hit the the submit and not preview button. :o

Yes, SkirtFix was the alleged rip-off script noted at slnn. It doesn't seem to have enjoyed particularly great longetivity. :D

And yes, the trip was wonderful thanks. I will bore you all to tears about it when I can summon some more energy. (See Margaret - I wasn't ignoring you after all! :D )


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 11, 2007 5:06 am 
Offline
Friend of Darkmere
User avatar

Joined: Thu Aug 30, 2007 1:58 am
Posts: 2546
Mr Vinson! How nice to see you.

_________________
Yet strange to say, the more sanely I talked and acted the crazier I was thought to be


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 12, 2007 2:14 am 
Offline
Darkmerese
User avatar

Joined: Thu Aug 16, 2007 4:41 am
Posts: 147
Yay for Cale! =D

I forgot to take down the script when SC went down, but someone helpfully gave it to me on SC regs.. ^^


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 12, 2007 5:05 am 
Offline
Friend of Darkmere
User avatar

Joined: Sat Sep 15, 2007 12:07 pm
Posts: 74
You rock, Cale!


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 13, 2007 3:23 pm 
Offline
Lady Mourning
User avatar

Joined: Thu Aug 16, 2007 4:07 am
Posts: 641
Welcome back, Cale! I hope you had a wonderful time. :) Thank you so much for sharing this with the community. (In the time you've been gone, I've popped this into almost every skirt I own. :D) This is, most assuredly, the best freebie I've ever availed myself to! :wub:

_________________
ImageImage


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 17, 2007 5:28 am 
Offline
Darkmerese
User avatar

Joined: Wed Aug 22, 2007 5:15 pm
Posts: 19
Thank your for posting this :) i was kicking myself for not taking a copy when you posted this on SC, :D


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 23, 2007 4:51 pm 
Offline
Friend of Darkmere
User avatar

Joined: Sat Aug 18, 2007 3:44 am
Posts: 756
The following is in response to the thread:

http://forums.secondlife.com/showthread.php?t=218662

which requests support for setting the skirt positioning for the walk animation.

This new version makes one minor change:

There is now a "Walking" button. So, stand still. Position the skirt where you would like it to be when you are walking. Then to record this information, hit the "Walking" button, rather than the "Record" button..

I'll document this more thoughly when I'm awake, consider this a beta version for now. :)



Code:

// "SkirtSitter.lsl"
//
// Cale Vinson, Jan-2007
//
//   "BAS" = "Basic Animation State", the simplest description of the AV's posture.
//   Examples include 'Walking', and 'Sitting'. For each BAS we store its name, and
//   the position and rotation that the attachment had when that BAS was playing.
//
//  Oct-24, 2007
//  Added support for the walking animation in particular.


string gAnimState;
string gAnimStateOld;
string gBAS_FREE;
list gBAS_Name;
integer gBAS_MAX_NUMBER;
list gBAS_Pos;
list gBAS_Rot;
integer gCHANNEL;
float gDialogPlayingTime;
float gDIALOG_TIMEOUT;
vector gINITIAL_POS;
rotation gINITIAL_ROT;
integer gListenHandle;
float gTICK_RATE;
string gTmpString;


ApplyBAS(string bas)
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [bas]);
   
   if ( basIndex == -1 )  // No data for this BAS, so just take the defaults.
   {
      llSetPos(gINITIAL_POS);
      llSetRot(gINITIAL_ROT);
   }
   else
   {
      llSetPos(llList2Vector(gBAS_Pos, basIndex));
      llSetRot(llList2Rot(gBAS_Rot, basIndex));
   }
}


InitBAS()
{
   integer i;
   
   gBAS_Name = [];
   gBAS_Pos = [];
   gBAS_Rot = [];
   
   for ( i = 0; i < gBAS_MAX_NUMBER; i++ )
   {
      gBAS_Name += [gBAS_FREE];
      gBAS_Pos  += [ZERO_VECTOR];
      gBAS_Rot  += [ZERO_ROTATION];
   }
}


InitOnce()
{
   gTICK_RATE = 1.0;

   gBAS_FREE = "empty";
   gBAS_MAX_NUMBER = 10;
   gCHANNEL = 666;
   gDIALOG_TIMEOUT = 60.0;
   
   InitBAS();
   
   gINITIAL_POS = llGetLocalPos();
   gINITIAL_ROT = llGetLocalRot();
}


InitOnRez()
{
   gAnimStateOld = llGetAnimation(llGetOwner());
   ApplyBAS(llGetAnimation(llGetOwner()));
}


ListenDelete()
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [gAnimState]);
   
   if ( basIndex > -1 )
   {
      gBAS_Name = llListReplaceList(gBAS_Name, [gBAS_FREE], basIndex, basIndex);
      gBAS_Pos  = llListReplaceList(gBAS_Pos,  [ZERO_VECTOR], basIndex, basIndex);
      gBAS_Rot  = llListReplaceList(gBAS_Rot,  [ZERO_ROTATION], basIndex, basIndex);
   }
   
   ApplyBAS(gAnimState);
   
   llOwnerSay("BAS data for this animation state has been deleted.");
}


ListenHelp()
{
   llOwnerSay("Summary of Commands >>>");
   llOwnerSay("<Delete>   Delete the positioning data for this animation-state.");
   llOwnerSay("<Record>   Record the positioning data for this animation-state.");
   llOwnerSay("<Reset>    Set the positioning data for this animation-state to default values.");
   llOwnerSay("<Status>   Give a list of positioning data for each animation-state recorded.");
   llOwnerSay("<Walking>  Record the positioning data, and apply it to the walking animation-state.");
}


ListenRecord()
{
   UpdateBAS(gAnimState, llGetLocalPos(), llGetLocalRot());
   llOwnerSay("BAS data for this animation state recorded.");
}


ListenReset()
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [gAnimState]);
   
   if ( basIndex > -1 )
   {
      gBAS_Pos  = llListReplaceList(gBAS_Pos,  [gINITIAL_POS], basIndex, basIndex);
      gBAS_Rot  = llListReplaceList(gBAS_Rot,  [gINITIAL_ROT], basIndex, basIndex);
   }
   
   ApplyBAS(gAnimState);
   
   llOwnerSay("BAS data for this animation state has been reset to default values.");
}


ListenStatus()
{
   integer i;
   
   llOwnerSay("Currently stored BAS are >>>     (name, pos, rot)");
   for ( i = 0; i < llGetListLength(gBAS_Name); i++ )
      if ( llList2String(gBAS_Name, i) != gBAS_FREE )
      {
         gTmpString  = llList2String(gBAS_Name, i) + " / ";
         gTmpString += (string)llList2Vector(gBAS_Pos, i) + " / ";
         gTmpString += (string)llList2Rot(gBAS_Rot, i);
         llOwnerSay(gTmpString);
      }
}


ListenWalking()
{
   UpdateBAS("Walking", llGetLocalPos(), llGetLocalRot());
}


MakeDialog()
{
   list buttons;
   
   gDialogPlayingTime = 0.0;  // Start recording how long the listen channel is open.
   
   buttons = ["Help", "Record", "Reset", "Status", "Delete", "Turn Off", "Walking"];
   llDialog(llGetOwner(), " ", buttons, gCHANNEL);
   
   llListenRemove(gListenHandle);
   gListenHandle = llListen(gCHANNEL, "", llGetOwner(), "");
}


UpdateBAS(string bas, vector pos, rotation rot)
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [bas]);
   
   if ( basIndex == -1 )  // A new BAS request.
   {
      basIndex = llListFindList(gBAS_Name, [gBAS_FREE]);
      
      if ( basIndex == -1 )  // No Free slots available
      {
         gTmpString    = "No free BAS slots available. Please delete one currently in use ";
         gTmpString += "and try again.";
         llOwnerSay(gTmpString);
         return;         
      }
   }
   
   gBAS_Name = llListReplaceList(gBAS_Name, [bas], basIndex, basIndex);
   gBAS_Pos  = llListReplaceList(gBAS_Pos,  [pos], basIndex, basIndex);
   gBAS_Rot  = llListReplaceList(gBAS_Rot,  [rot], basIndex, basIndex);
}


//==============================================================================================
//   "default" state
//
//==============================================================================================

default
{
   on_rez(integer start_param)
   {
      llResetScript();
   }
   
   
   state_entry()
   {
      InitOnce();
      InitOnRez();
      
      llOwnerSay("Initialised, touch attachment to proceed.");
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
      state on;      
   }
}


//==============================================================================================
//   "off" state
//
//==============================================================================================

state off
{
   state_entry()
   {
      llSetPos(gINITIAL_POS);
      llSetRot(gINITIAL_ROT);

      llSetTimerEvent(0.0);
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
      llOwnerSay("Activated.");
      InitOnRez();
      state on;
   }
}


//==============================================================================================
//   "on" state
//
//==============================================================================================

state on
{
   listen(integer channel, string name, key id, string message)
   {
      string lcMsg;
      
      lcMsg = llToLower(message);
      
      if ( lcMsg == "delete" )
         ListenDelete();
      else if ( lcMsg == "help" )
         ListenHelp();
      else if ( lcMsg == "record" )
         ListenRecord();
      else if (lcMsg == "reset" )
         ListenReset();
      else if ( lcMsg == "status" )
         ListenStatus();
      else if ( lcMsg == "turn off" )
      {
         llOwnerSay("Deactivated. Touch the attachment to re-activate.");
         state off;
      }
      else if ( lcMsg == "walking" )
         ListenWalking();
      
      llListenRemove(gListenHandle);  // Only have a listen open when required.
   }
   
   
   on_rez(integer start_param)
   {
      InitOnRez();
   }
   
   
   state_entry()
   {
      llSetTimerEvent(gTICK_RATE);
   }
   
   
   state_exit()
   {
      llSetTimerEvent(0.0);
   }
   
   
   timer()
   {
      
//      Clean up any unused listeners.
      
      gDialogPlayingTime += gTICK_RATE;
      if ( gDialogPlayingTime > gDIALOG_TIMEOUT )
      {
         gDialogPlayingTime = -1.0E+20;
         llListenRemove(gListenHandle);
      }
   
      gAnimState = llGetAnimation(llGetOwner());
      
      if ( gAnimState != gAnimStateOld )
      {
         ApplyBAS(gAnimState);
         gAnimStateOld = gAnimState;
      }
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
//      We are only polling the BAS every so often, we may have to wait for the current state to be polled.
      
      if ( gAnimState != llGetAnimation(llGetOwner()) )
      {
         gTmpString = "Animation state not yet updated. Please wait a moment and try again.";
         llOwnerSay(gTmpString);
         return;
      }
      
      MakeDialog();
   }
}



Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 24, 2007 3:55 pm 
Offline
Friend of Darkmere
User avatar

Joined: Sat Aug 18, 2007 3:44 am
Posts: 756
Latest version, with three new features:

a) "Copy/Paste" position/rotation data from one animation state to another.
b) Ability to dump out all the position/rotation data to chat. The user can copy this to a configuration notecard, which the script can subsequently read back. Allows backup of settings, and the ability to rapidly set up a large number of geometrically similar skirts using the first as a template. The notecard system is completely optional however.
c) A command to "wipe" the script, clearing all stored data.

New features documented in sections B.10 through B.14.


Code:
DOCUMENTATION FOR THE "SKIRTSITTER.LSL" SCRIPT


Contents:
   A) Script Purpose  (aka "what is this thing anyway?")
   B) Instructions on use  (please read thoroughly)
   C) Script development/release history (optional reading)


(A) Script Purpose:

"SkirtSitter" is a script that is added to an attachment, and can then record the attachment's position/rotation on an AV when requested, for any animation state (standing, walking, sitting, etc). Once this data is stored, the script then moves the attachment into the stored attachment position/rotation automatically as the AV stands, walks, sits, etc.

As the name suggests, what motivated me to write it is the horribly annoying default behaviour of prim-skirts: when you sit, the skirt remains vertical (often flowing through a chair :-) ), rather than falling naturally around the legs. That said, there is nothing particular to skirts in the script itself, and if you want a top-hat that lifts from the head slightly when the AV is falling, this should work for that too.


(B) Instructions on use:

B.1) Prequisite: you will need a mod-skirt to be able to place the "SkirtSitter" script inside it.

B.2) If possible, make a backup copy of your prim-skirt.

B.3) Stand-up, and have no other animations playing. If necessary, adjust the position of the skirt using the standard edit controls.

B.4) Edit the skirt, and place the "SkirtSitter" script inside it.

B.5) Touch the skirt once to activate it. Touching the skirt again will bring up a menu - for the moment just close it.

B.6) Go into a desired pose - here we'll use the example of sitting.

B.7) Using the standard edit controls, position the skirt into a sensible position for the seated AV.

B.8) When you're happy with the positioning, touch the skirt to bring up the menu, and chose "Record". Note that if you're selling attachments that use SkirtSitter, you can do this positioning yourself before placing the item up for sale, sparing potential customers the effort.

B.9) You will now find that when you stand up, your skirt returns to its standing position/rotation, and when you sit it returns to its seated position/rotation. You may repeat steps (6) to (8) for any other poses you wish.

B.10) The above is fine for dealing with setting the seated position/rotation. However, if we try the same procedure for walking we encounter a problem - it doesn't appear possible to have the AV walk and to edit the skirt at the same time. This issue was noted by Constanza Volare and Qie Niangao in the following thread:
http://forums.secondlife.com/showthread.php?t=218662 And it is not only walking where it seems impossible to edit simultaneously.

B.11) For walking in particular, one can get around (B.10) by using the "Walking" button. Have your AV standing, then place the skirt in the position/rotation you'd like it to have when you're walking, then hit the "Walking" button. Unlike "Record", "Walking" takes the current position/rotation data, and stores it as the position/rotation data for the *walking* animations state, regardless of what animation-state is currently playing.

B.12) A general solution to (B.10) for any animation-state which does not allow editing, is to use the "Copy" and "Paste" buttons. "Copy" stores the current position/rotation data into a temporary buffer in the script, and "Paste" takes that data and records it as the position/rotation data for the currently playing animation state. So, for the walking example, you could use "Copy" to temporarily store the position/rotation data whilst standing (and hence able to edit the skirt), and then "Paste" to store that data whilst walking. Keep your AV still by walking into a wall or something. :-) You might also use "Copy" and "Paste" to transfer position/rotation data when you want one animation state to have exactly the same data as another.

B.13) SkirtSitter can be used with 100% functionality, without any configuration notecards. However, support for the use of such notecards is available, if you want to use it. Configuration notecards can be useful for individuals to "back up" favourite settings, and may be particularly useful for designers who need only set up one skirt by hand, and then simply copy the configuration notecard into all the various colours and texturings of a given prim skirt, as found in a typical "fat pack".

B.13.1) The "Status" button causes the script to produce a listing of all the currently stored position/rotation data for each animation-state that has such data. This listing can be easily cut and paste (eg., ctrl-p and ctrl-v on a PC) from the chat history, into a configuration notecard, which must be named "SkirtSitterConfig". It doesn't matter if you include extra chat lines in the cut and paste process. Once you have the notecard, place it inside the skirt.

B.13.2) If a "SkirtSitterConfig" notecard is present, then hitting the "Read CFG" button will clear all the current position/rotation data, and then read the position/rotation data contained in the configuration notecard. If the notecard is not present, then this button does nothing.

B.14) There are several other useful menu commands.

B.14.1) "Turn Off" temporarily deactivates the script. To turn it on again, just touch the skirt. Important note: many pose and dance balls work by having you *sit* on them, whereupon they make your AV lay down in a hammock, do the Time-Warp, or whatever. Despite what you see on-screen, as far as the internals of SL are concerned, your AV is still "seated", and SkirtSitter still repositions attachments accordingly. So, if you are going dancing and you sit on a pink ball to do this, its advisable to turn SkirtSitter off first. :-)

B.14.2) The skirt position/rotation data for the currently playing animation state can be reset to default values, or deleted entirely (to save memory space), via the "Reset" and "Delete" commands.

B.14.3) The "WIPE!" button causes the SCRIPT AS A WHOLE to reset, exactly as if you had used the client tool menu option to reset scripts in selection. This wipes all position/rotation data stored in the script itself (not notecards), so be very careful in using it, and perhaps make a backup notecard first (see (B.13)).

B.14.4) The "Help" button should be reasonably transparent. :-)


(C) Script development/release history:

As I write (Oct-10, 2007) there are at least four similarly purposed scripts out there, and the net being what it is there's a reasonable chance that at some point somone will point at someone else and scream "he/she copied!". The following describes how SkirtSitter came to be developed and released, and its (non)relationship with the other scripts. If push came to shove I could possibly provide at least partial proof for this section (for example, there are people who saw SkirtSitter in action over six months ago), but ultimately you'll have to make up your own mind. There's also an independent (of me at least :-) )write-up of the release of the three first publically available scripts of this type at: http://www.slnn.com/index.php/article/about/sitting-pretty-deux/page/1.html.

As I mentioned in (A), the default behaviour of prim-skirts in SL had driven me around the twist for ages, and in January 2007 I decided to do something about it. I date all my scripts, and, since it is by no means a particularly complex one, it would have been finished at the latest by February. I've used it pretty much continually since, and have demoed it or given copies to friends over that time.

In terms of commercial exploitation, I did nothing for a few months, then produced a "demo pack" which I sent out, completely unsolicited, to one designer (most definitely *not* one of the designers involved with the current other scripts), and got a "I'll look at it and get back to you" response, which never happened. I had no problem with this of course. I also gave the demo pack to a friend of a friend (literally) who said she had many contacts in the fashion world. I never heard anything back from her subsequently.

Its rather an understatement to say that I'm not the most commercially driven person in SL. :-) So, while I continued to use it, I forgot about any commerical exploitation for a couple of months, while focussing on newer, shinier projects. :-) Eventually a couple of friends suggested that I really should be selling the thing, one even making dedicated space available in his shop. I knew that any decent scripter would be able to recreate the functionality of SkirtSitter in a couple of hours, so my plan was to sell it *cheap*, say at $20 L for a no-mod/no-trans/copy perm version. This would reduce the incentive for copy-cat creations, and I hoped I'd sell enough volume to make a little shopping change. But, whilst scripting is fun, writing/designing/placing adds, setting up a store, etc still seemed too much like "work" to me, and my complete mastery of procastination ensured that even the $20 L plan never eventuated. :-)

Then, in early-mid September, Nyte Caligari of Nyte'N'Day released her "SensiDress", which I discovered via my usual perusal of Linden LifeStyles. And, incredibly, this happened the day before I was off to Europe (I'm an Aussie) for a four week holiday. I read both the LL and N'N'D blogs, and (rather belatedly) saw the enthusiasm that was out there for such a script. Having had SkirtSitter sit on my drive for months, I decided the only way a lazy sod like myself would ever get around to making it publically available was simply to distribute it free. I hurriedly posted the instructions and the script itself up on the Second Citizen forums that night, and posted about its availability on a couple of blogs. The reasons for the rush were:

i) I am not ego-less, and I did not want to be accused of being a mere copy-cat, which seemed to me to be more likely if SkirtSitter had appeared a month after alternative commercial products were released.

ii) Having seen the blog enthusiasm, I did not want a month to go by with people thinking that their *only* option was to purchase this sort of script. This is in no way intended as a criticism of the commerical offerings - to this day I have not seen them in action, and it may very well be that they have extra features, ease of use, and support that justifies every last $L of their purchase price and more. But choice is always good too. :-)

The unlikely series of events continued, when the Second Citizen forums imploded whilst I was overseas. To make SkirtSitter publically available once more, I'm uploading it to the Duchy of Darkmere SL Technical forum at: http://duchyofdarkmere.freeforums.org/viewtopic.php?t=538

========

Enough words I think. :-)

Unless you're a freebie reseller, I hope that SkirtSitter performs well for you in whatever purpose you chose to apply it to. If you do receive SkirtSitter via some commercial transaction, please remember, I'm not making a brass razoo out of this - contact the seller for support. :-)

Cale Vinson.




Code:
// "SkirtSitter.lsl"
//
// Cale Vinson, Jan-2007 (Original Version)
//
//   "BAS" = "Basic Animation State", the simplest description of the AV's posture.
//   Examples include 'Walking', and 'Sitting'. For each BAS we store its name, and
//   the position and rotation that the attachment had when that BAS was playing.
//
//  Oct-24, 2007
//  Added support for the walking animation in particular.
//
//  Oct-24a, 2007
//   Added support for copy/paste of BAS data, and for reading and 'writing' of entire
//   BAS list to a configuration notecard. Also added command to reset script entirely.


string gAnimState;
string gAnimStateOld;
string gBAS_FREE;
list gBAS_Name;
integer gBAS_MAX_NUMBER;
list gBAS_Pos;
list gBAS_Rot;
integer gCHANNEL;
vector gCopyPos;
rotation gCopyRot;
float gDialogPlayingTime;
float gDIALOG_TIMEOUT;
vector gINITIAL_POS;
rotation gINITIAL_ROT;
integer gListenHandle;
integer gNoteCardLine;
string gNOTE_CARD_NAME;
key gNoteCardQuery;
string gSEP_STR;
float gTICK_RATE;
list gTmpList;
rotation gTmpRot;
string gTmpString;
vector gTmpVec;


ApplyBAS(string bas)
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [bas]);
   
   if ( basIndex == -1 )  // No data for this BAS, so just take the defaults.
   {
      llSetPos(gINITIAL_POS);
      llSetRot(gINITIAL_ROT);
   }
   else
   {
      llSetPos(llList2Vector(gBAS_Pos, basIndex));
      llSetRot(llList2Rot(gBAS_Rot, basIndex));
   }
}


InitBAS()
{
   integer i;
   
   gBAS_Name = [];
   gBAS_Pos = [];
   gBAS_Rot = [];
   
   for ( i = 0; i < gBAS_MAX_NUMBER; i++ )
   {
      gBAS_Name += [gBAS_FREE];
      gBAS_Pos  += [ZERO_VECTOR];
      gBAS_Rot  += [ZERO_ROTATION];
   }
}


InitOnce()
{
   gTICK_RATE = 1.0;

   gBAS_FREE = "empty";
   gBAS_MAX_NUMBER = 10;
   gCHANNEL = 666;
   gDIALOG_TIMEOUT = 60.0;
   
   InitBAS();
   
   gINITIAL_POS = llGetLocalPos();
   gINITIAL_ROT = llGetLocalRot();
   
   gNOTE_CARD_NAME = "SkirtSitterConfig";
   gSEP_STR = "  /::/  ";
}


InitOnRez()
{
   gAnimStateOld = llGetAnimation(llGetOwner());
   ApplyBAS(llGetAnimation(llGetOwner()));
   gCopyPos = gINITIAL_POS;
   gCopyRot = gINITIAL_ROT;
}


ListenCopy()
{
   gCopyPos = llGetLocalPos();
   gCopyRot = llGetLocalRot();
}


ListenDelete()
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [gAnimState]);
   
   if ( basIndex > -1 )
   {
      gBAS_Name = llListReplaceList(gBAS_Name, [gBAS_FREE], basIndex, basIndex);
      gBAS_Pos  = llListReplaceList(gBAS_Pos,  [ZERO_VECTOR], basIndex, basIndex);
      gBAS_Rot  = llListReplaceList(gBAS_Rot,  [ZERO_ROTATION], basIndex, basIndex);
   }
   
   ApplyBAS(gAnimState);
   
   llOwnerSay("BAS data for this animation state has been deleted.");
}


ListenHelp()
{
   llOwnerSay("Summary of Commands >>>");
   llOwnerSay("<Copy>       Copy the current positioning data into memory.");
   llOwnerSay("<Delete>     Delete the positioning data for this animation-state.");
   llOwnerSay("<Paste>      Paste the positioning data stored in memory, into that for the current animation-state.");
   llOwnerSay("<Read CFG>   Read all the positioning data in from a supplied configuration notecard.");
   llOwnerSay("<Record>     Record the positioning data for this animation-state.");
   llOwnerSay("<Reset>      Set the positioning data for this animation-state to default values.");
   llOwnerSay("<Status>     Give a list of positioning data for each animation-state recorded.");
   llOwnerSay("<Walking>    Record the positioning data, and apply it to the walking animation-state.");
   llOwnerSay("<WIPE!>      CAUTION: Restarts the script, thereby eliminating all script-stored positioning data.");
}


ListenPaste()
{
   UpdateBAS(gAnimState, gCopyPos, gCopyRot);
   ApplyBAS(gAnimState);
   llOwnerSay("BAS data for this animation state pasted from memory.");
}

ListenRecord()
{
   UpdateBAS(gAnimState, llGetLocalPos(), llGetLocalRot());
   llOwnerSay("BAS data for this animation state recorded.");
}


ListenReset()
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [gAnimState]);
   
   if ( basIndex > -1 )
   {
      gBAS_Pos  = llListReplaceList(gBAS_Pos,  [gINITIAL_POS], basIndex, basIndex);
      gBAS_Rot  = llListReplaceList(gBAS_Rot,  [gINITIAL_ROT], basIndex, basIndex);
   }
   
   ApplyBAS(gAnimState);
   
   llOwnerSay("BAS data for this animation state has been reset to default values.");
}


ListenStatus()
{
   integer i;
   
   llOwnerSay("Currently stored BAS are >>>     (name, pos, rot)");
   gTmpString  = gSEP_STR + "Default" + gSEP_STR;
   gTmpString += (string)gINITIAL_POS + gSEP_STR + (string)gINITIAL_ROT + gSEP_STR;
   llOwnerSay(gTmpString);
   for ( i = 0; i < llGetListLength(gBAS_Name); i++ )
      if ( llList2String(gBAS_Name, i) != gBAS_FREE )
      {
         gTmpString  = gSEP_STR + llList2String(gBAS_Name, i) + gSEP_STR;
         gTmpString += (string)llList2Vector(gBAS_Pos, i) + gSEP_STR;
         gTmpString += (string)llList2Rot(gBAS_Rot, i)  + gSEP_STR;
         llOwnerSay(gTmpString);
      }
   llOwnerSay("Free memory: " + (string)llGetFreeMemory());
}


ListenWalking()
{
   UpdateBAS("Walking", llGetLocalPos(), llGetLocalRot());
   llOwnerSay("The walking-animation-state positioning data has been set to the current positioning data.");
}


MakeDialog()
{
   list buttons;
   
   gDialogPlayingTime = 0.0;  // Start recording how long the listen channel is open.
   
   buttons = ["Help", "Record", "Reset", "Status", "Delete", "Turn Off"];
   buttons += ["Walking", "Copy", "Paste", "Read CFG", "WIPE!"];
   llDialog(llGetOwner(), " ", buttons, gCHANNEL);
   
   llListenRemove(gListenHandle);
   gListenHandle = llListen(gCHANNEL, "", llGetOwner(), "");
}


UpdateBAS(string bas, vector pos, rotation rot)
{
   integer basIndex;
   
   basIndex = llListFindList(gBAS_Name, [bas]);
   
   if ( basIndex == -1 )  // A new BAS request.
   {
      basIndex = llListFindList(gBAS_Name, [gBAS_FREE]);
      
      if ( basIndex == -1 )  // No Free slots available
      {
         gTmpString    = "No free BAS slots available. Please delete one currently in use ";
         gTmpString += "and try again.";
         llOwnerSay(gTmpString);
         return;         
      }
   }
   
   gBAS_Name = llListReplaceList(gBAS_Name, [bas], basIndex, basIndex);
   gBAS_Pos  = llListReplaceList(gBAS_Pos,  [pos], basIndex, basIndex);
   gBAS_Rot  = llListReplaceList(gBAS_Rot,  [rot], basIndex, basIndex);
}


//==============================================================================================
//   "default" state
//
//==============================================================================================

default
{
   on_rez(integer start_param)
   {
      llResetScript();
   }
   
   
   state_entry()
   {
      InitOnce();
      InitOnRez();
      
      llOwnerSay("Initialised, touch attachment to proceed.");
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
      state on;      
   }
}


//==============================================================================================
//   "off" state
//
//==============================================================================================

state off
{
   state_entry()
   {
      llSetPos(gINITIAL_POS);
      llSetRot(gINITIAL_ROT);

      llSetTimerEvent(0.0);
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
      llOwnerSay("Activated.");
      InitOnRez();
      state on;
   }
}


//==============================================================================================
//   "on" state
//
//==============================================================================================

state on
{
   listen(integer channel, string name, key id, string message)
   {
      string lcMsg;
      
      lcMsg = llToLower(message);
      
      if ( lcMsg == "copy" )
         ListenCopy();
      else if ( lcMsg == "delete" )
         ListenDelete();
      else if ( lcMsg == "help" )
         ListenHelp();
      else if ( lcMsg == "paste" )
         ListenPaste();
      else if ( lcMsg == "read cfg" )
         state readConfig;
      else if ( lcMsg == "record" )
         ListenRecord();
      else if ( lcMsg == "reset" )
         ListenReset();
      else if ( lcMsg == "status" )
         ListenStatus();
      else if ( lcMsg == "turn off" )
      {
         llOwnerSay("Deactivated. Touch the attachment to re-activate.");
         state off;
      }
      else if ( lcMsg == "walking" )
         ListenWalking();
      else if ( lcMsg == "wipe!" )
      {
         llOwnerSay("Resetting the script, all positioning data stored in the script will be lost.");
         llResetScript();
      }
      
      llListenRemove(gListenHandle);  // Only have a listen open when required.
   }
   
   
   on_rez(integer start_param)
   {
      InitOnRez();
   }
   
   
   state_entry()
   {
      llSetTimerEvent(gTICK_RATE);
   }
   
   
   state_exit()
   {
      llSetTimerEvent(0.0);
   }
   
   
   timer()
   {
      
//      Clean up any unused listeners.
      
      gDialogPlayingTime += gTICK_RATE;
      if ( gDialogPlayingTime > gDIALOG_TIMEOUT )
      {
         gDialogPlayingTime = -1.0E+20;
         llListenRemove(gListenHandle);
      }
   
      gAnimState = llGetAnimation(llGetOwner());
      
      if ( gAnimState != gAnimStateOld )
      {
         ApplyBAS(gAnimState);
         gAnimStateOld = gAnimState;
      }
   }
   
   
   touch_start(integer num_detected)
   {
      if ( llDetectedKey(0) != llGetOwner() )
         return;
      
//      We are only polling the BAS every so often, we may have to wait for the current state to be polled.
      
      if ( gAnimState != llGetAnimation(llGetOwner()) )
      {
         gTmpString = "Animation state not yet updated. Please wait a moment and try again.";
         llOwnerSay(gTmpString);
         return;
      }
      
      MakeDialog();
   }
}


//==============================================================================================
//   "readConfig" state
//
//==============================================================================================

state readConfig
{
   dataserver(key queryid, string data)
   {
      if ( queryid != gNoteCardQuery )
         return;
      
      if ( data == EOF )
      {
         llOwnerSay("Completed reading configuration notecard, returning to ON state.");
         state on;
      }
      else
      {
         gTmpList = llParseString2List(data, [gSEP_STR], []);
         if ( llGetListLength(gTmpList) >= 4 )
         {
            gTmpString = llList2String(gTmpList, 1);
            gTmpVec = (vector)llList2String(gTmpList, 2);
            gTmpRot = (rotation)llList2String(gTmpList, 3);
            if ( gTmpString == "Default" )
            {
               gINITIAL_POS = gTmpVec;
               gINITIAL_ROT = gTmpRot;
            }
            else
               UpdateBAS(gTmpString, gTmpVec, gTmpRot);
         }
         
         gNoteCardLine += 1;
         gNoteCardQuery = llGetNotecardLine(gNOTE_CARD_NAME, gNoteCardLine);
      }
   }
   
   
   on_rez(integer start_param)
   {
      llResetScript();   // We should never get here.
   }
   
   
   state_entry()
   {
      if ( llGetInventoryType(gNOTE_CARD_NAME) != INVENTORY_NOTECARD )
      {
         llOwnerSay("No configuration notecard <" + gNOTE_CARD_NAME + "> found, returning to ON state.");
         state on;
      }
      
      InitBAS();
      gNoteCardLine = 0;
      gNoteCardQuery = llGetNotecardLine(gNOTE_CARD_NAME, gNoteCardLine);
   }
}




Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: