How to add NPCs that roam between passages

Hi again! Sorry, but this is probably going to be my most complicated request.

I’m trying to create some NPCs that move between specific passages and can move to different passages when the player takes a major action. To define a major action, something like talking to a different NPC, getting something to eat, using the bathroom, or studying. For something like this, I’d imagine I’d have to implement some sort of time system so that each action takes up a specific amount of time, which is also something I’m not really sure how to add in.

Just to clarify, I haven’t made any actual NPCs yet either since I don’t know how to. I’ve seen HiEv’s older replies on how to make NPCs and how to get them to move, but I’m still pretty confused on how it works.

At the moment, player movement is done by using buttons to go to different passages like so:

<span id = "buttons1">
<<button "Kitchen">><<replace #buttons1>>

<<goto [[Kitchen]]>>

<</replace>><</button>>

<<button "Bathroom">><<replace #buttons1>>

<<goto [[Bathroom]]>>

<</replace>><</button>>

<<button "Upstairs">><<replace #buttons1>>

<<goto [[Upstairs]]>>

<</replace>><</button>>
</span>

I want that in each location, the player can have unique interactions with the NPC, like different dialogue choices or action choices, but the options are still there if the player returns to that location with that same NPC in that location at the same time. I’d also like something to track each NPC’s current location inside of those buttons, with something like

Upstairs - $name1 is here

or 

Upstairs - $name1 and $name2 is here

Basically, what I want are four things:

  1. How to create NPCs
  2. How to create a routine where NPCs move to different passages based on the time and day
  3. How to track where NPCs are on button locations
  4. How to create a time and day system that determines when NPCs move

Sorry if that sounded confusing, but that’s about it for my request.

1 Like

Parts of this are quite similar to something I’ve done recently, but for moving PCs, so I’ll share my approach:

  1. You can create objects for NPCs in the StoryInit special passage. Include the starting location for each NPC.
<<set $james to {
	name: "James",
	location: "Kitchen",
	}
>>
  1. For this, you have to figure it out for yourself in a way that fits your game, but in general, you should put a code somewhere that sets the NPC’s “location” parameter, like <<set $james.location to "Garden">>. Make sure you always spell the locations the same way the corresponding passages are named.

You can also do thins like <<set $james.location to passage()>> to “bring” the NPC to the passage the player is currently in, as if they followed the player.

  1. In each “location” passage, add code to check if the location of the NPC equals passage name. If so, include the content of the passage named after the NPC, where you can put the interactions.
<<if $james.location == passage()>>
<<include "James">>
<</if>>

→ If James’s location equals the name of the current passage, the contents of the passage named “James” are displayed.

You can put this code in PassageFooter or create a widget for it, so that you don’t have to paste it into every “location” passage.

  1. It very much depends on how basic/complex you want this to be, but for a simple example: you can setup a $hour variable in your StoryInit, assign some value to it that is the initial time, and then create widget to add hours (put it in a “widget”-tagged passage):
<<widget "addhours">>

<<set $hours += $args[0]>>

<<if $hours  > 23>>
<<set $hours to 0 + ($hours - 24)>>
<</if>>

<</widget>>

(this goes from 0 to 23 and wraps)

Then, you can call the widget when the player clicks a link to perform an action:

<<link [[Make dinner|Kitchen]]>><<addhours 1>><</link>>

This adds 1 hour (the numer is represented by $args[0] in the widget code, and you can of course change it).

You’ll then have to figure out where to put the code which will change the locations of your NPCs if the hour is/is later than a particular value. You could, for example, create another widget to check it and call it inside the <<addhours>> one.

4 Likes

This is all good stuff, thanks for sharing!

How would I do that? In HiEv’s forum he mentioned this as well, but I don’t know how to make one.

As shown in the example above: <<widget "addhours">>...<</widget>>. See also the <<widget>> documentation.

1 Like

I didn’t see that before, that’s for that!

An additional question, if I wanted to create a time system based on general time zones rather than by hour, like a day cycle: early morning → late morning → early afternoon → late afternoon → evening → night → midnight; how would I do that? Would I change the widget to being named “daytime” and then create some new variable for it?

1 Like

A note on this: the wodgets can be named however you want (except they can’t use names of existing SugarCube macros, like “replace”), but it’s best to keep the names descriptive.

There are several approaches to creating a day cycle, and there are even available systems for really advanced time-keeping like Chapel’s Cycles system.

But if you need something simple, with only a few phases to cycle through, you can also use one of these approaches:

For simplicity’s sake, in the following example I’ll only use 4 day phases: Morning, Afternoon, Evening, Night.

  1. The simplest, rather inelegant method is to use an if-statement when you advance time, to check what the current phase is and advance to the next one.
<<widget "advancetime">>

<<if $time == "Morning">><<set $time to "Afternoon">>
<<elseif $time == "Afternoon">><<set $time to "Evening">>
<<elseif $time == "Evening">><<set $time to "Night">>
<<else>><<set $time to "Morning">>
<</if>>

<</widget>>

This can work if you only have a few phases, but if you want to advance twice in one action, you’ll have to call the widget twice: <<link [[Do something|Next passage]]>><<advancetime>><<advancetime>><</link>>. You’ll also need to set your initial phase in StoryInit: <<set $time to "Morning">>

  1. You can make an array with your phases in StoryInit:
<<set setup.phases to ["Morning", "Afternoon", "Evening", "Night"]>>

(I’m using the “setup” object here, because the available phases will never change during the game. Data in the “setup” object will not be stored in your StoryHistory and save files.)

Also in StoryInit, I set the initial time: <<set $time to 0>>

Arrays in SugarCube are 0-based, so “Morning” is at index 0 and Night is at index 3. You can print a member of the array in your game using its index: <<print setup.phases[$time]>>

You can then adapt the “addhours” widget so that it only goes from 0 to 3 and changes your $time variable:

<<widget "addtime">>

<<set $time += $args[0]>>

<<if $time  > 3>>
<<set $time to 0 + ($time - 4)>>
<</if>>

<</widget>>

Now you have a time system which cycles through 0-3, and you can choose how many phases to advance at once, e.g. <<addtime 2>>. You can also print the names of the phases, so the player sees them instead of numbers.

When checking if it’s a certain time in your code, you can use either <<if $time == 3>> or <<if setup.phases[$time] == "Night">>.

3 Likes

Since for this game I’m using buttons instead of links, would it look like this instead?

<span id = "buttons1">
<<button "Make food">><<replace #buttons1>>
<<button "Make food">><<addhours 1>><</button>>

You made some food.

<span id = "button1">
<<button "Leave">><<replace #button1>>
1 Like

It’s very similar with buttons - just put any widgets/other code you want to run when the button is clicked between <<button>> and <</button>>.

(Note: In your first example, there is an unnecessary second <<button>> part and the <span> element and <<replace>> macro aren’t closed. In the second example, the <<button>> & <<replace>> macros and the <span> are not closed. Maybe you only copied part of your code, since your original post in this thread does this all correctly. Also note - if you’re displaying your current time to the player somewhere in the passage, you should wrap it in a <span> and use <<replace>> on it, so that it updates properly.)

1 Like

With the help of the Modulo operator, you can simplify this to (works with any number even ):

<<widget "addhour">>

<<set $hours += ($hours + $args[0]) % 23>>

<</widget>>

let say $hours set to 23 and $args[0] is 12
basically it takes $hours + $args[0] (23 + 12 = 35)
divides 35 by 23 and gives out the remainder = 11

this should works with the Day Phases

<<widget "addtime">>
<<set $time += ($time + $args[0]) % (setup.phases.length - 1) >>
<</widget>>

I know this is only just nitpicking some code, but I thought it might be useful for people that are interested in building a Clock for their game, the modulo operator can simplify work by quite a lot here.

Also, the widget will now be able to accept even larger numbers over 48h or (setup.phases.length * 2)

this could also be overcome if you do it recursively (without the modulus operator like the following)

<<widget "addtime">>

<<if  ($time  + $args[0])  <= setup.phases.length - 1 >> // If time + increment  less then phases 
  <<set $time  += $args[0]>>
  <<else>> // time + increment = out of bounds of current phases so:
    <<if $time > 0>> // move to "next day"
        <<set $time = 0>>
        <<set _time to $args[0] - $time>>
        <<addtime _time>>
     // << addDay 1>>
    <<else>> // if already next day, skip "a Hole Day" until increment + time is smaller than phases.length (this is the important part for the recursion)
        <<set _time to $args[0] -4>>
        <<addtime _time>>
     // << addDay 1>>
    <</if>>
<</if>>
<</widget>>

I also added the widget <<addDay>> this would be used if you want to implement a Day system into your game so u can have the NPCs do something different on Monday than on Saturday.

1 Like

Yep, this is the full code. I had the second layer because I wanted the button option to still show, as a sort of reminder to the player “oh yeah I said this” type thing.

<center>																																																																There's no one here. 																																																											<span id = "buttons1">
<<button "Make food">><<replace #buttons1>>
<<button "Make food">><<addhours 1>><</button>>

You made some food.

<span id = "button1">
<<button "Leave">><<replace #button1>>

<<goto [[Home Ch 1 Pg 5]]>>

<</replace>><</button>>
</span>

<</replace>><</button>>

<<button "Go back">><<replace #buttons1>>

<<goto [[Home Ch 1 Pg 5]]>>

<</replace>><</button>>
</span>

</center>

So in this case, would I put the <<addhours 1>> on the first button like this since it’s the button that the player actually presses, or keep it under?

<center>																																																																There's no one here. 																																																											<span id = "buttons1">
<<button "Make food">><<addhours 1>><<replace #buttons1>>
<<button "Make food">><</button>>

You made some food.

<span id = "button1">
<<button "Leave">><<replace #button1>>

<<goto [[Home Ch 1 Pg 5]]>>

<</replace>><</button>>
</span>

<</replace>><</button>>

<<button "Go back">><<replace #buttons1>>

<<goto [[Home Ch 1 Pg 5]]>>

<</replace>><</button>>
</span>

</center>
1 Like

You have to place the macro inside the button that the player actually presses to perform an action, so in your case, the first button (which means your second example is correct).

I’m not so sure about replacing the button with an identical button which does nothing. In your example, the player can press the “Make food” button multiple times, but it only works the first time. This could leave the players wondering if the game is broken. Maybe at least add some line that pops up when the button is clicked again, which states “You’re not hungry now”, or something?

1 Like