CoverLevelOverride

Tracking Issue: #1565

This feature allows mods to override which cover level a unit has against an attack by another unit on a case-by-case basis, gaining various tactical benefits.

Normally this override would have been implemented as an event, but events in To Hit Chance Calculation logic can cause issues, see GetHitChanceEvents, so the delegates system is used instead.

This feature applies to X2Effect_HuntersInstinctDamage, X2AbilityToHitCalc_StandardAim, and all descendants thereof. It does not apply to hit calcs if:

  • It is a descendant class which overrides GetHitChance without supporting this feature
  • The attack is not subject to cover (bIndirectFire, bMeleeAttack)
  • It does apply if bIgnoreCoverBonus is true, but does not override its behavior

It does not apply to Hunter's Instinct if:

  • It is a descendant class which overrides GetAttackingDamageModifier without supporting this feature
  • The effect would not be affected by cover level (e.g. it's a melee attack and thus ineligible for Hunter's Instinct)

NOTE: While this feature allows the delegate to affect other visibility data, the results of changing it are not fully understood by the developer. Use with caution!

How to use

Implement the following code in your mod's X2DownloadableContentInfo class:

static event OnPostTemplatesCreated()
{
    local CHHelpers CHHelpersObj;

    CHHelpersObj = class'CHHelpers'.static.GetCDO();
    if (CHHelpersObj != none)
    {
        CHHelpersObj.AddOverrideHasHeightAdvantageCallback(OverrideHasHeightAdvantage);
    }
}

// To avoid crashes associated with garbage collection failure when transitioning between Tactical and Strategy,
// this function must be bound to the ClassDefaultObject of your class. Having this function in a class that
// `extends X2DownloadableContentInfo` is the easiest way to ensure that.
static private function EHLDelegateReturn OverrideHasHeightAdvantage(XComGameState_Unit Attacker, XComGameState_Unit TargetUnit, out GamesRuleCache_VisibilityInfo VisInfo, Object EventSource)
{
    // Optionally modify `VisInfo.TargetCover` here.
    // This is an enum containing the target's cover level against the attacker.

    // Return EHLDR_NoInterrupt or EHLDR_InterruptDelegates depending on
    // if you want to allow other delegates to run after yours
    // and potentially modify VisInfo further.
    return EHLDR_NoInterrupt;
}

Delegate Priority

You can optionally specify callback Priority.

CHHelpersObj.AddOverrideCoverLevelCallback(OverrideCoverLevel, 45);

Delegates with higher Priority value are executed first. Delegates with the same Priority are executed in the order they were added to CHHelpers, which would normally be the same as DLCRunOrder. This function will return true if the delegate was successfully registered.

Removing Delegates

If necessary, it's possible to remove a delegate.

CHHelpersObj.RemoveOverrideCoverLevelCallback(OverrideCoverLevel);

The function will return true if the Callback was successfully deleted, return false otherwise.

Source code references