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); } }
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); }
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. } } } } }
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); }
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 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)); }
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)); }
// 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); }
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); } }
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); }
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); }
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); }
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)); } }
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); } } } } } }
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); } }
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))); }
internal static ChassisLocations ToChassisLocation(this ArmorLocation armorLocation) { return(MechStructureRules.GetChassisLocationFromArmorLocation(armorLocation)); }
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)); } }
// ============ 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); } }