quote: Ideally I could improve caretaker behavior with a widget that is accepted as default on by the devs. Is there a checklist/guidelines what that would entail? |
The general requirements for a default widget (or UI/AI gadget) are as follows:
-
Do not hinder or make the UI worse for players that are unaware of the widget.
-
Pay attention to the performance cost in relation to the benefit.
-
Write a gadget instead of a widget if gadget-space allows for a cleaner solution, or perhaps to remove the decision entirely.
The UI is often made worse through clutter or when units appear to act against what the player thought they told their units to do. Note that this is based on what the player thinks, not what actually happens, so even a widget that implements good behaviour can be bad if players often get the feeling of fighting against it. This can be a challenging requirement because, taken to the extreme, you would essentially have to read the players mind. If someone puts a Caretaker down on the frontline, and gives it no orders, did they intend for it to repair damaged units or reclaim? The UI has to guess.
Here are three good ways to avoid making the UI worse:
-
Don't override direct orders from the player. If the player orders a Caretaker to reclaim while their storage is full then trust that they did it for a reason. Even if they simply did not notice their metal bar, it is probably better to let them issue the order and move on rather than have the unit appear to fight against the order.
-
If implementing an active behaviour (such as Attack Move skirmishing) then keep it as simple as possible. This allows the player to learn what to expect when they issue the command. Teaching the player what to expect when they issue a command is basically as good as mind reading.
-
Limit the AI to only handle the dumbest and most common cases. I think players are fairly happy for unit AI to step in and stop unambiguously stupid automated behaviour, but when the UI tries to be smarter it risks fighting the player. For example, automatic reclaim at full storage is obviously bad in a way that reclaiming at 80% storage is not. Being a bit stupid in the edge cases, in the pursuit of reliability, is fine.
Performance is obviously important, and it depends on what the widget does. Even a widget with a small performance impact may be no good if I can't find any evidence of the problem it solves ever coming up in real game. In my experience Spring.Get{Thing}In{Volume} can quickly result in very poor performance so I am wary of widgets that use it frequently. In gadget-space I'm wary of anything that reads or handles projectiles. The current smart nanos widget gets units within a volume so I would need to test its frequency. Also, don't use the iterators pairs or ipairs (I made a file called IterableMap to replace them if you want).
Writing a gadget instead is often a solution to one or both of the first two issues. Gadgets,
-
are latency-free,
-
have access to the entire gamestate,
-
allow for cleaner implementations of unit states, and
-
have many more callins and hooks into the engine.
The downsides are that they can be a bit harder to open up to player configuration, and their performance impact is felt for all players. Sometimes the possibility of a bit of unit AI reveals that the mechanic that necessitates the AI should not exist in the first place. In this case "writing a gadget" would be changing the game such that the widget can't exist. For example, imagine if cloak disabled when you have less than 100 energy. Someone could write a widget to manage the economy such that you don't drop below 100 energy. At this point the mechanic is rendered pointless so may have been removed in the first place.
To give some examples, the Kodachi AI widget was not included because its effectiveness was highly dependent on latency and it fought the player for control of the set target command. Similarly, the Artemis AI is vulnerable to latency and fights the player for control of firestates. Moreover, when I last checked, it uses massive Spring.GetUnitsInCylinder and similar, much cheaper, functionality exists in the target priority, overkill prevention, and "Don't fire at radar" gadgets.
Caretaker AI as a widget sounds fine if you are smart about it. It should probably be added to "Auto Patrol Nanos" since this is the only widget that handles Caretakers. The proposed widget is implementing an idle behaviour so to start with I would focus on the simplest, dumbest, behaviors. More can be added if further issues arise. I would target these two cases:
-
Don't reclaim automatically if metal storage is full.
-
Don't build automatically if your storage is empty, provided there is something to reclaim or repair nearby.
Note that "Don't build automatically" is potentially too much automation, since I expect that many players manage their build priority partially via overbuilding Caretakers near their factory. As long as it is limited to cases where Caretakers could do something else then it is probably fine.
I would try using area commands to avoid all the target selection issues. Here is an approach:
-
If you are out of metal, intermittently insert large area-reclaim and repair-only area-repair commands at the start of the queue. Insert reclaim before repair, and stagger the Caretaker updates over multiple seconds to make them naturally balance their reclaim. Skip inserting repair if you are also low on energy.
-
If your metal storage is full, replace the Caretaker patrol command with area-repair. This update could be checked faster as balancing is less useful.
When using the area commands there are two things to consider:
-
If a Caretaker is already doing an appropriate command when one of the above conditions is triggered, then modify its command queue in such a way to not interrupt its current command.
-
Make the radius of the command extremely large (if this doesn't cause bugs) because drawing circles everywhere is ugly.