public static Func <AttackModifier> GetMeleeModifierFactor(string factorId) { switch (factorId) { case "armmounted": return(() => { AttackModifier result = new AttackModifier("PUNCHING ARM"); if (AttackType == MeleeAttackType.DFA || Target is Vehicle || Target.IsProne || !(Attacker is Mech mech)) { return result; } if (mech.MechDef.Chassis.PunchesWithLeftArm) { if (mech.IsLocationDestroyed(ChassisLocations.LeftArm)) { return result; } } else if (mech.IsLocationDestroyed(ChassisLocations.RightArm)) { return result; } return result.SetValue(CombatConstants.ToHit.ToHitSelfArmMountedWeapon); }); case "dfa": return(() => new AttackModifier("DEATH FROM ABOVE", Hit.GetDFAModifier(AttackType))); case "height": return(() => { AttackModifier result = new AttackModifier("HEIGHT DIFF"); if (AttackType == MeleeAttackType.DFA) { return result.SetValue(Hit.GetHeightModifier(Attacker.CurrentPosition.y, Target.CurrentPosition.y)); } float diff = AttackPos.y - Target.CurrentPosition.y; if (Math.Abs(diff) < HalfMaxMeleeVerticalOffset || (diff < 0 && !CombatConstants.ToHit.ToHitElevationApplyPenalties)) { return result; } float mod = CombatConstants.ToHit.ToHitElevationModifierPerLevel; return result.SetValue(diff <= 0 ? mod : -mod); }); case "obstruction": return(() => new AttackModifier("OBSTRUCTED", Hit.GetCoverModifier(Attacker, Target, Combat.LOS.GetLineOfFire(Attacker, AttackPos, Target, TargetPos, Target.CurrentRotation, out Vector3 collision)))); case "refire": return(() => new AttackModifier("RE-ATTACK", Hit.GetRefireModifier(AttackWeapon))); case "selfchassis": return(() => new AttackModifier(Hit.GetMeleeChassisToHitModifier(Attacker, AttackType)).SetName("CHASSIS PENALTY", "CHASSIS BONUS")); case "targetevasion": return(() => { AttackModifier result = new AttackModifier("TARGET MOVED"); if (!(Target is AbstractActor actor)) { return result; } return result.SetValue(Hit.GetEvasivePipsModifier(actor.EvasivePipsCurrent, AttackWeapon)); }); case "targetprone": return(() => new AttackModifier("TARGET PRONE", Hit.GetTargetProneModifier(Target, true))); case "targetshutdown": return(() => new AttackModifier("TARGET SHUTDOWN", Hit.GetTargetShutdownModifier(Target, true))); } return(null); }
public static Func <AttackModifier> GetRangedModifierFactor(string factorId) { switch (factorId) { case "armmounted": return(() => new AttackModifier("ARM MOUNTED", Hit.GetSelfArmMountedModifier(AttackWeapon))); case "range": // Depended by ShowNeutralRangeInBreakdown return(() => { Weapon w = AttackWeapon; float range = Vector3.Distance(AttackPos, TargetPos), modifier = Hit.GetRangeModifierForDist(w, range); AttackModifier result = new AttackModifier(modifier); if (range < w.MinRange) { return result.SetName($"MIN RANGE (<{(int)w.MinRange}m)"); } if (range < w.ShortRange) { return result.SetName("SHORT RANGE" + SmartRange(w.MinRange, range, w.ShortRange)); } if (range < w.MediumRange) { return result.SetName("MED RANGE" + SmartRange(w.ShortRange, range, w.MediumRange)); } if (range < w.LongRange) { return result.SetName("LONG RANGE" + SmartRange(w.MediumRange, range, w.LongRange)); } if (range < w.MaxRange) { return result.SetName("MAX RANGE" + SmartRange(w.LongRange, range, w.MaxRange)); } return result.SetName($"OUT OF RANGE (>{(int)w.MaxRange}m)"); }); case "height": return(() => new AttackModifier("HEIGHT", Hit.GetHeightModifier(AttackPos.y, TargetPos.y))); case "indirect": return(() => new AttackModifier("INDIRECT FIRE", Hit.GetIndirectModifier(Attacker, LineOfFire < LineOfFireLevel.LOFObstructed && AttackWeapon.IndirectFireCapable))); case "locationdamage": return(() => { if (Attacker is Mech mech) { Text location = Mech.GetAbbreviatedChassisLocation((ChassisLocations)AttackWeapon.Location); return new AttackModifier($"{location} DAMAGED", MechStructureRules.GetToHitModifierLocationDamage(mech, AttackWeapon)); } else { return new AttackModifier("CHASSIS DAMAGED", Hit.GetSelfDamageModifier(Attacker, AttackWeapon)); } }); case "obstruction": return(() => new AttackModifier("OBSTRUCTED", Hit.GetCoverModifier(Attacker, Target, LineOfFire))); case "precision": return(() => new AttackModifier(CombatConstants.CombatUIConstants.MoraleAttackDescription.Name, Hit.GetMoraleAttackModifier(Target, IsMoraleAttack))); case "refire": return(() => new AttackModifier("RECOIL", Hit.GetRefireModifier(AttackWeapon))); case "targetevasion": return(() => new AttackModifier("TARGET MOVED", Hit.GetTargetSpeedModifier(Target, AttackWeapon))); case "targetprone": return(() => new AttackModifier("TARGET PRONE", Hit.GetTargetProneModifier(Target, false))); case "targetshutdown": return(() => new AttackModifier("TARGET SHUTDOWN", Hit.GetTargetShutdownModifier(Target, false))); case "sensorlock": return(() => new AttackModifier("SENSOR LOCK", Hit.GetTargetDirectFireModifier(Target, LineOfFire < LineOfFireLevel.LOFObstructed && AttackWeapon.IndirectFireCapable))); case "weapondamage": return(() => { AttackModifier result = new AttackModifier("WEAPON DAMAGED"); if (!(Attacker is Mech mech)) { return result; } return result.SetValue(MechStructureRules.GetToHitModifierWeaponDamage(mech, AttackWeapon)); }); } return(null); }