internal static ArmorLocation GetPassthroughLocation(
            ArmorLocation location,
            AttackDirection attackDirection
            )
        {
            try
            {
                if (ComponentExplosionsFeature.IsInternalExplosion && currentMech != null)
                {
                    var chassisLocation = MechStructureRules.GetChassisLocationFromArmorLocation(location);
                    var properties      = ComponentExplosionsFeature.Shared.GetCASEProperties(currentMech, (int)chassisLocation);
                    if (properties != null)
                    {
                        currentMech.PublishFloatieMessage("EXPLOSION CONTAINED");

                        //Control.mod.Logger.LogDebug($"prevented explosion pass through from {Mech.GetAbbreviatedChassisLocation(chassisLocation)}");

                        return(ArmorLocation.None); // CASE redirects damage, so lets redirect it to none
                    }
                }
            }
            catch (Exception e)
            {
                Control.mod.Logger.LogError(e);
            }

            return(MechStructureRules.GetPassthroughLocation(location, attackDirection));
        }
        private static void PrintHitLocations(WeaponHitInfo hitInfo)
        {
            if (!Core.ModSettings.debug)
            {
                return;
            }
            try
            {
                var output = "";
                output += $"clustered hits: {hitInfo.hitLocations.Length}\n";
                for (int i = 0; i < hitInfo.hitLocations.Length; i++)
                {
                    int location = hitInfo.hitLocations[i];
                    var chassisLocationFromArmorLocation =
                        MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)location);

                    if (location == 0 || location == 65536)
                    {
                        output += $"hitLocation {i}: NONE/INVALID\n";
                    }
                    else
                    {
                        output += $"hitLocation {i}: {chassisLocationFromArmorLocation} ({location})\n";
                    }
                }
                Logger.Debug(output);
            }
            catch (Exception e)
            {
                Logger.Error(e);
            }
        }
        public static bool Prefix(
            Mech __instance,
            WeaponHitInfo hitInfo,
            ArmorLocation aLoc,
            ref float directStructureDamage,
            ref bool __result)
        {
            try
            {
                if (ComponentExplosionsFeature.IsInternalExplosionContained)
                {
                    __result = false;
                    Control.Logger.Warning.Log("prevented explosion pass through (you should never see this message)");
                    return(false);
                }

                if (ComponentExplosionsFeature.IsInternalExplosion)
                {
                    var location = MechStructureRules.GetChassisLocationFromArmorLocation(aLoc);
                    UpdateStructureDamage(__instance, location, hitInfo, ref directStructureDamage);
                }
            }
            catch (Exception e)
            {
                Control.Logger.Error.Log(e);
            }

            return(true);
        }
        public static void LogHitLocations(WeaponHitInfo hitInfo)
        {
            try
            {
                string output = "---\n";
                output += $"[Utilities_LogHitLocations] Clustered hits: {hitInfo.hitLocations.Length}\n";
                for (int i = 0; i < hitInfo.hitLocations.Length; i++)
                {
                    int location = hitInfo.hitLocations[i];
                    var chassisLocationFromArmorLocation = MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)location);

                    if (location == 0 || location == 65536)
                    {
                        output += $"[Utilities_LogHitLocations] HitLocation {i}: NONE/INVALID({location})";
                    }
                    else
                    {
                        output += $"[Utilities_LogHitLocations] HitLocation {i}: {chassisLocationFromArmorLocation}({location})";
                    }

                    output += (i < hitInfo.hitLocations.Length - 1) ? "\n" : "\n---";
                }
                Logger.Info(output, false);
            }
            catch (Exception e)
            {
                Logger.Error(e);
            }
        }
Example #5
0
            static void Prefix(Mech __instance, int originalHitLoc, WeaponHitInfo hitInfo, ArmorLocation aLoc, Weapon weapon,
                               float totalArmorDamage, float directStructureDamage, int hitIndex, AttackImpactQuality impactQuality, DamageType damageType)
            {
                if (aLoc == ArmorLocation.None || aLoc == ArmorLocation.Invalid)
                {
                    return;
                }


                float num          = totalArmorDamage;
                float currentArmor = __instance.GetCurrentArmor(aLoc);

                if (currentArmor > 0f)
                {
                    num = totalArmorDamage - currentArmor;
                }
                num += directStructureDamage; // account for damage split: this should get us back where we were when we both had armour spillover damage and
                // any damage done directly to the structure
                if (num <= 0f)
                {
                    return; //no need to continue if the shot doesn't do anything we care about
                }
                ChassisLocations chassisLocationFromArmorLocation = MechStructureRules.GetChassisLocationFromArmorLocation(aLoc);


                float currentStructure = __instance.GetCurrentStructure(chassisLocationFromArmorLocation);

                if (currentStructure > 0f)
                {
                    float num4         = Math.Min(num, currentStructure);
                    bool  WasDestroyed = (currentStructure - num) <= 0; //if currentstructure minus remaining damage is less or equal to 0, then the location is destroyed.

                    num -= num4;
                    if (WasDestroyed && num4 > 0.01f) //this location was destroyed, so we now check for dependents.
                    {
                        if (chassisLocationFromArmorLocation == ChassisLocations.LeftArm)
                        {
                            Holder.LeftArmSurvived = false; //invalidate if the actual arm was destroyed
                        }
                        else if (chassisLocationFromArmorLocation == ChassisLocations.RightArm)
                        {
                            Holder.RightArmSurvived = false; //invalidate if the actual arm was destroyed
                        }
                        ChassisLocations dependentLocation = MechStructureRules.GetDependentLocation(chassisLocationFromArmorLocation);
                        if (dependentLocation != ChassisLocations.None && !__instance.IsLocationDestroyed(dependentLocation))
                        {
                            if (dependentLocation == ChassisLocations.LeftArm)
                            {
                                Holder.LeftArmSurvived = true; //side torso was destroyed, no reason the arm should be totally trashed.
                            }
                            else if (dependentLocation == ChassisLocations.RightArm)
                            {
                                Holder.RightArmSurvived = true; //side torso was destroyed, no reason the arm should be totally trashed.
                            }
                        }
                    }
                }
            }
Example #6
0
 public static void AddDamagedLocation(this Mech unit, int Location)
 {
     if (DamagedStructureLocationsThisTurn.ContainsKey(unit) == false)
     {
         DamagedStructureLocationsThisTurn.Add(unit, new HashSet <int>());
     }
     DamagedStructureLocationsThisTurn[unit].Add((int)MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)Location));
     unit.StatCollection.SetOrCreateStatisic(unit.GetArmorStringForLocation(Location) + "_damageRound", unit.Combat.TurnDirector.CurrentRound);
 }
Example #7
0
        public static float GetRemainingHealth(this Mech mech, ArmorLocation aLocation)
        {
            ChassisLocations cLocation = MechStructureRules.GetChassisLocationFromArmorLocation(aLocation);

            float armorCurrent     = mech.GetCurrentArmor(aLocation);
            float structureCurrent = mech.GetCurrentStructure(cLocation);

            Logger.Info($"[MechExtensions_GetRemainingHealth] ({aLocation}) H:{structureCurrent + armorCurrent}(S:{structureCurrent}, A:{armorCurrent})");

            return(armorCurrent + structureCurrent);
        }
            public static void Postfix(Mech __instance, int stackID, string attackerID)
            {
                if (__instance.IsDead || (__instance.IsFlaggedForDeath && __instance.HasHandledDeath) || !__instance.IsOverheated && !__instance.IsShutDown)
                {
                    return; //don't bother if they're dead or not overheating
                }
                foreach (MechComponent mechComponent in __instance.allComponents)
                {
                    if (mechComponent as AmmunitionBox != null)
                    {
                        AmmunitionBox ammoBox = mechComponent as AmmunitionBox;

                        if (ammoBox != null)
                        {
                            int   value    = ammoBox.StatCollection.GetValue <int>("CurrentAmmo");
                            int   capacity = ammoBox.ammunitionBoxDef.Capacity;
                            float num      = value / (float)capacity;
                            if (num < 0.5f && Settings.UseHBSMercySetting)
                            {
                                return;
                            }
                            var rng        = (new System.Random()).Next(100);
                            var rollToBeat = __instance.IsShutDown ? Settings.ShutdownHeatChance : Settings.OverheatChance; //if shut down, we use the Shutdown chance. Otherwise, the normal overheat chance.


                            if (rng < rollToBeat) //things are exploding captain!
                            {
                                if (__instance.Combat.Constants.PilotingConstants.InjuryFromAmmoExplosion)
                                {
                                    Pilot pilot = __instance.GetPilot();
                                    if (pilot != null)
                                    {
                                        pilot.SetNeedsInjury(InjuryReason.AmmoExplosion);
                                    }
                                }
                                string text = string.Format("{0} EXPLOSION", ammoBox.Name);
                                ammoBox.parent.Combat.MessageCenter.PublishMessage(new FloatieMessage(ammoBox.parent.GUID, ammoBox.parent.GUID, text, FloatieMessage.MessageNature.CriticalHit));
                                //we make a fake hit info to apply the nuking
                                WeaponHitInfo hitInfo = new WeaponHitInfo(stackID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null, new AttackDirection[]
                                {
                                    AttackDirection.FromFront
                                }, null, null, null);
                                Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere;
                                __instance.NukeStructureLocation(hitInfo, ammoBox.Location, (ChassisLocations)ammoBox.Location, onUnitSphere, DamageType.Overheat);
                                ChassisLocations dependentLocation = MechStructureRules.GetDependentLocation((ChassisLocations)ammoBox.Location);
                                if (dependentLocation != ChassisLocations.None && !__instance.IsLocationDestroyed(dependentLocation))
                                {
                                    __instance.NukeStructureLocation(hitInfo, ammoBox.Location, dependentLocation, onUnitSphere, DamageType.Overheat);
                                }
                            }
                        }
                    }
                }
            }
 public static void LogMechHit(ArmorLocation __result, Dictionary <ArmorLocation, int> hitTable, float randomRoll, ArmorLocation bonusLocation, float bonusLocationMultiplier)
 {
     LogHitSequence(MechStructureRules.GetChassisLocationFromArmorLocation(__result), randomRoll, bonusLocation, bonusLocationMultiplier,
                    TryGet(hitTable, ArmorLocation.Head) + Separator +
                    (TryGet(hitTable, ArmorLocation.CenterTorso) + TryGet(hitTable, ArmorLocation.CenterTorsoRear)) + Separator +
                    (TryGet(hitTable, ArmorLocation.LeftTorso) + TryGet(hitTable, ArmorLocation.LeftTorsoRear)) + Separator +
                    (TryGet(hitTable, ArmorLocation.RightTorso) + TryGet(hitTable, ArmorLocation.RightTorsoRear)) + Separator +
                    TryGet(hitTable, ArmorLocation.LeftArm) + Separator +
                    TryGet(hitTable, ArmorLocation.RightArm) + Separator +
                    TryGet(hitTable, ArmorLocation.LeftLeg) + Separator +
                    TryGet(hitTable, ArmorLocation.RightLeg));
 }
Example #10
0
        public static float GetRemainingHealthRatio(this Mech mech, ArmorLocation aLocation)
        {
            ChassisLocations cLocation = MechStructureRules.GetChassisLocationFromArmorLocation(aLocation);

            float armorCurrent     = mech.GetCurrentArmor(aLocation);
            float structureCurrent = mech.GetCurrentStructure(cLocation);
            float armorMax         = mech.GetMaxArmor(aLocation);
            float structureMax     = mech.GetMaxStructure(cLocation);

            Logger.Info($"[MechExtensions_GetRemainingHealthRatio] ({aLocation}) S:{structureCurrent}/{structureMax}, A:{armorCurrent}/{armorMax}");

            return((armorCurrent + structureCurrent) / (armorMax + structureMax));
        }
Example #11
0
        public static void ShowCalledLocationHP(CombatHUDCalledShotPopUp __instance)
        {
            try {
                if (title == null)
                {
                    title = UnityEngine.GameObject.Find("calledShot_Title")?.GetComponent <TMPro.TextMeshProUGUI>();
                    title.enableAutoSizing = false;
                    if (title == null)
                    {
                        return;
                    }
                }

                /*
                 * public void SetText(StringBuilder text);
                 * public void SetText(string text, float arg0, float arg1, float arg2);
                 * public void SetText(string text, float arg0, float arg1);
                 * public void SetText(string text, float arg0);
                 * public void SetText(string text, bool syncTextInputBox);
                 * public void SetText(string text);*/

                CombatHUDCalledShotPopUp me           = __instance;
                ArmorLocation            hoveredArmor = me.MechArmorDisplay.HoveredArmor;
                if (me.locationNameText.text.StartsWith("-"))
                {
                    title.SetText("Called Shot");
                }
                else if (me.DisplayedActor is Mech mech)
                {
                    float hp = mech.GetCurrentStructure(MechStructureRules.GetChassisLocationFromArmorLocation(hoveredArmor));
                    if (hp <= 0)
                    {
                        title.SetText("Called Shot");
                        me.locationNameText.SetText("-choose target-", ZeroObjects);
                    }
                    else
                    {
                        float mhp = mech.GetMaxStructure(MechStructureRules.GetChassisLocationFromArmorLocation(hoveredArmor)),
                              armour = mech.GetCurrentArmor(hoveredArmor), marmour = mech.GetMaxArmor(hoveredArmor);
                        title.text = me.locationNameText.text;
                        me.locationNameText.text = string.Format("{0:0}/{1:0} <#FFFFFF>{2:0}/{3:0}", hp, mhp, armour, marmour);
                    }
                }
            }                 catch (Exception ex) { Error(ex); }
        }
Example #12
0
        // The default method assumes an absractActor exists, and tries to draw a line of fire. We don't have that, so skip it.
        public static void ResolveSourcelessWeaponDamage(this Mech mech, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType)
        {
            AttackDirector.AttackSequence attackSequence = ModState.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId);
            float damagePerShot          = weapon.DamagePerShot;
            float structureDamagePerShot = weapon.StructureDamagePerShot;

            LineOfFireLevel lineOfFireLevel = LineOfFireLevel.LOFClear;

            damagePerShot          = mech.GetAdjustedDamage(damagePerShot, weapon.WeaponCategoryValue, mech.occupiedDesignMask, lineOfFireLevel, false);
            structureDamagePerShot = mech.GetAdjustedDamage(structureDamagePerShot, weapon.WeaponCategoryValue, mech.occupiedDesignMask, lineOfFireLevel, false);
            foreach (KeyValuePair <int, float> keyValuePair in hitInfo.ConsolidateCriticalHitInfo(mech.GUID, damagePerShot))
            {
                if (keyValuePair.Key != 0 && keyValuePair.Key != 65536 && (mech.ArmorForLocation(keyValuePair.Key) <= 0f || structureDamagePerShot > 0f))
                {
                    ChassisLocations chassisLocationFromArmorLocation = MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)keyValuePair.Key);
                    if (!mech.IsLocationDestroyed(chassisLocationFromArmorLocation))
                    {
                        Traverse checkForCritT = Traverse.Create(mech).Method("CheckForCrit", new Type[] { typeof(WeaponHitInfo), typeof(ChassisLocations), typeof(Weapon) });
                        checkForCritT.GetValue(new object[] { hitInfo, chassisLocationFromArmorLocation, weapon });
                    }
                }
            }
            if (weapon.HeatDamagePerShot > 0f)
            {
                bool flag = false;
                for (int i = 0; i < hitInfo.numberOfShots; i++)
                {
                    if (hitInfo.DidShotHitTarget(mech.GUID, i) && hitInfo.ShotHitLocation(i) != 0 && hitInfo.ShotHitLocation(i) != 65536)
                    {
                        flag = true;
                        mech.AddExternalHeat(string.Format("Heat Damage from {0}", weapon.Description.Name), (int)weapon.HeatDamagePerShotAdjusted(hitInfo.hitQualities[i]));
                    }
                }
                if (flag && attackSequence != null)
                {
                    attackSequence.FlagAttackDidHeatDamage(mech.GUID);
                }
            }
            float num3 = hitInfo.ConsolidateInstability(mech.GUID, weapon.Instability(), mech.Combat.Constants.ResolutionConstants.GlancingBlowDamageMultiplier,
                                                        mech.Combat.Constants.ResolutionConstants.NormalBlowDamageMultiplier, mech.Combat.Constants.ResolutionConstants.SolidBlowDamageMultiplier);

            num3 *= mech.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier");
            num3 *= mech.EntrenchedMultiplier;
            mech.AddAbsoluteInstability(num3, StabilityChangeSource.Attack, hitInfo.attackerId);
        }
Example #13
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);
        }
Example #14
0
        public static string GetLocationHealthString(ICombatant combatant, ArmorLocation location)
        {
            string result = "";

            if (combatant.UnitType != UnitType.Mech)
            {
                return("NO MECH");
            }

            Mech m = combatant as Mech;

            Color  g             = LazySingletonBehavior <UIManager> .Instance.UIColorRefs.gold;
            Color  w             = LazySingletonBehavior <UIManager> .Instance.UIColorRefs.whiteHalf;
            string colorTagG     = $"<color=#{ColorUtility.ToHtmlStringRGBA(g)}>";
            string colorTagW     = $"<color=#{ColorUtility.ToHtmlStringRGBA(w)}>";
            string closeColorTag = "</color>";

            int currentArmor     = (int)m.GetCurrentArmor(location);
            int maxArmor         = (int)HUDMechArmorReadout.GetInitialArmorForLocation(m.MechDef, location);
            int currentStructure = Math.Max(1, ((int)m.GetCurrentStructure(MechStructureRules.GetChassisLocationFromArmorLocation(location))));
            int maxStructure     = (int)m.GetMaxStructure(MechStructureRules.GetChassisLocationFromArmorLocation(location));
            int totalCurrent     = currentArmor + currentStructure;
            int totalMax         = maxArmor + maxStructure;

            // Simple
            if (currentStructure < maxStructure || currentArmor <= 0)
            {
                result = $"{colorTagG}LOCATION HEALTH: {totalCurrent} / {totalMax}{closeColorTag}";
            }
            else
            {
                result = $"{colorTagW}LOCATION HEALTH: {totalCurrent} / {totalMax}{closeColorTag}";
            }

            // Differentiated
            //result = $"{colorTagG}STRUCTURE: {currentStructure} / {maxStructure}{closeColorTag}      {colorTagW}ARMOR: {currentArmor} / {maxArmor}{closeColorTag}";

            return(result);
        }
Example #15
0
        public void Repair(MechComponent component, bool isFloatieMessage = false)
        {
            Mech    mech    = component.parent as Mech;
            Vehicle vehicle = component.parent as Vehicle;
            Turret  turret  = component.parent as Turret;

            Log.Debug?.Write("Repair:" + component.parent.DisplayName + ":" + component.parent.GUID + ":" + component.defId + " mech:" + (mech != null ? "true" : "false") + " vehicle:" + (vehicle != null ? "true" : "false") + " turret:" + (turret != null ? "true" : "false") + "\n");
            HashSet <int> affectedISLocations    = new HashSet <int>();
            HashSet <int> affectedArmorLocations = new HashSet <int>();
            bool          armorReparied          = false;
            bool          structureReparied      = false;

            if (this.AffectInstalledLocation)
            {
                affectedISLocations.Add(component.Location);
                if (mech != null)
                {
                    ChassisLocations componentLocation = (ChassisLocations)component.Location;
                    switch (componentLocation)
                    {
                    case ChassisLocations.CenterTorso:
                        affectedArmorLocations.Add((int)ArmorLocation.CenterTorso);
                        affectedArmorLocations.Add((int)ArmorLocation.CenterTorsoRear);
                        break;

                    case ChassisLocations.RightTorso:
                        affectedArmorLocations.Add((int)ArmorLocation.RightTorso);
                        affectedArmorLocations.Add((int)ArmorLocation.RightTorsoRear);
                        break;

                    case ChassisLocations.LeftTorso:
                        affectedArmorLocations.Add((int)ArmorLocation.LeftTorso);
                        affectedArmorLocations.Add((int)ArmorLocation.LeftTorsoRear);
                        break;

                    default:
                        affectedArmorLocations.Add((int)componentLocation);
                        break;
                    }
                }
                else
                {
                    affectedArmorLocations.Add(component.Location);
                }
            }
            ;
            int stackItemUID = component.parent.Combat.StackManager.NextStackUID;

            if (mech != null)
            {
                for (int t = 0; t < this.MechStructureLocations.Length; ++t)
                {
                    affectedISLocations.Add((int)this.MechStructureLocations[t]);
                }
                for (int t = 0; t < this.MechArmorLocations.Length; ++t)
                {
                    affectedArmorLocations.Add((int)this.MechArmorLocations[t]);
                }
            }
            else
            if (vehicle != null)
            {
                for (int t = 0; t < this.VehicleLocations.Length; ++t)
                {
                    affectedISLocations.Add((int)this.VehicleLocations[t]);
                    affectedArmorLocations.Add((int)this.VehicleLocations[t]);
                }
            }
            else
            {
                for (int t = 0; t < this.BuildingLocations.Length; ++t)
                {
                    affectedISLocations.Add((int)this.BuildingLocations[t]);
                    affectedArmorLocations.Add((int)this.BuildingLocations[t]);
                }
            }
            Log.Debug?.Write(" Affected armor locations:");
            foreach (var loc in affectedArmorLocations)
            {
                Log.Debug?.Write(" " + loc);
            }
            Log.Debug?.Write(" \n");
            if (this.Armor > Core.Epsilon)
            {
                foreach (int Location in affectedArmorLocations)
                {
                    Statistic stat = component.parent.GetArmorStatisticForLocation(Location);
                    if (stat == null)
                    {
                        Log.Debug?.TWriteCritical(0, "Can't get armor stat " + new Text(component.parent.DisplayName).ToString() + " location:" + Location);
                        continue;
                    }
                    Log.Debug?.TWL(0, "turnsSinceLocationDamage:" + component.parent.turnsSinceLocationDamage(Location) + " component:" + TurnsSinceDamage);
                    if (TurnsSinceDamage >= 0)
                    {
                        if (component.parent.turnsSinceLocationDamage(Location) > TurnsSinceDamage)
                        {
                            Log.Debug?.WL(1, "damage too long ago. No reparing performed.");
                            continue;
                        }
                    }
                    float maxArmor          = stat.DefaultValue <float>();
                    float currentArmor      = stat.Value <float>();
                    int   StructureLocation = Location;
                    if (mech != null)
                    {
                        StructureLocation = (int)MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)Location);
                    }
                    currentArmor += this.Armor;
                    if (currentArmor > maxArmor)
                    {
                        currentArmor = maxArmor;
                    }
                    ;
                    float delta = currentArmor - component.parent.ArmorForLocation(Location);
                    Log.Debug?.WL(2, "location:" + Location + " maxArmor:" + maxArmor + " currentArmor:" + currentArmor + "(" + delta + ")");
                    if (delta > Core.Epsilon)
                    {
                        if (mech != null)
                        {
                            Log.Debug?.Write("  mech stat armor location:" + mech.GetStringForArmorLocation((ArmorLocation)Location) + "\n");
                            LocationDamageLevel locationDamageLevel = mech.GetLocationDamageLevel((ChassisLocations)StructureLocation);
                            if (locationDamageLevel >= LocationDamageLevel.Destroyed)
                            {
                                Log.Debug?.Write(" can't repair destroyed location\n");
                                continue;
                            }
                            armorReparied = true;
                            component.parent.StatCollection.ModifyStat <float>(component.parent.GUID, stackItemUID, mech.GetStringForArmorLocation((ArmorLocation)Location), StatCollection.StatOperation.Float_Add, delta, -1, true);
                        }
                        else
                        if (vehicle != null)
                        {
                            Log.Debug?.Write("  vehicle stat armor location:" + vehicle.GetStringForArmorLocation((VehicleChassisLocations)Location) + "\n");
                            LocationDamageLevel locationDamageLevel = vehicle.GetLocationDamageLevel((VehicleChassisLocations)StructureLocation);
                            if (locationDamageLevel >= LocationDamageLevel.Destroyed)
                            {
                                Log.Debug?.Write(" can't repair destroyed location\n");
                                continue;
                            }
                            armorReparied = true;
                            component.parent.StatCollection.ModifyStat <float>(component.parent.GUID, stackItemUID, vehicle.GetStringForArmorLocation((VehicleChassisLocations)Location), StatCollection.StatOperation.Float_Add, delta, -1, true);
                        }
                        else
                        if (turret != null)
                        {
                            Log.Debug?.Write("  turret stat armor location:" + turret.GetStringForArmorLocation((BuildingLocation)Location) + "\n");
                            LocationDamageLevel locationDamageLevel = turret.GetLocationDamageLevel((BuildingLocation)StructureLocation);
                            if (locationDamageLevel >= LocationDamageLevel.Destroyed)
                            {
                                Log.Debug?.Write(" can't repair destroyed location\n");
                                armorReparied = true;
                                continue;
                            }
                            component.parent.StatCollection.ModifyStat <float>(component.parent.GUID, stackItemUID, turret.GetStringForArmorLocation((BuildingLocation)Location), StatCollection.StatOperation.Float_Add, delta, -1, true);
                        }
                        else
                        {
                            Log.Debug?.Write("  combatant has no armor\n");
                        }
                    }
                }
            }
            Log.Debug?.Write(" Affected inner structure locations:");
            foreach (var loc in affectedISLocations)
            {
                Log.Debug?.Write(" " + loc);
            }
            Log.Debug?.Write(" \n");
            if (this.InnerStructure > Core.Epsilon)
            {
                foreach (int Location in affectedISLocations)
                {
                    float maxStructure     = component.parent.MaxStructureForLocation(Location);
                    float currentStructure = component.parent.StructureForLocation(Location);
                    if (currentStructure < Core.Epsilon)
                    {
                        Log.Debug?.Write(" can't repair locations with zero structure\n");
                        continue;
                    }
                    currentStructure += this.InnerStructure;
                    if (currentStructure > maxStructure)
                    {
                        currentStructure = maxStructure;
                    }
                    ;
                    float delta = currentStructure - component.parent.StructureForLocation(Location);
                    Log.Debug?.Write(" inner structure repair amount:" + delta + "\n");
                    if (delta > Core.Epsilon)
                    {
                        if (mech != null)
                        {
                            Log.Debug?.Write("  mech stat structure location:" + mech.GetStringForStructureLocation((ChassisLocations)Location) + "\n");
                            LocationDamageLevel locationDamageLevel = mech.GetLocationDamageLevel((ChassisLocations)Location);
                            if (locationDamageLevel >= LocationDamageLevel.Destroyed)
                            {
                                Log.Debug?.Write(" can't repair destroyed location\n");
                                continue;
                            }
                            structureReparied = true;
                            component.parent.StatCollection.ModifyStat <float>(component.parent.GUID, stackItemUID, mech.GetStringForStructureLocation((ChassisLocations)Location), StatCollection.StatOperation.Float_Add, delta, -1, true);
                        }
                        else
                        if (vehicle != null)
                        {
                            Log.Debug?.Write("  vehicle stat structure location:" + vehicle.GetStringForStructureLocation((VehicleChassisLocations)Location) + "\n");
                            LocationDamageLevel locationDamageLevel = vehicle.GetLocationDamageLevel((VehicleChassisLocations)Location);
                            if (locationDamageLevel >= LocationDamageLevel.Destroyed)
                            {
                                Log.Debug?.Write(" can't repair destroyed location\n");
                                continue;
                            }
                            component.parent.StatCollection.ModifyStat <float>(component.parent.GUID, stackItemUID, vehicle.GetStringForStructureLocation((VehicleChassisLocations)Location), StatCollection.StatOperation.Float_Add, delta, -1, true);
                        }
                        else
                        if (turret != null)
                        {
                            Log.Debug?.Write("  turret stat structure location:" + turret.GetStringForArmorLocation((BuildingLocation)Location) + "\n");
                            LocationDamageLevel locationDamageLevel = turret.GetLocationDamageLevel((BuildingLocation)Location);
                            if (locationDamageLevel == LocationDamageLevel.Destroyed)
                            {
                                Log.Debug?.Write(" can't repair destroyed location\n");
                                continue;
                            }
                            structureReparied = true;
                            component.parent.StatCollection.ModifyStat <float>(component.parent.GUID, stackItemUID, turret.GetStringForStructureLocation((BuildingLocation)Location), StatCollection.StatOperation.Float_Add, delta, -1, true);
                        }
                        else
                        {
                            Log.Debug?.Write("  other structure location:" + "Structure" + "\n");
                            structureReparied = true;
                            component.parent.StatCollection.ModifyStat <float>(component.parent.GUID, stackItemUID, "Structure", StatCollection.StatOperation.Float_Add, delta, -1, true);
                        }
                    }
                }
            }
            if ((armorReparied || structureReparied) && (isFloatieMessage))
            {
                string text = component.Description.UIName + " __/CAE.REPAIRED/__" + (armorReparied ? " __/CAE.REPAIRARMOR/__" : " ") + (structureReparied ? " __/CAE.REPAIRSTRUCTURE/__" : "");
                component.parent.Combat.MessageCenter.PublishMessage((MessageCenterMessage) new FloatieMessage(component.parent.GUID, component.parent.GUID, text, FloatieMessage.MessageNature.Buff));
            }
        }
 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));
             }
         }
 internal static ChassisLocations ToChassisLocation(this ArmorLocation armorLocation)
 {
     return(MechStructureRules.GetChassisLocationFromArmorLocation(armorLocation));
 }
 public static void LogMechDamage(Mech __instance, ArmorLocation aLoc, Weapon weapon, DamageType damageType)
 {
     try {
         if (aLoc == ArmorLocation.None || aLoc == ArmorLocation.Invalid || !IsLoggedDamage(damageType))
         {
             return;
         }
         int line = LogActorDamage(__instance.GetCurrentArmor(aLoc), __instance.GetCurrentStructure(MechStructureRules.GetChassisLocationFromArmorLocation(aLoc)));
         if (line >= 0 && Settings.CritFollowDamageTransfer && hitMap != null)
         {
             string newKey = GetHitKey(weapon.uid, aLoc, __instance.GUID);
             if (DebugLog)
             {
                 Verbo("Log damage transfer {0} = {1}", newKey, line);
             }
             hitMap[newKey] = line;
         }
     }                 catch (Exception ex) { Error(ex); }
 }
    internal static ArmorLocation ToArmorLocation(this ChassisLocations chassisLocation, bool isRearArmor)
    {
        var armorLocation = MechStructureRules.GetArmorFromChassisLocation(chassisLocation);

        return(armorLocation & (isRearArmor ? ArmorLocationRear : ~ArmorLocationRear));
    }
 public static void RecordMechDamage(Mech __instance, ArmorLocation aLoc, float totalDamage)
 {
     if (aLoc == ArmorLocation.None || aLoc == ArmorLocation.Invalid)
     {
         return;
     }
     RecordUnitDamage(aLoc.ToString(), totalDamage,
                      __instance.GetCurrentArmor(aLoc), __instance.GetCurrentStructure(MechStructureRules.GetChassisLocationFromArmorLocation(aLoc)));
 }
Example #21
0
        // ============ Zombie ============

        public static void FixZombieMech(Mech __instance, ref float totalDamage, ArmorLocation aLoc)
        {
            try {
                if (aLoc == ArmorLocation.None || aLoc == ArmorLocation.Invalid)
                {
                    return;
                }
                float armour = __instance.GetCurrentArmor(aLoc);
                if (armour >= totalDamage)
                {
                    return;
                }
                KillZombie("mech", __instance.DisplayName, armour + __instance.GetCurrentStructure(MechStructureRules.GetChassisLocationFromArmorLocation(aLoc)), ref totalDamage);
            }                 catch (Exception ex) { Error(ex); }
        }
        public static Func <AttackModifier> GetRangedModifierFactor(string factorId)
        {
            switch (factorId)
            {
            case "armmounted":
                return(() => new AttackModifier("ARM MOUNTED", Hit.GetSelfArmMountedModifier(AttackWeapon)));

            case "range": // Depended by ShowNeutralRangeInBreakdown
                return(() => {
                    Weapon w = AttackWeapon;
                    float range = Vector3.Distance(AttackPos, TargetPos), modifier = Hit.GetRangeModifierForDist(w, range);
                    AttackModifier result = new AttackModifier(modifier);
                    if (range < w.MinRange)
                    {
                        return result.SetName($"MIN RANGE (<{(int)w.MinRange}m)");
                    }
                    if (range < w.ShortRange)
                    {
                        return result.SetName("SHORT RANGE" + SmartRange(w.MinRange, range, w.ShortRange));
                    }
                    if (range < w.MediumRange)
                    {
                        return result.SetName("MED RANGE" + SmartRange(w.ShortRange, range, w.MediumRange));
                    }
                    if (range < w.LongRange)
                    {
                        return result.SetName("LONG RANGE" + SmartRange(w.MediumRange, range, w.LongRange));
                    }
                    if (range < w.MaxRange)
                    {
                        return result.SetName("MAX RANGE" + SmartRange(w.LongRange, range, w.MaxRange));
                    }
                    return result.SetName($"OUT OF RANGE (>{(int)w.MaxRange}m)");
                });

            case "height":
                return(() => new AttackModifier("HEIGHT", Hit.GetHeightModifier(AttackPos.y, TargetPos.y)));

            case "indirect":
                return(() => new AttackModifier("INDIRECT FIRE", Hit.GetIndirectModifier(Attacker, LineOfFire < LineOfFireLevel.LOFObstructed && AttackWeapon.IndirectFireCapable)));

            case "locationdamage":
                return(() => {
                    if (Attacker is Mech mech)
                    {
                        Text location = Mech.GetAbbreviatedChassisLocation((ChassisLocations)AttackWeapon.Location);
                        return new AttackModifier($"{location} DAMAGED", MechStructureRules.GetToHitModifierLocationDamage(mech, AttackWeapon));
                    }
                    else
                    {
                        return new AttackModifier("CHASSIS DAMAGED", Hit.GetSelfDamageModifier(Attacker, AttackWeapon));
                    }
                });

            case "obstruction":
                return(() => new AttackModifier("OBSTRUCTED", Hit.GetCoverModifier(Attacker, Target, LineOfFire)));

            case "precision":
                return(() => new AttackModifier(CombatConstants.CombatUIConstants.MoraleAttackDescription.Name, Hit.GetMoraleAttackModifier(Target, IsMoraleAttack)));

            case "refire":
                return(() => new AttackModifier("RECOIL", Hit.GetRefireModifier(AttackWeapon)));

            case "targetevasion":
                return(() => new AttackModifier("TARGET MOVED", Hit.GetTargetSpeedModifier(Target, AttackWeapon)));

            case "targetprone":
                return(() => new AttackModifier("TARGET PRONE", Hit.GetTargetProneModifier(Target, false)));

            case "targetshutdown":
                return(() => new AttackModifier("TARGET SHUTDOWN", Hit.GetTargetShutdownModifier(Target, false)));

            case "sensorlock":
                return(() => new AttackModifier("SENSOR LOCK", Hit.GetTargetDirectFireModifier(Target, LineOfFire < LineOfFireLevel.LOFObstructed && AttackWeapon.IndirectFireCapable)));

            case "weapondamage":
                return(() => {
                    AttackModifier result = new AttackModifier("WEAPON DAMAGED");
                    if (!(Attacker is Mech mech))
                    {
                        return result;
                    }
                    return result.SetValue(MechStructureRules.GetToHitModifierWeaponDamage(mech, AttackWeapon));
                });
            }
            return(null);
        }
        static void evaluateWeaponAttackOnMech(float expectedDamage, Weapon w, ref DamageExpectationRecord damageExpectationRecord, Vector3 attackerPosition, Mech targetMech, Vector3 targetPosition, Quaternion targetRotation)
        {
            // use hit table to figure out where this will go
            Dictionary <ArmorLocation, float> locations = GetLocationDictionary(attackerPosition, targetMech, targetPosition, targetRotation);

            foreach (KeyValuePair <ArmorLocation, float> locKVP in locations)
            {
                ArmorLocation loc         = locKVP.Key;
                float         probability = locKVP.Value;

                DamageExpectationRecord locRecord = new DamageExpectationRecord();
                damageExpectationRecord.AddChildRecord(probability, locRecord);

                float existingArmor          = targetMech.ArmorForLocation((int)loc);
                float armorThatWillBeRemoved = Mathf.Min(existingArmor, expectedDamage);
                float damageRemaining        = expectedDamage - existingArmor;
                locRecord.AddArmorDamage(armorThatWillBeRemoved, loc);

                ChassisLocations sLoc = MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)loc);

                // there's a chance this hit will be a critical hit
                if (!targetMech.IsLocationDestroyed(sLoc))
                {
                    float critChance = targetMech.Combat.CritChance.GetCritChance(targetMech, sLoc, w);

                    if (critChance > 0)
                    {
                        DamageExpectationRecord critRecord = new DamageExpectationRecord();
                        locRecord.AddChildRecord(critChance, critRecord);

                        // iterate over components, apply one point of damage to each location.

                        Dictionary <ComponentLocator, float> componentDict = getComponentDictionary(targetMech, sLoc);

                        float probOfHittingAmmo = 0.0f;
                        foreach (KeyValuePair <ComponentLocator, float> componentKVP in componentDict)
                        {
                            ComponentLocator compLoc              = componentKVP.Key;
                            MechComponent    component            = compLoc.GetComponent();
                            float            componentProbability = componentKVP.Value;

                            DamageExpectationRecord componentRecord = new DamageExpectationRecord();
                            critRecord.AddChildRecord(componentProbability, componentRecord);

                            componentRecord.AddComponentDamage(1.0f, compLoc);

                            // if this component is ammo, there's a chance we could lose this location and all child locations
                            if (component.componentType == ComponentType.AmmunitionBox)
                            {
                                AmmunitionBox abComponent   = component as AmmunitionBox;
                                int           remainingAmmo = abComponent.CurrentAmmo;
                                int           capacity      = abComponent.ammunitionBoxDef.Capacity;
                                float         percentage    = ((float)remainingAmmo) / ((float)capacity);

                                if (percentage > 0.5f)
                                {
                                    probOfHittingAmmo += componentProbability;
                                }
                            }
                        }
                        if (probOfHittingAmmo > 0.0f)
                        {
                            DamageExpectationRecord ammoBlownRecord = new DamageExpectationRecord();
                            locRecord.AddChildRecord(probOfHittingAmmo, ammoBlownRecord);

                            foreach (KeyValuePair <ComponentLocator, float> componentKVP in componentDict)
                            {
                                ComponentLocator compLoc = componentKVP.Key;
                                ammoBlownRecord.AddComponentDamage(2.0f, compLoc);
                            }
                        }
                    }
                }

                if (damageRemaining > 0)
                {
                    // some goes in to the structure
                    float currentStructure = targetMech.GetCurrentStructure(sLoc);

                    float structureDamage      = Mathf.Min(damageRemaining, currentStructure);
                    float damageAfterStructure = damageRemaining - structureDamage;

                    locRecord.AddStructureDamage(structureDamage, sLoc);

                    if (damageAfterStructure > 0)
                    {
                        // some hits a component
                        Dictionary <ComponentLocator, float> componentDict = getComponentDictionary(targetMech, sLoc);

                        float probOfHittingAmmo = 0.0f;

                        foreach (KeyValuePair <ComponentLocator, float> componentKVP in componentDict)
                        {
                            ComponentLocator compLoc              = componentKVP.Key;
                            MechComponent    component            = compLoc.GetComponent();
                            float            componentProbability = componentKVP.Value;

                            DamageExpectationRecord componentRecord = new DamageExpectationRecord();
                            locRecord.AddChildRecord(componentProbability, componentRecord);

                            componentRecord.AddComponentDamage(1.0f, compLoc);

                            // if this component is ammo, there's a chance we could lose this location and all child locations
                            if (component.componentType == ComponentType.AmmunitionBox)
                            {
                                AmmunitionBox abComponent   = component as AmmunitionBox;
                                int           remainingAmmo = abComponent.CurrentAmmo;
                                int           capacity      = abComponent.ammunitionBoxDef.Capacity;
                                float         percentage    = ((float)remainingAmmo) / ((float)capacity);

                                if (percentage > 0.5f)
                                {
                                    probOfHittingAmmo += componentProbability;
                                }
                            }
                        }

                        if (probOfHittingAmmo > 0)
                        {
                            DamageExpectationRecord ammoBlownRecord = new DamageExpectationRecord();
                            locRecord.AddChildRecord(probOfHittingAmmo, ammoBlownRecord);

                            foreach (KeyValuePair <ComponentLocator, float> componentKVP in componentDict)
                            {
                                ComponentLocator compLoc = componentKVP.Key;
                                ammoBlownRecord.AddComponentDamage(2.0f, compLoc);
                            }
                        }
                    }
                }
            }
        }
Example #24
0
        public static Statistic GetStructureStatisticForLocation(this AbstractActor unit, int Location)
        {
            Mech    mech    = unit as Mech;
            Vehicle vehicle = unit as Vehicle;
            Turret  turret  = unit as Turret;

            if (mech != null)
            {
                return(unit.StatCollection.GetStatistic(mech.GetStringForStructureLocation(MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)Location))));
            }
            if (vehicle != null)
            {
                return(unit.StatCollection.GetStatistic(vehicle.GetStringForStructureLocation((VehicleChassisLocations)Location)));
            }
            if (turret != null)
            {
                return(unit.StatCollection.GetStatistic(turret.GetStringForStructureLocation((BuildingLocation)Location)));
            }
            return(null);
        }