Regarding the improvements made recently to the AI system, I think it's a good time to write another design post explaining how my NPC deal with the environment. Except specified otherwise, it concerns the 0.3.0 version of the game (currently in development). And as usual, this is a design document, containing technical stuff with random ideas thrown in that may or may not be implemented in the long run.
1.General Behaviors
Currently, NPC can do a rather large number of things that can be categorized in six main domains or 'states'.
- Hungry: The NPC will try to eat something.
- Go to a Bar or Restaurant: If he has the money, and if such a facility is nearby, the NPC may decide to take a lunch there. He will look for a "Food Source" item (like the tables at a restaurant) and bump into it until his hunger is satisfied.
- Go Shopping: If the NPC is wealthy enough and a food related shop is nearby, he can decide to buy some food there. The items being randomly chosen, it may not be enough to satisfy his hunger.
- Use Items: If the NPC has food in his inventory, he will use it in priority. If he has such items in a container (a fridge for instance), and he is in a nearby location, he may decide to retrieve the food item from there.
- Sleepy: The NPC is tired and need to take a nap.
- Use a bed: The NPC will look for his personal bed and sleep there. When hotels will be implemented, he may decide to use a room there if his house is too far away.
- Use Items: If he has some coffee or other sleepiness reduction item, the NPC will use it. However he won't actively buy such item when tired, he must already have it in his inventory.
- Working: When low on funds NPC will go working.
- Basic: What a NPC will do when working depends on his job. Most of the jobs consist in going to the related "work" object (like a computer) and use it to gain some money. What the work will produce is depending on this object. A production bench in a factory will produce items that can be moved to related stores. NPC get paid each time the use the object.
- Patrol: Some NPC like the cops and the thugs will patrol the streets, looking for enemies. They are paid for each location visited, and receive a bonus when they kill someone.
- Trading: Those who are traders, mostly shop owners, are working differently. When they need money, they will stay in their respective shops. However, they receive some money for everything bought there, no matter if they are working or not. As such, traders should be wealthier than other NPC.
- Interactions: Some NPC, like the pickpocket or the doctor, need another NPC to work. They will usually go to a (random) location and look of a potential target. When such a target is found, he will close in and "Use" it, with varying results according the job.
- Hurt: When a NPC needs to be healed.
- Use Item: He will use an item from his inventory to heal self.
- Go Shopping: He will go to a store to buy some health related items
- Sleep in a hospital: Otherwise he will go to a nearby hospital and sleep there to recover.
- Combat: When attacked, or when a hostile is found while patroling
- Attack: Still basic combat mode, the NPC will either close in or attack his target.
- Flee: If his health is too low, of if the NPC has no weapon equipped, he will try to flee from his opponent.
- Idling: When the NPC has nothing better to do.
- Go to a Park: No better place to idle :)
- Idle in house: The NPC may decide to go back to his house for a while
- Go Shopping: If he has enough money and if a shop is nearby, the NPC may buy random items there.
- Fill Containers: If the NPC owns a container of a specific type (food item -> fridge), and has money, he may decide to go buy such items and deposit those in this container for later use.
- Manage Inventory: If the inventory of a NPC is full, and he owns a general container, he may decide to drop some of his stuff there. If his inventory is near empty, he may decide to retrieve random useful items from it.
All of this is very nice, however I don't really like how it's currently implemented. I've put a bunch of "if .. else if .." and "case" all over the place, with a some redundancy. There's a specific function to build the orders for each domain. This is usually normal with a finite state machine (fsm) AI, however my Smart Terrain AI was supposed to bypass that completely. The system should be able to get a list of object/agent to interact with directly depending on the current state of the agent and build the order accordingly without tons of special cases (like 'if I have the money then I can shop). Common orders like "use inventory" and "use object/npc" are good examples regarding redundancies. This is partly because the way objects (activators) are defined is not good enough and partly because I am still experimenting in this domain. If I was rewriting the thing from scratch right now, the AI module would probably 2 or 3 times smaller and would be much easier to adapt to handle new jobs and objects as a result.
However, CPU wise, the impact would be marginal and it's still much easier to maintain and faster than pure FSM. As a result, I don't think I am going to rewrite the current system for GRA. Instead, I will reorganize the system in my next major project.
2. Group Behaviors
A recent addition to GRA is that NPC will react to combat happening around them. If a civilian is attacked, nearby friendlies will either flee or come to his help if they have a weapon in hand. The same thing happens for other factions. Attacking a cop will make nearby cops aggressive no matter if they are on duty or not. It will work a bit differently when dealing with gang members (as soon as the faction tree of the roadmap is under development): generic illegal characters will ignore calls for help, but members of specific factions will defend both their faction-mates and friendlies.
Also, to balance the general ineffectiveness of melee weapons, using them to attack an enemy won't trigger group behaviors.
3. Private Property
NPC now have a basic understanding of the private property rules. If you are trying to open a container when the owner can see you, your stealth related check will be harder to pass, and the NPC may see that as an aggressive action. He may either flee from the location or attack you depending on the usual combat rules. Once the police faction will be implemented properly, he will call for help and nearby officers will arrive to the location shortly after that. The same applies when you're opening a safe that's not yours in front of a police officer. Of course, the same is valid for NPC with the yet to be implemented Thief job.
4. Code Wise - JobList Mechanism
Pure coding here. NPC use a stack of jobs to execute orders. Jobs are defined like this:
- Action: The general action performed. It can be one of the following:
- Move To - Move to a specific (X,Y) location
- MoveIdle - Move around randomly
- MoveToZone - Move to a specific zone (usually a building or a park)
- UseItem - Interact with an object on the map
- TalkTo - Interact with a specific NPC or look for a NPC and then interact with it.
- Attack - Attack a NPC
- Patrol - Move around a location, looking for enemies
- Shop - Buy an item that will help with a specific need
- UseInventory - Use an item from the inventory to satisfy a specific need
- Follow - Follow a specific NPC
- Destination: Where the NPC is supposed to move to validate the order. It can be a position, a zone, another npc, or a specific activator.
- NeededObject: What type of item the NPC is supposed to buy/use/trade/store
- Duration: Repeat the action for this amount of turn. If the value is -1 then he will repeat the action until it fails or until the action is finished.
- AllowScan: Determines if the NPC will scan for enemies and attack them will doing this action. If a target is found, the NPC will switch to attack mode against it.
The whole system is very flexible. Orders are a class on their own, I can easily insert a new job in an already running list (that's what patrolling does, it inserts an "attack" job when a target is found during the patrol), append new ones or delete existing ones on the fly and the NPC will react accordingly. If an item in the list fails for some reason (target is dead for instance); the whole list will be canceled and the NPC will build another stack.
An example:
Job = Orders.AddNewJob
Job.Action = MoveTo
Job.Destination = Specific "Computer" activator
Job.Duration = -1
Job = Orders.AddNewJob
Job.Action = UseItem
Job.Destination = Specific "Computer" activator
Job.Duration = 60
This is basically how the "work" order for an office worker is written.
5. Random Thoughts
Even if my current implementation is not as well written as I would want it to be, this is still quite an achievement. The engine is able to handle several thousands of NPC with a fully working AI on a 5 years old computer without any kind of slowdown, without using some kind of simulator for "out-of-sector" NPC, and without eating too much RAM (around 100Mb). Thank to the whole design, CPU cost won't go much further, no matter what feature I add next. And more to the point, there's still a lot of speed improvement tweaks that are disabled in my engine.
I also have kinda resolved the issue regarding NPC to (N)PC interactions by adding an "UseMe" function on the NPC class. It works the same as with activators. The main NPC interact with the target, calling its UseMe function, and the function will process the respective job and faction of both to determine the result of this interaction. It's not very practical, and i can't maintain tons of such interactions without going into in an unreadable mess, but it's sufficient for basic things like stealing, trading, and chatting.
Hmmm very interesting, this will be a GREAT game. (:
ReplyDeleteSerial,
ReplyDeleteHow's the Development going?
0.3 should be available this week. Not everything I want about the economy is ready, but it's still good enough and the changelog is already massive.
ReplyDeleteNext, I'm going to start the faction related stuff like gang warfare, better police, general combat, and leveling.
Nice,
ReplyDeleteSo your making good headway. Thats very good.
Regarding the factional warfare,
will the factions have randomly generated names?
I am going to write a few articles on the matter. But, yes factions will have randomized names and, more importantly, behaviors.
ReplyDeleteThe name will probably be a combination like adjective + noun chosen from text files.