// Evaluates whether a given mech needs any structure repaired public static bool CheckStructureDamage(MechDef mech) { // Default to not requesting any structure repair bool mechNeedsRepair = false; // Using the repair priority for loop here as it is faster and simpler than foreach'ing over ChassisLocations and filtering out ones that don't have armor for (int index = 0; index < Globals.repairPriorities.Count; index++) { // Set current ChassisLocation ChassisLocations thisLoc = Globals.repairPriorities.ElementAt(index).Value; // Get current mech location loadout from the looped chassis definitions LocationLoadoutDef thisLocLoadout = mech.GetLocationLoadoutDef(thisLoc); // Friendly name for this location string thisLocName = thisLoc.ToString(); // Work out difference of armor lost for each location - default to 0 int structureDifference = 0; float currentStructure = thisLocLoadout.CurrentInternalStructure; float definedStructure = mech.GetChassisLocationDef(thisLoc).InternalStructure; structureDifference = (int)Mathf.Abs(currentStructure - definedStructure); // If any difference betwen the location's current and assigned armor is detected, flag this mech for armor repair if (structureDifference > 0) { Logger.LogDebug(mech.Name + " requires structure repair based on damage to: " + thisLocName); mechNeedsRepair = true; break; // Stop evaluating other locations once a repair requirement is determined } } return(mechNeedsRepair); }
internal static void Postfix( ref LocationLoadoutDef ___loadout, ref MechLabPanel ___mechLab, MechComponentDef newComponentDef, ref bool __result) { try { if (!__result) { return; } var chassisDef = ___mechLab?.activeMechDef?.Chassis; if (chassisDef == null) { return; } var location = ___loadout.Location; if (location == ChassisLocations.None) { return; } __result = OmniSlotsFeature.Shared.ValidateAddSimple(chassisDef, location, newComponentDef); } catch (Exception e) { Control.Logger.Error.Log(e); } }
private static void AddFillersToSlot(List <Transform> slots, LocationLoadoutDef loadout, MechLabLocationWidget instance) { List <Image> images = new List <Image>(); foreach (var slot in slots) { var go = new GameObject(); var rect = go.AddComponent <RectTransform>(); rect.pivot = new Vector2(0.5f, 0.5f); rect.anchorMin = new Vector2(0, 0); rect.anchorMax = new Vector2(1, 1); rect.anchoredPosition = Vector2.zero; rect.sizeDelta = new Vector2(-6, -6); go.AddComponent <CanvasRenderer>(); var image = go.AddComponent <Image>(); image.color = Color.red; images.Add(image); rect.SetParent(slot, false); } var loc = new LocationInfo(instance, images, loadout); ReservedSlots.RegisterLocation(loc); }
public LocationInfo(MechLabLocationWidget widget, List <Image> images, LocationLoadoutDef location) { this.location = location; this.FillerImages = images; this.loadout = widget; var traverse = Traverse.Create(loadout); MaxSlots = traverse.Field("maxSlots").GetValue <int>(); used_slots = traverse.Field("usedSlots"); }
static void Postfix(MechLabLocationWidget __instance, LocationLoadoutDef loadout) { LocationDef locationDef = ReflectionUtils.GetChassisLocationDef(__instance); __instance.currentArmor = Math.Min(loadout.CurrentArmor, ArmorRules.MaxFrontArmor(locationDef, __instance.loadout, 0)); __instance.currentRearArmor = Math.Min(loadout.CurrentRearArmor, ArmorRules.MaxRearArmor(locationDef, __instance.loadout, __instance.currentArmor)); __instance.maxArmor = ArmorRules.MaxFrontArmor(locationDef, __instance.loadout, __instance.currentRearArmor); __instance.maxRearArmor = ArmorRules.MaxRearArmor(locationDef, __instance.loadout, __instance.currentArmor); __instance.ModifyArmor(false, 0, false); }
public static float MaxFrontArmor(LocationDef locationDef, LocationLoadoutDef loadout, float currentRearArmor) { if (locationDef.Location == ChassisLocations.Head && Control.settings.HeadMaxArmorOverride != null) { return(Control.settings.HeadMaxArmorOverride.Value); } else { float baseStructure = Control.settings.UseCurrentStructure ? loadout.CurrentInternalStructure : locationDef.InternalStructure; float maxFront = baseStructure * Control.settings.StructureFrontLoadCapacityFactor; float maxTotal = baseStructure * Control.settings.StructureTotalLoadCapacityFactor - currentRearArmor; return(Math.Max(0, Math.Min(maxFront, maxTotal))); } }
public static void Postfix(MechLabLocationWidget __instance, int ___maxSlots, ref LocationLoadoutDef loadout) { try { var widget = __instance; var widgetLayout = new WidgetLayout(widget); MechLabSlotsFixer.FixSlots(widgetLayout, ___maxSlots); DynamicSlotsFeature.PrepareWidget(widgetLayout); AdjustMechLabLocationNaming(widget, loadout.Location); } catch (Exception e) { Control.Logger.Error.Log(e); } }
public static float GetMechArmor(this MechDef m) { float r = 0; foreach (ChassisLocations l in Locations) { LocationLoadoutDef v = m.GetLocationLoadoutDef(l); r += v.AssignedArmor; } foreach (ChassisLocations l in RearArmoredLocs) { LocationLoadoutDef v = m.GetLocationLoadoutDef(l); r += v.AssignedRearArmor; } return(r); }
public static float MaxRearArmor(LocationDef locationDef, LocationLoadoutDef loadout, float currentFrontArmor) { float baseStructure = Control.settings.UseCurrentStructure ? loadout.CurrentInternalStructure : locationDef.InternalStructure; float maxRear; if (locationDef.Location == ChassisLocations.CenterTorso || locationDef.Location == ChassisLocations.LeftTorso || locationDef.Location == ChassisLocations.RightTorso) { maxRear = baseStructure * Control.settings.StructureRearLoadCapacityFactor; } else { maxRear = 0; } float maxTotal = baseStructure * Control.settings.StructureTotalLoadCapacityFactor - currentFrontArmor; return(Math.Max(0, Math.Min(maxRear, maxTotal))); }
// Evaluates whether a given mech needs any armor repaired public static bool CheckArmorDamage(MechDef mech) { // Default to not requesting any armor repair bool mechNeedsArmor = false; // Using the repair priority for loop here as it is faster and simpler than foreach'ing over ChassisLocations and filtering out ones that don't have armor for (int index = 0; index < Globals.repairPriorities.Count; index++) { // Set current ChassisLocation ChassisLocations thisLoc = Globals.repairPriorities.ElementAt(index).Value; // Get current mech location loadout from the looped chassis definitions LocationLoadoutDef thisLocLoadout = mech.GetLocationLoadoutDef(thisLoc); // Friendly name for this location string thisLocName = thisLoc.ToString(); // Work out difference of armor lost for each location - default to 0 int armorDifference = 0; // Consider rear armour in difference calculation if this is a RT, CT or LT if (thisLocLoadout == mech.CenterTorso || thisLocLoadout == mech.RightTorso || thisLocLoadout == mech.LeftTorso) { armorDifference = (int)Mathf.Abs(thisLocLoadout.CurrentArmor - thisLocLoadout.AssignedArmor) + (int)Mathf.Abs(thisLocLoadout.CurrentRearArmor - thisLocLoadout.AssignedRearArmor); } else { armorDifference = (int)Mathf.Abs(thisLocLoadout.CurrentArmor - thisLocLoadout.AssignedArmor); } // If any difference betwen the location's current and assigned armor is detected, flag this mech for armor repair if (armorDifference > 0) { Logger.LogDebug(mech.Name + " requires armor repair based on armor loss from: " + thisLocName); mechNeedsArmor = true; break; // Stop evaluating other locations once a repair requirement is determined on any location (no point checking further) } } if (!mechNeedsArmor) { Logger.LogInfo(mech.Name + " does not require armor repairs."); } return(mechNeedsArmor); }
public static bool Prefix(SimGameState __instance, WorkOrderEntry_RepairMechStructure order) { if (order.IsMechLabComplete) { return(true); } else { MechDef mechByID = __instance.GetMechByID(order.MechLabParent.MechID); LocationLoadoutDef locationLoadoutDef = mechByID.GetLocationLoadoutDef(order.Location); locationLoadoutDef.CurrentInternalStructure = mechByID.GetChassisLocationDef(order.Location).InternalStructure; // Original method resets currentArmor to assignedArmor here for some reason! Removed them from this override Logger.LogDebug("ALERT: Intercepted armor reset from ML_RepairMech and prevented it."); mechByID.RefreshBattleValue(); order.SetMechLabComplete(true); return(false); // Prevent original method from firing } }
public void ModifyMech(MechDef mDef, SimGameState s, UpgradeList ulist, ref float _, List <string[]> changedAmmoTypes, MechDef fromData) { float tonnage = 0; float max = 0; MechStatisticsRules.CalculateTonnage(mDef, ref tonnage, ref max); float armorfact = mDef.GetMechArmorPointFactor(); BTRandomMechComponentUpgrader_Init.Log.Log($"correcting tonnage 2: armor (each armor point costs {armorfact} t)"); while (tonnage + armorfact <= mDef.Chassis.Tonnage) { bool assOne = false; foreach (ChassisLocations c in RMCU_Helper.Locations) { if (tonnage + armorfact >= mDef.Chassis.Tonnage) { break; } LocationLoadoutDef l = mDef.GetLocationLoadoutDef(c); if (l.AssignedArmor >= mDef.GetChassisLocationDef(c).MaxArmor) { continue; } l.AssignedArmor += 1; l.CurrentArmor += 1; tonnage += armorfact; BTRandomMechComponentUpgrader_Init.Log.Log($"increased {c} armor to {l.AssignedArmor}"); assOne = true; } foreach (ChassisLocations c in RMCU_Helper.RearArmoredLocs) { if (tonnage + armorfact >= mDef.Chassis.Tonnage) { break; } LocationLoadoutDef l = mDef.GetLocationLoadoutDef(c); if (l.AssignedRearArmor >= mDef.GetChassisLocationDef(c).MaxRearArmor) { continue; } l.AssignedRearArmor += 1; l.CurrentRearArmor += 1; tonnage += armorfact; BTRandomMechComponentUpgrader_Init.Log.Log($"increased {c} rear armor to {l.AssignedRearArmor}"); assOne = true; } if (!assOne) { BTRandomMechComponentUpgrader_Init.Log.Log("no free armor location found!"); break; } } while (tonnage > mDef.Chassis.Tonnage) { bool assOne = false; foreach (ChassisLocations c in RMCU_Helper.Locations) { if (tonnage <= mDef.Chassis.Tonnage) { break; } LocationLoadoutDef l = mDef.GetLocationLoadoutDef(c); if (l.AssignedArmor <= 1) { continue; } l.AssignedArmor -= 1; l.CurrentArmor -= 1; tonnage -= armorfact; BTRandomMechComponentUpgrader_Init.Log.Log($"decreased {c} armor to {l.AssignedArmor}"); assOne = true; } foreach (ChassisLocations c in RMCU_Helper.RearArmoredLocs) { if (tonnage <= mDef.Chassis.Tonnage) { break; } LocationLoadoutDef l = mDef.GetLocationLoadoutDef(c); if (l.AssignedRearArmor <= 1) { continue; } l.AssignedRearArmor -= 1; l.CurrentRearArmor -= 1; tonnage -= armorfact; BTRandomMechComponentUpgrader_Init.Log.Log($"decreased {c} rear armor to {l.AssignedRearArmor}"); assOne = true; } if (!assOne) { BTRandomMechComponentUpgrader_Init.Log.Log("no free armor location found!"); break; } } BTRandomMechComponentUpgrader_Init.Log.Log($"final weight: {tonnage}/{mDef.Chassis.Tonnage}"); }
public static void Postfix(MechLabLocationWidget __instance, int ___maxSlots, LocationLoadoutDef ___loadout) { try { // we can't reduce to zero if (___maxSlots < 1) { return; } var widgetLayout = new WidgetLayout(__instance, ___loadout.Location); if (widgetLayout.layout_slots == null) { return; } ModifySlotCount(widgetLayout, ___maxSlots); AddFillersToSlots(widgetLayout); } catch (Exception e) { Control.mod.Logger.LogError(e); } }
// @ToDo: Somehow implement that manual Remove/Add of components AFTER this method-call calculates work-orders correctly public static void SetEquipment(this MechLabPanel mechLabPanel, List <InventoryItemElement_Simple> equipment, MechLabLocationWidget locationWidget, LocationLoadoutDef loadout) { locationWidget.loadout = loadout; // Nah. This kills fixed equipment! //locationWidget.ClearInventory(); for (int i = 0; i < equipment.Count; i++) { if (equipment[i].ComponentRef.MountedLocation == loadout.Location) { Logger.Debug("[Extensions.SetEquipment] Component: " + equipment[i].ComponentRef.ComponentDefID + " gets installed at: " + loadout.Location.ToString() + " and was fetched from (simulated): " + equipment[i].Origin); // NOTE that creation of items (vs. simulate-grabbing the real ones from inventory) will confuse the work-order-entries // @ToDo: Try setting "copyComponentRef" to true and test somewhen MechLabItemSlotElement mechLabItemSlotElement = mechLabPanel.CreateMechComponentItem(equipment[i].ComponentRef, false, loadout.Location, locationWidget, null); Traverse.Create(mechLabItemSlotElement).Field("originalDropParentType").SetValue(equipment[i].Origin); if (mechLabItemSlotElement != null) { List <MechLabItemSlotElement> ___localInventory = (List <MechLabItemSlotElement>)AccessTools.Field(typeof(MechLabLocationWidget), "localInventory").GetValue(locationWidget); ___localInventory.Add(mechLabItemSlotElement); int ___usedSlots = (int)AccessTools.Field(typeof(MechLabLocationWidget), "usedSlots").GetValue(locationWidget); ___usedSlots += equipment[i].ComponentRef.Def.InventorySize; Transform ___inventoryParent = (Transform)AccessTools.Field(typeof(MechLabLocationWidget), "inventoryParent").GetValue(locationWidget); mechLabItemSlotElement.gameObject.transform.SetParent(___inventoryParent, false); mechLabItemSlotElement.gameObject.transform.localScale = Vector3.one; ReflectionHelper.InvokePrivateMethode(locationWidget, "RefreshMechComponentData", new object[] { mechLabItemSlotElement, false }); locationWidget.RefreshHardpointData(); // Add WorkOrderEntry WorkOrderEntry_InstallComponent subEntry = locationWidget.Sim.CreateComponentInstallWorkOrder(mechLabPanel.baseWorkOrder.MechID, equipment[i].ComponentRef, loadout.Location, ChassisLocations.None); mechLabPanel.baseWorkOrder.AddSubEntry(subEntry); } } } //mechLabPanel.ValidateLoadout(false); }
public static void SetArmor(this MechLabPanel mechLabPanel, MechLabLocationWidget locationWidget, LocationLoadoutDef loadout) { locationWidget.currentArmor = loadout.AssignedArmor; bool locationHasRearArmor = (bool)AccessTools.Field(typeof(MechLabLocationWidget), "useRearArmor").GetValue(locationWidget); if (locationHasRearArmor) { locationWidget.currentRearArmor = loadout.AssignedRearArmor; } // Create work-order, otherwise Mech is invalid after it is actually changed // Check if the values actually changed beforehand (Vanilla does actually NOT check this) int armorDiff = (int)Mathf.Abs(locationWidget.currentArmor - locationWidget.originalArmor) + (int)Mathf.Abs(locationWidget.currentRearArmor - locationWidget.originalRearArmor); if (armorDiff != 0) { WorkOrderEntry_ModifyMechArmor subEntry = locationWidget.Sim.CreateMechArmorModifyWorkOrder(mechLabPanel.activeMechDef.GUID, locationWidget.loadout.Location, armorDiff, (int)locationWidget.currentArmor, (int)locationWidget.currentRearArmor); mechLabPanel.baseWorkOrder.AddSubEntry(subEntry); } //mechLabPanel.ValidateLoadout(false); ReflectionHelper.InvokePrivateMethode(locationWidget, "RefreshArmor", null); }
public static void Postfix(MechLabLocationWidget __instance, int ___maxSlots, LocationLoadoutDef ___loadout) { try { // we can't reduce to zero if (___maxSlots < 1) { return; } var widget = __instance.transform; var layout = widget.GetChild("layout_slots"); if (layout == null) { return; } var slots = layout.GetChildren() .Where(x => x.name.StartsWith("slot")) .OrderByDescending(x => x.localPosition.y) .ToList(); //foreach (var slot in slots) //{ // Control.mod.Logger.LogDebug(slot.name); //} var changedSlotCount = ___maxSlots - slots.Count; if (changedSlotCount == 0) { return; } var templateSlot = slots[0]; // add missing for (var i = slots.Count; i < ___maxSlots; i++) { var newSlot = UnityEngine.Object.Instantiate(templateSlot, layout); newSlot.localPosition = new Vector3(0, -(1 + i * SlotHeight), 0); newSlot.SetSiblingIndex(templateSlot.GetSiblingIndex()); newSlot.name = "slot (" + i + ")"; } // remove abundant for (var i = ___maxSlots; i < slots.Count; i++) { UnityEngine.Object.Destroy(slots[i].gameObject); } var changedHeight = changedSlotCount * SlotHeight; widget.AdjustHeight(changedHeight); layout.AdjustHeight(changedHeight); } catch (Exception e) { Control.mod.Logger.LogError(e); } }
public static void Postfix(MechLabLocationWidget __instance, int ___maxSlots, LocationLoadoutDef ___loadout) { try { // we can't reduce to zero if (___maxSlots < 1) { return; } var widgetLayout = new WidgetLayout(__instance); if (widgetLayout.layout_slots == null) { return; } if (__instance == (__instance.parentDropTarget as MechLabPanel).centerTorsoWidget) { ___maxSlots -= MechLabSlotsFeature.settings.MechLabGeneralSlots; } ModifySlotCount(widgetLayout, ___maxSlots); AddFillersToSlots(widgetLayout, ___loadout.Location); } catch (Exception e) { Control.mod.Logger.LogError(e); } }
public static bool Prefix(MechBayPanel __instance, MechBayMechUnitElement mechElement) { Logger.LogDebug("We are repairing, yes?"); Logger.Log("We are repairing, yes?"); if (!Core.Settings.RepairRearm) { return(true); } var sim = UnityGameInstance.BattleTechGame.Simulation; MechDef mechDef = mechElement.MechDef; WorkOrderEntry_MechLab workOrderEntry_MechLab = __instance.Sim.GetWorkOrderEntryForMech(mechDef); bool flag = false; for (int i = 0; i < mechDef.Inventory.Length; i++) { MechComponentRef mechComponentRef = mechDef.Inventory[i]; if (mechComponentRef.DamageLevel != ComponentDamageLevel.Functional && mechComponentRef.DamageLevel != ComponentDamageLevel.Installing && !MechValidationRules.MechComponentUnderMaintenance(mechComponentRef, MechValidationLevel.MechLab, workOrderEntry_MechLab)) { flag = true; break; } } if (!mechDef.IsDamaged && !flag) { return(false); } List <ChassisLocations> list = new List <ChassisLocations>(); __instance.pendingWorkOrderNew = false; __instance.pendingWorkOrderEntriesToAdd.Clear(); if (workOrderEntry_MechLab == null) { workOrderEntry_MechLab = new WorkOrderEntry_MechLab(WorkOrderType.MechLabGeneric, "MechLab-BaseWorkOrder", Strings.T("Modify 'Mech - {0}", new object[] { mechDef.Description.Name }), mechDef.GUID, 0, Strings.T(__instance.Sim.Constants.Story.GeneralMechWorkOrderCompletedText, new object[] { mechDef.Description.Name })); workOrderEntry_MechLab.SetMechDef(mechDef); __instance.pendingWorkOrderNew = true; } __instance.pendingWorkOrder = workOrderEntry_MechLab; if (!MechValidationRules.MechStructureUnderMaintenance(ChassisLocations.Head, MechValidationLevel.MechLab, workOrderEntry_MechLab) && mechDef.Head.CurrentInternalStructure < mechDef.Chassis.Head.InternalStructure) { list.Add(ChassisLocations.Head); } if (!MechValidationRules.MechStructureUnderMaintenance(ChassisLocations.CenterTorso, MechValidationLevel.MechLab, workOrderEntry_MechLab) && mechDef.CenterTorso.CurrentInternalStructure < mechDef.Chassis.CenterTorso.InternalStructure) { list.Add(ChassisLocations.CenterTorso); } if (!MechValidationRules.MechStructureUnderMaintenance(ChassisLocations.LeftTorso, MechValidationLevel.MechLab, workOrderEntry_MechLab) && mechDef.LeftTorso.CurrentInternalStructure < mechDef.Chassis.LeftTorso.InternalStructure) { list.Add(ChassisLocations.LeftTorso); } if (!MechValidationRules.MechStructureUnderMaintenance(ChassisLocations.RightTorso, MechValidationLevel.MechLab, workOrderEntry_MechLab) && mechDef.RightTorso.CurrentInternalStructure < mechDef.Chassis.RightTorso.InternalStructure) { list.Add(ChassisLocations.RightTorso); } if (!MechValidationRules.MechStructureUnderMaintenance(ChassisLocations.LeftLeg, MechValidationLevel.MechLab, workOrderEntry_MechLab) && mechDef.LeftLeg.CurrentInternalStructure < mechDef.Chassis.LeftLeg.InternalStructure) { list.Add(ChassisLocations.LeftLeg); } if (!MechValidationRules.MechStructureUnderMaintenance(ChassisLocations.RightLeg, MechValidationLevel.MechLab, workOrderEntry_MechLab) && mechDef.RightLeg.CurrentInternalStructure < mechDef.Chassis.RightLeg.InternalStructure) { list.Add(ChassisLocations.RightLeg); } if (!MechValidationRules.MechStructureUnderMaintenance(ChassisLocations.LeftArm, MechValidationLevel.MechLab, workOrderEntry_MechLab) && mechDef.LeftArm.CurrentInternalStructure < mechDef.Chassis.LeftArm.InternalStructure) { list.Add(ChassisLocations.LeftArm); } if (!MechValidationRules.MechStructureUnderMaintenance(ChassisLocations.RightArm, MechValidationLevel.MechLab, workOrderEntry_MechLab) && mechDef.RightArm.CurrentInternalStructure < mechDef.Chassis.RightArm.InternalStructure) { list.Add(ChassisLocations.RightArm); } if (list.Count < 1 && !flag) { GenericPopupBuilder.Create("Repair Already Ordered", string.Format("A repair order has already been queued for " + "{0}", mechDef.Name)).AddFader(new UIColorRef?(LazySingletonBehavior <UIManager> .Instance.UILookAndColorConstants.PopupBackfill), 0f, true).Render(); __instance.OnRepairAllCancelled(); return(false); } int num = 0; int num2 = 0; for (int j = 0; j < list.Count; j++) { LocationDef chassisLocationDef = mechDef.GetChassisLocationDef(list[j]); LocationLoadoutDef locationLoadoutDef = mechDef.GetLocationLoadoutDef(list[j]); int structureCount = Mathf.RoundToInt(Mathf.Max(0f, chassisLocationDef.InternalStructure - locationLoadoutDef.CurrentInternalStructure)); WorkOrderEntry_RepairMechStructure workOrderEntry_RepairMechStructure = __instance.Sim.CreateMechRepairWorkOrder(mechDef.GUID, list[j], structureCount); __instance.pendingWorkOrderEntriesToAdd.Add(workOrderEntry_RepairMechStructure); num += workOrderEntry_RepairMechStructure.GetCost(); num2 += workOrderEntry_RepairMechStructure.GetCBillCost(); } StringBuilder stringBuilder = new StringBuilder(); int num3 = 0; for (int k = 0; k < mechDef.Inventory.Length; k++) { MechComponentRef mechComponentRef2 = mechDef.Inventory[k]; if (string.IsNullOrEmpty(mechComponentRef2.SimGameUID)) { mechComponentRef2.SetSimGameUID(__instance.Sim.GenerateSimGameUID()); } if (mechComponentRef2.DamageLevel == ComponentDamageLevel.Destroyed) { if (num3 < 1) { stringBuilder.Append("\n\nThe following components have been Destroyed. If you continue with the Repair, " + "replacement Components will NOT be installed. If you want to replace them with identical or " + "different Components, you must Refit the 'Mech.\n\n"); } if (num3 < 5) { stringBuilder.Append(mechComponentRef2.MountedLocation.ToString()); stringBuilder.Append(": "); stringBuilder.Append(mechComponentRef2.Def.Description.Name); stringBuilder.Append("\n"); } num3++; WorkOrderEntry_InstallComponent workOrderEntry_InstallComponent = sim.CreateComponentInstallWorkOrder(__instance.selectedMech.MechDef.GUID, mechComponentRef2, ChassisLocations.None, mechComponentRef2.MountedLocation); __instance.pendingWorkOrderEntriesToAdd.Insert(0, workOrderEntry_InstallComponent); num += workOrderEntry_InstallComponent.GetCost(); num2 += workOrderEntry_InstallComponent.GetCBillCost(); } else if (mechComponentRef2.DamageLevel != ComponentDamageLevel.Functional && mechComponentRef2.DamageLevel != ComponentDamageLevel.Installing) { WorkOrderEntry_RepairComponent workOrderEntry_RepairComponent = __instance.Sim.CreateComponentRepairWorkOrder(mechComponentRef2, true); __instance.pendingWorkOrderEntriesToAdd.Add(workOrderEntry_RepairComponent); num += workOrderEntry_RepairComponent.GetCost(); num2 += workOrderEntry_RepairComponent.GetCBillCost(); } } foreach (var foo in __instance.pendingWorkOrderEntriesToAdd) { Logger.LogDebug(foo.ID); } Logger.LogDebug("Armor Repair Section"); float armorLoss = 1; bool armorTag = false; foreach (var tag in mechDef.MechTags) { Logger.LogDebug(tag); if (tag.StartsWith("XLRPArmor")) { armorTag = true; string[] parsedString = tag.Split('_'); armorLoss = float.Parse(parsedString[1]); } Logger.LogDebug(armorLoss.ToString()); } if (armorTag) { if (!mechDef.MechTags.Contains("XLRP_Armor_Repairing")) { mechDef.MechTags.Add("XLRP_Armor_Repairing"); } int brokenArmor = (int)((1 - armorLoss) * mechDef.MechDefAssignedArmor); int frontArmor = (int)(mechDef.MechDefAssignedArmor - mechDef.CenterTorso.AssignedRearArmor - mechDef.LeftTorso.AssignedRearArmor - mechDef.RightTorso.AssignedRearArmor); int rearArmor = (int)(mechDef.CenterTorso.AssignedRearArmor + mechDef.LeftTorso.AssignedRearArmor + mechDef.RightTorso.AssignedRearArmor); Logger.LogDebug($"brokenAmor: {brokenArmor}, frontArmor: {frontArmor}, rearArmor: {rearArmor}"); WorkOrderEntry_ModifyMechArmor subEntry = sim.CreateMechArmorModifyWorkOrder(__instance.selectedMech.MechDef.GUID, ChassisLocations.All, brokenArmor, frontArmor, rearArmor); __instance.pendingWorkOrderEntriesToAdd.Add(subEntry); num += subEntry.GetCost(); num2 += subEntry.GetCBillCost(); } num = Mathf.Max(1, Mathf.CeilToInt((float)num / (float)__instance.Sim.MechTechSkill)); if (num3 > 5) { stringBuilder.Append(Strings.T("...\nAnd {0} additional destroyed components.\n", new object[] { num3 - 5 })); } string body = Strings.T("Repairing {0} will cost {1:n0} C-Bills and take {2} Days.{3}\n\nProceed?", new object[] { mechDef.Name, num2, num, stringBuilder.ToString() }); GenericPopupBuilder.Create("Repair 'Mech?", body).AddButton("Cancel", new Action(__instance.OnRepairAllCancelled), true, null). AddButton("Repair", new Action(__instance.OnRepairAllAccepted), true, null).AddFader(new UIColorRef?(LazySingletonBehavior <UIManager> .Instance.UILookAndColorConstants.PopupBackfill), 0f, true).Render(); return(false); }
public static bool Prefix(SimGameState __instance, MechDef mech) { try { // Start of analysing a mech for armor repair Logger.LogInfo("Analysing Mech: " + mech.Name); Logger.LogInfo("============================================"); // Base generic MechLab WO for a mech that requires armor or structure repair - each individual locational subentry WO has to be added to this base WO later WorkOrderEntry_MechLab newMechLabWorkOrder = null; /* STRUCTURE DAMAGE CHECKS * ------------------------ * Check if the given mech needs any structure repaired and that EnableStructureRepair is true in the mod settings * */ if (ArmorRepair.ModSettings.EnableStructureRepair) { if (Helpers.CheckStructureDamage(mech)) { Logger.LogDebug("SimGameConstant: StructureRepairTechPoints: " + __instance.Constants.MechLab.StructureRepairTechPoints); Logger.LogDebug("SimGameConstant: StructureRepairCost: " + __instance.Constants.MechLab.StructureRepairCost); // Loop over the ChassisLocations for repair in their highest -> lowest priority order from the dictionary defined in Helpers for (int index = 0; index < Globals.repairPriorities.Count; index++) { // Set current looped ChassisLocation ChassisLocations thisLoc = Globals.repairPriorities.ElementAt(index).Value; // Get current mech's loadout definition from the looped chassis location LocationLoadoutDef thisLocLoadout = mech.GetLocationLoadoutDef(thisLoc); // Friendly name for this location string thisLocName = thisLoc.ToString(); Logger.LogDebug("Analysing location: " + thisLocName); // Check if a new base MechLab order needs to be created or not if (newMechLabWorkOrder == null) { // Create new base work order of the generic MechLab type if it doesn't already exist newMechLabWorkOrder = Helpers.CreateBaseMechLabOrder(__instance, mech); } float currentStructure = thisLocLoadout.CurrentInternalStructure; float definedStructure = mech.GetChassisLocationDef(thisLoc).InternalStructure; // Only create work orders for repairing structure if this location has taken damage in combat if (currentStructure != definedStructure) { // Work out difference of structure lost for each location - default to 0 int structureDifference = 0; structureDifference = (int)Mathf.Abs(currentStructure - definedStructure); Logger.LogInfo("Total structure difference for " + thisLocName + " is " + structureDifference); Logger.LogInfo("Creating MechRepair work order entry for " + thisLocName); Logger.LogDebug("Calling CreateMechRepairWorkOrder with params - GUID: " + mech.GUID.ToString() + " | Location: " + thisLocName + " | structureDifference: " + structureDifference ); WorkOrderEntry_RepairMechStructure newRepairWorkOrder = __instance.CreateMechRepairWorkOrder( mech.GUID, thisLocLoadout.Location, structureDifference ); Logger.LogDebug("Adding WO subentry to repair missing " + thisLocName + " structure."); newMechLabWorkOrder.AddSubEntry(newRepairWorkOrder); } else { Logger.LogDebug("Structure repair not required for: " + thisLocName); } } } } /* COMPONENT DAMAGE CHECKS * ----------------------- * Check if the given mech needs any critted components repaired * * NOTE: Not yet working. Repair components are added to work order but not actually repaired after WO completes. Noticed there is another queue involved on SGS.WorkOrderComponents we need to debug. * Currently throws "SimGameState [ERROR] ML_RepairComponent MechBay - RepairComponent - SGRef_490 had an invalid mechComponentID Ammo_AmmunitionBox_Generic_AC5, skipping" in SimGame logger on WO completion. * if (Helpers.CheckDamagedComponents(mech)) * { * for (int index = 0; index < mech.Inventory.Length; index++) * { * MechComponentRef mechComponentRef = mech.Inventory[index]; * * // Penalized = Critted Component * if (mechComponentRef.DamageLevel == ComponentDamageLevel.Penalized) * { * // Check if a new base MechLab order needs to be created or not * if (newMechLabWorkOrder == null) * { * // Create new base work order of the generic MechLab type if it doesn't already exist * newMechLabWorkOrder = Helpers.CreateBaseMechLabOrder(__instance, mech); * } * * // Create a new component repair work order for this component * Logger.LogInfo("Creating Component Repair work order entry for " + mechComponentRef.ComponentDefID); * WorkOrderEntry_RepairComponent newComponentRepairOrder = __instance.CreateComponentRepairWorkOrder(mechComponentRef, false); * * // Attach as a child to the base Mech Lab order. * Logger.LogDebug("Adding WO subentry to repair component " + mechComponentRef.ComponentDefID); * newMechLabWorkOrder.AddSubEntry(newComponentRepairOrder); * } * } * } */ /* ARMOR DAMAGE CHECKS * ------------------- * Check if the given mech needs any structure repaired * */ if (Helpers.CheckArmorDamage(mech)) { Logger.LogDebug("SimGameConstant: ArmorInstallTechPoints: " + __instance.Constants.MechLab.ArmorInstallTechPoints); Logger.LogDebug("SimGameConstant: ArmorInstallCost: " + __instance.Constants.MechLab.ArmorInstallCost); // Loop over the ChassisLocations for repair in their highest -> lowest priority order from the dictionary defined in Helpers for (int index = 0; index < Globals.repairPriorities.Count; index++) { // Set current ChassisLocation ChassisLocations thisLoc = Globals.repairPriorities.ElementAt(index).Value; // Get current mech's loadout from the looped chassis location LocationLoadoutDef thisLocLoadout = mech.GetLocationLoadoutDef(thisLoc); // Friendly name for this location string thisLocName = thisLoc.ToString(); Logger.LogDebug("Analysing location: " + thisLocName); // Check if a new base MechLab order needs to be created if (newMechLabWorkOrder == null) { // Create new base work order of the generic MechLab type if it doesn't already exist newMechLabWorkOrder = Helpers.CreateBaseMechLabOrder(__instance, mech); } // Work out difference of armor lost for each location - default to 0 int armorDifference = 0; // Consider rear armour in difference calculation if this is a RT, CT or LT if (thisLocLoadout == mech.CenterTorso || thisLocLoadout == mech.RightTorso || thisLocLoadout == mech.LeftTorso) { Logger.LogDebug("Location also has rear armor."); armorDifference = (int)Mathf.Abs(thisLocLoadout.CurrentArmor - thisLocLoadout.AssignedArmor) + (int)Mathf.Abs(thisLocLoadout.CurrentRearArmor - thisLocLoadout.AssignedRearArmor); } else { armorDifference = (int)Mathf.Abs(thisLocLoadout.CurrentArmor - thisLocLoadout.AssignedArmor); } // Only create work orders for repairing armor if this location has taken armor damage in combat if (armorDifference != 0) { Logger.LogInfo("Total armor difference for " + thisLocName + " is " + armorDifference); Logger.LogInfo("Creating ModifyMechArmor work order entry for " + thisLocName); Logger.LogDebug("Calling ModifyMechArmor WO with params - GUID: " + mech.GUID.ToString() + " | Location: " + thisLocName + " | armorDifference: " + armorDifference + " | AssignedArmor: " + thisLocLoadout.AssignedArmor + " | AssignedRearArmor: " + thisLocLoadout.AssignedRearArmor ); WorkOrderEntry_ModifyMechArmor newArmorWorkOrder = __instance.CreateMechArmorModifyWorkOrder( mech.GUID, thisLocLoadout.Location, armorDifference, (int)(thisLocLoadout.AssignedArmor), (int)(thisLocLoadout.AssignedRearArmor) ); /* IMPORTANT! * This has turned out to be required as CurrentArmor appears to be reset to AssignedArmor from somewhere unknown in the game after battle * So if we don't reset AssignedArmor now, player can cancel the work order to get a free armor reset anyway! * * NOTE: CeilToInt (or similar rounding) is vital to prevent fractions of armor from causing Mech tonnage / validation issues for the player */ Logger.LogDebug("Forcing assignment of Assigned Armor: " + thisLocLoadout.AssignedArmor + " To Current Armor (CeilToInt): " + Mathf.CeilToInt(thisLocLoadout.CurrentArmor)); thisLocLoadout.AssignedArmor = Mathf.CeilToInt(thisLocLoadout.CurrentArmor); thisLocLoadout.AssignedRearArmor = Mathf.CeilToInt(thisLocLoadout.CurrentRearArmor); Logger.LogInfo("Adding WO subentry to install missing " + thisLocName + " armor."); newMechLabWorkOrder.AddSubEntry(newArmorWorkOrder); } else { Logger.LogDebug("Armor repair not required for: " + thisLocName); } } } /* WORK ORDER SUBMISSION * --------------------- * Submit the complete work order for the mech, which will include any repair armor / structure subentries for each location * */ if (newMechLabWorkOrder != null) { if (newMechLabWorkOrder.SubEntryCount > 0) { // Submit work order to our temporary queue for internal processing Helpers.SubmitTempWorkOrder( __instance, newMechLabWorkOrder, mech ); } else { Logger.LogInfo(mech.Name + " did not require repairs."); } } // Lifted from original RestoreMechPostCombat method - resets any non-functional mech components back to functional foreach (MechComponentRef mechComponentRef in mech.Inventory) { if (mechComponentRef.DamageLevel == ComponentDamageLevel.NonFunctional) { Logger.LogDebug("Resetting non-functional mech component: " + mechComponentRef.ToString()); mechComponentRef.DamageLevel = ComponentDamageLevel.Functional; } } return(false); // Finally, prevent firing the original method } catch (Exception ex) { Logger.LogError(ex); return(true); // Allow original method to fire if there is an exception } }