What am I doing wrong here - annoying script problem

Urrgh, this is frustrating. I feel quite stupid at the moment. I thought the following script would work but somehow it doesn’t. I have this on the OnDamage of a door. When the amount of damage the door has received is above 25, something is supposed to happen. The script is running, I know that for sure, because at first I used a much more simpler variation of this script but I wanted to account for multiple hits on the door and add them up. I’m surely making some utterly stupid mistake here. Can you help me?

#include "ginc_object"

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


void main()
{

object oDamager = GetLastDamager();
if(!GetIsPC(oDamager)) return;

if(!GetGlobalInt("WreckTowerDoor")) return;

PrepForDestruction(OBJECT_SELF);

int iCurrentDamage = GetGlobalInt("DamageTDoor");

int iDamage = GetTotalDamageDealt();

int iTotalDamage = SetGlobalInt("DamageTDoor",iCurrentDamage + iDamage);

	if(iTotalDamage > 25)
	{
	
	object oPlaceable = SpawnPlaceableAtWP("towerent","i2tentrancewp");
	DestroyObject(OBJECT_SELF,0.2);

	}

}

doors have by default only 15 hp … give your door more hp … i suspect it’s being destroyed before the damage can tally up to 25 hp

ps. I did a test with code very much like yours and it worked fine once i upped the hp.

Change this:

int iTotalDamage = SetGlobalInt("DamageTDoor",iCurrentDamage + iDamage);

To this:

int iTotalDamage = iCurrentDamage + iDamage;

SetGlobalInt("DamageTDoor", iTotalDamage);
1 Like

@kevL_s - My door has 200 hp so that’s not the issue here.
@travus - Ok, I’ll try your variation. Hopefully that works better.

here’s the script that worked for me, if you want to compare

const string sVarDamageAccrued = "DamageAccrued";

void main()
{
	if (GetIsPC(GetLastDamager()))
	{
		int taken = GetTotalDamageDealt();
		int d = GetLocalInt(OBJECT_SELF, sVarDamageAccrued) + taken;
		if (d > 25)
		{
			object point = GetObjectByTag("wp_doordestroy");
			if (GetIsObjectValid(point))
			{
				location lLoc = GetLocation(point);
				CreateObject(OBJECT_TYPE_PLACEABLE, "plc_mp_lever_usable", lLoc);
			}
			DestroyObject(OBJECT_SELF, 0.2f);
		}
		else
			SetLocalInt(OBJECT_SELF, sVarDamageAccrued, d);
	}
}

I just tried @travus solution. Now it worked perfectly. How come you have to write it like that for it to work?
SetGlobalInt can’t add two numbers directly in the function perhaps?

@kevL_s - From what I can deduce from your script you don’t stack damage from multiple hits, but I’m not sure I’m reading it right. Maybe each time you deal damage it adds that to the local int somehow? In any case with travus’ suggestion it works for me now.

2 Likes
int iTotalDamage = SetGlobalInt("DamageTDoor",iCurrentDamage + iDamage);

seems like a fault in the compiler, this might work …

int iTotalDamage = SetGlobalInt("DamageTDoor", (iCurrentDamage + iDamage));

 
@andgalf

d is the sum of previous damage taken + current damage taken, and it overwrites the local_int if the door doesn’t get destroyed.

2 Likes

I tried with

int iTotalDamage = SetGlobalInt("DamageTDoor", (iCurrentDamage + iDamage));

but that didn’t work either.

@kevL_s - Even though I could use your code here with

just as well as travus’ suggestion, I’ll go with his for now since I’ve tested it now and it works.
One thing I wonder is…why do you need the sVarDamageAccrued to be a constant string?

Thanks for all the help you guys!

1 Like

Explanation :

When you write

int iTotalDamage = SetGlobalInt("DamageTDoor",iCurrentDamage + iDamage);

you initialize iTotalDamage with the result of the function SetGlobalInt which is either 1 (done) or 0 (some hard disk issue)
So you always get 1 which is obviously < 25.

Sure SetGlobalInt can handle a formula as 2nd parameter.

I’m not so sure that’s true. I’ve been able to set a global int (through ga_global_int that is) to any number, and in that case this shouldn’t work either, right? :

int iTotalDamage = iCurrentDamage + iDamage;

SetGlobalInt("DamageTDoor", iTotalDamage);

Or maybe I’m not understanding you correctly here @Claudius33 .

However, as soon as you do a GetGlobalInt to check for, the game, as I’ve understood it, interprets any number above 0 as TRUE and 0 as FALSE.

You are confusing the value you assign to a global variable (“DamageTDoor”) through the function SetGlobalInt with the result of the function itself

// Global Var stuff
// set a global int
int SetGlobalInt(string sName, int nValue);

The result is not the value you assign to the global variable but 1 if successful or 0 if not (hard disk issue since the global variable are stored into a xml file).

To avoid confusion never put a SetGlobal function as a right member of an equation. What @travus did.
With the coding he suggested iTotalDamage is correctly initialized and SetGlobalInt does the work.

2 Likes

I only half understand what you are saying here but…ok.

The one thing I draw from what you are saying, not sure if I understand it totally but…I shouldn’t do a calculation within the SetGlobalInt function itself, but do it outside of that function like travus did…maybe?
It seems that’s the way it’s done when I look at the content of the ga_global_int script.

Sure you can use a computation inside the SetGlobalInt function for instance you could write:

SetGlobalInt("DamageTDoor", iDamage + GetGlobalInt("DamageTDoor")); //store the new amount of damage
if (GetGlobalInt("DamageTDoor") > 25)  //test it

Think SetGlobalInt as a forklift adding crates on a pile. Every times it adds a new crate it returns 1 (ok new crate stored) or 0 (sorry no more room) but not the number of crates stored. So you have to ask, how many crates now using GetGlobalInt.

it’s :
void SetGlobalInt not int

you can’ t do int i = SetGlobalInt beceause it’s a setter wich return “void” nothing.

SetGlobalInt("DamageTDoor",iCurrentDamage + iDamage);

is perfectly valid and work perfectly but int = Set… that one is nevers going to compile ever.

so:

int iDamageA,DamageB;
int iTotalDamage = iDamageA + iDamageB;
SetGlobalInt("DamageTDoor",iTotalDamage);

Here it means you have stored iTotalDamage value inside the global int "DamageTDoor"

if you wish to access that value from outside this script :

int iTotalDamage = GetGlobalInt("DamageTDoor");

But if you want that value inside the script you don't need to use a global int.

A global int is a way to store a value in the database.

Set means “setter”, a setter is a function that will store a value. It always of “void” type, it doesn’ t return any value.

The value is returned by a “getter”.

To get a value stored you need to use a “getter”, which name normally start with Get.

Shallina, SetGlobalInt is NWN2 specific. Although SetLocalInt remains a void function as for NWN, SetGlobalInt is a int function.

This is taken from the NWN2 toolset when you ask for information about the function SetGlobalInt:

// Global Var stuff
// set a global int
int SetGlobalInt(string sName, int nValue);

So unfortunately int i = SetGlobalInt does compile under NWN2 and may lead to confusion.

Try

void main()
{
int i = SetGlobalInt("Dummy", 25);
}

It compiles successfully.

1 Like

I agree. Better to think of the function as a void rather than an int - and then use it that way like we do the “local” versions. Only difference is the global does not require an object in which to store the variable - and it stores to a file on the hard drive rather than on an object within the module.

3 Likes

i think a local_int stored on the door itself is best … when door gets destroyed, no variable left at all :)

3 Likes

This is quite interesting. Just checked myself and see that it is as you all say that SetGlobalInt is an int while SetLocalInt is a void. Really pecuiliar. Things like that certainly lead to confusion just as Claudius33 says, but from this discussion I agree that one should probably regard SetGlobalInt as void and not int.

Why I chose Global Int in my case was that I at first thought that I wanted to run this script several times and therefore had to store the the number outside of the script/the object somehow, but when I looked at kevL_s’ script, I realized that I didn’t need to do that. But, lazy as I am, I thought I would use travus’ change becuase that meant less work for me. Otherwise I agree with kevL_s on this.
Remember, my mind was never made for scripting. It has taken me four years to get to the basic level of understanding scripting the way I do now (I’ve been an extremely slow learner when it comes to this), so I don’t always draw these logical conclusions like you all do. Things I understand at the moment my brother, who’s a programmer like all of you here, understood at the age of 12, so I know I am not that bright when it comes to all this. :grin:

So I am still learning…luckily NWN2 and the things I want to do in that game, forces me to try to understand all of this. I am not content on just using stock scripts like I know Tsongo does most of the time (I probably would have a lot less of headaches if I did though), and I am not smart enough to think outside-of-the-box like he is.
I have too many ideas on how I want things to be in NWN2 and my modules and thus I have to use scripting…

EDIT: And I have to say I am very proud I managed to come up with my own system of scrolling through potential party members and choosing a random one as the owner of a dialogue in one of my recent scripts, since in this module I never know what companions the party consists of.

2 Likes

Ok, when pondering this some more, I decided to change my script and do it like this instead. I just have to test it to see that it actually works, which I think it will. Like kevL_s says:

#include "ginc_object"

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


void main()
{

object oDamager = GetLastDamager();
if(!GetIsPC(oDamager)) return;

if(!GetGlobalInt("WreckTowerDoor")) return;

PrepForDestruction(OBJECT_SELF);

int iCurrentDamage = GetLocalInt(OBJECT_SELF,"DamageTDoor");

int iDamage = GetTotalDamageDealt();

int iTotalDamage = iCurrentDamage + iDamage;

SetLocalInt(OBJECT_SELF,"DamageTDoor", iTotalDamage);

	if(iTotalDamage > 25)
	{
	
	object oPlaceable = SpawnPlaceableAtWP("towerent","i2tentrancewp");
	DestroyObject(OBJECT_SELF,0.2);

	}

}

EDIT: Yep, it worked.

1 Like

it doesn’t have to be. But I’ve gotten in the habit, that whenever a string is used more than once, const it.

'Cause … while the compiler will catch typos in sVarDamageAccrued it won’t catch a typo in “DamageAccrued” … the script compiles and you won’t notice anything wrong and you got a bug. So i use const

1 Like