Exemple #1
0
        /* Submits a Mech Lab Work Order to the game's Mech Lab queue to actually be processed */
        public static void SubmitWorkOrder(SimGameState simGame, WorkOrderEntry_MechLab newMechLabWorkOrder)
        {
            try
            {
                Logger.LogDebug("Begin SubmitWorkOrder(): ");

                // Now that all WO subentries are added, insert the base MechLab work order to the game's Mech Lab Work Order Queue as the highest priority (index 0)
                simGame.MechLabQueue.Insert(0, newMechLabWorkOrder);
                // Call this to properly Initialize the base Mech Lab WO and make it visible in the Mech Lab queue UI / timeline etc.
                simGame.InitializeMechLabEntry(newMechLabWorkOrder, newMechLabWorkOrder.GetCBillCost());
                // Force an update of the Mech Lab queue, false is to tell it a day isn't passing.
                simGame.UpdateMechLabWorkQueue(false);

                // Simple cost debugging for the log
                foreach (WorkOrderEntry subEntries in newMechLabWorkOrder.SubEntries)
                {
                    Logger.LogDebug(subEntries.Description + " Repair Tech Costs: " + subEntries.GetCost());
                }

                Logger.LogInfo(simGame.GetMechByID(newMechLabWorkOrder.MechID).Name + " Repair Costs are - techCost: " + newMechLabWorkOrder.GetCost() + " | CBill Cost: " + newMechLabWorkOrder.GetCBillCost());
                Logger.LogInfo("=====================================================================");

                // Deduct the total CBill costs of the WO from player inventory. For some reason this isn't done automatically via the HBS WO system.
                simGame.AddFunds(-newMechLabWorkOrder.GetCBillCost(), "ArmorRepair", true);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
            }
        }
Exemple #2
0
 /* Submits a Mech Lab Work Order to our temporary queue, it will be held there until the player decides whether to let Yang run the repairs or not.*/
 public static void SubmitTempWorkOrder(SimGameState simGame, WorkOrderEntry_MechLab newMechLabWorkOrder, MechDef mech)
 {
     try
     {
         Logger.LogDebug("Adding base MechLab WO to temporary queue.");
         Globals.tempMechLabQueue.Add(newMechLabWorkOrder);
         Logger.LogDebug("Number of work orders in temp queue: " + Globals.tempMechLabQueue.Count.ToString());
     }
     catch (Exception ex)
     {
         Logger.LogError(ex);
     }
 }
        private void ApplyCosts(WorkOrderEntry_MechLab workOrder, WorkOrderCosts.Costs costs, Dictionary <string, string> variables = null)
        {
            if (costs == null)
            {
                return;
            }

            var adapter = new WorkOrderEntry_MechLabAdapter(workOrder);

            if (!string.IsNullOrEmpty(costs.CBillCost))
            {
                adapter.CBillCost = Convert.ToInt32(FormulaEvaluator.Shared.Evaluate(costs.CBillCost, variables));
            }
            if (!string.IsNullOrEmpty(costs.TechCost))
            {
                adapter.Cost = Convert.ToInt32(FormulaEvaluator.Shared.Evaluate(costs.TechCost, variables));
            }
        }
Exemple #4
0
            public static void Postfix(SimGameState __instance, WorkOrderEntry entry)
            {
                if (!Core.Settings.RepairRearm)
                {
                    return;
                }

                if (entry.Type == WorkOrderType.MechLabModifyArmor)
                {
                    WorkOrderEntry_MechLab workOrderEntry_MechLab = entry as WorkOrderEntry_MechLab;
                    MechDef mechBayID = __instance.GetMechByID(workOrderEntry_MechLab.MechID);
                    Logger.LogDebug("CancelWorkOrder");
                    if (mechBayID.MechTags.Contains("XLRP_Armor_Repairing"))
                    {
                        mechBayID.MechTags.Remove("XLRP_Armor_Repairing");
                    }
                }
            }
Exemple #5
0
            public static void Postfix(SimGameState __instance, WorkOrderEntry entry)
            {
                if (!Core.Settings.RepairRearm)
                {
                    return;
                }

                if (entry.Type == WorkOrderType.MechLabModifyArmor)
                {
                    Logger.LogDebug("CompleteWorkOrder");
                    WorkOrderEntry_MechLab workOrderEntry_MechLab = entry as WorkOrderEntry_MechLab;
                    MechDef mechBayID = __instance.GetMechByID(workOrderEntry_MechLab.MechLabParent.MechID);
                    if (mechBayID.MechTags.Contains("XLRP_Armor_Repairing"))
                    {
                        mechBayID.MechTags.Remove("XLRP_Armor_Repairing");
                        mechBayID.MechTags.Remove("XLRP_R&R");
                        mechBayID.MechTags.Where(tag => tag.StartsWith("XLRPArmor")).Do(x => mechBayID.MechTags.Remove(x));
                    }
                }
            }
        // Run after completion of contracts and queue up any orders in the temp queue into the game's Mech Lab queue
        public static void Postfix(SimGameState __instance)
        {
            try
            {
                // If there are any work orders in the temporary queue, prompt the player
                if (Globals.tempMechLabQueue.Count > 0)
                {
                    Logger.LogDebug("Processing temp Mech Lab queue orders.");

                    int    cbills                   = 0;
                    int    techCost                 = 0;
                    int    mechRepairCount          = 0;
                    int    skipMechCount            = 0;
                    string mechRepairCountDisplayed = String.Empty;
                    string skipMechCountDisplayed   = String.Empty;
                    string skipMechMessage          = String.Empty;
                    string finalMessage             = String.Empty;

                    // If player has disabled auto repairing mechs with destroyed components, check for them and remove them from the temp queue before continuing
                    if (!ArmorRepair.ModSettings.AutoRepairMechsWithDestroyedComponents)
                    {
                        for (int index = 0; index < Globals.tempMechLabQueue.Count; index++)
                        {
                            WorkOrderEntry_MechLab order = Globals.tempMechLabQueue[index];

                            Logger.LogDebug("Checking for destroyed components.");
                            bool    destroyedComponents = false;
                            MechDef mech = __instance.GetMechByID(order.MechID);
                            destroyedComponents = Helpers.CheckDestroyedComponents(mech);

                            if (destroyedComponents)
                            {
                                // Remove this work order from the temp mech lab queue if the mech has destroyed components and move to next iteration
                                Logger.LogDebug("Removing " + mech.Name + " order from temp queue due to destroyed components and mod settings.");
                                Globals.tempMechLabQueue.Remove(order);
                                destroyedComponents = false;
                                skipMechCount++;
                                index++;
                            }
                        }
                    }

                    Logger.LogDebug("Temp Queue has " + Globals.tempMechLabQueue.Count + " entries.");

                    // Calculate summary of total repair costs from the temp work order queue
                    for (int index = 0; index < Globals.tempMechLabQueue.Count; index++)
                    {
                        WorkOrderEntry_MechLab order = Globals.tempMechLabQueue[index];
                        MechDef mech = __instance.GetMechByID(order.MechID);
                        Logger.LogDebug("Adding " + mech.Name + " to RepairCount.");
                        cbills   += order.GetCBillCost();
                        techCost += order.GetCost();
                        mechRepairCount++;
                    }

                    mechRepairCount = Mathf.Clamp(mechRepairCount, 0, 4);
                    Logger.LogDebug("Temp Queue has " + Globals.tempMechLabQueue.Count + " work order entries.");

                    // If Yang's Auto Repair prompt is enabled, build a message prompt dialog for the player
                    if (ArmorRepair.ModSettings.EnableAutoRepairPrompt)
                    {
                        // Calculate a friendly techCost of the work order in days, based on number of current mechtechs in the player's game.
                        if (techCost != 0 && __instance.MechTechSkill != 0)
                        {
                            techCost = Mathf.CeilToInt((float)techCost / (float)__instance.MechTechSkill);
                        }
                        else
                        {
                            techCost = 1; // Safety in case of weird div/0
                        }

                        // Generate a quick friendly description of how many mechs were damaged in battle
                        switch (mechRepairCount)
                        {
                        case 0: { Logger.LogDebug("mechRepairCount was 0."); break; }

                        case 1: { mechRepairCountDisplayed = "one of our 'Mechs was"; break; }

                        case 2: { mechRepairCountDisplayed = "a couple of the 'Mechs were"; break; }

                        case 3: { mechRepairCountDisplayed = "three of our 'Mechs were"; break; }

                        case 4: { mechRepairCountDisplayed = "our whole lance was"; break; }
                        }
                        // Generate a friendly description of how many mechs were damaged but had components destroyed
                        switch (skipMechCount)
                        {
                        case 0: { Logger.LogDebug("skipMechCount was 0."); break; }

                        case 1: { skipMechCountDisplayed = "one of the 'Mechs is damaged but has"; break; }

                        case 2: { skipMechCountDisplayed = "two of the 'Mechs are damaged but have"; break; }

                        case 3: { skipMechCountDisplayed = "three of the 'Mechs are damaged but have "; break; }

                        case 4: { skipMechCountDisplayed = "the whole lance is damaged but has"; break; }
                        }

                        // Check if there are any mechs to process
                        if (mechRepairCount > 0 || skipMechCount > 0)
                        {
                            Logger.LogDebug("mechRepairCount is " + mechRepairCount + " skipMechCount is " + skipMechCount);

                            // Setup the notification for mechs with damaged components that we might want to skip
                            if (skipMechCount > 0 && mechRepairCount == 0)
                            {
                                skipMechMessage = String.Format("{0} destroyed components. I'll leave the repairs for you to review.", skipMechCountDisplayed);
                            }
                            else
                            {
                                skipMechMessage = String.Format("{0} destroyed components, so I'll leave those repairs to you.", skipMechCountDisplayed);
                            }

                            Logger.LogDebug("Firing Yang's UI notification.");
                            SimGameInterruptManager notificationQueue = __instance.GetInterruptQueue();

                            // If all of the mechs needing repairs have damaged components and should be skipped from auto-repair, change the message notification structure to make more sense (e.g. just have an OK button)
                            if (skipMechCount > 0 && mechRepairCount == 0)
                            {
                                finalMessage = String.Format(
                                    "Boss, {0} \n\n",
                                    skipMechMessage
                                    );

                                // Queue Notification
                                notificationQueue.QueuePauseNotification(
                                    "'Mech Repairs Needed",
                                    finalMessage,
                                    __instance.GetCrewPortrait(SimGameCrew.Crew_Yang),
                                    string.Empty,
                                    delegate
                                {
                                    Logger.LogDebug("[PROMPT] All damaged mechs had destroyed components and won't be queued for repair.");
                                },
                                    "OK"
                                    );
                            }
                            else
                            {
                                if (skipMechCount > 0)
                                {
                                    finalMessage = String.Format(
                                        "Boss, {0} damaged. It'll cost <color=#DE6729>{1}{2:n0}</color> and {3} days for these repairs. Want my crew to get started?\n\nAlso, {4}\n\n",
                                        mechRepairCountDisplayed,
                                        '¢', cbills.ToString(),
                                        techCost.ToString(),
                                        skipMechMessage
                                        );
                                }
                                else
                                {
                                    finalMessage = String.Format(
                                        "Boss, {0} damaged on the last engagement. It'll cost <color=#DE6729>{1}{2:n0}</color> and {3} days for the repairs.\n\nWant my crew to get started?",
                                        mechRepairCountDisplayed,
                                        '¢', cbills.ToString(),
                                        techCost.ToString()
                                        );
                                }


                                // Queue up Yang's notification
                                notificationQueue.QueuePauseNotification(
                                    "'Mech Repairs Needed",
                                    finalMessage,
                                    __instance.GetCrewPortrait(SimGameCrew.Crew_Yang),
                                    string.Empty,
                                    delegate
                                {
                                    Logger.LogDebug("[PROMPT] Moving work orders from temp queue to Mech Lab queue: " + Globals.tempMechLabQueue.Count + " work orders");
                                    foreach (WorkOrderEntry_MechLab workOrder in Globals.tempMechLabQueue.ToList())
                                    {
                                        Logger.LogInfo("[PROMPT] Moving work order from temp queue to Mech Lab queue: " + workOrder.Description + " - " + workOrder.GetCBillCost());
                                        Helpers.SubmitWorkOrder(__instance, workOrder);
                                        Globals.tempMechLabQueue.Remove(workOrder);
                                    }
                                },
                                    "Yes",
                                    delegate
                                {
                                    Logger.LogInfo("[PROMPT] Discarding work orders from temp queue: " + Globals.tempMechLabQueue.Count + " work orders");
                                    foreach (WorkOrderEntry_MechLab workOrder in Globals.tempMechLabQueue.ToList())
                                    {
                                        Logger.LogInfo("[PROMPT] Discarding work order from temp queue: " + workOrder.Description + " - " + workOrder.GetCBillCost());
                                        Globals.tempMechLabQueue.Remove(workOrder);
                                    }
                                },
                                    "No"
                                    );
                            }
                        }
                    }
                    else // If Auto Repair prompt is not enabled, just proceed with queuing the remaining temp queue work orders and don't notify the player
                    {
                        foreach (WorkOrderEntry_MechLab workOrder in Globals.tempMechLabQueue.ToList())
                        {
                            Logger.LogInfo("[AUTO] Moving work order from temp queue to Mech Lab queue: " + workOrder.Description + " - " + workOrder.GetCBillCost());
                            Helpers.SubmitWorkOrder(__instance, workOrder);
                            Globals.tempMechLabQueue.Remove(workOrder);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Globals.tempMechLabQueue.Clear();
                Logger.LogError(ex);
            }
        }
Exemple #7
0
            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);
            }
Exemple #8
0
        internal static void Validate(List <MechDef> mechdefs)
        {
            foreach (var mechDef in mechdefs)
            {
                try
                {
                    var dm   = UnityGameInstance.BattleTechGame.DataManager;
                    var work = new WorkOrderEntry_MechLab(WorkOrderType.MechLabGeneric, "test", "test", "test", 0);

                    if (mechDef == null)
                    {
                        Control.LogError("NullMECHDEF!");
                        continue;
                    }
                    if (Control.Settings.IgnoreValidationTags != null && Control.Settings.IgnoreValidationTags.Length > 0)
                    {
                        bool skip = false;
                        foreach (var tag in Control.Settings.IgnoreValidationTags)
                        {
                            if ((mechDef.Chassis.ChassisTags != null && mechDef.Chassis.ChassisTags.Contains(tag)) ||
                                (mechDef.MechTags != null && mechDef.MechTags.Contains(tag)))
                            {
                                Control.LogDebug(DType.AutofixValidate, $"{mechDef.Description.Id} Ignored by {tag}");
                                skip = true;
                                break;
                            }
                        }
                        if (skip)
                        {
                            continue;
                        }
                    }

                    var error = MechValidationRules.ValidateMechDef(MechValidationLevel.Full, dm,
                                                                    mechDef, work);
                    foreach (var component in mechDef.Inventory)
                    {
                        foreach (var validator in component.GetComponents <IMechValidate>())
                        {
                            validator.ValidateMech(error, MechValidationLevel.MechLab, mechDef, component);
                        }
                    }

                    bool bad_mech = false;
                    foreach (var pair in error)
                    {
                        if (pair.Value.Count > 0)
                        {
                            if (!bad_mech)
                            {
                                bad_mech = true;
                                Control.LogDebug(DType.AutofixValidate, $"{mechDef.Description.Id} has errors:");
                            }
                            foreach (var text in pair.Value)
                            {
                                Control.LogDebug(DType.AutofixValidate, $"[{pair.Key}]:{text}");
                            }
                        }
                    }
                    if (!bad_mech && !Control.Settings.DEBUG_ShowOnlyErrors)
                    {
                        Control.LogDebug(DType.AutofixValidate, $"{mechDef.Description.Id} no errors");
                    }
                }
                catch (Exception e)
                {
                    Control.LogError($"{mechDef.Description.Id} throwed exception on validation", e);
                }
            }
        }
Exemple #9
0
        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
            }
        }
Exemple #10
0
        // Run after completion of contracts and queue up any orders in the temp queue into the game's Mech Lab queue
        public static void Postfix(SimGameState __instance)
        {
            try
            {
                foreach (var mechDef in Core.CombatMechs)
                {
                    if (mechDef.MechDefCurrentStructure < mechDef.MechDefMaxStructure)
                    {
                        continue;
                    }

                    bool componentDamage = false;
                    for (int i = 0; i < mechDef.inventory.Length; i++)
                    {
                        if (mechDef.inventory[i].DamageLevel == ComponentDamageLevel.Destroyed ||
                            mechDef.inventory[i].DamageLevel == ComponentDamageLevel.NonFunctional)
                        {
                            componentDamage = true;
                        }
                    }
                    if (componentDamage)
                    {
                        continue;
                    }

                    var tempWO = Helpers.CreateBaseMechLabOrder(__instance, mechDef);
                    tempWO.AddSubEntry(Repair_ReArm.RepairArmorMechDef(mechDef));
                    Core.tempMechLabQueue.Add(tempWO);
                }


                // If there are any work orders in the temporary queue, prompt the player
                if (Core.tempMechLabQueue.Count > 0)
                {
                    Logger.LogDebug("Processing temp Mech Lab queue orders.");

                    int    cbills                   = 0;
                    int    techCost                 = 0;
                    int    mechRepairCount          = 0;
                    int    skipMechCount            = 0;
                    string mechRepairCountDisplayed = String.Empty;
                    string skipMechCountDisplayed   = String.Empty;
                    string skipMechMessage          = String.Empty;
                    string finalMessage             = String.Empty;

                    //int Counter = Core.tempMechLabQueue.Count;
                    //for (int index = Counter - 1; index < 0; index--)
                    //{
                    //    if (Counter == 0)
                    //        break;

                    //    WorkOrderEntry_MechLab order = Core.tempMechLabQueue[index];

                    //    LogDebug("Checking for destroyed components.");
                    //    bool destroyedComponents = false;
                    //    MechDef mech = __instance.GetMechByID(order.MechID);
                    //    if (mech != null)
                    //        destroyedComponents = Helpers.CheckDestroyedComponents(mech);
                    //    else
                    //        destroyedComponents = true;

                    //    if (destroyedComponents)
                    //    {
                    //        // Remove this work order from the temp mech lab queue if the mech has destroyed components and move to next iteration
                    //        Logger.LogDebug("Removing " + mech.Name + " order from temp queue due to destroyed components and mod settings.");
                    //        Core.tempMechLabQueue.Remove(order);
                    //        destroyedComponents = false;
                    //        skipMechCount++;
                    //    }
                    //}

                    // Calculate summary of total repair costs from the temp work order queue
                    for (int index = 0; index < Core.tempMechLabQueue.Count; index++)
                    {
                        if (Core.tempMechLabQueue.Count == 0)
                        {
                            break;
                        }

                        WorkOrderEntry_MechLab order = Core.tempMechLabQueue[index];
                        MechDef mech = __instance.GetMechByID(order.MechID);
                        LogDebug("Adding " + mech.Name + " to RepairCount.");
                        cbills   += order.GetCBillCost();
                        techCost += order.GetCost();
                        mechRepairCount++;
                    }

                    mechRepairCount = Mathf.Clamp(mechRepairCount, 0, 6);

                    // If Yang's Auto Repair prompt is enabled, build a message prompt dialog for the player
                    if (true)
                    {
                        // Calculate a friendly techCost of the work order in days, based on number of current mechtechs in the player's game.
                        if (techCost != 0 && __instance.MechTechSkill != 0)
                        {
                            techCost = Mathf.CeilToInt((float)techCost / (float)__instance.MechTechSkill);
                        }
                        else
                        {
                            techCost = 1; // Safety in case of weird div/0
                        }

                        // Generate a quick friendly description of how many mechs were damaged in battle
                        switch (mechRepairCount)
                        {
                        case 0: { Logger.LogDebug("mechRepairCount was 0."); break; }

                        case 1: { mechRepairCountDisplayed = "one of our 'Mechs had only its armor"; break; }

                        case 2: { mechRepairCountDisplayed = "a couple of the 'Mechs had only their armor"; break; }

                        case 3: { mechRepairCountDisplayed = "three of our 'Mechs had only their armor"; break; }

                        case 4: { mechRepairCountDisplayed = "an entire lance of ours had only their armor"; break; }

                        case 5: { mechRepairCountDisplayed = "five of our 'Mechs had only their armor"; break; }

                        case 6: { mechRepairCountDisplayed = "every 'Mech we dropped with had only their armor"; break; }
                        }
                        // Generate a friendly description of how many mechs were damaged but had components destroyed
                        switch (skipMechCount)
                        {
                        case 0: { Logger.LogDebug("skipMechCount was 0."); break; }

                        case 1: { skipMechCountDisplayed = "one of the 'Mechs is damaged but has"; break; }

                        case 2: { skipMechCountDisplayed = "two of the 'Mechs are damaged but have"; break; }

                        case 3: { skipMechCountDisplayed = "three of the 'Mechs are damaged but have "; break; }

                        case 4: { skipMechCountDisplayed = "the whole lance is damaged but has"; break; }
                        }

                        // Check if there are any mechs to process
                        if (mechRepairCount > 0 || skipMechCount > 0)
                        {
                            Logger.LogDebug("mechRepairCount is " + mechRepairCount + " skipMechCount is " + skipMechCount);

                            // Setup the notification for mechs with damaged components that we might want to skip
                            if (skipMechCount > 0 && mechRepairCount == 0)
                            {
                                skipMechMessage = String.Format("{0} destroyed components. I'll leave the repairs for you to review.", skipMechCountDisplayed);
                            }
                            else
                            {
                                skipMechMessage = String.Format("{0} destroyed components, so I'll leave those repairs to you.", skipMechCountDisplayed);
                            }

                            Logger.LogDebug("Firing Yang's UI notification.");
                            SimGameInterruptManager notificationQueue = __instance.GetInterruptQueue();

                            // If all of the mechs needing repairs have damaged components and should be skipped from auto-repair, change the message notification structure to make more sense (e.g. just have an OK button)
                            if (skipMechCount > 0 && mechRepairCount == 0)
                            {
                                finalMessage = String.Format(
                                    "Boss, {0} \n\n",
                                    skipMechMessage
                                    );

                                // Queue Notification
                                notificationQueue.QueuePauseNotification(
                                    "'Mech Armor Repairs Needed",
                                    finalMessage,
                                    __instance.GetCrewPortrait(SimGameCrew.Crew_Yang),
                                    string.Empty,
                                    delegate
                                {
                                    Logger.LogDebug("[PROMPT] All damaged mechs had destroyed components and won't be queued for repair.");
                                },
                                    "OK"
                                    );
                            }
                            else
                            {
                                if (skipMechCount > 0)
                                {
                                    finalMessage = String.Format(
                                        "Boss, {0} damaged. It'll cost <color=#DE6729>{1}{2:n0}</color> and {3} days for these repairs. Want my crew to get started?\n\nAlso, {4}\n\n",
                                        mechRepairCountDisplayed,
                                        '¢', cbills.ToString(),
                                        techCost.ToString(),
                                        skipMechMessage
                                        );
                                }
                                else
                                {
                                    finalMessage = String.Format(
                                        "Boss, {0} damaged on the last engagement. It'll cost <color=#DE6729>{1}{2:n0}</color> and {3} days for the repairs.\n\nWant my crew to get started?",
                                        mechRepairCountDisplayed,
                                        '¢', cbills.ToString(),
                                        techCost.ToString()
                                        );
                                }


                                // Queue up Yang's notification
                                notificationQueue.QueuePauseNotification(
                                    "'Mech Armor Repairs Needed",
                                    finalMessage,
                                    __instance.GetCrewPortrait(SimGameCrew.Crew_Yang),
                                    string.Empty,
                                    delegate
                                {
                                    Logger.LogDebug("[PROMPT] Moving work orders from temp queue to Mech Lab queue: " + Core.tempMechLabQueue.Count + " work orders");
                                    foreach (WorkOrderEntry_MechLab workOrder in Core.tempMechLabQueue.ToList())
                                    {
                                        Helpers.SubmitWorkOrder(__instance, workOrder);
                                        Core.tempMechLabQueue.Remove(workOrder);
                                    }
                                },
                                    "Yes",
                                    delegate
                                {
                                    foreach (WorkOrderEntry_MechLab workOrder in Core.tempMechLabQueue.ToList())
                                    {
                                        Core.tempMechLabQueue.Remove(workOrder);
                                    }
                                },
                                    "No"
                                    );
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Core.tempMechLabQueue.Clear();
                Error(ex);
            }
        }