Steffan Mielziner Posted March 24, 2017 Share Posted March 24, 2017 I have an object that I put some dance animations into. The files are named like so: <dance_name>;<length_in_seconds> I want the avie to be able to sit/dance, continually play each animation to its length, move on to the next dance, then continually loops back to whatever the first animation is. So, THAT part seems to work OK. What doesn't work is getting the animations to stop once the avie stands. Even after telling the Avater Health to Stop Animations in the client, the next dance will kick in after the sleep timeout. What am I doing wrong here? Thanks, Steff string danceFileName; integer dancing; start_dancing() { integer totalDances = llGetInventoryNumber(INVENTORY_ANIMATION); integer currentDanceNum = 0; dancing = 1; while( dancing ) { danceFileName = llGetInventoryName(INVENTORY_ANIMATION, currentDanceNum); list danceFileNameTokens = llParseString2List(danceFileName, [";"], []); string danceLength = llList2String( danceFileNameTokens, 1 ); llStartAnimation(danceFileName); llSleep( (float) danceLength ); llStopAnimation(danceFileName); currentDanceNum = currentDanceNum + 1; if (currentDanceNum == totalDances) { currentDanceNum = 0; } } } default { state_entry() { llSetSitText("Dance"); llSitTarget(<0.0, 0.0, 1>, ZERO_ROTATION); } changed(integer change) { if (change & CHANGED_LINK) { key av = llAvatarOnSitTarget(); if (av) { llRequestPermissions(av, PERMISSION_TRIGGER_ANIMATION); } else { if (danceFileName) { llStopAnimation(danceFileName); } dancing = 0; llResetScript(); } } } run_time_permissions(integer perm) { if (perm & PERMISSION_TRIGGER_ANIMATION) { llStopAnimation("sit"); start_dancing(); } } } Link to comment Share on other sites More sharing options...
Innula Zenovka Posted March 24, 2017 Share Posted March 24, 2017 (edited) The big problem is that you never do anything to stop the animations. Your user function start_dancing sets dancing to TRUE and then enters an infinite loop, while (dancing), which is always going to evaluate as TRUE because nothing can make it FALSE. There's an additional potential problem, in that since you cause the script to sleep for the length of each animation, even when you fix the main problem, the script isn't going to be able to do anything until the clip that it's playing has finished. If I were writing this, I would get rid the llSleep call and using a timer, instead. (always a good idea, to my mind, if you find you're putting the script to sleep for any longer than 0.5 seconds or so). So, in the changed event, if there's an avatar sitting on the object, I would ask for animation permissions and then, in the run_time_permissions event, I would start the first animation and set a timer for the length of that animation. Then in the timer event, I would step through my animation list, starting a new timer for each clip, and then go back to the start, as you do in the user function. To stop the dancing when the avatar gets up, simply call llStopAnimation in the changed event if there isn't anyone sitting on the prim any more, and then stop the timer. Edited March 24, 2017 by Innula Zenovka Link to comment Share on other sites More sharing options...
Love Zhaoying Posted March 24, 2017 Share Posted March 24, 2017 (edited) I like Innula Zenovka's answer. Edited March 24, 2017 by Love Zhaoying Better answer below! Link to comment Share on other sites More sharing options...
Love Zhaoying Posted March 24, 2017 Share Posted March 24, 2017 2 minutes ago, Innula Zenovka said: To stop the dancing when the avatar gets up, simply call llStopAnimation in the changed event if there isn't anyone sitting on the prim any more, and then stop the timer. I like this. Link to comment Share on other sites More sharing options...
Innula Zenovka Posted March 24, 2017 Share Posted March 24, 2017 11 minutes ago, Love Zhaoying said: Once an avatar stands, (since you said it is a poseball) the animations are no longer controlled by the script. However, the animation keeps running because you did not tell it to stop. Non-poseball dance (whether a "sign", big ball in the sky, or a hud to click) machines handle this by having a menu option the user clicks to "STOP". (The user had already given permission to animate, so "stop" doesn't ask for permission again but stops all animations that the script had run.) I fear that your users have no option but to select "stop all animations/stop animating me" from the viewer menu. If they have an AO, the next AO cycle should stop the animation also. You can also consider an option to "click the ball" to stop dancing once they got off of it (similar to STOP menu item for a non-sitting/non-poseball dance machine). I think it's worse than that. The script keeps its animation permissions unless it's told to release them (or the script is reset). Normally that wouldn't be a problem since, as you say, the avatar's AO is going to start playing a stand or walk animation as soon as the dancer gets up, and most animation scripts won't try to do anything to the former sitter after she's stood, even if they don't explicitly stop the animation. However, since the start_dancing() user function never gets told to stop, I think what's likely to happen is that the script is going to keep on animating the avatar for as long as she's on the same region, or until someone else sits on the prim. Even then, though, because of the llSleep(), the script isn't going to know about the next sitter until the end of the current animation, so I suspect the second sitter is probably going to get up again before anything starts and then be surprised to find herself animated some 10 seconds or so later. 3 Link to comment Share on other sites More sharing options...
Xiija Posted March 24, 2017 Share Posted March 24, 2017 (edited) The wiki suggests a little trick too... Quote if you must stop a looped animation, playing a single frame non-looped one immediately after stopping it, at low priority, will clear the list. so something like... llStopAnimation(danceFileName); llStartAnimation("b43c9176-112c-944f-33fa-da2d275a9ac"); llStopAnimation("b43c9176-112c-944f-33fa-da2d275a9ac"); the UUID is one i have for a blank anim, from MP Blank Animation-Zero priority Edited March 24, 2017 by Xiija Link to comment Share on other sites More sharing options...
Innula Zenovka Posted March 24, 2017 Share Posted March 24, 2017 While you can stop animations by using either the name of the animation or its uuid, you can call them only by name. I think llStartAnimation("b43c9176-112c-944f-33fa-da2d275a9ac"); is going to trigger a script error message complaining it can't find an animation called "b43c9176-112c-944f-33fa-da2d275a9ac". When I want to stop a looped animation like that, I use the built-in system animations, which you can call by name without having them in the objects's inventory. So I call llStartAnimation("stand"); when the avatar stands up. If the avatar is using an AO, then the AO will kick in almost immediately and cancel "stand" (which is priority 0, so it's as low as it gets). If not, at least the avatar is standing rather than stuck in the looped animation. 2 Link to comment Share on other sites More sharing options...
Steffan Mielziner Posted March 24, 2017 Author Share Posted March 24, 2017 Thank you Innula and Love for the detailed reply. With your help, I finally got it working. I think in my brain I'm mixing up procedural code with event driven scripting. For completeness, here is what I ended up with: string danceFileName; integer currentDanceNum; integer totalDances; default { state_entry() { currentDanceNum = 0; totalDances = llGetInventoryNumber(INVENTORY_ANIMATION); llSetSitText("Dance"); llSitTarget(<0.0, 0.0, 1>, ZERO_ROTATION); } timer() { llStopAnimation(danceFileName); llSetTimerEvent(0.0); currentDanceNum = currentDanceNum + 1; if (currentDanceNum == totalDances) { currentDanceNum = 0; } danceFileName = llGetInventoryName(INVENTORY_ANIMATION, currentDanceNum); list danceFileNameTokens = llParseString2List(danceFileName, [";"], []); string danceLength = llList2String( danceFileNameTokens, 1 ); llStartAnimation(danceFileName); llSetTimerEvent((float)danceLength); } changed(integer change) { if (change & CHANGED_LINK) { key av = llAvatarOnSitTarget(); if (av) { llRequestPermissions(av, PERMISSION_TRIGGER_ANIMATION); } else { if (danceFileName) { llStopAnimation(danceFileName); } llSetTimerEvent(0.0); llResetScript(); } } } run_time_permissions(integer perm) { if (perm & PERMISSION_TRIGGER_ANIMATION) { llStopAnimation("sit"); danceFileName = llGetInventoryName(INVENTORY_ANIMATION, currentDanceNum); list danceFileNameTokens = llParseString2List(danceFileName, [";"], []); string danceLength = llList2String( danceFileNameTokens, 1 ); llStartAnimation(danceFileName); llSetTimerEvent((float)danceLength); } } } 1 Link to comment Share on other sites More sharing options...
Steffan Mielziner Posted March 25, 2017 Author Share Posted March 25, 2017 There seems to be one minor bug left in this, if an avie doesn't stand before logging off, I get: llStopAnimation: Script trying to stop animations but agent not found Is there a good way to ask if anyone is still dancing on the animation or if the user is still online before trying to stop? I was thinking about trying to use llRequestAgentData with DATA_ONLINE, but then I noticed that this seems to be unresolved https://jira.secondlife.com/browse/SVC-6831? suggestions? Thanks, -Steff Link to comment Share on other sites More sharing options...
Rolig Loon Posted March 25, 2017 Share Posted March 25, 2017 One of the easiest things to do is to ask if (llGetAgentSize(agent_UUID) != ZERO_VECTOR) { llStopAnimation(my_animation); } If the avatar is anywhere in the region, the script will stop the animation. Otherwise, it won't even try. 2 Link to comment Share on other sites More sharing options...
Steffan Mielziner Posted March 26, 2017 Author Share Posted March 26, 2017 (edited) Awesome. Thank you Rolig! this seems to work flawlessly: string danceFileName; integer currentDanceNum; integer totalDances; key currentAvatarKey; default { state_entry() { currentDanceNum = 0; totalDances = llGetInventoryNumber(INVENTORY_ANIMATION); llSetSitText("Dance"); llSitTarget(<0.0, 0.0, 1>, ZERO_ROTATION); } timer() { llStopAnimation(danceFileName); llSetTimerEvent(0.0); currentDanceNum = currentDanceNum + 1; if (currentDanceNum == totalDances) { currentDanceNum = 0; } danceFileName = llGetInventoryName(INVENTORY_ANIMATION, currentDanceNum); list danceFileNameTokens = llParseString2List(danceFileName, [";"], []); string danceLength = llList2String( danceFileNameTokens, 1 ); llStartAnimation(danceFileName); llSetTimerEvent((float)danceLength); } changed(integer change) { if (change & CHANGED_LINK) { key requestingAvatarKey = llAvatarOnSitTarget(); if (requestingAvatarKey) { llRequestPermissions(requestingAvatarKey, PERMISSION_TRIGGER_ANIMATION); currentAvatarKey = requestingAvatarKey; } else { if (llGetAgentSize(currentAvatarKey) != ZERO_VECTOR) { llStopAnimation(danceFileName); } llSetTimerEvent(0.0); llResetScript(); } } } run_time_permissions(integer perm) { if (perm & PERMISSION_TRIGGER_ANIMATION) { llStopAnimation("sit"); danceFileName = llGetInventoryName(INVENTORY_ANIMATION, currentDanceNum); list danceFileNameTokens = llParseString2List(danceFileName, [";"], []); string danceLength = llList2String( danceFileNameTokens, 1 ); llStartAnimation(danceFileName); llSetTimerEvent((float)danceLength); } } } Edited March 26, 2017 by Steffan Mielziner 1 Link to comment Share on other sites More sharing options...
Charahalee Allure Posted March 26, 2017 Share Posted March 26, 2017 Go to Avatar on the top of the Screen go to Avatar health and then sop avatar animation. Link to comment Share on other sites More sharing options...
Rolig Loon Posted March 26, 2017 Share Posted March 26, 2017 1 hour ago, stepfordbride said: Go to Avatar on the top of the Screen go to Avatar health and then sop avatar animation. That's fine, except when you are looking for a scripted solution that will keep the next owner from having to do that. 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Please take a moment to consider if this thread is worth bumping.
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now