Damage Callbacks#

Damage callbacks allow you to override damage decisions made by the zone system. This callback fires when damage is dealt, blocked, or reflected, and allows you to override the decision to allow or block damage.

Important: Damage callbacks run after ShouldAllowDamage makes its decision. You can override the decision by returning true to force allow damage, or return the original result to respect the zone system's decision.

Interface#

class DamageCallback
{
    // Called when damage is about to be dealt to a player
    // @param victim - The player receiving damage
    // @param attacker - The player dealing damage (can be null for environmental damage)
    // @param damageResult - The damage calculation result
    // @param damageType - Type of damage (e.g., DT_FIRE, DT_BULLET)
    // @param source - The entity causing damage
    // @param component - Component index
    // @param dmgZone - Damage zone name
    // @param ammo - Ammo type
    // @param modelPos - Model position
    // @param speedCoef - Speed coefficient
    // @param shouldAllowDamageResult - The decision from ShouldAllowDamage (true = allow, false = block)
    // @return true to force allow damage, false or shouldAllowDamageResult to respect original decision
    bool OnShouldAllowDamageOverride(PlayerBase victim, PlayerBase attacker, TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef, bool shouldAllowDamageResult) {}
    
    // Called when damage is about to be dealt to an item
    // @param item - The item receiving damage
    // @param attacker - The player dealing damage (can be null)
    // @param damageResult - The damage calculation result
    // @param damageType - Type of damage
    // @param source - The entity causing damage
    // @param dmgZone - Damage zone name
    // @param ammo - Ammo type
    // @param modelPos - Model position
    // @param speedCoef - Speed coefficient
    // @param shouldAllowItemDamageResult - The decision from ShouldAllowItemDamage (true = allow, false = block)
    // @return true to force allow damage, false or shouldAllowItemDamageResult to respect original decision
    bool OnShouldAllowItemDamageOverride(ItemBase item, PlayerBase attacker, TotalDamageResult damageResult, int damageType, EntityAI source, string dmgZone, string ammo, vector modelPos, float speedCoef, bool shouldAllowItemDamageResult) {}
}

Registration#

Server-side only:

// In your mod's MissionServer.c file
modded class MissionServer
{
    override void OnInit()
    {
        super.OnInit();
        
        // Create and register the damage callback
        MyDamageCallback myCallback = new MyDamageCallback();
        DamageUtils.RegisterDamageCallback(myCallback);
    }
}

// Define your callback class
class MyDamageCallback : DamageCallback
{
    override bool OnShouldAllowDamageOverride(PlayerBase victim, PlayerBase attacker, TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef, bool shouldAllowDamageResult)
    {
        if (!victim)
            return shouldAllowDamageResult;
        
        // Your custom logic here
        // Return true to force allow damage, or shouldAllowDamageResult to respect original decision
        return shouldAllowDamageResult;
    }
    
    override bool OnShouldAllowItemDamageOverride(ItemBase item, PlayerBase attacker, TotalDamageResult damageResult, int damageType, EntityAI source, string dmgZone, string ammo, vector modelPos, float speedCoef, bool shouldAllowItemDamageResult)
    {
        if (!item)
            return shouldAllowItemDamageResult;
        
        // Your custom logic here
        return shouldAllowItemDamageResult;
    }
}

How It Works#

The damage callback system works as follows:

  1. Damage Event Occurs: When damage is about to be dealt, the zone system first evaluates whether to allow or block it based on zone rules (PvE protection, SafeZone protection, etc.).
  2. ShouldAllowDamage Decision: The zone system makes a decision (shouldAllowDamageResult). If true, damage is allowed. If false, damage is blocked.
  3. Callback Execution: Your callback is called with the decision. You can:
    • Return true to force allow damage (override the zone system's decision)
    • Return false or shouldAllowDamageResult to respect the zone system's decision
  4. Final Decision: The callback's return value becomes the final decision.
Warning: Be careful when overriding damage decisions. Allowing damage in PvE zones or SafeZones can break gameplay balance. Always validate conditions before overriding.

Zone State Checks#

You can check the zone state of players using these properties:

// Check if player is in a PvE zone
bool isInPvE = player.netSync_IsInPvEZone;

// Check if player is in a PvP zone
bool isInPvP = player.netSync_IsInPvPZone;

// Check if player is in a SafeZone
bool isInSafeZone = player.netSync_IsInSafeZone;

// For items, get the owner first
PlayerBase owner = item.GetOwnerPlayer();
if (owner)
{
    bool ownerInPvE = owner.netSync_IsInPvEZone;
    bool ownerInPvP = owner.netSync_IsInPvPZone;
    bool ownerInSafeZone = owner.netSync_IsInSafeZone;
}

Use Cases#

For a complete working example, see Example 5: Allow Damage in PvE Zones in the Examples section.