Swapping idle mode?

Is there a way to swap the idle mode on a model? I’m thinking of building an animated placeable that requires a skeleton. But it appears that a skeleton model needs to be a creature. This model needs to have two idle modes: open and closed. If it’s in one or the other I want it to stay that way without needing to run a heartbeat script. Any suggestions?

You could do it with the animations PLC_NameOfPlaceable_Idle.gr2 and PLC_NameOfPlaceable_PLC_OpenIdle.gr2, with one the closed position and the other the opened position.
To swap from one state to the other, obviously you just need to open it (or activate it):

void main()
{
	// note that nActive == 1 does  not necessarily mean the placeable is active, that depends on the initial state of the object

	object oSELF = OBJECT_SELF;

	int nActive = GetLocalInt (oSELF, "X2_L_PLC_OPEN_STATE");

	// * Play Appropriate Animation

	if (!nActive)

	{

		ActionPlayAnimation(ANIMATION_PLACEABLE_OPEN);

	}

	else

	{

		ActionPlayAnimation(ANIMATION_PLACEABLE_CLOSE);

	}

	// * Store New State

	SetLocalInt(oSELF, "X2_L_PLC_OPEN_STATE", !nActive);

}

The above code is obviously fired from the OnUsed slot of the placeable, but if you define oSELF (say, with Get*ObjectByTag) you could call it from a trigger or a conversation or any other way you see fit.

@4760 put [code] on its own line

sweet :)

2 Likes

That’s way better now! Thanks @kevL_s!

1 Like

Perhaps I wasn’t clear. This model will use a skeleton, so it needs to have SKIN packets rather than just the RIGD of regular placeables.

Ah… In this case, the only way I was able to achieve this was to create two appearances (same mesh, same “physical” skeleton but with a different name for the root bone, like c_creatureidleopen_skel and c_creatureidleclose_skel).
It’s then easy to have two different idle animations. But of course there are drawbacks:

  1. in addition to having an extra appearance (and its gr2 files)
  2. you’ll need to swap from one to the other with a SetCreatureAppearanceType(oModel, nAppearanceType); call, where oModel is the object you want to swap from and nAppearanceType the line number in Appearance.2da for the new appearance (which is not a new appearance, just the same with a different idle animation).
  3. this could lead to some stuttering or animation weirdness.

It’s like polymorphing the model :wink:

Okay, yes I was aware of that approach. I was just hoping there was a way to do it with one model. Thanks.

Something else that could work: launch a looping animation when required conditions are met (or upon entering the area):

// custom function to wrap PlayCustomAnimation()
void PlayCustomAnimationVoid(object oObject, string sAnimation, int iLoop, float fSpeed = 1.f)
{
	PlayCustomAnimation(oObject, sAnimation, iLoop, fSpeed);
}
// the farmer is spading his garden
object oJorai = GetNearestObjectByTag("c_jorai");
AssignCommand(oJorai, PlayCustomAnimationVoid(oJorai, "shoveling", TRUE));
// the smith is working on a sword
object oBob = GetNearestObjectByTag("c_bob");
AssignCommand(oBob, PlayCustomAnimationVoid(oBob, "forge01", TRUE));
// the woodcutter is sawing a large trunk
object oAlder = GetNearestObjectByTag("c_alder");
AssignCommand(oAlder, PlayCustomAnimationVoid(oAlder, "forge02", TRUE));

You don’t normally need to use a heartbeat script there, but if the PC interacts with the placeable/creature, even if the animation will keep on being played, the placeable/creature will probably rotate to face the PC (unless you use walkmesh cutter to make sure only one direction is possible).

I use these two generic campaign scripts for animating idle people.

Put on Heartbeat. Set the variables on the creature you want to animate, in the toolset, by script, whatever, you are done. The creature carries the variables.

// generic animation - recurrent

void main ()
{
	ClearAllActions();
	SetFacing(IntToFloat(GetLocalInt(OBJECT_SELF,"Bearing")));
	PlayCustomAnimation(OBJECT_SELF, GetLocalString(OBJECT_SELF, "Anim"), 1, 1.0);
}

On above Jorai set Bearing to the direction you want Jorai to face, for instance 180, set Anim to “shoveling”
On above Bob set Bearing to the direction you want him to face, for instance 90, set Anim to “forge01”

The second script adds a third variable Stop also carried by the creature.
Whenever Stop is set to 1, animation reverts to idle. Whenever Stop is set back to 0, the animation resumes.

// 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);
}

And yes you can talk to a bard playing guitar :grinning:

I know it can be done with a heartbeat script, but I was looking for another option since heartbeat scripts add overhead even when the player is not in the area.

What you might try is inserting some SendMessageToPC calls in your heartbeat scripts and see when they fire.

Well, I have extensivily used these heartbeat scripts in my mods without experiencing any additional overhead. Actually they do replace the default heartbeat script “nw_c2_default1” which likely is more resource demanding …

Obviously my two scripts are meant for civilians. Though you can use the “stop” version for a recruitable NPC.

Perhaps there are other options such as attaching that kind of script to an area at the price of scripting every involved creature as shown by 4760.