public void ModifyMech(MechDef mDef, SimGameState s, UpgradeList ulist, ref float canFreeTonns, List <string[]> changedAmmoTypes, MechDef fromData)
        {
            BTRandomMechComponentUpgrader_Init.Log.Log("checking addition sublists");
            List <MechComponentRef> inv = mDef.Inventory.ToList();

            foreach (UpgradeList.UpgradeEntry[] l in ulist.Additions)
            {
                if (s.NetworkRandom.Float(0f, 1f) < ulist.UpgradePerComponentChance)
                {
                    string log = "";
                    UpgradeList.UpgradeEntry ue = ulist.RollEntryFromSubList(l, s.NetworkRandom, -1, s.CurrentDate, ref log, ulist.UpgradePerComponentChance);
                    if (ue != null && !ue.ID.Equals(""))
                    {
                        MechComponentDef d   = s.GetComponentDefFromID(ue.ID);
                        ChassisLocations loc = mDef.SearchLocationToAddComponent(d, canFreeTonns, inv, null, ChassisLocations.None);
                        if (loc == ChassisLocations.None)
                        {
                            BTRandomMechComponentUpgrader_Init.Log.Log("cannot add " + log);
                            continue;
                        }
                        BTRandomMechComponentUpgrader_Init.Log.Log($"adding {log} into {loc}");
                        MechComponentRef r = new MechComponentRef(ue.ID, null, d.ComponentType, loc, -1, ComponentDamageLevel.Functional, false);
                        r.SetComponentDef(d);
                        inv.Add(r);
                        canFreeTonns -= d.Tonnage;
                    }
                    else
                    {
                        BTRandomMechComponentUpgrader_Init.Log.Log("cannot add, nothing rolled " + log);
                    }
                }
            }
            mDef.SetInventory(inv.ToArray());
        }
        public string ValidateDrop(MechLabItemSlotElement drop_item, List <InvItem> new_inventory)
        {
            var mechDef = MechLabHelper.CurrentMechLab.ActiveMech;

            var errors1 = new Errors();

            validator.ValidateMech(mechDef, errors1);

            var mechDef2   = new MechDef(mechDef);
            var inventory2 = new_inventory.Select(x =>
            {
                var r             = new MechComponentRef(x.Item);
                r.MountedLocation = x.Location;
                return(r);
            }).ToList();

            mechDef2.SetInventory(inventory2.ToArray());

            var errors2 = new Errors();

            validator.ValidateMech(mechDef2, errors2);

            var newErrors = errors2.Except(errors1);

            return(newErrors.FirstOrDefault()?.Message ?? string.Empty);
        }
        public static void AddInventory(string defaultID, MechDef mech, ChassisLocations location, ComponentType type, SimGameState state)
        {
            var r = CreateRef(defaultID, type, mech.DataManager, state);

            if (r != null)
            {
                r.SetData(location, -1, ComponentDamageLevel.Functional, true);
                var inv = mech.Inventory.ToList();
                inv.Add(r);
                mech.SetInventory(inv.ToArray());

#if CCDEBUG
                if (Control.Settings.DebugInfo.HasFlag(DType.FixedCheck))
                {
                    var flag = r.GetComponent <Flags>();
                    Control.LogDebug(DType.FixedCheck,
                                     $"AddInventory: {r.Def.Description.Id} isdefult:{r.Def.IsDefault()} isfixed:{r.IsFixed} isFlag:{flag == null}");
                    if (flag == null)
                    {
                        Control.LogDebug(DType.FixedCheck, $"-- NO FLAGS!");
                    }
                    else
                    {
                        Control.LogDebug(DType.FixedCheck,
                                         $"-- default: {flag.IsSet("default")} isdefault:{flag.Default}");
                    }

                    foreach (var simpleCustomComponent in r.GetComponents <SimpleCustomComponent>())
                    {
                        Control.LogDebug(DType.FixedCheck, $"-- {simpleCustomComponent}");
                    }
                }
#endif
            }
        }
        public void ModifyMech(MechDef mDef, SimGameState s, UpgradeList ulist, ref float canFreeTonns, List <string[]> changedAmmoTypes, MechDef fromData)
        {
            BTRandomMechComponentUpgrader_Init.Log.Log("checking changed ammo types");
            List <MechComponentRef> inv = mDef.Inventory.ToList();

            foreach (string[] ca in changedAmmoTypes)
            {
                AmmunitionBoxDef basebox = GetMainAmmoBox(ca[0], s);
                AmmunitionBoxDef box     = GetMainAmmoBox(ca[1], s);
                if (box == null && basebox == null)
                {
                    BTRandomMechComponentUpgrader_Init.Log.Log($"changing ammo {ca[0]} -> {ca[1]} (both null ???)");
                    continue;
                }
                if (box == null) // removed ammo dependency, remove all ammoboxes as well, tonnagefixer will take care of missing tonnage
                {
                    BTRandomMechComponentUpgrader_Init.Log.Log($"changing ammo {ca[0]} -> {ca[1]} (box null, removing all)");
                    inv.RemoveAll((a) => ca[0].Equals((a.Def as AmmunitionBoxDef)?.AmmoID));
                    continue;
                }
                if (basebox == null) // added ammo dependency, try to add an ammobox
                {
                    TryAddAmmoBox(mDef, ref canFreeTonns, inv, ca, box);
                    continue;
                }
                int   numOldBox = CountAmmoBoxes(inv, ca[0]);
                float or        = (float)GetAmmoTypeUsagePerTurn(inv, ca[0]) / basebox.Capacity;
                float ne        = (float)GetAmmoTypeUsagePerTurn(inv, ca[1]) / box.Capacity;
                if (numOldBox <= 0 || (numOldBox == 1 && or > 0)) // should not happen, but just in case
                {
                    TryAddAmmoBox(mDef, ref canFreeTonns, inv, ca, box);
                    continue;
                }
                float ratio = ne / (or + ne);
                int   swap  = Mathf.RoundToInt(numOldBox * ratio);
                BTRandomMechComponentUpgrader_Init.Log.Log($"changing ammo {ca[0]} -> {ca[1]} (usage {or}/{ne}, changing {swap} boxes)");
                foreach (MechComponentRef r in inv.Where((a) => ca[0].Equals((a.Def as AmmunitionBoxDef)?.AmmoID)))
                {
                    if (swap <= 0)
                    {
                        break;
                    }
                    if (r.CanUpgrade(box, canFreeTonns, mDef, r.MountedLocation, inv))
                    {
                        BTRandomMechComponentUpgrader_Init.Log.Log($"changing ammo {r.Def.Description.Id} -> {box.Description.Id}");
                        r.DoUpgrade(box, ref canFreeTonns);
                        swap--;
                    }
                    else
                    {
                        BTRandomMechComponentUpgrader_Init.Log.Log($"cannot change ammo {r.Def.Description.Id} -> {box.Description.Id}");
                    }
                }
                if (swap > 0)
                {
                    BTRandomMechComponentUpgrader_Init.Log.Log($"missed {swap} changes");
                }
            }
            mDef.SetInventory(inv.ToArray());
        }
Example #5
0
        public void AutoFixMechDef(MechDef mechDef, float originalTotalTonnage)
        {
            //Control.mod.Logger.LogDebug($"ArmActuatorHandler.AutoFixMechDef");
            //Control.mod.Logger.LogDebug($" chassis={mechDef.Chassis.Description.Id}");

            var builder = new MechDefBuilder(mechDef.Chassis, mechDef.Inventory.ToList());

            UpgradeDef GetComponent(ArmActuator.TypeDef type)
            {
                switch (type)
                {
                case ArmActuator.TypeDef.Hand:
                    return(mechDef.DataManager.UpgradeDefs.Get("emod_arm_hand"));

                case ArmActuator.TypeDef.Lower:
                    return(mechDef.DataManager.UpgradeDefs.Get("emod_arm_lower"));

                case ArmActuator.TypeDef.Upper:
                    return(mechDef.DataManager.UpgradeDefs.Get("emod_arm_upper"));

                default:
                    return(null);
                }
            }

            void AddActuatorToArm(ChassisLocations location, ArmActuator.TypeDef limit)
            {
                if (mechDef.Inventory.Any(r => r.MountedLocation == location && r.Def.Is <ArmActuator>()))
                {
                    return;
                }

                //Control.mod.Logger.LogDebug($" AddActuatorToArm");
                //Control.mod.Logger.LogDebug($" location={location} limit={limit}");
                foreach (var candidate in Enum.GetValues(typeof(ArmActuator.TypeDef)).Cast <ArmActuator.TypeDef>().Where(type => type >= limit))
                {
                    //Control.mod.Logger.LogDebug($"  candidate={candidate}");
                    var component = GetComponent(candidate);
                    if (candidate <= ArmActuator.TypeDef.Upper && builder.GetFreeSlots(location) < component.InventorySize)
                    {
                        continue;
                    }

                    //Control.mod.Logger.LogDebug($"  add");
                    builder.Add(component, location);
                    break;
                }
            }

            var limits      = mechDef.Chassis.GetComponent <ArmActuatorSupport>() ?? new ArmActuatorSupport();
            var beforeCount = builder.Inventory.Count;

            AddActuatorToArm(ChassisLocations.LeftArm, limits.LeftLimit);
            AddActuatorToArm(ChassisLocations.RightArm, limits.RightLimit);
            if (builder.Inventory.Count != beforeCount)
            {
                mechDef.SetInventory(builder.Inventory.ToArray());
            }
        }
Example #6
0
        public static void RemoveInventory(string defaultID, MechDef mech, ChassisLocations location, ComponentType type)
        {
            var item = mech.Inventory.FirstOrDefault(i => i.MountedLocation == location && i.ComponentDefID == defaultID);

            if (item != null)
            {
                var inv = mech.Inventory.ToList();
                inv.Remove(item);
                mech.SetInventory(inv.ToArray());
            }
        }
Example #7
0
        public static void AddInventory(string defaultID, MechDef mech, ChassisLocations location, ComponentType type, SimGameState state)
        {
            var r = CreateRef(defaultID, type);

            if (r != null)
            {
                r.SetData(location, -1, ComponentDamageLevel.Functional, true);
                var inv = mech.Inventory.ToList();
                inv.Add(r);
                mech.SetInventory(inv.ToArray());
            }
        }
        private static void MakeMech(SimGameState sim)
        {
            Control.LogDebug($"Mech Assembly started for {mech.Description.UIName}");
            MechDef new_mech = new MechDef(mech, mechBay.Sim.GenerateSimGameUID(), true);

            try
            {
                if (Control.Settings.UnEquipedMech)
                {
                    Control.LogDebug($"-- Clear Inventory");
#if USE_CC
                    new_mech.SetInventory(DefaultHelper.ClearInventory(new_mech, mechBay.Sim));
#else
                    new_mech.SetInventory(new MechComponentRef[0]);
#endif
                }
            }
            catch (Exception e)
            {
                Control.LogError($"ERROR in ClearInventory", e);
            }

            if (Control.Settings.BrokenMech)
            {
                BrokeMech(new_mech, sim);
            }

            try
            {
                Control.LogDebug("-- Adding mech");
                mechBay.Sim.AddMech(0, new_mech, true, false, true, null);
                Control.LogDebug("-- Posting Message");
                mechBay.Sim.MessageCenter.PublishMessage(new SimGameMechAddedMessage(new_mech, chassis.MechPartMax, true));
            }
            catch (Exception e)
            {
                Control.LogError($"ERROR in MakeMach", e);
            }
        }
        public void ModifyMech(MechDef mDef, SimGameState s, UpgradeList ulist, ref float _, List <string[]> changedAmmoTypes, MechDef fromData)
        {
            BTRandomMechComponentUpgrader_Init.Log.Log("correcting tonage 1: inventory");
            List <MechComponentRef> inv = mDef.Inventory.ToList();
            float tonnage = 0;
            float max     = 0;

            MechStatisticsRules.CalculateTonnage(mDef, ref tonnage, ref max);
            while (tonnage > mDef.Chassis.Tonnage)
            {
                int i = inv.FindIndex((x) => !x.IsFixed && ulist.CanRemove.Contains(x.ComponentDefID));
                if (i == -1)
                {
                    BTRandomMechComponentUpgrader_Init.Log.Log("no removable found");
                    break;
                }
                BTRandomMechComponentUpgrader_Init.Log.Log($"removed {inv[i].ComponentDefID} to reduce weight");
                tonnage -= inv[i].Def.Tonnage;
                inv.RemoveAt(i);
            }

            foreach (string id in ulist.CanRemove)
            {
                MechComponentDef d = s.GetComponentDefFromID(id);
                while (tonnage + d.Tonnage <= mDef.Chassis.Tonnage)
                {
                    ChassisLocations loc = ChassisLocations.None;
                    foreach (ChassisLocations l in RMCU_Helper.Locations)
                    {
                        if (mDef.GetFreeSlotsInLoc(inv, l, null) >= d.InventorySize && d.CanPutComponentIntoLoc(l))
                        {
                            loc = l;
                            break;
                        }
                    }
                    if (loc == ChassisLocations.None)
                    {
                        BTRandomMechComponentUpgrader_Init.Log.Log("no free location found!");
                        break;
                    }
                    MechComponentRef r = new MechComponentRef(d.Description.Id, null, d.ComponentType, loc, -1, ComponentDamageLevel.Functional, false);
                    r.SetComponentDef(d);
                    inv.Add(r);
                    tonnage += d.Tonnage;
                    BTRandomMechComponentUpgrader_Init.Log.Log($"added {r.ComponentDefID} to use free weight");
                }
            }
            mDef.SetInventory(inv.ToArray());
        }
Example #10
0
        public void AutoFixMechDef(MechDef mechDef)
        {
            if (mechDef.Inventory.Any(x => x.Def != null && identifier.IsCustomType(x.Def)))
            {
                return;
            }

            var componentRefs = new List <MechComponentRef>(mechDef.Inventory);

            var componentRef = new MechComponentRef(adder.ComponentDefId, null, adder.ComponentType, adder.ChassisLocation);

            componentRefs.Add(componentRef);

            mechDef.SetInventory(componentRefs.ToArray());
        }
Example #11
0
        internal static ArmActuatorSlot ClearDefaultActuators(MechDef mechdef, ChassisLocations location)
        {
            mechdef.SetInventory(mechdef.Inventory.Where(i =>
                                                         !(i.MountedLocation == location && i.Is <ArmActuator>() && i.IsFixed &&
                                                           !i.IsModuleFixed(mechdef))).ToArray());

            var slot = ArmActuatorSlot.None;

            foreach (var item in mechdef.Inventory.Where(i => i.MountedLocation == location && i.Is <ArmActuator>()))
            {
                var actuator = item.GetComponent <ArmActuator>();
                slot = slot | actuator.Type;
            }

            return(slot);
        }
        public string ValidateDrop(MechLabItemSlotElement drop_item, MechDef mech, List <InvItem> new_inventory, List <IChange> changes)
        {
            var inventory = new_inventory.Select(x =>
            {
                var r = new MechComponentRef(x.item);
                Traverse.Create(r).Property(nameof(MechComponentRef.MountedLocation)).SetValue(x.location);
                return(r);
            }).ToList();

            var mechDef = new MechDef(mech);

            mechDef.SetInventory(inventory.ToArray());

            var errors = new Errors();

            validator.ValidateMech(mechDef, errors);

            return(errors.FirstOrDefault()?.Message ?? string.Empty);
        }
Example #13
0
        internal static void AddGyroIfPossible(MechDef mechDef)
        {
            if (!Control.settings.AutoFixMechDefGyro)
            {
                return;
            }

            if (mechDef.Inventory.Any(x => x.Def != null && x.Def.IsCenterTorsoUpgrade()))
            {
                return;
            }

            var componentRefs = new List <MechComponentRef>(mechDef.Inventory);

            var componentRef = new MechComponentRef(Control.GearGyroGeneric, null, ComponentType.Upgrade, ChassisLocations.CenterTorso);

            componentRefs.Add(componentRef);

            mechDef.SetInventory(componentRefs.ToArray());
        }
Example #14
0
        internal static void AddCockpitIfPossible(MechDef mechDef)
        {
            if (!Control.settings.AutoFixMechDefCockpit)
            {
                return;
            }

            if (mechDef.Inventory.Any(x => x.Def != null && x.Def.IsCockpit()))
            {
                return;
            }

            var componentRefs = new List <MechComponentRef>(mechDef.Inventory);

            var componentRef = new MechComponentRef(Control.settings.AutoFixMechDefCockpitId, null, ComponentType.Upgrade, ChassisLocations.Head);

            componentRefs.Add(componentRef);

            mechDef.SetInventory(componentRefs.ToArray());
        }
Example #15
0
        internal static void AddStructureIfPossible(MechDef mechDef)
        {
            if (!Control.settings.AutoFixStructure)
            {
                return;
            }

            if (mechDef.Inventory.Any(x => x.Def != null && x.Def.IsStructure()))
            {
                return;
            }

            var componentRefs = new List <MechComponentRef>(mechDef.Inventory);

            var struct_def = Control.settings.AutoFixStructureDef + mechDef.Chassis.Tonnage;

            var componentRef = new MechComponentRef(struct_def, null, ComponentType.Upgrade, ChassisLocations.CenterTorso);

            componentRefs.Add(componentRef);

            mechDef.SetInventory(componentRefs.ToArray());
        }
        private static void AddBullsharkLT(SimGameState s)
        {
            MechDef d = s.DataManager.MechDefs.Get("mechdef_bullshark_BSK-LT");

            d = new MechDef(d, s.GenerateSimGameUID(), true);
            d.SetInventory(d.Inventory.Where((x) => x.IsFixed || x.ComponentDefID.Equals("Ammo_AmmunitionBox_Generic_LongTom")).ToArray());
            int baySlot       = s.GetFirstFreeMechBay();
            int mechReadyTime = 625000; // about 50 days
            WorkOrderEntry_ReadyMech workOrderEntry_ReadyMech = new WorkOrderEntry_ReadyMech(string.Format("ReadyMech-{0}", d.GUID), string.Format("Readying 'Mech - {0}", new object[]
            {
                d.Chassis.Description.Name
            }), mechReadyTime, baySlot, d, string.Format(s.Constants.Story.MechReadiedWorkOrderCompletedText, new object[]
            {
                d.Chassis.Description.Name
            }));

            s.MechLabQueue.Add(workOrderEntry_ReadyMech);
            s.ReadyingMechs[baySlot] = d;
            s.RoomManager.AddWorkQueueEntry(workOrderEntry_ReadyMech);
            s.UpdateMechLabWorkQueue(false);
            AudioEventManager.PlayAudioEvent("audioeventdef_simgame_vo_barks", "workqueue_readymech", WwiseManager.GlobalAudioObject, null);
        }
Example #17
0
        public static bool ReadyVehicle(MechBayPanel __instance, MechBayChassisUnitElement chassisElement,
                                        ref MechBayChassisUnitElement ___selectedChassis, MechBayRowGroupWidget ___bayGroupWidget)
        {
            try
            {
                var chassisDef = chassisElement.ChassisDef;
                if (!chassisDef.IsVehicle())
                {
                    return(true);
                }

                var id      = chassisElement.ChassisDef.Description.Id;
                var sim     = __instance.Sim;
                int start   = sim.VehicleShift();
                int end     = start + sim.GetMaxActiveMechs();
                int baySlot = -1;
                for (int i = start; i < end; i++)
                {
                    MechDef mech_in_slot = null;
                    if (!sim.ActiveMechs.TryGetValue(i, out mech_in_slot))
                    {
                        sim.ReadyingMechs.TryGetValue(i, out mech_in_slot);
                    }
                    if (mech_in_slot == null)
                    {
                        baySlot = i;
                        break;
                    }
                }

                if (baySlot < 0)
                {
                    Control.Instance.LogDebug(DInfo.General, "No Free vehicle slots for {0}", id);
                    return(false);
                }

                var mid    = ChassisHandler.GetMDefFromCDef(id);
                var sim_id = sim.GenerateSimGameUID();
                var stock  = __instance.DataManager.MechDefs.Get(mid);
                var mech   = new MechDef(chassisDef, sim_id, stock);
                mech.SetInventory(stock.Inventory);


                WorkOrderEntry_ReadyMech workOrderEntry_ReadyMech = new WorkOrderEntry_ReadyMech(
                    string.Format("ReadyMech-{0}", sim_id), Strings.T("Readying 'Mech - {0}", new object[]
                {
                    chassisDef.Description.Name
                }), sim.Constants.Story.MechReadyTime, baySlot, mech, Strings.T(
                        sim.Constants.Story.MechReadiedWorkOrderCompletedText, new object[]
                {
                    chassisDef.Description.Name
                }));

                sim.MechLabQueue.Add(workOrderEntry_ReadyMech);
                sim.ReadyingMechs[baySlot] = mech;
                sim.RoomManager.AddWorkQueueEntry(workOrderEntry_ReadyMech);
                sim.UpdateMechLabWorkQueue(false);
                sim.RemoveItemStat(id, typeof(MechDef), false);

                AudioEventManager.PlayAudioEvent("audioeventdef_simgame_vo_barks", "workqueue_readymech",
                                                 WwiseManager.GlobalAudioObject, null);


                ___selectedChassis = null;
                __instance.RefreshData(true);
                __instance.ViewBays();
                __instance.SelectMech(___bayGroupWidget.GetMechUnitForSlot(baySlot), true);
            }
            catch (Exception e)
            {
                Control.Instance.LogError(e);
            }

            return(false);
        }
Example #18
0
        public void AutoFixMechDef(MechDef mechDef)
        {
            if (!AutoFixerFeature.settings.MechDefEngine)
            {
                return;
            }

            //DumpAllAsTable();
            if (mechDef.Inventory.Any(c => c.Def.GetComponent <EngineCoreDef>() != null))
            {
                return;
            }

            Control.mod.Logger.Log($"Auto fixing mechDef={mechDef.Description.Id} chassisDef={mechDef.Chassis.Description.Id}");

            ArmorStructureRatioFeature.Shared.AutoFixMechDef(mechDef);

            var builder             = new MechDefBuilder(mechDef.Chassis, mechDef.Inventory.ToList());
            var standardHeatSinkDef = mechDef.DataManager.GetDefaultEngineHeatSinkDef();
            var engineHeatSinkDef   = builder.Inventory
                                      .Select(r => r.Def.GetComponent <CoolingDef>())
                                      .Where(d => d != null)
                                      .Select(d => mechDef.DataManager.HeatSinkDefs.Get(d.HeatSinkDefId))
                                      .Where(d => d != null)
                                      .Select(d => d.GetComponent <EngineHeatSinkDef>())
                                      .FirstOrDefault() ?? standardHeatSinkDef;

            float freeTonnage;
            {
                float currentTotalTonnage = 0, maxValue = 0;
                MechStatisticsRules.CalculateTonnage(mechDef, ref currentTotalTonnage, ref maxValue);
                var maxFreeTonnage = mechDef.Chassis.Tonnage - currentTotalTonnage;

                var initialTonnage         = mechDef.Chassis.InitialTonnage;
                var originalInitialTonnage = ChassisHandler.GetOriginalInitialTonnage(mechDef.Chassis) ?? initialTonnage;
                var initialTonnageGain     = Mathf.Max(0, originalInitialTonnage - initialTonnage);
                if (AutoFixerFeature.settings.MechDefAutoFixAgainstMaxFreeTonnage.Contains(mechDef.Description.Id))
                {
                    freeTonnage = maxFreeTonnage;
                }
                else
                {
                    var freeTonnageThreshold = AutoFixerFeature.settings.MechDefAutoFixInitialTonnageDiffThreshold;
                    freeTonnage = Mathf.Min(maxFreeTonnage, initialTonnageGain + freeTonnageThreshold);
                }

                Control.mod.Logger.LogDebug($"freeTonnage={freeTonnage}" +
                                            $" currentTotalTonnage={currentTotalTonnage}" +
                                            $" maxFreeTonnage={maxFreeTonnage}" +
                                            $" initialTonnageGain={initialTonnageGain}" +
                                            $" initialGainSmaller={initialTonnageGain < maxFreeTonnage}");
            }

            //Control.mod.Logger.LogDebug("C maxEngineTonnage=" + maxEngineTonnage);
            var standardWeights   = new Weights(); // use default gyro and weights
            var standardHeatBlock = mechDef.DataManager.HeatSinkDefs.Get(AutoFixerFeature.settings.MechDefHeatBlockDef).GetComponent <EngineHeatBlockDef>();
            var standardCooling   = mechDef.DataManager.HeatSinkDefs.Get(AutoFixerFeature.settings.MechDefCoolingDef).GetComponent <CoolingDef>();

            var engineCoreDefs = mechDef.DataManager.HeatSinkDefs
                                 .Select(hs => hs.Value)
                                 .Select(hs => hs.GetComponent <EngineCoreDef>())
                                 .Where(c => c != null)
                                 .OrderByDescending(x => x.Rating);

            Engine maxEngine = null;

            {
                //var heatSinks = builder.Inventory.Where(x => x.ComponentDefType == ComponentType.HeatSink && x.Def.Is<EngineHeatSinkDef>()).ToList();
                var jumpJetList = builder.Inventory.Where(x => x.ComponentDefType == ComponentType.JumpJet).ToList();
                var engines     = new LinkedList <Engine>();

                foreach (var coreDef in engineCoreDefs)
                {
                    {
                        var engine = new Engine(standardCooling, standardHeatBlock, coreDef, standardWeights, new List <MechComponentRef>());
                        engines.AddFirst(engine);
                    }

                    {
                        // remove superfluous jump jets
                        var maxJetCount = coreDef.GetMovement(mechDef.Chassis.Tonnage).JumpJetCount;
                        //Control.mod.Logger.LogDebug($"before Inventory.Count={builder.Inventory.Count} jumpJetList.Count={jumpJetList.Count} maxJetCount={maxJetCount}");
                        while (jumpJetList.Count > maxJetCount)
                        {
                            var lastIndex = jumpJetList.Count - 1;
                            var jumpJet   = jumpJetList[lastIndex];
                            freeTonnage += jumpJet.Def.Tonnage;
                            builder.Remove(jumpJet);
                            jumpJetList.Remove(jumpJet);
                        }
                        //Control.mod.Logger.LogDebug($"after Inventory.Count={builder.Inventory.Count} jumpJetList.Count={jumpJetList.Count} maxJetCount={maxJetCount}");
                    }

                    foreach (var engine in engines)
                    {
//                        Control.mod.Logger.LogDebug($"D engine={engine.CoreDef} engine.TotalTonnage={engine.TotalTonnage} freeTonnage={freeTonnage}");

                        if (engine.TotalTonnage <= freeTonnage)
                        {
                            maxEngine = engine;
                        }
                        else
                        {
                            break;
                        }
                    }
                    if (maxEngine != null)
                    {
                        break;
                    }
                }
            }

            if (maxEngine == null)
            {
                return;
            }

            Control.mod.Logger.LogDebug($" maxEngine={maxEngine.CoreDef} freeTonnage={freeTonnage}");
            {
                var dummyCore = builder.Inventory.FirstOrDefault(r => r.ComponentDefID == AutoFixerFeature.settings.MechDefCoreDummy);
                if (dummyCore != null)
                {
                    builder.Remove(dummyCore);
                }
            }

            // add engine
            builder.Add(maxEngine.CoreDef.Def, ChassisLocations.CenterTorso, true);

            if (!EngineFeature.settings.AllowMixingHeatSinkTypes)
            {
                // remove incompatible heat sinks
                var incompatibleHeatSinks = builder.Inventory
                                            .Where(r => r.Def.Is <EngineHeatSinkDef>(out var hs) && hs.HSCategory != engineHeatSinkDef.HSCategory)
                                            .ToList();
                foreach (var incompatibleHeatSink in incompatibleHeatSinks)
                {
                    builder.Remove(incompatibleHeatSink);
                }

                //Control.mod.Logger.LogDebug($"Inventory.Count={builder.Inventory.Count} incompatibleHeatSinks.Count={incompatibleHeatSinks.Count}");
                // add same amount of compatible heat sinks
                foreach (var unused in incompatibleHeatSinks)
                {
                    builder.Add(engineHeatSinkDef.Def);
                }

                //Control.mod.Logger.LogDebug($"Inventory.Count={builder.Inventory.Count}");
            }

            // add free heatsinks
            {
                //var maxFree = maxEngine.CoreDef.ExternalHeatSinksFreeMaxCount;
                //var current = maxEngine.ExternalHeatSinkCount;
                var maxFree = maxEngine.HeatSinkExternalFreeMaxCount;
                var current = 0; //we assume exiting heatsinks on the mech are additional and not free
                for (var i = current; i < maxFree; i++)
                {
                    if (!builder.Add(engineHeatSinkDef.Def))
                    {
                        break;
                    }
                }
                //Control.mod.Logger.LogDebug($"Inventory.Count={builder.Inventory.Count} maxFree={maxFree}");
            }

            // find any overused location
            if (builder.HasOveruseAtAnyLocation())
            {
                // heatsinks, upgrades
                var itemsToBeReordered = builder.Inventory
                                         .Where(IsReorderable)
                                         .OrderBy(c => MechDefBuilder.LocationCount(c.Def.AllowedLocations))
                                         .ThenByDescending(c => c.Def.InventorySize)
                                         .ThenByDescending(c =>
                {
                    switch (c.ComponentDefType)
                    {
                    case ComponentType.Upgrade:
                        return(2);

                    case ComponentType.AmmunitionBox:
                        return(1);

                    default:
                        return(0);
                    }
                })
                                         .ToList();

                // remove all items that can be reordered: heatsinks, upgrades
                foreach (var item in itemsToBeReordered)
                {
                    builder.Remove(item);
                }

                // then add most restricting, and then largest items first (probably double head sinks)
                foreach (var item in itemsToBeReordered)
                {
                    // couldn't add everything
                    if (!builder.Add(item.Def))
                    {
                        return;
                    }
                }
            }

            mechDef.SetInventory(builder.Inventory.OrderBy(element => element, new OrderComparer()).ToArray());

            //{
            //    float currentTotalTonnage = 0, maxValue = 0;
            //    MechStatisticsRules.CalculateTonnage(mechDef, ref currentTotalTonnage, ref maxValue);
            //    Control.mod.Logger.LogDebug($" end currentTotalTonnage={currentTotalTonnage} mechDef.Chassis.Tonnage={mechDef.Chassis.Tonnage}");
            //}
        }
Example #19
0
        public void AutoFixMechDef(MechDef mechDef, float originalTotalTonnage)
        {
            if (mechDef.Inventory.Any(c => c.Def.GetComponent <EngineCoreDef>() != null))
            {
                return;
            }

            float freeTonnage;
            {
                float currentTotalTonnage = 0, maxValue = 0;
                MechStatisticsRules.CalculateTonnage(mechDef, ref currentTotalTonnage, ref maxValue);

                var originalInitialTonnage = ChassisHandler.GetOriginalTonnage(mechDef.Chassis);
                if (originalInitialTonnage.HasValue) // either use the freed up tonnage from the initial tonnage fix
                {
                    freeTonnage  = originalInitialTonnage.Value - mechDef.Chassis.InitialTonnage;
                    freeTonnage -= currentTotalTonnage - originalTotalTonnage;
                }

                else // or use up available total tonnage
                {
                    freeTonnage = mechDef.Chassis.Tonnage - currentTotalTonnage;
                }
            }

            var maxEngine = (Engine)null;

            //Control.mod.Logger.LogDebug("C maxEngineTonnage=" + maxEngineTonnage);

            var standardEngineType  = mechDef.DataManager.HeatSinkDefs.Get(Control.settings.AutoFixMechDefEngineTypeDef).GetComponent <EngineType>();
            var standardHeatSinkDef = mechDef.DataManager.GetDefaultEngineHeatSinkDef();

            var engineHeatSinkdef = mechDef.Inventory
                                    .Select(r => r.Def.GetComponent <EngineHeatSink>())
                                    .FirstOrDefault(d => d != null && d != standardHeatSinkDef) ?? standardHeatSinkDef;

            foreach (var keyvalue in mechDef.DataManager.HeatSinkDefs)
            {
                var heatSinkDef = keyvalue.Value;

                var coreDef = heatSinkDef.GetComponent <EngineCoreDef>();
                if (coreDef == null)
                {
                    continue;
                }

                var coreRef = new EngineCoreRef(engineHeatSinkdef, coreDef);
                var engine  = new Engine(coreRef, standardEngineType, Enumerable.Empty <MechComponentRef>());
                if (engine.TotalTonnage > freeTonnage)
                {
                    continue;
                }

                if (maxEngine != null && maxEngine.CoreDef.Rating >= coreDef.Rating)
                {
                    continue;
                }

                maxEngine = engine;
            }

            if (maxEngine == null)
            {
                return;
            }

            // Control.mod.Logger.LogDebug("D maxEngine=" + maxEngine.CoreDef);

            var componentRefs = new List <MechComponentRef>(mechDef.Inventory);

            {
                // remove superfluous jump jets
                var maxJetCount = maxEngine.CoreDef.GetMovement(mechDef.Chassis.Tonnage).JumpJetCount;
                var jumpJetList = componentRefs.Where(x => x.ComponentDefType == ComponentType.JumpJet).ToList();
                for (var i = 0; i < jumpJetList.Count - maxJetCount; i++)
                {
                    componentRefs.Remove(jumpJetList[i]);
                }
            }

            var builder = new MechDefBuilder(mechDef.Chassis, componentRefs);

            // add engine
            builder.Add(
                maxEngine.CoreDef.Def,
                ChassisLocations.CenterTorso,
                engineHeatSinkdef != standardHeatSinkDef ? "/ihstype=" + engineHeatSinkdef.Def.Description.Id : null
                );

            // add standard shielding
            builder.Add(standardEngineType.Def, ChassisLocations.CenterTorso);

            // add free heatsinks
            {
                var count = 0;
                while (count < maxEngine.CoreDef.MaxFreeExternalHeatSinks)
                {
                    if (builder.Add(engineHeatSinkdef.Def))
                    {
                        count++;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            mechDef.SetInventory(componentRefs.ToArray());
        }
Example #20
0
        public void AutoFixMechDef(MechDef mechDef)
        {
            if (!AutoFixerFeature.settings.MechDefEngine)
            {
                return;
            }

            if (!AutoFixerFeature.settings.MechTagsAutoFixEnabled.Any(mechDef.MechTags.Contains))
            {
                return;
            }

            Control.mod.Logger.Log($"Auto fixing mechDef={mechDef.Description.Id} chassisDef={mechDef.Chassis.Description.Id}");

            MechDefBuilder builder;

            {
                var inventory = mechDef.Inventory.ToList();
                foreach (var componentRef in inventory)
                {
                    Control.mod.Logger.LogDebug($" {componentRef.ComponentDefID}{(componentRef.IsFixed?" (fixed)":"")} at {componentRef.MountedLocation}");
                }

                builder = new MechDefBuilder(mechDef.Chassis, inventory);
            }

            ArmorStructureRatioFeature.Shared.AutoFixMechDef(mechDef);

            var res = EngineSearcher.SearchInventory(builder.Inventory);

            var engineHeatSinkDef = mechDef.DataManager.HeatSinkDefs.Get(res.CoolingDef.HeatSinkDefId).GetComponent <EngineHeatSinkDef>();

            float CalcFreeTonnage()
            {
                float currentTotalTonnage = 0, maxValue = 0;

                MechStatisticsRules.CalculateTonnage(mechDef, ref currentTotalTonnage, ref maxValue);
                var freeTonnage = mechDef.Chassis.Tonnage - currentTotalTonnage;

                return(freeTonnage);
            }

            if (!EngineFeature.settings.AllowMixingHeatSinkTypes)
            {
                // remove incompatible heat sinks
                var incompatibleHeatSinks = builder.Inventory
                                            .Where(r => r.Def.Is <EngineHeatSinkDef>(out var hs) && hs.HSCategory != engineHeatSinkDef.HSCategory)
                                            .ToList();

                foreach (var incompatibleHeatSink in incompatibleHeatSinks)
                {
                    builder.Remove(incompatibleHeatSink);
                    builder.Add(engineHeatSinkDef.Def, ChassisLocations.Head, true);
                }
            }

            Engine engine = null;

            if (res.CoreDef != null)
            {
                engine = new Engine(res.CoolingDef, res.HeatBlockDef, res.CoreDef, res.Weights, new List <MechComponentRef>());

                // convert external heat sinks into internal ones
                // TODO only to make space if needed, drop the rest of the heat sinks

                {
                    var max     = engine.HeatSinkInternalAdditionalMaxCount;
                    var current = engine.EngineHeatBlockDef.HeatSinkCount;

                    var heatSinks = builder.Inventory
                                    .Where(r => r.Def.Is <EngineHeatSinkDef>(out var hs) && hs.HSCategory == engineHeatSinkDef.HSCategory)
                                    .ToList();

                    while (current < max && heatSinks.Count > 0)
                    {
                        var component = heatSinks[0];
                        heatSinks.RemoveAt(0);
                        builder.Remove(component);
                        current++;
                    }

                    if (current > 0)
                    {
                        var heatBlock = builder.Inventory.FirstOrDefault(r => r.Def.Is <EngineHeatBlockDef>());
                        if (heatBlock != null)
                        {
                            builder.Remove(heatBlock);
                        }

                        var heatBlockDefId = $"{AutoFixerFeature.settings.MechDefHeatBlockDef}_{current}";
                        var def            = mechDef.DataManager.HeatSinkDefs.Get(heatBlockDefId);
                        builder.Add(def, ChassisLocations.CenterTorso, true);
                    }
                }
            }
            else
            {
                var freeTonnage = CalcFreeTonnage();

                Control.mod.Logger.LogDebug($" find engine for freeTonnage={freeTonnage}");

                var jumpJets       = builder.Inventory.Where(x => x.ComponentDefType == ComponentType.JumpJet).ToList();
                var jumpJetTonnage = jumpJets.Select(x => x.Def.Tonnage).FirstOrDefault(); //0 if no jjs

                var externalHeatSinks = builder.Inventory
                                        .Where(r => r.Def.Is <EngineHeatSinkDef>(out var hs) && hs.HSCategory == engineHeatSinkDef.HSCategory)
                                        .ToList();
                var internalHeatSinksCount = res.HeatBlockDef.HeatSinkCount;

                var engineCandidates = new List <Engine>();

                var engineCoreDefs = mechDef.DataManager.HeatSinkDefs
                                     .Select(hs => hs.Value)
                                     .Select(hs => hs.GetComponent <EngineCoreDef>())
                                     .Where(c => c != null)
                                     .OrderByDescending(x => x.Rating);

                var removedExternalHeatSinksOverUse = false;

                foreach (var coreDef in engineCoreDefs)
                {
                    {
                        // remove superfluous jump jets
                        var maxJetCount = coreDef.GetMovement(mechDef.Chassis.Tonnage).JumpJetCount;
                        while (jumpJets.Count > maxJetCount)
                        {
                            var lastIndex = jumpJets.Count - 1;
                            var jumpJet   = jumpJets[lastIndex];
                            freeTonnage += jumpJet.Def.Tonnage;
                            builder.Remove(jumpJet);
                            jumpJets.Remove(jumpJet);

                            Control.mod.Logger.LogDebug("  Removed JumpJet");
                        }
                    }

                    {
                        var candidate = new Engine(res.CoolingDef, res.HeatBlockDef, coreDef, res.Weights, new List <MechComponentRef>());

                        Control.mod.Logger.LogDebug($"  candidate id={coreDef.Def.Description.Id} TotalTonnage={candidate.TotalTonnage}");

                        engineCandidates.Add(candidate);

                        var internalHeatSinksMax = candidate.HeatSinkInternalAdditionalMaxCount;

                        // convert external ones to internal ones
                        while (internalHeatSinksCount < internalHeatSinksMax && externalHeatSinks.Count > 0)
                        {
                            var component = externalHeatSinks[0];
                            externalHeatSinks.RemoveAt(0);
                            builder.Remove(component);
                            internalHeatSinksCount++;

                            Control.mod.Logger.LogDebug("  ~Converted external to internal");
                        }

                        // this only runs on the engine that takes the most heat sinks (since this is in a for loop with rating descending order)
                        // that way we only remove external heat sinks that couldn't be moved internally
                        while (!removedExternalHeatSinksOverUse && externalHeatSinks.Count > 0)
                        {
                            var component = externalHeatSinks[0];
                            externalHeatSinks.RemoveAt(0);
                            builder.Remove(component);
                            var newComponent = builder.Add(component.Def);
                            if (newComponent == null)
                            {
                                Control.mod.Logger.LogDebug("  Removed external heat sink that doesn't fit");
                                // might still need to remove some
                                continue;
                            }
                            // addition worked
                            externalHeatSinks.Add(newComponent);
                            break;
                        }
                        removedExternalHeatSinksOverUse = true;

                        // convert internal ones to external ones
                        while (internalHeatSinksCount > internalHeatSinksMax)
                        {
                            if (builder.Add(engineHeatSinkDef.Def) == null)
                            {
                                Control.mod.Logger.LogDebug("  ~Dropped external when converting from internal");
                                freeTonnage++;
                            }
                            else
                            {
                                Control.mod.Logger.LogDebug("  ~Converted internal to external");
                            }
                            internalHeatSinksCount--;
                        }

                        // remove candidates that make no sense anymore
                        // TODO not perfect and maybe too large for small mechs
                        engineCandidates = engineCandidates.Where(x => x.TotalTonnage <= freeTonnage + 6 * engineHeatSinkDef.Def.Tonnage + jumpJetTonnage).ToList();
                    }

                    // go through all candidates, larger first
                    engine = engineCandidates.FirstOrDefault(candidate => candidate.TotalTonnage <= freeTonnage);

                    if (engine != null)
                    {
                        break;
                    }
                }

                if (engine != null)
                {
                    Control.mod.Logger.LogDebug($" engine={engine.CoreDef} freeTonnage={freeTonnage}");
                    var dummyCore = builder.Inventory.FirstOrDefault(r => r.ComponentDefID == AutoFixerFeature.settings.MechDefCoreDummy);
                    builder.Remove(dummyCore);
                    builder.Add(engine.CoreDef.Def, ChassisLocations.CenterTorso, true);

                    // convert internal heat sinks back as external ones if the mech can fit it
                    while (internalHeatSinksCount > 0 && builder.Add(engineHeatSinkDef.Def) != null)
                    {
                        internalHeatSinksCount--;
                    }

                    if (internalHeatSinksCount > 0)
                    {
                        var heatBlock = builder.Inventory.FirstOrDefault(r => r.Def.Is <EngineHeatBlockDef>());
                        if (heatBlock != null)
                        {
                            builder.Remove(heatBlock);
                        }

                        var heatBlockDefId = $"{AutoFixerFeature.settings.MechDefHeatBlockDef}_{internalHeatSinksCount}";
                        var def            = mechDef.DataManager.HeatSinkDefs.Get(heatBlockDefId);
                        builder.Add(def, ChassisLocations.CenterTorso, true);
                    }
                }
            }

            if (engine == null)
            {
                return;
            }

            // add free heat sinks
            {
                var max = engine.HeatSinkExternalFreeMaxCount;
                for (var i = 0; i < max; i++)
                {
                    builder.Add(engineHeatSinkDef.Def, ChassisLocations.Head, true);
                }
            }

            // find any overused location
            if (builder.HasOveruseAtAnyLocation())
            {
                Control.mod.Logger.LogError($" Overuse found");
                // heatsinks, upgrades
                var itemsToBeReordered = builder.Inventory
                                         .Where(IsMovable)
                                         .OrderBy(c => MechDefBuilder.LocationCount(c.Def.AllowedLocations))
                                         .ThenByDescending(c => c.Def.InventorySize)
                                         .ToList();

                // remove all items that can be reordered: heatsinks, upgrades
                foreach (var item in itemsToBeReordered)
                {
                    builder.Remove(item);
                }

                // then add most restricting, and then largest items first (probably double head sinks)
                foreach (var item in itemsToBeReordered)
                {
                    if (builder.Add(item.Def) == null)
                    {
                        Control.mod.Logger.LogError($" Component {item.ComponentDefID} from {item.MountedLocation} can't be re-added");
                    }
                    else
                    {
                        Control.mod.Logger.LogDebug($"  Component {item.ComponentDefID} re-added");
                    }
                }
            }

            mechDef.SetInventory(builder.Inventory.OrderBy(element => element, new OrderComparer()).ToArray());

            {
                var freeTonnage = CalcFreeTonnage();
                if (freeTonnage > 0)
                {
                    // TODO add armor for each location with free tonnage left
                }
                else if (freeTonnage < 0)
                {
                    var removableItems = builder.Inventory
                                         .Where(IsRemovable)
                                         .OrderBy(c => c.Def.Tonnage)
                                         .ThenByDescending(c => c.Def.InventorySize)
                                         .ThenByDescending(c =>
                    {
                        switch (c.ComponentDefType)
                        {
                        case ComponentType.HeatSink:
                            return(2);

                        case ComponentType.JumpJet:
                            return(1);

                        default:
                            return(0);
                        }
                    })
                                         .ToList();

                    while (removableItems.Count > 0 && freeTonnage < 0)
                    {
                        var item = removableItems[0];
                        removableItems.RemoveAt(0);
                        freeTonnage += item.Def.Tonnage;
                        builder.Remove(item);
                    }
                }
            }

            mechDef.SetInventory(builder.Inventory.OrderBy(element => element, new OrderComparer()).ToArray());
        }
Example #21
0
        public void OnInstalled(WorkOrderEntry_InstallComponent order, SimGameState state, MechDef mech)
        {
            Control.LogDebug(DType.ComponentInstall, $"- Category");
            if (order.PreviousLocation != ChassisLocations.None)
            {
                Control.LogDebug(DType.ComponentInstall, "-- removing");
                MechComponentRef def_replace = DefaultFixer.Shared.GetReplaceFor(mech, CategoryID, order.PreviousLocation, state);
                if (def_replace != null)
                {
                    Control.LogDebug(DType.ComponentInstall, $"--- added {def_replace.ComponentDefID}");
                    var inv = mech.Inventory.ToList();
                    inv.Add(def_replace);
                    mech.SetInventory(inv.ToArray());
                }
            }

            if (order.DesiredLocation == ChassisLocations.None)
            {
                return;
            }

            if (!CategoryDescriptor.AutoReplace || CategoryDescriptor.MaxEquiped < 0 && CategoryDescriptor.MaxEquipedPerLocation < 0)
            {
                Control.LogDebug(DType.ComponentInstall, $"-- {CategoryDescriptor.DisplayName} r:{CategoryDescriptor.AutoReplace}  max:{CategoryDescriptor.MaxEquiped} mpr:{CategoryDescriptor.MaxEquipedPerLocation} = not requre replace");

                return;
            }


            int n1 = mech.Inventory.Count(i => i.IsCategory(CategoryID));
            int n2 = mech.Inventory.Count(i => i.MountedLocation == order.DesiredLocation && i.IsCategory(CategoryID));

#if CCDEBUG
            if (Control.Settings.DebugInfo.HasFlag(DType.ComponentInstall))
            {
                Control.LogDebug(DType.ComponentInstall, "--- list:");
                foreach (var def in mech.Inventory
                         .Where(i => i.MountedLocation == order.DesiredLocation && i.IsCategory(CategoryID))
                         .Select(i => i.Def))
                {
                    Control.LogDebug(DType.ComponentInstall,
                                     $"---- list: {def.Description.Id}: Default:{def.IsDefault()}");
                }
            }
#endif

            Control.LogDebug(DType.ComponentInstall, $"-- total {n1}/{CategoryDescriptor.MaxEquiped}  location: {n2}/{CategoryDescriptor.MaxEquipedPerLocation}");

            var replace = mech.Inventory.FirstOrDefault(i => !i.IsModuleFixed(mech) && (i.MountedLocation == order.DesiredLocation || CategoryDescriptor.ReplaceAnyLocation) && i.IsCategory(CategoryID) && i.IsDefault());

            Control.LogDebug(DType.ComponentInstall, $"-- possible replace: {(replace == null ? "not found" : replace.ComponentDefID)}");

            if (replace == null)
            {
                return;
            }

            bool need_replace = (CategoryDescriptor.MaxEquiped > 0 && n1 > CategoryDescriptor.MaxEquiped) ||
                                (CategoryDescriptor.MaxEquipedPerLocation > 0 && n2 > CategoryDescriptor.MaxEquipedPerLocation);

            Control.LogDebug(DType.ComponentInstall, $"-- need_repalce: {need_replace}");

            if (need_replace)
            {
                DefaultHelper.RemoveInventory(replace.ComponentDefID, mech, replace.MountedLocation, replace.ComponentDefType);
            }
        }
Example #22
0
        void process_default(MechDef mechDef, IDefault def, SimGameState state)
        {
            string id = GetID(def);

            for (int i = 0; i < num_changed; i++)
            {
                if (changed_deafult[i] == id)
                {
#if CCDEBUG
                    Control.LogDebug(DType.AutoFix, $"---- {def.CategoryID}: already changed");
#endif
                    return;
                }
            }

            var component = def.AnyLocation
                ? mechDef.Inventory.FirstOrDefault(i => i.IsCategory(def.CategoryID))
                : mechDef.Inventory.FirstOrDefault(i =>
                                                   i.IsCategory(def.CategoryID) && def.Location == i.MountedLocation);



            if (component != null)
            {
                if (!component.IsDefault())
                {
#if CCDEBUG
                    Control.LogDebug(DType.AutoFix, $"---- {def.CategoryID}: Found not default {component.ComponentDefID}, skiped");
#endif
                }
                else if (component.IsModuleFixed(mechDef))
                {
#if CCDEBUG
                    Control.LogDebug(DType.AutoFix, $"---- {def.CategoryID}: Found fixed {component.ComponentDefID}, skiped");
#endif
                }
                else if (def.NeedReplaceExistDefault(mechDef, component))
                {
#if CCDEBUG
                    Control.LogDebug(DType.AutoFix, $"---- {def.CategoryID}: Found wrong default {component.ComponentDefID}, replacing with {def}");
#endif
                    var inventory = mechDef.Inventory.ToList();
                    inventory.Remove(component);
                    inventory.Add(def.GetReplace(mechDef, state));
                    mechDef.SetInventory(inventory.ToArray());
                }
                else
                {
#if CCDEBUG
                    Control.LogDebug(DType.AutoFix, $"---- {def.CategoryID}: Found exist default {component.ComponentDefID}, marks as installed");
#endif
                }
                set_changed(id);
            }
            else
            {
#if CCDEBUG
                Control.LogDebug(DType.AutoFix, $"---- {def.CategoryID}: not found, adding {def} to {def.Location}");
#endif
                if (def.AddItems(mechDef, state))
                {
                    set_changed(id);
                }
            }
        }
Example #23
0
        private static void add_full_actuators(MechDef mechdef)
        {
            void process_location(ChassisLocations location)
            {
                var total_slots = mechdef.Inventory.Where(i => i.MountedLocation == location && i.Is <ArmActuator>())
                                  .Select(i => i.GetComponent <ArmActuator>())
                                  .Aggregate(ArmActuatorSlot.None, (current, item) => current | item.Type);

                //if not present any actuators
                if (total_slots == ArmActuatorSlot.None)
                {
                    //add shoulder, and upper
                    AddDefaultToInventory(mechdef, null, location, ArmActuatorSlot.PartShoulder, ref total_slots);
                    AddDefaultToInventory(mechdef, null, location, ArmActuatorSlot.PartUpper, ref total_slots);

                    //get max avaliable actuator
                    ArmActuatorSlot max = mechdef.Chassis.Is <ArmActuatorSupport>(out var support) ?
                                          support.GetLimit(location) :
                                          ArmActuatorSlot.PartHand;

                    foreach (var item in mechdef.Inventory.Where(i => i.MountedLocation == location &&
                                                                 i.Is <ArmActuator>()).Select(i => i.GetComponent <ArmActuator>()))
                    {
                        if (item.MaxSlot < max)
                        {
                            max = item.MaxSlot;
                        }
                    }

                    var builder = new MechDefBuilder(mechdef);
                    if (max >= ArmActuatorSlot.PartLower && !total_slots.HasFlag(ArmActuatorSlot.PartLower))
                    {
                        var def = UnityGameInstance.BattleTechGame.DataManager.UpgradeDefs.Get(ArmActuatorFeature.settings.DefaultCBTLower);
                        if (def == null)
                        {
                            return;
                        }
                        if (!builder.Add(def, location))
                        {
                            return;
                        }
                    }

                    if (max >= ArmActuatorSlot.PartHand && !total_slots.HasFlag(ArmActuatorSlot.PartHand))
                    {
                        var def = UnityGameInstance.BattleTechGame.DataManager.UpgradeDefs.Get(ArmActuatorFeature.settings.DefaultCBTHand);
                        builder.Add(def, location);
                    }
                    mechdef.SetInventory(builder.Inventory.ToArray());
                }
                else
                {
                    //recheck and add if needed shoulder and arm
                    AddDefaultToInventory(mechdef, null, location, ArmActuatorSlot.PartShoulder, ref total_slots);
                    AddDefaultToInventory(mechdef, null, location, ArmActuatorSlot.PartUpper, ref total_slots);
                }
            }

            process_location(ChassisLocations.RightArm);
            process_location(ChassisLocations.LeftArm);
        }
Example #24
0
        public void AutoFixMechDef(MechDef mechDef, float originalTotalTonnage)
        {
            if (mechDef.Inventory.Any(c => c.Def.GetComponent <EngineCoreDef>() != null))
            {
                return;
            }

            var inventory           = new List <MechComponentRef>(mechDef.Inventory);
            var standardHeatSinkDef = mechDef.DataManager.GetDefaultEngineHeatSinkDef();
            var engineHeatSinkDef   = inventory
                                      .Select(r => r.Def.GetComponent <EngineHeatSink>())
                                      .FirstOrDefault(d => d != null && d != standardHeatSinkDef) ?? standardHeatSinkDef;

            if (!Control.settings.AllowMixingHeatSinkTypes)
            {
                // remove incompatible heat sinks
                inventory.RemoveAll(r => r.Def.Is <EngineHeatSink>(out var engineHeatSink) && engineHeatSink.HSCategory != engineHeatSinkDef.HSCategory);
            }

            float freeTonnage;
            {
                float currentTotalTonnage = 0, maxValue = 0;
                MechStatisticsRules.CalculateTonnage(mechDef, ref currentTotalTonnage, ref maxValue);

                var originalInitialTonnage = ChassisHandler.GetOriginalTonnage(mechDef.Chassis);
                if (originalInitialTonnage.HasValue) // either use the freed up tonnage from the initial tonnage fix
                {
                    freeTonnage  = originalInitialTonnage.Value - mechDef.Chassis.InitialTonnage;
                    freeTonnage -= currentTotalTonnage - originalTotalTonnage;
                }

                else // or use up available total tonnage
                {
                    freeTonnage = mechDef.Chassis.Tonnage - currentTotalTonnage;
                }
            }

            //Control.mod.Logger.LogDebug("C maxEngineTonnage=" + maxEngineTonnage);
            var standardWeights   = new Weights(); // use default gyro and weights
            var stanardEngineType = mechDef.DataManager.HeatSinkDefs.Get(Control.settings.AutoFixMechDefEngineTypeDef);

            var engineCoreDefs = mechDef.DataManager.HeatSinkDefs
                                 .Select(hs => hs.Value)
                                 .Select(hs => hs.GetComponent <EngineCoreDef>())
                                 .Where(c => c != null)
                                 .OrderByDescending(x => x.Rating);

            var maxEngine = engineCoreDefs
                            .Select(coreDef => new EngineCoreRef(engineHeatSinkDef, coreDef))
                            .Select(coreRef => new Engine(coreRef, standardWeights, Enumerable.Empty <MechComponentRef>()))
                            .FirstOrDefault(engine => !(engine.TotalTonnage > freeTonnage));

            if (maxEngine == null)
            {
                return;
            }

            // Control.mod.Logger.LogDebug("D maxEngine=" + maxEngine.CoreDef);

            {
                // remove superfluous jump jets
                var maxJetCount = maxEngine.CoreDef.GetMovement(mechDef.Chassis.Tonnage).JumpJetCount;
                var jumpJetList = inventory.Where(x => x.ComponentDefType == ComponentType.JumpJet).ToList();
                for (var i = 0; i < jumpJetList.Count - maxJetCount; i++)
                {
                    inventory.Remove(jumpJetList[i]);
                }
            }

            var builder = new MechDefBuilder(mechDef.Chassis, inventory);

            // add engine
            builder.Add(
                maxEngine.CoreDef.Def,
                ChassisLocations.CenterTorso,
                engineHeatSinkDef != standardHeatSinkDef ? "/ihstype=" + engineHeatSinkDef.Def.Description.Id : null
                );

            // add standard shielding
            builder.Add(stanardEngineType, ChassisLocations.CenterTorso);

            // add free heatsinks
            {
                var count = 0;
                while (count < maxEngine.CoreDef.MaxFreeExternalHeatSinks)
                {
                    if (builder.Add(engineHeatSinkDef.Def))
                    {
                        count++;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            mechDef.SetInventory(inventory.ToArray());
        }
Example #25
0
        internal static void AddEngineIfPossible(MechDef mechDef)
        {
            if (!Control.settings.AutoFixMechDefEngine)
            {
                return;
            }

            //Control.mod.Logger.LogDebug("A Id=" + mechDef.Description.Id);

            mechDef.Refresh();

            //Control.mod.Logger.LogDebug("B DataManager=" + mechDef.DataManager);

            if (mechDef.Inventory.Any(x => x.GetEngineRef() != null))
            {
                return;
            }

            float currentValue = 0, maxValue = 0;

            MechStatisticsRules.CalculateTonnage(mechDef, ref currentValue, ref maxValue);

            var tonnage          = mechDef.Chassis.Tonnage;
            var maxEngineTonnage = tonnage - currentValue;
            var maxEngine        = (EngineDef)null;

            //Control.mod.Logger.LogDebug("C maxEngineTonnage=" + maxEngineTonnage);

            foreach (var keyvalue in mechDef.DataManager.HeatSinkDefs)
            {
                var heatSinkDef = keyvalue.Value;

                if (heatSinkDef.Tonnage > maxEngineTonnage)
                {
                    continue;
                }

                var engineDef = heatSinkDef.GetEngineDef();
                if (engineDef == null)
                {
                    continue;
                }

                if (engineDef.Type != EngineDef.EngineType.Std)
                {
                    continue;
                }

                if (maxEngine != null && maxEngine.Rating >= engineDef.Rating)
                {
                    continue;
                }

                maxEngine = engineDef;
            }

            //Control.mod.Logger.LogDebug("D maxEngine=" + maxEngine);

            if (maxEngine == null)
            {
                return;
            }

            var componentRefs = new List <MechComponentRef>(mechDef.Inventory);

            { // remove superfluous jump jets
                var maxJetCount = Control.calc.CalcJumpJetCount(maxEngine, tonnage);
                var jumpJetList = componentRefs.Where(x => x.ComponentDefType == ComponentType.JumpJet).ToList();
                for (var i = 0; i < jumpJetList.Count - maxJetCount; i++)
                {
                    componentRefs.Remove(jumpJetList[i]);
                }
            }

            { // add engine
                var componentRef = new MechComponentRef(maxEngine.Def.Description.Id, null, maxEngine.Def.ComponentType, ChassisLocations.CenterTorso);
                componentRefs.Add(componentRef);
            }

            mechDef.SetInventory(componentRefs.ToArray());
        }
        public void AutoFixMechDef(MechDef mechDef, float originalTotalTonnage)
        {
            var builder = new MechDefBuilder(mechDef.Chassis, mechDef.Inventory.ToList());

            // find any overused location
            if (!builder.HasOveruse())
            {
                return;
            }

            // heatsinks, upgrades
            var itemsToBeReordered = mechDef.Inventory
                                     .Where(c => IsReorderable(c.Def))
                                     .OrderBy(c => MechDefBuilder.LocationCount(c.Def.AllowedLocations))
                                     .ThenByDescending(c => c.Def.InventorySize)
                                     .ThenByDescending(c =>
            {
                switch (c.ComponentDefType)
                {
                case ComponentType.Upgrade:
                    return(2);

                case ComponentType.AmmunitionBox:
                    return(1);

                default:
                    return(0);
                }
            })
                                     .ToList();

            // remove all items that can be reordered: heatsinks, upgrades
            foreach (var item in itemsToBeReordered)
            {
                builder.Remove(item);
            }

            // then add most restricting, and then largest items first (probably double head sinks)
            foreach (var item in itemsToBeReordered)
            {
                // couldn't add everything
                if (!builder.Add(item.Def))
                {
                    return;
                }
            }

            // if reorder does not work perfectly, ignore
            if (builder.HasOveruse())
            {
                return;
            }

            // save
            mechDef.SetInventory(builder.Inventory.ToArray());

            //Control.mod.Logger.LogDebug($"Name={mechDef.Name} ChassisID={mechDef.ChassisID}");
            foreach (var item in mechDef.Inventory)
            {
                //Control.mod.Logger.LogDebug($" ComponentDefID={item.ComponentDefID} MountedLocation={item.MountedLocation}");
            }
        }