OnClientEnter question

I had a weird problem when testing some things just now. I oftentimes use scripts on the OnClientEnter of an area. I’ve never had any issues with this before, but now I had some odd and worrying things happen, which made me doubt my own understanding of how the OnClientEnter of an area actually works…

This script ran the first time I entered the area but NOT the second time for some reason.

My understanding, which I now think is not right, is that the OnClientEnter only runs if the PC enters the area, but the OnEnter of an area runs everytime something enters? Is that correct. Anyhow, here’s my script:

void CheckArea()
{

object oPC = GetFirstPC();

object oArea = GetObjectByTag("Island");
object oCasper = GetObjectByTag("casper");

	if(GetArea(oCasper) == oArea)
	{
	
		SetLocalInt(OBJECT_SELF,"Done",1);
		SetCutsceneMode(oPC);
		AssignCommand(oCasper, ActionStartConversation(oPC, "c_casper", FALSE, FALSE, TRUE, FALSE));
	
	}


}

void main()
{

object oPC = GetEnteringObject();

if(!GetIsPC(oPC)) return;

SendMessageToPC(oPC,"The script is found and runs.");

if(GetLocalInt(OBJECT_SELF,"Done")) return;

DelayCommand(0.3,CheckArea());



}

EDIT: To Clarify: When testing this the object oCasper wasn’t in the area, so that bit of code was never run. Also, when switching to using this on the OnEnter of the area, it worked both times I when I entered, and then reentered the area (by going to another area and then coming back). By the way, this script is in my campaign folder, if that has anything to do with it.

Alright, NOW it gets interesting. I tried this script again on OnClientEnter, but this time I first went to this area, then to another area and then back again. And this time it worked!

So the curious thing is that before, when it doesn’t work, I used @kevL_s’ scripts with the Party Roster thingy I discussed in another thread. Here are those two scripts again (with additions from myself):

/*
    Door OnOpen script. Shows the PartySelect gui. Original script by kevL_s and previous script ideas by travus. Specific module additions and changes by andgalf.
*/

const string sROSTER_NELOWYN = "nelowync"; // note: this needs to be the *roster* string-id
const string sROSTER_WRENBUR = "gnome"; // note: this needs to be the *roster* string-i
const string sROSTER_LANIA = "leniac"; // note: this needs to be the *roster* string-i
const string sROSTER_FLEKSA = "fleksac"; // note: this needs to be the *roster* string-i
const string sROSTER_TINDRA = "tindra"; // note: this needs to be the *roster* string-i
const string sROSTER_SEMAPHINE = "semaphine"; // note: this needs to be the *roster* string-i

#include "ginc_gui"

void SelectYourParty()
{

    ShowPartySelect(GetFirstPC(),
					TRUE,         // modal
                    "jump_exit",  // callback script on Accept
                    TRUE);        // show close button

}

void main()
{

	SetGlobalInt("academygoout",1);
		
	object oTindra = GetObjectFromRosterName(sROSTER_TINDRA);
	object oSemaphine = GetObjectFromRosterName(sROSTER_SEMAPHINE);
	object oFleksa = GetObjectFromRosterName(sROSTER_FLEKSA);
	
	SetIsRosterMemberSelectable(sROSTER_NELOWYN,TRUE);
	SetIsRosterMemberSelectable(sROSTER_WRENBUR,TRUE);
	SetIsRosterMemberSelectable(sROSTER_LANIA,TRUE);
	
	if(GetIsObjectValid(oFleksa))
	{
		SetIsRosterMemberSelectable(sROSTER_FLEKSA,TRUE);
	}
	
	if(GetIsObjectValid(oSemaphine))
	{
		SetIsRosterMemberSelectable(sROSTER_SEMAPHINE,TRUE);
	}
	
	if(GetIsObjectValid(oTindra))
	{
		SetIsRosterMemberSelectable(sROSTER_TINDRA,TRUE);
	}
	
	
	DelayCommand(0.5, SelectYourParty());

}

/*
    Callback script for PartySelect gui. Set by 's_a1_leaveacademy' (door OnOpen
	script). Script by kevL_s.
*/

#include "ginc_transition"

void main()
{
    object oTarget = GetWaypointByTag("outsacad_wp");
    SinglePartyTransition(OBJECT_SELF, oTarget); 
	//destination must be in the same module, else use SaveRosterLoadModule()
}

When using these two scripts leaving another area, and entering the area with my OnClientEnter script, the OnClientEnter script doesn’t run. Why is that! It’s so odd!

followed by

SetLocalInt(OBJECT_SELF,"Done",1);

will make it run only once, this is a trick used to have a script run only once, in this case, on enter area it’s mostly done for initialisation which normaly is done only once

You set 1 the first time a player enter the area. and you check if 1 was set in that area. If it’s set you cut the execution.

1 Like

@Shallina - I’m afraid you are wrong about this in this particular situation. As I said,

So the CheckArea function never ran when testing this and that’s where I put the SetLocalInt(OBJECT_SELF,"Done",1);

And if following your logic, it wouldn’t have worked when I tried the other test without kevL_s’ scripts, and it worked perfectly fine there, so the whole issue seems to rather be something with the ShowPartySelect thingy or maybe the SinglePartyTransition…or something…

@kevL_s - I think I found the solution, since now it seems to be working. By changing your second script back to Colorsfade’s original one that looked like this seemed to solve this odd bug:

#include "ginc_transition"
#include "ginc_gui"


void DoTransition(object oTarget)
{
	object oPC = GetFirstPC(); 
	SinglePartyTransition(OBJECT_SELF, oTarget);
	
	object oPCF = GetFirstFactionMember(OBJECT_SELF,FALSE);
	while (GetIsObjectValid(oPCF))
	{
		CloseGUIScreen(oPCF,GUI_PARTY_SELECT);		
		oPCF = GetNextFactionMember(OBJECT_SELF,FALSE);	
	}
}

void main()
{

object oTarget= GetWaypointByTag("outsacad_wp");
DelayCommand(0.2f, DoTransition(oTarget));


}

So maybe for some odd reason you have to use the CloseGUIScreen for the bug to not be there.

strange … I tried it here on my end. transition from an exterior area /w door onopen to an interior waypoint. With companions in the party and without … the debug in an OnClientEnter script slotted on the destination area always fired as expected (using my original barebones scripts as posted)

anyway / just a note …

 
I have no clue why the gui seemingly needs to be closed, the cancel/accept buttons ought close the PartySelect screen auto.

*shrug :\

 
ps. I tend to think the 0.2f delay on SinglePartyTransition() fixes it if anything … rather than the calls to CloseGUIScreen()

2 Likes

Were you possessing a different PC?

i.e. It may fire if you are possessing your main PC, but maybe not if possessing a companion?

Just querying as I also have some strange behaviour in the early days, and I cannot recall what it was in the end. Even my own notes were “wrong” when I just checked them.

Try using a single PC as a test and see if it always fires then. Otherwise, maybe controlling a different PC at time of entry causes issues with the way it is.

Catch you later!

@kevL_s - Ah, so you think it might be the delay that’s the necessary bit here? Could be…I’ll test that tomorrow. Now I need some sleep.

@Lance_Botelle - I was possessing the main PC, as in the area where I go from I only have the PC, then the GUI happens when you choose which companions to come with you, you teleport the party, and with kevL_s’ jump_exit script I found the bug.

1 Like

@kevL_s - I did as you suggested and delayed the SinglePartyTransition with 0.2, and now it worked! Strange that it needs a delay there. Anyway, since it works now, I’ll go back to your script again (with the delay, of course) as I find it more logical and compact. So, for future me, if I get into a similar situation again, the script now looks like this:

// 'jump_exit'
/*
    Callback script for PartySelect gui. Set by 'dr_op_partyselect' (door OnOpen
	script).
*/

#include "ginc_transition"

void main()
{
    object oTarget = GetWaypointByTag("outsacad_wp");
    DelayCommand(0.2,SinglePartyTransition(OBJECT_SELF, oTarget));
}

Another thing with this that is a bit odd (I think, I’m not sure) is that when I loaded a save, to be in the right place and not have to replay stuff, I am in the area with the OnClientEnter, and when loading I didn’t get the SendMessageToPC message. However, if I play “from the beginning” (not really but…) and I arrive in the area, since I placed the SetStartLocation there, I get the message. But everytime, in both cases, when I go to the other area, and from that other area do the Party Select and teleport out to the area with OnClientEnter, I get the message. I thought that even if you load a save, you “enter” the area where the save is at, and that should fire the OnClientEnter, but maybe that’s not correct?

1 Like

well… i did my test on a barebones test-module setup. You’ve no doubt got all kinds of stuff going on … placeables to load etc etc etc. Perhaps the engine just needs a fraction of a second to work all that extra stuff out …

uh… when loading a game the splash screen(s) tend to hide messages to the chatbox, or causes them to be bypassed … if you want/need accurate debug during such events you’ve got to go with PrintString() to the NwN2 logfile

2 Likes

Aha. Didn’t know that. Interesting. Well, then nothing’s wrong, I guess. I just wondered if I had found another bug I needed to adress.

1 Like

A few days ago I noticed some more interesting things about this. As far as I can tell if you have this code on the OnClientEnter:


object oPC = GetEnteringObject();

if(!GetIsPC(oPC)) return;

Then, when loading a save, the game doesn’t recognize the entering object…or something. When I removed this, the script ran and everything was fine. So I’m beginning to suspect that somehow the game doesn’t check for an entering object when you load a save. Maybe (loading a save that is) it doesn’t recognize that as “the player/player character entering an area”. In this particular case of mine it was obvious, since I had a creature I wanted to lie down, and it didn’t lie down when loading the save if I used the GetEnteringObject thing, but when skipping that (I used a check for an integer instead if the script was to run or not) the creature lay down all the time.

“if it is not a player controled character at the moment that is entering the object then exit the script.”

that s what is written in those 2 lines.

Yes, of course. I know. What do you mean? :melting_face:

When you load a save and enter the area, the player controlled character is entering the area.

and you exit the script and don’ t execute what’s after so it’s normal that nothing happens

What? :expressionless:

Did you actually read my previous posts?

EDIT: I know what the script does. That’s not the problem here. Again:

I’m no scripter so I might be talking nonsense but I think you’re both looking at this from different angles as I’m a bit confused too.

Is it that you enter the area then save, reload and the script isn’t running any more ? Which probably has something to do with the computer thinking I’ve already done that and nobody’s entering because you’re already in, so why do it again. Maybe the integer is just stored differently and the on enter is a one hit wonder.

Or that you save from outside the area then enter after reloading and it doesn’t work now because that’s weird and means that any save outside the area will stop it working which can’t be right.

@andgalf

Many years ago I also noticed some strange behaviour with reloading a game. So much so that I even (at one time) altered an XML that forced a player to reload from the main menu rather than the base load.

I have forgotten the specifics, but your comments sound familiar to me. I’ll try to locate the post and link it here, and/or try to recall what I actually did to avoid the issue.

Here’s that post I was referring to …

Maybe you can test your situation by the way you reload the game … Try reloading from the Main Menu and not the other way … Make sense?

HOWEVER, since writing that post, I have reverted back to the original XML and allow loading as usual now, so maybe I found an alternative solution to the problem. The point is, though, I also discovered some unusual things happening on the Load Game (that was not via the Main Menu). I will try to see what else I may have done and post back.

EDIT: OK, I found out what was happening by the looks of it, as I have this note in my own area OnClientEnter script notes … Unfortunately, I cannot find the text I quoted.

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// QUOTE: THIS SCRIPT FIRES AFTER THE AREA HAS FINISHED LOADING - SO WILL ONLY FIRE FOR ONE PLAYER
// UNLESS MP PLAYERS ARE JOINING AT A LATER TIME. (ONCE IN GAME ONLY FIRES ONCE PER AREA LOAD FOR HOST!)
// THEREFORE, WE NEED TO CONSIDER USING ALB_AREA_ENTER FOR CODE THAT THEY ALL NEED EACH AREA LOAD
// I ALSO BELIEVE THAT THE ALB_AREA_ENTER (ON AREA ENTER) FIRES *BEFORE* THIS SCRIPT THEN!
// !!!!!!!! MOSTLY TRIGGERS ONLY WHEN THE LEAD PLAYER ENTERS THE AREA !!!!!!!!!!!!!!!!!!
// !!!!! NB: THE DM COULD BE THE HOST, SO WE NEED TO CHECK VIA PC LEADER !!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

I do not include this condition in my own area OnClientEnter, as I believe the script is supposed to run as soon as the area loads, and so we can assume oPC is the main PC anyway. Maybe (for some reason) the condition is not always reliable from this point of view.

i.e. It’s safe not to include this condition check … as the PC will be the host regardless, I suspect. (Or maybe another player in a MP game.)

Furthermore, if you want to ensure an area entry script fires for every creature, you need to use the Area On Enter Script to do that. The OnClientEnter is used more for area setup and variables rather than anything PC specific.

For Players (Main PC’s only): OnClientEnter
For any PC (inc companions): OnEnter

1 Like

Could be, yes. I thought that the game would consider one entering the area when you load the area, but that seems not to be the case…At least I don’t think so, but that’s what this whole thing is about. This is what I wanted to know, what all my questions were about. I would want to know the answer to this about how the game considers things in this case.

Yeah, maybe. I always thought that if you do the On Area Enter thing, the game will run this script as soon as any character moves in an area, and thus slows the game down if you have many areas with such a script, and the On Client Area thing runs when a player character is entering the area. Me including this script with if(!GetIsPC(oPC)) return; is maybe redundant because the game only runs this script when a player enters the area anyway so it might be unnecessary to check this.
In any case, by me including this, perhaps, unnecessary thing, I noticed the OnClientArea script is not run if you load an area your character is already in. I always assumed since the game says it loads an area, when you load a savegame that is, that that way it will always run this script, but maybe it only runs that type of script when you teleport your character from one area to another, and not when you are already there, even if you load a savegame.

EDIT: Since NWN2 loves delays in its scripts. Maybe, just maybe, if I would do a delay on the whole script, it would run even when you load a game (and the character is in that area). I think I’ll test that.

EDIT2: I tested the delay. That changed nothing. I even tested loading from the main menu but that didn’t change anything either.

So, it seems that to me, in conclusion: When loading a savegame with an area your main character is already in, that doesn’t count as the main character entering the area although the game has always made me think that it did. Only when teleporting from another area, and the game loads the new area, does it seem to count as the character “enters” the area.

EDIT3: No, scratch that, this can’t be right… it’s still a very odd. If OnClientEnter is only supposed to run when the main character enters the area, it shouldn’t run at all when loading a savegame, and it still does run for me. However, if I put the

object oPC = GetEnteringObject();

if(!GetIsPC(oPC)) return;

it exits since it doesn’t recognize the main character entering the area…but it’s only supposed to run when the main character enters the area… :woozy_face: :crazy_face:

So, the way I have it working on one area now (I have tested it) is by doing the following:

  1. I wrap the whole OnClientEnter script in a function.
  2. I run that function in the main script by doing a 0.3 second delay.
  3. In the script I write like this instead, and that seems to work great:
object oPC1 = GetFirstPC();
object oArea = GetObjectByTag("Forest");

if(GetArea(oPC1) != oArea) return;

This way the game doesn’t check for any entering of the area, it just looks for if the main character is already, at the moment, in the area. For that to work properly, we need a delay to really make sure the main character is loaded into the area when the check comes.