Наследование: Vexe.Runtime.Types.BetterBehaviour
Пример #1
0
	void buildMech(Mech m) {
		string[] parts = new string[9]{ m.Core, m.Arms, m.Legs, m.Head, m.Booster, m.Weapon1L, m.Weapon1R, m.Weapon2L, m.Weapon2R };
	
		// Create new array to store skinned mesh renderers 
		SkinnedMeshRenderer[] newSMR = new SkinnedMeshRenderer[5];

		Material[] materials = new Material[5];
		for (int i = 0; i < 5; i++) {
			// Load mech part
			GameObject part = Resources.Load (parts [i], typeof(GameObject)) as GameObject;

			// Extract Skinned Mesh
			newSMR [i] = part.GetComponentInChildren<SkinnedMeshRenderer> () as SkinnedMeshRenderer;

			// Load texture
			materials [i] = Resources.Load (parts [i] + "mat", typeof(Material)) as Material;
		}

		// Replace all
		SkinnedMeshRenderer[] curSMR = GetComponentsInChildren<SkinnedMeshRenderer> ();
		for (int i = 0; i < curSMR.Length; i++){
			curSMR[i].sharedMesh = newSMR[i].sharedMesh;
			curSMR[i].material = materials[i];
			curSMR[i].enabled = true;
		}

		// Make weapons
		buildWeapons (new string[4]{parts[5],parts[6],parts[7],parts[8]});
	}
Пример #2
0
 public BaseMech(Mech mech)
 {
     MechName = mech.Name;
     MechAttack = mech.Attack;
     MechDefense = mech.Defense;
     MechWeight = mech.Weight;
     WeightClass = AssignMechWeightClass(mech.Weight);
     Faction = mech.Faction;
 }
Пример #3
0
    public void enact(Mech mech)
    {
        switch (type) {
            case ActionTypes.Idle: {
            } break;

            case ActionTypes.Attack: {
            } break;

            case ActionTypes.Hide: {
            } break;

            case ActionTypes.Evade: {
            } break;

            case ActionTypes.Flee: {
            } break;

            case ActionTypes.Shield: {
                // do actions
            } break;

            case ActionTypes.EMP: {
                // do actions
            } break;

            case ActionTypes.Charge: {
                // do actions
            } break;

            case ActionTypes.Dodge: {
            } break;

            case ActionTypes.Collect: {
                // do actions
            } break;

            case ActionTypes.Defend: {
                // do actions
            } break;

            case ActionTypes.Destroy: {
                // do actions
            } break;

            case ActionTypes.Move: {
                // do actions
            } break;

            default: {
                // do nothing
            } break;
        }
    }
Пример #4
0
 public void addMechtoMechTable(string name, int attack, int defense, int weight, string faction, string range, string speed, string pilot, int mechgroupid)
 {
     Mech newMech = new Mech();
     newMech.Name = name;
     newMech.Faction = faction;
     newMech.Attack = attack;
     newMech.Defense = defense;
     newMech.Weight = weight;
     newMech.Range = range;
     newMech.Speed = speed;
     newMech.Pilot = pilot;
     newMech.MechGroupId = mechgroupid;
     entities.Mechs.Add(newMech);
     entities.SaveChanges();
 }
Пример #5
0
 /// <summary>
 /// Even though a projectile is instantiated, it won't begin doining anything
 /// until the owning mech launches it. This establishes ownership, etc.
 /// </summary>
 /// <param name="ownerMech"></param>
 /// <param name="weaponIdx"></param>
 public void Launch(Mech ownerMech, int weaponIdx, Vector3 position, Quaternion rotation)
 {
     #if DEBUG_PROJECTILE
      Debug.Log(string.Format("Projectile from Weapon: {0} has launched!", WeaponIndex));
       #endif
       Owner = ownerMech;
       WeaponIndex = weaponIdx;
       OwnerWeapon = Owner.GetWeapon(WeaponIndex);
       transform.position = position;
       transform.rotation = rotation;
       IsHit = false;
       PayloadDelivered = false;
       DistTraveled = 0.0f;
       DespawnTimer = 0.0f;
       Launched = true;
 }
        private static float CalculateCheckMod(Mech mech, float multi, bool gutsSkill)
        {
            int rawSkill   = gutsSkill ? mech.SkillGuts : mech.SkillPiloting;
            int actorSkill = SkillUtils.NormalizeSkill(rawSkill);

            Mod.Log.Debug?.Write($"Actor: {CombatantUtils.Label(mech)} has rawSkill: {actorSkill} normalized to {actorSkill}");

            int malus = 0;

            if (!gutsSkill)
            {
                // Piloting checks must use damage malus
                malus += mech.ActuatorDamageMalus();
            }

            float adjustedSkill = actorSkill - malus > 0f ? actorSkill - malus : 0f;

            Mod.Log.Info?.Write($"  AdjustedSkill: {adjustedSkill} = actorSkill: {actorSkill} - malus: {malus}.");

            float checkMod = adjustedSkill * multi;

            Mod.Log.Info?.Write($"  CheckMod: {checkMod} = adjustedSkill: {adjustedSkill} * multi: {multi}");
            return(checkMod);
        }
Пример #7
0
        public void TestPunchDamage_TargetDamageStat_UndamagedAttacker()
        {
            // Test override stat
            Mech attacker50 = TestHelper.BuildTestMech(tonnage: 50);
            ActorMeleeCondition attackerCondition50 = TestHelper.AllEnabledCondition(attacker50);

            ModState.meleeConditionCache[attacker50.DistinctId()] = attackerCondition50;

            attacker50.StatCollection.AddStatistic <float>(ModStats.PunchTargetDamage, 2f);
            Assert.AreEqual(100, attacker50.PunchDamage());

            // Test override stat @ 0; should default to ModValue
            Mod.Config.Melee.Punch.TargetDamagePerAttackerTon = 3.0f;
            attacker50.StatCollection.Set <float>(ModStats.PunchTargetDamage, 0);
            Assert.AreEqual(150, attacker50.PunchDamage());

            // Test override stat @ negatives; should default to modValue
            Mod.Config.Melee.Punch.TargetDamagePerAttackerTon = 4.0f;
            attacker50.StatCollection.Set <float>(ModStats.PunchTargetDamage, -20);
            Assert.AreEqual(200, attacker50.PunchDamage());

            // Reset for other tests
            Mod.Config.Melee.Punch.TargetDamagePerAttackerTon = 0.5f;
        }
Пример #8
0
        public static void Prefix(Mech __instance)
        {
            try
            {
                if (!Control.settings.HeatDamageInjuryEnabled)
                {
                    return;
                }

                var mech = __instance;
                if (!mech.IsOverheated)
                {
                    return;
                }
                if (mech.StatCollection.ReceiveHeatDamageInjury())
                {
                    mech.pilot?.SetNeedsInjury(InjuryReason.NotSet);
                }
            }
            catch (Exception e)
            {
                Control.mod.Logger.LogError(e);
            }
        }
Пример #9
0
        static Weapon FindWeaponToHitTarget(AbstractActor attacker, List <Weapon> weaponList, ICombatant target)
        {
            Mech targetMech      = target as Mech;
            bool targetIsEvasive = ((targetMech != null) && (targetMech.IsEvasive));

            for (int wi = 0; wi < weaponList.Count; ++wi)
            {
                Weapon w = weaponList[wi];

                if (!attacker.Combat.LOFCache.UnitHasLOFToTargetAtTargetPosition(
                        attacker, target, w.MaxRange, attacker.CurrentPosition, attacker.CurrentRotation,
                        target.CurrentPosition, target.CurrentRotation, w.IndirectFireCapable))
                {
                    continue;
                }

                float dmg = GetExpectedDamageForMultiTargetWeapon(attacker, attacker.CurrentPosition, target, target.CurrentPosition, targetIsEvasive, w, attacker.MaxTargets);
                if (dmg > 0)
                {
                    return(w);
                }
            }
            return(null);
        }
Пример #10
0
        public void TestMimetic_AttackMod_NoDecay_Pinged_ProbeCarrier()
        {
            Mech attacker = TestHelper.BuildTestMech();
            Mech target   = TestHelper.BuildTestMech();

            target.CurrentPosition = new Vector3(0f, 0, 0);
            Traverse previousPositionT = Traverse.Create(target).Field("previousPosition");

            previousPositionT.SetValue(new Vector3(0f, 0f, 0f));

            attacker.StatCollection.AddStatistic <float>("SpotterDistanceMultiplier", 1f);
            attacker.StatCollection.AddStatistic <float>("SpotterDistanceAbsolute", 0f);
            attacker.StatCollection.Set(ModStats.ProbeCarrier, 3);

            target.StatCollection.AddStatistic <float>("SpottingVisibilityMultiplier", 1f);
            target.StatCollection.AddStatistic <float>("SpottingVisibilityAbsolute", 0f);
            target.StatCollection.Set(ModStats.MimeticEffect, "4_0.10_1_2");
            target.StatCollection.Set(ModStats.PingedByProbe, 2);

            EWState attackerState = new EWState(attacker);
            EWState targetState   = new EWState(target);

            Assert.AreEqual(0, targetState.MimeticAttackMod(attackerState));
        }
        public static void Postfix(Mech __instance, ChassisLocations location, float damage, WeaponHitInfo hitInfo)
        {
            Mod.Log.Trace?.Write("M:ASSD - entered.");

            if (ModState.BreachCheck == 0f || ModState.BreachAttackId == ModState.NO_ATTACK_SEQUENCE_ID)
            {
                return;
            }                                                                                                        // nothing to do
            if (hitInfo.attackSequenceId != ModState.BreachAttackId)
            {
                Mod.Log.Warn?.Write($"AttackSequenceId: {hitInfo.attackSequenceId} does not match hull breach attack sequence id: {ModState.BreachAttackId}... wasn't expecting this, skipping!");
                return;
            }

            Mod.Log.Debug?.Write($" --- Location: {location} needs breach check.");
            if (ModState.BreachHitsMech.ContainsKey(location))
            {
                ModState.BreachHitsMech[location]++;
            }
            else
            {
                ModState.BreachHitsMech.Add(location, 1);
            }
        }
        public static void Prefix(Mech __instance)
        {
            try
            {
                if (!ShutdownInjuryProtectionFeature.settings.HeatDamageInjuryEnabled)
                {
                    return;
                }

                var mech = __instance;
                if (!mech.IsOverheated)
                {
                    return;
                }
                if (mech.StatCollection.ReceiveHeatDamageInjury().Get())
                {
                    mech.pilot?.SetNeedsInjury(Pilot_InjuryReasonDescription_Patch.InjuryReasonOverheated);
                }
            }
            catch (Exception e)
            {
                Control.Logger.Error.Log(e);
            }
        }
Пример #13
0
            private static void Postfix(Mech __instance)
            {
                var mech = __instance;

                if (!modSettings.LosingLimbAlwaysPanics ||
                    mech == null || mech.IsDead || mech.IsFlaggedForDeath && mech.HasHandledDeath)
                {
                    return;
                }

                var index = GetPilotIndex(mech);

                if (trackedPilots[index].mech != mech.GUID)
                {
                    return;
                }

                if (trackedPilots[index].panicWorsenedRecently && modSettings.OneChangePerTurn)
                {
                    return;
                }

                ApplyPanicDebuff(mech);
            }
        private void CalculateModifiers(Mech attacker, AbstractActor target)
        {
            // If target is prone, -2 modifier
            if (target.IsProne)
            {
                this.AttackModifiers.Add(ModText.LT_Label_Target_Prone, Mod.Config.Melee.ProneTargetAttackModifier);
            }

            // +2 to hit for each upper/lower actuator hit
            ActorMeleeCondition attackerCondition = ModState.GetMeleeCondition(attacker);
            int leftArmMalus  = (2 - attackerCondition.LeftArmActuatorsCount) * Mod.Config.Melee.Punch.ArmActuatorDamageMalus;
            int rightArmMalus = (2 - attackerCondition.RightArmActuatorsCount) * Mod.Config.Melee.Punch.ArmActuatorDamageMalus;
            int bestMalus     = leftArmMalus <= rightArmMalus ? leftArmMalus : rightArmMalus;

            // If the ignore actuators stat is set, set the malus to 0 regardless of damage
            Statistic ignoreActuatorsStat = attacker.StatCollection.GetStatistic(ModStats.PhysicalWeaponIgnoreActuators);

            if (ignoreActuatorsStat != null && ignoreActuatorsStat.Value <bool>())
            {
                bestMalus = 0;
            }

            // Add actuator damage if it exists
            if (bestMalus != 0)
            {
                this.AttackModifiers.Add(ModText.LT_Label_Actuator_Damage, bestMalus);
            }

            // Check for attack modifier statistic
            Statistic phyWeapAttackMod = attacker.StatCollection.GetStatistic(ModStats.PhysicalWeaponAttackMod);

            if (phyWeapAttackMod != null && phyWeapAttackMod.Value <int>() != 0)
            {
                this.AttackModifiers.Add(ModText.LT_Label_Physical_Weapon_Attack_Mod, attacker.StatCollection.GetValue <int>(ModStats.PhysicalWeaponAttackMod));
            }
        }
Пример #15
0
    void buildMech(Mech m)
    {
        string[] parts = new string[9] {
            m.Core, m.Arms, m.Legs, m.Head, m.Booster, m.Weapon1L, m.Weapon1R, m.Weapon2L, m.Weapon2R
        };

        // Create new array to store skinned mesh renderers
        SkinnedMeshRenderer[] newSMR = new SkinnedMeshRenderer[5];

        Material[] materials = new Material[5];
        for (int i = 0; i < 5; i++)
        {
            // Load mech part
            GameObject part = Resources.Load(parts [i], typeof(GameObject)) as GameObject;

            // Extract Skinned Mesh
            newSMR [i] = part.GetComponentInChildren <SkinnedMeshRenderer> () as SkinnedMeshRenderer;

            // Load texture
            materials [i] = Resources.Load(parts [i] + "mat", typeof(Material)) as Material;
        }

        // Replace all
        SkinnedMeshRenderer[] curSMR = GetComponentsInChildren <SkinnedMeshRenderer> ();
        for (int i = 0; i < curSMR.Length; i++)
        {
            curSMR[i].sharedMesh = newSMR[i].sharedMesh;
            curSMR[i].material   = materials[i];
            curSMR[i].enabled    = true;
        }

        // Make weapons
        buildWeapons(new string[4] {
            parts[5], parts[6], parts[7], parts[8]
        });
    }
Пример #16
0
        private static void Postfix(Mech __instance)
        {
            var mech = __instance;

            if (!modSettings.LosingLimbAlwaysPanics ||
                mech == null || mech.IsDead || mech.IsFlaggedForDeath && mech.HasHandledDeath)
            {
                return;
            }

            var index = GetActorIndex(mech);

            if (TrackedActors[index].Guid != mech.GUID)
            {
                return;
            }

            if (TrackedActors[index].PanicWorsenedRecently && modSettings.OneChangePerTurn)
            {
                return;
            }

            TrackedActors[index].PanicStatus++;
        }
Пример #17
0
        internal static float PercentForStructureLocation(Mech mech, int Location)
        {
            // Invalid locations are always 100%
            // This helps makes the functions generic for the missing leg back armor, for example
            if (Location == 0)
            {
                return(1);
            }

            if (mech != null)
            {
                Statistic stat = mech.StatCollection.GetStatistic(mech.GetStringForStructureLocation((ChassisLocations)Location));
                if (stat == null)
                {
                    LogDebug($"Can't get structure stat  { mech.DisplayName } location:{ Location}");
                    return(0);
                }

                LogDebug($"Structure stat  { mech.DisplayName } location:{ Location} cur:{stat.Value<float>()} max:{stat.DefaultValue<float>()}");
                return(stat.Value <float>() / stat.DefaultValue <float>());
            }
            LogDebug($"Mech null");
            return(0);
        }
Пример #18
0
    public float utility(Mech mech)
    {
        switch (type) {
            case ActionTypes.Idle: {
                return maxIdleValue;
            }

            case ActionTypes.Attack: {
                float best_utility = 0;
                // foreach (Mech enemy in ec.mechs) {
                // 	if ((enemy.transform.position - mech.transform.position).sqrMagnitude < mech.sensorRange * mech .sensorRange) {
                // 		var utility = compensatedScore(considerations.Select(cons => {
                // 			var con_utility = cons.utility(mech, enemy.transform);
                // 			// Debug.Log(enemy.name + " | " + cons.type + ": " + con_utility);
                // 			return con_utility;
                // 		}));
                // 		mech.target  = (utility > best_utility) ? enemy.transform : mech.target;
                // 		best_utility = (utility > best_utility) ? utility : best_utility;
                // 	}
                // }
                // Debug.Log(mech.name + " | " + type + ": " + best_utility);
                return best_utility;
            }

            case ActionTypes.Hide: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.Flee: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.Shield: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.EMP: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.Charge: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.Dodge: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.Collect: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.Defend: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.Destroy: {
                var best_utility = 0;
                return best_utility;
            }

            case ActionTypes.Move: {
                var best_utility = 0;
                return best_utility;
            }

            default: {
                var best_utility = 0;
                return best_utility;
            }
        }
    }
Пример #19
0
 public static void Postfix(Mech __instance)
 {
     Mod.Log.Trace("M:I entered.");
     __instance.StatCollection.AddStatistic <int>(ModStats.TurnsOverheated, 0);
 }
Пример #20
0
 public static void Prefix(UnitSpawnPointGameLogic __instance, ref MechDef mDef, PilotDef pilot, Team team, Mech __result)
 {
     if (__instance.team == TeamDefinition.TargetsTeamDefinitionGuid)
     {
         if (ModState.AIGetsPlayerMechs)
         {
             var oldmDef = mDef;
             ModInit.modLog.LogMessage(
                 $"AI UNIT: First mech in playerMechs was {ModState.playerMechs.First().mechDef.Name} with count {ModState.playerMechs.First().count}");
             var playerMechVariants = ModState.playerMechs
                                      .Where(x => x.mechDef.Description.Id == oldmDef.Description.Id).OrderBy(x => x.count)
                                      .ToList();
             ModInit.modLog.LogMessage(
                 $"AI UNIT: Filtered to match mechdef IDs and reordered! First mech in playerMechVariants is now {playerMechVariants.First().mechDef.Name} with count {playerMechVariants.First().count}");
             ModState.playerMechs.First().count += 1;
             var newMechDef = playerMechVariants.FirstOrDefault()?.mechDef;
             if (newMechDef != null)
             {
                 newMechDef.DependenciesLoaded(1000U);
                 mDef = newMechDef;
             }
         }
     }
 }
        public static void ChooseBestWeaponForTarget(AbstractActor unit, ICombatant target, bool isStationary)
        {
            List <Weapon> ammoWeapons = new List <Weapon>();

            foreach (Weapon weapon in unit.Weapons)
            {
                if (CustomAmmoCategories.isWeaponHasDiffirentAmmo(weapon) == true)
                {
                    CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " has ammo to choose\n");
                    ammoWeapons.Add(weapon);
                }
            }
            if (ammoWeapons.Count == 0)
            {
                CustomAmmoCategoriesLog.Log.LogWrite(" None choosable ammo\n");
                return;
            }
            ;
            if (target is Mech)
            {
                CustomAmmoCategoriesLog.Log.LogWrite(" Target is mech\n");
                Mech          targetMech      = (target as Mech);
                List <Weapon> ammoHeatWeapons = new List <Weapon>();
                foreach (Weapon weapon in ammoWeapons)
                {
                    if (CustomAmmoCategories.isWeaponHasHeatAmmo(weapon) == true)
                    {
                        CustomAmmoCategories.switchToMostHeatAmmo(weapon);
                        CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " has hit ammo\n");
                        ammoHeatWeapons.Add(weapon);
                    }
                }
                float expectedHeat = CustomAmmoCategories.calcHeatCoeff(unit, target);
                CustomAmmoCategoriesLog.Log.LogWrite(" Expected heat " + expectedHeat + "\n");
                if ((targetMech.CurrentHeat + expectedHeat) > targetMech.OverheatLevel)
                {
                    foreach (Weapon weapon in ammoHeatWeapons)
                    {
                        CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " - ammo choosed\n");
                        ammoWeapons.Remove(weapon);
                    }
                }
                List <int>    hitLocations      = targetMech.GetPossibleHitLocations(unit);
                List <Weapon> ammoClusterWeapon = new List <Weapon>();
                foreach (Weapon weapon in ammoWeapons)
                {
                    if (CustomAmmoCategories.isWeaponHasClusterAmmo(weapon))
                    {
                        CustomAmmoCategories.switchToMostClusterAmmo(weapon);
                        CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " has cluster ammo\n");
                        ammoClusterWeapon.Add(weapon);
                    }
                }
                foreach (Weapon weapon in ammoClusterWeapon)
                {
                    float toHit = 0f;
                    if (weapon.parent.HasLOFToTargetUnit(target, weapon.MaxRange, CustomAmmoCategories.getIndirectFireCapable(weapon)))
                    {
                        toHit = weapon.GetToHitFromPosition(target, 1, unit.CurrentPosition, target.CurrentPosition, true, targetMech.IsEvasive, false);
                    }
                    if (toHit < 0.4f)
                    {
                        CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " cluster toHit is too low " + toHit + "\n");
                        continue;
                    }
                    if (CustomAmmoCategories.hasHittableLocations(weapon, hitLocations, targetMech) == true)
                    {
                        CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " can crit one of locations\n");
                        ammoWeapons.Remove(weapon);
                    }
                }
            }
            AbstractActor targetActor = (target as AbstractActor);

            foreach (Weapon weapon in ammoWeapons)
            {
                List <string> avaibleAmmo = CustomAmmoCategories.getAvaibleEffectiveAmmo(weapon);
                if (avaibleAmmo.Count == 0)
                {
                    continue;
                }
                ;
                CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " choose ammo default algorithm\n");
                string bestAmmo       = "";
                float  expectedDamage = 0;
                foreach (string ammoId in avaibleAmmo)
                {
                    CustomAmmoCategories.SetWeaponAmmo(weapon, ammoId);
                    float toHit = 0f;
                    if (unit.HasLOFToTargetUnit(target, weapon.MaxRange, CustomAmmoCategories.getIndirectFireCapable(weapon)))
                    {
                        toHit = weapon.GetToHitFromPosition(target, 1, unit.CurrentPosition, target.CurrentPosition, true, (targetActor != null) ? targetActor.IsEvasive : false, false);
                    }
                    float nonClusterCoeff = 1f;
                    int   numberOfShots   = weapon.ShotsWhenFired * weapon.ProjectilesPerShot;
                    if ((toHit > 0.6f) && (numberOfShots == 1))
                    {
                        nonClusterCoeff = 1.2f;
                    }
                    float tempExpectedDamage = numberOfShots * weapon.DamagePerShot * toHit * nonClusterCoeff;
                    CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " toHit " + toHit + " expectedDamage:" + tempExpectedDamage + "\n");
                    if (tempExpectedDamage > expectedDamage)
                    {
                        expectedDamage = tempExpectedDamage;
                        bestAmmo       = ammoId;
                    }
                }
                if (string.IsNullOrEmpty(bestAmmo) == false)
                {
                    CustomAmmoCategories.SetWeaponAmmo(weapon, bestAmmo);
                    CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " best ammo choosed\n");
                }
            }
        }
        // Resolve mech hits - mark components invalid, but kill the pilot on a head-hit
        private static void ResolveMechHullBreaches(Mech targetMech)
        {
            bool needsQuip = false;

            foreach (ChassisLocations hitLocation in ModState.BreachHitsMech.Keys)
            {
                List <MechComponent> componentsInLocation =
                    targetMech.allComponents.Where(mc => mc.mechComponentRef.DamageLevel == ComponentDamageLevel.Functional && mc.mechComponentRef.MountedLocation == hitLocation).ToList();

                // Check for immunity in this location
                bool hasImmunity = false;
                foreach (MechComponent mc in componentsInLocation)
                {
                    if (mc.StatCollection.ContainsStatistic(ModStats.HullBreachImmunity))
                    {
                        Mod.Log.Debug($"  Component: {mc.UIName} grants hull breach immunity, skipping!");
                        hasImmunity = true;
                        break;
                    }
                }
                if (hasImmunity)
                {
                    continue;
                }

                // If no immunity, sum the breach check across all trials
                float passChance         = 1f - ModState.BreachCheck;
                float sequencePassChance = Mathf.Pow(passChance, ModState.BreachHitsMech[hitLocation]);
                float sequenceThreshold  = 1f - sequencePassChance;
                Mod.Log.Debug($" For pass chance: {passChance} with n trials: {ModState.BreachHitsMech[hitLocation]} has sequencePassChance: {sequencePassChance} => sequenceThreshold: {sequenceThreshold}");

                // Check for failure
                bool passedCheck = CheckHelper.DidCheckPassThreshold(sequenceThreshold, targetMech, 0f, Mod.Config.LocalizedFloaties[ModConfig.FT_Hull_Breach]);
                Mod.Log.Debug($"Actor: {CombatantUtils.Label(targetMech)} HULL BREACH check: {passedCheck} for location: {hitLocation}");
                if (!passedCheck)
                {
                    string        floatieText      = new Text(Mod.Config.LocalizedFloaties[ModConfig.FT_Hull_Breach]).ToString();
                    MultiSequence showInfoSequence = new ShowActorInfoSequence(targetMech, floatieText, FloatieMessage.MessageNature.Debuff, false);
                    targetMech.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(showInfoSequence));

                    needsQuip = true;

                    if (hitLocation <= ChassisLocations.RightTorso)
                    {
                        switch (hitLocation)
                        {
                        case ChassisLocations.Head:
                            Mod.Log.Debug($"  Head structure damage taken, killing pilot!");
                            targetMech.GetPilot().KillPilot(targetMech.Combat.Constants, "", 0, DamageType.Enemy, null, null);
                            break;

                        case ChassisLocations.CenterTorso:
                        default:
                            if (hitLocation == ChassisLocations.CenterTorso)
                            {
                                Mod.Log.Debug($"  Center Torso hull breach!");
                            }
                            // Walk the location and disable every component in it
                            foreach (MechComponent mc in componentsInLocation)
                            {
                                Mod.Log.Debug($"  Marking component: {mc.defId} of type: {mc.componentDef.Description.Name} nonfunctional");
                                mc.DamageComponent(default(WeaponHitInfo), ComponentDamageLevel.NonFunctional, true);
                            }
                            break;
                        }
                    }
                }
            }
            if (needsQuip)
            {
                QuipHelper.PublishQuip(targetMech, Mod.Config.Qips.Breach);
            }
        }
        public static void ShowStructureDamageThroughArmour(HUDMechArmorReadout __instance)
        {
            try {
                HUDMechArmorReadout me = __instance;
                Mech    mech           = me.DisplayedMech;
                MechDef mechDef        = mech?.MechDef ?? me.DisplayedMechDef;
                if (mech == null && mechDef == null)
                {
                    return;
                }
                ChassisLocations[] location = me.flipFrontDisplay ? Flipped : Normal;
                int[]   back      = me.flipFrontDisplay != me.flipRearDisplay ? new int[] { 0, 0, 4, 3, 2 } : new int[] { 0, 0, 2, 3, 4 };
                Color   clear     = Color.clear;
                Color[] armor     = (Color[])armorProp.GetValue(me, null);
                Color[] armorRear = (Color[])armorRearProp.GetValue(me, null);
                Color[] outline   = null, outlineRear = null, structure = null, structureRear = null;

                for (int i = 0; i < 8; i++)
                {
                    float percent = float.NaN;
                    // Front
                    if (armor[i] != clear) // Skip check on armour-less locations
                    {
                        if (IsStructureDamaged(ref percent, mech, mechDef, location[i]))
                        {
                            if (structure == null) // Lazy reflection access
                            {
                                structure = (Color[])structureProp.GetValue(me, null);
                                outline   = (Color[])outlineProp.GetValue(me, null);
                            }
                            outline[i] = structure[i] = armor[i];
                            if (me.UseForCalledShots)
                            {
                                armor[i] = clear;
                            }
                            else
                            {
                                armor[i].a *= 0.5f; // Front has structure over armor, but structure has more blank to fill.
                            }
                        }
                    }
                    // Back
                    if (i < 2 || i > 4)
                    {
                        continue;
                    }
                    int j = back[i];
                    if (armorRear[j] != clear)
                    {
                        if (IsStructureDamaged(ref percent, mech, mechDef, location[i])) // i is not typo. We want to check same chassis location as front.
                        {
                            if (structureRear == null)
                            {
                                structureRear = (Color[])structureRearProp.GetValue(me, null);
                                outlineRear   = (Color[])outlineRearProp.GetValue(me, null);
                            }
                            outlineRear[j] = structureRear[j] = armorRear[j];
                            armorRear[j]   = clear;
                        }
                    }
                }
            }                 catch (Exception ex) { Error(ex); }
        }
Пример #24
0
 public MechMovingState(Mech character, MechStateMachine stateMachine) : base(character, stateMachine)
 {
 }
Пример #25
0
 public void Init()
 {
     pathFinderMech = CreatePathFinderMech();
     // pathFinderVehicle = CreatePathFindingVehicle();
 }
Пример #26
0
        public static void HUDMechArmorReadout_SetHoveredArmor_Postfix(HUDMechArmorReadout __instance, ArmorLocation location, Mech ___displayedMech)
        {
            if (__instance == null || __instance.HUD == null ||
                __instance.HUD.SelectedActor == null || __instance.HUD.SelectedTarget == null)
            {
                return; // nothing to do
            }
            if (__instance.UseForCalledShots && location == ArmorLocation.Head)
            {
                Mod.Log.Trace("HUDMAR:SHA entered");

                bool             canAlwaysCalledShot = false;
                List <Statistic> customStats         = ActorHelper.FindCustomStatistic(ModStats.CalledShowAlwaysAllow, __instance.HUD.SelectedActor);
                foreach (Statistic stat in customStats)
                {
                    if (stat.ValueType() == typeof(bool) && stat.Value <bool>())
                    {
                        canAlwaysCalledShot = true;
                    }
                }
                bool canBeTargeted = __instance.HUD.SelectedTarget.IsShutDown || __instance.HUD.SelectedTarget.IsProne || canAlwaysCalledShot;

                Mod.Log.Debug($"  Hover - target:({___displayedMech.DistinctId()}) canBeTargeted:{canBeTargeted} by attacker:({__instance.HUD.SelectedActor.DistinctId()})");
                Mod.Log.Debug($"      isShutdown:{___displayedMech.IsShutDown} isProne:{___displayedMech.IsProne} canAlwaysCalledShot:{canAlwaysCalledShot}");

                if (!canBeTargeted)
                {
                    Mod.Log.Debug("  preventing targeting of head.");
                    __instance.ClearHoveredArmor(ArmorLocation.Head);
                }
                else
                {
                    Mod.Log.Debug("  target head can be targeted.");
                }
            }
        }
Пример #27
0
    // Use this for initialization
    void Start()
    {
        // Every weapon must have a protoweapon component
          Proto = GetComponent<ProtoWeapon>();

          // Note - not every weapon has to have an animator. Up to use code to check for null
          Animator = GetComponent<Animator>();

          Owner = transform.root.gameObject.GetComponent<Mech>();
          if (Owner == null)
         Debug.LogWarning("Weapon attached to a nonmech item. No owner, so it won't attribute damage correctly.");

          // Reset the Weapon
          ResetWeapon();
    }
Пример #28
0
        private void FireFlyJets(Mech mech)
        {
            if (fuel < Type.FuelUsage || !keepFlying)
            {
                keepFlying = false;
                return;
            }

            fuel -= Type.FuelUsage;

            Vec3 vel = mech.MainGun.Rotation.GetForward();

            vel = vel.GetNormalize() * Type.Velocity;

            //mech.PhysicsModel.Bodies[0].LinearVelocity = vel;
            mech.PhysicsModel.Bodies[0].AddForce(ForceType.GlobalAtLocalPos, 0, 1000f * vel, Position);
        }
Пример #29
0
 public PilotTracker(Mech mech)
 {
     this.mech             = mech.GUID;
     panicStatus           = PanicStatus.Confident;
     panicWorsenedRecently = false;
 }
Пример #30
0
 public float invUtility(Mech m, Transform t)
 {
     return 1 - utility(m,t);
 }
Пример #31
0
 public void FullReset()
 {
     pathFinderMech = null;
     // pathFinderVehicle = null;
 }
Пример #32
0
    public float utility(Mech m, Transform t)
    {
        Mech      mech   = m;
        Transform target = t;
        float     result = 0f;

        switch (type) {
            case ConsiderationTypes.Distance: {
                var dir = (target.position - mech.transform.position);
                result = Mathf.Max(Mathf.Min(utilCurve.Evaluate(dir.magnitude / mech.sensorRange), 1), 0);
            } break;

            case ConsiderationTypes.EnemyHealth: {
                var enemy = target.GetComponent<Mech>();
                var hp_ratio = enemy.currentHealth / enemy.totalHealth;
                result = utilCurve.Evaluate(hp_ratio);
            } break;

            case ConsiderationTypes.EnemyTeamSize: {
                var enemy = target.GetComponent<Mech>();
                var cur_team_size = enemy.currentTeamSize / (float)enemy.maxTeamSize;
                result = utilCurve.Evaluate(cur_team_size);
            } break;

            case ConsiderationTypes.Health: {
                var hp_ratio = mech.currentHealth / mech.totalHealth;
                result = utilCurve.Evaluate(hp_ratio);
            } break;

            case ConsiderationTypes.LineOfSight: {
                var los = Physics.Linecast(mech.transform.position, target.position);
                //  inverse &&  los -> 0
                //  inverse && !los -> 1
                // !inverse &&  los -> 1
                // !inverse && !los -> 0
                result = inverse
                    ? (los ? 0 : 1)
                    : (los ? 1 : 0);
            } break;

            case ConsiderationTypes.TeamSize: {
                var cur_team_size = mech.currentTeamSize / (float)mech.maxTeamSize;
                result = utilCurve.Evaluate(cur_team_size);
            } break;

            case ConsiderationTypes.Time: {
                var cur_time = Time.time - startTime;
                var time_ratio = cur_time / timeLimit;
                result = Mathf.Min(utilCurve.Evaluate(time_ratio), 1);
            } break;

            case ConsiderationTypes.WeaponCooldown: {
                // var wep = mech.CurrentWeapon;
                // var cooldown_over = wep.fireTime < 0;
                // //  inverse &&  cooldown_over -> 0
                // //  inverse && !cooldown_over -> 1
                // // !inverse &&  cooldown_over -> 1
                // // !inverse && !cooldown_over -> 0
                // result = inverse
                // 	? (cooldown_over ? 0 : 1)
                // 	: (cooldown_over ? 1 : 0);
            } break;

            default: {
                // Do nothing
            } break;
        }

        return result;
    }
 public static IStackSequence DoneNoAnimation(this Mech mech)
 {
     mech.OnActivationBegin(mech.GUID, -1);
     return(mech.GetDoneWithActorOrders());
 }
Пример #34
0
        private void FireDashJets(Mech mech)
        {
            if (fuel < Type.FuelUsage) return;

            fuel -= Type.FuelUsage;

            Vec3 vel = mech.PhysicsModel.GetBody("mainBody").Rotation.GetForward();

            vel = vel.GetNormalize() * Type.Velocity;

            mech.PhysicsModel.GetBody("mainBody").LinearVelocity = vel;
        }
 public static bool OverridePaperDollTooltip(CombatHUDMechTrayArmorHover __instance, Mech mech, ArmorLocation location)
 {
     try {
         if (!FriendOrFoe(mech, Settings.ShowAmmoInTooltip, Settings.ShowEnemyAmmoInTooltip))
         {
             return(true);
         }
         CombatHUDMechTrayArmorHover  me      = __instance;
         CombatHUDTooltipHoverElement ToolTip = (CombatHUDTooltipHoverElement)MechTrayArmorHoverToolTipProp.GetValue(me, null);
         ToolTip.BuffStrings.Clear();
         ToolTip.DebuffStrings.Clear();
         ToolTip.BasicString = Mech.GetLongArmorLocation(location);
         foreach (MechComponent mechComponent in mech.GetComponentsForLocation(MechStructureRules.GetChassisLocationFromArmorLocation(location), ComponentType.NotSet))
         {
             string componentName = mechComponent.UIName.ToString();
             int    allAmmo       = 1;
             if (mechComponent is Weapon weaponComp && !weaponComp.AmmoCategoryValue.Is_NotSet)
             {
                 componentName += "<size=80%> (x" + (allAmmo = weaponComp.CurrentAmmo) + ")";
             }
             else if (mechComponent is AmmunitionBox ammo)
             {
                 int curr = ammo.CurrentAmmo, max = ammo.AmmoCapacity;
                 componentName += "<size=80%> (" + curr + "/" + max + ")";
                 if (curr < max / 2)
                 {
                     componentName = "<#808080>" + componentName;
                 }
             }
             if (mechComponent.DamageLevel >= ComponentDamageLevel.NonFunctional || allAmmo <= 0)
             {
                 ToolTip.DebuffStrings.Add(new Text(componentName));
             }
             else
             {
                 ToolTip.BuffStrings.Add(new Text(componentName));
             }
         }
Пример #36
0
        private void FireJumpJets(Mech mech)
        {
            //mech.PhysicsModel.Bodies[0].AddForce(ForceType.GlobalAtGlobalPos, TickDelta, Vec3.ZAxis*Type.Force, mech.Position);
            //mech.PhysicsModel.Bodies[0].AddForce(ForceType.GlobalAtGlobalPos, TickDelta, Vec3.ZAxis * 2500f, mech.Position);

            if (fuel < Type.Fuel) return;

            fuel = 0f;

            Vec3 vel = mech.PhysicsModel.Bodies[0].LinearVelocity;

            vel.Z = Type.Velocity;
            mech.PhysicsModel.Bodies[0].LinearVelocity = vel;
        }
 public static bool hasHittableLocations(Weapon weapon, List <int> hitLocations, Mech target)
 {
     foreach (int location in hitLocations)
     {
         if (weapon.DamagePerShot * 2 >= target.ArmorForLocation(location))
         {
             return(true);
         }
     }
     return(false);
 }
Пример #38
0
    /// <summary>
    /// Start
    /// Pretty much everything that we do in MechUserControl we 
    /// only do for the local player..
    /// </summary>
    private void Start()
    {
        if (!isLocalPlayer)
         return;

          // get the transform of the main camera
          if (Camera.main != null)
          {
         m_Cam = Camera.main.transform;
          }
          else
          {
         Debug.LogWarning(
               "Warning: no main camera found. Third person character needs a Camera tagged \"MainCamera\", for camera-relative controls.");
         // we use self-relative controls in this case, which probably isn't what the user wants, but hey, we warned them!
          }

          // get the third person character ( this should never be null due to require component )
          m_MechController = GetComponent<MechController>();
          m_Mech = GetComponent<Mech>();
    }
        internal static void UpdateStructureDamage(
            this Mech mech,
            ChassisLocations location,
            WeaponHitInfo hitInfo,
            ref float damage
            )
        {
            if (damage <= 0)
            {
                return; // ignore 0 damage calls
            }

            var properties = ComponentExplosionsFeature.Shared.GetCASEProperties(mech, (int)location);

            if (properties == null)
            {
                return;
            }

            ComponentExplosionsFeature.IsInternalExplosionContained = true;
            Control.Logger.Debug?.Log($"prevent explosion pass through from {Mech.GetAbbreviatedChassisLocation(location)}");

            var maxStructureDamage = mech.GetCurrentStructure(location);

            Control.Logger.Debug?.Log($"damage={damage} maxStructureDamage={maxStructureDamage}");

            if (properties.MaximumDamage == null)
            {
                damage = Mathf.Min(maxStructureDamage, damage);
                mech.PublishFloatieMessage("EXPLOSION CONTAINED");
                return;
            }

            var newInternalDamage = Mathf.Min(damage, properties.MaximumDamage.Value);
            var backDamage        = damage - newInternalDamage;

            Control.Logger.Debug?.Log($"reducing structure damage from {damage} to {newInternalDamage}");

            damage = Mathf.Min(maxStructureDamage, newInternalDamage);
            mech.PublishFloatieMessage("EXPLOSION REDIRECTED");

            if (backDamage <= 0)
            {
                return;
            }

            if ((location & ChassisLocations.Torso) == 0)
            {
                return;
            }

            ArmorLocation armorLocation;

            switch (location)
            {
            case ChassisLocations.LeftTorso:
                armorLocation = ArmorLocation.LeftTorsoRear;
                break;

            case ChassisLocations.RightTorso:
                armorLocation = ArmorLocation.RightTorsoRear;
                break;

            default:
                armorLocation = ArmorLocation.CenterTorsoRear;
                break;
            }

            var armor = mech.GetCurrentArmor(armorLocation);

            if (armor <= 0)
            {
                return;
            }

            var armorDamage = Mathf.Min(backDamage, armor);

            Control.Logger.Debug?.Log($"added blowout armor damage {armorDamage} to {Mech.GetLongArmorLocation(armorLocation)}");

            mech.ApplyArmorStatDamage(armorLocation, armorDamage, hitInfo);
        }
 private void OnActionSetToAttack(Mech obj) => Action = UnitAction.PrimaryAttack;
Пример #41
0
        protected override BehaviorTreeResults Tick()
        {
            if (unit.HasMovedThisRound)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            BehaviorVariableValue targetLanceGuidValue = this.tree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_TARGET_GUID_KEY);

            if (targetLanceGuidValue == null)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            string targetLanceGuid = targetLanceGuidValue.StringVal;
            Lance  targetLance     = DestinationUtil.FindLanceByGUID(this.tree, targetLanceGuid);

            if (targetLance == null)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }
            List <AbstractActor> lanceMembers = AIUtil.GetLanceUnits(this.unit.Combat, this.unit.LanceId);

            float travelDistance = Mathf.Max(this.unit.MaxSprintDistance, this.unit.MaxWalkDistance);

            if (this.waitForLance)
            {
                for (int i = 0; i < lanceMembers.Count; i++)
                {
                    AbstractActor abstractActor = lanceMembers[i] as AbstractActor;

                    if (abstractActor != null)
                    {
                        float lanceMemberTravelDistance = Mathf.Max(abstractActor.MaxWalkDistance, abstractActor.MaxSprintDistance);
                        travelDistance = Mathf.Min(travelDistance, lanceMemberTravelDistance);
                    }
                }
            }

            AbstractActor targetActor   = null;
            float         targetTonnage = 0;

            for (int i = 0; i < targetLance.unitGuids.Count; i++)
            {
                ITaggedItem itemByGUID = this.unit.Combat.ItemRegistry.GetItemByGUID(targetLance.unitGuids[i]);

                if (itemByGUID != null)
                {
                    AbstractActor abstractActor = itemByGUID as AbstractActor;

                    if (abstractActor != null && !abstractActor.IsDead)
                    {
                        if (abstractActor is Mech)
                        {
                            Mech mech = (Mech)abstractActor;
                            if (mech.tonnage > targetTonnage)
                            {
                                targetActor   = mech;
                                targetTonnage = mech.tonnage;
                            }
                        }
                        else if (abstractActor is Vehicle)
                        {
                            Vehicle vehicle = (Vehicle)abstractActor;
                            if (vehicle.tonnage > targetTonnage)
                            {
                                targetActor   = vehicle;
                                targetTonnage = vehicle.tonnage;
                            }
                        }
                    }
                }
            }

            if (targetActor == null)
            {
                Main.Logger.LogError("[MoveToFollowLanceNode] Target Actor is null");
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            Main.LogDebug($"[MoveToFollowLanceNode] Target to follow is '{targetActor.DisplayName} {targetActor.VariantName}'");

            bool shouldSprint = this.tree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_SHOULD_SPRINT_KEY).BoolVal;

            shouldSprint = (!this.unit.HasAnyContactWithEnemy);
            shouldSprint = (this.unit.CurrentPosition - targetActor.CurrentPosition).magnitude > 200f; // sprint if the unit is over 200 metres away

            AbstractActor closestDetectedEnemy = AiUtils.GetClosestDetectedEnemy(this.unit, targetLance);
            Vector3       lookDirection        = (closestDetectedEnemy == null) ? targetActor.CurrentPosition : closestDetectedEnemy.CurrentPosition;

            MoveType moveType = (shouldSprint) ? MoveType.Sprinting : MoveType.Walking;

            this.unit.Pathing.UpdateAIPath(targetActor.CurrentPosition, lookDirection, moveType);

            Vector3 vectorToTarget   = this.unit.Pathing.ResultDestination - this.unit.CurrentPosition;
            float   distanceToTarget = vectorToTarget.magnitude;

            if (distanceToTarget > travelDistance)
            {
                // If the target is out of range, head in the direction of that unit to the maximum possible travel distance for this turn
                vectorToTarget = vectorToTarget.normalized * travelDistance;
            }

            // Ensure the units aren't crowded
            Vector3 targetDestination = RoutingUtil.Decrowd(this.unit.CurrentPosition + vectorToTarget, this.unit);

            targetDestination = RegionUtil.MaybeClipMovementDestinationToStayInsideRegion(this.unit, targetDestination);

            float followLanceZoneRadius = this.unit.BehaviorTree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_ZONE_RADIUS_KEY).FloatVal;

            if (RoutingUtils.IsUnitInsideRadiusOfPoint(this.unit, targetActor.CurrentPosition, followLanceZoneRadius))
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            this.unit.Pathing.UpdateAIPath(targetDestination, lookDirection, (shouldSprint) ? MoveType.Sprinting : MoveType.Walking);
            targetDestination = this.unit.Pathing.ResultDestination;
            float        maxCost             = this.unit.Pathing.MaxCost;
            PathNodeGrid currentGrid         = this.unit.Pathing.CurrentGrid;
            Vector3      targetActorPosition = targetActor.CurrentPosition;

            if ((currentGrid.GetValidPathNodeAt(targetDestination, maxCost) == null || (targetDestination - targetActor.CurrentPosition).magnitude > 1f) && this.unit.Combat.EncounterLayerData.inclineMeshData != null)
            {
                float maxSlope = Mathf.Tan(0.0174532924f * AIUtil.GetMaxSteepnessForAllLance(this.unit));
                List <AbstractActor> lanceUnits = AIUtil.GetLanceUnits(this.unit.Combat, this.unit.LanceId);
                targetDestination = this.unit.Combat.EncounterLayerData.inclineMeshData.GetDestination(this.unit.CurrentPosition, targetDestination, maxCost, maxSlope, this.unit, shouldSprint, lanceUnits, this.unit.Pathing.CurrentGrid, out targetActorPosition);
            }

            Vector3 currentPosition = this.unit.CurrentPosition;

            AIUtil.LogAI(string.Format("issuing order from [{0} {1} {2}] to [{3} {4} {5}] looking at [{6} {7} {8}]", new object[] {
                currentPosition.x,
                currentPosition.y,
                currentPosition.z,
                targetDestination.x,
                targetDestination.y,
                targetDestination.z,
                targetActorPosition.x,
                targetActorPosition.y,
                targetActorPosition.z
            }), "AI.DecisionMaking");

            return(new BehaviorTreeResults(BehaviorNodeState.Success)
            {
                orderInfo = new MovementOrderInfo(targetDestination, targetActorPosition)
                {
                    IsSprinting = shouldSprint
                },
                debugOrderString = string.Format("{0} moving toward destination: {1} dest: {2}", this.name, targetDestination, targetActor.CurrentPosition)
            });
        }
Пример #42
0
 public MechResearchState(Mech character, MechStateMachine stateMachine) : base(character, stateMachine)
 {
 }
Пример #43
0
            private static void Prefix(Mech __instance, string sourceID, int stackItemID)
            {
                if (__instance.IsOverheated)
                {
                    CBTPilotingRules rules          = new CBTPilotingRules(__instance.Combat);
                    float            gutsTestChance = rules.GetGutsModifier(__instance);
                    float            skillRoll      = __instance.Combat.NetworkRandom.Float();
                    float            ammoRoll       = __instance.Combat.NetworkRandom.Float();

                    int   turnsOverheated         = __instance.StatCollection.ContainsStatistic(ModStats.TurnsOverheated) ? __instance.StatCollection.GetValue <int>("TurnsOverheated") : 0;
                    float shutdownPercentage      = HeatHelper.GetShutdownPercentageForTurn(turnsOverheated);
                    float ammoExplosionPercentage = HeatHelper.GetAmmoExplosionPercentageForTurn(turnsOverheated);

                    Mod.Log.Debug($"Mech:{CombatantHelper.LogLabel(__instance)} is overheated for {turnsOverheated} turns. Checking shutdown override.");
                    Mod.Log.Debug($"  Guts -> skill: {__instance.SkillGuts}  divisor: {Mod.Config.GutsDivisor}  bonus: {gutsTestChance}");
                    Mod.Log.Debug($"  Skill roll: {skillRoll} plus guts roll: {skillRoll + gutsTestChance}  target: {shutdownPercentage}");
                    Mod.Log.Debug($"  Ammo roll: {ammoRoll} plus guts roll: {ammoRoll + gutsTestChance}  target: {ammoExplosionPercentage}");

                    if (Mod.Config.UseGuts)
                    {
                        ammoRoll  = ammoRoll + gutsTestChance;
                        skillRoll = skillRoll + gutsTestChance;
                    }

                    MultiSequence sequence = new MultiSequence(__instance.Combat);
                    sequence.SetCamera(CameraControl.Instance.ShowDeathCam(__instance, false, -1f), 0);

                    if (HeatHelper.CanAmmoExplode(__instance))
                    {
                        if (ammoRoll < ammoExplosionPercentage)
                        {
                            __instance.Combat.MessageCenter.PublishMessage(new FloatieMessage(__instance.GUID, __instance.GUID, "Ammo Overheated!", FloatieMessage.MessageNature.CriticalHit));

                            var ammoBox = __instance.ammoBoxes.Where(box => box.CurrentAmmo > 0).OrderByDescending(box => box.CurrentAmmo / box.AmmoCapacity).FirstOrDefault();
                            if (ammoBox != null)
                            {
                                WeaponHitInfo fakeHit = new WeaponHitInfo(stackItemID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null, new AttackDirection[] { AttackDirection.None }, null, null, null);
                                ammoBox.DamageComponent(fakeHit, ComponentDamageLevel.Destroyed, true);
                            }

                            return;
                        }

                        sequence.AddChildSequence(new ShowActorInfoSequence(__instance, "Ammo Explosion Avoided!", FloatieMessage.MessageNature.Debuff, true), sequence.ChildSequenceCount - 1);
                    }

                    if (!__instance.IsPastMaxHeat)
                    {
                        if (skillRoll < shutdownPercentage)
                        {
                            Mod.Log.Debug(string.Format("Skill Check Failed! Initiating Shutdown"));

                            MechEmergencyShutdownSequence mechShutdownSequence = new MechEmergencyShutdownSequence(__instance);
                            sequence.AddChildSequence(mechShutdownSequence, sequence.ChildSequenceCount - 1);

                            __instance.StatCollection.Set <int>("TurnsOverheated", 0);
                        }
                        else
                        {
                            Mod.Log.Debug(string.Format("Skill Check Succeeded!"));

                            sequence.AddChildSequence(new ShowActorInfoSequence(__instance, "Shutdown Override Successful!", FloatieMessage.MessageNature.Buff, true), sequence.ChildSequenceCount - 1);

                            turnsOverheated += 1;
                            __instance.StatCollection.Set <int>("TurnsOverheated", turnsOverheated);
                        }
                    }

                    sequence.AddChildSequence(new DelaySequence(__instance.Combat, 2f), sequence.ChildSequenceCount - 1);

                    __instance.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(sequence));
                }
                else
                {
                    int turnsOverheated = __instance.StatCollection.GetValue <int>("TurnsOverheated");
                    if (turnsOverheated > 0)
                    {
                        __instance.StatCollection.Set <int>("TurnsOverheated", 0);
                    }
                }
            }
Пример #44
0
 void Start()
 {
     mech = GetComponent<Mech>();
     actions = actionTypes.Select  (at => Actions.createType(at)).ToList();
     moves   = movementTypes.Select(mt => Actions.createType(mt)).ToList();
 }