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); } }