Odd thing happening in a fight

When testing a fight in my module a few days ago something quite odd happened. As I was trying to balance the fight and testing a few times, at one time I saved in the middle of the battle. Then when reloading all of a sudden I noticed my characters in the party were immortal for some reason. When testing the fight before without saving and reloading everything worked as normal but just this once, this thing happened.

Any thoughts on this?

Tried to do the fight from the beginning, saving in the middle of it, and then reloading, and this time everything worked as it should. Maybe it was a temporary bug, I don’t know…

1 Like

At the moment my brother is beta testing my module and one of the companions suddenly became immortal, or whatever is happening. It’s just a white 0 above the head when she gets hit. So I tried solving this by putting some additional code in the script at the OnClientEnter of the area, and tried with one of my brother’s savegames before getting into that area. I’m now using the Campaign mode by the way, so I should be able to replace scripts without problems. This is the script for the OnClientEnter of the area, and STILL the character called Loreen doesn’t take damage in a fight. Is there some other issue here? I mean, ok, if it is a bug, but I should be able to fix it with some code like this, shouldn’t I? It doesn’t make sense to me.

#include "ginc_object"


//ft1 = Swamp
//ft2 = Road with camp
//ft3 = Dein
//ft4 = Mountains
//ft5 = Hills
//ft6 = Outside Fallbrook

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


void Death(string sTagString, int iInstance = 0)
{
	PrettyDebug("Applying Death Effect To: " + sTagString + " Instance = " + IntToString(iInstance));		
    
        object oObject = GetObjectByTag(sTagString, iInstance);

        AssignCommand(oObject, SetIsDestroyable( FALSE,FALSE,TRUE ));
	    SetImmortal( oObject, FALSE );
	    SetPlotFlag( oObject, FALSE );
        effect eFX = EffectDeath();
		PrettyDebug("Name of oObject = " + GetName(oObject));		
        ApplyEffectToObject( DURATION_TYPE_INSTANT,eFX,oObject );
    
}



void main()
{

object oPlayerPc = GetFirstPC();
object oTaik = GetObjectByTag("taik");
object oElvera = GetObjectByTag("elvera");
object oCelestine = GetNearestObjectByTag("celestine");
object oLoreen = GetNearestObjectByTag("loreen");
//int nJe = GetLocalInt(oPlayerPc,"NW_JOURNAL_ENTRYq_church");

DelayCommand(0.5,PrepForDestruction(oCelestine));
DelayCommand(0.5,PrepForDestruction(oLoreen));

	if(!GetGlobalInt("swampenter"))
	{

	SetGlobalInt("swampenter",1);

	}

	if(!GetLocalInt(OBJECT_SELF,"Spawnscared") && GetFactionEqual(oPlayerPc,oElvera))
	{
	
	SetLocalInt(OBJECT_SELF,"Spawnscared",1);
	object oScared = SpawnCreatureAtWP("scared","scared_wp");
	
	}

int nJe2 = GetLocalInt(oPlayerPc,"NW_JOURNAL_ENTRYq_summon");

	if(!GetLocalInt(OBJECT_SELF,"Fasttravel") && GetGlobalInt("fasttravelset") && GetFactionEqual(oPlayerPc,oElvera))
	{
		object oFT6 = SpawnPlaceableAtWP("ft6", "ft6_wp");
		SetLocalInt(OBJECT_SELF,"Fasttravel",1);
	
	}
	
	if(nJe2 > 30)
	{
		
	object oHoodGuy = SpawnCreatureAtWP("hoodedman", "hoodwp");
	object oNote = SpawnObjectAtWP(OBJECT_TYPE_ITEM,"hoodnote","hoodnwp");
	Death("hoodedman");
	
	}
	
	else return;
	
}	

Sometimes working with NWN2 is depressing.

Here are two pictures of how it looks ingame:

nodamage

nodamage2

Could it have something to do with using Encounter Triggers? I’ve not noticed any problems with that kind before, but…I’m just grasping at straws here. There’s a square on the properties saying “Player Only?”. Maybe that should be marked? Again just trying to come up with some way to fix this…

I had the same results when the damage from the opponent was lower than than the damage resistance. Does Loreen wear any cloak or ring of damage resistance?

Change these lines:

object oCelestine = GetNearestObjectByTag("celestine");
object oLoreen = GetNearestObjectByTag("loreen");

to this:

object oCelestine = GetObjectByTag("celestine");
object oLoreen = GetObjectByTag("loreen");

I’m assuming there are no other instances of these characters in the module with the same tag.

@travus I tried with your change before doing the GetNearest unfortunately, so I already know that that doesn’t work.

@4760 Well, she has quite good armor, I’ll give you that. It’s just that I can’t remember her not taking damage in the fights in these areas before when I myself tested it, but I could be wrong…

armor

1 Like

I’ll try and remove her armor before getting into the area and see if that does any difference.

Edit: Removed her armor but still the same result. No damage whatsoever.

You assume correctly.

Just to make sure I’m clear - Taik, Elvera, Celistine, and Loreen are all companions in your party and they should all be Mortal/Unplotted members. Is that correct?

@andgalf,

I noticed the issue being discussed here, so will throw in some ideas here … :slight_smile:

Assuming there is only the one tagged object as such in your module.

I have found it is best to use GetObjectByTag whenever possible.

The delay is a good idea, but try only 0.1 instead and stick with GetObjectByTag instead of GetNearestObjectByTag. Also try just making the delay between each companion slightly different. i.e. 0.1 for one and 0.2 for another.

Let me know if that helps or not.

@travus

I believe that is the objective, but I guess andgalf will correct me if I am wrong.

1 Like

Yes, that is correct.

(Edited) Yes, I decided to get everyone into the conversation, since this seems such an odd thing (and since I’ve brought up this phenomenon before). Maybe we can all work it out together. I told my brother, who is just at the beginning of the module, to replay the whole thing, and if he notices this thing again, to keep his eye open as to where it occurs the first time. Since it is really in the beginning there are only so many places where this could have occured.

Ok, I’ll try that one, but it will have to be tomorrow. Too tired right now. My job takes a bit of a toll on me right now, but it’s just a phaze. It will be better in a week or two (I think).

Get some sleep :slight_smile:

Later you might give this a shot…

Replace this:

DelayCommand(0.5,PrepForDestruction(oCelestine));
DelayCommand(0.5,PrepForDestruction(oLoreen));

With this:

SetMortal(oPlayerPc);

And add this wrapper:

void SetMortal(object oTarget)
{
	object oFM = GetFirstFactionMember(oTarget, FALSE);

	while (GetIsObjectValid(oFM))
	{	
		SetPlotFlag(oFM, FALSE);
    	SetImmortal(oFM, FALSE);
    	AssignCommand(oFM, SetIsDestroyable(FALSE));
		oFM =  GetNextFactionMember(oTarget, FALSE);
	}
}
2 Likes

Good idea. I see what you’ve done here. It’s irritating when you find a bug like this and you think that it should be solvable by just “resetting” stuff to normal, but I guess this is NWN2 we’re talking about. I still don’t have a deep enough knowledge of how this game opperates when stuff like this happens. You all seem to have such way better understanding of how things are done under the hood of this buggy game, and how to get around its quirks.

Yep, I’ll got get some sleep now. It’s after midnight around here so…

2 Likes

@andgalf,

I nearly wrote an identical function to @travus for you, but stuck with the format you were using to keep it in style you had written. Also, to help demonstrate how this can be used for “individual” companions. However, if you just want a party wide reset (which is what I believe you want) and you understand what Travus has done, then go with that, because as I say, I nearly did the same thing (and should work). :slight_smile:

Basically, the way I used your function (with the differing delays) should do something similar with the two companions in question … or so I believe. But, again, is untested.

In all fairness to NWN2, while I agree that there are some “buggy” parts, some of these types of issues may well be just due to “us” (I include myself here) not quite understanding some important timing aspects of the code. For instance, some functions require more calculations and power to do than others. So, some ways we write script may be asking for some overzealous calculations or functionality that the toolset would rather be written another way. It is not always clear when this is the case, but when we do not see the results we were expecting (like here), then that suggests another approach may be required. Funnily enough, I actually find what we may call “bugs” help me to code more efficiently … or maybe that should be correctly.

For instance, I have often found better ways to code after finding a “bug” that had been caused by me trying to make a script I had poorly written do something more than it originally was written to do. It was fine for the first instance I had written it, but when trying to use it somewhere else showed up my “poor” script. In particular, (and you may begin to experience this yourself), when it comes to adding “safety” code or code to cater for MP aspects too. By safety code, I mean checks that ensure we are checking the right objects at the right time and for the right reason.

Take care, Lance.

1 Like

Yeah, I know that sometimes a “bug” is not a bug, but you really have to understand how the game does things. Sometimes it can be really hard to discover this though, which makes it quite frustrating at times.

I’m home from work now (but I still work, patiently awaiting responses with phone calls and text messages on my phone) so I’ll try out what you suggested here.

Tried with both of your new suggestions and still the same result. Loreen won’t take damage. It’s so odd that you can’t seem to reset things. Could it be some spell she’s under…or something? Nothing shows beside the portrait though…

@andgalf,

To check if the script and condition are even being fired/present, write some debug code that sends a message to the player that tells the player what the plot status of each companion is. You can use the GetPlotFlag function to check. And make sure debug feeds back the name of the PC it is checking so you get confirmation for each PC, by it returning 1 or 0 to inform you if it is indeed a plot flag set.

As I say, I do recall something akin to this in some of my own testing, but cannot recall what I did to get around the issue. However, I also recall the delayed plot flag being set upon PC entry too, and had to wait until I could remove it after a few seconds. i.e. I believe I recall having something in the heartbeat of a PC that removed the condition every heartbeat - subject to a variable check perhaps? Sorry I cannot be too specific at this point … hard to tell he exact environment again.

Just a quick thought - I assume your tester never employed God mode at any time?

Thanks, Lance.

EDIT: You can even add some of the SendMessageTo debug code similar to what Travus has below into your original script to give feedback both prior and after the function is supposed to remove any plot or immune status - even if it is simply “Script fired” and “Removal function fired” in the case of making sure the script is firing at least. Then add other for individual PC checks if need be.

1 Like

Like what @Lance_Botelle, said. Make a a debug script like this and call it “mortal_check” (or whatever):

// mortal_check

void main()
{
	string sMortal = " is not immortal."; 	
	object oPC = GetFirstPC(FALSE);
	object oFM = GetFirstFactionMember(oPC, FALSE);

	while (GetIsObjectValid(oFM))
	{	
		if (GetImmortal(oFM)) sMortal = " IS immortal.";
		
		SendMessageToPC(oPC, GetName(oFM) + sMortal); 
		oFM =  GetNextFactionMember(oFM, FALSE);
	}
}

Get into your game and start debugmode. Then run that script, “rs mortal_check”.
What do you see in your message window?

2 Likes