Jump to content

how to write/debug AI routines?


davidlallen

Recommended Posts

I have spent some time looking through XComAI.ini and the way that some mods enhance it. I am trying to write AI that will use a number of standard soldier abilities. I have basic AI for each class but it doesn't use a lot of the advanced abilities. Here are my target abilities:

 

Grenadier: LaunchGrenade, Shredder, Demolition, HoloTargeting, SaturationFire, Rupture
Ranger: SwordSlice, Blademaster, Shadowstep, RunAndGun, Implacable, Untouchable
Sharpshooter: Squadsight, ReturnFire, LightningHands, DeathFromAbove, Serial, KillZone
Specialist: RevivalProtocol, AidProtocol, FieldMedic, CoveringFire, Sentinel, Restoration

 

I have so many questions. I ranked them most important to least.

 

1. Is there an in-game way to monitor the behavior trees? I know about the external visualizer, but I want to see the tree branches which are taken in particular in-game situations.

 

2. My grenadier units have a launcher equipped, but they don't use it. The loadout in XComGameData.ini contains a frag grenade. When I take over the enemy unit using "x2allowselectall 1", I can see that I don't have the option to either throw, or launch grenades. Is there some additional step missing, like filling a grenade pocket?

 

3. Is there a good way to prove if a sniper AI is using squadsight? It seems like sniper AI will make the unit move till it has personal LOS, rather than relying on squad LOS.

 

4. For specialist heal and revival, I can't figure out how to select a target and use the ability. Are there any examples of healer AI? Is there any special trick to using a gremlin based ability?

 

5. I was pleasantly surprised to see that the ranger uses Implacable. But, how can I make good use of Run And Gun?

 

6. Some abilities, like Kill Zone, require selecting a cone. Are there examples of AI using this type of selection?

 

7. It doesn't seem that AI snipers have any interest in high ground. Are there any hooks to make AI's move to high ground? This is a less important detail, but still interesting.

Link to comment
Share on other sites

  • Replies 43
  • Created
  • Last Reply

Top Posters In This Topic

I haven't got into the sdk or anything yet, so I can't help with most of this, but I can report that squadsight units will use it against you, though whether they deliberately seek out squadsight shots or just happen to use any that they have I'm not sure.

Link to comment
Share on other sites

The BT will try each of child[0] ... child[N] in order until one succeeds. Your suggestion is to add N more children alternating with the original ones, so that somewhere between 1..N redscreens will come during each AI turn. If redscreens 1,2,3 come, but redscreen 4 does not come, then I infer that child 3 must have succeeded. Is that correct? That seems very painful, but it is better than nothing.

 

Any other suggestions?

 

The external visualizer is described here, I have not tried it:

 

http://forums.nexusmods.com/index.php?/topic/3921590-cannot-use-multiple-mods-each-adding-new-enemies/page-3&do=findComment&comment=36016755

Link to comment
Share on other sites

Oh my, you just went right for the good stuff, didn't you :)

 

The AI trees that i build for my custom enemies are (a lot^^) less complicated than the ones needed for a human enemy with 5 or more active skills. I actually didn't dive really deep into more exotic things. At the moment, i usually avoid spending a lot of time on troubleshooting abilities that give me grief - my mod is better off if i take the time to make a different ability instead. I am still at the phase where volume is the name of the game, in a month i will probably be looking at the things that i had to abandon. Like enemies with grenade launchers or Gremlins...

 

But maybe i can throw some helpful things your way nonetheless!

 

1 - I don't know about any better way of monitoring the decision trees and how the AI goes through its branches. My units behaviour can usually be observed fairly well by just spawning three of them and see what they do when i hit 'End turn'. When i do need to debug something more closely, i use "SkipMove" in a similar way to how swinka suggested using the redscreen output.

 

2 - Had the same experience when i tried to give a launcher to one of the Advent Captains. I didn't look into it very far so i don't know what's the problem there.

 

3 - There is no such thing as a sniper AI in vanilla XCOM. Here's the one i did for my Sniper Captain:

+Behaviors=(BehaviorName=TryShootOrReloadOrOverwatch_Sniper, NodeType=Selector, Child[0]=ConsiderTakingOverwatch, Child[1]=ShootIfAvailable_Sniper, Child[2]=NeedsReload)
+Behaviors=(BehaviorName=ShootIfAvailable_Sniper, NodeType=Sequence, Child[0]=IsAbilityAvailable-SniperStandardFire, Child[1]=SelectTargetForSniperStandardFire, Child[2]=SelectAbility-SniperStandardFire)

+Behaviors=(BehaviorName=IsAbilityAvailable-SniperStandardFire, NodeType=Condition)
+Behaviors=(BehaviorName=SelectTargetForSniperStandardFire, NodeType=Sequence, Child[0]=SetTargetStack-SniperStandardFire, Child[1]=GenericSelectBestTarget, Child[2]=HasValidTarget-SniperStandardFire)
+Behaviors=(BehaviorName=SelectAbility-SniperStandardFire, NodeType=Action)

+Behaviors=(BehaviorName=SetTargetStack-SniperStandardFire, NodeType=Action)
+Behaviors=(BehaviorName=HasValidTarget-SniperStandardFire, NodeType=Condition)

Nothing too complicated (actually the first new behaviour lines i made for my mod \o/ ), just the setup for the SniperStandardFire ability which should not be folded into the regular StandardShot AI because it uses two actions instead of one. If you want to know if the targeting handles Squadsight, you'd probably need to look into the class behind the SetTargetStack action.

Or, more pragmatically, try setting the detection and sight radius of your sniper to just one or two and see if he can still shoot at something.

 

4 - There's a mod called Advent Priest that adds a healer unit. It uses a psi ability as the carrier for the heal. Looking at that mods files should be helpful. Didn't do so myself yet.

I actually experimented with the Gremlin as well. I wasn't able to line up the animations correctly, but the targeting worked. Here's a part of the AI of my (so far unreleased) Tech Commando, a Shieldbearer with a Gremlin that uses Aid Protocol and Heal Protocol:

+Behaviors=(BehaviorName=SelectAbility-AidProtocol, NodeType=Action)
+Behaviors=(BehaviorName=SelectAbility-GremlinHeal, NodeType=Action)
+Behaviors=(BehaviorName=SetTargetStack-AidProtocol, NodeType=Action)
+Behaviors=(BehaviorName=SetTargetStack-GremlinHeal, NodeType=Action)
+Behaviors=(BehaviorName=IsAbilityReady-AidProtocol, NodeType=Condition)
+Behaviors=(BehaviorName=IsAbilityReady-GremlinHeal, NodeType=Condition)
+Behaviors=(BehaviorName=HasValidTarget-AidProtocol, NodeType=Condition)
+Behaviors=(BehaviorName=HasValidTarget-GremlinHeal, NodeType=Condition)

+Behaviors=(BehaviorName=SelectTargetForAidProtocol, NodeType=Sequence, Child[0]=SetTargetStack-AidProtocol, Child[1]=SelectTargetForAid, Child[2]=HasValidTarget-AidProtocol)
+Behaviors=(BehaviorName=SelectTargetForAid, NodeType=Sequence,  Child[0]=SetNextTarget, Child[1]=ScoreBestTargetForAid, Child[2]=UpdateBestTarget)
+Behaviors=(BehaviorName=ScoreBestTargetForAid, NodeType=Sequence, Child[0]=TargetIsAlly, Child[1]=TargetWounded, Child[2]=EvaluateForAid)
+Behaviors=(BehaviorName=EvaluateForAid, NodeType=Sequence, Child[0]=ScoreByHP)

+Behaviors=(BehaviorName=SelectTargetForGremlinHeal, NodeType=Sequence, Child[0]=SetTargetStack-GremlinHeal, Child[1]=SelectTargetForHeal, Child[2]=HasValidTarget-GremlinHeal)
+Behaviors=(BehaviorName=SelectTargetForHeal, NodeType=Sequence,  Child[0]=SetNextTarget, Child[1]=ScoreBestTargetForHeal, Child[2]=UpdateBestTarget)
+Behaviors=(BehaviorName=ScoreBestTargetForHeal, NodeType=Sequence, Child[0]=TargetIsAlly, Child[1]=TargetWounded, Child[2]=EvaluateForHeal)
+Behaviors=(BehaviorName=EvaluateForHeal, NodeType=Sequence, Child[0]=ScoreByHP)

+Behaviors=(BehaviorName=TryAidProtocol, NodeType=Sequence, Child[0]=IsAbilityReady-AidProtocol, Child[1]=SelectTargetForAidProtocol, Child[2]=SelectAbility-AidProtocol)
+Behaviors=(BehaviorName=TryGremlinHeal, NodeType=Sequence, Child[0]=IsAbilityReady-GremlinHeal, Child[1]=SelectTargetForGremlinHeal, Child[2]=SelectAbility-GremlinHeal)

"TargetWounded" and "TargetIsAlly" are already existing conditions that i tied together with the also already existiing "ScoreByHP" evaluation into a new "ScoreTargetForHeal" command.

Disclaimer: The above is more of a demonstration and tech test that i did for myself to see how this works. Heal and Aid still use the same conditions etc etc. But the general gist of it should be clear.

 

5 - No idea. I struggled with that as well and dropped it fairly quickly. Doesn't the Sectopod use three actions in one turn? Not sure.

 

6 - I did a cone targeting ability for my firebreathing Berserker that works just fine:

+Behaviors=(BehaviorName=TryFirebreath, NodeType=Sequence, Child[0]=IsAbilityAvailable-Firebreath, Child[1]=FindPotentialAoETargets-FirebreathProfile, Child[2]=SelectAoETarget-FirebreathProfile, Child[3]=SelectAbility-Firebreath)

+Behaviors=(BehaviorName=SelectAbility-Firebreath, NodeType=Action)
+Behaviors=(BehaviorName=SetTargetStack-Firebreath, NodeType=Action)
+Behaviors=(BehaviorName=IsAbilityAvailable-Firebreath, NodeType=Condition)
+Behaviors=(BehaviorName=HasValidTarget-Firebreath, NodeType=Condition)
+Behaviors=(BehaviorName=FindPotentialAoETargets-FirebreathProfile, NodeType=Action)
+Behaviors=(BehaviorName=SelectAoETarget-FirebreathProfile, NodeType=Action)

In addition to that, the actual targeting profile needs to be added to the AI.ini. Important: it gets added under a different header than the behaviour lines!

[XComGame.XGAIBehavior]
+AoEProfiles=( Profile=FirebreathProfile, Ability=Firebreath, bIgnoreSelfDamage=True, MinTargets=2)

More isn't needed... i assume because the cone targeting is keyed into the ability itself and it's referenced in the profile. I guess the most similar ability is Null Lance?

Anyways, i tested this by making the firebreather react to different placements of soldiers and it works.

 

7 - Hm, didn't think about this before. I don't think there's anything about elevation in the AI so far. No immediate idea how to do it either. My gut says it can't be done just with ini editing.

Link to comment
Share on other sites

Whew. Quite a burst of AI modding. Well, after the first six hours of beating my head against the wall on why weapon abilities were all reporting insufficient ammo. Protip: soldiers have abilities which link to weapons through eInvSlot_Primary/SecondaryWeapon. Enemies don't. You can't link through a weapon slot. You need a ton of custom weapons, with the abilities on the weapons. Never put abilities on enemy characters, only weapons. Also, grenade launchers are weird.

 

I made a pretty nice sharpshooter AI. A pistol sharpshooter at major level can have fan fire, faceoff and lightning hands. The first move point is (1) lightning hands, (2) move if flanked, (3) faceoff if multiple enemies visible, (4) sniper shots. The second move point, which mostly happens if the first move point was a flanked move, is (1) fan fire, (2) pistol standard shot. In a typical engagement, this means a player fighting this AI will see all four actions. The opening is usually both lightning hands and faceoff, and if you flank, he moves off and does fan fire or a standard shot.

 

It took a long thread at /r/xcom2mods for me to figure out why the grenade launcher wasn't working. OK, "figure out" is giving myself too much credit, another redditer basically posted the code:

 

https://www.reddit.com/r/xcom2mods/comments/4cde3d/why_do_my_enemy_soldiers_need_ammo/

 

Now that I can manually fire the grenades, it ""shouldn't be that hard"" to get the grenadier to use them. After that I will work on getting the specialist to do healing. Thanks for the suggestion about Advent Priest, and thanks for posting the example code from tech commando. I think there is enough here to get going.

 

I have a couple more questions, if you don't mind.

 

1. The conditions like IsAbilityAvailable-LightningHands don't seem to have any "function body". Is there something hard coded that IsAbilityAvailable-xyz will just look for ability xyz? I wonder, because your sniper captain uses IsAbilityAvailable-SniperStandardFire, but I can't find any function body for it and there is no ability with that exact name. I am using that line, and now I am curious how it can work.

 

2. Should modders worry about name collisions in XComAI.ini? You have defined some handy behaviors like TryFaceoff, which include customized things like MultipleEnemiesVisible. This is a nice, predictable name, which some other modder may also have used with a different definition. If they happened to give it a completely different set of children, I suppose the actual behavior would depend on mod load order. It's unlikely people would notice this behavior unless there was a redscreen. Should I get in the habit of naming all my behaviors with a prefix, say "HT_TryFaceoff" to reduce the likelihood of this type of collision?

Edited by davidlallen
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...