Local Variables are not being reset

Hello everyone, First time post, long time NWN fan

I am currently trying to wrap my mind about this odd error that I just may not be obviously seeing but its been giving me trouble persistently.

I am currently building a single player module. The module is currently filled with several areas. Each area runs the same OnEnter script when the PC enters.

In the area are several types of objects,triggers,encounters etc. Some triggers and encounters have scripts and local variables attached to them

The problem I am having is when the module is first tested on an area, the local variables are correctly set and the script triggers correctly. How ever, a second time around testing the module, the SetLocalVar do not seem to function any more.

Ive been testing them on my triggers OnEnter and my encounters OnExhausted scripts. The Areas OnEnter is claiming it is setting the local vars of these objects to the correct number, how ever when i run a debug on my objects, they claim they are unchanged.

So I am very confused on what is happening. Would anyone know if SetLocalVar works on an area once per module build?

I can say that I use SetLocal(Int/String…) regularly in my scripts and they seem to be working for me. However, without seeing your actual script and how you are calling the variables, I can only guess. If you could post the OnEnter script and then one of the instances where checking it doesn’t seem to work on the second pass?

Thank you for the reply!
I understand, I guess I am missing something, but here are my scripts. I trimmed it down to where the problem is arising. the SetupTriggers() will be the focus here. The trigger script is afterwards.
The first time I check the module and enter the area, it correctly finds the trigger and tells me its local variable is set to 1. The trigger correctly sets up the ambush’s at the markers
How ever, the second time I load the module, The areas OnEnter script still tells me that the variables are correctly set to 1, how ever when I enter the trigger, it tells me the “active” local var is 0.
Its very odd. Maybe has to do when I create another area in the module? Its mind boggling

//The OnEnter area script
void SetupTriggers();
void CloseDoors();
void LockDoors(int a,int b);
void SetupEncounters(int e);
void SetupContainers(int c);
void DestroyObjects();
void main()
{
object oPC = GetEnteringObject();
if(!GetIsPC(oPC))
    return;
int r = GetLocalInt(OBJECT_SELF,"reset");
//object oEnc = GetFirstObjectInArea(OBJECT_SELF);
//string sTreasure = "x0_tres_anylow";
//location lLoc = GetLocation(oEnc);
int c = GetLocalInt(OBJECT_SELF,"waypoints");
int e = GetLocalInt(OBJECT_SELF,"encounters");
int s = GetLocalInt(OBJECT_SELF,"silverdoor");
int b = GetLocalInt(OBJECT_SELF,"bossdoor");
//if r == 1 -> find all objects eith enc, set active
    if(r == 1 && GetIsPC(oPC))
    {
        DestroyObjects();
        SetupTriggers();
        SetupEncounters(e);
        SetupContainers(c);
        LockDoors(s,b);
       SetLocalInt(OBJECT_SELF,"reset", 0);

    }
}


void SetupTriggers()
{
object oPC = GetEnteringObject();
string sType = "";
object oArea = GetArea(OBJECT_SELF);
    if(GetStringLeft(GetTag(oArea),3) == "Und")
        sType = "trig_ambush_und";
    else sType = "trig_ambush_und";
object oTrigger = GetObjectByTag(sType);
if(GetIsObjectValid(oTrigger))
    {
        SetLocalInt(oTrigger, "active", 1);
        SendMessageToPC(oPC,"Trigger activated: " +IntToString(GetLocalInt(oTrigger, "active")));//DEBUG
    }
SendMessageToPC(oPC,"SECOND CALL: " +IntToString(GetLocalInt(oTrigger, "active")));//DEBUG
}
//The script attached to the trigger object OnEnter
void main()
{
object oPC = GetEnteringObject();
object oWP = GetObjectByTag("ambush_marker",0);
string sTag = "ambush_marker";
string sType = "";
location lLoc = GetLocation(oWP);
int iActive = GetLocalInt(OBJECT_SELF,"active");
SendMessageToPC(oPC,"Value of active is: " + IntToString(iActive));//DEBUG
int iMarkers =   GetLocalInt(OBJECT_SELF,"markers");
int iDiff = GetLocalInt(OBJECT_SELF, "difficulty");
int r = Random(10);
int i = 0;
    if(iActive == 1)
    {
         SendMessageToPC(oPC,"Entered for active block");//DEBUG
        for(i = 0; i < iMarkers; i++)
        {
        SendMessageToPC(oPC,"Entered the for loop");//DEBUG
            oWP = GetNearestObjectByTag(sTag, OBJECT_SELF, i);
            lLoc =  GetLocation(oWP);
            if(GetIsObjectValid(oWP))
            {
                 if(iDiff == 1)//easy
                    {
                    if(r <= 5)
                        sType = "amb_und_easy";
                    else
                        sType = "amb_und_easy2";
                    }
                 else if(iDiff == 2)//normal
                    {
                    if(r<=5)
                        sType = "amb_und_med";
                    else
                        sType = "amb_und_med2";
                    }
                else if(iDiff == 3)//hard
                    {
                      sType = "amb_und_hard";
                    }
            }
            CreateObject(OBJECT_TYPE_PLACEABLE,sType, lLoc, FALSE);
            SendMessageToPC(oPC,"Ambush created");//DEBUG
        }
        SetLocalInt(OBJECT_SELF,"active",0) ;
    }
}

If you wish for your code to be readable on this forum, post it as code:

[code]
paste your code here
[/code]

You can edit your post. Visit this topic to learn how to use this site.

Additional code posting guidelines (click to expand).
  1. Put scripts into separate [code] sections for extra readability.
  2. You can use ``` instead of [code] and [/code].
  3. Post inline code like this: `short code fragment`.
  4. “Hide details” function (:gear: icon of the post editor) can collapse long code sections, reducing post size. Select text, then choose that option. It essentially does this:
[details="my_script.nss"]
[code]
code of my_script.nss
[/code]
[/details]

Done! My mistake, I was looking for a button with that functionality. Thank you

1 Like

So I can confirm that the error is arising when ever I create a new area in my module and use these scripts for that area. The newly created area will function with the local vars properly, how ever all other areas seem to not function. Is it due to the fact that these local vars share the same name? I would figure each object stores its local data independently from all others.

For the record, I am using NWN Platinum edition ver 1.69

Can you write step-by-step what are you trying to achieve and when it fails? When a script should run, how many times, etc.

Some pointers:

  1. Keep in mind that area’s OnEnter also fires when you load a singleplayer game.
  2. GetObjectByTag is global (picks objects module-wide, not only in current area).
  3. It never hurts to spam the code with a ton of SendMessageToPCs.
  4. Use ObjectToString to uniquely identify objects.
  5. sType is always the same after this branch:
if(GetStringLeft(GetTag(oArea),3) == "Und")
        sType = "trig_ambush_und";
    else sType = "trig_ambush_und";

GetObjectByTag` is global (picks objects module-wide, not only in current area).

Until you pointed that out, I was oblivious and thought I was using NEAREST object by tag which I was consistently using throughout my module.

The else statement was just a test statement sorry

if(GetStringLeft(GetTag(oArea),3) == "Und")
        sType = "trig_ambush_und";
    else sType = "trig_ambush_und";

Going to plead ignorance and brash for that one. Thank you very much!

Well, hopefully shortly now after that confusion was cleared up, Im hoping to release this single player module in the near future. It will be a dungeon diving module that allows the player to enter different themed-dungeons and allows them to reset the dungeons with a single click, re-populating them with encounters, chests etc.

Thank you again

(To quote from a post, select portion of its text and a “quote” button will appear).

If you need a function that iterates objects by tag in specific area, use this code:

GetObjectByTagInArea() - click here

This function is a hack, but is robust and has optimal performance.
It wraps GetNearestObjectByTag() for one special case.
It does not however guarantee that object order will be constant in runtime.

// By NWShacker, 2021-02-13
// returns iNth object in area oArea with tag sTag
object GetObjectByTagInArea(string sTag, object oArea=OBJECT_SELF, int iNth=1)
{
    // get first object in the area
    object oObject = GetFirstObjectInArea(oArea);

    // if this object does NOT have tag sTag,
    // pass control to GetNearestObjectByTag()
    if(GetTag(oObject) != sTag)
    {
        return GetNearestObjectByTag(sTag, oObject, iNth);
    }

    // otherwise, if iNth is 1, return it;
    // this is required because GetNearestObjectByTag()
    // does not return its oTarget if it matches sTag
    if(iNth == 1)
    {
        return oObject;
    }

    // otherwise return (n-1)th nearest object
    return GetNearestObjectByTag(sTag, oObject, iNth - 1);
}

Good luck with your module.

2 Likes

Very nice and efficient, instead of running several loops and gathering redundant data.

Thanks again for your help

1 Like