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()); }
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()); } }
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()); } }
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()); }
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()); }
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); }
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()); }
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()); }
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); }
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); }
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}"); //} }
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()); }
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()); }
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); } }
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); } } }
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); }
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()); }
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}"); } }