diff --git a/Yafc.Model/Data/DataClasses.cs b/Yafc.Model/Data/DataClasses.cs index acbff2a1..5e28fad0 100644 --- a/Yafc.Model/Data/DataClasses.cs +++ b/Yafc.Model/Data/DataClasses.cs @@ -414,8 +414,8 @@ public class Entity : FactorioObject { public float basePower { get; internal set; } public float Power(Quality quality) => factorioType is "boiler" or "reactor" or "generator" or "burner-generator" ? quality.ApplyStandardBonus(basePower) + : factorioType is "beacon" ? basePower * quality.BeaconConsumptionFactor : basePower; - public EntityEnergy energy { get; internal set; } = null!; // TODO: Prove that this is always properly initialized. (Do we need an EntityWithEnergy type?) public Item[] itemsToPlace { get; internal set; } = null!; // null-forgiving: This is initialized in CalculateMaps. public int size { get; internal set; } @@ -531,6 +531,11 @@ public override void GetDependencies(IDependencyCollector collector, List MathF.Floor(ApplyStandardBonus(baseValue) * 100) / 100; // applies the .2 per level beacon transmission bonus internal float ApplyBeaconBonus(float baseValue) => baseValue + level * .2f; + + public float StandardBonus => .3f * level; + public float AccumulatorCapacityBonus => level; + public float BeaconTransmissionBonus => .2f * level; + public float BeaconConsumptionFactor { get; internal set; } } /// diff --git a/Yafc.Parser/Data/FactorioDataDeserializer_RecipeAndTechnology.cs b/Yafc.Parser/Data/FactorioDataDeserializer_RecipeAndTechnology.cs index 2d875bc3..072fee75 100644 --- a/Yafc.Parser/Data/FactorioDataDeserializer_RecipeAndTechnology.cs +++ b/Yafc.Parser/Data/FactorioDataDeserializer_RecipeAndTechnology.cs @@ -50,6 +50,7 @@ private void DeserializeQuality(LuaTable table, ErrorCollector errorCollector) { quality.nextQuality = GetObject(nextQuality); quality.nextQuality.previousQuality = quality; } + quality.BeaconConsumptionFactor = table.Get("beacon_power_usage_multiplier", 1f); quality.level = table.Get("level", 0); } diff --git a/Yafc/Widgets/ObjectTooltip.cs b/Yafc/Widgets/ObjectTooltip.cs index 72803145..def451b4 100644 --- a/Yafc/Widgets/ObjectTooltip.cs +++ b/Yafc/Widgets/ObjectTooltip.cs @@ -125,6 +125,8 @@ private static void BuildItem(ImGui gui, IFactorioObjectWrapper item) { } protected override void BuildContents(ImGui gui) { + BuildCommon(target.target, gui); + Quality? targetQuality = (target as IObjectWithQuality)?.quality ?? Quality.Normal; switch (target.target) { case Technology technology: BuildTechnology(technology, gui); @@ -133,13 +135,13 @@ protected override void BuildContents(ImGui gui) { BuildRecipe(recipe, gui); break; case Goods goods: - BuildGoods(goods, gui); + BuildGoods(goods, targetQuality, gui); break; case Entity entity: - BuildEntity(entity, gui); + BuildEntity(entity, targetQuality, gui); break; - default: - BuildCommon(target.target, gui); + case Quality quality: + BuildQuality(quality, gui); break; } } @@ -190,9 +192,7 @@ private void BuildCommon(FactorioObject target, ImGui gui) { {EntityEnergyType.SolidFuel, "Solid fuel energy usage: "}, }; - private void BuildEntity(Entity entity, ImGui gui) { - BuildCommon(entity, gui); - + private static void BuildEntity(Entity entity, Quality quality, ImGui gui) { if (entity.loot.Length > 0) { BuildSubHeader(gui, "Loot"); using (gui.EnterGroup(contentPadding)) { @@ -214,8 +214,8 @@ private void BuildEntity(Entity entity, ImGui gui) { BuildSubHeader(gui, "Crafts"); using (gui.EnterGroup(contentPadding)) { BuildIconRow(gui, crafter.recipes, 2); - if (crafter.baseCraftingSpeed != 1f) { - gui.BuildText(DataUtils.FormatAmount(crafter.baseCraftingSpeed, UnitOfMeasure.Percent, "Crafting speed: ")); + if (crafter.CraftingSpeed(quality) != 1f) { + gui.BuildText(DataUtils.FormatAmount(crafter.CraftingSpeed(quality), UnitOfMeasure.Percent, "Crafting speed: ")); } var productivity = crafter.effectReceiver?.baseEffect.productivity ?? 0; @@ -241,7 +241,7 @@ private void BuildEntity(Entity entity, ImGui gui) { } if (entity.energy != null) { - string energyUsage = EnergyDescriptions[entity.energy.type] + DataUtils.FormatAmount(entity.basePower, UnitOfMeasure.Megawatt); + string energyUsage = EnergyDescriptions[entity.energy.type] + DataUtils.FormatAmount(entity.Power(quality), UnitOfMeasure.Megawatt); if (entity.energy.drain > 0f) { energyUsage += " + " + DataUtils.FormatAmount(entity.energy.drain, UnitOfMeasure.Megawatt); } @@ -277,14 +277,14 @@ private void BuildEntity(Entity entity, ImGui gui) { miscText = "Swing time: " + DataUtils.FormatAmount(inserter.inserterSwingTime, UnitOfMeasure.Second); break; case EntityBeacon beacon: - miscText = "Beacon efficiency: " + DataUtils.FormatAmount(beacon.baseBeaconEfficiency, UnitOfMeasure.Percent); + miscText = "Beacon efficiency: " + DataUtils.FormatAmount(beacon.BeaconEfficiency(quality), UnitOfMeasure.Percent); break; case EntityAccumulator accumulator: - miscText = "Accumulator charge: " + DataUtils.FormatAmount(accumulator.baseAccumulatorCapacity, UnitOfMeasure.Megajoule); + miscText = "Accumulator charge: " + DataUtils.FormatAmount(accumulator.AccumulatorCapacity(quality), UnitOfMeasure.Megajoule); break; case EntityCrafter solarPanel: if (solarPanel.baseCraftingSpeed > 0f && entity.factorioType == "solar-panel") { - miscText = "Power production (average): " + DataUtils.FormatAmount(solarPanel.baseCraftingSpeed, UnitOfMeasure.Megawatt); + miscText = "Power production (average): " + DataUtils.FormatAmount(solarPanel.CraftingSpeed(quality), UnitOfMeasure.Megawatt); } break; @@ -297,8 +297,7 @@ private void BuildEntity(Entity entity, ImGui gui) { } } - private void BuildGoods(Goods goods, ImGui gui) { - BuildCommon(goods, gui); + private void BuildGoods(Goods goods, Quality quality, ImGui gui) { if (goods.showInExplorers) { using (gui.EnterGroup(contentPadding)) { gui.BuildText("Middle mouse button to open Never Enough Items Explorer for this " + goods.type, TextBlockDisplayStyle.WrappedText); @@ -365,23 +364,23 @@ private void BuildGoods(Goods goods, ImGui gui) { BuildSubHeader(gui, "Module parameters"); using (gui.EnterGroup(contentPadding)) { if (moduleSpecification.baseProductivity != 0f) { - gui.BuildText(DataUtils.FormatAmount(moduleSpecification.baseProductivity, UnitOfMeasure.Percent, "Productivity: ")); + gui.BuildText(DataUtils.FormatAmount(moduleSpecification.Productivity(quality), UnitOfMeasure.Percent, "Productivity: ")); } if (moduleSpecification.baseSpeed != 0f) { - gui.BuildText(DataUtils.FormatAmount(moduleSpecification.baseSpeed, UnitOfMeasure.Percent, "Speed: ")); + gui.BuildText(DataUtils.FormatAmount(moduleSpecification.Speed(quality), UnitOfMeasure.Percent, "Speed: ")); } if (moduleSpecification.baseConsumption != 0f) { - gui.BuildText(DataUtils.FormatAmount(moduleSpecification.baseConsumption, UnitOfMeasure.Percent, "Consumption: ")); + gui.BuildText(DataUtils.FormatAmount(moduleSpecification.Consumption(quality), UnitOfMeasure.Percent, "Consumption: ")); } if (moduleSpecification.basePollution != 0f) { - gui.BuildText(DataUtils.FormatAmount(moduleSpecification.basePollution, UnitOfMeasure.Percent, "Pollution: ")); + gui.BuildText(DataUtils.FormatAmount(moduleSpecification.Pollution(quality), UnitOfMeasure.Percent, "Pollution: ")); } if (moduleSpecification.baseQuality != 0f) { - gui.BuildText(DataUtils.FormatAmount(moduleSpecification.baseQuality, UnitOfMeasure.Percent, "Quality: ")); + gui.BuildText(DataUtils.FormatAmount(moduleSpecification.Quality(quality), UnitOfMeasure.Percent, "Quality: ")); } } } @@ -393,7 +392,6 @@ private void BuildGoods(Goods goods, ImGui gui) { } private void BuildRecipe(RecipeOrTechnology recipe, ImGui gui) { - BuildCommon(recipe, gui); using (gui.EnterGroup(contentPadding, RectAllocator.LeftRow)) { gui.BuildIcon(Icon.Time, 2f, SchemeColor.BackgroundText); gui.BuildText(DataUtils.FormatAmount(recipe.time, UnitOfMeasure.Second)); @@ -501,11 +499,7 @@ private void BuildRecipe(RecipeOrTechnology recipe, ImGui gui) { private void BuildTechnology(Technology technology, ImGui gui) { bool isResearchTriggerCraft = (technology.flags & RecipeFlags.HasResearchTriggerCraft) == RecipeFlags.HasResearchTriggerCraft; - if (isResearchTriggerCraft) { - BuildCommon(technology, gui); - - } - else { + if (!isResearchTriggerCraft) { BuildRecipe(technology, gui); } @@ -551,6 +545,35 @@ private void BuildTechnology(Technology technology, ImGui gui) { } } + private static void BuildQuality(Quality quality, ImGui gui) { + BuildSubHeader(gui, "Quality bonuses"); + if (quality == Quality.Normal) { + using (gui.EnterGroup(contentPadding)) { + gui.BuildText("Normal quality provides no bonuses.", TextBlockDisplayStyle.WrappedText); + } + return; + } + gui.allocator = RectAllocator.LeftAlign; + (string left, string right)[] text = [ + ("Crafting speed:", '+' + DataUtils.FormatAmount(quality.StandardBonus, UnitOfMeasure.Percent)), + ("Accumulator capacity:", '+' + DataUtils.FormatAmount(quality.AccumulatorCapacityBonus, UnitOfMeasure.Percent)), + ("Module effects:", '+' + DataUtils.FormatAmount(quality.StandardBonus, UnitOfMeasure.Percent) + '*'), + ("Beacon transmission efficiency:", '+' + DataUtils.FormatAmount(quality.BeaconTransmissionBonus, UnitOfMeasure.None)) + ]; + + float rightWidth = text.Max(t => gui.GetTextDimensions(out _, t.right).X); + + using (gui.EnterGroup(contentPadding)) { + gui.allocator = RectAllocator.LeftAlign; + foreach (var (left, right) in text) { + gui.BuildText(left); + Rect rect = new(gui.statePosition.Width - rightWidth, gui.lastRect.Y, rightWidth, gui.lastRect.Height); + gui.DrawText(rect, right); + } + gui.BuildText("* Only applied to beneficial module effects.", TextBlockDisplayStyle.WrappedText); + } + } + public void SetFocus(IFactorioObjectWrapper target, ImGui gui, Rect rect, ObjectTooltipOptions tooltipOptions) { this.tooltipOptions = tooltipOptions; this.target = target;