Jump to content

R&D AI Improvements


Amineri

Recommended Posts

I thought I recall seeing a special "Flank Move" action that the alien can be made to do, which can cause it do dash, but I don't yet understand the triggers that can cause it. I figured it was a part of the team attack code, but I suppose it isn't.

 

Definitely even Sectoids can suppress using their Plasma Pistols, even in Single Player. Confirmed this by using the developer console and swapping a sectoid to my team. It had the Suppress ability icon available in the HUD, and suppressing worked normally.

 

Part of what keeps the AI from acting more intelligently (besides the bugs) is that there is no multi-move planner in the game. Chess programs works by exploring the possible move space in order to identify "good" moves. They are the ones the ultimately lead to advantageous trades or ultimately to a checkmate.

 

However, Chess is a much simpler search space.

  • Everything is known, so the AI doesn't have to deal with uncertainties
  • Everything is deterministic, whereas XCOM is probabilitistic
  • The board size in XCOM is much larger than 8x8 tiles
  • There are more different pieces, especially considering various configurations -- this is probably why the AI doesn't have as many configuration options for alien units

It would be a massive project on its own trying to build a competent AI that could plan moves over several turns -- probably as big or bigger than coding the game was. After all, making a good Chess playing program is a lot harder than writing a program that allows two humans to play Chess ;)

 

-------------------------

 

That said, I think trying to come up with a better way to assign a priority to Suppression is probably a good thing.

 

Issues with using Suppression :

  • If the suppressed unit has a move where it can move 1 tile and break LOS it can break the Suppression. The AI has used this against me :p
  • Suppression deals no damage. It's really only useful for pinning down a dangerous unit. Since the aliens are often outnumbered, each alien could suppress one XCOM unit and they wouldn't get anywhere

Will have to give some thought to what the right conditions are under which suppression could be used.

 

I have had the AI use Suppression in seemingly coordinated attacks. Once against pod of three Floaters, 1 used Launch in an attempt to flank my Rocketeer, and the other 2 Suppressed : one Suppressed the flanked unit and the other suppressed the next nearest unit. However, I still had 3 or 4 other units. Honestly the AI using Suppression there probably made my life easier because it meant that the Floaters had no chance to deal damage to me.

 

I moved some units in the rear line and took out the flanking unit, and just ignored the Suppressors (locking units 1-to-1 is to my advantage when I outnumber the aliens like that). When the next turn came around it was the same situation for the aliens as the previous turn except that now there were only 2 floaters.

Link to comment
Share on other sites

  • Replies 144
  • Created
  • Last Reply

Top Posters In This Topic

Amineri proposed a solution to activate all pods by default in the other thread a while ago. I went ahead and researched and posted the hex change that would put her proposal into the code (in the "Turning on alien pods by default" thread). Let us know if it works!

Sadly, it does not work, and I'm not exactly sure what it ends up doing. :( When I have time, I am going to try mucking around with the states in XGAIBehavior, though I am not familiar enough with what is contingent on what to really make an educated guess beyond that.

Link to comment
Share on other sites

No, floaters just tend to use suppression a lot (compared to other aliens, that is), because they have very poor aim, so suppression is valid tactic for them (and yes, shooting for them in that situation may have been better). Problem in that move that floater launched itself, not floaters using suppress (they may have missed anyway). While launch seem like a good ability on paper, floaters (and by extension heavy floaters) lacking survivability/numbers to pull off moves like that; btw does it even landed in cover?

 

I will have to disagree on usefulness of suppression:

why it is usually better, than just taking an okay shot?

1. While it deals no damage, it also cannot miss (while with standard shot its all-or-nothing; also reaction fire from suppression will have better hit chances than standard shot on unit in high cover)

2. Suppression may remove cover (and expose that enemy to allies) or set that cover on fire; in both cases targeted unit is pretty badly screwed;

3. It removes overwatch/possibility of reaction fire, and confers nasty aim penalty, which can be only removed along with offending unit, or by taking reaction shot.

 

And 1-tile-move is long known "feature" of the game (as attack triggers/rolls only when unit crosses boundaries of tiles, therefore both tiles on which unit moves must visible, or reaction shot will not happen);

 

On issue of aliens being outnumbered - I think we have Increased Alien pod size to help that :cool:.

 

 

 

Amineri proposed a solution to activate all pods by default in the other thread a while ago. I went ahead and researched and posted the hex change that would put her proposal into the code (in the "Turning on alien pods by default" thread). Let us know if it works!

Sadly, it does not work, and I'm not exactly sure what it ends up doing. :( When I have time, I am going to try mucking around with the states in XGAIBehavior, though I am not familiar enough with what is contingent on what to really make an educated guess beyond that.

 

I can confirm your results; also done some research on that, and actually found function in XGAIBehavior isActive, which always returns true.

Edited by Tycus
Link to comment
Share on other sites

Am working on a new modlet to the AI which makes "last alien units" behave a bit smarter / realistic.

 

The scenario is kind of a no-win situation : You're the last unit standing. You're being suppressed or overwatched. There's at least one unit that's drawn a bead on your flank. You don't have any shots that are worth taking. WHAT DO YOU DO?

 

Okay, besides turning off the game in disgust or save-scumming. Because it's the AI I'm talking about, and it doesn't get those options! (seriously, what would the world be like if the AI could save-scum like the human players!?!)

 

Generally, make a break for it. Dash as far away from the attacking units as you, try and get into some sort of cover. Then overwatch and wait for the enemy to come to you (well, XCOM soldiers would book back to the dropzone, but aliens in this game don't have that luxury -- oh, I miss that in Apocalypse )

 

So, my plan is to replace some of the dev console debug conditionals in XGAIBehavior.state_ExecutingAI. My initial "panic now" code is as follows:

if(m_kUnit.IsBeingSuppressed() || m_iOverwatchDangerZone > 0)
{
	if((m_kUnit.GetNumFlankers() > 0) || (!m_kUnit.IsInCover() && m_kUnit.CanUseCover))
	{
		if(m_kUnit.GetVisibleFriends() == 0)
		{
			if(!m_kAbilityDM.m_bHasStrongAttack)
			{
				GotoState('Flee');
			}
		}
	}
}
  1. The first conditional checks whether the unit is being suppressed or overwatched. If it isn't it can move normally without fear, single moving to find some better cover and then shooting. So, no need to panic/flee if you aren't suppressed or overwatched. The AI generally does a pretty good job of getting out of being flanked when not overwatched / suppressed.
  2. The next conditional checks to see if there is anyone flanking the unit, or if the unit is standing around in the open. Some units can't use cover, like Cyberdiscs, Drones, Sectopods, Chyssalids, Zombies, and Berserkers. They don't need to find cover or flee, as they are presumed to have enough defense in the open to handle themselves. These units generally take action even when suppressed / overwatched as well, so no special AI condition is needed. Chryssalids, Zombies and Cyberdiscs are already configured to completely ignore overwatchers when considering movement options.
  3. The next conditional checks to see if the unit has any friends nearby (this seriously is an in-game function!). If there are friends nearby then no need to panic just yet, as maybe they'll be able to help you out.
  4. The last conditional checks to see if the unit has a strong attack. Specifically, if it has an attack that has a 50% or better chance to hit. At this point if it can shoot someone, that's probably the best alternative to getting shot at while dashing.
  5. Otherwise, FLEE!

-----------

 

I'm also planning to tweak the flee state code a bit with some previously written code. Basically it allows the unit to make a dashing move, and allows the unit to fallback on shooting as an emergency if it really absolutely fails to find a place to flee to (perhaps the player has cleverly blocked it in with 6 battlescanners, or fire is blocking off the only escape route -- whatever).

 

--------

 

If you are interested in more details, here is the code I plan to replace in XGAIBehavior.state_ExecutingAI:

 

 

            if(((m_bCanMove && XComTacticalCheatManager(GetALocalPlayerController().CheatManager) != none) && XComTacticalCheatManager(GetALocalPlayerController().CheatManager).bForceFlank) && ShouldFlank())
            {
                m_iDebugHangLocation = 4;
                GotoState('Flank');
            }
            else
            {
                if((m_bCanMove && XComTacticalCheatManager(GetALocalPlayerController().CheatManager) != none) && XComTacticalCheatManager(GetALocalPlayerController().CheatManager).bForceEngage)
                {
                    m_iDebugHangLocation = 5;
                    GotoState('Engage'); 

 

 

 

And here is the initial hex code I've prototyped to make sure that the functionality I wanted could be achieved:

 

 

if(m_kUnit.IsBeingSuppressed() || m_iOverwatchDangerZone > 0)
07 C3 01 84 19 01 B8 8A 00 00 0A 00 3E 31 00 00 00 1B F0 3C 00 00 00 00 00 00 16 18 0D 00 97 01 8C 8A 00 00 25 16 16 

	if((m_kUnit.GetNumFlankers() > 0) || (!m_kUnit.IsInCover() && m_kUnit.CanUseCover))
	07 C3 01 84 97 19 01 B8 8A 00 00 0A 00 D7 B1 00 00 00 1B A5 33 00 00 00 00 00 00 16 25 16 18 32 00 82 81 19 01 B8 8A 00 00 0A 00 A4 31 00 00 00 1C A5 31 00 00 16 18 1C 00 19 01 B8 8A 00 00 0B 00 CC 33 00 00 00 1B A3 0F 00 00 00 00 00 00 4A 16 16 16 
	
		if(m_kUnit.GetVisibleFriends().Length == 0)
		07 C3 01 9A 36 19 01 B8 8A 00 00 0A 00 B1 B2 00 00 00 1B 53 35 00 00 00 00 00 00 16 25 16 
		
			if(!m_kAbilityDM.m_bHasStrongAttack)
			07 C3 01 81 19 01 B3 8A 00 00 09 00 A7 88 00 00 00 01 A7 88 00 00 16 
			
				GotoState('Flee');
				71 21 10 2E 00 00 00 00 00 00 4A 4A 4A 16 

 

 

Link to comment
Share on other sites

Okay, here's an initial set of hex changes.

 

I've verified that the game doesn't crash on load, and that the AI can still take a variety of actions with the changes in play (moving, overwatching, double moving, moving then shooting, etc).

 

The primary change is to add some specific conditions under which the usual priority mechanism will be shortcut and the unit will be forced to flee. I've set dashing(true) for the the 'Flee' state, so hopefully the unit will correctly dash when it has to.

 

I've also included a provision to allow the unit to fallback to SwitchToAttack() if for some reason the unit is unable to execute a move during the Flee action. If the unit does take a single move to a point where it is not flanked (and survives), it will still be able to take its second action to shoot / overwatch / hunker down, etc.

 

I ended up re-ordering the calls in XGAIBehavior.InitTurn, as the m_iOverWatchDangerZone was not being computed before XGAIAbilityDM.InitTurn was called. I believe that this was the cause of the divide-by-zero error that was causing flanked + overwatched units to fail to take an action. I've included a revised version of that fix, which will now reduce the move score for overwatching units instead of flanking units.

 

hex changes:

 

 

Last Alien Standing AI Hex Changes

XGAIBehavior.InitTurn -- reordered so that OverWatchDangerZone is computed prior to XGAIAbilityDM initialization

original hex:
1B CB 3A 00 00 00 00 00 00 16 19 01 B3 8A 00 00 13 00 00 00 00 00 00 1B F7 3A 00 00 00 00 00 00 01 B8 8A 00 00 16 14 2D 01 C6 8A 00 00 28 14 2D 01 C3 8A 00 00 28 0F 01 8B 8A 00 00 2A 1B F2 3A 00 00 00 00 00 00 16 1B 6F 3A 00 00 00 00 00 00 16 0F 19 01 B9 8A 00 00 09 00 6F BB 00 00 00 01 6F BB 00 00 1B 4B 33 00 00 00 00 00 00 16 07 AE 02 2D 35 64 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 A5 35 5D 8A 00 00 65 8A 00 00 00 01 01 DE 8A 00 00 16 07 27 02 2D 35 5E 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 A5 35 5C 8A 00 00 65 8A 00 00 00 01 01 DE 8A 00 00 16 07 57 02 97 35 5C 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 2C 02 16 1B 74 11 00 00 00 00 00 00 16 06 AE 02 1B BD 6E 00 00 00 00 00 00 16 07 AE 02 B0 35 5F 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 C2 AB 1E 00 00 A0 40 38 3F 2C 40 16 16 16 14 2D 35 5E 8A 00 00 65 8A 00 00 00 01 01 DE 8A 00 00 27 07 E8 02 96 19 01 B8 8A 00 00 0A 00 37 34 00 00 00 1B 2F 35 00 00 00 00 00 00 16 01 BB 8A 00 00 16 A1 01 AD 8A 00 00 2C 3C 16 0F 01 AB 8A 00 00 1B 3B 32 00 00 00 00 00 00 16 07 13 03 9B 01 AB 8A 00 00 01 AC 8A 00 00 16 0F 1A 25 01 9B 8A 00 00 23 00 00 00 00 00 00 00 00 00 00 00 00 0F 1A 26 01 9B 8A 00 00 23 00 00 00 00 00 00 00 00 00 00 00 00 14 2D 01 C7 8A 00 00 28 0F 01 AE 8A 00 00 38 60 1F 2D 00 0F 01 A7 8A 00 00 19 01 B8 8A 00 00 0A 00 D7 32 00 00 00 1B FE 32 00 00 00 00 00 00 16 14 2D 01 CE 8A 00 00 28 14 2D 01 CA 8A 00 00 1B 0D 64 00 00 00 00 00 00 16 1B B4 14 00 00 00 00 00 00 16 04 0B 53

new hex:
1B CB 3A 00 00 00 00 00 00 16 14 2D 01 C6 8A 00 00 28 14 2D 01 C3 8A 00 00 28 0F 01 8B 8A 00 00 2A 1B F2 3A 00 00 00 00 00 00 16 1B 01 1A 00 00 00 00 00 00 16 19 01 B3 8A 00 00 13 00 00 00 00 00 00 1B F7 3A 00 00 00 00 00 00 01 B8 8A 00 00 16 0F 19 01 B9 8A 00 00 09 00 6F BB 00 00 00 01 6F BB 00 00 1B 4B 33 00 00 00 00 00 00 16 07 AE 02 2D 35 64 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 A5 35 5D 8A 00 00 65 8A 00 00 00 01 01 DE 8A 00 00 16 07 27 02 2D 35 5E 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 A5 35 5C 8A 00 00 65 8A 00 00 00 01 01 DE 8A 00 00 16 07 57 02 97 35 5C 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 2C 02 16 1B 74 11 00 00 00 00 00 00 16 06 AE 02 1B BD 6E 00 00 00 00 00 00 16 07 AE 02 B0 35 5F 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 C2 AB 1E 00 00 A0 40 38 3F 2C 40 16 16 16 14 2D 35 5E 8A 00 00 65 8A 00 00 00 01 01 DE 8A 00 00 27 07 E8 02 96 19 01 B8 8A 00 00 0A 00 37 34 00 00 00 1B 2F 35 00 00 00 00 00 00 16 01 BB 8A 00 00 16 A1 01 AD 8A 00 00 2C 3C 16 0F 01 AB 8A 00 00 1B 3B 32 00 00 00 00 00 00 16 07 13 03 9B 01 AB 8A 00 00 01 AC 8A 00 00 16 0F 1A 25 01 9B 8A 00 00 23 00 00 00 00 00 00 00 00 00 00 00 00 0F 1A 26 01 9B 8A 00 00 23 00 00 00 00 00 00 00 00 00 00 00 00 14 2D 01 C7 8A 00 00 28 0F 01 AE 8A 00 00 38 60 1F 2D 00 0F 01 A7 8A 00 00 19 01 B8 8A 00 00 0A 00 D7 32 00 00 00 1B FE 32 00 00 00 00 00 00 16 14 2D 01 CE 8A 00 00 28 14 2D 01 CA 8A 00 00 1B 0D 64 00 00 00 00 00 00 16 1B 6F 3A 00 00 00 00 00 00 16 04 0B 53

-----------------------


Let fleeing units have access to Dashing

XGAIBehavior.state_Flee.DecideNextDestination

original hex:
CF 8F 00 00 50 55 00 00 00 00 00 00 B3 8F 00 00 CA 8C 00 00 00 00 00 00 BA 8F 00 00 00 00 00 00 36 1A 00 00 A6 75 03 00 58 01 00 00 E8 00 00 00 0B 0E 1C F9 FF FF 61 43 48 BA 8F 00 00 1F 46 4C 45 45 00 16 0F 00 B6 8F 00 00 19 01 B8 8A 00 00 0A 00 D7 32 00 00 00 1B FE 32 00 00 00 00 00 00 16 0F 00 B7 8F 00 00 00 B6 8F 00 00 07 9E 00 2D 35 64 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 0F 00 B8 8F 00 00 35 60 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 0F 00 B4 8F 00 00 AF 1E 00 00 80 BF AB 12 20 BC 4D 00 00 2A 00 6F 4D 00 00 00 1C 71 4D 00 00 A8 A8 38 57 01 04 FA FF FF 38 57 61 1C 16 16 38 57 1C B5 FC FF FF 16 16 16 38 3F 2C 03 16 16 07 43 01 81 1B 6E 2D 00 00 00 00 00 00 00 B7 8F 00 00 00 B8 8F 00 00 00 B5 8F 00 00 00 B4 8F 00 00 48 BA 8F 00 00 16 16 1B C3 68 00 00 00 00 00 00 48 BA 8F 00 00 16 04 00 B7 8F 00 00 04 3A B9 8F 00 00 53 

new hex: (virtual size 0x154)
CF 8F 00 00 50 55 00 00 00 00 00 00 B3 8F 00 00 CA 8C 00 00 00 00 00 00 BA 8F 00 00 00 00 00 00 36 1A 00 00 A6 75 03 00 54 01 00 00 E8 00 00 00 19 01 B8 8A 00 00 0B 00 00 00 00 00 00 1B AE 61 00 00 00 00 00 00 27 16 0F 00 B6 8F 00 00 19 01 B8 8A 00 00 0A 00 D7 32 00 00 00 1B FE 32 00 00 00 00 00 00 16 0F 00 B7 8F 00 00 00 B6 8F 00 00 07 A2 00 2D 35 64 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 0F 00 B8 8F 00 00 35 60 8A 00 00 65 8A 00 00 00 00 01 DE 8A 00 00 0F 00 B4 8F 00 00 AF 1E 00 00 80 BF AB 12 20 BC 4D 00 00 2A 00 6F 4D 00 00 00 1C 71 4D 00 00 A8 A8 38 57 01 04 FA FF FF 38 57 61 1C 16 16 38 57 1C B5 FC FF FF 16 16 16 38 3F 2C 03 16 16 07 47 01 81 1B 6E 2D 00 00 00 00 00 00 00 B7 8F 00 00 00 B8 8F 00 00 00 B5 8F 00 00 00 B4 8F 00 00 48 BA 8F 00 00 16 16 1B C3 68 00 00 00 00 00 00 48 BA 8F 00 00 16 04 00 B7 8F 00 00 0B 0B 53 

-----------------------

Make (state 'flee') FindRunAwayPosition return true only if it actually found a run-away position, so that the SwitchToAttack can occur if it failed.

XGAIBehavior.state_Flee.FindRunawayPosition

before:
04 27 04 3A AB 8F 00 00 53 

after:
04 2D 01 D0 8A 00 00 0B 53 


-----------------------

XGAIBehavior.state_ExecutingAI -- added conditions for unit to flee

original hex: next-line at 0x1C0
07 26 01 82 82 82 2D 01 D5 8A 00 00 18 2C 00 77 2E DA 72 00 00 19 1C 69 FC FF FF 16 09 00 B9 F9 FF FF 00 01 B9 F9 FF FF 2A 16 16 18 3F 00 19 2E DA 72 00 00 19 1C 69 FC FF FF 16 09 00 B9 F9 FF FF 00 01 B9 F9 FF FF 0A 00 28 6F 00 00 00 2D 01 28 6F 00 00 16 18 0B 00 1B 06 64 00 00 00 00 00 00 16 16 0F 01 85 8A 00 00 2C 04 71 21 EE 2D 00 00 00 00 00 00 4A 4A 4A 16 06 31 08 07 C3 01 82 82 2D 01 D5 8A 00 00 18 2C 00 77 2E DA 72 00 00 19 1C 69 FC FF FF 16 09 00 B9 F9 FF FF 00 01 B9 F9 FF FF 2A 16 16 18 3F 00 19 2E DA 72 00 00 19 1C 69 FC FF FF 16 09 00 B9 F9 FF FF 00 01 B9 F9 FF FF 0A 00 27 6F 00 00 00 2D 01 27 6F 00 00 16 0F 01 85 8A 00 00 2C 05 71 21 5F 25 00 00 00 00 00 00 4A 4A 4A 16 


new hex: next-line at 0x1A0
07 C3 01 82 82 82 84 82 81 19 01 B8 8A 00 00 0A 00 A4 31 00 00 00 1C A5 31 00 00 16 16 18 21 00 19 01 B8 8A 00 00 0B 00 CC 33 00 00 00 1B A3 0F 00 00 00 00 00 00 4A 16 16 18 23 00 97 36 19 01 B8 8A 00 00 09 00 91 30 00 00 00 01 91 30 00 00 25 16 16 18 31 00 84 19 01 B8 8A 00 00 0A 00 3E 31 00 00 00 1B F0 3C 00 00 00 00 00 00 16 18 0D 00 97 01 8C 8A 00 00 25 16 16 16 18 23 00 9A 36 19 01 B8 8A 00 00 09 00 9B 30 00 00 00 01 9B 30 00 00 25 16 16 18 21 00 81 19 01 B3 8A 00 00 09 00 A7 88 00 00 00 01 A7 88 00 00 16 16 71 21 10 2E 00 00 00 00 00 00 4A 4A 4A 16 01 B8 8A 00 00 01 B8 8A 00 00 01 B8 8A 00 00 01 B8 8A 00 00 01 B8 8A 00 00 01 B8 8A 00 00 01 B8 8A 00 00 0B 0B 0B 0B 0B 0B 0B 0B 

----------------------

XGAIAbilityDM.AI_GetScoreModifier -- use OverWatchDangerZone now that it is set prior to this executing. Change to ensure no divide-by-zero errors.
	
original hex:
07 F6 01 82 81 19 01 B0 88 00 00 0A 00 C2 8A 00 00 00 2D 01 C2 8A 00 00 16 18 23 00 97 36 19 01 B1 88 00 00 09 00 77 BB 00 00 00 01 77 BB 00 00 25 16 16 B6 00 B8 88 00 00 AC 1E 9A 99 99 3E 38 3F 19 01 B0 88 00 00 09 00 8C 8A 00 00 00 01 8C 8A 00 00 16 16 

new hex:
07 F6 01 82 81 19 01 B0 88 00 00 0A 00 C2 8A 00 00 00 2D 01 C2 8A 00 00 16 18 22 00 97 19 01 B0 88 00 00 09 00 8C 8A 00 00 00 01 8C 8A 00 00 25 16 16 0B B6 00 B8 88 00 00 AC 1E 9A 99 99 3E 38 3F 19 01 B0 88 00 00 09 00 8C 8A 00 00 00 01 8C 8A 00 00 16 16  

 

 

 

The conditional implemented is logically equivalent, but a bit messier-looking due to the need to support a following else statement :

if(((!m_kUnit.IsInCover() && m_kUnit.CanUseCover()) || (m_kUnit.m_arrFlankingUnits.Length > 0)) && (m_kUnit.IsBeingSuppressed() || m_iOverwatchDangerZone > 0) && m_kUnit.m_arrVisibleFriends.Length == 0 && !m_kAbilityDM.m_bHasStrongAttack )
{		
	GotoState('Flee');
}

The conditions are fairly specific to try and prevent new exploitable behavior by the AI.

Link to comment
Share on other sites

And here is another attempted fix ... this time for Suppression causing aliens to skip their turn.

 

The root of the problem appears to be that Suppression causes the move ability to be "filtered" out -- it doesn't even get scored for priority. However, another function filters non-movement abilities if the unit is flanked, unless "ShouldAvoidMovement" is true. However, being Suppressed does not cause ShouldAvoidMovement to be true. This results in non-movement abilities being filtered because of flanking, while the move ability is filtered because of suppression, resulting in no valid abilities.

 

The exception in vanilla was floaters, as Launch counts as a move ability so isn't filtered from from being flanked, yet Launch is not filtered by Suppression. This resulted in flanked + suppressed floaters always using Launch, which is something I'd noticed while playing (mostly in retrospect ^_^).

 

The solution I've put together is to add a IsBeingSuppressed() condition to the ShouldAvoidMovement function. This really only represents the fact that movement has already been filtered, which prevents other abilities from being filtered due to being flanked.

 

The other condition for ShouldAvoidMovement was if the unit was unflanked and had a 70%+ shot. However, there was no exclusion for the unit being exposed, so I've added that in (with the further exception that a unit that is flying or can't use cover (e.g. Drone, Chryssalid, Sectopod) will avoid movement to take the shot still).

 

So, here is the hex replacement :

 

 

 

XGAIBehavior.ShouldAvoidMovement 

original hex:
header:
9E 8F 00 00 50 55 00 00 00 00 00 00 86 8F 00 00 00 00 00 00 00 00 00 00 89 8F 00 00 00 00 00 00 48 19 00 00 55 58 03 00 6F 01 00 00 07 01 00 00 

body:
07 11 01 82 9A 36 19 01 B8 8A 00 00 09 00 91 30 00 00 00 01 91 30 00 00 25 16 18 0D 00 81 2D 01 CA 8A 00 00 16 16 07 94 00 2D 01 C3 8A 00 00 0F 00 88 8F 00 00 1B A7 32 00 00 00 00 00 00 19 01 B8 8A 00 00 09 00 DE F8 FF FF 00 01 DE F8 FF FF 01 8B 8A 00 00 4A 16 07 91 00 97 00 88 8F 00 00 2C 46 16 04 27 06 11 01 58 19 01 B8 8A 00 00 67 00 9C 30 00 00 00 01 9C 30 00 00 00 87 8F 00 00 00 4A 10 01 0F 00 88 8F 00 00 1B A7 32 00 00 00 00 00 00 19 01 B8 8A 00 00 09 00 DE F8 FF FF 00 01 DE F8 FF FF 00 87 8F 00 00 28 16 07 0F 01 97 00 88 8F 00 00 2C 46 16 30 04 27 31 30 07 62 01 82 82 81 19 01 B8 8A 00 00 0A 00 10 34 00 00 00 1B D7 3D 00 00 00 00 00 00 16 16 18 0D 00 81 2D 01 C8 8A 00 00 16 16 18 16 00 97 01 8C 8A 00 00 1B 2A 33 00 00 00 00 00 00 16 16 16 04 27 04 28 04 3A 89 8F 00 00 53 

new hex: (virtual 0x167)
header:
9E 8F 00 00 50 55 00 00 00 00 00 00 86 8F 00 00 00 00 00 00 00 00 00 00 89 8F 00 00 00 00 00 00 48 19 00 00 55 58 03 00 67 01 00 00 07 01 00 00 

body:
07 E4 00 9A 36 19 01 B8 8A 00 00 09 00 91 30 00 00 00 01 91 30 00 00 25 16 07 E4 00 81 2D 01 CA 8A 00 00 16 07 E4 00 84 19 01 B8 8A 00 00 0A 00 A4 31 00 00 00 1C A5 31 00 00 16 18 0D 00 81 1B A3 0F 00 00 00 00 00 00 16 16 16 58 19 01 B8 8A 00 00 67 00 9C 30 00 00 00 01 9C 30 00 00 00 87 8F 00 00 00 4A E3 00 0F 00 88 8F 00 00 1B A7 32 00 00 00 00 00 00 19 01 B8 8A 00 00 09 00 DE F8 FF FF 00 01 DE F8 FF FF 00 87 8F 00 00 28 16 07 E2 00 97 00 88 8F 00 00 2C 46 16 30 04 27 31 30 07 08 01 19 01 B8 8A 00 00 0A 00 10 34 00 00 00 1B D7 3D 00 00 00 00 00 00 16 04 28 07 17 01 2D 01 C8 8A 00 00 04 28 07 3B 01 19 01 B8 8A 00 00 0A 00 3E 31 00 00 00 1B F0 3C 00 00 00 00 00 00 16 04 27 07 55 01 97 01 8C 8A 00 00 1B 2A 33 00 00 00 00 00 00 16 16 04 27 04 28 0B 0B 0B 0B 0B 04 3A 89 8F 00 00 53 
 

 

 

 

Have verified that the game doesn't crash on loading or when the AI takes actions.

 

Will take a while to verify an improvement in AI behavior, so I'm just posting it up "as is".

Link to comment
Share on other sites

Had an opportunity to put the new "last alien panic" AI change to the test.

 

Had faced down my third pod of Mutons (on a FC Mission no less ~_~ -- that's Long War for ya!), and had the last Muton down to 1 HP. I had one flanking unit, a Gunner that was suppressing, and two additional units on overwatch. All XCOM units were in full cover.

 

The new case appears to have kicked in -- the alien tried to make a break for it. Gunner reaction shot missed, as did my Medic (with SCOPE and laser rifle), but my Assault hit, killing it. No more passively-giving-up aliens! I think this is going to make capturing aliens a bit trickier. @_@

Link to comment
Share on other sites

Here's an example picture of a second situation involving the reworked AI.

 

http://wiki.tesnexus.com/images/3/38/2013-07-17_00001.jpg

 

In this scenario I also have a Sniper flanking the alien (in sight of the alien) off camera to the lower right.

 

If the alien is Suppressed + overwatched in this scenario its decision is to shoot at my Assault, who is just above the Muton. Range bonus for the Assault with pistol is +23, so presuming it is symmetric the alien has a 70 + 23 - 30 - 55 = 8% chance to hit the Assault, so it takes that shot. It did so for two consecutive turns, so it's pretty consistent.

 

However, when I re-loaded and moved my Assault out of line-of-sight of the Muton, and proceeded to Suppress + overwatch + flank (with the Sniper), the alien lost the +23 bonus for range so had only a 1% shot against the Sniper. In this scenario it chose to move, drawing some Suppressive and Overwatch fire which missed.

 

This generally seems to be an improvement over the previous behavior of not doing anything at all.

 

My Engineer with an Arc Thrower is just to the left of the Muton, and is stun range. The Engineer has tactical sense but Carapace armor so her defense is 50. Additionally the range is closer, supplying a +29 aim bonus for range. This means the Muton has a 70 + 29 - 30 - 50 = 19% chance to hit. However, the Engineer is not flanking the Muton, and the AI pretty rigorously prioritizes shooting at flanking targets, which is something I'd really rather not tinker with as 99% of the time it's the right decision.

Link to comment
Share on other sites

I think this is going to make capturing aliens a bit trickier. @_@

This is why I am not putting this fix into my mod (because it is already fairly challenging task (in my mod), that require multi-turn luck-defined plan(ugh, there is a lot of things, that may go horribly wrong already), with rolls for stun is being generated once per turn and are excluded from normal sequence of actions (so if game rolled that you fail this stun in this turn - you fail, no matter what you do); and with this "fix" it just overkill (I do not want to penalize player for bad rolls); however, I would like to this tactic employed by aliens in intelligent manner (when they have non-zero chance of survival, say 15%).

 

Once I was attempting capture of Muton, so he was suppressed, had his weapon disabled, and had assault with Close Combat Specialist standing next to him (just failed to stun him), and has been overwatched by 2 supports, so on alien turn he decided go all kamikaze on my troops, pulls of grenade and blows himself up along with my assault (this was actually good move, and surprised me); this happened with no fixes applied.

Edited by Tycus
Link to comment
Share on other sites

 

 

Once I was attempting capture of Muton, so he was suppressed, had his weapon disabled, and had assault with Close Combat Specialist standing next to him (just failed to stun him), and has been overwatched by 2 supports, so on alien turn he decided go all kamikaze on my troops, pulls of grenade and blows himself up along with my assault (this was actually good move, and surprised me); this happened with no fixes applied.

 

 

Some aliens have access to abilities that generally aren't affected by the Suppression + flanking glitch.

 

Floaters for instance have Launch, which counts as a move ability but is not filtered when the unit is suppressed. Mutons have grenades, which can hit regardless of reduction of to-hit values via Suppression.

 

What this does is close a loophole that is borderline between a tactic and an exploit.

 

Without this change it is possible to set up a situation (I have done it several times) in which the stunning unit can attempt several stuns over successive turns and the alien unit will perform no action at all on its turn. While that may be a decent simulation of non-optimal human behavior, taking no action makes it a bit exploit-y in my opinion.

 

This is because of the following combination of "hard rules" implemented in the AI:

1) If Suppressed, the move ability is filtered from priority calculations -- the unit can only move it it flees

2) If flanked, and not marked as shouldavoid movement (only happens if overwatched or if has a 70%+ shot), then filter any non-move abilities (everything but move / launch)

3) Always prioritize shooting at units that are flanking alien units

 

So, to shut down an alien :

0) Alien must be in cover

1) Put the stunner in cover to the alien (not exposed or flanked), within stun range but not flanking the alien

2) Suppress but do not overwatch the alien

3) Flank the alien with a unit at a distance (to avoid range bonuses), preferably one with defense bonuses from armor / tactical sense

 

This will result in the alien taking no action during its turn. It is only allowed to shoot the flankers, but all attack abilities are filtered because it is flanked. The move action is filtered because it is suppressed (and not overwatched). Paradoxically, overwatching the enemy in this situation will allow it to take attack actions like using grenades -- not overwatching will prevent them from happening.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...