Can't get the party to face the right way

I have tried for a couple of hours to get the party in my single player module to face the right way when arriving in a new area. I have used functions provided by @kevL_s and @travus, and in other situations these script functions have worked really well. For some reason though, it doesn’t work for me here. I have checked the Script Assist together with the excellent EC_super_include script, that I think I got from kevL_s at some point, to find other functions to use to find other solutions to the problem, but nothing works.

When entering a conversation these functions in my script seems to work better for some reason, but in this particular situation, I don’t want a conversation, I just want them to face the right direction when arriving in the area.

This script I’ve put on the OnClientEnter. If anyone has a clue as what to do to get this working, I’m all ears (the “fstipspeak2” is a placeable iPoint):

#include "ginc_group"
#include "nw_i0_spells"
#include "x0_i0_petrify"
#include "ginc_cutscene"

#include "x2_am_inc"

void RemoveTheEffect(object oPC1)
{

	SendMessageToPC(oPC1,"RemoveEffect is running");
	object oFM = GetFirstFactionMember(oPC1, FALSE);
	while (GetIsObjectValid(oFM))
	{
		RemoveEffectOfType(oFM, EFFECT_TYPE_CUTSCENEIMMOBILIZE);
		oFM = GetNextFactionMember(oPC1, FALSE);
	}
	
	SetCutsceneMode(oPC1,FALSE);
	

}

void FaceParty(object oPC, string sFacee)
{
	vector v = GetPosition(GetObjectByTag(sFacee));
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	SendMessageToPC(oPC,"FaceParty is running");

	//object oFacee = GetObjectByTag("fstipspeak2");
	//vector vTarget = GetPosition(oFacee);
	
	
	while (GetIsObjectValid(oFM))
	{
		AssignCommand(oFM, ClearAllActions());
		DelayCommand(GetRandomDelay(), AssignCommand(oFM, SetFacingPoint(v, TRUE)));
		//AssignCommand(oFM, ActionDoCommand(SetFacingPoint(vTarget, TRUE)));
		//AssignCommand(oFM,SetFacing(DIRECTION_EAST));
		//AssignCommand(oFM,Face(oFM,oFacee));
		ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), oFM);
		oFM = GetNextFactionMember(oPC, FALSE);
	}
	
	

}

void PartyFacingDo(string sFacee, float fSpacing)
{
	object oPC = GetFirstPC();
	
	SendMessageToPC(oPC,"PartyFacingDo is running");
	
	if (fSpacing < 0.8) fSpacing = 0.8f;
	
	//vector v = GetPosition(GetObjectByTag(sFacee));

	ResetGroup(PARTY_GROUP_NAME);
	GroupAddFaction(PARTY_GROUP_NAME, oPC, GROUP_LEADER_FIRST, TRUE);	
	GroupSetBMAFormation(PARTY_GROUP_NAME, fSpacing);
	GroupSetNoise(PARTY_GROUP_NAME);	
	GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oPC), MOVE_JUMP_INSTANT);
	//GroupSetFacingPoint(PARTY_GROUP_NAME,v);
	DelayCommand(0.1f, FaceParty(oPC, sFacee));
}

void fadetoblack(float fSpeed, float fFailsafe, int nColor)
{

	object oPCh = GetEnteringObject();

	if (IsFloatNearInt(fFailsafe, 0))
		fFailsafe = 15.0f;

	FadeToBlackParty(oPCh, 1, fSpeed, fFailsafe, nColor);

}

void main()
{

object oPC = GetEnteringObject();
object oPC1 = GetFirstPC();

	fadetoblack(3.2,3.2,0);

if(GetLocalInt(OBJECT_SELF,"done")) return;

SetLocalInt(OBJECT_SELF,"Done",TRUE);

//AssignCommand(oPC1, ClearAllActions());

SetCutsceneMode(oPC1);

DelayCommand(0.5,FaceParty(oPC1,"fstipspeak2"));
DelayCommand(0.8,PartyFacingDo("fstipspeak2",1.0));
DelayCommand(1.1,RemoveTheEffect(oPC1));		


}

I noticed that in FaceParty(), SetFacingPoint() is delayed, but EffectCutsceneImmobilize() is immediate (remember, the order the instructions are written in the script is not a guarantee they will be executed in the same order).
Don’t forget that:

// It is suggested that functions which create effects should not be used
// as parameters to delayed actions.  Instead, the effect should be created in the
// script and then passed into the action.

.

2 Likes

@4760 - Thanks for the reply. I’ll see what happens if I perhaps delay the EffectCutsceneImmobilize() instead.

I changed the script to this, but it behaves like before. No change:

#include "ginc_group"
#include "nw_i0_spells"
#include "x0_i0_petrify"
#include "ginc_cutscene"

#include "x2_am_inc"

void RemoveTheEffect(object oPC1)
{

	SendMessageToPC(oPC1,"RemoveEffect is running");
	object oFM = GetFirstFactionMember(oPC1, FALSE);
	while (GetIsObjectValid(oFM))
	{
		RemoveEffectOfType(oFM, EFFECT_TYPE_CUTSCENEIMMOBILIZE);
		oFM = GetNextFactionMember(oPC1, FALSE);
	}
	
	SetCutsceneMode(oPC1,FALSE);
	

}

void FaceParty(object oPC, string sFacee)
{
	vector v = GetPosition(GetObjectByTag(sFacee));
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	SendMessageToPC(oPC,"FaceParty is running");

	//object oFacee = GetObjectByTag("fstipspeak2");
	//vector vTarget = GetPosition(oFacee);
	
	
	while (GetIsObjectValid(oFM))
	{
		AssignCommand(oFM, ClearAllActions());
		//DelayCommand(GetRandomDelay(), AssignCommand(oFM, SetFacingPoint(v, TRUE)));
		DelayCommand(0.2,AssignCommand(oFM, SetFacingPoint(v, TRUE)));
		//AssignCommand(oFM, ActionDoCommand(SetFacingPoint(vTarget, TRUE)));
		//AssignCommand(oFM,SetFacing(DIRECTION_EAST));
		//AssignCommand(oFM,Face(oFM,oFacee));
		DelayCommand(0.7,ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), oFM));
		oFM = GetNextFactionMember(oPC, FALSE);
	}
	
	

}

void PartyFacingDo(string sFacee, float fSpacing)
{
	object oPC = GetFirstPC();
	
	SendMessageToPC(oPC,"PartyFacingDo is running");
	
	if (fSpacing < 0.8) fSpacing = 0.8f;
	
	//vector v = GetPosition(GetObjectByTag(sFacee));

	ResetGroup(PARTY_GROUP_NAME);
	GroupAddFaction(PARTY_GROUP_NAME, oPC, GROUP_LEADER_FIRST, TRUE);	
	GroupSetBMAFormation(PARTY_GROUP_NAME, fSpacing);
	GroupSetNoise(PARTY_GROUP_NAME);	
	GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oPC), MOVE_JUMP_INSTANT);
	//GroupSetFacingPoint(PARTY_GROUP_NAME,v);
	DelayCommand(0.1f, FaceParty(oPC, sFacee));
}

void fadetoblack(float fSpeed, float fFailsafe, int nColor)
{

	object oPCh = GetEnteringObject();

	if (IsFloatNearInt(fFailsafe, 0))
		fFailsafe = 15.0f;

	FadeToBlackParty(oPCh, 1, fSpeed, fFailsafe, nColor);

}

void main()
{

object oPC = GetEnteringObject();
object oPC1 = GetFirstPC();

	fadetoblack(3.2,3.2,0);

if(GetLocalInt(OBJECT_SELF,"done")) return;

SetLocalInt(OBJECT_SELF,"Done",TRUE);

AssignCommand(oPC1, ClearAllActions());

SetCutsceneMode(oPC1);

DelayCommand(0.5,FaceParty(oPC1,"fstipspeak2"));
DelayCommand(0.8,PartyFacingDo("fstipspeak2",1.0));
DelayCommand(1.1,RemoveTheEffect(oPC1));		


}

EDIT: Made another small change (see script above), but still it behaves the same way.

I found an older thread where @Lance_Botelle discussed this: SetFacing (Finally). I tried his solution and even @Tsongo’s solution, but both still failed for me (you can see by what I have commented out, what I have tried in this script):

#include "ginc_group"
#include "nw_i0_spells"
#include "x0_i0_petrify"
#include "ginc_cutscene"

#include "x2_am_inc"

void RemoveTheEffect(object oPC1)
{

	SendMessageToPC(oPC1,"RemoveEffect is running");
	object oFM = GetFirstFactionMember(oPC1, FALSE);
	while (GetIsObjectValid(oFM))
	{
		RemoveEffectOfType(oFM, EFFECT_TYPE_CUTSCENEIMMOBILIZE);
		oFM = GetNextFactionMember(oPC1, FALSE);
	}
	
	SetCutsceneMode(oPC1,FALSE);
	

}

void FaceParty(object oPC, string sFacee)
{
	vector v = GetPosition(GetObjectByTag(sFacee));
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	SendMessageToPC(oPC,"FaceParty is running");

	//object oFacee = GetObjectByTag("fstipspeak2");
	//vector vTarget = GetPosition(oFacee);
	
	
	while (GetIsObjectValid(oFM))
	{
	
		SendMessageToPC(oPC,"FaceParty companion");
		AssignCommand(oFM, ClearAllActions());
		//DelayCommand(GetRandomDelay(), AssignCommand(oFM, SetFacingPoint(v, TRUE)));
		//DelayCommand(0.2,AssignCommand(oFM, SetFacingPoint(v, TRUE)));
		
		//DelayCommand(0.0, AssignCommand(oFM, SetFacingPoint(GetPosition(oFM))));	
		//DelayCommand(0.25, AssignCommand(oFM, SetFacingPoint(v, 1)));
		
		AssignCommand(oFM,ActionOrientToTag("fstipspeak2",ORIENT_FACE_TARGET));	
		
		//AssignCommand(oFM, ActionDoCommand(SetFacingPoint(vTarget, TRUE)));
		//AssignCommand(oFM,SetFacing(DIRECTION_EAST));
		//AssignCommand(oFM,Face(oFM,oFacee));
		//DelayCommand(0.5,ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), oFM));
		oFM = GetNextFactionMember(oPC, FALSE);
	}
	
	

}

void PartyFacingDo(string sFacee, float fSpacing)
{
	object oPC = GetFirstPC();
	
	SendMessageToPC(oPC,"PartyFacingDo is running");
	
	if (fSpacing < 0.8) fSpacing = 0.8f;
	
	//vector v = GetPosition(GetObjectByTag(sFacee));

	ResetGroup(PARTY_GROUP_NAME);
	GroupAddFaction(PARTY_GROUP_NAME, oPC, GROUP_LEADER_FIRST, TRUE);	
	GroupSetBMAFormation(PARTY_GROUP_NAME, fSpacing);
	GroupSetNoise(PARTY_GROUP_NAME);	
	GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oPC), MOVE_JUMP_INSTANT);
	//GroupSetFacingPoint(PARTY_GROUP_NAME,v);
	DelayCommand(0.1f, FaceParty(oPC, sFacee));
}

void fadetoblack(float fSpeed, float fFailsafe, int nColor)
{

	object oPCh = GetEnteringObject();

	if (IsFloatNearInt(fFailsafe, 0))
		fFailsafe = 15.0f;

	FadeToBlackParty(oPCh, 1, fSpeed, fFailsafe, nColor);

}

void main()
{

object oPC = GetEnteringObject();
object oPC1 = GetFirstPC();

	fadetoblack(3.2,3.2,0);

if(GetLocalInt(OBJECT_SELF,"done")) return;

SetLocalInt(OBJECT_SELF,"Done",TRUE);

AssignCommand(oPC1, ClearAllActions());

SetCutsceneMode(oPC1);

DelayCommand(0.5,FaceParty(oPC1,"fstipspeak2"));
DelayCommand(0.7,PartyFacingDo("fstipspeak2",1.0));
DelayCommand(1.0,RemoveTheEffect(oPC1));		


}

Upon testing and testing and testing, I have noticed that on rare occasions one or two of the companions actually turn the right way, but that’s like in 10 % of the cases, so I don’t know how to force the bloody game to do the right thing. As always, NWN2 works in mysterious ways.

By all the SendMessageToPC I can see that the game runs all the script functions the way it is supposed to, but even still, the companions do not turn the way they are supposed to. It looks so ugly when they are sitting on their horses and it looks like this:

start simple ;)

// 'ag_oce_area'
/*
*/

#include "ginc_group"

void MusterParty();

// MAIN //
void main()
{
	SendMessageToPC(GetFirstPC(FALSE), "Client Enter area= " + GetTag(OBJECT_SELF));

	if (!GetLocalInt(OBJECT_SELF, "Done"))
	{
		SetLocalInt(OBJECT_SELF, "Done", TRUE);

		SetCutsceneMode(GetFirstPC());

		FadeToBlack(GetEnteringObject(), FADE_SPEED_SLOWEST);

		DelayCommand(0.5f, MusterParty());
	}
}

//
void MusterParty()
{
	SendMessageToPC(GetFirstPC(FALSE), "MusterParty()");

	ResetGroup(PARTY_GROUP_NAME);

	GroupSetBMAFormation(PARTY_GROUP_NAME, 1.f);
	GroupSetNoise(PARTY_GROUP_NAME);

	object oFirstPc = GetFirstPC();
	GroupAddFaction(PARTY_GROUP_NAME, oFirstPc, GROUP_LEADER_FIRST, TRUE);
	GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oFirstPc), MOVE_JUMP_INSTANT);

	object oFaced = GetObjectByTag("fstipspeak2");
	if (GetIsObjectValid(oFaced))
	{
		GroupSetFacingPoint(PARTY_GROUP_NAME, GetPosition(oFaced));
	}
	else SendMessageToPC(GetFirstPC(FALSE), ". ERROR : object to Face is invalid");
}

Maybe try like this:

// Create the effect to apply
effect eImmobilize = EffectCutsceneImmobilize();
while (GetIsObjectValid(oFM))
{
// [keep your code here, except for the line where you apply the effect, replacing it as below]
DelayCommand(0.7,ApplyEffectToObject(DURATION_TYPE_PERMANENT, eImmobilize, oFM));
// [rest of your script]
}

there are a number of quirks and anomalies in the script and i think it should be done from scratch …

“done” is not “Done”

fade to black party is unnecessary (i think) because each client (aka player) that enters should run its own fade to black – no need to do party-fade each time a player enters the area

FaceParty() is done in main, then done again in PartyFacingDo()

don’t do cutscene immobilize unless you really need to – applying it for only 0.5 seconds seems a bit overkill …

 
but, wha’ver

getting a party in formation and facing shouldn’t take 100 lines of code,

You could land them in a speak trigger with some random animal owning the conversation and then it just runs off, it’s only line of conversation being a noise and then it’s gone. Use that line to get everybody to look at it. Or you could just write a quick cutscene conversation about what just happened to the party.

You could also try it without the horses maybe they’ve caused confusion. It might be that the game can’t work out the spacing.

Just one question, why is there a chair in the forest ? Did that scare the horses ?

2 Likes

@kevL_s - Tried your

code. No difference at all.

That is my debug-test chair. It’s just a placeable. Could have been anything. I have that with a debug conversation where I set different stuff to test.

@4760 - I’ll try what you suggested.

2 Likes

@4760 - I remade my script like this. Not sure if that’s what you meant. Either way, it made no difference.

#include "nw_i0_spells"
#include "x0_i0_petrify"
#include "ginc_cutscene"

#include "x2_am_inc"

void RemoveTheEffect(object oPC1)
{

	SendMessageToPC(oPC1,"RemoveEffect is running");
	object oFM = GetFirstFactionMember(oPC1, FALSE);
	while (GetIsObjectValid(oFM))
	{
		RemoveEffectOfType(oFM, EFFECT_TYPE_CUTSCENEIMMOBILIZE);
		oFM = GetNextFactionMember(oPC1, FALSE);
	}
	
	SetCutsceneMode(oPC1,FALSE);
	

}

void FaceParty(object oPC, string sFacee)
{
	vector v = GetPosition(GetObjectByTag(sFacee));
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	SendMessageToPC(oPC,"FaceParty is running");

	//object oFacee = GetObjectByTag("fstipspeak2");
	//vector vTarget = GetPosition(oFacee);
	
	effect eImmobilize = EffectCutsceneImmobilize();
	
	while (GetIsObjectValid(oFM))
	{
	
		SendMessageToPC(oPC,"FaceParty companion");
		AssignCommand(oFM, ClearAllActions());
		//DelayCommand(GetRandomDelay(), AssignCommand(oFM, SetFacingPoint(v, TRUE)));
		DelayCommand(0.2,AssignCommand(oFM, SetFacingPoint(v, TRUE)));
		
		//DelayCommand(0.0, AssignCommand(oFM, SetFacingPoint(GetPosition(oFM))));	
		//DelayCommand(0.25, AssignCommand(oFM, SetFacingPoint(v, 1)));
		
		//DelayCommand(0.2,AssignCommand(oFM,ActionOrientToTag("fstipspeak2",ORIENT_FACE_TARGET)));	
		
		//AssignCommand(oFM, ActionDoCommand(SetFacingPoint(vTarget, TRUE)));
		//AssignCommand(oFM,SetFacing(DIRECTION_EAST));
		//AssignCommand(oFM,Face(oFM,oFacee));
		DelayCommand(0.7,ApplyEffectToObject(DURATION_TYPE_PERMANENT, eImmobilize, oFM));
		//DelayCommand(0.5,ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), oFM));
		oFM = GetNextFactionMember(oPC, FALSE);
	}
	
	

}

void PartyFacingDo(string sFacee, float fSpacing)
{
	object oPC = GetFirstPC();
	
	SendMessageToPC(oPC,"PartyFacingDo is running");
	
	if (fSpacing < 0.8) fSpacing = 0.8f;
	
	//vector v = GetPosition(GetObjectByTag(sFacee));

	ResetGroup(PARTY_GROUP_NAME);
	GroupAddFaction(PARTY_GROUP_NAME, oPC, GROUP_LEADER_FIRST, TRUE);	
	GroupSetBMAFormation(PARTY_GROUP_NAME, fSpacing);
	GroupSetNoise(PARTY_GROUP_NAME);	
	GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oPC), MOVE_JUMP_INSTANT);
	//GroupSetFacingPoint(PARTY_GROUP_NAME,v);
	DelayCommand(0.1f, FaceParty(oPC, sFacee));
}

void fadetoblack(float fSpeed, float fFailsafe, int nColor)
{

	object oPCh = GetEnteringObject();

	if (IsFloatNearInt(fFailsafe, 0))
		fFailsafe = 15.0f;

	FadeToBlackParty(oPCh, 1, fSpeed, fFailsafe, nColor);

}

void main()
{

object oPC = GetEnteringObject();
object oPC1 = GetFirstPC();

	fadetoblack(3.2,3.2,0);

if(GetLocalInt(OBJECT_SELF,"done")) return;

SetLocalInt(OBJECT_SELF,"done",TRUE);

AssignCommand(oPC1, ClearAllActions());

SetCutsceneMode(oPC1);

DelayCommand(0.5,FaceParty(oPC1,"fstipspeak2"));
DelayCommand(0.7,PartyFacingDo("fstipspeak2",1.0));
DelayCommand(1.0,RemoveTheEffect(oPC1));		


}

I have tried without the immobilize thing too, but there was no difference.

Ok. I might change that to FadeToBlack instead. This is just code I’ve used before. I very much like to use code that I’ve witnessed has worked before. If I change too much then that might be why it doesn’t work. So that’s why that fadetoblack function is in there.

1 Like

I agree. Right now, I have everything in there that I have tried, but nothing works. Once I find something that works, I can redo the script, but as of now, I am clueless how to get it to work.

I know. I’ve noticed that too. For some reason I had it like that in another script. I have tried several times with and without it. No difference.

Yep. Simple mistake. Corrected.

I really thought all this would work when I tried Lance’s code from the other thread, but that made no difference either for some strange reason. I really don’t want to go into a dialogue as soon as I enter this area, because there will be a conversation very shortly after entering anyway.

I find this game very strange in how it handles stuff sometimes. Something simple like this should be a non-issue, I think, but for some reason it is an issue.

EDIT: Did another test, combining @kevL_s code with Lance’s code, but still it won’t work:

#include "ginc_group"

void MusterParty();

// MAIN //
void main()
{
	SendMessageToPC(GetFirstPC(FALSE), "Client Enter area= " + GetTag(OBJECT_SELF));

	if (!GetLocalInt(OBJECT_SELF, "Done"))
	{
		SetLocalInt(OBJECT_SELF, "Done", TRUE);

		SetCutsceneMode(GetFirstPC());

		FadeToBlack(GetEnteringObject(), FADE_SPEED_SLOWEST);

		DelayCommand(0.5f, MusterParty());
	}
}

//
void MusterParty()
{
	SendMessageToPC(GetFirstPC(FALSE), "MusterParty()");

	ResetGroup(PARTY_GROUP_NAME);

	GroupSetBMAFormation(PARTY_GROUP_NAME, 1.f);
	GroupSetNoise(PARTY_GROUP_NAME);

	object oFirstPc = GetFirstPC();
	GroupAddFaction(PARTY_GROUP_NAME, oFirstPc, GROUP_LEADER_FIRST, TRUE);
	GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oFirstPc), MOVE_JUMP_INSTANT);
	/*
	object oFaced = GetObjectByTag("fstipspeak2");
	if (GetIsObjectValid(oFaced))
	{
		GroupSetFacingPoint(PARTY_GROUP_NAME, GetPosition(oFaced));
	}
	else SendMessageToPC(GetFirstPC(FALSE), ". ERROR : object to Face is invalid");
	*/
	object oFM = GetFirstFactionMember(oFirstPc, FALSE);
	vector v = GetPosition(GetObjectByTag("fstipspeak2"));
	
	while (GetIsObjectValid(oFM))
	{
		DelayCommand(0.0, AssignCommand(oFM, SetFacingPoint(GetPosition(oFM))));	
		DelayCommand(0.25, AssignCommand(oFM, SetFacingPoint(v, 1)));
		oFM = GetNextFactionMember(oFirstPc, FALSE);
	}
	
}

EDIT2: Tried with this script, which is nearly identical to the one I use on the first node on conversations. When on those nodes this script works perfectly, but here on the OnClientEnter of the area it doesn’t work. I get the message that it runs but the companions won’t face the right way:

#include "ginc_group"
#include "nw_i0_spells"

void FaceParty(object oPC, string sFacee)
{
	vector v = GetPosition(GetObjectByTag(sFacee));
	object oFM = GetFirstFactionMember(oPC, FALSE);

	while (GetIsObjectValid(oFM))
	{
		AssignCommand(oFM, ClearAllActions());
		DelayCommand(GetRandomDelay(), AssignCommand(oFM, SetFacingPoint(v, TRUE)));
		//ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), oFM);
		oFM = GetNextFactionMember(oPC, FALSE);
	}	
}

void main()
{
	object oPC = GetFirstPC();
	
	SendMessageToPC(oPC,"The new script is running...away");
	
	float fSpacing = 0.8f;
	
	ResetGroup(PARTY_GROUP_NAME);
	GroupAddFaction(PARTY_GROUP_NAME, oPC, GROUP_LEADER_FIRST, TRUE);	
	GroupSetBMAFormation(PARTY_GROUP_NAME, fSpacing);
	GroupSetNoise(PARTY_GROUP_NAME);	
	GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oPC), MOVE_JUMP_INSTANT);
	DelayCommand(0.1f, FaceParty(oPC, "fstipspeak2"));
}
1 Like

Try SetFacing() instead of SetFacingPoint() - a bit harder to set up but i think i got the former to work on occasions when the latter didnt …

i think there’s an #include that calculates the facing to use, given an object to face …

 
bleh, looks like i had to write one →

// kL ->
// Gets the direction (0.f .. 360.f in degrees) for oSource to face oTarget.
// - returns 999.f if source and target are at the same position
// - note before call Ensure that
//   (GetIsObjectValid(oSource) && GetIsObjectValid(oTarget)
//    && GetArea(oSource) == GetArea(oTarget))
// - a check should also be done for (oSource != oTarget) but if they are the
//   return is 999.f
float GetDirectionToTarget(object oTarget, object oSource = OBJECT_SELF)
{
	vector pSource = GetPosition(oSource);
	vector pTarget = GetPosition(oTarget);

	float dx = pTarget.x - pSource.x;
	float dy = pTarget.y - pSource.y;

	float dx_abs = fabs(dx);
	float dy_abs = fabs(dy);

	if (dx_abs > epsilon || dy_abs > epsilon)
	{
		if (dx_abs <= epsilon) // guard vs divbyzero
		{
			if (dy < 0.f) return 270.f;
						  return  90.f;
		}

		if (dy_abs <= epsilon)
		{
			if (dx < 0.f) return 180.f;
						  return   0.f;
		}

		float dir = atan(dy_abs/dx_abs); // yep they return atan in degrees ...

		if (dx < 0.f)
		{
			if (dy > 0.f) return 180.f - dir;	// top left quadrant
						  return 180.f + dir;	// bot left quadrant
		}

		if (dy < 0.f) return 360.f - dir;		// bot right quadrant
					  return         dir;		// top right quadrant
	}
	return 999.f;
}

 
edit → i use this for epsilon
const float epsilon = 0.00005f;

So do I use this function together with SetFacing() you mean?

yep

I tried it like this. Still no difference:

const float epsilon = 0.00005f;

// kL ->
// Gets the direction (0.f .. 360.f in degrees) for oSource to face oTarget.
// - returns 999.f if source and target are at the same position
// - note before call Ensure that
//   (GetIsObjectValid(oSource) && GetIsObjectValid(oTarget)
//    && GetArea(oSource) == GetArea(oTarget))
// - a check should also be done for (oSource != oTarget) but if they are the
//   return is 999.f
float GetDirectionToTarget(object oTarget, object oSource = OBJECT_SELF)
{
	vector pSource = GetPosition(oSource);
	vector pTarget = GetPosition(oTarget);

	float dx = pTarget.x - pSource.x;
	float dy = pTarget.y - pSource.y;

	float dx_abs = fabs(dx);
	float dy_abs = fabs(dy);

	if (dx_abs > epsilon || dy_abs > epsilon)
	{
		if (dx_abs <= epsilon) // guard vs divbyzero
		{
			if (dy < 0.f) return 270.f;
						  return  90.f;
		}

		if (dy_abs <= epsilon)
		{
			if (dx < 0.f) return 180.f;
						  return   0.f;
		}

		float dir = atan(dy_abs/dx_abs); // yep they return atan in degrees ...

		if (dx < 0.f)
		{
			if (dy > 0.f) return 180.f - dir;	// top left quadrant
						  return 180.f + dir;	// bot left quadrant
		}

		if (dy < 0.f) return 360.f - dir;		// bot right quadrant
					  return         dir;		// top right quadrant
	}
	return 999.f;
}



#include "ginc_group"

void MusterParty();

// MAIN //
void main()
{
	SendMessageToPC(GetFirstPC(FALSE), "Client Enter area= " + GetTag(OBJECT_SELF));

	if (!GetLocalInt(OBJECT_SELF, "Done"))
	{
		SetLocalInt(OBJECT_SELF, "Done", TRUE);

		SetCutsceneMode(GetFirstPC());

		FadeToBlack(GetEnteringObject(), FADE_SPEED_SLOWEST);

		DelayCommand(0.5f, MusterParty());
	}
}

//
void MusterParty()
{
	SendMessageToPC(GetFirstPC(FALSE), "MusterParty()");

	ResetGroup(PARTY_GROUP_NAME);

	GroupSetBMAFormation(PARTY_GROUP_NAME, 1.f);
	GroupSetNoise(PARTY_GROUP_NAME);

	object oFirstPc = GetFirstPC();
	GroupAddFaction(PARTY_GROUP_NAME, oFirstPc, GROUP_LEADER_FIRST, TRUE);
	GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oFirstPc), MOVE_JUMP_INSTANT);
	/*
	object oFaced = GetObjectByTag("fstipspeak2");
	if (GetIsObjectValid(oFaced))
	{
		GroupSetFacingPoint(PARTY_GROUP_NAME, GetPosition(oFaced));
	}
	else SendMessageToPC(GetFirstPC(FALSE), ". ERROR : object to Face is invalid");
	*/
	object oFM = GetFirstFactionMember(oFirstPc, FALSE);
	object oFacee = GetObjectByTag("fstipspeak2");
	
	while (GetIsObjectValid(oFM))
	{
			
		DelayCommand(0.25, AssignCommand(oFM, SetFacing(GetDirectionToTarget(oFacee), 1)));
		oFM = GetNextFactionMember(oFirstPc, FALSE);
	}
	
}
DelayCommand(0.25, AssignCommand(oFM, SetFacing(GetDirectionToTarget(oFacee), 1)));

DelayCommand(0.25, AssignCommand(oFM, SetFacing(GetDirectionToTarget(oFacee, oFM), 1)));

pass in oFM as oSource

1 Like

It looks like your entry waypoint might be too close to the edge of the map. Make sure it is far enough away from the edge so the party members can be set into BMA formation behind the main PC. If there is not enough room for them, then they will be bumped forward which would cause them to be out of position. If they are bumped too far away from the main PC, they will try to walk closer to him once the RemoveEffectOfType(oFM, EFFECT_TYPE_CUTSCENEIMMOBILIZE); is fired.

2 Likes

@travus - I tried moving the waypoint a little bit. Still didn’t seem to solve the issue though.

Did that. No change.

@travus - Maybe I should try with making them non-bumpable when entering? Would that change anything?

EDIT: Tried that. Didn’t do anything.

I tested your script (the initial one on the first post) with a large party from the OnCliententer and it works fine. I don’t know enough about the horse mod you are using…but just to rule something out, comment out this line:
DelayCommand(1.1,RemoveTheEffect(oPC1));
… to see if they hold their facing.

2 Likes