Make NPC Close Door and Lock Door

I’ve got a couple short scripts that cause my door to close and lock just fine but I really want to step it up and be able to make an NPC in the same area actually walk to the door and close and lock it. I’ve searched and found scripts that cause this but only based on it being initiated by conversation. I don’t want it done from a conversation. I want it to happen ON_EXIT from an area. I would really appreciate the help.

I assume you mean just prior to the PC exiting the area. If it was on exit, you surely wouldn’t see anything. Without more information, the way I would go about this is to place a waypoint immediately in front of the door, facing the door. I would then place a generic trigger over that waypoint. Finally I would have a generic trigger placed somewhere in the vicinity, where the PC must cross in order to exit the area. In this latter triggers OnEnter script you place tests to make sure it only fires when the PC has done whatever the PC needs to do in order for the NPC to feel like locking said door. Assuming these conditions are met, you tell the NPC to walk to the waypoint. When the NPC reaches the waypoint the associated generic triggers OnEnter event will fire. Make sure that the code you write for closing and locking the door only fires for that NPC. Use the OnEnter event for whatever animation you want and then lock the door.

BTW Have you got the scripting FAQs? Also a couple of useful collections of old scripts here and here?

TR

Adding to that -

You can run whatever code you like from whatever source you like. Usually, to turn a conversation script into a different kind (OnEnter.,. OnExit… OnPlayerChat…), all you need is to use different functions to determine the objects involved.

GetEnteringObject() is for OnEnter events, GetExitingObject() is for OnExit events, just as GetPCSpeaker() is for finding the player speaker involved in a conversation or GetPCChatSpeaker() is for the OnPlayerChat event.

A floor trigger’s OnEnter event is one option. If you put it in the area’s OnExit event, the player will never see the NPC walk to the door and close it, because they’ll already be in the loading screen and then off into the new area.

I think ActionCloseDoor() should work without waypoints or playing animations/closing the door manually. Best call ClearAllActions() on them first, too, so they quit whatever else they might be doing and go straight to close the door.

AssignCommand(oNPC, ClearAllActions());
AssignCommand(oNPC, ActionCloseDoor(oDoor));

I’ve never gotten aborting area exiting to work via an area’s OnExit event (), but you can make the area transitions (doors, floor triggers) prevent or delay the area transition long enough for the PC to see the door being closed. Use the OnClick, or OnAreaTransitionClick, events for that.

object oPC = GetClickingObject();
object oNPC = GetNearestObjectByTag("NPC");
object oDoor = GetNearestObjectByTag("DOOR");
location lTarget = GetLocation(GetObjectByTag("LOCATION"));

AssignCommand(oNPC, ClearAllActions());
AssignCommand(oNPC, ActionCloseDoor(oDoor));
DelayCommand(3.0, AssignCommand(oPC, JumpToLocation(lTarget)));
2 Likes

Relying on NPC actions can be tricky. At minimum, use SetCommandable to prevent interruption, as shown in some of the Lexicon examples.

ActionCloseDoor will do the movement, unless blocked by some other wandering NPC or whatever.

If it’s mission-critical, you need belt-and-braces. Either tell the door to close and lock itself OnExit (even if the NPC never made it to the door) or run a pseudo-heartbeat with ForceMoveToObject that keeps kicking the NPC until the door is actually closed and locked.

Clearly, the scene must play out before OnExit, otherwise the player won’t see it. Also, on exit or when there are no players in the area, NPC AI level might not be high enough to perform an action reliably, unless you explicitly SetAILevel.

2 Likes

I want the script to be fired ON_EXIT of an area because that area is not the same area that my door is in. The area that the door is in is the area that the PC will enter immediately after leaving the room (ON_EXIT) so the action would be seen by the PC unless the PC immediately runs out of that area also. Think of it this way. PC enters the town Inn. PC buys room key from NPC. PC opens room key with door. Key is removed. PC exits (ON_EXIT) room after resting. This is the time frame that I want Inn Keeper NPC to move to door, close and lock it. I do not want this script to be fired from conversation. I do not want the PC to need to tell the Inn Keeper that he/she (PC) is finished with the room. I want it fired sometime, about 5 seconds after leaving the inn room.

So, I’ve tried executing the following script ON_EXIT of the room PC has just arrived from. It’s not working. Any obvious reason?

void main()
{
object oNPC = GetNearestObjectByTag(“INN_KEEPER”);
object oDoor = GetNearestObjectByTag(“BIREnt”);
AssignCommand(oNPC, ClearAllActions());
DelayCommand(5.0,AssignCommand(oNPC, ActionCloseDoor(oDoor)));
}

GetNearestObjectByTag defaults to looking for the nearest object to the caller unless you specify a “source” object. In case of your OnExit event script here, that’s the area you’re exiting from.

Since INN_KEEPER and BIREnt are in a different area entirely, I’d wager that GetNearestObjectByTag just isn’t finding them. Try switching to GetObjectByTag, or else specify a source that’s within the new area.

I tried this and still nothing at all.

void main()
{
object oNPC = GetObjectByTag(“INN_KEEPER”);
object oDoor = GetObjectByTag(“BIREnt”);
AssignCommand(oNPC, ClearAllActions());
DelayCommand(10.0,AssignCommand(oNPC, ActionCloseDoor(oDoor)));
}

Alright, I’ve set the scenario up in a test module, and the problem is the delayed command. Maybe the area doesn’t want to run scripts anymore if there is no PC in it.

To work around that, you could do it like this, without delays:

AssignCommand(oNPC, ClearAllActions());
AssignCommand(oNPC, ActionWait(3.0));
AssignCommand(oNPC, ActionCloseDoor(oDoor));

… or else run the code from your inn area’s OnEnter event instead.

Did it work for you? Nothing regarding the NPC is working at all. I’ve tried to figure a work around. I have the door lock itself after PC exits the room. It works fine. So, I figured I would try putting the close door script in the “OnLock” of the door. That doesn’t work either. It’s like I can’t get the NPC to do anything. Sorry, yes I also tried your solution but that didn’t work either. I don’t want to try firing it OnEnter because that means NPC would go and close the door from PC just entering the inn from the outside also.

Have you checked whether the tag matches? The test scenario is working for me.

Try putting in a debug message; make the NPC SpeakString something, or send the name of the NPC (via SendMessageToPC(oPC, "The NPC is "+GetName(oNPC)), to check whether you’re finding and targeting the right object.

If there is more than one object with that tag in the module, it’s possible you’re targeting another INN_KEEPER elsewhere.


You could use the inn room area’s OnExit script to set a variable on the PC, which you check for and remove again in the inn’s OnEnter event, to only have the door-closing happen after the PC just exited their inn room. It’s a little clunky, but it makes using OnEnter viable again.

1 Like

I’m glad you asked me about the tags matching, It turns out, the tag I was using in the script was not the same as the NPC tag. I’m sorry for such a blunder and you may now laugh at me as much as you want. Thank you though. I really appreciate the help.

2 Likes

Happens to me, too. ^^ It’s such an “ARGHGHGHGH!!!”-moment, every time. Watch out for the compile trap, too - if you’re making changes to a script library, you need to compile all the scripts that use it (Build -> Build Module, with Compile -> Scripts ticked active), or the changes may not take effect and you’ll be left spending hours and hours searching for the nonexistent error.

1 Like

Sounds like you have something working, but normally this would be done OnEnter to the new area, perhaps using a cutscene to immobilise the PC for the duration. That way, both the area and the actor are active objects at the time.

OnExit is not quite as moribund as assigning commands to a dead NPC, but you get the idea - safest to use it for immediate commands only.

Yes, I have it working great now except now I am also trying to do a couple more things involving the same NPC. I am working on preventing the NPC from being interrupted from finishing the task such as being talked to by the PC or being attacked or really any action that would normally interrupt the NPC. Also, I am trying to use SetFacing to make the NPC face West after finishing his move back to his way-point (his store) so that he faces his desk. Question: If PC leaves the area (the inn), will the NPC continue the action in that area or does it get interrupted by PC exiting that area? Sorry I didn’t think enough before asking that question. I just performed the test and the NPC apparently freezes while PC is not in the area but he does resume the task when PC enters back into the area. I don’t mind it too much but I would prefer for time to not stop simply from the PC not being in the area. Any way to make the NPC resume the task while PC is not in the area?

I don’t know about making things continue happening in areas in absence of a player in them, but applying a cutscene domination effect to an NPC makes them immune to interruption by conversation. :thinking:

You could make the doors close themselves on area exit if the leaving player is the only player in the area, and return the innkeeper to his default position instantly, resetting the scenery.

That SetCommandable link I posted above shows how to prevent the NPC from being interrupted by AI, PC conversation or combat. They will just carry on with the assigned task unless blocked or killed.

EffectCutsceneGhost will prevent blocking. Occasionally looks slightly odd as the NPC glides through onlookers, but better than failure.

Plot flag will prevent death. In general, NPCs who have something important to do probably ought to be plot anyway, in case of collateral damage. A neutral faction will prevent attack by other toons, but the plot flag provides protection from PCs, too.

3 Likes