Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow mods to adjust AI behaviour of AoE profiles to specifically exclude lost units #1369

Open
BlackDog86 opened this issue Aug 2, 2024 · 9 comments · May be fixed by #1451
Open

Allow mods to adjust AI behaviour of AoE profiles to specifically exclude lost units #1369

BlackDog86 opened this issue Aug 2, 2024 · 9 comments · May be fixed by #1451
Assignees
Milestone

Comments

@BlackDog86
Copy link
Contributor

BlackDog86 commented Aug 2, 2024

Currently, XGAIBehaviour does not have any specific means of excluding lost units from AoE targetting profiles. Setting bTargetTheLost in XComAI.ini allows units to explicitly include lost for abilities which wouldn't otherwise (this is only set for Harbor Wave and purifier flamethrower in the base game) but there is nothing which specifically excludes lost units when bTargetEnemy is set (which is thge default setting for all abilities if not explicity set in AI config).

Proposal would be to add an additional variable (bExpliciltyExludeLost or similar) to the AoETargetingInfo struct and set up some code to remove lost units from the valid targets UnitList array if that bool is set (similar to how the Deprioritised effects bit works in the GetUnfilteredAOETargetList function).

Advice on whether this would be a sensible approach would be greatly appreciated!

@Iridar
Copy link
Contributor

Iridar commented Aug 2, 2024

Does this have a use case?

@BlackDog86
Copy link
Contributor Author

BlackDog86 commented Aug 2, 2024

Yes, basically to stop grenadiers, rocketeers and modded units with AoE AI profiles from firing explosives at big groups of lost and prioritising XCOM soldiers. I'd like to implement it on the AoE profiles in my alien pack, for one thing but it would be a useful nice-to-have across the board I think, being able to just set a flag in the AI config and have AoE abilities not count lost units for targetting purposes (e.g. Must have max 2 non-lost units to target this area or w.e.)

@Iridar
Copy link
Contributor

Iridar commented Aug 2, 2024

Seems like a legitimate use of AOE abilities though?

@BlackDog86
Copy link
Contributor Author

BlackDog86 commented Aug 2, 2024

Well, grenadiers flashbanging lost is pretty weird, as is vipers using posion spit on them (giving they are immune to both). Perhaps it could be gotten around by using bTestTargetEffectsApply in the AI, or with specific conditions applied on the abilities via OPTC or something but the test-target-effects check looks pretty janky in the source. Generally, I think it would be nice for modders to have more choice/control to exclude them from the targetting arrays but I'm open to alternative suggestions.

@Iridar
Copy link
Contributor

Iridar commented Aug 2, 2024

Fair enough

@BlackDog86
Copy link
Contributor Author

BlackDog86 commented Aug 21, 2024

Since RJ has suggested that the proposed commit is a bit iffy - are there other implementations that might work? For example, there is an X2Condition in LWOTC

class X2Condition_NotLost extends X2Condition;

event name CallMeetsCondition(XComGameState_BaseObject kTarget) 
{
	local XComGameState_Unit UnitState;

	UnitState = XComGameState_Unit(kTarget);

	if (UnitState != none)
	{
		if (UnitState.GetTeam() != eTeam_TheLost)
		{
			return 'AA_Success'; 
		}
	}
	else return 'AA_NotAUnit';

	return 'AA_AbilityUnavailable';
}

Would putting such an X2_Condition on the ability, along with setting bTestTargetEffectsApply in the XGAIBehaviour be enough to have the same effect?

@Iridar
Copy link
Contributor

Iridar commented Sep 5, 2024

I don't really know how AI works.

@Iridar Iridar modified the milestones: 1.29.0, 1.30.0 Dec 2, 2024
@BlackDog86
Copy link
Contributor Author

BlackDog86 commented Jan 7, 2025

Just been doing a little more testing on this issue. Whilst it's not related to 'specifically' excluding lost from AOE profiles, there is a (at least one) bug in XGAIBehavior::GetAllAOETargets which is short circuiting the check for whether targets are immune to the effects AOE abilities, if bTestTargetEffectsApply is set on the AOE Targeting Profile in the AI.
Added some logging here:

if ( Profile.bTestTargetEffectsApply )
		{
			`log("XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid:" @ bValid,,'BDLOG');
			AbilityTemplate = AbilityState.GetMyTemplate();
			// Ignore units that are immune to this ability. (passes as long as any effect applies to this unit)
			foreach AbilityTemplate.AbilityMultiTargetEffects(MultiTargetEffect)
			{				
				if (MultiTargetEffect.TargetIsValidForAbility(TargetState, UnitState, AbilityState))
				{
					`log("XGAIBehaviour::GetAllAOETargets:Ability:" @ AbilityState.GetMyTemplateName() @ "Effect:" @ MultiTargetEffect.Class @ "Considered valid for TestTargetEffectsApply",,'BDLOG');
					bValid = true;
					break;
				}
			}
			if (!bValid)
			{
				continue;
			}
		}

And here is the output of a custom poison spit ability from one of the Vipers in the LWOTC Alien pack (I set bTestTargetEffectsApply on all of the AOE profiles on the AI in my pack as a contingency): As you can see, because bValid is not set back to false at the start of the For loop, if it finds one unit that isn't immune to the effects, it considers every other target in the AOE as not immune as well. As a minimum, if we re-set this to false, it will make AOE profiles with TestTargetEffectsApply somewhat better. However I think there may be other ways that the check can be circumvented as well.

[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: Soldier ObjectID: 21
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: False
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:Ability: BD_PoisonSpit Effect: X2Effect_ApplyWeaponDamage Considered valid for TestTargetEffectsApply
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: Soldier ObjectID: 24
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: SparkSoldier ObjectID: 27
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: Soldier ObjectID: 31
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP6 ObjectID: 85
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP3 ObjectID: 1425
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostDasherHP5 ObjectID: 1464
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP2 ObjectID: 1476
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP2 ObjectID: 1500
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP5 ObjectID: 1512
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP2 ObjectID: 1648
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP3 ObjectID: 1660
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP2 ObjectID: 1672
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP4 ObjectID: 1684
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostDasherHP3 ObjectID: 1696
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP6 ObjectID: 1708
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP4 ObjectID: 1720
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:UnfilteredTargetList: TheLostHP2 ObjectID: 1732
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets: Testing target effects apply: bValid: True
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: Soldier ObjectID: 21
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: Soldier ObjectID: 24
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: SparkSoldier ObjectID: 27
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: Soldier ObjectID: 31
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP6 ObjectID: 85
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP3 ObjectID: 1425
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostDasherHP5 ObjectID: 1464
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP2 ObjectID: 1476
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP2 ObjectID: 1500
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP5 ObjectID: 1512
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP2 ObjectID: 1648
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP3 ObjectID: 1660
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP2 ObjectID: 1672
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP4 ObjectID: 1684
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostDasherHP3 ObjectID: 1696
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP6 ObjectID: 1708
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP4 ObjectID: 1720
[1686.60] BDLOG: XGAIBehaviour::GetAllAOETargets:FilteredTargetList: TheLostHP2 ObjectID: 1732

@Iridar
Copy link
Contributor

Iridar commented Jan 7, 2025

bValid is not set back to false at the start of the For loop

Yeah fixing this seems reasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants