// Resolve turret hits - any hull breach kill the unit
        private static void ResolveTurretHullBreaches(Turret targetTurret)
        {
            bool needsQuip = false;

            // Check for immunity
            List <MechComponent> components =
                targetTurret.allComponents.Where(mc => mc.DamageLevel == ComponentDamageLevel.Functional).ToList();
            bool hasImmunity = false;

            foreach (MechComponent mc in components)
            {
                if (mc.StatCollection.ContainsStatistic(ModStats.HullBreachImmunity))
                {
                    Mod.Log.Debug?.Write($"  Component: {mc.UIName} grants hull breach immunity, skipping!");
                    hasImmunity = true;
                    break;
                }
            }
            if (hasImmunity)
            {
                return;
            }

            foreach (BuildingLocation hitLocation in ModState.BreachHitsTurret.Keys)
            {
                // If no immunity, sum the breach check across all trials
                float passChance = 1f - ModState.BreachCheck;
                //float sequencePassChance = Mathf.Pow(passChance, ModState.BreachHitsTurret[hitLocation]);
                // TODO: Number of trials is way too rough, and can make breaches extremely common. Weakening to flat percentage chance.
                float sequencePassChance = Mathf.Pow(passChance, 1);
                float sequenceThreshold  = 1f - sequencePassChance;
                Mod.Log.Debug?.Write($" For pass chance: {passChance} with n trials: {ModState.BreachHitsTurret[hitLocation]} has sequencePassChance: {sequencePassChance} => sequenceThreshold: {sequenceThreshold}");

                // Check for failure
                bool passedCheck = CheckHelper.DidCheckPassThreshold(sequenceThreshold, targetTurret, 0f, Mod.LocalizedText.Floaties[ModText.FT_Hull_Breach]);
                Mod.Log.Debug?.Write($"Actor: {CombatantUtils.Label(targetTurret)} HULL BREACH check: {passedCheck} for location: {hitLocation}");
                if (!passedCheck)
                {
                    Mod.Log.Info?.Write($" Turret {CombatantUtils.Label(targetTurret)} suffers a hull breach in location: {hitLocation}");

                    string        floatieText      = new Text(Mod.LocalizedText.Floaties[ModText.FT_Hull_Breach]).ToString();
                    MultiSequence showInfoSequence = new ShowActorInfoSequence(targetTurret, floatieText, FloatieMessage.MessageNature.Debuff, false);
                    targetTurret.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(showInfoSequence));

                    needsQuip = true;

                    if (targetTurret.GetPilot() != null)
                    {
                        targetTurret.GetPilot().KillPilot(targetTurret.Combat.Constants, "", 0, DamageType.Unknown, null, null);
                    }
                    targetTurret.FlagForDeath("Dead from hull breach!", DeathMethod.Unknown, DamageType.Unknown, -1, -1, "", false);
                    targetTurret.HandleDeath("0");
                }
            }
            if (needsQuip)
            {
                QuipHelper.PublishQuip(targetTurret, Mod.LocalizedText.Quips.Breach);
            }
        }
        private static void ResolveVehicleHullBreaches(Vehicle targetVehicle)
        {
            bool needsQuip = false;

            foreach (VehicleChassisLocations hitLocation in ModState.BreachHitsVehicle.Keys)
            {
                List <MechComponent> componentsInLocation =
                    targetVehicle.allComponents.Where(mc => mc.mechComponentRef.DamageLevel == ComponentDamageLevel.Functional && mc.mechComponentRef.MountedLocation == (ChassisLocations)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.BreachHitsVehicle[hitLocation]);
                float sequenceThreshold  = 1f - sequencePassChance;
                Mod.Log.Debug($" For pass chance: {passChance} with n trials: {ModState.BreachHitsVehicle[hitLocation]} has sequencePassChance: {sequencePassChance} => sequenceThreshold: {sequenceThreshold}");

                // Check for failure
                bool passedCheck = CheckHelper.DidCheckPassThreshold(sequenceThreshold, targetVehicle, 0f, Mod.Config.LocalizedFloaties[ModConfig.FT_Hull_Breach]);
                Mod.Log.Debug($"Actor: {CombatantUtils.Label(targetVehicle)} 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(targetVehicle, floatieText, FloatieMessage.MessageNature.Debuff, false);
                    targetVehicle.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(showInfoSequence));

                    needsQuip = true;

                    if (targetVehicle.GetPilot() != null)
                    {
                        targetVehicle.GetPilot().KillPilot(targetVehicle.Combat.Constants, "", 0, DamageType.Unknown, null, null);
                    }
                    targetVehicle.FlagForDeath("Dead from hull breach!", DeathMethod.Unknown, DamageType.Unknown, -1, -1, "", false);
                    targetVehicle.HandleDeath("0");
                    break;
                }
            }
            if (needsQuip)
            {
                QuipHelper.PublishQuip(targetVehicle, Mod.Config.Qips.Breach);
            }
        }
Exemplo n.º 3
0
 private void Taunt()
 {
     if (!hasTaunted)
     {
         // Create a quip
         Guid g = Guid.NewGuid();
         QuipHelper.PlayQuip(ModState.Combat, g.ToString(),
                             this.AmbushTeam, "IED Ambush", Mod.Config.Quips.ExplosiveAmbush, this.timeToTaunt);
         hasTaunted = true;
     }
 }
Exemplo n.º 4
0
        static void Postfix(BehaviorNode __instance, ref BehaviorTreeResults __result)
        {
            Traverse      unitT = Traverse.Create(__instance).Field("unit");
            AbstractActor unit  = unitT.GetValue <AbstractActor>();

            if (unit is Mech mech)
            {
                float heatCheck  = mech.HeatCheckMod(Mod.Config.SkillChecks.ModPerPointOfGuts);
                int   futureHeat = mech.CurrentHeat - mech.AdjustedHeatsinkCapacity;

                // Check to see if we will shutdown
                bool passedStartupCheck = CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.Shutdown, futureHeat, mech, heatCheck, ModText.FT_Check_Startup);
                Mod.Log.Info?.Write($"AI unit {CombatantUtils.Label(mech)} heatCheck: {heatCheck} vs. futureHeat: {futureHeat} " +
                                    $"(from currentHeat: {mech.CurrentHeat} - sinking: {mech.AdjustedHeatsinkCapacity}) => passed: {passedStartupCheck}");

                if (!passedStartupCheck)
                {
                    Mod.Log.Info?.Write($" -- shutdown check failed, forcing it to remain shutdown.");
                    BehaviorTreeResults newResult = new BehaviorTreeResults(BehaviorNodeState.Failure);
                    newResult.orderInfo = new OrderInfo(OrderType.Stand);
                    __result            = newResult;

                    bool failedInjuryCheck = CheckHelper.ResolvePilotInjuryCheck(mech, futureHeat, -1, -1, heatCheck);
                    if (failedInjuryCheck)
                    {
                        Mod.Log.Info?.Write("  -- unit did not pass injury check!");
                    }

                    bool failedSystemFailureCheck = CheckHelper.ResolveSystemFailureCheck(mech, futureHeat, -1, heatCheck);
                    if (failedSystemFailureCheck)
                    {
                        Mod.Log.Info?.Write("  -- unit did not pass system failure check!");
                    }

                    bool failedAmmoCheck = CheckHelper.ResolveRegularAmmoCheck(mech, futureHeat, -1, heatCheck);
                    if (failedAmmoCheck)
                    {
                        Mod.Log.Info?.Write("  -- unit did not pass ammo explosion check!");
                    }

                    bool failedVolatileAmmoCheck = CheckHelper.ResolveVolatileAmmoCheck(mech, futureHeat, -1, heatCheck);
                    if (failedVolatileAmmoCheck)
                    {
                        Mod.Log.Info?.Write("  -- unit did not pass volatile ammo explosion check!");
                    }

                    QuipHelper.PublishQuip(mech, Mod.LocalizedText.Quips.Startup);
                }
                else
                {
                    Mod.Log.Info?.Write($" -- shutdown check passed, starting up normally.");
                }
            }
        }
Exemplo n.º 5
0
 private void Taunt()
 {
     if (!hasTaunted)
     {
         Mod.Log.Debug?.Write("Taunting player.");
         // Create a quip
         Guid g = Guid.NewGuid();
         QuipHelper.PlayQuip(ModState.Combat, g.ToString(), AttackingActors[0].team,
                             "Infantry Ambush", Mod.Config.Quips.InfantryAmbush, this.timeToTaunt * 3f);
         hasTaunted = true;
     }
 }
Exemplo n.º 6
0
        public static bool Prefix(MechStartupInvocation __instance, CombatGameState combatGameState)
        {
            Mech mech = combatGameState.FindActorByGUID(__instance.MechGUID) as Mech;

            if (mech == null)
            {
                return(true);
            }

            // Check to see if we should restart automatically
            float heatCheck          = mech.HeatCheckMod(Mod.Config.Piloting.SkillMulti);
            int   futureHeat         = mech.CurrentHeat - mech.AdjustedHeatsinkCapacity;
            bool  passedStartupCheck = CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.Shutdown, futureHeat, mech, heatCheck, ModConfig.FT_Check_Startup);

            if (passedStartupCheck)
            {
                return(true);
            }                                        // Do the normal startup process

            Mod.Log.Debug($"Mech: {CombatantUtils.Label(mech)} failed a startup roll, venting heat but remaining offline.");

            QuipHelper.PublishQuip(mech, Mod.Config.Qips.Startup);

            DoneWithActorSequence doneWithActorSequence = (DoneWithActorSequence)mech.GetDoneWithActorOrders();
            MechHeatSequence      mechHeatSequence      = new MechHeatSequence(mech, true, true, "STARTUP");

            doneWithActorSequence.AddChildSequence(mechHeatSequence, mechHeatSequence.MessageIndex);

            InvocationStackSequenceCreated message = new InvocationStackSequenceCreated(doneWithActorSequence, __instance);

            combatGameState.MessageCenter.PublishMessage(message);
            AddSequenceToStackMessage.Publish(combatGameState.MessageCenter, doneWithActorSequence);

            //mech.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(mechHeatSequence));

            //mech.OnStartupComplete(mechHeatSequence.SequenceGUID);
            //mech.DoneWithActor();

            return(false);
        }
        // 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);
            }
        }
Exemplo n.º 8
0
        public static bool Prefix(MechStartupInvocation __instance, CombatGameState combatGameState)
        {
            Mech mech = combatGameState.FindActorByGUID(__instance.MechGUID) as Mech;

            if (mech == null)
            {
                return(true);
            }

            Mod.Log.Info?.Write($"Processing startup for Mech: {CombatantUtils.Label(mech)}");

            // Check to see if we should restart automatically
            float heatCheck          = mech.HeatCheckMod(Mod.Config.SkillChecks.ModPerPointOfGuts);
            int   futureHeat         = mech.CurrentHeat - mech.AdjustedHeatsinkCapacity;
            bool  passedStartupCheck = CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.Shutdown, futureHeat, mech, heatCheck, ModText.FT_Check_Startup);

            Mod.Log.Info?.Write($"  -- futureHeat: {futureHeat} = current: {mech.CurrentHeat} - HSCapacity: {mech.AdjustedHeatsinkCapacity} vs. heatCheck: {heatCheck} => passedStartup: {passedStartupCheck}");

            bool failedInjuryCheck = CheckHelper.ResolvePilotInjuryCheck(mech, futureHeat, -1, -1, heatCheck);

            if (failedInjuryCheck)
            {
                Mod.Log.Info?.Write("  -- unit did not pass injury check!");
            }

            bool failedSystemFailureCheck = CheckHelper.ResolveSystemFailureCheck(mech, futureHeat, -1, heatCheck);

            if (failedSystemFailureCheck)
            {
                Mod.Log.Info?.Write("  -- unit did not pass system failure check!");
            }

            bool failedAmmoCheck = CheckHelper.ResolveRegularAmmoCheck(mech, futureHeat, -1, heatCheck);

            if (failedAmmoCheck)
            {
                Mod.Log.Info?.Write("  -- unit did not pass ammo explosion check!");
            }

            bool failedVolatileAmmoCheck = CheckHelper.ResolveVolatileAmmoCheck(mech, futureHeat, -1, heatCheck);

            if (failedVolatileAmmoCheck)
            {
                Mod.Log.Info?.Write("  -- unit did not pass volatile ammo explosion check!");
            }

            if (passedStartupCheck)
            {
                Mod.Log.Debug?.Write($" -- passed startup roll, going through regular MechStartupSequence.");
                return(true);
            }

            Mod.Log.Info?.Write($" -- failed startup roll, venting heat but remaining offline.");

            DoneWithActorSequence doneWithActorSequence = (DoneWithActorSequence)mech.GetDoneWithActorOrders();
            MechHeatSequence      mechHeatSequence      = new MechHeatSequence(OwningMech: mech, performHeatSinkStep: true, applyStartupHeatSinks: false, instigatorID: "STARTUP");

            doneWithActorSequence.AddChildSequence(mechHeatSequence, mechHeatSequence.MessageIndex);

            QuipHelper.PublishQuip(mech, Mod.LocalizedText.Quips.Startup);

            InvocationStackSequenceCreated message = new InvocationStackSequenceCreated(doneWithActorSequence, __instance);

            combatGameState.MessageCenter.PublishMessage(message);
            AddSequenceToStackMessage.Publish(combatGameState.MessageCenter, doneWithActorSequence);

            Mod.Log.Debug?.Write($" -- sent sequence to messageCenter");
            return(false);
        }
Exemplo n.º 9
0
 public static void Postfix(MechFallSequence __instance)
 {
     Mod.Log.Trace?.Write("MFS:OnAdded - entered.");
     QuipHelper.PublishQuip(__instance.OwningMech, Mod.LocalizedText.Quips.Knockdown);
 }