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); }
// 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); }
private static bool ProcessMechArmorStructureRatioForLocation( MechDef mechDef, ChassisLocations location, Dictionary <MechValidationType, List <Text> > errorMessages = null, bool applyChanges = false) { var mechLocationDef = mechDef.GetLocationLoadoutDef(location); var chassisLocationDef = mechDef.Chassis.GetLocationDef(location); var armor = Mathf.Max(mechLocationDef.AssignedArmor, 0); var armorRear = Mathf.Max(mechLocationDef.AssignedRearArmor, 0); var structure = chassisLocationDef.InternalStructure; var ratio = location == ChassisLocations.Head ? 3 : 2; var total = armor + armorRear; var totalMax = ratio * structure; if (total <= totalMax) { return(true); } if (applyChanges) { // Control.mod.Logger.LogDebug($"structure={structure} location={location} totalMax={totalMax}"); // Control.mod.Logger.LogDebug($"before AssignedArmor={mechLocationDef.AssignedArmor} AssignedRearArmor={mechLocationDef.AssignedRearArmor}"); if ((location & ChassisLocations.Torso) != 0) { mechLocationDef.AssignedArmor = PrecisionUtils.RoundUp((totalMax * 2 / 3), 5); mechLocationDef.CurrentArmor = mechLocationDef.AssignedArmor; mechLocationDef.AssignedRearArmor = PrecisionUtils.RoundDown((totalMax * 1 / 3), 5); mechLocationDef.CurrentRearArmor = mechLocationDef.AssignedRearArmor; } else { mechLocationDef.AssignedArmor = totalMax; mechLocationDef.CurrentArmor = mechLocationDef.AssignedArmor; } Control.mod.Logger.LogDebug($"set AssignedArmor={mechLocationDef.AssignedArmor} AssignedRearArmor={mechLocationDef.AssignedRearArmor} on location={location}"); } //Control.mod.Logger.LogDebug($"{Mech.GetAbbreviatedChassisLocation(location)} armor={armor} armorRear={armorRear} structure={structure}"); if (errorMessages != null) { var locationName = Mech.GetLongChassisLocation(location); errorMessages[MechValidationType.InvalidHardpoints].Add(new Text($"ARMOR {locationName}: Armor can only be {ratio} times more than structure.")); } return(false); }
// 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); }
private static bool IsStructureDamaged(ref float percent, Mech mech, MechDef mechDef, ChassisLocations location) { if (float.IsNaN(percent)) { float hp, maxHp; if (mech != null) { hp = mech.GetCurrentStructure(location); maxHp = mech.GetMaxStructure(location); } else // if ( mechDef != null ) { hp = mechDef.GetLocationLoadoutDef(location).CurrentInternalStructure; maxHp = mechDef.GetChassisLocationDef(location).InternalStructure; } percent = hp / maxHp; } return(percent < 1f); }
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 } }
static bool Prefix(Contract __instance, List <UnitResult> enemyMechs, List <VehicleDef> enemyVehicles, List <UnitResult> lostUnits, bool logResults = false) { try { Settings settings = Helper.LoadSettings(); if (__instance.BattleTechGame.Simulation == null) { return(false); } ReflectionHelper.SetPrivateField(__instance, "finalPotentialSalvage", new List <SalvageDef>()); ReflectionHelper.InvokePrivateMethode(__instance, "set_SalvagedChassis", new object[] { new List <SalvageDef>() }); ReflectionHelper.InvokePrivateMethode(__instance, "set_LostMechs", new object[] { new List <MechDef>() }); ReflectionHelper.InvokePrivateMethode(__instance, "set_SalvageResults", new object[] { new List <SalvageDef>() }); SimGameState simulation = __instance.BattleTechGame.Simulation; SimGameConstants constants = simulation.Constants; for (int i = 0; i < lostUnits.Count; i++) { MechDef mech = lostUnits[i].mech; Pilot pilot = lostUnits[i].pilot; float num = simulation.NetworkRandom.Float(0f, 1f); float ejectRecoveryBonus = 0; float incapacitatedRecoveryBonus = 0; bool notDestroyed = !mech.IsLocationDestroyed(ChassisLocations.CenterTorso) && !mech.IsLocationDestroyed(ChassisLocations.Head) && (!mech.IsLocationDestroyed(ChassisLocations.LeftLeg) && !mech.IsLocationDestroyed(ChassisLocations.RightLeg)); if (pilot.HasEjected) { ejectRecoveryBonus = settings.ejectRecoveryBonus; } else if (mech.IsLocationDestroyed(ChassisLocations.Head) || (pilot.IsIncapacitated && notDestroyed)) { incapacitatedRecoveryBonus = settings.incapacitatedRecoveryBonus; } bool flag = num <= constants.Salvage.DestroyedMechRecoveryChance + ejectRecoveryBonus + incapacitatedRecoveryBonus; // keep mech if the roll is good enough, or if CT + head + legs are intact and the pilot isn't incapacitated if (flag || (notDestroyed && !pilot.IsIncapacitated)) { lostUnits[i].mechLost = false; } else { lostUnits[i].mechLost = true; float mechparts = simulation.Constants.Story.DefaultMechPartMax; if (mech.IsLocationDestroyed(ChassisLocations.CenterTorso)) { mechparts = settings.centerTorsoSalvageValue; } else { if (mech.IsLocationDestroyed(ChassisLocations.LeftArm)) { mechparts -= (simulation.Constants.Story.DefaultMechPartMax / 5); } if (mech.IsLocationDestroyed(ChassisLocations.RightArm)) { mechparts -= (simulation.Constants.Story.DefaultMechPartMax / 5); } if (mech.IsLocationDestroyed(ChassisLocations.LeftLeg)) { mechparts -= (simulation.Constants.Story.DefaultMechPartMax / 5); } if (mech.IsLocationDestroyed(ChassisLocations.RightLeg)) { mechparts -= (simulation.Constants.Story.DefaultMechPartMax / 5); } } SalvageDef def = (SalvageDef)ReflectionHelper.InvokePrivateMethode(__instance, "CreateMechPart", new object[] { constants, mech }); if (settings.ownMechsForFree) { for (int s = 0; s < Mathf.RoundToInt(mechparts); s++) { __instance.SalvageResults.Add(def); } } else { List <SalvageDef> finalPotentialSalvage = (List <SalvageDef>)ReflectionHelper.GetPrivateField(__instance, "finalPotentialSalvage"); ReflectionHelper.InvokePrivateMethode(__instance, "CreateAndAddMechPart", new object[] { constants, mech, Mathf.RoundToInt(mechparts), finalPotentialSalvage }); } if (settings.ownMechsForFree) { foreach (MechComponentRef mechComponentRef in mech.Inventory) { if (!mech.IsLocationDestroyed(mechComponentRef.MountedLocation) && mechComponentRef.DamageLevel != ComponentDamageLevel.Destroyed) { ReflectionHelper.InvokePrivateMethode(__instance, "AddToFinalSalvage", new object[] { new SalvageDef { MechComponentDef = mechComponentRef.Def, Description = new DescriptionDef(mechComponentRef.Def.Description), RewardID = __instance.GenerateRewardUID(), Type = SalvageDef.SalvageType.COMPONENT, ComponentType = mechComponentRef.Def.ComponentType, Damaged = false, Count = 1 } }); } } } else { foreach (MechComponentRef mechComponentRef in mech.Inventory) { if (!mech.IsLocationDestroyed(mechComponentRef.MountedLocation) && mechComponentRef.DamageLevel != ComponentDamageLevel.Destroyed) { List <SalvageDef> finalPotentialSalvage = (List <SalvageDef>)ReflectionHelper.GetPrivateField(__instance, "finalPotentialSalvage"); ReflectionHelper.InvokePrivateMethode(__instance, "AddMechComponentToSalvage", new object[] { finalPotentialSalvage, mechComponentRef.Def, ComponentDamageLevel.Functional, false, constants, simulation.NetworkRandom, true }); } } } } } int k = 0; while (k < enemyMechs.Count) { MechDef mech2 = enemyMechs[k].mech; Pilot pilot = enemyMechs[k].pilot; SalvageDef salvageDef = null; bool flag2 = false; bool flag3 = false; List <SalvageDef> finalPotentialSalvage = (List <SalvageDef>)ReflectionHelper.GetPrivateField(__instance, "finalPotentialSalvage"); if (pilot.IsIncapacitated || mech2.IsDestroyed || mech2.Inventory.Any(cref => cref.Def != null && cref.Def.CriticalComponent && cref.DamageLevel == ComponentDamageLevel.Destroyed)) { float mechparts = simulation.Constants.Story.DefaultMechPartMax; if (mech2.IsLocationDestroyed(ChassisLocations.CenterTorso)) { mechparts = settings.centerTorsoSalvageValue; } else { if (mech2.IsLocationDestroyed(ChassisLocations.LeftArm)) { mechparts -= (simulation.Constants.Story.DefaultMechPartMax / 5); } if (mech2.IsLocationDestroyed(ChassisLocations.RightArm)) { mechparts -= (simulation.Constants.Story.DefaultMechPartMax / 5); } if (mech2.IsLocationDestroyed(ChassisLocations.LeftLeg)) { mechparts -= (simulation.Constants.Story.DefaultMechPartMax / 5); } if (mech2.IsLocationDestroyed(ChassisLocations.RightLeg)) { mechparts -= (simulation.Constants.Story.DefaultMechPartMax / 5); } } ReflectionHelper.InvokePrivateMethode(__instance, "CreateAndAddMechPart", new object[] { constants, mech2, Mathf.RoundToInt(mechparts), finalPotentialSalvage }); goto IL_2E4; } IL_4AB: k++; continue; IL_2E4: foreach (MechComponentRef mechComponentRef2 in mech2.Inventory) { if (!mech2.IsLocationDestroyed(mechComponentRef2.MountedLocation) && mechComponentRef2.DamageLevel != ComponentDamageLevel.Destroyed) { ReflectionHelper.InvokePrivateMethode(__instance, "AddMechComponentToSalvage", new object[] { finalPotentialSalvage, mechComponentRef2.Def, ComponentDamageLevel.Functional, false, constants, simulation.NetworkRandom, true }); } } if (flag3) { salvageDef = new SalvageDef(); salvageDef.Type = SalvageDef.SalvageType.CHASSIS; salvageDef.Description = new DescriptionDef(mech2.Chassis.Description); salvageDef.Count = 1; IEnumerator enumerator = Enum.GetValues(typeof(ChassisLocations)).GetEnumerator(); try { while (enumerator.MoveNext()) { object obj = enumerator.Current; ChassisLocations chassisLocations = (ChassisLocations)obj; if (chassisLocations != ChassisLocations.None && chassisLocations != ChassisLocations.All && chassisLocations != ChassisLocations.Arms && chassisLocations != ChassisLocations.Legs && chassisLocations != ChassisLocations.Torso && chassisLocations != ChassisLocations.MainBody) { salvageDef.ChassisLocations.Add(chassisLocations); salvageDef.ChassisStructure.Add(mech2.GetLocationLoadoutDef(chassisLocations).CurrentInternalStructure); } } } finally { IDisposable disposable; if ((disposable = (enumerator as IDisposable)) != null) { disposable.Dispose(); } } if (flag2) { for (int m = 0; m < salvageDef.ChassisLocations.Count; m++) { List <float> chassisStructure; int index; (chassisStructure = salvageDef.ChassisStructure)[index = m] = chassisStructure[index] / 2f; } } salvageDef.Weight = constants.Salvage.DefaultChassisWeight; __instance.SalvagedChassis.Add(salvageDef); goto IL_4AB; } goto IL_4AB; } for (int n = 0; n < enemyVehicles.Count; n++) { VehicleDef vehicleDef = enemyVehicles[n]; List <SalvageDef> finalPotentialSalvage = (List <SalvageDef>)ReflectionHelper.GetPrivateField(__instance, "finalPotentialSalvage"); foreach (VehicleComponentRef vehicleComponentRef in vehicleDef.Inventory) { ReflectionHelper.InvokePrivateMethode(__instance, "AddMechComponentToSalvage", new object[] { finalPotentialSalvage, vehicleComponentRef.Def, ComponentDamageLevel.Functional, false, constants, simulation.NetworkRandom, true }); } } int num2 = __instance.SalvagePotential; float num3 = constants.Salvage.VictorySalvageChance; float num4 = constants.Salvage.VictorySalvageLostPerMechDestroyed; if (__instance.State == Contract.ContractState.Failed) { num3 = constants.Salvage.DefeatSalvageChance; num4 = constants.Salvage.DefeatSalvageLostPerMechDestroyed; } else if (__instance.State == Contract.ContractState.Retreated) { num3 = constants.Salvage.RetreatSalvageChance; num4 = constants.Salvage.RetreatSalvageLostPerMechDestroyed; } float num5 = num3; float num6 = (float)num2 * __instance.PercentageContractSalvage; if (num2 > 0) { num6 += (float)constants.Finances.ContractFloorSalvageBonus; } num3 = Mathf.Max(0f, num5 - num4 * (float)lostUnits.Count); int num7 = Mathf.FloorToInt(num6 * num3); if (num2 > 0) { num2 += constants.Finances.ContractFloorSalvageBonus; } ReflectionHelper.InvokePrivateMethode(__instance, "set_FinalSalvageCount", new object[] { num7 }); ReflectionHelper.InvokePrivateMethode(__instance, "set_FinalPrioritySalvageCount", new object[] { Mathf.FloorToInt((float)num7 * constants.Salvage.PrioritySalvageModifier) }); return(false); } catch (Exception e) { Logger.LogError(e); return(false); } }
public static void ApplyLoadout(this MechLabPanel mechLabPanel, string mechDefId) { try { // Check first if (!mechLabPanel.Sim.DataManager.Exists(BattleTechResourceType.MechDef, mechDefId)) { GenericPopupBuilder .Create("Apply Loadout failed", "The requested MechDef " + mechDefId + " was not found") .AddButton("Confirm", null, true, null) .AddFader(new UIColorRef?(LazySingletonBehavior <UIManager> .Instance.UILookAndColorConstants.PopupBackfill), 0f, true) .SetAlwaysOnTop() .SetOnClose(delegate { // Nothing }) .Render(); // Abort! return; } MechDef activeMechDef = mechLabPanel.activeMechDef; MechDef requestedMechDef = new MechDef(mechLabPanel.Sim.DataManager.MechDefs.Get(mechDefId), null, true); // Check second List <string> errorDescriptions = new List <string>(); if (!mechLabPanel.CanApplyLoadout(requestedMechDef, out errorDescriptions)) { string popupTitle = "Apply Loadout failed"; //string popupBody = "The following problems were encountered:" + Environment.NewLine; string popupBody = ""; foreach (string errorDescription in errorDescriptions) { popupBody += errorDescription + Environment.NewLine; } GenericPopupBuilder .Create(popupTitle, popupBody) .AddButton("Confirm", null, true, null) .AddFader(new UIColorRef?(LazySingletonBehavior <UIManager> .Instance.UILookAndColorConstants.PopupBackfill), 0f, true) .SetAlwaysOnTop() .SetOnClose(delegate { // Nothing }) .Render(); // Abort! return; } // Checks done // Hard cleanup upfront mechLabPanel.OnRevertMech(); // Get data MechLabInventoryWidget inventoryWidget = (MechLabInventoryWidget)AccessTools.Field(typeof(MechLabPanel), "inventoryWidget").GetValue(mechLabPanel); MechLabDismountWidget dismountWidget = (MechLabDismountWidget)AccessTools.Field(typeof(MechLabPanel), "dismountWidget").GetValue(mechLabPanel); MechLabMechInfoWidget mechInfoWidget = (MechLabMechInfoWidget)AccessTools.Field(typeof(MechLabPanel), "mechInfoWidget").GetValue(mechLabPanel); HBS_InputField mechNickname = (HBS_InputField)AccessTools.Field(typeof(MechLabMechInfoWidget), "mechNickname").GetValue(mechInfoWidget); List <MechComponentRef> dropshipInventory = mechLabPanel.Sim.GetAllInventoryItemDefs(); List <MechComponentRef> storageInventory = mechLabPanel.storageInventory; List <MechComponentRef> activeMechInventory = mechLabPanel.activeMechInventory; MechComponentRef[] requestedMechComponentsArray = (MechComponentRef[])AccessTools.Field(typeof(MechDef), "inventory").GetValue(requestedMechDef); List <MechComponentRef> requestedMechComponents = requestedMechComponentsArray.ToList(); // Remove fixed equipment as it will be ignored from dismounting et all for (int i = requestedMechComponents.Count - 1; i >= 0; i--) { if (requestedMechComponents[i].IsFixed) { Logger.Debug("[Extensions.ResetToStock] FOUND AND WILL REMOVE FIXED EQUIPMENT: " + requestedMechComponents[i].ComponentDefID); requestedMechComponents.RemoveAt(i); } } // This puts the current equipment into dismountWidget and also clears the Mechs inventory // NOTE that fixed equipment will stay where it is -> must be removed from requestedComponents manually! mechLabPanel.OnStripEquipment(); // Collect items from dismountWidget and/or inventoryWidget List <MechComponentRef> requestedMechComponentsRequired = requestedMechComponents.ToList(); //List<MechLabItemSlotElement> activeMechDismountedItems = new List<MechLabItemSlotElement>(dismountWidget.localInventory); List <MechLabItemSlotElement> activeMechDismountedItems = dismountWidget.localInventory; //List<InventoryItemElement_NotListView> localInventoryItems = new List<InventoryItemElement_NotListView>(inventoryWidget.localInventory); List <InventoryItemElement_NotListView> localInventoryItems = inventoryWidget.localInventory; List <MechLabItemSlotElement> itemsCollectedFromDismount = new List <MechLabItemSlotElement>(); List <InventoryItemElement_NotListView> itemsCollectedFromInventory = new List <InventoryItemElement_NotListView>(); // CHECK foreach (MechComponentRef comp in requestedMechComponentsRequired) { Logger.Debug("[Extensions.ResetToStock] INIT requestedMechComponentsRequired: " + comp.ComponentDefID); } // Check for required items in dismountWidget first, remove/add from/to applicable Lists // @ToDo: Put in method for (int i = requestedMechComponentsRequired.Count - 1; i >= 0; i--) { bool found = false; for (int j = activeMechDismountedItems.Count - 1; j >= 0; j--) { if (requestedMechComponentsRequired[i].ComponentDefID == activeMechDismountedItems[j].ComponentRef.ComponentDefID) { Logger.Debug("[Extensions.ResetToStock] FOUND in activeMechDismountedItems: " + requestedMechComponentsRequired[i].ComponentDefID); found = true; requestedMechComponentsRequired.RemoveAt(i); itemsCollectedFromDismount.Add(activeMechDismountedItems[j]); // Remove visually // Do not forget to refresh the widget MechLabItemSlotElement mechLabItemSlotElement = activeMechDismountedItems[j]; mechLabItemSlotElement.gameObject.transform.SetParent(null, false); mechLabPanel.dataManager.PoolGameObject(MechLabPanel.MECHCOMPONENT_ITEM_PREFAB, mechLabItemSlotElement.gameObject); // Remove data AFTERWARDS too activeMechDismountedItems.RemoveAt(j); break; } } if (!found) { Logger.Debug("[Extensions.ResetToStock] NOT FOUND in activeMechDismountedItems: " + requestedMechComponentsRequired[i].ComponentDefID); } } // Refresh UI ReflectionHelper.InvokePrivateMethode(dismountWidget, "RefreshComponentCountText", null); // CHECK foreach (MechLabItemSlotElement item in itemsCollectedFromDismount) { Logger.Debug("[Extensions.ResetToStock] itemsCollectedFromDismount: " + item.ComponentRef.ComponentDefID + ", MountedLocation: " + item.MountedLocation + ", DropParent: " + item.DropParent); } // Check for REMAINING required items in inventoryWidget, remove/add from/to applicable Lists // NEEDS conversion of remaining components to inventory items via custom type List <InventoryItemElement_Simple> requestedMechItemsRequired = Utilities.ComponentsToInventoryItems(requestedMechComponentsRequired, true); List <InventoryItemElement_Simple> missingItems = new List <InventoryItemElement_Simple>(); bool itemsAvailableInInventory = mechLabPanel.ItemsAvailableInInventory(requestedMechItemsRequired, localInventoryItems, out missingItems); Logger.Debug("[Extensions.ResetToStock] itemsAvailableInInventory: " + itemsAvailableInInventory); if (itemsAvailableInInventory) { itemsCollectedFromInventory = mechLabPanel.PullItemsFromInventory(requestedMechItemsRequired, localInventoryItems); // Clear required components list requestedMechComponentsRequired.Clear(); } else { // Hard exit, SHOULD NEVER END UP HERE! Logger.Debug("[Extensions.ResetToStock] MISSING ITEMS. ABORTING. YOU SHOULD NEVER SEE THIS!"); mechLabPanel.OnRevertMech(); return; } // CHECK foreach (InventoryItemElement_NotListView item in itemsCollectedFromInventory) { Logger.Debug("[Extensions.ResetToStock] itemsCollectedFromInventory: " + item.ComponentRef.ComponentDefID + ", MountedLocation: " + item.MountedLocation + ", DropParent: " + item.DropParent); } // At this point inventoryWidget.localInventory AND dismountWidget.localInventory already have the potentially reusable components REMOVED // So, in "SetEquipment" they must be SPAWNED otherwise they are lost forever // Helper Dictionary Dictionary <ChassisLocations, MechLabLocationWidget> LocationHandler = new Dictionary <ChassisLocations, MechLabLocationWidget>(); LocationHandler.Add(ChassisLocations.Head, mechLabPanel.headWidget); LocationHandler.Add(ChassisLocations.CenterTorso, mechLabPanel.centerTorsoWidget); LocationHandler.Add(ChassisLocations.LeftTorso, mechLabPanel.leftTorsoWidget); LocationHandler.Add(ChassisLocations.RightTorso, mechLabPanel.rightTorsoWidget); LocationHandler.Add(ChassisLocations.LeftArm, mechLabPanel.leftArmWidget); LocationHandler.Add(ChassisLocations.RightArm, mechLabPanel.rightArmWidget); LocationHandler.Add(ChassisLocations.LeftLeg, mechLabPanel.leftLegWidget); LocationHandler.Add(ChassisLocations.RightLeg, mechLabPanel.rightLegWidget); // Prepare custom equipment with info about desired origin beforehand List <InventoryItemElement_Simple> requestedEquipment = new List <InventoryItemElement_Simple>(); List <MechLabItemSlotElement> dismountedItems = itemsCollectedFromDismount.ToList(); foreach (MechComponentRef requestedItem in requestedMechComponents) { InventoryItemElement_Simple requestedInventoryItem = new InventoryItemElement_Simple(); requestedInventoryItem.ComponentRef = requestedItem; requestedInventoryItem.Origin = MechLabDropTargetType.InventoryList; for (int i = dismountedItems.Count - 1; i >= 0; i--) { if (requestedItem.ComponentDefID == dismountedItems[i].ComponentRef.ComponentDefID) { requestedInventoryItem.Origin = MechLabDropTargetType.Dismount; dismountedItems.RemoveAt(i); break; } } requestedEquipment.Add(requestedInventoryItem); } // CHECK foreach (MechComponentRef item in requestedMechComponents) { Logger.Debug("[Extensions.ResetToStock] baseMechComponents: " + item.ComponentDefID); } foreach (InventoryItemElement_Simple item in requestedEquipment) { Logger.Debug("[Extensions.ResetToStock] requestedEquipment: " + item.ComponentRef.ComponentDefID + ", Origin: " + item.Origin); } // Set inventory including a hint to where the components were taken from // Example manual call: mechLabPanel.SetEquipment(requestedEquipment, mechLabPanel.centerTorsoWidget, requestedMechDef.GetLocationLoadoutDef(ChassisLocations.CenterTorso)); foreach (KeyValuePair <ChassisLocations, MechLabLocationWidget> LocationPair in LocationHandler) { mechLabPanel.SetEquipment(requestedEquipment, LocationPair.Value, requestedMechDef.GetLocationLoadoutDef(LocationPair.Key)); mechLabPanel.SetArmor(LocationPair.Value, requestedMechDef.GetLocationLoadoutDef(LocationPair.Key)); } // Refresh main inventory mechLabPanel.activeMechInventory = new List <MechComponentRef>(requestedMechDef.Inventory); //ReflectionHelper.InvokePrivateMethode(mechLabPanel.activeMechDef, "InsertFixedEquipmentIntoInventory", null); // Better as it calls RefreshInventory()? -> No, Tonnage is not adjusted... need to look into it somewhen //mechLabPanel.activeMechDef.SetInventory(requestedMechDef.Inventory); // Update dependent widgets (also calls CalculateCBillValue() -> CalculateSimGameWorkOrderCost() -> PruneWorkOrder()) mechInfoWidget.RefreshInfo(); // Mark as modified Traverse.Create(mechLabPanel).Field("Modified").SetValue(true); GameObject modifiedIcon = (GameObject)AccessTools.Field(typeof(MechLabPanel), "modifiedIcon").GetValue(mechLabPanel); modifiedIcon.SetActive(mechLabPanel.Modified); // Validate mechLabPanel.ValidateLoadout(true); ReflectionHelper.InvokePrivateMethode(mechLabPanel, "RefreshInventorySelectability", null); // Set Nickname mechNickname.SetText(requestedMechDef.Description.Name); // @ToDo: Inform user about what components were installed from where } catch (Exception e) { Logger.Error(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); }
private static DumperDataEntry FillMech(MechDef d, int parts, int maxparts, int storage, int active, int sma_parts) { DumperDataEntry r = new DumperDataEntry(); r.DataTxt = new string[9]; r.DataTxt[0] = ((storage + active) > 0 ? "+" : "-") + d.Chassis.Tonnage + "t " + TryLoc(d.Chassis.Description.UIName) + " " + TryLoc(d.Chassis.VariantName); r.DataTxt[1] = TryLoc(d.Chassis.StockRole) + ""; int bal = 0; int en = 0; int mis = 0; int sup = 0; foreach (ChassisLocations c in AllChassisLocs) { MechStatisticsRules.GetHardpointCountForLocation(d, c, ref bal, ref en, ref mis, ref sup); } r.DataTxt[2] = bal + "/" + en + "/" + mis + "/" + sup; r.DataTxt[3] = (d.Chassis.Tonnage - d.Chassis.InitialTonnage) + "/" + d.Chassis.Heatsinks; float carmor = 0; float marmor = 0; foreach (ChassisLocations c in AllChassisLocs) { carmor += d.GetLocationLoadoutDef(c).AssignedArmor; marmor += d.GetChassisLocationDef(c).MaxArmor; if (d.GetChassisLocationDef(c).MaxRearArmor > 0) { carmor += d.GetLocationLoadoutDef(c).AssignedRearArmor; marmor += d.GetChassisLocationDef(c).MaxRearArmor; } } float div = UnityGameInstance.BattleTechGame.MechStatisticsConstants.ARMOR_PER_TENTH_TON * 10f; if (d.Chassis.ChassisTags.Contains("chassis_ferro")) { if (d.Chassis.ChassisTags.Contains("chassis_clan")) { div = UnityGameInstance.BattleTechGame.MechStatisticsConstants.ARMOR_PER_TENTH_TON * 12f; } else { div = UnityGameInstance.BattleTechGame.MechStatisticsConstants.ARMOR_PER_TENTH_TON * 11.2f; } } carmor /= div; marmor /= div; carmor = Mathf.Round(carmor * 10) / 10; marmor = Mathf.Round(marmor * 10) / 10; r.DataTxt[3] += "/" + carmor + "/" + marmor + "/" + (d.Chassis.Tonnage - d.Chassis.InitialTonnage - marmor); if (d.Chassis.MovementCapDef == null) { d.Chassis.RefreshMovementCaps(); if (d.Chassis.MovementCapDef == null) { r.DataTxt[4] = "??/" + d.Chassis.MaxJumpjets; } else { r.DataTxt[4] = d.Chassis.MovementCapDef.MaxWalkDistance + "/" + d.Chassis.MaxJumpjets; } } else { r.DataTxt[4] = d.Chassis.MovementCapDef.MaxWalkDistance + "/" + d.Chassis.MaxJumpjets; } r.DataTxt[5] = d.Chassis.MeleeDamage + "/" + d.Chassis.MeleeInstability + "/" + d.Chassis.DFADamage + "/" + d.Chassis.DFAInstability; r.DataTxt[6] = active + "/" + storage + "/" + parts; if (sma_parts >= 0) { r.DataTxt[6] += "(" + sma_parts + ")"; } r.DataTxt[6] += "/" + maxparts; r.DataTxt[7] = d.Chassis.Description.Id + "/" + d.Description.Id; Dictionary <string, int> eq = new Dictionary <string, int>(); Dictionary <string, int> feq = new Dictionary <string, int>(); foreach (MechComponentRef c in d.Inventory) { if (c.ComponentDefType == ComponentType.Weapon) { WeaponDef wep = c.Def as WeaponDef; if (wep != null && wep.WeaponCategoryValue.IsMelee || wep.WeaponSubType == WeaponSubType.AIImaginary || wep.WeaponEffectID.Contains("WeaponEffect-Artillery")) { continue; } } string key = c.Def.Description.Id; if (c.IsFixed) { if (feq.ContainsKey(key)) { feq[key]++; } else { feq.Add(key, 1); } } else { if (eq.ContainsKey(key)) { eq[key]++; } else { eq.Add(key, 1); } } } string txteq = ""; string txtfeq = ""; foreach (string key in eq.Keys.OrderBy((k) => k)) { if (!string.IsNullOrEmpty(txteq)) { txteq += ","; } txteq += key + ":" + eq[key]; } foreach (string key in feq.Keys.OrderBy((k) => k)) { if (!string.IsNullOrEmpty(txtfeq)) { txtfeq += ","; } txtfeq += key + ":" + feq[key]; } string txtext = ""; foreach (string ex in ExtrasToNote) { if (d.Chassis.ChassisTags.Contains(ex)) { if (!string.IsNullOrEmpty(txtext)) { txtext += ","; } txtext += ex; } } r.DataTxt[8] = txtext + "/" + txteq + "/" + txtfeq; r.Sort = string.Format("{0,3}_{1}", new object[] { d.Chassis.Tonnage, d.Chassis.VariantName }); r.DataCsv = d.Chassis.Tonnage + ";" + d.Chassis.Description.UIName + ";" + d.Chassis.VariantName + ";" + d.Chassis.StockRole; r.DataCsv += ";" + bal + ";" + en + ";" + mis + ";" + sup; r.DataCsv += ";" + (d.Chassis.Tonnage - d.Chassis.InitialTonnage) + ";" + d.Chassis.Heatsinks + ";" + carmor + ";" + marmor + ";" + (d.Chassis.Tonnage - d.Chassis.InitialTonnage - marmor); r.DataCsv += ";" + (d.Chassis.MovementCapDef == null ? -1f : d.Chassis.MovementCapDef.MaxWalkDistance) + ";" + d.Chassis.MaxJumpjets; r.DataCsv += ";" + d.Chassis.MeleeDamage + ";" + d.Chassis.MeleeInstability + ";" + d.Chassis.DFADamage + ";" + d.Chassis.DFAInstability; r.DataCsv += ";" + active + ";" + storage + ";" + parts; if (sma_parts >= 0) { r.DataCsv += "(" + sma_parts + ")"; } r.DataCsv += ";" + maxparts; r.DataCsv += ";" + d.Chassis.Description.Id + ";" + d.Description.Id; r.DataCsv += ";" + txtext + ";" + txteq + ";" + txtfeq; return(r); }
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 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 } }