Developer Diary Week 7 - Sleep System, Player Hobbies, NPC Initiated Conversation
- gtristanitristani
- Jul 6, 2023
- 6 min read
Once again, this week was packed with new content and project updates! I started with the idea of implementing three different systems, with NPC-initiated conversation being the anticipated task that would take the most time.
This week, I focused on three main aspects of the system: sleep, player participation in hobbies, and NPC-initiated conversation. I worked on each in that order, and will break down exactly what each entailed below.
To start, the sleep system involved mainly retailoring of existing behaviors. I added two new Timestamp variables, SleepTime and WakeTime, to the Job class. This lets a villager’s job dictate when they sleep and wake up. The villager class also gained a new variable: a pointer to an Actor that they travel to, their bed, before sleeping. Upon overlapping the actor, they play their sleeping animation, and remain asleep until the WakeTime time value is reached in the game’s clock.
While asleep, the NPC gains back energy at a rate configurable by the user, as well as gaining the same mood recovery benefits from being unconscious or relaxing. No affinity change takes place, and their location remains the same for the duration.
During this period, the NPC can not be interacted with by the player, except by being hurt. At this point, they wake up, reprimand the player, and then fall asleep again. Since I added a knockback force on NPCs after being hurt, this effectively lets the player push them out of the bed, so they end up going back to sleep on the floor. While not initially intended, I ended up enjoying it quite a bit since it seems like the NPC is too groggy to move back into the bed before passing out again.

A major focus when adding all of this behavior was the Timestamp class, as the full duration of the sleep behavior relies on it. I wanted it to be very easy to have a variety of NPCs that sleep and wake up at very different times in the day, and for the duration that they sleep in game to be accurate regardless of such choices. To implement this, I decided the Timestamp class itself needed a new function to reduce the number of checks written. This function, when called by a Timestamp object, returns a Boolean value indicating whether or not it is between the first timestamp argument and second timestamp argument provided.

With this basic helper function, I was also able to reduce a lot of the code within the check to dictate whether the NPC is at work or performing a hobby! Time-based behaviors should be much faster for me to write and test going forward, and I’m glad that it’s now easier for users to specify their own.

I added another helper function, Generate Random Time, to generate a random time duration between a max and min time spent range. It should be called by the timestamp representing current in-game time. It then automatically adjusts a passed in start and end time for that specific action. This is designed for use with the hobby and conversation sub-behaviors, but could be further applied in other future cases as well, at the user’s need!
Moving into player hobby participation, I decided to start with a very basic approach. The goal was that logically, the functionality intended will be there, with some room to adjust how it visually appears to the user with more experimentation.

To start, instead of a basic actor being specified as a hobby location, I created a new Actor derivative called a HobbyStation. This HobbyStation simply keeps track of if the player is in range, if they are performing a hobby, and what villagers are currently invoking its associated hobby. It adds and removes villagers from the array as they start and stop invoking the hobby. This makes it a lot easier to tell logically what villagers the player is performing a given hobby with!

In order to relay and test their functionality, I created a new basic UI widget that indicates when a player is standing in range of a HobbyStation. The UI also indicates whether or not the player is performing the hobby. The player can press a configurable keyboard key or button to begin and end a hobby.

While the player performs a hobby, they cannot move in the world, but can still control their camera.

All NPCs currently at the hobby space will gain affinity towards the player at a user-configurable rate. This gets across the idea of the system: NPCs grow closer to the player by performing hobbies with them, and the player is free to start or stop hobbies whenever they are within a range of the hobby space!
The final and largest task was allowing the NPCs themselves to initiate conversation. I wanted this to be a behavior that could be selected to be invoked when in an idle state. What that meant in terms of design was that there are several potential options (meander, hobby, conversation) when an NPC is bored. In that case, there would be reason to allow the user to tailor how likely it is for an NPC to choose each option. So instead of jumping straight into implementation, I spent a bit of time thinking about how I could go about this.
I decided that it would be best to implement this via assigning each idle-selected course of action a configurable percent value. Thinking about it more deeply, I realized it would be convenient to manage time-related variables in a single object related to that course of action when possible. This could be satisfied through a struct, but would require a good deal of work to fully implement through the NPC Villager existing system. However, it seemed to be work that would pay off, so I proceeded with this plan. If later I or a user wanted to add new subbehaviors, this would provide a useful mechanism to do so.

Above, I have all possible variables to influence Idle sub-behaviors stored within a struct. This way, each behavior can be associated with its percent chance, min and max time to execute, and previous execution start and stop times. This is very similar to what’s included in each hobby variable. It may be worthwhile to convert hobbies to use these time variables, but for now, they are separate.

Now, the NPC has 3 distinct behaviors it can choose to invoke when idle. Each of them has an associated “percent chance” that can be tailored by the user as well. This can readily be tailored on a by-personality or by-NPC basis.

Additionally, when an NPC goes to talk with anyone, they should at least be in a state where they will enjoy the conversation. Because of this, before transitioning into a conversation state, they will check if they have enough energy and are in a positive mood to begin talking.
I want NPCs to actually have two distinct conversation implementations: one focusing on their conversation with the player, and one focusing on their conversation with another NPC.


In the case of a player conversation, the NPC has a certain number of random responses they will generate when talking to the player. The player can click as normally to advance to the next response. The number of responses that they generate within the conversation is a random selection between the minimum and maximum Execution variables. The entire time, they stay within the talking state. After delivering this many responses, they will end the conversation. If at any point in the conversation they are not able to talk anymore due to energy, mood, or career, they will leave early. During conversation, the NPC should gain the same affinity and mood adjustments gained through each response normally.
After significant time spent implementing it fully, the NPC is able to approach the player to strike up a conversation as long as they’re in the mood and with enough energy to talk! They will end the conversation early due to bad mood, low energy, or work.
The plan for NPC conversation is that they will approach a random selected NPC that is able to talk, and then converse for a set period of time. If either has to leave early, the conversation will terminate.
Unfortunately, due to time constraints, I didn’t quite get to NPC-to-NPC conversation this week. However, the implementation of an NPC seeking out an actor (the player), walking to them, and remaining in the talking state while looking at them for a set randomly calculated period of time was implemented for testing before the rework of NPC-initiated player interaction was designed.
With this implementation need in mind, next week, I plan to finish it, as well as fixing some bugs I noticed with the current systems. Additionally, I want to implement a new feature where the player can directly interfere with an NPC’s schedule. For each in-game minute the player spends distracting the NPC while they’re supposed to be at work, the NPC will need to work a minute in overtime. While working overtime, the NPC will increase negative moods and decrease positive moods. Similarly, they will need to work overtime if they pass out at work for the duration of being passed out. This similarly would allow the player to interfere with the NPC’s ability to sleep at night by hitting them to make them pass out at work later. The final thing I would like to implement is that if an NPC has high player affinity, they start losing it each day that passes without the player choosing to interact with them.
Once again, I wanted to link the project on GitHub and invite anyone interested to experiment with it and provide feedback! It would mean a lot. Thank you for reading, and I hope you'll be looking forward to next week's update!
Project Link: https://github.com/grist-maker/NPCVillagers




