Help with scripts and triggers?

I apologize in advance if such questions have already been asked here, I am a Russian guy who can only communicate through an interpreter, it is difficult for me. If you know where I can find answers to them, send a link. Thanks!

Begin. I’m just starting to learn scripts, so far I use already created ones. I want to create an emerging Rest Area trigger. The player speaks with NPCs, the dialogue triggered the script “Activate\the Occurrence of a trigger Rest Zone”, the conversation ends, the player goes to the lounge, resting, it turns out, the script runs “Off\the disappearance of the trigger Rest Zone”.

I already have scripts for working Rest Area (entry\exit). Help to write a script Activation. Thanks!

At first I tried to make it myself. Used two Waypoints, one in a place inaccessible to the player, the other is in the right place of occurrence. Drew a Rest Area trigger in an inaccessible location.
Created a script for the dialogue.

void main()
{
object oRe = GetObjectByTag("TRIG_REST_ZONE");
object oRePoint1 = GetWaypointByTag("REST_ZONE_POINT_1"); 
AssignCommand(oRe,JumpToObject(oRePoint1));///the trigger arrives in the desired zone
 }

Add to the entry in the trigger script.

void main()
{
    object oPC = GetEnteringObject();
    if (!GetIsPC(oPC))
        return;
    SetLocalInt(oPC, "RESTZONE", 1);
    FloatingTextStringOnCreature("Вы в зоне отдыха. Можно отдыхать.", oPC);
    string sMess = GetName(OBJECT_SELF);
    if (sMess != "")
        DelayCommand(1.4, AssignCommand(oPC, SpeakString(sMess)));
}

I add a script to exit the trigger.

void main()
    {
        object oPC = GetExitingObject();
        object oRePoint2 = GetWaypointByTag("REST_ZONE_POINT_2"); 
        if (!GetIsPC(oPC))
            return;
        SetLocalInt(oPC, "RESTZONE", 0);
        FloatingTextStringOnCreature("Вы покинули зону отдыха. Отдых невозможен.", oPC);
        AssignCommand(oRe,JumpToObject(oRePoint2)); ///the trigger flies into the inaccessible zone
    }

What am I doing wrong? Maybe you don’t need to use AssignCommand? Just Jump To an Object or ActionJunpToObject? I need the Zone to appear through dialogue with the NPC and disappear when leaving it. Thanks!

1 Like

it’s very hard to understand what you’re trying to do.

Also, i can’t copy code in spoiler tags …

[code]

// code

[/code]

It sounds to me like … you have an NPC whose dialog sends the PC to an inaccessible area with a trigger. The PC walks into the trigger and … then the PC walks out of the trigger and …

1 Like

I didn’t know spoilers worked like this. Sorry for the translation.

I started to learn a Tutorial on NWN scripts by Celowin
https://neverwintervault.org/project/nwn1/other/just-faqs-maam

I want to teleport the trigger to the Waypoint, not the player to the trigger. Is it possible? Or how do I disable, enable the trigger? Thanks!

For starters, the third script does not compile because oRe is not defined (though it should be replaced by OBJECT_SELF, if I understood correctly), however, even if it did compile, I doubt it would work as I don’t think that actions can be assigned to non-creature objects.

Instead of teleporting the trigger, you should place two triggers (the second one being at the destination waypoint you originally had in mind) and have them disabled with a local variable depending on the progress made by the player. I tagged the second trigger as TRIG_REST_ZONE_2 , this is important to make the scripts below work to identify the second trigger properly. Also don’t forget to set the same On Entry and On Exit scripts on the second trigger as well if you haven’t already done so.

The 3 above scripts would be changed to the following:

Dialogue:

void main()
{
	object oRe = GetObjectByTag("TRIG_REST_ZONE");
	object oRe2 = GetObjectByTag("TRIG_REST_ZONE_2"); 
	SetLocalInt(oRe, "DISABLED", TRUE);
	SetLocalInt(oRe2, "ENABLED", TRUE);
}

On Entry Script:

void main()
{
	object oPC = GetEnteringObject();
        if (!GetIsPC(oPC)) return;
	
	object oTRIG = OBJECT_SELF;
	string sTRIG = GetTag(oTRIG);
	if (sTRIG == "TRIG_REST_ZONE")
	{
		if (GetLocalInt(oTRIG, "DISABLED") == TRUE) return;
	}
	else if (sTRIG == "TRIG_REST_ZONE_2")
	{
		if (GetLocalInt(oTRIG, "ENABLED") != TRUE) return;
	}
	
    SetLocalInt(oPC, "RESTZONE", 1);
    FloatingTextStringOnCreature("Вы в зоне отдыха. Можно отдыхать.", oPC, FALSE);
}

On Exit Script:

void main()
{
	object oPC = GetExitingObject();
	if (!GetIsPC(oPC)) return;
	DeleteLocalInt(oPC, "RESTZONE");
	
	object oTRIG = OBJECT_SELF;
	string sTRIG = GetTag(oTRIG);
	if (sTRIG == "TRIG_REST_ZONE")
	{
		if (GetLocalInt(oTRIG, "DISABLED") == TRUE) return;
	}
	else if (sTRIG == "TRIG_REST_ZONE_2")
	{
		if (GetLocalInt(oTRIG, "ENABLED") != TRUE) return;
	}
	
	FloatingTextStringOnCreature("Вы покинули зону отдыха. Отдых невозможен.", oPC, FALSE);
}

In the end, it should achieve the same result as teleporting the trigger from one place to the other.

Edit: oh crap, I just realized this is NWN1, let me check if this compiles properly there…
Edit2: Checked it on NWN1, it compiles just fine.

2 Likes

Thanks for your help! Okay, I’ll try this.

And what does function mean " != " in the last script?
I know that " == " compares values…

It’s the opposite of “==”.

“==” means “equal to” in comparative terms.
“!=” means “NOT equal to” in comparative terms.

1 Like

Wow! Amazing, it works! Thank you # Clangeddin. The issue has been resolved. D deal further on their own, with the help lessons :grinning:

2 Likes

FYI triggers cannot teleport in 1.69. Nor can items, waypoints and placeables. Only live creatures (that is, objects with an action queue) can successfully call (Action)JumpTo(Object|Location) functions.

1 Like

I upgraded your code. Initially, I wanted one area. Which would be activated during the dialogue and disconnected when you exit it.

Dialogue:

void main()
{
    object oRe = GetObjectByTag("TRIG_REST_ZONE");
    SetLocalInt(oRe, "ENABLED", TRUE);
}

On Entry Script:

void main()
    {
         object oRe = OBJECT_SELF;
         object oPC = GetEnteringObject();
         if (!GetIsPC(oPC))return;
    if (GetLocalInt(oRe, "ENABLED") != TRUE) return;
    SetLocalInt(oPC, "RESTZONE", 1);
    FloatingTextStringOnCreature("You are in a recreation area. You can relax.", oPC, FALSE);
    string sMess = GetName(OBJECT_SELF);
    if (sMess != "")
        DelayCommand(1.4, AssignCommand(oPC, SpeakString(sMess)));
    }

On Exit Script:

void main()
    {
        object oRe = OBJECT_SELF;
        object oPC = GetExitingObject();
        if (!GetIsPC(oPC)) return;
        SetLocalInt(oPC, "RESTZONE", 0);
{
 if (GetLocalInt(oRe, "ENABLED") != TRUE) return;
 FloatingTextStringOnCreature("You have left the recreation area. Rest is not possible.", oPC);
}
        SetLocalInt(oRe, "ENABLED", FALSE);
    }

Help me add more to Entry Script :

FloatingTextStringOnCreature("I need to ask permission to rest.", oPC, FALSE);

This should work when the Rest Zone is not active, when the character enters the inactive Rest Zone.
I tried just adding:

 if (GetLocalInt(oRe, "ENABLED") != or == TRUE or FALSE) return;

But they work all together, but not separately.

New Entry Script (not work):

void main()
    {
         object oRe = OBJECT_SELF;
         object oPC = GetEnteringObject();
         if (!GetIsPC(oPC))return;
    {
    if (GetLocalInt(oRe, "ENABLED") != TRUE) return;
    SetLocalInt(oPC, "RESTZONE", 1);
    FloatingTextStringOnCreature("You are in a recreation area. You can relax.", oPC, FALSE);
    string sMess = GetName(OBJECT_SELF);
    if (sMess != "")
        DelayCommand(1.4, AssignCommand(oPC, SpeakString(sMess)));
    }
if (GetLocalInt(oRe, "ENABLED") == TRUE) return;
FloatingTextStringOnCreature("I need to ask permission to rest.", oPC, FALSE);
}

Well, if you want to use a more general-purpose code, without needing to retag every separate trigger, you could use the following:

Dialogue:

void main()
{
	object oRe = GetNearestObjectByTag("TRIG_REST_ZONE");
        SetLocalInt(oRe, "ENABLED", TRUE);
}

On Entry:

void main()
{
	object oPC = GetEnteringObject();
	if (!GetIsPC(oPC)) return;
	
	object oRe = OBJECT_SELF;
	if (GetLocalInt(oRe, "ENABLED") != TRUE)
	{
		FloatingTextStringOnCreature("I need to ask permission to rest.", oPC, FALSE);
		return;
	}
	
	SetLocalInt(oPC, "RESTZONE", 1);
        FloatingTextStringOnCreature("You are in a recreation area. You can relax.", oPC, FALSE);

	string sMess = GetName(oRe);
	if (sMess == "") return;
	DelayCommand(1.4, AssignCommand(oPC, SpeakString(sMess)));
}

On Exit:

void main()
{
	object oPC = GetExitingObject();
	if (!GetIsPC(oPC)) return;
	
	object oRe = OBJECT_SELF;
	if (GetLocalInt(oRe, "ENABLED") != TRUE) return;
	
	DeleteLocalInt(oRe, "ENABLED");
	DeleteLocalInt(oPC, "RESTZONE");
	FloatingTextStringOnCreature("You have left the recreation area. Rest is not possible.", oPC);
}

For this to work there are two requirements though:

  1. The dialogue must NOT happen inside the trigger.
  2. The dialogue has to happen “near” the trigger you intend to activate. This means there would be one dialogue per trigger, close, but outside of it.

Maybe I misunderstood something, however, this appears to be something different than what originally asked in this thread, this is more like asking permission to rest in the closest rest zone.

1 Like

To avoid the location problems, use local string variable on the NPC to get the target trigger’s tag. Or build a list of triggers to enable them in bulk.

1 Like

Your script really works, as I wanted, and as it should be! Thanks friend! :slightly_smiling_face:

if(...) { /* code */ }
else if(...) { /* code */ }
else if(...) { /* code */ }
else { /* code */ }

Or use the less verbose switch statement if you wish to test several int constants against one variable (probably N/A in this case).

1 Like

I tried the “else if” editor writes a compilation error. Maybe I’m doing it wrong, it’s very difficult, each sign and its position means a lot. I’ll try … I’m waiting for a comment from Clangeddin :innocent: Well explains with examples

Compilation error…
11/21/2019 20:54:51: error. ‘dm_trig_rest_en’ is not compiled.
dm_trig_rest_en.nss (12): ERROR: OPERATOR “else” SHOULD BE USED TOGETHER WITH “if”.

Umm, why? :slightly_smiling_face:

Else must immediately follow if's compound, like this:

if(iFoo > 40)
{
    SpeakString("Foo is larger than 40")
}
else if(iFoo < 20)
{
    SpeakString("Foo is lower than 20")
}
else
{
    SpeakString("Foo is between 20 and 40")
}

You can chain as many else ifs as you want.

EDIT: how switch works: https://en.wikipedia.org/wiki/Switch_statement

1 Like

This seems strange, the code I posted above should work, I did not test it myself, however, there could be an issue of language barrier here, maybe I’m not understanding what you actually want to be done.
What I understood is that there’s someone you ask for permission to rest, and he gives you permission to rest to the nearest rest zone, and the scripts I posted above should exactly do that.

I’ll do some testing and see if there’s some unforeseen issues that arised.

1 Like

I have tested the scripts I made and they work as I intended them, maybe you meant something else?

As you can see from the video, triggers also tend to be laggy and wanky, so they might give the impression they’re not working at first, as they either stop the character or just plainly not recognize the on enter event and you must click on them a few times before they actually fire.

1 Like

The problem is this -

You Have (pseudo code)

if()
{
    code block
}
statement //this is the problem - compiler sees it as following the if() and not as part of it
else if()

With an if() You can either have a single statement or a code block. You cannot have a code block followed by a statement and then expect the compiler treat both as belonging to that if(). Which is why the following else if() throws an error.

As you are just starting out on scripting you might like to check this thread out. It has loads of links to tutorials and tools to help you.

TR

1 Like

( and that’s one good reason among others for standardized indentation )

2 Likes