Another FACTION Question (POTENTIALLY FIXED!)

@kevL_s

I have some situations where I don’t want Defenders to assist commoners and so just kept it “neutral” for the time being.

As you say, it appears that the “Neutral fix” - certainly has NOT worked. :woozy_face:

I may have it somewhere, but no harm posting again for me if you can? :blush:

And yet I have seen a creature “randomly” switch from “friendly” with speech bubble icon to “hostile” with sword icon just because it was in the vicinity of PCs attacking hostiles. I also had a NEUTRAL “prisoner” attacked by hostiles because the PCs (who were also neutral to the prisoner) attacked them (as hostiles).

I feel like I am chasing my tail … and I have no idea why the “reputation” functions are not working at all. My only guess is that they are NOT as user friendly when adjusting/testing such alterations from mid-game.

but did the creature who changed its reputation have any ai-scripts slotted? I’d like to conclusively establish whether it is or is not one of your creature ai-scripts …

Lance, tbh this is my “AdustReputation” funct

// this function corrects the fault in AdjustReputation()
void kL_AdjustReputation(object oTarget, object oSource, int iAdjustment)
{
	int iRep_source = GetReputation(oTarget, oSource);
	int iRep_target = GetReputation(oSource, oTarget);

	int iDiff = iRep_source - iRep_target;
		iDiff += iAdjustment;

	AdjustReputation(oTarget, oSource, iDiff);
}

It reverses oSource and oTarget … my opinion is that most if not all faction-related functs in nwn2 were accidentally reversed – but only between nonPC creatures (so am not sure how applicable it is to the issue here).

@kevL_s,

There was no extra AI as such, although I have my own event hook scripts anyway … so they are edited in some way. Although, more to do with my own stuff than anything else.

I started to work something along these lines, but just went hard test … BUT, I am now also double-checking the fact that my FACTION pigs are “plot” and it may be a long shot that I am unable to “correct” their reputations due to this being the case.

I am just retesting my “faction” fix code allowing the pigs to be temporarily unplotted to make changes. I will report back with the results.

I also managed to find a saved game where the PCs had the correct faction standing with the ANTIPARTY (as 0), and tried monitoring what was causing the change. Will report back in a bit with results.

I think this is up to date …

testfactions.nss
// 'testfactions'
/*
	Utility script for checking how Creatures feel about other Creatures in an
	area. It effectively switches the parameters oSource and oTarget for these
	functions:

	- GetReputation()
	- GetIsEnemy(), GetIsNeutral(), GetIsFriend()
	- GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_*)

	HAVE FUN WITH THAT!!!!!
	Ie. with the changes, this script returns correct values.

	Conclusion: For factions to work correctly in NwN2 invert the Faction Table
	(except the Player column because it always returns its own value).
*/
// kevL 2014 apr 20.

// debug to Chat.
void Tell(string sTell)
{
	SendMessageToPC(GetFirstPC(FALSE), sTell);
	PrintString(sTell);
}

/**
 * Prototypes
 */

// Returns TRUE if Source feels REPUTATION_TYPE_* against oTarget.
// - uses switched parameters for GetReputation() ....
int GetIsReputationType(int iRepType, object oTarget, object oSource = OBJECT_SELF);

// A variant of GetNearestCreature() that switches the determination of Target's
// reputation against Source for Source's reputation against Target.
// - it works in accord with the toolset FactionTable!!
object GetNearestCreature_kL(int iType1, int iVal1,
							 object oSource = OBJECT_SELF, int i = 1,
							 int iType2 = -1, int iVal2 = -1,
							 int iType3 = -1, int iVal3 = -1);

// Not used in this script:
// this function corrects the fault in AdjustReputation()
void kL_AdjustReputation(object oTarget, object oSource, int iAdjustment);


/**
 * MAIN ***
 */
void main()
{
	object oTarget;
	int iRepValue;

	string sSource;
	int i;

	object oSource = GetFirstObjectInArea();
	while (GetIsObjectValid(oSource))
	{
		if (GetObjectType(oSource) == OBJECT_TYPE_CREATURE)
		{
			sSource = GetName(oSource);
			if (sSource == "") sSource = "Source";

			i = 1;
			oTarget = GetNearestObject(OBJECT_TYPE_CREATURE, oSource, i);
			while (GetIsObjectValid(oTarget))
			{
				iRepValue = GetReputation(oTarget, oSource);
				Tell("\n. " + sSource + " vs " + GetName(oTarget) + " : " + IntToString(iRepValue));

				Tell(". . isEnemy = "   + IntToString(GetIsEnemy(  oSource, oTarget)));
				Tell(". . isNeutral = " + IntToString(GetIsNeutral(oSource, oTarget)));
				Tell(". . isFriend = "  + IntToString(GetIsFriend( oSource, oTarget)));

				oTarget = GetNearestObject(OBJECT_TYPE_CREATURE, oSource, ++i);
			}


			Tell("\n. " + sSource + "'s near Enemies :");
			i = 1;
			oTarget = GetNearestCreature_kL(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oSource, i);
			while (GetIsObjectValid(oTarget))
			{
				Tell(". . . " + GetName(oTarget));
				oTarget = GetNearestCreature_kL(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oSource, ++i);
			}

			Tell("\n. " + sSource + "'s near Neutrals :");
			i = 1;
			oTarget = GetNearestCreature_kL(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_NEUTRAL, oSource, i);
			while (GetIsObjectValid(oTarget))
			{
				Tell(". . . " + GetName(oTarget));
				oTarget = GetNearestCreature_kL(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_NEUTRAL, oSource, ++i);
			}

			Tell("\n. " + sSource + "'s near Friends :");
			i = 1;
			oTarget = GetNearestCreature_kL(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oSource, i);
			while (GetIsObjectValid(oTarget))
			{
				Tell(". . . " + GetName(oTarget));
				oTarget = GetNearestCreature_kL(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oSource, ++i);
			}
		}

		oSource = GetNextObjectInArea();
	}
}


/**
 * Functions
 */

// A variant of GetNearestCreature() that switches the determination of Target's
// reputation against Source for Source's reputation against Target.
// - it works in accord with the toolset FactionTable!!
object GetNearestCreature_kL(int iType1, int iVal1,
							 object oSource = OBJECT_SELF, int i = 1,
							 int iType2 = -1, int iVal2 = -1,
							 int iType3 = -1, int iVal3 = -1)
{
	if (   iType1 != CREATURE_TYPE_REPUTATION
		&& iType2 != CREATURE_TYPE_REPUTATION
		&& iType3 != CREATURE_TYPE_REPUTATION)
	{
		return GetNearestCreature(iType1, iVal1, oSource, i, iType2, iVal2, iType3, iVal3);
	}


	object oTarget;
	int
		j = 1,
		iMatch = 0,
		iRepType;

	if (iType1 == CREATURE_TYPE_REPUTATION)
	{
		int bType = FALSE;

		iRepType = iVal1;
		if (iType2 > -1)
		{
			bType = TRUE;

			iType1 = iType2; iVal1 = iVal2;
			iType2 = iType3; iVal2 = iVal3;

			oTarget = GetNearestCreature(iType1, iVal1, oSource, j, iType2, iVal2);
		}
		else
			oTarget = GetNearestObject(OBJECT_TYPE_CREATURE, oSource, j);

		while (GetIsObjectValid(oTarget))
		{
			if (GetIsReputationType(iRepType, oTarget, oSource) && ++iMatch == i)
				return oTarget;

			if (bType)
				oTarget = GetNearestCreature(iType1, iVal1, oSource, ++j, iType2, iVal2);
			else
				oTarget = GetNearestObject(OBJECT_TYPE_CREATURE, oSource, ++j);
		}
	}
	else if (iType2 == CREATURE_TYPE_REPUTATION)
	{
		iRepType = iVal2;
		if (iType3 > -1)
		{
			iType2 = iType3; iVal2 = iVal3;
		}
		else
		{
			iType2 = -1; iVal2 = -1;
		}

		oTarget = GetNearestCreature(iType1, iVal1, oSource, j, iType2, iVal2);
		while (GetIsObjectValid(oTarget))
		{
			if (GetIsReputationType(iRepType, oTarget, oSource) && ++iMatch == i)
				return oTarget;

			oTarget = GetNearestCreature(iType1, iVal1, oSource, ++j, iType2, iVal2);
		}
	}
	else if (iType3 == CREATURE_TYPE_REPUTATION)
	{
		oTarget = GetNearestCreature(iType1, iVal1, oSource, j, iType2, iVal2);
		while (GetIsObjectValid(oTarget))
		{
			if (GetIsReputationType(iVal3, oTarget, oSource) && ++iMatch == i)
				return oTarget;

			oTarget = GetNearestCreature(iType1, iVal1, oSource, ++j, iType2, iVal2);
		}
	}

	return OBJECT_INVALID;
}


// Returns TRUE if Source feels REPUTATION_TYPE_* against oTarget.
// - uses switched parameters for GetReputation() ....
int GetIsReputationType(int iRepType, object oTarget, object oSource = OBJECT_SELF)
{
	if (iRepType == REPUTATION_TYPE_ENEMY)
	{
		return (GetReputation(oTarget, oSource) < 11);
	}

	if (iRepType == REPUTATION_TYPE_NEUTRAL)
	{
		return (GetReputation(oTarget, oSource) > 10
			 && GetReputation(oTarget, oSource) < 90);
	}

	if (iRepType == REPUTATION_TYPE_FRIEND)
	{
		return (GetReputation(oTarget, oSource) > 89);
	}

	return FALSE;
}


// Not used in this script:
// this function corrects the fault in AdjustReputation()
void kL_AdjustReputation(object oTarget, object oSource, int iAdjustment)
{
	int iRep_source = GetReputation(oTarget, oSource);
	int iRep_target = GetReputation(oSource, oTarget);

	int iDiff = iRep_source - iRep_target;
		iDiff += iAdjustment;

	AdjustReputation(oTarget, oSource, iDiff);
}
1 Like

@kevL_s

Thanks mate! I will give it some deeper testing with that now. :+1:

From testing a saved game, the situation remains where I am currently unable to revert the ANTIPARTY reputation setting from 100 back to 0 (zero). I think if I ever manage to do that, then I may be one step closer to finding a more stable fix.

1 Like

@kevL_s

Some good news about the reputation adjustment … I DID manage to alter it back to zero after temporarily switching the faction pigs to non plot!

Basically, the game had managed to alter the entire ANTIPARTY faction to friendly due to the NEUTRAL “fixes”, and to alter it back I had to remove plot flag so I could alter it back on the pig. At the same time, I could then redress the differences (errors) before switching them back.

Bottom line … I think the fact that these “plot” faction pigs had somehow changed reputation relationship proves it could not have been my own scripting that did it, as this is the first instance that I have ever un-plotted them for the purpose of fixing their faction relationships.

Now, I have a bit of code that simply keeps these two factions at their proper levels every heartbeat. My issue before was that I had fixed one side of the relationship, but had missed the other side (not realising that the two factions had interacted with each other outside of my code).

I will now give my wife the fix and see how she gets on and post the v1.40E after some more testing - including using your script to help keep an eye for a while.

Thanks for your help again @kevL_s :+1:

Here is an EXAMPLE what I used … Actual differs in places. (Tidying up now.)

//////////////////////////////////////////////////////////////////////////////////////////////
	// NEUTRAL & ANTIPARTY FIX 14/04/21
	//////////////////////////////////////////////////////////////////////////////////////////////	
	
	object oANTIPARTY = GetObjectByTag("SETFACTION_ANTIPARTY");	
	object oNEUTRAL = GetObjectByTag("SETFACTION_NEUTRAL");
			
	int iREP = GetReputation(oANTIPARTY, oPCORCOMP);
	int iREP2 = GetReputation(oNEUTRAL, oPCORCOMP);
	
	if(iREP > 0 || iREP2 != 50)
	{
		SetPlotFlag(oNEUTRAL, FALSE);
		SetPlotFlag(oANTIPARTY, FALSE);
		
		ClearPersonalReputation(oNEUTRAL, oANTIPARTY);		
		AdjustReputation(oNEUTRAL, oANTIPARTY, 50);	
		
		ClearPersonalReputation(oPCORCOMP, oANTIPARTY);	
		ClearPersonalReputation(oPCORCOMP, oNEUTRAL);
			
		AdjustReputation(oPCORCOMP, oANTIPARTY, -100);
		AdjustReputation(oPCORCOMP, oNEUTRAL, 50);			
			
		SetPlotFlag(oNEUTRAL, TRUE);
		SetPlotFlag(oANTIPARTY, TRUE);
	}

okay

but that’s not a fix its a workaround –

Im still curious what (exactly) is causing a rep-change that apparently shouldn’t be happening …

 
And ill suspend disbelief for the moment that a pig needs to be unplotted to access its faction correctly  ;)

1 Like

@kevL_s,

I agree … It’s certainly not an ideal situation, but if it works, it will have to do for the time being until a permanent fix can be found.

Accessing its faction is OK (for comparison), but I was unable to adjust its reputation until unplotted. I should double-check that point for one or two other situations I have with respect to the NPCs that reference the pigs too … as it may be that I am unable to adjust them if I have them plotted as well.

By the way, do you know that if if an adjustment is made, is it one-sided? e.g. Will Clearing a reputation clear it for both factions of just the one?

If you have not yet done so, check this out …

oh, yeh i can believe that …

ClearPersonalReputation ? If personal reputation isn’t on I wouldn’t think that that call matters … but if it does id do it both ways

1 Like

I will play around with this function and your test script and see what comes about …

I need to be sure I have this settled before yet another release … :blush:

EDIT: I am trying to write a function that allows me to SET the actual reputation for two factions at the moment.

I will update my own scripts when that is done.

1 Like

go back to around 2008… on one of the old old boards the old guard was was up in arms: wtf nwn2 rep/faction?

That was when i realized/came to believe that something was seriously borked between Nwn1 and 2. I was doing Nwn1 and factions worked great (for my purposes) – but things in 2 were just off.

Personal Reputation does not work in any decent way – I tried, others tried. reasons.

After extensive testing I believe oSource and oTarget got reversed /shrug

so whatever Nwn1/EE is doing it’s no where near as “crazy” as nwn2.

 
I never knew about RepAdjust.2da … could be …

back it up, zero it, and see what happens  :)

Woh! That would be a headache!

I am tempted (as I mention in an earlier post), but leave that for the time being …

At the moment, I am just trying to write a function that allows me to set the exact reputation between two factions - It’s a bit confusing to tell if setting for one to one direction will set the same back the other way.

As soon as I have that confirmed, I hope I am in a better position to know how to keep my factions reputations working - admittedly, not ideally “fixed” - but working enough that I can live with until a better solution presents itself.

Sometimes I make a pig-of-faction blueprint and use it like a faction-ninja

spawn the pig, do the faction alterations, then destroy it.

I see - sort of like a fresh PIG every time … I have just a set of pigs that I refer to. The plan was that they were never meant to alter though. Latest play testing has proven this is not the case.

EDIT: I can confirm that reputation adjustment works two ways. i.e. You adjust -30 from the perspective of the source and if you have the PC shout their reputation with regard to the source, their rep figure is EXACTLY the same. (I had both source and PC shout together after altering from just one perspective.)

i.e. Source Rep (to PC) - PC Rep (to Source) == 0

If both factions are NPC/Monster and their reps are different ( a vs b is not b vs a ) then you could run into my faction-reversal problem …

not likely. That is each call should be one-way only. Thus allows ( a vs b to be different than b vs a ).

 
 
as a bit of an aside, I started thinking about reps as “feels about” – “critterA feels about critterB” ( oSource feels about oTarget )
 

rather : to Target. “PC feels about Target” – anything else is confusing to me … /shrug
 

if you have blueprints for them ready to go, they can be spawned and despawned anywhere, in any unforeseen area, eg.

yep – but try that with 2 NPC faction critters instead of a PC. And let their reputations be different toward each other.

OK - I will keep that in mind and look out for it - I guess I am a few years behind you in testing here. :smile:

OK - I will test that next and see what happens.

EDIT: As you say, ClearPersonalReputations does not (at this stage) appear to do anything.

1 Like

@kevL_s,

I just had a thought as to why the monster factions may be able to differ (not tested yet), but likely because you can set them differently within the faction tables (to each other), whereas the PLAYER has only one potential entry. (PLAYER has only a row entry.) That would probably explain any differences in that arrangement anyway.

Also, I currently don’t actually have any situations where monster to monster factions would differ after setting yet, but my guess would be if two monster factions who were friends became enemies, then you would have to alter both factions to become hostile one to another, as opposed to setting just one faction if the player was turned hostile to a monster faction. (i.e. Two way is assumed in the player situation.)

ALTHOUGH, there could be some scary results if a builder did have two monster factions change, as it could have massive repercussions throughout all other factions involved if different factions with different relationships witnessed PC behaviour among each - I dread to think what would happen. E.g. If (from my own experience), two monster factions have reacted strangely when the PC reacts differently to them, then it could be a lot worse.

EDIT: TESTING GAVE ME SOME REALLY WEIRD RESULTS …

		int iNEUTANTIREP = GetReputation(oANTIPARTY, oNEUTRAL);
		int iANTINEUTREP = GetReputation(oNEUTRAL, oANTIPARTY);			
		
		//AdjustReputation(oNEUTRAL, oANTIPARTY, -10);
		AdjustReputation(oANTIPARTY, oNEUTRAL, -30);

When I did debug alternating between these two reputation feedbacks, using -10 one way and then -30 the next. The first gave -90, but then never changed (even though it should have decreased by 10 because it was called from a heartbeat), whereas the -30 returned zero! They had both started at 100 when not called.

I think something (as you say) really weird is going on here - I would even say that altering reputations between monster factions may never have been expected to be used. i.e. The code left in for us to alter player faction v monster only - even though the function info would suggest otherwise.

I’m gonna have to call it a night and return to testing some more tomorrow. If you have any more info, I’ll catch up with you later. :slight_smile: :sleeping:

1 Like

nb. (PLAYER has only a column entry.)

using your faction table above

factions on the left “feel <rep> about” factions along the top. And yes ofc they can be set and varied differently :)

The Player column immediately says that the creatures on the left have “feelings” – the Player makes up his/her own mind about how he/she feels. Hence Player does not appear on the left but only along the top.

There is a module with a faction war going on … Dorateen’s Edinmoor … I don’t remember the factions changing reputations to each other but there is substantial drama that can go on if/when factions/reputations are working correctly.

At one point I was scouting carefully and saw some hostiles. They start moving toward me and I think “here they come” but they were instead going after the other faction … it was a zing moment …

1 Like

My bad - That’s what I meant … :woozy_face: Need sleep. :wink:

Agreed - Even in my own module, factions can change and it can be quite interesting results. However, some results have obviously gone awry - hence this post.

BUT, I do believe I am getting closer to resolving it now. My main problem (I believe) is the issue with “witnessing” and SILENT calls altering reputation values and then not noticing PLOT creatures being unable to alter back. Now I have those two points, I hope to fix (make a workaround) for my own situations.

In the process, I hope to write a SetReputation function for players towards monsters and faction pigs and vice-versa.

Anyway, I’ll catch up with you later now. take care! :sleeping:

1 Like

g’night

1 Like