Again it's been hard to find the few hours of time out of a day lately to write a proper article, but finally found a good opportunity for it while taking a 2.5 hour bus trip to meet up with the contractor who's been working on the teaser trailer for the game. Might as well spend the time doing something useful, right?
Anyway I've been a professional software developer long enough and done enough analysis that usually planning things out is not much of a problem and even though some of the principles of game programming are a bit different, it's not been that hard to adapt my previous work experience.
The AI has been a different story. Figuring out a proper code architecture for the AI has proven to be one of the most challenging tasks for me so far. When I started out I had pretty much no clue how artificial intelligence in most games is implemented and in my ignorance I did little to counter that fact. This has led me to having to redo big chunks of the implementation as I gain new knowledge from the bottomless database that is the Internet.
The first implementation was pretty straightforward and simple. I defined wider employee tasks such as "do work", "go to toilet" or "get coffee". I gave each employee a priority queue and the tasks and their priorities were added randomly with the probabilities based on certain employee stats. Each of those tasks had their own subtasks that were carried out in order, so for example 'get coffee' would involve finding a path to the closest coffee machine, going there and using the machine. If any of the subtasks failed, it would just move on to the next task in the priority queue. This system sort of worked, but lacked flexibility, was mostly hardcoded and resulted in odd "non human" behavior like employees visiting the toilet over and over again when they had nothing better to do.
Several months later I was inspired by reading an article about behavior trees in Project Zomboid. The article helped me understand what behavior trees even are and why it's become quite a common AI implementation today. Coincidentally gdx-ai had just been released as a Libgdx (the Java framework that I use for the game development) module and it included behavior tree support as well, so I decided to use it. Additionally I figured as long as I'm redoing thing anyway, I might as well add Lua scripting support (more about it in the previous article). So I ported my previous subtasks code to behaviour trees in Lua, but I left the main task priority queue implementation pretty much untouched. That meant that even though subtasks were now much more flexible and employees carried them out in a more "intelligent" way, problems with main task priorities stayed.
Then I somehow found a few articles about AI in the Sims (here, here and here). The described utility formulas made a lot of sense to me and in my naivety it seemed to me that all it took to adapt it was to run some line formulas on top of the priority variables before sorting the queue. Turns out it was quite not so easy after all. Analyzing things a bit more, I realized that the random increasing of priorities had been a bad approach. Instead priorities should be calculated only based on the formula of each task. But that again brought a number of questions that I had no easy answer to. At what point should the tasks be added into the queue? Or should the queue always include all the tasks that the employee can carry out? What if a certain task fails, ie. the bathrooms are occupied when employee tries to go there? Unless I factor a failure "cooldown" into the priority formula, what stops the employee trying the same task again and again after every failure? If so, how long should the cooldown period be? At the time of writing this article I'm still stumped with some of these questions, so I'll end the first part of this series of articles here. Next time I'll concentrate on the code parts of the whole implementation and hopefully have the answers I'm looking for as well.