public AttackDetails(AbstractActor attacker, ICombatant target, Vector3 attackPos, Vector3 targetPos, bool useRevengeBonus) { this.Attacker = attacker; this.Target = target; this.AttackPosition = attackPos; this.TargetPosition = targetPos; this.UseRevengeBonus = useRevengeBonus; // Precalculate some values heavily used by the prediction engine // Impact quality for any melee attack is always solid this.BaseRangedImpactQuality = SharedState.Combat.ToHit.GetBlowQuality(attacker, attackPos, null, target, MeleeAttackType.Punch, false); this.AttackerDesignMask = SharedState.Combat.MapMetaData.GetPriorityDesignMaskAtPos(attackPos); if (this.AttackerDesignMask == null) { AttackerDesignMask = new DesignMaskDef(); } this.TargetDesignMask = SharedState.Combat.MapMetaData.GetPriorityDesignMaskAtPos(targetPos); if (this.TargetDesignMask == null) { TargetDesignMask = new DesignMaskDef(); } // Calculate the total damage multiplier for attacks by weaponType this.DamageMultipliers.Add(DamageMultiType.Ballistic, CalculateDamageMulti(DamageMultiType.Ballistic, target)); this.DamageMultipliers.Add(DamageMultiType.Energy, CalculateDamageMulti(DamageMultiType.Energy, target)); this.DamageMultipliers.Add(DamageMultiType.Missile, CalculateDamageMulti(DamageMultiType.Missile, target)); this.DamageMultipliers.Add(DamageMultiType.Support, CalculateDamageMulti(DamageMultiType.Support, target)); this.DamageMultipliers.Add(DamageMultiType.Generic, CalculateDamageMulti(DamageMultiType.Generic, target)); }
public static void Prefix(Mech __instance, WeaponHitInfo hitInfo, ArmorLocation aLoc, Weapon weapon, float totalArmorDamage, float directStructureDamage, int hitIndex, AttackImpactQuality impactQuality, DamageType damageType) { if (aLoc == ArmorLocation.Head) { Mod.Log.Info($"Head hit from weapon:{weapon?.UIName} for {totalArmorDamage} armor damage and {directStructureDamage} structure damage. " + $"Quality was:{impactQuality} with type:{damageType}"); float currHeadArmor = __instance.GetCurrentArmor(aLoc); int damageMod = (int)Math.Ceiling(totalArmorDamage); float damageThroughArmor = totalArmorDamage - currHeadArmor; Mod.Log.Debug($"TotalArmorDamage:{totalArmorDamage} - Head armor:{currHeadArmor} = throughArmor:{damageThroughArmor}"); if (totalArmorDamage - currHeadArmor <= 0) { damageMod = (int)Math.Floor(damageMod * Mod.Config.Combat.PainTolerance.HeadHitArmorOnlyMulti); Mod.Log.Info($"Head hit impacted armor only, reduced damage to:{damageMod}"); } if (directStructureDamage != 0) { Mod.Log.Debug($"Attack inflicted ${directStructureDamage}, adding to total resist damage."); damageMod += (int)Math.Ceiling(directStructureDamage); } ModState.InjuryResistPenalty = damageMod * Mod.Config.Combat.PainTolerance.PenaltyPerHeadDamage; Mod.Log.Info($"Setting resist penalty to:{damageMod} x {Mod.Config.Combat.PainTolerance.PenaltyPerHeadDamage} = {ModState.InjuryResistPenalty}"); } }
static void Prefix(Mech __instance, int originalHitLoc, WeaponHitInfo hitInfo, ArmorLocation aLoc, Weapon weapon, float totalArmorDamage, float directStructureDamage, int hitIndex, AttackImpactQuality impactQuality, DamageType damageType) { if (aLoc == ArmorLocation.None || aLoc == ArmorLocation.Invalid) { return; } float num = totalArmorDamage; float currentArmor = __instance.GetCurrentArmor(aLoc); if (currentArmor > 0f) { num = totalArmorDamage - currentArmor; } num += directStructureDamage; // account for damage split: this should get us back where we were when we both had armour spillover damage and // any damage done directly to the structure if (num <= 0f) { return; //no need to continue if the shot doesn't do anything we care about } ChassisLocations chassisLocationFromArmorLocation = MechStructureRules.GetChassisLocationFromArmorLocation(aLoc); float currentStructure = __instance.GetCurrentStructure(chassisLocationFromArmorLocation); if (currentStructure > 0f) { float num4 = Math.Min(num, currentStructure); bool WasDestroyed = (currentStructure - num) <= 0; //if currentstructure minus remaining damage is less or equal to 0, then the location is destroyed. num -= num4; if (WasDestroyed && num4 > 0.01f) //this location was destroyed, so we now check for dependents. { if (chassisLocationFromArmorLocation == ChassisLocations.LeftArm) { Holder.LeftArmSurvived = false; //invalidate if the actual arm was destroyed } else if (chassisLocationFromArmorLocation == ChassisLocations.RightArm) { Holder.RightArmSurvived = false; //invalidate if the actual arm was destroyed } ChassisLocations dependentLocation = MechStructureRules.GetDependentLocation(chassisLocationFromArmorLocation); if (dependentLocation != ChassisLocations.None && !__instance.IsLocationDestroyed(dependentLocation)) { if (dependentLocation == ChassisLocations.LeftArm) { Holder.LeftArmSurvived = true; //side torso was destroyed, no reason the arm should be totally trashed. } else if (dependentLocation == ChassisLocations.RightArm) { Holder.RightArmSurvived = true; //side torso was destroyed, no reason the arm should be totally trashed. } } } } }
static void Prefix(Mech __instance, int originalHitLoc, WeaponHitInfo hitInfo, ArmorLocation aLoc, Weapon weapon, float totalDamage, int hitIndex, AttackImpactQuality impactQuality) { if (aLoc == ArmorLocation.Head) { //we do some quick calculation of damage to see if it's an armor hit or an structure hit float currentArmor = __instance.GetCurrentArmor(aLoc); float remainingDamage = totalDamage - currentArmor; if (remainingDamage <= 0 && totalDamage < LessHeadInjuries.ArmorHeadHitIgnoreDamageBelow) { //remainign damage less or equal to zero mean no structure penetration. Treat as an armour hit. LessHeadInjuries.IgnoreNextHeadHit.Add(__instance.pilot); } else if (remainingDamage > 0 && totalDamage < LessHeadInjuries.StructHeadHitIgnoreDamageBelow) { LessHeadInjuries.IgnoreNextHeadHit.Add(__instance.pilot); } } }
static void Prefix(Mech __instance, int originalHitLoc, WeaponHitInfo hitInfo, ArmorLocation aLoc, Weapon weapon, float totalArmorDamage, float directStructureDamage, int hitIndex, AttackImpactQuality impactQuality, DamageType damageType) { if (aLoc == ArmorLocation.Head) { Boolean DirectHit = false; //we do some quick calculation of damage to see if it's an armor hit or an structure hit float currentArmor = Math.Max(__instance.GetCurrentArmor(aLoc), 0f); //either it has armor remaining or it's got nothing left float remainingDamage = totalArmorDamage - currentArmor; // subtract our armour damage by totalArmorDamage: if it's more than 0, we calculate for structure damage float structureDamage = directStructureDamage; if (remainingDamage > 0f) { structureDamage += remainingDamage; } if (structureDamage >= 0f) // need to account for direct structure damage { DirectHit = true; } if (!DirectHit && totalArmorDamage < LessHeadInjuries.Settings.ArmorHitDamageMinimum) { //remainign damage less or equal to zero mean no structure penetration. Treat as an armour hit. LessHeadInjuries.IgnoreNextHeadHit.Add(__instance.pilot); } else if (DirectHit && structureDamage < LessHeadInjuries.Settings.StructureHitDamageMinimum) { LessHeadInjuries.IgnoreNextHeadHit.Add(__instance.pilot); } } }
internal static bool DamageLocation(this Mech mech, int originalHitLoc, WeaponHitInfo hitInfo, ArmorLocation aLoc, Weapon weapon, float totalArmorDamage, float directStructureDamage, int hitIndex, AttackImpactQuality impactQuality, DamageType damageType) { return(Traverse.Create(mech).Method(nameof(DamageLocation), originalHitLoc, hitInfo, aLoc, weapon, totalArmorDamage, directStructureDamage, hitIndex, impactQuality, damageType).GetValue <bool>()); }
internal static bool DamageLocation(this Vehicle vehicle, WeaponHitInfo hitInfo, int originalHitLoc, VehicleChassisLocations vLoc, Weapon weapon, float totalDamage, AttackImpactQuality impactQuality) { return(Traverse.Create(vehicle).Method(nameof(DamageLocation), hitInfo, originalHitLoc, vLoc, weapon, totalDamage, impactQuality).GetValue <bool>()); }
internal static void Postfix(Mech __instance, int originalHitLoc, WeaponHitInfo hitInfo, ArmorLocation aLoc, Weapon weapon, float totalDamage, int hitIndex, AttackImpactQuality impactQuality, bool __result) { currentMech = null; }