Skip to content

Commit 584a4ec

Browse files
authored
Load and display heating information (#427)
This loads and displays heat required on cold planets, provided it's non-zero. The new line in the tooltip and both lines in the shopping list will not appear if they would display zero. ![image](https://github.com/user-attachments/assets/29ef9952-fd90-4617-80e7-451e73c0493e) ![image](https://github.com/user-attachments/assets/297bf829-1a11-4ee5-b4ca-3bc3e88e7531) The four links in the bottom line each pop up a list containing the described items; "other entities" are things likes radars, beacons, turrets, and roboports. I'd like it to be more visible, but I'm not ready to tackle the task of making planet-specific tables or figuring out how the heat demand should integrate with the solver.
2 parents 4da2f1c + f2d6af5 commit 584a4ec

File tree

9 files changed

+76
-10
lines changed

9 files changed

+76
-10
lines changed

Yafc.Model/Data/DataClasses.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ public float Power(Quality quality)
521521
internal List<Ammo> captureAmmo { get; } = [];
522522
internal List<Entity> sourceEntities { get; set; } = null!;
523523
internal string? autoplaceControl { get; set; }
524+
public float heatingPower { get; internal set; }
524525
public int size { get; internal set; }
525526
internal override FactorioObjectSortOrder sortingOrder => FactorioObjectSortOrder.Entities;
526527
public override string type => "Entity";

Yafc.Parser/Data/FactorioDataDeserializer_Entity.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,8 @@ void parseEffect(LuaTable effect) {
621621
fuelUsers.Add(entity, SpecialNames.Void);
622622
}
623623

624+
entity.heatingPower = ParseEnergy(table.Get<string>("heating_energy"));
625+
624626
if (table.Get("production_health_effect", out LuaTable? healthEffect) && healthEffect.Get("not_producing", out float? lossPerTick)) {
625627
entity.baseSpoilTime = (float)(table.Get<float>("max_health") * -60 * lossPerTick.Value);
626628
table.Get<LuaTable>("dying_trigger_effect")?.ReadObjectOrArray(readDeathEffect);

Yafc/Widgets/ImmediateWidgets.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,9 @@ public static Click BuildFactorioObjectButtonWithText(this ImGui gui, IFactorioO
198198
}
199199

200200
internal static bool BuildInlineObjectList<T>(this ImGui gui, IEnumerable<T> list, [NotNullWhen(true)] out T? selected, ObjectSelectOptions<T> options) where T : class, IFactorioObjectWrapper {
201-
gui.BuildText(options.Header, Font.productionTableHeader);
201+
if (options.Header != null) {
202+
gui.BuildText(options.Header, Font.productionTableHeader);
203+
}
202204
IEnumerable<T> sortedList = list;
203205

204206
if (options.Ordering != DataUtils.AlreadySortedRecipe) {
@@ -460,7 +462,7 @@ public record DisplayAmount(float Value, UnitOfMeasure Unit = UnitOfMeasure.None
460462
/// <param name="Checkmark">If not <see langword="null"/>, this will be called to determine if a checkmark should be drawn on the item.
461463
/// Not used when selecting with a 'None' item or when <paramref name="Multiple"/> is <see langword="false"/>.</param>
462464
/// <param name="ExtraText">If not <see langword="null"/>, this will be called to get extra text to be displayed right-justified after the item's name.</param>
463-
public sealed record ObjectSelectOptions<T>(string Header, [AllowNull] IComparer<T> Ordering = null, int MaxCount = 6, bool Multiple = false, Predicate<T>? Checkmark = null,
465+
public sealed record ObjectSelectOptions<T>(string? Header, [AllowNull] IComparer<T> Ordering = null, int MaxCount = 6, bool Multiple = false, Predicate<T>? Checkmark = null,
464466
Func<T, string>? ExtraText = null) where T : IFactorioObjectWrapper {
465467

466468
public IComparer<T> Ordering { get; init; } = Ordering ?? (IComparer<T>)DataUtils.DefaultOrdering;

Yafc/Widgets/ObjectTooltip.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,16 @@ private void BuildEntity(Entity entity, Quality quality, ImGui gui) {
317317
}
318318
}
319319

320+
if (entity.heatingPower != 0) {
321+
using (gui.EnterGroup(contentPadding))
322+
using (gui.EnterRow(0)) {
323+
gui.AllocateRect(0, 1.5f);
324+
gui.BuildText($"Requires {DataUtils.FormatAmount(entity.heatingPower, UnitOfMeasure.Megawatt)}");
325+
gui.BuildFactorioObjectIcon(Database.heat, IconDisplayStyle.Default with { Size = 1.5f });
326+
gui.BuildText("heat on cold planets.");
327+
}
328+
}
329+
320330
string? miscText = null;
321331

322332
switch (entity) {

Yafc/Windows/SelectMultiObjectPanel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class SelectMultiObjectPanel : SelectObjectPanel<IEnumerable<FactorioObje
2020
/// <param name="header">The string that describes to the user why they're selecting these items.</param>
2121
/// <param name="selectItem">An action to be called for each selected item when the panel is closed.</param>
2222
/// <param name="ordering">An optional ordering specifying how to sort the displayed items. If <see langword="null"/>, defaults to <see cref="DataUtils.DefaultOrdering"/>.</param>
23-
public static void Select<T>(IEnumerable<T> list, string header, Action<T> selectItem, IComparer<T>? ordering = null, Predicate<T>? checkMark = null) where T : FactorioObject {
23+
public static void Select<T>(IEnumerable<T> list, string? header, Action<T> selectItem, IComparer<T>? ordering = null, Predicate<T>? checkMark = null) where T : FactorioObject {
2424
SelectMultiObjectPanel panel = new(o => checkMark?.Invoke((T)o) ?? false); // This casting is messy, but pushing T all the way around the call stack and type tree was messier.
2525
panel.Select(list, header, selectItem!, ordering, (objs, mappedAction) => { // null-forgiving: selectItem will not be called with null, because allowNone is false.
2626
foreach (var obj in objs!) { // null-forgiving: mapResult will not be called with null, because allowNone is false.

Yafc/Windows/SelectObjectPanel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Yafc;
1313
/// <typeparam name="T">The type of result the panel can generate.</typeparam>
1414
public abstract class SelectObjectPanel<T> : PseudoScreenWithResult<T> {
1515
private readonly SearchableList<FactorioObject?> list;
16-
private string header = null!; // null-forgiving: set by Select
16+
private string? header;
1717
private Rect searchBox;
1818
private string? noneTooltip;
1919
private Quality? currentQuality;
@@ -25,7 +25,7 @@ public abstract class SelectObjectPanel<T> : PseudoScreenWithResult<T> {
2525

2626
protected SelectObjectPanel() : base(40f) => list = new SearchableList<FactorioObject?>(30, new Vector2(2.5f, 2.5f), ElementDrawer, ElementFilter);
2727

28-
protected void SelectWithQuality<U>(IEnumerable<U> list, string header, Action<ObjectWithQuality<U>?> selectItem, IComparer<U>? ordering, Action<T?, Action<FactorioObject?>> mapResult,
28+
protected void SelectWithQuality<U>(IEnumerable<U> list, string? header, Action<ObjectWithQuality<U>?> selectItem, IComparer<U>? ordering, Action<T?, Action<FactorioObject?>> mapResult,
2929
bool allowNone, string? noneTooltip, Quality? currentQuality) where U : FactorioObject
3030
=> Select(list, header, u => selectItem((u, this.currentQuality!)), ordering, mapResult, allowNone, noneTooltip, currentQuality ?? Quality.Normal);
3131

@@ -44,7 +44,7 @@ protected void SelectWithQuality<U>(IEnumerable<U> list, string header, Action<O
4444
/// <param name="allowNone">If <see langword="true"/>, a "none" option will be displayed. Selection of this item will be conveyed by calling <paramref name="mapResult"/>
4545
/// and <paramref name="selectItem"/> with <see langword="default"/> values for <typeparamref name="T"/> and <typeparamref name="U"/>.</param>
4646
/// <param name="noneTooltip">If not <see langword="null"/>, this tooltip will be displayed when hovering over the "none" item.</param>
47-
protected void Select<U>(IEnumerable<U> list, string header, Action<U?> selectItem, IComparer<U>? ordering, Action<T?, Action<FactorioObject?>> mapResult, bool allowNone,
47+
protected void Select<U>(IEnumerable<U> list, string? header, Action<U?> selectItem, IComparer<U>? ordering, Action<T?, Action<FactorioObject?>> mapResult, bool allowNone,
4848
string? noneTooltip = null, Quality? currentQuality = null) where U : FactorioObject {
4949

5050
_ = MainScreen.Instance.ShowPseudoScreen(this);

Yafc/Windows/SelectSingleObjectPanel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public SelectSingleObjectPanel() : base() { }
1919
/// <param name="header">The string that describes to the user why they're selecting these items.</param>
2020
/// <param name="selectItem">An action to be called for the selected item when the panel is closed.</param>
2121
/// <param name="ordering">An optional ordering specifying how to sort the displayed items. If <see langword="null"/>, defaults to <see cref="DataUtils.DefaultOrdering"/>.</param>
22-
public static void Select<T>(IEnumerable<T> list, string header, Action<T> selectItem, IComparer<T>? ordering = null) where T : FactorioObject
22+
public static void Select<T>(IEnumerable<T> list, string? header, Action<T> selectItem, IComparer<T>? ordering = null) where T : FactorioObject
2323
// null-forgiving: selectItem will not be called with null, because allowNone is false.
2424
=> Instance.Select(list, header, selectItem!, ordering, (obj, mappedAction) => mappedAction(obj), false);
2525

@@ -47,7 +47,7 @@ public static void SelectWithQuality<T>(IEnumerable<T> list, string header, Acti
4747
/// The parameter will be <see langword="null"/> if the "none" or "clear" option is selected.</param>
4848
/// <param name="ordering">An optional ordering specifying how to sort the displayed items. If <see langword="null"/>, defaults to <see cref="DataUtils.DefaultOrdering"/>.</param>
4949
/// <param name="noneTooltip">If not <see langword="null"/>, this tooltip will be displayed when hovering over the "none" item.</param>
50-
public static void SelectWithNone<T>(IEnumerable<T> list, string header, Action<T?> selectItem, IComparer<T>? ordering = null, string? noneTooltip = null) where T : FactorioObject
50+
public static void SelectWithNone<T>(IEnumerable<T> list, string? header, Action<T?> selectItem, IComparer<T>? ordering = null, string? noneTooltip = null) where T : FactorioObject
5151
=> Instance.Select(list, header, selectItem, ordering, (obj, mappedAction) => mappedAction(obj), true, noneTooltip);
5252

5353
/// <summary>
@@ -60,7 +60,7 @@ public static void SelectWithNone<T>(IEnumerable<T> list, string header, Action<
6060
/// The parameter will be <see langword="null"/> if the "none" or "clear" option is selected.</param>
6161
/// <param name="ordering">An optional ordering specifying how to sort the displayed items. If <see langword="null"/>, defaults to <see cref="DataUtils.DefaultOrdering"/>.</param>
6262
/// <param name="noneTooltip">If not <see langword="null"/>, this tooltip will be displayed when hovering over the "none" item.</param>
63-
public static void SelectQualityWithNone<T>(IEnumerable<T> list, string header, Action<ObjectWithQuality<T>?> selectItem, Quality? currentQuality, IComparer<T>? ordering = null,
63+
public static void SelectQualityWithNone<T>(IEnumerable<T> list, string? header, Action<ObjectWithQuality<T>?> selectItem, Quality? currentQuality, IComparer<T>? ordering = null,
6464
string? noneTooltip = null) where T : FactorioObject
6565
=> Instance.SelectWithQuality(list, header, selectItem, ordering, (obj, mappedAction) => mappedAction(obj), true, noneTooltip, currentQuality);
6666

Yafc/Windows/ShoppingListScreen.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ namespace Yafc;
1010

1111
public class ShoppingListScreen : PseudoScreen {
1212
private enum DisplayState { Total, Built, Missing }
13+
14+
private static readonly ObjectSelectOptions<Entity> options
15+
= new(null, MaxCount: 15, ExtraText: e => DataUtils.FormatAmount(e.heatingPower, UnitOfMeasure.Megawatt));
16+
1317
private readonly VirtualScrollList<(IObjectWithQuality<FactorioObject>, float)> list;
14-
private float shoppingCost, totalBuildings, totalModules;
18+
private float shoppingCost, totalBuildings, totalModules, totalHeat;
19+
private List<Entity> pipes = null!, belts = null!, other = null!; //null-forgiving: set by RebuildData
1520
private bool decomposed = false;
1621
private static DisplayState displayState {
1722
get => (DisplayState)(Preferences.Instance.shoppingDisplayState >> 1);
@@ -50,6 +55,7 @@ private void RebuildData() {
5055
decomposed = false;
5156

5257
// Count buildings and modules
58+
totalHeat = 0;
5359
Dictionary<IObjectWithQuality<FactorioObject>, int> counts = [];
5460
foreach (RecipeRow recipe in recipes) {
5561
if (recipe.entity != null) {
@@ -62,6 +68,7 @@ private void RebuildData() {
6268
DisplayState.Missing => MathUtils.Ceil(Math.Max(recipe.buildingCount - builtCount, 0)),
6369
_ => throw new InvalidOperationException(nameof(displayState) + " has an unrecognized value.")
6470
};
71+
totalHeat += recipe.entity.target.heatingPower * displayCount;
6572
counts[shopItem] = prev + displayCount;
6673
if (recipe.usedModules.modules != null) {
6774
foreach ((ObjectWithQuality<Module> module, int moduleCount, bool beacon) in recipe.usedModules.modules) {
@@ -90,6 +97,16 @@ private void RebuildData() {
9097
shoppingCost = cost;
9198
totalBuildings = buildings;
9299
totalModules = modules;
100+
101+
pipes = Database.entities.all.Where(e => e.factorioType is "pipe" or "pipe-to-ground" or "storage-tank" or "pump" && e.heatingPower > 0)
102+
.ToList();
103+
belts = Database.entities.all
104+
.Where(e => e.factorioType is "transport-belt" or "underground-belt" or "splitter" or "loader" or "loader-1x1" && e.heatingPower > 0)
105+
.ToList();
106+
other = Database.entities.all
107+
.Except(Database.allInserters).Except(pipes).Except(belts)
108+
.Where(e => e is not EntityCrafter && e.heatingPower > 0)
109+
.ToList();
93110
}
94111

95112
private static readonly (string, string?)[] displayStateOptions = [
@@ -121,6 +138,36 @@ public override void Build(ImGui gui) {
121138
}
122139
gui.AllocateSpacing(1f);
123140
list.Build(gui);
141+
142+
if (totalHeat > 0) {
143+
using (gui.EnterRow(0)) {
144+
gui.AllocateRect(0, 1.5f);
145+
gui.BuildText("These entities require " + DataUtils.FormatAmount(totalHeat, UnitOfMeasure.Megawatt));
146+
gui.BuildFactorioObjectIcon(Database.heat, IconDisplayStyle.Default with { Size = 1.5f });
147+
gui.BuildText("heat on cold planets.");
148+
}
149+
150+
using (gui.EnterRow(0)) {
151+
gui.BuildText("Allow additional heat for ");
152+
if (gui.BuildLink("inserters")) {
153+
gui.BuildObjectSelectDropDown(Database.allInserters, _ => { }, options);
154+
}
155+
gui.BuildText(", ");
156+
if (gui.BuildLink("pipes")) {
157+
gui.BuildObjectSelectDropDown(pipes, _ => { }, options);
158+
}
159+
gui.BuildText(", ");
160+
if (gui.BuildLink("belts")) {
161+
gui.BuildObjectSelectDropDown(belts, _ => { }, options);
162+
}
163+
gui.BuildText(", and ");
164+
if (gui.BuildLink("other entities")) {
165+
gui.BuildObjectSelectDropDown(other, _ => { }, options);
166+
}
167+
gui.BuildText(".");
168+
}
169+
}
170+
124171
using (gui.EnterRow(allocator: RectAllocator.RightRow)) {
125172
if (gui.BuildButton("Done")) {
126173
Close();

changelog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
// Bugfixes go there.
1515
// Internal changes:
1616
// Changes to the code that do not affect the behavior of the program.
17+
Version:
18+
Date:
19+
Features:
20+
- (SA) Calculate the required heating and show it in tooltips and the shopping list.
1721
----------------------------------------------------------------------------------------------------------------------
1822
Version: 2.9.0
1923
Date: February 24th 2025

0 commit comments

Comments
 (0)