Example #1
0
        public static float GetBaseChance(AIMCritInfo info)
        {
            float chance = 0;

            if (info.IsArmourBreached)
            {
                chance = GetBaseChance(info.currentStructure, info.maxStructure);
                if (DebugLog)
                {
                    Verbo("Normal base crit chance = {0} + {1} x {2}/{3} = {4}", CritChanceBase, CritChanceVar, info.currentStructure, info.maxStructure, chance);
                }
                AttackLog.LogAIMBaseCritChance(chance, info.maxStructure);
                return(Mathf.Max(CritChanceMin, Mathf.Min(chance, CritChanceMax)));
            }
            else if (ThroughArmorCritEnabled)
            {
                chance = GetTACBaseChance(info.currentArmour, info.maxArmour);
                if (DebugLog)
                {
                    Verbo("TAC base crit chance = {0} + {1} x {2}/{3} = {4}", TACritChanceBase, TACritChanceVar, info.currentArmour, info.maxArmour, chance);
                }
                AttackLog.LogAIMBaseCritChance(chance, info.maxArmour);
            }
            return(chance);
        }
Example #2
0
 private static void PostCheckForCrit(AIMCritInfo info, bool logCrit)
 {
     if (logCrit)
     {
         AttackLog.LogCritResult(info.target, info.weapon);
     }
 }
        public override void CombatStartsOnce()
        {
            scale                       = Settings.FixHitDistribution ? SCALE : 1;
            CallShotClustered           = Settings.CalledShotUseClustering;
            MechCalledShotMultiplier    = (float)Settings.MechCalledShotMultiplier;
            VehicleCalledShotMultiplier = (float)Settings.VehicleCalledShotMultiplier;

            if (Settings.FixCalledShotMultiplierSquare)
            {
                Patch(typeof(AbstractActor), "get_CalledShotBonusMultiplier", null, "FixCalledShotMultiplierSquare");
            }

            bool prefixMech          = MechCalledShotMultiplier != 1 || Settings.CalledShotUseClustering,
                 prefixVehicle       = VehicleCalledShotMultiplier != 1;
            MethodInfo MechGetHit    = AttackLog.GetHitLocation(typeof(ArmorLocation)),
                       VehicleGetHit = AttackLog.GetHitLocation(typeof(VehicleChassisLocations));

            if (prefixMech)
            {
                Patch(typeof(BattleTech.HitLocation), "GetMechHitTable", null, "RecordHitDirection");
                Patch(MechGetHit, "PrefixMechCalledShot", null);
            }
            if (prefixVehicle)
            {
                Patch(VehicleGetHit, "PrefixVehicleCalledShot", null);
            }
            if (Settings.FixHitDistribution)
            {
                ScaledMechHitTables    = new Dictionary <Dictionary <ArmorLocation, int>, Dictionary <ArmorLocation, int> >();
                ScaledVehicleHitTables = new Dictionary <Dictionary <VehicleChassisLocations, int>, Dictionary <VehicleChassisLocations, int> >();
                Patch(MechGetHit, "ScaleMechHitTable", "RestoreHeadToScaledHitTable");
                Patch(VehicleGetHit, "ScaleVehicleHitTable", null);
            }
        }
Example #4
0
        public static bool CheckForCrit(AIMCritInfo info, int hitLocation, bool logCrit)
        {
            try {
                if (info?.weapon == null)
                {
                    return(true);
                }
                info.SetHitLocation(hitLocation);
                AbstractActor target = info.target;
                if (SkipCritingDeadMech && IsBeatingDeadMech(target))
                {
                    return(false);
                }
                float chance = info.GetCritChance();
                for (int i = 1; chance > 0; i++)
                {
                    float critRoll = Combat.NetworkRandom.Float(); // If use original code AttackDirector.GetRandomFromCache( info.hitInfo, 2 ), may run out of rolls
                    if (DebugLog)
                    {
                        Verbo("Crit {3} roll {0} <= chance {1}? {2}", critRoll, chance, critRoll <= chance, i);
                    }
                    if (i == 1)
                    {
                        AttackLog.LogAIMCritRoll(critRoll);
                    }
                    if (critRoll > chance)
                    {
                        break;
                    }
                    float slotRoll = Combat.NetworkRandom.Float();
                    if (AttackLog.thisCritComp == null)
                    {
                        AttackLog.LogAIMSlotRoll(slotRoll);
                    }
                    MechComponent component = FindAndCritComponent(info, slotRoll);
                    if (i > 1)
                    {
                        Verbo("Crit x{0} on location {1} of {2} by {3}. Roll {4} <= Chance {5}. Crit'ed {6}",
                              i, component?.Location ?? hitLocation, info.target, info.weapon, critRoll, chance, component?.UIName.ToString() ?? "(None)");
                    }
                    if (logCrit)
                    {
                        AttackLog.LogCritResult(target, info.weapon);
                        logCrit = false;
                    }
                    if (!Settings.MultipleCrits)
                    {
                        break;
                    }
                    chance -= critRoll;
                }
                PostCheckForCrit(info, logCrit);
            }                 catch (Exception ex) { Error(ex); }

            return(false);
        }
Example #5
0
 private static void PostCheckForCrit(AIMCritInfo info, bool logCrit)
 {
     if (logCrit)
     {
         AttackLog.LogCritResult(info.target, info.weapon);
     }
     if (MechEngineerCheckCritPostfix != null)
     {
         Mech mech = new Mech();
         MechSetCombat.Invoke(mech, new object[] { Combat });
         MechEngineerCheckCritPostfix.Invoke(null, new object[] { mech });
     }
 }
Example #6
0
        public static float GetMultiplier(AIMCritInfo info)
        {
            float critMultiplier = Combat.CritChance.GetCritMultiplier(info.target, info.weapon, true);

            if (DebugLog)
            {
                Verbo("Base crit multiplier x{0}, vehicle x{1}, Turret x{2}", critMultiplier, Settings.CriChanceVsVehicle, Settings.CritChanceVsTurret);
            }
            if (info.target is Vehicle && Settings.CriChanceVsVehicle != 1)
            {
                critMultiplier *= (float)Settings.CriChanceVsVehicle;
            }
            else if (info.target is Turret && Settings.CritChanceVsTurret != 1)
            {
                critMultiplier *= (float)Settings.CritChanceVsTurret;
            }
            AttackLog.LogCritMultiplier(critMultiplier);
            return(critMultiplier);
        }
Example #7
0
        public static MechComponent GetComponentFromRoll(AbstractActor me, int location, float random)
        {
            List <MechComponent> list = ListComponentsAtLocation(me, location);

            if (me is Mech mech)
            {
                if ((list.IsNullOrEmpty() || list.All(e => e.DamageLevel >= ComponentDamageLevel.Destroyed)) && Settings.CritLocationTransfer)
                {
                    ArmorLocation newLocation = MechStructureRules.GetPassthroughLocation(MechStructureRules.GetArmorFromChassisLocation((ChassisLocations)location) & FrontArmours, AttackDirection.FromFront);
                    if (newLocation != ArmorLocation.None)
                    {
                        Verbo("Crit list empty at {0} of {1}, transferring crit to {2}", (ChassisLocations)location, me, newLocation);
                        ChassisLocations chassis = MechStructureRules.GetChassisLocationFromArmorLocation(newLocation);
                        return(GetComponentFromRoll(me, (int)chassis, random));
                    }
                }
                else if (!Settings.CritIgnoreEmptySlots)
                {
                    int MinSlots = mech.MechDef.GetChassisLocationDef((ChassisLocations)location).InventorySlots;
                    if (DebugLog && MinSlots > list.Count)
                    {
                        Verbo("Padding list to {0} with empty slots", MinSlots);
                    }
                    for (int i = list.Count; i < MinSlots; i++)
                    {
                        list.Add(null);
                    }
                }
            }
            int           slot   = (int)(list.Count * random);
            MechComponent result = slot < list.Count ? list[slot] : null;

            if (DebugLog)
            {
                Verbo("Slot roll {0}, slot count {1}, slot {2}, component {3} status {4}", random, list.Count, slot, result, result?.DamageLevel);
            }
            AttackLog.LogCritComp(result, slot);
            return(result);
        }