Stop animation problem

I am using kemo custom animations v.2 again in the module I’m working on now. So, a character is sitting down a certain way using one of these animations. Then I want the character to stop the animation and it is really weird. The character stops temporarily, standing up, but then after some other things happening (this is during a dialogue by the way) the character sits down again using the custom animation again. This is the script I’m using to stop the animation which I think has worked before. It must be something I’m missing:

#include "ginc_param_const"

void PlayCustomAnimationVoid(object oObject, string sAnimation, int iLoop = 0, float fSpeed = 1.f)
{
	PlayCustomAnimation(oObject, sAnimation, iLoop, fSpeed);
}

void main(string sTarget)
{
	
object oTarget = GetTarget(sTarget);
AssignCommand(oTarget, ClearAllActions());
PlayCustomAnimationVoid(oTarget, "%", FALSE);

}

The script used to get the character to sit in a certain way fromt the kemo custom animations looks like this:

// kemo_animation
/*
 	Conversation script wrapper for PlayCustomAnimation() command.

 	Parameters:
   		sTarget - tag of creature to play animation - default is conversation owner.
   		sAnim   - animation to play - uses PlayCustomAnimation's *, # and % rules.
   		iFrames  - as the delay with ga_play_custom_animation, but counted in fps from 3DSMax to make
					it easier to enter the length of the *previous* animation

Animation special symbols:
When "%" is passed to PlayCustomAnimation, it resets the creature to its idle animation, 
it kind of clears the current animation for the creature.

Asterisk "*" can be used to fill in the prefix of an animation. For example: PlayCustomAnimation("*dodge01")
will fill out the skeleton and gender data and choose correctly between MD009_dodge01, FH007_dodge01, etc.

Pound "#" is for facial animations.  For example #bigsmile to get a character to smile.  These didn't prove to
look as expected and are to be avoided if possible.
		
*/
// DBR 6/20/06
//EPF -- removed the AssignCommand from the delay code, since that seems to be a likely cause of interrupting animations.
// ChazM 5/1/07 added comments collected from DBR & EPF
// 7/13/08 modified by KEMO for Custom Animations; called by conversation through gui_hss_pc_tool
// 2/09 now called by KEMO_ANIM GUI

#include "ginc_param_const"
#include "kemo_includes"

void main(string sTarget, string sAnimA, int iFrames, int iNoLoop)
{
	object oTarget = GetTarget(sTarget);
	float fFrames = IntToFloat(iFrames); // frames of first animation (usually between 60 and 120)
	float fFramerate = 1.0/30.0;
	float fDelayUntilStart = fFrames*fFramerate; // duration of first anim based on frames

	fDelayUntilStart = fDelayUntilStart * RacialDelay(oTarget);
	
	string sAnimB = "kemo_" + sAnimA;
	string sAnimC = sAnimB + "i";
	
	if (iNoLoop) sAnimC = "idle"; // if this is a fireandforget animation, break the loop
								  // with an idle instead of animation #2

	AssignCommand(oTarget,StoreAnimation(sAnimB,fDelayUntilStart));
	AssignCommand(oTarget,StoreIdle(sAnimC));
	SetLocalLocation(oTarget,"AnimationLocation",GetLocation(oTarget));

	int iOverlap = GetLocalInt(oTarget,"AnimationOverlap"); //animation count (to check overlapped animations)
	iOverlap++; SetLocalInt(oTarget,"AnimationOverlap",iOverlap);

	//SetOrientOnDialog(oTarget,FALSE);

	PlayKemoAnimation(oTarget,sAnimB); // fires the transitional animation
		// a graphical bug causes some races to lose their eyes and lips on a non-looping animation,
		// so this uses a loop on animation #1, which must be ~30 frames longer than the frame count ---
		// this prevents the "jump" between animations, and may help counteract possible server lag
		// issues
	DelayCommand(fDelayUntilStart,AnimationLoop(oTarget,GetLocation(oTarget))); // fires the looping idle animation
}

Ok, don’t know what’s going on. Now it seems to be working. I fiddled around but don’t know if I did anything sigificant. The only thing in the scripts that I did was PlayCustomAnimationVoid(oTarget, "idle", FALSE); instead. But at first that didn’t work either. Will have to test a few more (like 10 times) and see what happens. Otherwise I guess it’s one of those weird animation bugs that appear every now and then in this game, and that is so random, that it’s hard to fix it.

Edit: Ok, took only one test, and I’m back where it started with the same bug again.

Edit: Tried out a few things. But the bug seems to appear now totally at random. My guess is that it is something of an interuption of the animation or something similar, just like previous problems with sitting down, but now it’s the opposite…or something.

I’m going to describe my problem in steps and see if perhaps @Lance_Botelle or someone have any idea of what I’ve screwed up this time around:

  1. Where at an inn. There’s a trigger that triggers a conversation. At the end of the conversation, the two companions leave the party and is jumped through a script to a waypoint in another room close by (it’s roughly the same room but that’s unimportant) while the PC is jumped to another waypoint by the same script.
  2. At the new location, as soon as the PC moves, he enters a trigger that triggers a new conversation. SetCutscenemode is initiated.
  3. This conversation begins with a line from the PC about going to lie down and sleep. At this node one of the companions is jumped to a new waypoint with ga_jump (we don’t see that companion since this is a NWN2 style conversation).
  4. In the next node (a red one) the PC moves to the bed through a script that looks like this:
void ClearPendingActions(object oPC, object oWP)
{
	// just to make sure we're right on the spot
	if (GetCurrentAction(oPC) == ACTION_MOVETOPOINT)
	{
		//SendMessageToPC(GetFirstPC(), "Timing issue!");
		AssignCommand(oPC, ClearAllActions());
	}
	AssignCommand(oPC, ActionJumpToLocation(GetLocation(oWP)));
}


void main()
{

object oPC = GetFirstPC();
object oWP = GetObjectByTag("bedpc_wp");

	DelayCommand(0.1, AssignCommand(oPC, ActionMoveToObject(oWP)));
	// just to make sure we're right on the spot
	DelayCommand(3.0, AssignCommand(oPC, ClearPendingActions(oPC, oWP)));
	// and the lovers are in the right direction


}
  1. The PC has a line (blue node) and on this line I use the kemo_animation script in first post in this thread.
  2. On the next node (red node) I have a delay of 2 seconds.
  3. Then an empty blue node.
  4. This next red node has the companion now sitting down (with the kemo_animation) and says a few lines. A static camera shows the companion. This always works.
  5. The next red node after this shows the other companion talking to the sitting companion.
  6. The next red node after this shows the first companion answering the other companion. In this node there’s a script where she changes clothes through this script:
void main()
{

	object oCompanion = GetObjectByTag("companion1");
	object oClothes = CreateItemOnObject("newclothes", oCompanion);
	AssignCommand(oCompanion, ActionEquipItem(oClothes, INVENTORY_SLOT_CHEST));
	
}
  1. Next red node after that shows the other companion talking again, now with new clothes.
  2. Next blue node after this I try to stop the sitting animation. This is where things sometimes don’t work:
#include "ginc_param_const"

void PlayCustomAnimationVoid(object oObject, string sAnimation, int iLoop = 0, float fSpeed = 1.f)
{
	PlayCustomAnimation(oObject, sAnimation, iLoop, fSpeed);
}

void main(string sTarget)
{
object oTarget = GetTarget(sTarget);
AssignCommand(oTarget, ClearAllActions());
PlayCustomAnimationVoid(oTarget, "idle", FALSE);
}
  1. Next red node: First companion now stands up and talks. Almost all of the times she stands, but on one occasion I saw her sitting down directly after standing up, like the animation got interupted, but most of the time she stands and it actually works.
  2. Next red nod: The other companion talks again.
  3. Blue node: Some text here but the PC doesn’t speak. Three scripts runs: 1. ga_fade_to_black, 2.One companion gets dressed with former clothes 3. The other companion also gets dressed with former clothes. Both these companions do this by this script or two variations of it. Looks something like this:
void main()
{

	object oGirl = GetObjectByTag("qurfasa2");
	object oClothes = GetObjectByTag("qurarm");
	AssignCommand(oGirl, ActionEquipItem(oClothes, INVENTORY_SLOT_CHEST));
	
	object oNu = GetObjectByTag("newclothes");
	DestroyObject(oNu,0.5);
	
}
  1. Red node: Here we do a ga_jump to a new waypoint nearby with the first companion that first sat, and then has stood up (as I said before: her standing up works most of the time).
  2. Blue node: SetcutsceneMode is turned off and we do a ga_fade_from_black. Edit: This is where the conversation ends, I forgot to tell all of you.
  3. Now when we move the PC back to the two companions, 50 % of the time the first companion sits down for some reason at the new waypoint, or she stands up. This is the main bug I’ve been talking about in the previous posts.

This all looks like déjà vu: Animations In Conversations (Via the editor) - Not Always Working

Not sure it will work at all, but based on my experience, @Lance_Botelle’s and @Gnomocratic_Agent’s findings and of course your own scripts, maybe (and I emphasize the maybe), you could try this:

  1. add a delay so PlayCustomAnimationVoid(oTarget, "idle", FALSE); plays after AssignCommand(oTarget, ClearAllActions());
    (by the way, did you try with “%” instead of “idle”? No reason it should change anything, but for the sake of thoroughness…)

  2. split the original conversation in two parts, and start the second part at this stage, with (as Lance suggests) a ga_play_animation first line.

Again, no guarantee this will work. I still haven’t been able to get a conversation with scripted animations works flawlessly every time, even using ga_play_animation instead of a script written specially for the conversation.

Thanks for the reply 4760!

Yeah, maybe these are some of the same issues (though I didn’t think about that before) that Lance had with when speaking in his thread about Animations in Conversations.

Yes, I tried with “%” first, but when that didn’t work I tried “idle”. I didn’t have ClearAllActions at first either, but thought that that might help things. I’ll try with a delay after that and see what happens.

I don’t know about splitting the conversation, since this is a whole continous cutscene but perhaps if I use CreateIpSpeaker here it could work. Seems risky but…

I forgot to say in 17. Here is where the conversation ends.

It’s after that, that you find the companion sitting down instead of standing up 50 % of the time.

I tried with a delay after ClearAllActions. It didn’t seem to do much, and it was a bit odd now when I came back to the teleported companion after the conversation. Now she was half standing up, and when I got into the room she was slowly sitting herself down. It’s odd that the game wants to do the kemo_animation even after I’ve said that she should do the idle animation or just stop the animation. It’s like this kemo thing is so robust (and that I take as a good thing actually) that the game tries to sit her down again (50 % of the time that is).

Ok, this is frustrating. About to try ga_play_animation now, but there is no “idle” among the constants. Don’t know what to do about that.

Edit: Tried with “stand up” but now I have another problem. When splitting the conversation in two parts, for some reason the second part just won’t start. I tried with both CreateIpSpeaker (and I KNOW this has worked before since I used it in my first module) and AssignCommand(oComanion, ActionStartConversation…) but nothing will start the second part. I did a ga_global_int and gc_global_int so that the second part is above the first in the conversation editor…Urggh, why must everything be so hard in this darn game.

@andgalf, @4760

We keep finding these issues with animations don’t we! :wink: … Anyway, I just want to add these two bits of info here as well (paraphrased from the last post), as they may be pertinent … or if not, just good to try to remember:-

A: " I think an animation may fail if the NPC it is attached to is in the process of orienting themselves to the PC - which is why it appeared random. That may explain the initial fail of the animation, but I still see no reason for the later nodes to fail - unless some other subtle orientation is taking place?."

B: “I have also discovered that (in my testing at least) that if a creature is in the middle of an animation, then a trigger to start a conversation with them may fail. I have found that I need to add the following line just after a ClearAllActions on them to help ensure the conversation starts from a trigger: PlayCustomAnimation(oSpeaker,”%", 0);"

However, that all said, I have also recently been trying to have a conversation where an NPC starts sitting, rises to say hello and then reseats for the remainder of the conversation. However, somewhere along the way, the animations went awry (again) and the NPC goes to sit, but stands back up again. However, I may not have considered point A above regarding the NPC orienting themselves.

I mention all this because it appears to me that animations rely a lot upon timing and current actions - and clearing said actions or having the animation timing correct appear a fine art to me. And finding a one time perfect solution still evades me even now.

Now, to answer your question, which I think may be happening, but am far from being sure about it, and would require closer inspection to be sure … but it may be this …

Because you say it appears “random”, that reminded me of my own situation with “A” above, in that if an NPC is in the process of orienting themselves towards the PC, then any animation firing at that time appears to be ignored … or immediately stopped/broken.

Now, the orientation operations may or may not be being influenced by the use of SetOrientOnDialog somewhere, or even where it is applied in a conversation start somewhere. The way to test if this is having a bearing, is to try to locate anywhere it may be being used and prevent it from firing … or, and this was my own test that appeared to help me determine it was an issue … try to run the conversation in such a way that the NPC is not reorienting themselves (probably towards the PC) when the animation is called. i.e. For the process of testing only, freeze the PC in place for the process of the conversation and see if that helps.

I write this as a reminder to myself and the issues I am having as well as to you in the hope that it may help us get to the bottom of the animations issues.

Bottom line, I do believe (at this stage) that a subtle orienting animation is somehow messing with other animations.

Thanks, Lance.

I just reread your issue, and it sounds like you may be having the “opposite” issue in that the NPC sits down again, rather than stands up from a required sit. Therefore, I would add you check the following … bear in mind I don’t fully recall how you do all your animation code calls …

  1. Make sure you have not used SIT_TALK (or TALK_SIT?) anywhere on any of the nodes, as it may try to reapply after other animations.

  2. Make sure you do not have a variable set somewhere that is trying to make them sit in a heartbeat (like I use). It may be kicking in after the conversation. i.e. I have a TRYSIT variable that is checked to sit an NPC down again in their heartbeat after a conversation.

This generic campaign script works not too bad. I have used it in sitting situations. Put in the OnHeartBeat of the involved NPC.

The NPC carries 3 local variables :

  • Anim the animation to be played
  • Bearing the direction to face when playing the animation
  • Stop the stop flag (init 0).
    Local variables can be changed at anytime from a convo or another script. Whenever the stop flag is set to 1 the animation is stopped. You may resume it later if it makes sense.
// anim with a stop flag.

void main ()
{
	object oNPC = OBJECT_SELF;
	string sAnim = GetLocalString(oNPC, "Anim");
	
	ClearAllActions();
	
	if (GetLocalInt(oNPC, "Stop"))
		sAnim = "idle";
	else
		SetFacing(IntToFloat(GetLocalInt(oNPC,"Bearing")));	
	
	PlayCustomAnimation(oNPC, sAnim, 1, 1.0);
}

It is not perfect at all, automatic facing redirections are not prevented, the guy briefly faces the PC, then get to his “Bearing”.
Hope it helps.

Yes, this seems to haunt me always when making my modules. It’s insane. :crazy_face:

This A thing you’re talking about feels like something I maybe should try, I don’t know.

What I noticed this morning before going to work, was that when trying to split the conversation in two, I could see the companion in the other room. I noticed something quite odd. On 13. I noticed her standing up like requested, stood for a while, but all of a sudden she went down sitting again. It’s like the kemo_animations say to me: “Don’t you dare try and stop our fabulous animations! We will have none of it!” I mean, my problems before has always been to get the PC and/or the companions to sit down but here all of a sudden it’s the opposite.

I don’t know, Lance, if you remember when we struggled with the other place where I had the companions jojo-ing up and down trying to sit down at a clearing. This is in ASW3 and works well now. I might have to go over what we did there. These are the same sitting down animations I use here. I think we did something, if remembering correctly with hindering the companions and all to orient themselves. That might actually be the case here, I guess. Will have to try a bit more.

Thanks for chiming in @Claudius33! I know your modules are pretty advanced and you know your stuff! Not exactly sure I understand fully your system here. I think I’ll try some of Lance’s suggestions first and look at my other module to see if I can get some clue to what’s going on.

I have used none of this in this case. The companion is not sitting on any chair. She is just sitting down on the floor. So this is a bit different from the case with the sitting chairs you managed to solve for me.

Ok, looking at how I did sitting down on the ground in my third module I actually just did a Stand Your Ground thing in the script, then they sit down with the kemo_animations script, like I use here too, and then in one of the first nodes I run a script like this where I force them to watch the fireplace in the middle of camp, and here I actually have SetOrientOnDialog(oCompanion,TRUE);

I’ll try in my new module and do a SetOrientOnDialog(oCompanion,FALSE); and see if this helps the animation. The companion isn’t supposed to face the PC anyway since he’s in another room lying in a bed so. Well, I’ll see what happens…

Edit: Actually, later in another node in my previous module I do a SetOrientOnDialog(GetNearestObjectByTag(“companiontag”,oPC),FALSE);

Edit: SetOrientOnDialog doesn’t seem to solve the issue. I’m thinking that maybe I should make the “idle” animation a loop? Cause right now, I noticed that even if the companion stands up, it seems after a few seconds she actually sits down again if I don’t talk to her. So, it’s like, whenever the idle animation has done its run, she reverts back to the kemo_animation. Could that be so? Can any of you see in the kemo_animation script here if that may be the case? I’m not always that good at reading more complicated scripts…

// kemo_animation
/*
 	Conversation script wrapper for PlayCustomAnimation() command.

 	Parameters:
   		sTarget - tag of creature to play animation - default is conversation owner.
   		sAnim   - animation to play - uses PlayCustomAnimation's *, # and % rules.
   		iFrames  - as the delay with ga_play_custom_animation, but counted in fps from 3DSMax to make
					it easier to enter the length of the *previous* animation

Animation special symbols:
When "%" is passed to PlayCustomAnimation, it resets the creature to its idle animation, 
it kind of clears the current animation for the creature.

Asterisk "*" can be used to fill in the prefix of an animation. For example: PlayCustomAnimation("*dodge01")
will fill out the skeleton and gender data and choose correctly between MD009_dodge01, FH007_dodge01, etc.

Pound "#" is for facial animations.  For example #bigsmile to get a character to smile.  These didn't prove to
look as expected and are to be avoided if possible.
		
*/
// DBR 6/20/06
//EPF -- removed the AssignCommand from the delay code, since that seems to be a likely cause of interrupting animations.
// ChazM 5/1/07 added comments collected from DBR & EPF
// 7/13/08 modified by KEMO for Custom Animations; called by conversation through gui_hss_pc_tool
// 2/09 now called by KEMO_ANIM GUI

#include "ginc_param_const"
#include "kemo_includes"

void main(string sTarget, string sAnimA, int iFrames, int iNoLoop)
{
	object oTarget = GetTarget(sTarget);
	float fFrames = IntToFloat(iFrames); // frames of first animation (usually between 60 and 120)
	float fFramerate = 1.0/30.0;
	float fDelayUntilStart = fFrames*fFramerate; // duration of first anim based on frames

	fDelayUntilStart = fDelayUntilStart * RacialDelay(oTarget);
	
	string sAnimB = "kemo_" + sAnimA;
	string sAnimC = sAnimB + "i";
	
	if (iNoLoop) sAnimC = "idle"; // if this is a fireandforget animation, break the loop
								  // with an idle instead of animation #2

	AssignCommand(oTarget,StoreAnimation(sAnimB,fDelayUntilStart));
	AssignCommand(oTarget,StoreIdle(sAnimC));
	SetLocalLocation(oTarget,"AnimationLocation",GetLocation(oTarget));

	int iOverlap = GetLocalInt(oTarget,"AnimationOverlap"); //animation count (to check overlapped animations)
	iOverlap++; SetLocalInt(oTarget,"AnimationOverlap",iOverlap);

	//SetOrientOnDialog(oTarget,FALSE);

	PlayKemoAnimation(oTarget,sAnimB); // fires the transitional animation
		// a graphical bug causes some races to lose their eyes and lips on a non-looping animation,
		// so this uses a loop on animation #1, which must be ~30 frames longer than the frame count ---
		// this prevents the "jump" between animations, and may help counteract possible server lag
		// issues
	DelayCommand(fDelayUntilStart,AnimationLoop(oTarget,GetLocation(oTarget))); // fires the looping idle animation
}

It seems, when looking in kemo_includes, that the animation is stored. I’m beginning to believe that’s why the animation begins again. Still, I can’t wrap my head around how to reset that thing when I need to. Can anyone of you scripting masters grasp how to reset the animation?:

//kemo_includes
//
// Determines the loop animation trigger delay based on PC's race/subrace; KEMO Emotes/Partners only

float RacialDelay(object oTarget);

// Plays the custom animation with an automatic loop, which works around the animation bug
void PlayKemoAnimation(object oTarget, string sAnim);

// Turns the PC to face the direction of the chair
void SetChairFacing(object oPC, object oChair);

// This function works around the NWN2 bug where PCs entering an area do not see looping animations that
// are currently in progress. AnimationLoop re-triggers the animation at a set interval as long as the PC has
// not moved from the original spot. lCurrentSpot is the animation's starting location, which is checked against
// the PC's current location.
void AnimationLoop(object oPC, location lCurrentSpot);

// Stores the parameters necessary to re-trigger the starting current/previous animation.
void StoreAnimation(string sAnim, float fDelay);

// Stores the parameters necessary to re-trigger the idle of the current/previous animation.
void StoreIdle(string sAnim);

float RacialDelay(object oTarget)
{
	switch (GetSubRace(oTarget)) // attempts to deal with the varying race speeds
		// I use this instead of a fractional animation speed because a fractional speed causes the
		// PC to move more slowly than is normal for his/her race
		// without these switches, a non-human-sized PC will "jump" right before the looping animation
	{
		case RACIAL_SUBTYPE_DROW: return 0.8f; break;
	}
	switch (GetRacialType(oTarget))	{
		case RACIAL_TYPE_HALFLING: return 0.5f; break; 
		case RACIAL_TYPE_ELF: return 0.9f; break; 
		case RACIAL_TYPE_HALFELF: return 0.95f; break; 
	}

	return 1.0f;
}

void PlayKemoAnimation(object oTarget, string sAnim)	//so it returns a void
{
	PlayCustomAnimation(oTarget,sAnim,1);
}

void SetChairFacing(object oPC, object oChair)
{
	float fChairFace = GetFacing(oChair);
	string sChairTag = GetTag(oChair);
	
	if (sChairTag == "kemo_chair_4") return;
	else if (sChairTag == "kemo_bench_2" ||
			sChairTag == "kemo_chair_5") AssignCommand(oPC,SetFacing(fChairFace));
	else if (sChairTag == "kemo_booth_1") AssignCommand(oPC,SetFacing(fChairFace-90.0f));
	else AssignCommand(oPC,SetFacing(fChairFace+180.0f));
}

void AnimationLoop(object oPC, location lCurrentSpot)
{
	/* This script now sets the animation information on a Secret Object and starts its heartbeat
	on a 48 second interval. If the Ipoint already exists, it transfers the new animation
	name to that Secret Object. Thanks to GrinningFool for this more elegant solution. 7/29/08 */
	object oPoint = GetLocalObject(oPC,"AnimationPoint");
	string sAnim = GetLocalString(oPC,"StoredAnimationIdle");

	SetCollision(oPC,0); //turns collision off for the course of the animation.
	if (oPoint != OBJECT_INVALID)
	{
		SetLocalString(oPoint,"StoredAnimationIdle",sAnim);
		PlayKemoAnimation(oPC,sAnim);
	}
	else
	{
		object oPoint = CreateObject(OBJECT_TYPE_PLACEABLE,"plc_secretobject",lCurrentSpot,FALSE,"AnimationPoint");
		SetLocalObject(oPC,"AnimationPoint",oPoint);
		SetLocalObject(oPoint,"StoredAnimationPC",oPC);
		SetLocalString(oPoint,"StoredAnimationIdle",sAnim);
		SetUseableFlag(oPoint,0);
		SetCustomHeartbeat(oPoint,12000);
		SetEventHandler(oPoint,SCRIPT_PLACEABLE_ON_HEARTBEAT,"kemo_animation_hb");
		PlayKemoAnimation(oPC,sAnim);
	}
}

/* the following is the original loop script, now replaced with a heartbeat on an Ipoint 7/29/08
{
	object oPC = OBJECT_SELF;
	location lSpot = GetLocalLocation(oPC,"AnimationLocation");
	vector vSpot = GetPositionFromLocation(lSpot);
	vector vCurrentSpot = GetPositionFromLocation(lCurrentSpot);
	string sAnim = GetLocalString(oPC,"StoredAnimationIdle");
	int iOverlap = GetLocalInt(oPC,"AnimationOverlap");
	
	// This function gets re-called for each new animation, so that more than one iteration of the
	// function can be running at the same time if the PC hasn't spent at least 48 seconds not in an
	// animation. The first two IF statements eliminate the excess function iterations (the overlaps)
	// while continuing to show the current animation. The third IF statement continues the animation
	// if the PC is still in the same spot. The ELSE statement clears the overlap count if all animations
	// have ceased (through PC movement without a new animation).
	//SendMessageToPC(oPC,"Overlap: " + IntToString(iOverlap)); //debug line
	//SendMessageToPC(oPC,"Animation: " + sAnim);				//debug line
	
	if (vSpot != vCurrentSpot)
	{
		iOverlap = 1;
		SetLocalInt(oPC,"AnimationOverlap",iOverlap);
		return;					 
	}
	if (iOverlap > 1)
	{
		iOverlap--;
		SetLocalInt(oPC,"AnimationOverlap",iOverlap);						 
		ActionDoCommand(PlayKemoAnimation(oPC,sAnim));
		return;
	}
	if (vSpot == GetPosition(oPC))
	{
		ActionDoCommand(PlayKemoAnimation(oPC,sAnim));
		ActionDoCommand(DelayCommand(48.0f,AnimationLoop(lCurrentSpot)));
	}
	else SetLocalInt(oPC,"AnimationOverlap",0);
}*/

void StoreAnimation(string sAnim, float fDelay)
{
	SetLocalString(OBJECT_SELF,"StoredAnimation",sAnim); // stores the animation name for re-triggering
	SetLocalFloat(OBJECT_SELF,"StoredDelay",fDelay); // stores the delay for re-triggering		
}

void StoreIdle(string sAnim)
{
	SetLocalString(OBJECT_SELF,"StoredAnimationIdle",sAnim);
}

I think I’ve managed to solve it now. I’ve tested the scene 10 times and not once has it failed now. What I did was that when looking at the include script I saw that in the AnimationLoop function it creates an invisible object, with the tag “AnimationPoint”, that seems to have a heartbeat that seems to restart the animation. Don’t know if that’s entirely correct, but by altering the script when my companion stands up, and destroying that object, that seemed to fix the problem. At least that’s what I think:

#include "ginc_param_const"

void PrepForDestruction(object oTarget)
{
	SetPlotFlag(oTarget,FALSE);
    SetImmortal(oTarget,FALSE);
    AssignCommand(oTarget,SetIsDestroyable(TRUE,FALSE,FALSE));
}


void PlayCustomAnimationVoid(object oObject, string sAnimation, int iLoop = 0, float fSpeed = 1.f)
{
	PlayCustomAnimation(oObject, sAnimation, iLoop, fSpeed);
}

void main(string sTarget)
{
	
object oTarget = GetTarget(sTarget);
AssignCommand(oTarget, ClearAllActions());

object oPoint = GetObjectByTag("AnimationPoint");

 if(GetIsObjectValid(oPoint))
 {
 PrepForDestruction(oPoint);
 }

DelayCommand(0.2, PlayCustomAnimationVoid(oTarget, "idle", FALSE));

 if(GetIsObjectValid(oPoint))
 {
 DelayCommand(0.3, DestroyObject(oPoint));
 }

}
2 Likes

Good catch … One of those things we would never have found as it is outside normal parameters that are specific to your design usage. i.e. I control mine via a variable and heartbeat from the PC and NOT from another placeable object. However, this/your issue is akin to having a variable set (like in my own) to “reset” the animation.

Thanks for updating, Lance.

Yeah, as I’ve stated in this thread many times I use the kemo animations v.2 for this, and the scripts that come with that, which I posted here.

I’ve tried it about 7 more times, and not one time it has failed me now. I also did another change that could have had to do with the error perhaps. When using the kemo_animation script in the dialogue I had iFrames set to 0, and when I looked at my previous module it was set to 90 everytime a character would do one of these animations. So I changed that here to 90 too. Maybe that could have had something to do with stuff, I don’t know.

1 Like

Nice! So, apart from destroying the object that made sure the animation would still be on, the “standard” scripts in your initial post were OK?

I think so, yes. It seems so at least.

Knowing the toolset and NWN2, I’m pretty sure this won’t be the last time I have trouble with animations though. So, I will probably ask for help again. :grinning:

Edit: This is one of the downside to using scripts that others have made (and that are a bit complicated), that “hidden” stuff like this is used that you haven’t thought about, or don’t know about. But hey, I’m still pretty bad at scripting, and scripting animations seems to be, like Lance says, “a fine art”, so I am often forced to use such scripts because it is beyond my understanding and knowledge.

Actually, I noticed the bug again, together with another bug, but it ONLY seems to happen if you save the game before the new conversation starts at 2. (see my third post for the numbers describing events) Since this is a really rare case, I don’t think that many will save at this particular point, I think I can live with it. And the two bugs are still only graphical ones (companion sitting down at the end of the dialogue and not changing clothes at a particular point) so nothing game breaking.