diff --git a/HeatMap.xlsx b/HeatMap.xlsx
new file mode 100644
index 0000000..19741e7
Binary files /dev/null and b/HeatMap.xlsx differ
diff --git a/mod-structure/1.4/Assemblies/HeatMap.dll b/mod-structure/1.4/Assemblies/HeatMap.dll
new file mode 100644
index 0000000..623e695
Binary files /dev/null and b/mod-structure/1.4/Assemblies/HeatMap.dll differ
diff --git a/mod-structure/1.5/Assemblies/HeatMap.dll b/mod-structure/1.5/Assemblies/HeatMap.dll
new file mode 100644
index 0000000..8e33c6d
Binary files /dev/null and b/mod-structure/1.5/Assemblies/HeatMap.dll differ
diff --git a/mod-structure/About/About.xml b/mod-structure/About/About.xml
index 735b79a..b356590 100644
--- a/mod-structure/About/About.xml
+++ b/mod-structure/About/About.xml
@@ -5,6 +5,8 @@
Falconne
Adds an overlay toggle button to show a temperature based colour gradient over indoor areas: green for the human comfort zone, getting bluer and redder for colder and hotter rooms respectively.
+ 1.5
+ 1.4
1.3
1.2
1.1
diff --git a/mod-structure/Languages/English/Keyed/FALCHM_LanguageData.xml b/mod-structure/Languages/English/Keyed/FALCHM_LanguageData.xml
index 7f79ca7..50dd0f6 100644
--- a/mod-structure/Languages/English/Keyed/FALCHM_LanguageData.xml
+++ b/mod-structure/Languages/English/Keyed/FALCHM_LanguageData.xml
@@ -1,43 +1,94 @@
+ Override vanilla overlay
+ Use Heat Map's overlay instead of the vanilla overlay.
+(default: {default})
+
+ Only overlay indoor areas
+ Only show the overlay for indoors areas.
+(default: {default})
+
Opacity of overlay
- Reduce this value to make the overlay more transparent.
+ Reduce this value to make the overlay more transparent.
+(default: {default}%)
Overlay update delay
- Number of ticks delay between overlay updates while game is unpaused. Lower numbers provide smoother updates, but may affect performance on low end machines.
+ Number of ticks delay between widget and temperature text updates while game is unpaused. Lower numbers provide smoother updates, but may affect performance on low end machines.
+(default: {default})
Show outdoor thermometer
- Displays a widget in the top right hand corner of the UI showing current outdoor temperature.
+ Displays a widget in the top right hand corner of the UI showing current outdoor temperature.
+(default: {default})
Opacity of thermometer
- Reduce this value to make the outdoor temperature thermometer background color more transparent.
+ Reduce this value to make the outdoor temperature thermometer background colour more transparent.
+(default: {default}%)
Lock thermometer position
- Locks the thermometer widget in place, disabling shift-click dragging.
+ Locks the thermometer widget in place, disabling shift-click dragging.
+(default: {default})
Right margin of thermometer
- Changes the margin between the thermometer widget and the right of the screen. The widget can be dragged using shift-click while ingame.
+ Changes the margin between the thermometer widget and the right of the screen. The widget can be dragged using shift-click while ingame.
+(default: {default})
Top margin of thermometer
- Changes the margin between the thermometer widget and the top of the screen. The widget can be dragged using shift-click while ingame.
+ Changes the margin between the thermometer widget and the top of the screen. The widget can be dragged using shift-click while ingame.
+(default: {default})
- Outdoor temperature.
-Click to toggle heat map overlay.
-Shift-click and drag to move the widget, the position can be locked in the mod settings.
-This widget can be disabled in mod settings.
- Show Heat Map
+ Show temperature over rooms
+ When overlay is on, this will also display the room temperature over the centre of the room.
+(default: {default})
+
+ Colour gradient hue {index}
+ Defines which colours will be used for the overlay's colour gradient. Colours are given as hue in degree.
+(default: {default})
+
+- Colours:
+0°/360° = red
+60° = yellow
+120° = green
+180° = cyan
+240° = blue
+300° = magenta
+
+Each degree of temperature between min/max (default: {min} to {max} °C) has a relative gradient step width of 1, except for the values between min/max comfort temperature (default: {comfortMin} to {comfortMax} °C), which have a step width of 4.
+I.e. each degree of the comfort temperature range takes up four times as much on the colour gradient as one outside of the comfort levels.
+For example when using default settings green will be applied to a smaller temperature range than red or blue.
Use custom range
When off, the colour gradient automatically maps to the human comfort range as defined by the game.
-When on, allows you to set a custom boundary for the blue and red ends of the gradient, in current temperature units
+When on, custom temperature boundaries for the colour gradient can be set.
+(default: {default})
Custom range min
- Blue end of gradient. Temperatures below this will be blue. Use current temperature units
+ Lower temperature limit of the colour gradient.
+Temperatures below this will be coloured using colour gradient hue 0, default: blue.
+Uses current temperature units
+(default: {default})
Custom range max
- Red end of gradient. Temperatures above this will be red. Use current temperature units
+ Upper temperature limit of the colour gradient.
+Temperatures above this will be coloured using colour gradient hue 4, default: red.
+Uses current temperature units
+(default: {default})
- Show temperature over rooms
- When overlay is on, this will also display the room temperature over the centre of the room.
+ Custom comfort range min
+ Lower comfort temperature.
+Between min-max comfort temperature the colour changes four times as quickly as outside these limits, making small changes more noticeable.
+Uses current temperature units
+(default: {default})
+
+ Custom comfort range max
+ Upper comfort temperature.
+Between min-max comfort temperature the colour changes four times as quickly as outside these limits, making small changes more noticeable.
+Uses current temperature units
+(default: {default})
+
+ Outdoor temperature.
+Click to toggle heat map overlay.
+Shift-click and drag to move the widget, the position can be locked in the mod settings.
+This widget can be disabled in mod settings.
+ Show Heat Map
diff --git a/src/HeatMap/ColorHelper.cs b/src/HeatMap/ColorHelper.cs
new file mode 100644
index 0000000..5f9f6df
--- /dev/null
+++ b/src/HeatMap/ColorHelper.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+
+namespace HeatMap
+{
+ public class ColorHelper
+ {
+ ///
+ /// Calculate a color from a color gradient between two colors
+ ///
+ /// Gradient start color
+ /// Gradient end color
+ /// Position in color gradient; can be equal to return
+ /// Number of steps in the color gradient
+ /// Alpha-Channel
+ ///
+ public static Color Gradient(Color start, Color end, float pos, float steps, float a = 1f)
+ {
+ if (steps <= 0)
+ return new Color(end.r, end.g, end.b, a);
+
+ pos %= steps + 1;
+
+ var rMin = start.r;
+ var rMax = end.r;
+ var gMin = start.g;
+ var gMax = end.g;
+ var bMin = start.b;
+ var bMax = end.b;
+
+ var rAverage = rMin + ((rMax - rMin) * pos / steps);
+ var gAverage = gMin + ((gMax - gMin) * pos / steps);
+ var bAverage = bMin + ((bMax - bMin) * pos / steps);
+
+ return new Color(rAverage, gAverage, bAverage, a);
+ }
+
+ ///
+ /// Creates a color gradient using and
+ ///
+ /// Colors to be used for the gradient with relative weighting factor; relatively higher factors will make the color be used for more steps
+ /// Steps with stepwidth; longer stepwidth advances through the gradient faster
+ /// Alpha-Channel
+ ///
+ public static List Gradient(IList> colors, IList steps, float a = 1f)
+ {
+ if (!(colors?.Count > 0))
+ {
+ Log.Warning("Colors must have at least 1 element");
+ return new List { Color.white };
+ }
+
+ if (!(steps?.Count > 0))
+ {
+ Log.Warning("Steps must have at least 1 element");
+ return new List { Color.white };
+ }
+
+ var stepsTotal = 0f;
+ foreach (var step in steps)
+ stepsTotal += step;
+ if (stepsTotal == 0)
+ {
+ Log.Warning("Steps total must be greater than 0");
+ return new List { Color.white };
+ }
+
+ var total = 0f;
+ for (int i = 0; i < colors.Count - 1; i++)
+ total += colors[i].Item2;
+
+ var offset = 0f;
+ var list = new List>();
+ foreach (var item in colors)
+ {
+ list.Add(new Tuple(item.Item1, offset));
+ offset += stepsTotal * (item.Item2 / total);
+ }
+
+ var output = new List();
+ var pos = 0f;
+ for (int i = 0, j = 0; i < list.Count - 1; i++)
+ {
+ var item = list[i];
+ var next = list[i + 1];
+ while (pos < next.Item2)
+ {
+ output.Add(Gradient(
+ item.Item1,
+ next.Item1,
+ pos - item.Item2,
+ next.Item2 - item.Item2,
+ a));
+ pos += steps[j++];
+ }
+ }
+ output.Add(colors.Last().Item1);
+ return output;
+ }
+ }
+}
diff --git a/src/HeatMap/HeatMap.cs b/src/HeatMap/HeatMap.cs
index c3479f7..1084de3 100644
--- a/src/HeatMap/HeatMap.cs
+++ b/src/HeatMap/HeatMap.cs
@@ -1,215 +1,400 @@
-using System;
-using RimWorld;
-using UnityEngine;
-using Verse;
-
-namespace HeatMap
-{
- public class HeatMap : ICellBoolGiver
- {
- public HeatMap()
- {
- if (Main.Instance.ShouldUseCustomRange())
- CreateCustomMap();
- else
- CreateComfortMap();
- }
-
- public void CreateCustomMap()
- {
- _mappedTemperatureRange = new IntRange(
- Main.Instance.GetCustomRangeMin(), Main.Instance.GetCustomRangeMax());
-
- var mappedColorCount = _mappedTemperatureRange.max - _mappedTemperatureRange.min;
- _mappedColors = new Color[mappedColorCount];
-
- var delta = 2f / (mappedColorCount - 1);
- var channelR = -1f;
- var channelG = 0f;
- var channelB = 1f;
- var greenRising = true;
-
- for (var i = 0; i < mappedColorCount - 1; i++)
- {
- var realR = Math.Min(channelR, 1f);
- realR = Math.Max(realR, 0f);
-
- var realG = Math.Min(channelG, 1f);
- realG = Math.Max(realG, 0f);
-
- var realB = Math.Min(channelB, 1f);
- realB = Math.Max(realB, 0f);
-
- _mappedColors[i] = new Color(realR, realG, realB);
-
- if (channelG >= 1f)
- greenRising = false;
-
- channelR += delta;
- channelG += greenRising ? delta : -delta;
- channelB -= delta;
- }
-
- // Force high end to be red (or else if the temperature range is an even number,
- // the green channel will not go down to zero in above loop).
- _mappedColors[mappedColorCount - 1] = Color.red;
- }
-
- public void CreateComfortMap()
- {
- var minComfortTemp = (int)ThingDefOf.Human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMin) + 3;
- var maxComfortTemp = (int)ThingDefOf.Human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMax) - 3;
-
- // Narrow down the green range to a quarter scale, to make boundary temps stand out more.
-
- var comfortDoubleRange = (maxComfortTemp - minComfortTemp) * 2;
- _mappedTemperatureRange = new IntRange(
- minComfortTemp - comfortDoubleRange, maxComfortTemp + comfortDoubleRange);
-
- var mappedColorCount = _mappedTemperatureRange.max - _mappedTemperatureRange.min;
- _mappedColors = new Color[mappedColorCount];
-
- var channelDelta = 1f / comfortDoubleRange;
- var channelR = -2f;
- var channelG = 0f;
- var channelB = 2f;
- var greenRising = true;
-
- var mappingTemperature = _mappedTemperatureRange.min;
- for (var i = 0; i < mappedColorCount - 1; i++, mappingTemperature++)
- {
- var realR = Math.Min(channelR, 1f);
- realR = Math.Max(realR, 0f);
-
- var realG = Math.Min(channelG, 1f);
- realG = Math.Max(realG, 0f);
-
- var realB = Math.Min(channelB, 1f);
- realB = Math.Max(realB, 0f);
-
- _mappedColors[i] = new Color(realR, realG, realB);
-
- if (channelG >= 2f)
- greenRising = false;
-
- var delta = channelDelta;
- if (mappingTemperature >= minComfortTemp - 1 &&
- mappingTemperature <= maxComfortTemp)
- {
- delta *= 4;
- }
-
- channelR += delta;
- channelG += greenRising ? delta : -delta;
- channelB -= delta;
- }
-
- // Force high end to be red (or else if the temperature range is an even number,
- // the green channel will not go down to zero in above loop).
- _mappedColors[mappedColorCount - 1] = Color.red;
- }
-
- public CellBoolDrawer Drawer
- {
- get
- {
- if (_drawerInt == null)
- {
- var map = Find.CurrentMap;
- _drawerInt = new CellBoolDrawer(this, map.Size.x, map.Size.z,
- Main.Instance.GetConfiguredOpacity());
- }
- return _drawerInt;
- }
- }
-
- public bool GetCellBool(int index)
- {
- var map = Find.CurrentMap;
- if (map.fogGrid.IsFogged(index))
- return false;
-
- var room = map.cellIndices.IndexToCell(index).GetRoom(map);
-
- if (room != null && !room.PsychologicallyOutdoors)
- {
- _nextColor = GetColorForTemperature(room.Temperature);
- return true;
- }
-
- return false;
- }
-
- public int GetIndexForTemperature(float temperature)
- {
- // These two checks are probably not needed due to array index boundary checks
- // below, but too worried to remove them now.
- if (temperature <= _mappedTemperatureRange.min)
- {
- return 0;
- }
-
- if (temperature >= _mappedTemperatureRange.max)
- {
- return _mappedColors.Length - 1;
- }
-
- var colorMapIndex = (int)temperature - _mappedTemperatureRange.min;
- if (colorMapIndex <= 0)
- {
- return 0;
- }
-
- if (colorMapIndex >= _mappedColors.Length)
- {
- return _mappedColors.Length - 1;
- }
-
- return colorMapIndex;
-
- }
-
- public Color GetColorForTemperature(float temperature)
- {
- return _mappedColors[GetIndexForTemperature(temperature)];
- }
-
- public Color GetCellExtraColor(int index)
- {
- return _nextColor;
- }
-
- public Color Color => Color.white;
-
- public void Update(int updateDelay)
- {
- if (Main.Instance.ShowHeatMap)
- {
- Drawer.MarkForDraw();
- var tick = Find.TickManager.TicksGame;
- if (tick >= _nextUpdateTick)
- {
- Drawer.SetDirty();
- _nextUpdateTick = tick + updateDelay;
- }
- Drawer.CellBoolDrawerUpdate();
- }
- }
-
- public void Reset()
- {
- _drawerInt = null;
- _nextUpdateTick = 0;
- }
-
- private CellBoolDrawer _drawerInt;
-
- private IntRange _mappedTemperatureRange;
-
- private Color[] _mappedColors;
-
- private Color _nextColor;
-
- private int _nextUpdateTick;
- }
-}
\ No newline at end of file
+using HugsLib.Settings;
+using HugsLib.Utils;
+using RimWorld;
+using RimWorld.Planet;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
+using Verse;
+
+namespace HeatMap
+{
+ public class HeatMap : HugsLib.ModBase
+ {
+ internal new ModLogger Logger => base.Logger;
+
+ internal static HeatMap Instance { get; private set; }
+
+ public override string ModIdentifier => "HeatMap";
+
+ public RoomTemperatureDisplayer TemperatureDisplayer { get; } = new RoomTemperatureDisplayer();
+
+ private const float _boxSize = 62f;
+ private bool _draggingThermometer = false;
+ private float _dragThermometerRight = 0f;
+ private float _dragThermometerTop = 0f;
+
+ private readonly Dictionary _temperatureTextureCache = new Dictionary();
+
+ private SettingHandle _overrideVanillaOverlay;
+ private SettingHandle _showIndoorsOnly;
+ private SettingHandle _opacity;
+ private SettingHandle _updateDelay;
+
+ private SettingHandle _showOutdoorThermometer;
+ private SettingHandle _outdoorThermometerOpacity;
+ private SettingHandle _outdoorThermometerFixed;
+ private SettingHandle _outdoorThermometerRight;
+ private SettingHandle _outdoorThermometerTop;
+
+ private SettingHandle _showTemperatureOverRooms;
+
+ public const int GradientSteps = 5;
+ private readonly SettingHandle[] _gradientHue = new SettingHandle[GradientSteps];
+
+ private SettingHandle _useCustomRange;
+ private SettingHandle _customRangeMin;
+ private SettingHandle _customRangeMax;
+ private SettingHandle _customRangeComfortMin;
+ private SettingHandle _customRangeComfortMax;
+
+
+ public bool OverrideVanillaOverlay =>
+ _overrideVanillaOverlay;
+ public bool ShowIndoorsOnly =>
+ _showIndoorsOnly;
+ public float OverlayOpacity =>
+ _opacity / 100f;
+ public bool ShouldUseCustomRange =>
+ _useCustomRange;
+ public int CustomRangeMin =>
+ _customRangeMin;
+ public int CustomRangeMax =>
+ _customRangeMax;
+ public int CustomRangeComfortMin =>
+ _customRangeComfortMin;
+ public int CustomRangeComfortMax =>
+ _customRangeComfortMax;
+
+ public Color GetGradientColor(int index)
+ {
+ if (index >= 0 && index < _gradientHue.Length)
+ return Color.HSVToRGB(_gradientHue[index] / 360f, 1f, 1f);
+ return Color.black;
+ }
+
+
+ public HeatMap()
+ {
+ Instance = this;
+ }
+
+ public void UpdateOutdoorThermometer()
+ {
+ if (!_showOutdoorThermometer)
+ return;
+
+ var right = Mathf.Clamp(_draggingThermometer ? _dragThermometerRight : _outdoorThermometerRight, _boxSize, UI.screenWidth);
+ var top = Mathf.Clamp(_draggingThermometer ? _dragThermometerTop : _outdoorThermometerTop, 0, UI.screenHeight - _boxSize);
+ var outRect = new Rect(UI.screenWidth - right, top, _boxSize, _boxSize);
+ if (TutorSystem.AdaptiveTrainingEnabled && Find.PlaySettings.showLearningHelper)
+ {
+ if (typeof(LearningReadout).GetField("windowRect", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(Find.Tutor.learningReadout) is Rect helpRect
+ && helpRect.Overlaps(outRect) == true)
+ outRect.x = helpRect.x - _boxSize - 5f;
+ }
+
+ if (!_outdoorThermometerFixed && Event.current.isMouse)
+ {
+ switch (Event.current.type)
+ {
+ case EventType.MouseDown:
+ if (Mouse.IsOver(outRect) && Event.current.modifiers == EventModifiers.Shift)
+ {
+ Event.current.Use();
+
+ _dragThermometerRight = _outdoorThermometerRight.Value;
+ _dragThermometerTop = _outdoorThermometerTop.Value;
+
+ _draggingThermometer = true;
+ }
+ break;
+ case EventType.MouseDrag:
+ if (_draggingThermometer)
+ {
+ Event.current.Use();
+
+ _dragThermometerRight -= Event.current.delta.x;
+ _dragThermometerRight = Mathf.Clamp(_dragThermometerRight, _boxSize, UI.screenWidth);
+ _dragThermometerTop += Event.current.delta.y;
+ _dragThermometerTop = Mathf.Clamp(_dragThermometerTop, 0, UI.screenHeight - _boxSize);
+ //outRect = new Rect(outRect.x - _dragThermometerRight, outRect.y + _dragThermometerTop, _boxSize, _boxSize); // repositioning is processed on next update
+ }
+ break;
+ case EventType.MouseUp:
+ if (_draggingThermometer)
+ {
+ Event.current.Use();
+
+ _outdoorThermometerRight.Value = _dragThermometerRight;
+ _outdoorThermometerTop.Value = _dragThermometerTop;
+
+ _draggingThermometer = false;
+ }
+ break;
+ }
+ }
+
+ var temperature = Find.CurrentMap.mapTemperature.OutdoorTemp;
+ var textureIndex = HeatMapHelper.GetIndexForTemperature(temperature);
+ if (!_temperatureTextureCache.ContainsKey(textureIndex))
+ {
+ var backColor = HeatMapHelper.GetColorForTemperature(temperature);
+ backColor.a = _outdoorThermometerOpacity / 100f;
+ _temperatureTextureCache[textureIndex] = SolidColorMaterials.NewSolidColorTexture(backColor);
+ }
+ GUI.DrawTexture(outRect, _temperatureTextureCache[textureIndex]);
+ GUI.DrawTexture(outRect, Resources.DisplayBoder);
+
+ var temperatureForDisplay = temperature.ToStringTemperature("F0");
+ Text.Font = GameFont.Medium;
+ Text.Anchor = TextAnchor.MiddleCenter;
+ GUI.color = Color.white;
+ Widgets.Label(outRect, temperatureForDisplay);
+
+ if (Widgets.ButtonInvisible(outRect))
+ Find.PlaySettings.showTemperatureOverlay = !Find.PlaySettings.showTemperatureOverlay;
+
+ TooltipHandler.TipRegion(outRect, "FALCHM.ThermometerTooltip".Translate());
+
+ Text.Anchor = TextAnchor.UpperLeft;
+ }
+
+ public override void OnGUI()
+ {
+ if (Current.ProgramState != ProgramState.Playing
+ || Find.CurrentMap == null
+ || WorldRendererUtility.WorldRenderedNow)
+ return;
+
+ UpdateOutdoorThermometer();
+ if (Find.PlaySettings.showTemperatureOverlay && _showTemperatureOverRooms)
+ {
+ TemperatureDisplayer.Update(_updateDelay);
+ TemperatureDisplayer.OnGUI();
+ }
+
+ if (Event.current.type != EventType.KeyDown || Event.current.keyCode == KeyCode.None)
+ return;
+
+ if (HeatMapKeyBingings.ToggleHeatMap.JustPressed)
+ {
+ if (WorldRendererUtility.WorldRenderedNow)
+ return;
+
+ Find.PlaySettings.showTemperatureOverlay = !Find.PlaySettings.showTemperatureOverlay;
+ }
+ }
+
+ public override void WorldLoaded()
+ {
+ ResetAll();
+ }
+
+ public override void DefsLoaded()
+ {
+ _overrideVanillaOverlay = Settings.GetHandle(
+ "overrideVanillaOverlay",
+ "FALCHM.OverrideVanillaOverlay".Translate(),
+ "FALCHM.OverrideVanillaOverlayDesc".Translate(new NamedArgument(true, "default")),
+ true);
+ _overrideVanillaOverlay.ValueChanged += val => ResetAll();
+
+ _showIndoorsOnly = Settings.GetHandle(
+ "showRoomsOnly",
+ "FALCHM.ShowIndoorsOnly".Translate(),
+ "FALCHM.ShowIndoorsOnlyDesc".Translate(new NamedArgument(true, "default")),
+ true);
+ _showIndoorsOnly.ValueChanged += val => ResetAll();
+
+ _opacity = Settings.GetHandle(
+ "opacity",
+ "FALCHM.OverlayOpacity".Translate(),
+ "FALCHM.OverlayOpacityDesc".Translate(new NamedArgument(30, "default")),
+ 30,
+ Validators.IntRangeValidator(0, 100));
+ _opacity.ValueChanged += val => ResetAll();
+
+ _updateDelay = Settings.GetHandle(
+ "updateDelay",
+ "FALCHM.UpdateDelay".Translate(),
+ "FALCHM.UpdateDelayDesc".Translate(new NamedArgument(100, "default")),
+ 100,
+ Validators.IntRangeValidator(1, 9999));
+
+
+ _showOutdoorThermometer = Settings.GetHandle(
+ "showOutdoorThermometer",
+ "FALCHM.ShowOutDoorThermometer".Translate(),
+ "FALCHM.ShowOutDoorThermometerDesc".Translate(new NamedArgument(true, "default")),
+ true);
+
+ _outdoorThermometerOpacity = Settings.GetHandle(
+ "outdoorThermometerOpacity",
+ "FALCHM.ThermometerOpacity".Translate(),
+ "FALCHM.ThermometerOpacityDesc".Translate(new NamedArgument(30, "default")),
+ 30,
+ Validators.IntRangeValidator(1, 100));
+ _outdoorThermometerOpacity.ValueChanged += val => _temperatureTextureCache.Clear();
+
+ _outdoorThermometerFixed = Settings.GetHandle(
+ "outdoorThermometerFixed",
+ "FALCHM.ThermometerFixed".Translate(),
+ "FALCHM.ThermometerFixedDesc".Translate(new NamedArgument(false, "default")),
+ false);
+
+ _outdoorThermometerRight = Settings.GetHandle(
+ "outdoorThermometerRight",
+ "FALCHM.ThermometerRight".Translate(),
+ "FALCHM.ThermometerRightDesc".Translate(new NamedArgument(8f + _boxSize, "default")),
+ 8f + _boxSize);
+
+ _outdoorThermometerTop = Settings.GetHandle(
+ "outdoorThermometerTop",
+ "FALCHM.ThermometerTop".Translate(),
+ "FALCHM.ThermometerTopDesc".Translate(new NamedArgument(8f, "default")),
+ 8f);
+
+
+ _showTemperatureOverRooms = Settings.GetHandle(
+ "showTemperatureOverRooms",
+ "FALCHM.ShowTemperatureOverRooms".Translate(),
+ "FALCHM.ShowTemperatureOverRoomsDesc".Translate(new NamedArgument(true, "default")),
+ true);
+
+ (var mappedRange, var minComfortTemp, var maxComfortTemp) = HeatMapHelper.GetComfortTemperatureRanges();
+
+ var gradientValidator = Validators.FloatRangeValidator(0f, 360f);
+ for (int i = 0; i < GradientSteps; i++)
+ {
+ _gradientHue[i] = Settings.GetHandle(
+ $"gradientHue{i}",
+ $"FALCHM.GradientHue".Translate(new NamedArgument(i, "index")),
+ $"FALCHM.GradientHueDesc".Translate(
+ new NamedArgument(240f - 60f * i, "default"),
+ new NamedArgument(mappedRange.min, "min"),
+ new NamedArgument(mappedRange.max, "max"),
+ new NamedArgument(minComfortTemp, "comfortMin"),
+ new NamedArgument(maxComfortTemp, "comfortMax")),
+ 240f - 60f * i, // 0° = red, 60° = yellow, 120° = green, 180° = cyan, 240° = blue, 300° = magenta; standard begins at blue (low) and ends at red (high)
+ gradientValidator);
+ _gradientHue[i].ValueChanged += val => ResetAll();
+ }
+
+
+ _useCustomRange = Settings.GetHandle(
+ "useCustomeRange",
+ "FALCHM.UseCustomeRange".Translate(),
+ "FALCHM.UseCustomeRangeDesc".Translate(new NamedArgument(false, "default")),
+ false);
+ _useCustomRange.ValueChanged += val => ResetAll();
+
+
+ _customRangeMin = Settings.GetHandle("customRangeMin", "Unused", "Unused", mappedRange.min);
+ _customRangeMin.VisibilityPredicate = () => false;
+
+ _customRangeMax = Settings.GetHandle("customRangeMax", "Unused", "Unused", mappedRange.max);
+ _customRangeMax.VisibilityPredicate = () => false;
+
+ _customRangeComfortMin = Settings.GetHandle("customRangeComfortMin", "Unused", "Unused", minComfortTemp);
+ _customRangeComfortMin.VisibilityPredicate = () => false;
+
+ _customRangeComfortMax = Settings.GetHandle("customRangeComfortMax", "Unused", "Unused", maxComfortTemp);
+ _customRangeComfortMax.VisibilityPredicate = () => false;
+
+
+ var customRangeValidator = Validators.IntRangeValidator(
+ (int)GenTemperature.CelsiusTo(-273f, Prefs.TemperatureMode),
+ (int)GenTemperature.CelsiusTo(1000f, Prefs.TemperatureMode));
+
+ var customRangeMin = Settings.GetHandle(
+ "customRangeMinPlaceholder",
+ "FALCHM.CustomRangeMin".Translate(),
+ $"{"FALCHM.CustomRangeMinDesc".Translate(new NamedArgument(mappedRange.min, "default"))} ({Prefs.TemperatureMode.ToStringHuman()})",
+ validator: customRangeValidator);
+ customRangeMin.Unsaved = true;
+ customRangeMin.VisibilityPredicate = () => _useCustomRange;
+ customRangeMin.Value = (int)GenTemperature.CelsiusTo(_customRangeMin, Prefs.TemperatureMode);
+
+ var customRangeMax = Settings.GetHandle(
+ "customRangeMaxPlaceholder",
+ "FALCHM.CustomRangeMax".Translate(),
+ $"{"FALCHM.CustomRangeMaxDesc".Translate(new NamedArgument(mappedRange.max, "default"))} ({Prefs.TemperatureMode.ToStringHuman()})",
+ validator: customRangeValidator);
+ customRangeMax.Unsaved = true;
+ customRangeMax.VisibilityPredicate = () => _useCustomRange;
+ customRangeMax.Value = (int)GenTemperature.CelsiusTo(_customRangeMax, Prefs.TemperatureMode);
+
+ var customRangeComfortMin = Settings.GetHandle(
+ "customRangeComfortMinPlaceholder",
+ "FALCHM.CustomRangeComfortMin".Translate(),
+ $"{"FALCHM.CustomRangeComfortMinDesc".Translate(new NamedArgument(minComfortTemp, "default"))} ({Prefs.TemperatureMode.ToStringHuman()})",
+ validator: customRangeValidator);
+ customRangeComfortMin.Unsaved = true;
+ customRangeComfortMin.VisibilityPredicate = () => _useCustomRange;
+ customRangeComfortMin.Value = (int)GenTemperature.CelsiusTo(_customRangeComfortMin, Prefs.TemperatureMode);
+
+ var customRangeComfortMax = Settings.GetHandle(
+ "customRangeComfortMaxPlaceholder",
+ "FALCHM.CustomRangeComfortMax".Translate(),
+ $"{"FALCHM.CustomRangeComfortMaxDesc".Translate(new NamedArgument(maxComfortTemp, "default"))} ({Prefs.TemperatureMode.ToStringHuman()})",
+ validator: customRangeValidator);
+ customRangeComfortMax.Unsaved = true;
+ customRangeComfortMax.VisibilityPredicate = () => _useCustomRange;
+ customRangeComfortMax.Value = (int)GenTemperature.CelsiusTo(_customRangeComfortMax, Prefs.TemperatureMode);
+
+
+ customRangeMin.ValueChanged += val =>
+ {
+ if (customRangeMax <= customRangeMin)
+ customRangeMax.Value = customRangeMin + 1;
+
+ _customRangeMin.Value = ConvertToCelcius(customRangeMin);
+ ResetAll();
+ };
+ customRangeMax.ValueChanged += val =>
+ {
+ if (customRangeMin >= customRangeMax)
+ customRangeMin.Value = customRangeMax - 1;
+
+ _customRangeMax.Value = ConvertToCelcius(customRangeMax);
+ ResetAll();
+ };
+ customRangeComfortMin.ValueChanged += val =>
+ {
+ _customRangeComfortMin.Value = ConvertToCelcius(customRangeComfortMin);
+ ResetAll();
+ };
+ customRangeComfortMax.ValueChanged += val =>
+ {
+ _customRangeComfortMax.Value = ConvertToCelcius(customRangeComfortMax);
+ ResetAll();
+ };
+ }
+
+ public void ResetAll()
+ {
+ HeatMapHelper.RegenerateColorMap();
+ TemperatureDisplayer.Reset();
+ _temperatureTextureCache.Clear();
+
+ Find.CurrentMap?.mapTemperature?.Drawer?.SetDirty();
+ }
+
+ private static int ConvertToCelcius(int value)
+ {
+ switch (Prefs.TemperatureMode)
+ {
+ default:
+ case TemperatureDisplayMode.Celsius:
+ return value;
+
+ case TemperatureDisplayMode.Kelvin:
+ return value - 273;
+
+ case TemperatureDisplayMode.Fahrenheit:
+ return (int)((value - 32) / 1.8f);
+ }
+ }
+ }
+}
diff --git a/src/HeatMap/HeatMap.csproj b/src/HeatMap/HeatMap.csproj
index d9e7cce..9496dd9 100644
--- a/src/HeatMap/HeatMap.csproj
+++ b/src/HeatMap/HeatMap.csproj
@@ -23,212 +23,17 @@
false
-
- ..\packages\Lib.Harmony.2.1.0\lib\net472\0Harmony.dll
-
-
- ..\..\ThirdParty\Assembly-CSharp.dll
-
-
- ..\packages\UnlimitedHugs.Rimworld.HugsLib.9.0.0\lib\net472\HugsLib.dll
-
-
-
-
-
- ..\..\ThirdParty\Unity.TextMeshPro.dll
-
-
- False
- ..\..\ThirdParty\UnityEngine.dll
-
-
- ..\..\ThirdParty\UnityEngine.AccessibilityModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.AIModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.AndroidJNIModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.AnimationModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.ARModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.AssetBundleModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.AudioModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.ClothModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.ClusterInputModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.ClusterRendererModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.CoreModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.CrashReportingModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.DirectorModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.DSPGraphModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.GameCenterModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.GridModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.HotReloadModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.ImageConversionModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.IMGUIModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.InputLegacyModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.InputModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.JSONSerializeModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.LocalizationModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.ParticleSystemModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.PerformanceReportingModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.Physics2DModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.PhysicsModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.ProfilerModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.ScreenCaptureModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.SharedInternalsModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.SpriteMaskModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.SpriteShapeModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.StreamingModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.SubstanceModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.TerrainModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.TerrainPhysicsModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.TextCoreModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.TextRenderingModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.TilemapModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.TLSModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UI.dll
-
-
- ..\..\ThirdParty\UnityEngine.UIElementsModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UIModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UmbraModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UNETModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UnityAnalyticsModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UnityConnectModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UnityTestProtocolModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UnityWebRequestAssetBundleModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UnityWebRequestAudioModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UnityWebRequestModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UnityWebRequestTextureModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.UnityWebRequestWWWModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.VehiclesModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.VFXModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.VideoModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.VRModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.WindModule.dll
-
-
- ..\..\ThirdParty\UnityEngine.XRModule.dll
-
+
-
-
-
+
+
+
@@ -279,7 +84,23 @@
-
+
+ 2.0.1
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ 1.4.3525
+
+
+ 2.2.2
+
+
+ 9.0.1
+
+
+
+
diff --git a/src/HeatMap/HeatMapHelper.cs b/src/HeatMap/HeatMapHelper.cs
new file mode 100644
index 0000000..01b5563
--- /dev/null
+++ b/src/HeatMap/HeatMapHelper.cs
@@ -0,0 +1,84 @@
+using RimWorld;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+
+namespace HeatMap
+{
+ public static class HeatMapHelper
+ {
+ internal static IntRange MappedTemperatureRange;
+ internal static Color[] MappedColors;
+
+ public static void RegenerateColorMap()
+ {
+ if (HeatMap.Instance.ShouldUseCustomRange)
+ CreateCustomMap();
+ else
+ CreateComfortMap();
+ }
+
+ private static void CreateCustomMap()
+ {
+ var minComfortTemp = HeatMap.Instance.CustomRangeComfortMin;
+ var maxComfortTemp = HeatMap.Instance.CustomRangeComfortMax;
+
+ MappedTemperatureRange = new IntRange(HeatMap.Instance.CustomRangeMin, HeatMap.Instance.CustomRangeMax);
+ MappedColors = CreateColorGradient(MappedTemperatureRange, minComfortTemp, maxComfortTemp);
+ }
+
+ private static void CreateComfortMap()
+ {
+ (var mappedRange, var minComfortTemp, var maxComfortTemp) = GetComfortTemperatureRanges();
+
+ MappedTemperatureRange = mappedRange;
+ MappedColors = CreateColorGradient(MappedTemperatureRange, minComfortTemp, maxComfortTemp);
+ }
+
+ private static Color[] CreateColorGradient(IntRange range, int minComfortTemp, int maxComfortTemp)
+ {
+ var mappedColorCount = MappedTemperatureRange.max - MappedTemperatureRange.min;
+
+ var gradientColors = new List>();
+ for (int i = 0; i < HeatMap.GradientSteps; i++)
+ gradientColors.Add(new Tuple(HeatMap.Instance.GetGradientColor(i), 1f));
+
+ var gradientSteps = new List();
+ for (int i = 0, t = range.min; i < mappedColorCount; i++, t++)
+ gradientSteps.Add((t >= minComfortTemp - 1 && t <= maxComfortTemp) ? 4f : 1f);
+
+ return ColorHelper.Gradient(gradientColors, gradientSteps).ToArray();
+ }
+
+ public static (IntRange mappedRange, int comfortTempMin, int comfortTempMax) GetComfortTemperatureRanges()
+ {
+ var human = ThingDefOf.Human;
+ var minComfortTemp = (int)human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMin) + 3;
+ var maxComfortTemp = (int)human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMax) - 3;
+
+ var comfortDoubleRange = (maxComfortTemp - minComfortTemp) * 2;
+ var mappedTemperatureRange = new IntRange(
+ minComfortTemp - comfortDoubleRange, maxComfortTemp + comfortDoubleRange);
+
+ return (mappedTemperatureRange, minComfortTemp, maxComfortTemp);
+ }
+
+ public static int GetIndexForTemperature(float temperature)
+ {
+ var colorMapIndex = (int)temperature - MappedTemperatureRange.min;
+ if (colorMapIndex < 0)
+ colorMapIndex = 0;
+ else if (colorMapIndex >= MappedColors.Length)
+ colorMapIndex = MappedColors.Length - 1;
+ return colorMapIndex;
+ }
+ public static Color GetColorForTemperature(float temperature)
+ {
+ return MappedColors[GetIndexForTemperature(temperature)];
+ }
+ }
+}
diff --git a/src/HeatMap/HeatMapKeyBindings.cs b/src/HeatMap/HeatMapKeyBindings.cs
new file mode 100644
index 0000000..6aada24
--- /dev/null
+++ b/src/HeatMap/HeatMapKeyBindings.cs
@@ -0,0 +1,16 @@
+using RimWorld;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+
+namespace HeatMap
+{
+ [DefOf]
+ public static class HeatMapKeyBingings
+ {
+ public static KeyBindingDef ToggleHeatMap;
+ }
+}
diff --git a/src/HeatMap/Main.cs b/src/HeatMap/Main.cs
deleted file mode 100644
index eeeac9a..0000000
--- a/src/HeatMap/Main.cs
+++ /dev/null
@@ -1,347 +0,0 @@
-using HugsLib.Settings;
-using HugsLib.Utils;
-using RimWorld;
-using RimWorld.Planet;
-using System.Collections.Generic;
-using System.Reflection;
-using UnityEngine;
-using Verse;
-
-namespace HeatMap
-{
- [DefOf]
- public static class HeatMapKeyBingings
- {
- public static KeyBindingDef ToggleHeatMap;
- }
-
- public class Main : HugsLib.ModBase
- {
- public Main()
- {
- Instance = this;
- }
-
- public void UpdateHeatMap()
- {
- if (_heatMap == null)
- _heatMap = new HeatMap();
-
- if (_opacity > 0)
- _heatMap.Update(_updateDelay);
- }
-
- public void UpdateOutdoorThermometer()
- {
- if (!_showOutdoorThermometer)
- return;
-
- if (_heatMap == null)
- return;
-
- var right = Mathf.Clamp(_draggingThermometer ? _dragThermometerRight : _outdoorThermometerRight, _boxSize, UI.screenWidth);
- var top = Mathf.Clamp(_draggingThermometer ? _dragThermometerTop : _outdoorThermometerTop, 0, UI.screenHeight - _boxSize);
- var outRect = new Rect(UI.screenWidth - right, top, _boxSize, _boxSize);
- if (TutorSystem.AdaptiveTrainingEnabled && Find.PlaySettings.showLearningHelper)
- {
- if (typeof(LearningReadout).GetField("windowRect", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(Find.Tutor.learningReadout) is Rect helpRect
- && helpRect.Overlaps(outRect) == true)
- outRect.x = helpRect.x - _boxSize - 5f;
- }
-
- if (!_outdoorThermometerFixed && Event.current.isMouse)
- {
- switch (Event.current.type)
- {
- case EventType.MouseDown:
- if (Mouse.IsOver(outRect) && Event.current.modifiers == EventModifiers.Shift)
- {
- Event.current.Use();
-
- _dragThermometerRight = _outdoorThermometerRight.Value;
- _dragThermometerTop = _outdoorThermometerTop.Value;
-
- _draggingThermometer = true;
- }
- break;
- case EventType.MouseDrag:
- if (_draggingThermometer)
- {
- Event.current.Use();
-
- _dragThermometerRight -= Event.current.delta.x;
- _dragThermometerRight = Mathf.Clamp(_dragThermometerRight, _boxSize, UI.screenWidth);
- _dragThermometerTop += Event.current.delta.y;
- _dragThermometerTop = Mathf.Clamp(_dragThermometerTop, 0, UI.screenHeight - _boxSize);
- //outRect = new Rect(outRect.x - _dragThermometerRight, outRect.y + _dragThermometerTop, _boxSize, _boxSize); // repositioning is processed on next update
- }
- break;
- case EventType.MouseUp:
- if (_draggingThermometer)
- {
- Event.current.Use();
-
- _outdoorThermometerRight.Value = _dragThermometerRight;
- _outdoorThermometerTop.Value = _dragThermometerTop;
-
- _draggingThermometer = false;
- }
- break;
- }
- }
-
- var temperature = Find.CurrentMap.mapTemperature.OutdoorTemp;
- var textureIndex = _heatMap.GetIndexForTemperature(temperature);
- if (!_temperatureTextureCache.ContainsKey(textureIndex))
- {
- var backColor = _heatMap.GetColorForTemperature(temperature);
- backColor.a = _outdoorThermometerOpacity / 100f;
- _temperatureTextureCache[textureIndex] = SolidColorMaterials.NewSolidColorTexture(backColor);
- }
- GUI.DrawTexture(outRect, _temperatureTextureCache[textureIndex]);
- GUI.DrawTexture(outRect, Resources.DisplayBoder);
-
- var temperatureForDisplay = temperature.ToStringTemperature("F0");
- Text.Font = GameFont.Medium;
- Text.Anchor = TextAnchor.MiddleCenter;
- GUI.color = Color.white;
- Widgets.Label(outRect, temperatureForDisplay);
-
- if (Widgets.ButtonInvisible(outRect))
- {
- ShowHeatMap = !ShowHeatMap;
- }
- TooltipHandler.TipRegion(outRect, "FALCHM.ThermometerTooltip".Translate());
-
- Text.Anchor = TextAnchor.UpperLeft;
- }
-
- public override void OnGUI()
- {
- if (Current.ProgramState != ProgramState.Playing ||
- Find.CurrentMap == null ||
- WorldRendererUtility.WorldRenderedNow ||
- _heatMap == null)
- {
- return;
- }
-
- UpdateOutdoorThermometer();
- if (ShowHeatMap && _showTemperatureOverRooms)
- {
- TemperatureDisplayer.Update(_updateDelay);
- TemperatureDisplayer.OnGUI();
- }
-
- if (Event.current.type != EventType.KeyDown || Event.current.keyCode == KeyCode.None)
- {
- return;
- }
-
- if (HeatMapKeyBingings.ToggleHeatMap.JustPressed)
- {
- if (WorldRendererUtility.WorldRenderedNow)
- {
- return;
- }
- ShowHeatMap = !ShowHeatMap;
- }
- }
-
- public override void WorldLoaded()
- {
- ResetAll();
- }
-
- public override void DefsLoaded()
- {
- _opacity = Settings.GetHandle(
- "opacity", "FALCHM.OverlayOpacity".Translate(),
- "FALCHM.OverlayOpacityDesc".Translate(), 30,
- Validators.IntRangeValidator(0, 100));
-
- _opacity.ValueChanged += val => { _heatMap?.Reset(); };
-
- _updateDelay = Settings.GetHandle("updateDelay",
- "FALCHM.UpdateDelay".Translate(),
- "FALCHM.UpdateDelayDesc".Translate(),
- 100,
- Validators.IntRangeValidator(1, 9999));
-
-
- _showOutdoorThermometer = Settings.GetHandle(
- "showOutdoorThermometer",
- "FALCHM.ShowOutDoorThermometer".Translate(),
- "FALCHM.ShowOutDoorThermometerDesc".Translate(),
- true);
-
- _outdoorThermometerOpacity = Settings.GetHandle(
- "outdoorThermometerOpacity",
- "FALCHM.ThermometerOpacity".Translate(),
- "FALCHM.ThermometerOpacityDesc".Translate(),
- 30,
- Validators.IntRangeValidator(1, 100));
- _outdoorThermometerOpacity.ValueChanged += val => { _temperatureTextureCache.Clear(); };
-
- _outdoorThermometerFixed = Settings.GetHandle(
- "outdoorThermometerFixed",
- "FALCHM.ThermometerFixed".Translate(),
- "FALCHM.ThermometerFixedDesc".Translate(),
- false);
-
- _outdoorThermometerRight = Settings.GetHandle(
- "outdoorThermometerRight",
- "FALCHM.ThermometerRight".Translate(),
- "FALCHM.ThermometerRightDesc".Translate(),
- 8f + _boxSize);
-
- _outdoorThermometerTop = Settings.GetHandle(
- "outdoorThermometerTop",
- "FALCHM.ThermometerTop".Translate(),
- "FALCHM.ThermometerTopDesc".Translate(),
- 8f);
-
-
- _showTemperatureOverRooms = Settings.GetHandle(
- "showTemperatureOverRooms",
- "FALCHM.ShowTemperatureOverRooms".Translate(),
- "FALCHM.ShowTemperatureOverRoomsDesc".Translate(),
- true);
-
-
- _useCustomRange = Settings.GetHandle(
- "useCustomeRange",
- "FALCHM.UseCustomeRange".Translate(),
- "FALCHM.UseCustomeRangeDesc".Translate(),
- false);
- _useCustomRange.ValueChanged += val => { ResetAll(); };
-
-
- _customRangeMin = Settings.GetHandle("customRangeMin", "Unused", "Unused", 0);
- _customRangeMax = Settings.GetHandle("customRangeMax", "Unused", "Unused", 40);
-
- _customRangeMin.VisibilityPredicate = () => false;
- _customRangeMax.VisibilityPredicate = () => false;
-
-
- var customRangeValidator = Validators.IntRangeValidator(
- (int)GenTemperature.CelsiusTo(-100, Prefs.TemperatureMode),
- (int)GenTemperature.CelsiusTo(100, Prefs.TemperatureMode));
-
- var customRangeMin = Settings.GetHandle(
- "customRangeMinPlaceholder",
- "FALCHM.CustomRangeMin".Translate(),
- $"{"FALCHM.CustomRangeMinDesc".Translate()} ({Prefs.TemperatureMode.ToStringHuman()})",
- (int)GenTemperature.CelsiusTo(_customRangeMin, Prefs.TemperatureMode),
- customRangeValidator);
-
- customRangeMin.Unsaved = true;
- customRangeMin.VisibilityPredicate = () => _useCustomRange;
-
- var customRangeMax = Settings.GetHandle(
- "customRangeMaxPlaceholder",
- "FALCHM.CustomRangeMax".Translate(),
- $"{"FALCHM.CustomRangeMaxDesc".Translate()} ({Prefs.TemperatureMode.ToStringHuman()})",
- (int)GenTemperature.CelsiusTo(_customRangeMax, Prefs.TemperatureMode),
- customRangeValidator);
-
- customRangeMax.Unsaved = true;
- customRangeMax.VisibilityPredicate = () => _useCustomRange;
-
-
- customRangeMin.ValueChanged += val =>
- {
- if (customRangeMax <= customRangeMin)
- customRangeMax.Value = customRangeMin + 1;
-
- _customRangeMin.Value = ConvertToCelcius(customRangeMin);
- ResetAll();
- };
-
-
- customRangeMax.ValueChanged += val =>
- {
- if (customRangeMin >= customRangeMax)
- customRangeMin.Value = customRangeMax - 1;
-
- _customRangeMax.Value = ConvertToCelcius(customRangeMax);
- ResetAll();
- };
- }
-
- public bool ShouldUseCustomRange()
- {
- return _useCustomRange;
- }
-
- public int GetCustomRangeMin()
- {
- return _customRangeMin;
- }
-
- public int GetCustomRangeMax()
- {
- return _customRangeMax;
- }
-
- public float GetConfiguredOpacity()
- {
- return _opacity / 100f;
- }
-
- public void ResetAll()
- {
- _heatMap = null;
- TemperatureDisplayer.Reset();
- _temperatureTextureCache.Clear();
- }
-
- private static int ConvertToCelcius(int value)
- {
- switch (Prefs.TemperatureMode)
- {
- case TemperatureDisplayMode.Celsius:
- return value;
-
- case TemperatureDisplayMode.Kelvin:
- return value - 273;
-
- default:
- return (int)((value - 32) / 1.8f);
- }
- }
-
- internal new ModLogger Logger => base.Logger;
-
- internal static Main Instance { get; private set; }
-
- public override string ModIdentifier => "HeatMap";
-
- public bool ShowHeatMap;
-
- public RoomTemperatureDisplayer TemperatureDisplayer { get; } = new RoomTemperatureDisplayer();
-
- private HeatMap _heatMap;
- private const float _boxSize = 62f;
- private bool _draggingThermometer = false;
- private float _dragThermometerRight = 0f;
- private float _dragThermometerTop = 0f;
-
- private readonly Dictionary _temperatureTextureCache = new Dictionary();
-
- private SettingHandle _opacity;
- private SettingHandle _updateDelay;
-
- private SettingHandle _showOutdoorThermometer;
- private SettingHandle _outdoorThermometerOpacity;
- private SettingHandle _outdoorThermometerFixed;
- private SettingHandle _outdoorThermometerRight;
- private SettingHandle _outdoorThermometerTop;
-
- private SettingHandle _showTemperatureOverRooms;
-
- private SettingHandle _useCustomRange;
- private SettingHandle _customRangeMin;
- private SettingHandle _customRangeMax;
- }
-}
diff --git a/src/HeatMap/MapInterface_Detour.cs b/src/HeatMap/MapInterface_Detour.cs
deleted file mode 100644
index 0138a24..0000000
--- a/src/HeatMap/MapInterface_Detour.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using HarmonyLib;
-using RimWorld;
-using RimWorld.Planet;
-using Verse;
-
-namespace HeatMap
-{
- [HarmonyPatch(typeof(MapInterface), "MapInterfaceUpdate")]
- public static class MapInterface_MapInterfaceUpdate_Detour
- {
- [HarmonyPostfix]
- static void Postfix()
- {
- if (Find.CurrentMap == null || WorldRendererUtility.WorldRenderedNow)
- {
- return;
- }
-
- Main.Instance.UpdateHeatMap();
- }
- }
-
- [HarmonyPatch(typeof(MapInterface), "Notify_SwitchedMap")]
- internal static class MapInterface_Notify_SwitchedMap_Detour
- {
- [HarmonyPostfix]
- static void Postfix()
- {
- Main.Instance.ResetAll();
- }
- }
-}
\ No newline at end of file
diff --git a/src/HeatMap/MapTemperature_Detour.cs b/src/HeatMap/MapTemperature_Detour.cs
new file mode 100644
index 0000000..251758d
--- /dev/null
+++ b/src/HeatMap/MapTemperature_Detour.cs
@@ -0,0 +1,92 @@
+using HarmonyLib;
+using RimWorld;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using Verse;
+
+namespace HeatMap
+{
+ [HarmonyPatch(typeof(MapTemperature), "GetColorForTemperature")]
+ public static class MapTemperature_GetColorForTemperature_Patch
+ {
+ [HarmonyPrefix]
+ static bool Prefix(ref Color __result, float temperature)
+ {
+ // use vanilla overlay
+ if (!HeatMap.Instance.OverrideVanillaOverlay)
+ return true; // execute original
+
+ // use HeatMap's overlay
+ __result = HeatMapHelper.GetColorForTemperature(temperature);
+ return false; // skip the original
+ }
+ }
+
+ [HarmonyPatch(typeof(MapTemperature), "get_Drawer")]
+ public static class MapTemperature_get_Drawer_Patch
+ {
+ [HarmonyPostfix]
+ static void Postfix(ref CellBoolDrawer __result)
+ {
+ // check if opacity changed
+ var opacity = HeatMap.Instance.OverlayOpacity;
+ if (__result?.opacity != opacity)
+ {
+ // set drawer opacity
+ __result.opacity = opacity;
+
+ // Material must be set to null to regenerate it, which applies the opacity
+ __result.material = null;
+ }
+ }
+ }
+
+ [HarmonyPatch(typeof(MapTemperature), "GetCellBool")]
+ public static class MapTemperature_GetCellBool_Patch
+ {
+ [HarmonyTranspiler]
+ static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ var output = new List();
+ foreach (var instruction in instructions)
+ {
+ // override everything past GetRooms
+ if (instruction.opcode == OpCodes.Call
+ && instruction.operand is MethodInfo methodInfo
+ && methodInfo.Name == nameof(GridsUtility.GetRoom))
+ break;
+
+ // keep everything before GetRooms
+ output.Add(instruction);
+ }
+
+ // call static System.Boolean HeatMap.MapTemperature_GetCellBool_Patch::Check(Verse.IntVec3 intVec, Verse.Map map)
+ output.Add(
+ new CodeInstruction(OpCodes.Call,
+ typeof(MapTemperature_GetCellBool_Patch).GetMethod(nameof(MapTemperature_GetCellBool_Patch.CheckRoom), BindingFlags.Static | BindingFlags.NonPublic)));
+ // ret NULL
+ output.Add(new CodeInstruction(OpCodes.Ret));
+
+ // output the changed IL code
+ return output;
+ }
+
+ ///
+ /// Checks if tile is valid and if it is outdoors, check if outdoors temperature should get an overlay
+ ///
+ ///
+ ///
+ ///
+ private static bool CheckRoom(IntVec3 intVec, Map map)
+ {
+ var room = intVec.GetRoom(map);
+ return room != null && (!room.PsychologicallyOutdoors || !HeatMap.Instance.ShowIndoorsOnly);
+ }
+ }
+}
diff --git a/src/HeatMap/PlaySettings_Detour.cs b/src/HeatMap/PlaySettings_Detour.cs
deleted file mode 100644
index 0e99472..0000000
--- a/src/HeatMap/PlaySettings_Detour.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using HarmonyLib;
-using RimWorld;
-using Verse;
-
-namespace HeatMap
-{
- [HarmonyPatch(typeof(PlaySettings), "DoPlaySettingsGlobalControls")]
- public static class PlaySettings_Detour
- {
- [HarmonyPostfix]
- static void PostFix(WidgetRow row, bool worldView)
- {
- if (worldView)
- return;
-
- if (row == null || Resources.Icon == null)
- return;
-
- row.ToggleableIcon(ref Main.Instance.ShowHeatMap, Resources.Icon,
- "FALCHM.ShowHeatMap".Translate(), SoundDefOf.Mouseover_ButtonToggle);
- }
- }
-}
\ No newline at end of file
diff --git a/src/HeatMap/Properties/AssemblyInfo.cs b/src/HeatMap/Properties/AssemblyInfo.cs
index 6305ec1..f04daa5 100644
--- a/src/HeatMap/Properties/AssemblyInfo.cs
+++ b/src/HeatMap/Properties/AssemblyInfo.cs
@@ -31,8 +31,10 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.3.18.0")]
-[assembly: AssemblyFileVersion("1.3.18.0")]
+[assembly: AssemblyVersion("1.5.19.0")]
+[assembly: AssemblyFileVersion("1.5.19.0")]
+
+
diff --git a/src/HeatMap/packages.config b/src/HeatMap/packages.config
deleted file mode 100644
index e422788..0000000
--- a/src/HeatMap/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file