Exemplo n.º 1
0
        //public static List<AttackEvaluation> EvaluateAttacks(AbstractActor attacker, ICombatant target,
        //    List<List<CondensedWeapon>>[] weaponSetListByAttack, Vector3 attackPosition, Vector3 targetPosition,
        //    bool targetIsEvasive) {

        //    ConcurrentBag<AttackEvaluation> allResults = new ConcurrentBag<AttackEvaluation>();

        //    // List 0 is ranged weapons, 1 is melee+support, 2 is DFA+support
        //    for (int i = 0; i < 3; i++) {

        //        List<List<CondensedWeapon>> weaponSetsByAttackType = weaponSetListByAttack[i];
        //        string attackLabel = "ranged attack";
        //        if (i == 1) { attackLabel = "melee attacks"; }
        //        if (i == 2) { attackLabel = "DFA attacks"; }
        //        Mod.Log.Debug?.Write($"Evaluating {weaponSetsByAttackType.Count} {attackLabel}");

        //        if (weaponSetsByAttackType != null) {

        //            //ConcurrentQueue<List<CondensedWeapon>> workQueue = new ConcurrentQueue<List<CondensedWeapon>>();
        //            //for (int j = 0; j < weaponSetsByAttackType.Count; j++) {
        //            //    workQueue.Enqueue(weaponSetsByAttackType[j]);
        //            //}

        //            //void evaluateWeaponSet() {
        //            //    Mod.Log.Debug?.Write($" New action started.");
        //            //    SpinWait spin = new SpinWait();
        //            //    while (true) {

        //            //        if (workQueue.TryDequeue(out List<Weapon> weaponSet)) {
        //            //            AttackEvaluator.AttackEvaluation attackEvaluation = new AttackEvaluator.AttackEvaluation();
        //            //            attackEvaluation.WeaponList = weaponSet;
        //            //            attackEvaluation.AttackType = (AIUtil.AttackType)i;
        //            //            attackEvaluation.HeatGenerated = (float)AIUtil.HeatForAttack(weaponSet);

        //            //            if (unit is Mech mech) {
        //            //                attackEvaluation.HeatGenerated += (float)mech.TempHeat;
        //            //                attackEvaluation.HeatGenerated -= (float)mech.AdjustedHeatsinkCapacity;
        //            //            }

        //            //            attackEvaluation.ExpectedDamage = AIUtil.ExpectedDamageForAttack(unit, attackEvaluation.AttackType, weaponSet, target, attackPosition, targetPosition, true, unit);
        //            //            attackEvaluation.lowestHitChance = AIUtil.LowestHitChance(weaponSet, target, attackPosition, targetPosition, targetIsEvasive);
        //            //            allResults.Add(attackEvaluation);
        //            //            Mod.Log.Debug?.Write($"Processed a weaponSet, {workQueue.Count} remaining");
        //            //        } else {
        //            //            Mod.Log.Debug?.Write($"Failed to dequeue, {workQueue.Count} remaining");
        //            //            if (workQueue.Count == 0) { break; } else { spin.SpinOnce(); }
        //            //        }
        //            //    }
        //            //    Mod.Log.Debug?.Write($" New action ending.");
        //            //};
        //            //Parallel.Invoke(evaluateWeaponSet, evaluateWeaponSet, evaluateWeaponSet);

        //            for (int j = 0; j < weaponSetsByAttackType.Count; j++) {
        //                List<CondensedWeapon> weaponList = weaponSetsByAttackType[j];
        //                Mod.Log.Debug?.Write($"Evaluating {weaponList?.Count} weapons for a {attackLabel}");
        //                AttackEvaluator.AttackEvaluation attackEvaluation = new AttackEvaluator.AttackEvaluation();
        //                attackEvaluation.AttackType = (AIUtil.AttackType)i;
        //                attackEvaluation.HeatGenerated = (float)AIHelper.HeatForAttack(weaponList);

        //                if (attacker is Mech mech) {
        //                    attackEvaluation.HeatGenerated += (float)mech.TempHeat;
        //                    attackEvaluation.HeatGenerated -= (float)mech.AdjustedHeatsinkCapacity;
        //                }

        //                attackEvaluation.ExpectedDamage = AIHelper.ExpectedDamageForAttack(attacker, attackEvaluation.AttackType,
        //                    weaponList, target, attackPosition, targetPosition, true, attacker);
        //                attackEvaluation.lowestHitChance = AIHelper.LowestHitChance(weaponList, target, attackPosition, targetPosition, targetIsEvasive);

        //                // Expand the list to all weaponDefs, not our condensed ones
        //                Mod.Log.Debug?.Write($"Expanding weapon list for AttackEvaluation");
        //                List<Weapon> aeWeaponList = new List<Weapon>();
        //                foreach (CondensedWeapon cWeapon in weaponList) {
        //                    List<Weapon> cWeapons = cWeapon.condensedWeapons;
        //                    if (cWeapon.ammoAndMode != null) {
        //                        foreach (Weapon wep in cWeapons) {
        //                            Mod.Log.Debug?.Write($" -- Setting ammoMode to: {cWeapon.ammoAndMode.ammoId}_{cWeapon.ammoAndMode.modeId} for weapon: {wep.UIName}");
        //                            CleverGirlHelper.ApplyAmmoMode(wep, cWeapon.ammoAndMode);
        //                        }
        //                    }

        //                    aeWeaponList.AddRange(cWeapon.condensedWeapons);
        //                }
        //                Mod.Log.Debug?.Write($"List size {weaponList?.Count} was expanded to: {aeWeaponList?.Count}");
        //                attackEvaluation.WeaponList = aeWeaponList;
        //                allResults.Add(attackEvaluation);
        //            }
        //        }
        //    }

        //    List<AttackEvaluator.AttackEvaluation> sortedResults = new List<AttackEvaluator.AttackEvaluation>();
        //    sortedResults.AddRange(allResults);
        //    sortedResults.Sort((AttackEvaluator.AttackEvaluation a, AttackEvaluator.AttackEvaluation b) => a.ExpectedDamage.CompareTo(b.ExpectedDamage));
        //    sortedResults.Reverse();

        //    return sortedResults;
        //}


        public static bool MeleeDamageOutweighsRisk(Mech attacker, ICombatant target)
        {
            float attackerMeleeDam = AIUtil.ExpectedDamageForMeleeAttackUsingUnitsBVs(attacker, target, attacker.CurrentPosition, target.CurrentPosition, false, attacker);

            if (attackerMeleeDam <= 0f)
            {
                Mod.Log.Debug?.Write("Attacker has no expected damage, melee is too risky.");
                return(false);
            }

            Mech targetMech = target as Mech;

            if (targetMech == null)
            {
                Mod.Log.Debug?.Write("Target has no expected damage, melee is safe.");
                return(true);
            }

            // Use the target mech's position, because if we melee the attacker they can probably get to us
            float targetMeleeDam      = AIUtil.ExpectedDamageForMeleeAttackUsingUnitsBVs(targetMech, attacker, targetMech.CurrentPosition, targetMech.CurrentPosition, false, attacker);
            float meleeDamageRatio    = attackerMeleeDam / targetMeleeDam;
            float meleeDamageRatioCap = AIHelper.GetBehaviorVariableValue(attacker.BehaviorTree, BehaviorVariableName.Float_MeleeDamageRatioCap).FloatVal;

            Mod.Log.Debug?.Write($" meleeDamageRatio: {meleeDamageRatio} = target: {targetMeleeDam} / attacker: {attackerMeleeDam} vs. cap: {meleeDamageRatioCap}");

            return(meleeDamageRatio > meleeDamageRatioCap);
        }