private static void Postfix(Mech __instance, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType) { AttackDirector.AttackSequence attackSequence = __instance.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId); AbstractActor actor = __instance.Combat.FindActorByGUID(hitInfo.targetId); if (actor is Mech) { Mech target = actor as Mech; float stabilityDamage = hitInfo.ConsolidateInstability(weapon.Instability(), __instance.Combat.Constants.ResolutionConstants.GlancingBlowDamageMultiplier, __instance.Combat.Constants.ResolutionConstants.NormalBlowDamageMultiplier, __instance.Combat.Constants.ResolutionConstants.SolidBlowDamageMultiplier); stabilityDamage *= __instance.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier"); stabilityDamage *= __instance.EntrenchedMultiplier; if (AttackDirector.attackLogger.IsLogEnabled) { AttackDirector.attackLogger.Log("[CBTPiloting] Checking Piloting Stability"); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Is Mech: {0}", (actor is Mech))); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Weapon Stab Dmg: {0}", stabilityDamage)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Target Dead: {0}", target.IsDead)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Target Unsteady: {0}", target.IsUnsteady)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Target IsOrWillBeProne: {0}", target.IsOrWillBeProne)); } if (stabilityDamage > 0 && !target.IsDead && target.IsUnsteady && !target.IsOrWillBeProne) { float skillBonus = (float)target.SkillPiloting / __instance.Combat.Constants.PilotingConstants.PilotingDivisor; float skillRoll = __instance.Combat.NetworkRandom.Float(); float skillTotal = skillRoll + skillBonus; if (AttackDirector.attackLogger.IsLogEnabled) { AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Bonus: {0}", skillBonus)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Roll: {0}", skillRoll)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Roll Total: {0}", skillTotal)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Target: {0}", CBTPiloting.Settings.PilotStabilityCheck)); } if (skillTotal < CBTPiloting.Settings.PilotStabilityCheck) { if (AttackDirector.attackLogger.IsLogEnabled) { AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Check Failed! Flagging for Knockdown")); } target.FlagForKnockdown(); target.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(target, $"Stability Check: Failed!", FloatieMessage.MessageNature.Debuff, true))); } else { if (AttackDirector.attackLogger.IsLogEnabled) { AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Check Succeeded!")); } target.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(target, $"Stability Check: Passed!", FloatieMessage.MessageNature.Buff, true))); } } } }
public static void Postfix(Mech __instance, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType) { Mod.Log.Trace("M:RWD entered."); AttackDirector.AttackSequence attackSequence = __instance.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId); AbstractActor actor = __instance.Combat.FindActorByGUID(hitInfo.targetId); if (actor is Mech target) { CombatResolutionConstantsDef crcd = __instance.Combat.Constants.ResolutionConstants; float stabilityDamage = hitInfo.ConsolidateInstability(hitInfo.targetId, weapon.Instability(), crcd.GlancingBlowDamageMultiplier, crcd.NormalBlowDamageMultiplier, crcd.SolidBlowDamageMultiplier); stabilityDamage *= __instance.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier"); stabilityDamage *= __instance.EntrenchedMultiplier; Mod.Log.Debug($" == Checking Piloting Stability"); Mod.Log.Debug($" target:{CombatantHelper.LogLabel(target)} isMech:{(actor is Mech)} IsDead:{target.IsDead} IsUnsteady:{target.IsUnsteady} IsOrWillBeProne:{target.IsOrWillBeProne}"); Mod.Log.Debug($" weapon stability damage:{stabilityDamage}"); if (stabilityDamage > 0 && !target.IsDead && target.IsUnsteady && !target.IsOrWillBeProne) { float skillBonus = (float)target.SkillPiloting / __instance.Combat.Constants.PilotingConstants.PilotingDivisor; float skillRoll = __instance.Combat.NetworkRandom.Float(); float skillTotal = skillRoll + skillBonus; Mod.Log.Debug($" Skill check -> bonus: {skillBonus} roll: {skillRoll} rollTotal: {skillTotal} target:{Mod.Config.PilotStabilityCheck}"); if (skillTotal < Mod.Config.PilotStabilityCheck) { Mod.Log.Debug(string.Format(" Skill Check Failed! Flagging for Knockdown")); bool showMessage = !target.IsFlaggedForKnockdown; target.FlagForKnockdown(); if (Mod.Config.ShowAllStabilityRolls || showMessage) { target.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(target, $"Stability Check: Failed!", FloatieMessage.MessageNature.Debuff, true))); } } else { Mod.Log.Debug(string.Format(" Skill Check Succeeded!")); if (Mod.Config.ShowAllStabilityRolls) { target.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(target, $"Stability Check: Passed!", FloatieMessage.MessageNature.Buff, true))); } } } else { Mod.Log.Debug($" target has no stability damage, is not unsteady, or is dead or prone - skipping"); } } }
// The default method assumes an absractActor exists, and tries to draw a line of fire. We don't have that, so skip it. public static void ResolveSourcelessWeaponDamage(this Mech mech, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType) { AttackDirector.AttackSequence attackSequence = ModState.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId); float damagePerShot = weapon.DamagePerShot; float structureDamagePerShot = weapon.StructureDamagePerShot; LineOfFireLevel lineOfFireLevel = LineOfFireLevel.LOFClear; damagePerShot = mech.GetAdjustedDamage(damagePerShot, weapon.WeaponCategoryValue, mech.occupiedDesignMask, lineOfFireLevel, false); structureDamagePerShot = mech.GetAdjustedDamage(structureDamagePerShot, weapon.WeaponCategoryValue, mech.occupiedDesignMask, lineOfFireLevel, false); foreach (KeyValuePair <int, float> keyValuePair in hitInfo.ConsolidateCriticalHitInfo(mech.GUID, damagePerShot)) { if (keyValuePair.Key != 0 && keyValuePair.Key != 65536 && (mech.ArmorForLocation(keyValuePair.Key) <= 0f || structureDamagePerShot > 0f)) { ChassisLocations chassisLocationFromArmorLocation = MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)keyValuePair.Key); if (!mech.IsLocationDestroyed(chassisLocationFromArmorLocation)) { Traverse checkForCritT = Traverse.Create(mech).Method("CheckForCrit", new Type[] { typeof(WeaponHitInfo), typeof(ChassisLocations), typeof(Weapon) }); checkForCritT.GetValue(new object[] { hitInfo, chassisLocationFromArmorLocation, weapon }); } } } if (weapon.HeatDamagePerShot > 0f) { bool flag = false; for (int i = 0; i < hitInfo.numberOfShots; i++) { if (hitInfo.DidShotHitTarget(mech.GUID, i) && hitInfo.ShotHitLocation(i) != 0 && hitInfo.ShotHitLocation(i) != 65536) { flag = true; mech.AddExternalHeat(string.Format("Heat Damage from {0}", weapon.Description.Name), (int)weapon.HeatDamagePerShotAdjusted(hitInfo.hitQualities[i])); } } if (flag && attackSequence != null) { attackSequence.FlagAttackDidHeatDamage(mech.GUID); } } float num3 = hitInfo.ConsolidateInstability(mech.GUID, weapon.Instability(), mech.Combat.Constants.ResolutionConstants.GlancingBlowDamageMultiplier, mech.Combat.Constants.ResolutionConstants.NormalBlowDamageMultiplier, mech.Combat.Constants.ResolutionConstants.SolidBlowDamageMultiplier); num3 *= mech.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier"); num3 *= mech.EntrenchedMultiplier; mech.AddAbsoluteInstability(num3, StabilityChangeSource.Attack, hitInfo.attackerId); }
public static void Postfix(Mech __instance, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType) { Mod.Log.Trace("M:RWD entered."); AttackDirector.AttackSequence attackSequence = __instance.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId); AbstractActor target = __instance.Combat.FindActorByGUID(hitInfo.targetId); if (target is Mech targetMech) { // Feature: Piloting Skill Check from instability // TODO: Let instability represent this? CombatResolutionConstantsDef crcd = target.Combat.Constants.ResolutionConstants; float stabilityDamage = hitInfo.ConsolidateInstability(hitInfo.targetId, weapon.Instability(), crcd.GlancingBlowDamageMultiplier, crcd.NormalBlowDamageMultiplier, crcd.SolidBlowDamageMultiplier); stabilityDamage *= __instance.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier"); stabilityDamage *= __instance.EntrenchedMultiplier; MechHelper.PilotCheckOnInstabilityDamage(targetMech, stabilityDamage); } }