Can't get SetFacing or SetFacingPoint to work

Hi all. Having trouble with a script that is supposed to allow the party to choose someone to participate in a duel while the rest of the party stand back and watch. Everything works fine (thank you andgalf and KevL for your discussion on this a while ago), except I can not get the non-participants to face the duelist. I’ve tried SetFacing using the direction to the duelist and SetFacingPoint using the position of the duelist.

The script is fired from a conversation set on a third party (a tree stump in this case) so neither the duelist or the other party member is OBJECT_SELF, so I think my problem is the right syntax for getting SetFacing to work from someone not the script owner (I’ve had no problem using it in other scripts where it setfaces the script owner). I’ve tried AssignCommand(SetFacingPoint(oFacer, GetPosition(oDuelist))) and AssignCommand(ActionDoCommand(…)).

I also have a wait command in there after the setfacing that seems not to fire either because there is no delay between (not) facing and the next command which they do execute (a SpeakString).

Not sure how to load the whole script up here other than cut&paste but happy to do that.

Thanks!
Chuck

Look at this pinned thread.

TR

Thanks TR. Let’s give that a try:
I just put the whole thing, even though there’s a alot not relevant to my question, but I figure if I edit something out, that’ll be the exact bit that is causing the problem.

#include "x0_i0_assoc"
#include "ginc_vectors"

float FaceOther(object oFacer, object oToBeFaced)
{
	vector VectA = GetPosition(oFacer);
	vector VectB = GetPosition(oToBeFaced);
	
	vector VectFacing = AtoB(VectA,VectB);
	float fDirect = VectorToAngle(VectFacing);
	return fDirect;
}

void main()
{
	object oDuelist = GetFirstPC(FALSE);//gets whoever is talking in an SoZ convo
	string sDuelist = GetTag(oDuelist);
	
	if (sDuelist=="")//PC's have no tag so need to assign a defacto one
	{
		sDuelist="mainPC";
	}	
	SpeakString("The duelist is "+ GetFirstName(oDuelist));
	
	object oPC = GetFirstPC();
	object oFaction = GetFirstFactionMember(oPC);
	int i = 1;
	while (GetIsObjectValid(oFaction))
	{
		string sFaction = GetTag(oFaction);	
	
		if (sFaction=="")//PC's have no tag so need to assign a defacto one
		{
			sFaction="mainPC";
		}
		if (sDuelist != sFaction)
		{
			SpeakString("current faction member is " + sFaction);
			AssignCommand(oFaction, ClearAllActions());
			
			SetAssociateState(NW_ASC_MODE_STAND_GROUND,TRUE,oFaction);
			float fDirect = FaceOther(oFaction, oDuelist);
			SpeakString("Direction is " + FloatToString(fDirect));
			vector vDuelist = GetPosition(oDuelist);
			AssignCommand(oFaction, ActionDoCommand(SetFacingPoint(vDuelist, FALSE)));
			AssignCommand(oFaction, ActionWait(4.0f));
			
			switch(i)
			{
			case 1:
				AssignCommand(oFaction,SpeakString("Good luck, " + GetFirstName(oDuelist)));
				break;
			case 2:
				AssignCommand(oFaction,SpeakString("You can do it, " + GetFirstName(oDuelist)));
				break;
			case 3:	
				AssignCommand(oFaction,SpeakString("Kick his butt!"));
				break;
			case 4:
				AssignCommand(oFaction,SpeakString("You got him, " + GetFirstName(oDuelist)));
				break;
			}
			i++;
			SetCommandable(FALSE, oFaction);
			SpeakString(sFaction + " is not commandable");
		}
		oFaction = GetNextFactionMember(oPC, FALSE);
    }
}

And like I said, everything works as designed except the two AssignCommand statements (that’s 4.0sec on the wait just to make sure I can see it when testing, which I can’t). All the speakstrings are just for debugging and they all spit out what they should, including the Direction one.

Lance Botelle and KevL_s are better experts than me on this subject (or any subject when it comes to NWN2 for that matter), however, all I can say is that this whole thing with getting NPCs and companions and the PC to face the right way, are somtimes very f?*¨´k up when it comes to NWN2. It works for the most part, but I have had SOO many issues with this, you cannot imagine. I usually just use the stock script ga_face_target, and most of the times it works ok, but I’ve had a conversation when I’ve called upon this multiple times and still the companion won’t face the right way, in my case an NPC, but when the PC talks, all of a sudden the companion faces the right way, when not asked to do so (it’s hardcoded, I believe). So it seems that the game is very paritcular when it comes to this. Both KevL_s and Lance have provided me with scripts for this, that should have worked, but somehow in some cases just didn’t.

And I believe you have to use quite particular delays with this for this to work.

the problem might be that when you call SetCommandable(FALSE) without wrapping it in ActionDoCommand()

the creature becomes uncommandable before its actions happen … so your script might be trying to assign actions to an uncommandable creature.

get it ?

 
also, don’t forget that the engine is hardcoded to change creatures’ facing during dialog. I think that was the major issue that andgalf and i were struggling with,

So you might also want SetFacingPoint(bLockToThisOrientation=TRUE) … depends what you want

 
the Speaker and Listener slots in the dialog may also be helpful. not sure ,

 
ps. you might find this interesting (heck it might even work)

#include "x0_i0_assoc"
#include "nw_i0_spells"

object oFirstPc;
int i = -1;

// OBJECT_SELF is oFaction
void standground(object oFaction, vector vPosToFace)
{
    SpeakString("current faction member is " + GetName(oFaction));

    SetAssociateState(NW_ASC_MODE_STAND_GROUND, TRUE, oFaction);

    ClearAllActions();
    SetFacingPoint(vPosToFace, FALSE); // TRUE depends - the engine will try to force facing on each node
    ActionWait(0.5f);

    switch (++i)
    {
        case 0:
            ActionSpeakString("Good luck, " + GetFirstName(oFirstPc));
            break;

        case 1:
            ActionSpeakString("You can do it, " + GetFirstName(oFirstPc));
            break;

        default:
        case 2:
            ActionSpeakString("Kick his butt!");
            break;

        case 3:
            ActionSpeakString("You got him, " + GetFirstName(oFirstPc));
            break;
    }

    ActionDoCommand(SetCommandable(FALSE, oFaction));
}


// OBJECT_SELF is ... treestump placeable
void main()
{
    oFirstPc = GetFirstPC(FALSE);
    SpeakString("The duelist is "+ GetFirstName(oFirstPc));

    vector vPosToFace = GetPosition(oFirstPc);

    object oFaction = GetFirstFactionMember(oFirstPc, FALSE);
    while (GetIsObjectValid(oFaction))
    {
        if (oFaction != oFirstPc)
            DelayCommand(GetRandomDelay(), AssignCommand(oFaction, standground(oFaction, vPosToFace)));

        oFaction = GetNextFactionMember(oFirstPc, FALSE);
    }
}

Don’t forget that there is an OnDialogue type function that can be used to prevent any face changing when in a dialogue. I forget the exact function name (not at main computer), but it is something like OrientOnDialogue, which I think (iirc) can be used to stop auto facing. As KevL says, timing plays a big part with these kind of actions.

EDIT: Although, perhaps I am thinking of the parameter that KevL mentions above? Although I thought there was a separate function. Hmm.

That did it KevL! Thanks! I needed an assign command too (ActionDo alone didn’t fix it):
AssignCommand(oFaction, ActionDoCommand(SetCommandable(FALSE, oFaction)));
They turned right to the correct companion. I was wondering if it was something like that, which is why I had the setcommandable at the end, but I didn’t realize that the script runs things through while stacking any assigncommands for timed execution.

Thank you all so much. This drove me insane for two days!

I like your suggested function. Since I now have it working I won’t mess with it but thanks for pointing out something I wasn’t sure of which is that the OBJECT_SELF of a subroutine can be assigned with AssignCommand, and thus be different than for the main script.

I had seen the parameters for the in-convo blocking parameter in SetFacing, but this script gets fired on the final convo node so the convo is basically over.

1 Like

npc OnSpawn script:

    if (GetLocalInt(oSelf, "NX2_NO_ORIENT_ON_DIALOG"))
        SetOrientOnDialog(oSelf, FALSE);
1 Like

@kevL_s

That’s it!

Thanks for the reminder.

1 Like

Ok new problem with this. Now during the duel, the opponent will spot the noncommandable party member and attack (especially but not only if the party challenger goes into stealth). That seems to cancel the notcommandable – the party member defends them self, starts casting buffs and can be otherwise controlled. Does being attached cancel a SetCommandable? Any suggestions on preventing that. I’ve got some scripts in the opponent’s OnEndCombatRound that checks the current target and cancels all actions if it’s not the challenger, but it seems just having the other party member as a target cancels the SetCommandable. I suppose I could make the other party member Hidden, but if there’s a way to avoid that I’d prefer it. They are supposed to be spectating.

In my module I also have a duel. I discussed several things regarding this in this thread. Maybe you can find something there to help you:

Well, if I’ve understodd you right, I think you need to, as I did in my module, to let the companion that is not to be attacked, leave the party temporarily and change him/her to a custom faction and have a faction pig with that same custom faction somewhere in the area.

Thanks Andgalf. I’ve seen that thread. Can you also change the main PC to a custom faction? The tricky part of this duel is that any party member can do it.

Unfortunately not. The PC will always belong to the player faction (or whatever it is called), so you can only do this with companions that leave the party roster.
You always have the PC in your party no matter what (which is unfortunate).

1 Like

reminder that in the OC there is the Trial By Combat …

iirc it keeps the party together and player can choose a Champion to fight …

the rest of the party stands in the stands. I think it works because the party is kept outside of Lorne’s agro range …

 
or perhaps because he can’t see and/or path to the other party members

try setting the opponent’s perception range to short

1 Like

Thanks guys. KevL’s suggestion from the OC trial is good. I don’t have space in the area to move them up and out of reach, but maybe I can put a transparent wall between them. I could create it at the same time teh party gets sets to non-commandable and destroy when the duel is done. I see Tschos did some work on this previously. What I don’t know is if I make a placeable transparent using it’s alpha channel if in-game the NPCs can see through it.

And I still find it weird that SetCommandable gets canceled as soon as that party member is targeted ( a trigger keeps the duel opponent from leaving the arena, so it doesn’t actually attack). Otherwise my duel works great. And maybe the player will be so busy in the duel they won’t notice the other party members are commandable again.

Regarding a transparent wall:

You can use a Collision Box that you copy and give a new tag, and then change its size, and to that end creating an invisible wall. However, according to Lance_Botelle this doesn’t block the line of sight, so he suggested this in another thread:

“NB: By default, this does not block line of sight. However, I have set up a new line in the placeables.2da with a copy of this with BlockLoS as true. I believe that should work, although I have never tried/used it in this way.”

1 Like

Hi. So I tried the placeable wall, made transparent using visual effect (Tschos’s second method) and Blocks Line of Sight set to true. Didn’t work. The opponent will still target the non participating party member and run around the wall to get to them. I’ll try Tchos’s first method at some point when I feel like making a new placeable. In the meantime I’mjust going to set the non participants to hidden.

Ok. I’m unfamiliar with Tschos’ methods, but I still think you ought to try Lance Botelle’s and my method, by using a Collision Box (which is invisible, no need for a transparent visual effect) and creating an invisible wall that way and then changing to BlockLoS in the placeables.2da. Just remember to activate Collision/C2 Data in the toolset, otherwise you won’t be able to see the invisible Collision Box.

1 Like

Hi again. Latest report, using Tscos’ first method doesn’t work either. In fact if you make a placeable fully transparent via it’s diffuse texture’s alpha channel, you can’t do anything to it in the toolset, place it, rotate it etc, nor will it bake, even set to Block LOS = TRUE and Walkable = FALSE. This method appears to work when only part of a placeable is set to transparent.
tschos’ tranparent placeble methods

I’ll try this with a collision box vice wall segment next.