Aller au contenu

Photo

Make NPCs disappear at night?


  • Veuillez vous connecter pour répondre
34 réponses à ce sujet

#1
Groove Widdit

Groove Widdit
  • Members
  • 378 messages
This is probably easy, but I couldn't come up with any google luck. How do you make npcs who disappear at night--townsfolk who go home--then appear again in the morning. I've played mods where they actually walk up to a specific doorway and disappear, but I don't want to do that. Thanx!

#2
kamal_

kamal_
  • Members
  • 5 238 messages

Probably the easiest way is in the area heartbeat script, check the time of day. If it's after the time you want them to disappear, loop through the npcs and make them script hidden. In the morning, un-scripthide them. You probably want to store this hidden value on the npc, and run a check to make sure it's set appropriately before hiding/unhiding so you're not hiding/unhiding them every heartbeat when they are already appropriately hidden/unhidden.

 

Alternately you could build that same logic into the heartbeat script of the individual npcs, a check on time of day. There's also IsNight and IsDay functions if you want less precise control over the time they disappear, IsNight and IsDay I think are coded for specific times.

 

Uncle FB's npc control and my commoner generics ai both allow for going to actual places at night, so you probably saw one of those.



#3
Tchos

Tchos
  • Members
  • 5 030 messages

It's easy, especially if you don't want them to walk up to specific doors.  Several ways to do it, but I think the most efficient way would be to have a single heartbeat script that checks the time (rather than putting the code in the heartbeat scripts of each NPC).  With that heartbeat you can do a lot of things, but let's say you just use it to make the NPCs come and go.

 

So the heartbeat checks the time.  The heartbeat can be on the area.  If it's not the right time, it does nothing.  When it's time to make the NPCs disappear, it cycles through each NPC in the area.  It can check for a particular name prefix or suffix, tag, local variable, whatever you want to use to identify which NPCs disappear.  Then make those NPCs script hidden, or maybe send them to limbo, if that function works.  Do the opposite at the time for them to reappear.



#4
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages

You also have to run the script on area-enter, in case dusk came while the player was off in another area.



#5
Tchos

Tchos
  • Members
  • 5 030 messages

What, do area heartbeats behave differently, and not run all the time as other heartbeats do, even when you're not in the same area?



#6
Dann-J

Dann-J
  • Members
  • 3 161 messages

I recently implemented NPCs who go home at night in the module I'm (occasionally) working on. I do it from the individual NPC's heartbeat script, so that each NPC can go home and return at a different time (so no mass exodus occurs).

 

The simplest method I came up with was to have two versions of an NPC; one outside and another inside. Each version of the NPC has a series of variables set on them:

  • Door (string)
  • Time1 (int)
  • Time2 (int)
  • OtherTag (string)

When their heartbeat script detects that the time is within the range of Time1 to Time2 (courtesy of a useful little function in ginc_time), they attempt to open the door with a tag that matches their Door value (walking over to it first if they're not right next to it). The attempt is only made if they're not in combat or conversation, and their action queue is empty.

 

The door has an OnOpen script that checks for the existence of an OtherTag string on the user. If it finds a valid string, them it hides the user and unhides the NPC with the same tag as their OtherTag string. Each version of the NPC has a different (non-overlapping) time range during which they head for their respective doors.

 

For instance, the outdoor version of one NPC will attempt to go home between 10pm (Time1 = 22) and 6am (Time2 = 6). Unless you keep them busy talking they generally head straight for their (outside) house door at 10pm, but if they're busy they'll keep retrying up until 6am. The indoor version of the NPC will head for their own door (inside the house) between 7am (Time1 = 7) and 9 pm (Time2 = 21). I had to make sure the two time ranges didn't overlap, otherwise they developed obsessive compulsive disorder (repeatedly heading back and forward during the overlap period).

 

The two scripts I'm using (NPC heartbeat and door OnOpen):

Spoiler

  • Groove Widdit aime ceci

#7
Groove Widdit

Groove Widdit
  • Members
  • 378 messages

Okay, this is what I've got for the area heartbeat. It won't compile--I get: "DECLARATION DOES NOT MATCH PARAMETERS" on the townie lass line.

 

#include "ginc_time"

void main()
{
int iHour = GetTimeHour();
if (iHour > 6)
    {
    DelayCommand(1.1, SetScriptHidden("Townie Lass", FALSE));
    }
    if (iHour > 22)
    {
    DelayCommand(1.0, SetScriptHidden("Townie Lass", TRUE));
    }
}



#8
Tchos

Tchos
  • Members
  • 5 030 messages

SetScriptHidden needs to have an object in that spot, not a string like "Townie Lass".  Declare an object with GetObjectByStringTag("Townie Lass").

 

Note that this will only do it to the first object it finds by that string.



#9
Dann-J

Dann-J
  • Members
  • 3 161 messages

It will also make that one NPC blink in and out of existence once every six seconds between 10pm and midnight, since both if statements will then be true. Admittedly you might not notice the 0.1 seconds during which they're visible. It will do nothing between midnight and 5am (hours 0 to 5).

 

If you're using ginc_time, then the IsCurrentHourInRange() function might be a better option.



#10
Groove Widdit

Groove Widdit
  • Members
  • 378 messages

Okay, I changed it to the below, and now I'm getting "ERROR PARSING VARIABLE LIST" on the object line.

 

#include "ginc_time"

void main()
{
int iHour = GetTimeHour();
object oTownie = GetObjectByString("Townie Lass");
if (iHour == 6)
    {
    DelayCommand(1.1, SetScriptHidden(oTownie, FALSE));
    }
    if (iHour == 22)
    {
    DelayCommand(1.0, SetScriptHidden(oTownie, TRUE));
    }
}



#11
Tchos

Tchos
  • Members
  • 5 030 messages

Sorry, I miswrote the function.  It's GetObjectByTag, not GetObjectByString.

 

Ultimately, you'll want to create a loop that iterates though all creatures with that tag and makes them all appear or disappear, assuming you plan to have more than one.



#12
Groove Widdit

Groove Widdit
  • Members
  • 378 messages
Ah, it compiled! Yeah, I'm going to do something like that. I still can't get her to disappear, but I can't work on it anymore tonight. Thankx! Happy Fourth! RESISTENCIA!

#13
Groove Widdit

Groove Widdit
  • Members
  • 378 messages

She's not disappearing. I start it at five and she's out there. Shouldn't the below make her disappear?

 

 

#include "ginc_time"

void main()
{
int iHour = GetTimeHour();
object oTownie = GetObjectByTag("Townie Lass");
DelayCommand(1.0, SetScriptHidden(oTownie, TRUE));
if (iHour == 6)
    {
    DelayCommand(1.1, SetScriptHidden(oTownie, FALSE));
    }
    if (iHour == 22)
    {
    DelayCommand(1.0, SetScriptHidden(oTownie, TRUE));
    }
}



#14
Tchos

Tchos
  • Members
  • 5 030 messages

No, because if you start at 5, then the condition that the hour equals 22 hasn't happened yet, so she has never been set hidden.  The way you have it set now, it will only happen if the script is running on those particular hours.  You need more complex checks, like checking "the hour is greater than or equal to this number, but less than this other number, and the character is/isn't already hidden".



#15
Groove Widdit

Groove Widdit
  • Members
  • 378 messages
I guess I don't quite understand this. Shouldn't this line hide her?: DelayCommand(1.0, SetScriptHidden(oTownie, TRUE)); But now that I'm looking at my code, that would hide at the beginning of every heartbeat.

#16
Groove Widdit

Groove Widdit
  • Members
  • 378 messages
Doesn't the area heartbeat run every six seconds around the clock?

#17
kamal_

kamal_
  • Members
  • 5 238 messages

The default time when you start the game is 12 (noon), so you'll be waiting a long time ingame to test that unless you have a time wand or the SLS time girl npc.

 

Also, it will fail if you jump the time by advancing it past those times, as the set time and advance time by x hour functions do not make the intervening times happen. If the time is 5 and you set the time to 8 or advance the time by 3 (so it's 8), then 6 and 7 never happen. Additionally, you would want to have else if instead of if on that second check, for performance reasons if you're going to be doing this for a lot of npcs.

 

Tchos mentioned checking if they are already in the correct hidden/non-hidden state, you need to do that so they don't get repeatedly hidden/shown on each heartbeat of the relevant hours. It makes the performance of the first heartbeat of the given hour slower, but likely speeds up all the other heartbeats of that hour.

 

You could look at how I handled doing things in a given time period in my ai, I got all that time stuff figured out (and more importantly, tested).

 

A style point: I hate spaces in tags.



#18
Tchos

Tchos
  • Members
  • 5 030 messages

Ah yes, I missed that line, and yes, it would hide her every heartbeat.  Also, is "Townie Lass" her tag, or her name?  As Kamal suggests, you might want to remove the space if it's in her tag.  At any rate, you need to use the tag in the script for the function GetObjectByTag to work.



#19
Groove Widdit

Groove Widdit
  • Members
  • 378 messages
Okay, got it. Can't you set the module starting time in the mod properties? That's what I was trying to do and it seemed to work.

#20
Shallina

Shallina
  • Members
  • 1 011 messages

best way is to take something which al rdy work and adapt it to your need.

 

I did day /night cycle in every major city area of the baldur's gate reloaded mode. Just check how it 's done.



#21
Dann-J

Dann-J
  • Members
  • 3 161 messages

My scripts posted above work fine. You could adapt the NPC HB script to your needs. Then each NPC that is intended to hide can run their own script, avoiding the need for loops from an area HB. Something like this should work, even if you advance the time:

#include "ginc_time"

void main()
{

int iTime1 = 6;
int iTime2 = 22;
int iHour = GetTimeHour();

// Between 6am and 10pm, appear if not visible
if (IsCurrentHourInRange(iTime1, iTime2) && GetIsScriptHidden(OBJECT_SELF, TRUE))
	{
	SetScriptHidden(OBJECT_SELF, FALSE);
	}

// Between 11pm and 5am, disappear if visible (and not busy)
if (IsCurrentHourInRange(iTime2+1, iTime1-1) && GetIsScriptHidden(OBJECT_SELF, FALSE)
	&& !IsInConversation(OBJECT_SELF) && !GetIsInCombat(OBJECT_SELF))
	{
	SetScriptHidden(OBJECT_SELF, TRUE, FALSE);// Keep HB running while hidden
	}

// Run the standard creature heartbeat script
ExecuteScript("nw_c2_default1", OBJECT_SELF);
}



#22
Tchos

Tchos
  • Members
  • 5 030 messages

Personally, it feels cleaner to me to have one master control heartbeat script that checks the time once per tick to affect a groups of NPCs, rather than all of those NPCs checking the time independently in their own heartbeats.  Not that it's significant for something like this...



#23
Dann-J

Dann-J
  • Members
  • 3 161 messages

I went for individual HBs in my case because I was storing different disappear times on my NPCs. That way you don't get a mass exodus at knock-off time. Although my solution is a fancier one, where they walk to a door, open it, disappear, and a second version of them is unhidden inside their home. The second version of the NPC has opposite disappear times, using the same set of scripts but with different local variables.

 

Since NPCs are running HB scripts anyway, a few more lines in the script shouldn't slow things down too much. Although my modified solution above makes them run their HB scripts while hidden. All that does though is to make things run at a consistent speed all the time, whereas the area HB approach would speed things up at night (when a whole lot of NPCs are no longer running their HB scripts).



#24
kevL

kevL
  • Members
  • 4 052 messages
don't underestimate the value of Random() when trying to create human behavior ...

#25
Dann-J

Dann-J
  • Members
  • 3 161 messages

don't underestimate the value of Random() when trying to create human behavior ...

 

Especially when alcohol is involved... :blink: