public static void Postfix(ref CalledShotAttackOrderInfo __result, AbstractActor attackingUnit, int enemyUnitIndex)
        {
            Mod.Log.Trace?.Write("AE:CCSLTC entered");

            ICombatant combatant = attackingUnit.BehaviorTree.enemyUnits[enemyUnitIndex];

            if (combatant is AbstractActor targetActor)
            {
                // Prevents blips from being the targets of called shots
                VisibilityLevel targetVisibility = attackingUnit.VisibilityToTargetUnit(targetActor);
                if (targetVisibility < VisibilityLevel.LOSFull)
                {
                    Mod.Log.Info?.Write($"Target {CombatantUtils.Label(combatant)} is a blip, cannot be targeted by AI called shot");
                    __result = null;
                    return;
                }

                float          distance      = Vector3.Distance(attackingUnit.CurrentPosition, targetActor.CurrentPosition);
                bool           hasVisualScan = VisualLockHelper.GetVisualScanRange(attackingUnit) >= distance;
                SensorScanType sensorScan    = SensorLockHelper.CalculateSharedLock(targetActor, attackingUnit);
                if (sensorScan < SensorScanType.ArmorAndWeaponType && !hasVisualScan)
                {
                    Mod.Log.Info?.Write($"Target {CombatantUtils.Label(targetActor)} sensor info {sensorScan} is less than SurfaceScan and outside visualID, cannot be targeted by AI called shot");
                    __result = null;
                    return;
                }
            }
        }
Esempio n. 2
0
        // CLONE OF HBS CODE - LIKELY BRITTLE!
        public static CalledShotAttackOrderInfo MakeCalledShotOrder(AbstractActor attackingUnit, AttackEvaluator.AttackEvaluation evaluatedAttack, ICombatant target, bool isMoraleAttack)
        {
            Mech mech = target as Mech;

            if (mech == null || !mech.IsVulnerableToCalledShots() || evaluatedAttack.AttackType == AIUtil.AttackType.Melee || evaluatedAttack.AttackType == AIUtil.AttackType.DeathFromAbove)
            {
                return(null);
            }

            Mech mech2 = attackingUnit as Mech;

            for (int i = 0; i < evaluatedAttack.WeaponList.Count; i++)
            {
                Weapon weapon = evaluatedAttack.WeaponList[i];
                if (weapon.WeaponCategoryValue.IsMelee || weapon.Type == WeaponType.Melee || (mech2 != null && (weapon == mech2.DFAWeapon || weapon == mech2.MeleeWeapon)))
                {
                    return(null);
                }
            }

            List <ArmorLocation> list = new List <ArmorLocation> {
                ArmorLocation.Head,
                ArmorLocation.CenterTorso,
                ArmorLocation.LeftTorso,
                ArmorLocation.LeftArm,
                ArmorLocation.LeftLeg,
                ArmorLocation.RightTorso,
                ArmorLocation.RightArm,
                ArmorLocation.RightLeg
            };

            List <ChassisLocations> list2 = new List <ChassisLocations> {
                ChassisLocations.Head,
                ChassisLocations.CenterTorso,
                ChassisLocations.LeftTorso,
                ChassisLocations.LeftArm,
                ChassisLocations.LeftLeg,
                ChassisLocations.RightTorso,
                ChassisLocations.RightArm,
                ChassisLocations.RightLeg
            };

            List <float> list3 = new List <float>(list.Count);
            float        num   = 0f;

            for (int j = 0; j < list.Count; j++)
            {
                float num2 = CalcCalledShotLocationTargetChance(mech, list[j], list2[j]);
                list3.Add(num2);
                num += num2;
            }

            float num3 = UnityEngine.Random.Range(0f, num);
            CalledShotAttackOrderInfo calledShotAttackOrderInfo = null;

            for (int k = 0; k < list.Count; k++)
            {
                float num4 = list3[k];
                if (num3 < num4)
                {
                    calledShotAttackOrderInfo = new CalledShotAttackOrderInfo(mech, list[k], isMoraleAttack);
                    break;
                }
                num3 -= num4;
            }

            if (calledShotAttackOrderInfo == null)
            {
                Debug.LogError("Failed to calculate called shot. Targeting head as fallback.");
                calledShotAttackOrderInfo = new CalledShotAttackOrderInfo(mech, ArmorLocation.Head, isMoraleAttack);
            }

            for (int l = 0; l < evaluatedAttack.WeaponList.Count; l++)
            {
                Weapon weapon2 = evaluatedAttack.WeaponList[l];
                AIUtil.LogAI("Called Shot: Adding weapon " + weapon2.Name, "AI.DecisionMaking");
                calledShotAttackOrderInfo.AddWeapon(weapon2);
            }

            return(calledShotAttackOrderInfo);
        }