diff --git a/UtilityGrid/GridPipe.cs b/UtilityGrid/GridPipe.cs
new file mode 100644
index 00000000..6f64058e
--- /dev/null
+++ b/UtilityGrid/GridPipe.cs
@@ -0,0 +1,8 @@
+namespace UtilityGrid
+{
+ public class GridPipe
+ {
+ public int index;
+ public int rotation;
+ }
+}
\ No newline at end of file
diff --git a/UtilityGrid/HelperEvents.cs b/UtilityGrid/HelperEvents.cs
new file mode 100644
index 00000000..9898b1be
--- /dev/null
+++ b/UtilityGrid/HelperEvents.cs
@@ -0,0 +1,245 @@
+using HarmonyLib;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using StardewModdingAPI;
+using StardewValley;
+using System;
+using System.Collections.Generic;
+
+namespace UtilityGrid
+{
+ /// The mod entry point.
+ public partial class ModEntry
+ {
+
+
+ public void Input_ButtonPressed(object sender, StardewModdingAPI.Events.ButtonPressedEventArgs e)
+ {
+ if (!Config.EnableMod || !(Game1.currentLocation is Farm) || !Game1.currentLocation.IsOutdoors || Game1.activeClickableMenu != null)
+ return;
+
+ if (e.Button == Config.ToggleGrid)
+ {
+ Helper.Input.Suppress(e.Button);
+ ShowingGrid = !ShowingGrid;
+ Monitor.Log($"Showing grid: {ShowingGrid}");
+ }
+ if (!ShowingGrid)
+ return;
+ if (e.Button == Config.SwitchGrid)
+ {
+ Helper.Input.Suppress(e.Button);
+ CurrentGrid = CurrentGrid == GridType.water ? GridType.electric : GridType.water;
+ Monitor.Log($"Showing grid: {CurrentGrid}");
+ }
+ else if (e.Button == Config.SwitchTile)
+ {
+ Helper.Input.Suppress(e.Button);
+ CurrentTile++;
+ CurrentTile %= 6;
+ CurrentRotation = 0;
+ //Monitor.Log($"Showing tile: {CurrentTile},{CurrentRotation}");
+ }
+ else if (e.Button == Config.RotateTile)
+ {
+ Helper.Input.Suppress(e.Button);
+ CurrentRotation++;
+ if (CurrentTile == 1)
+ CurrentRotation %= 2;
+ else if (CurrentTile == 4)
+ CurrentRotation = 0;
+ else
+ CurrentRotation %= 4;
+ //Monitor.Log($"Showing tile: {CurrentTile},{CurrentRotation}");
+ }
+ else if (e.Button == Config.PlaceTile)
+ {
+ Helper.Input.Suppress(e.Button);
+ Dictionary pipeDict;
+ if (CurrentGrid == GridType.electric)
+ {
+ pipeDict = electricPipes;
+ }
+ else
+ {
+ pipeDict = waterPipes;
+ }
+ if(CurrentTile == 5)
+ {
+ Monitor.Log($"Removing tile at {Game1.currentCursorTile}");
+ pipeDict.Remove(Game1.lastCursorTile);
+ }
+ else
+ {
+ Monitor.Log($"Placing tile {CurrentTile},{CurrentRotation} at {Game1.currentCursorTile}");
+ pipeDict[Game1.lastCursorTile] = new GridPipe() { index = CurrentTile, rotation = CurrentRotation };
+ }
+ RemakeGroups(CurrentGrid);
+ }
+ }
+ public void Display_RenderedWorld(object sender, StardewModdingAPI.Events.RenderedWorldEventArgs e)
+ {
+ if (!Config.EnableMod || !ShowingGrid)
+ return;
+
+ if(!(Game1.currentLocation is Farm) || !Game1.currentLocation.IsOutdoors || Game1.activeClickableMenu != null)
+ {
+ ShowingGrid = false;
+ return;
+ }
+
+ List groupList;
+ Color color;
+ Dictionary pipeDict;
+ if (CurrentGrid == GridType.electric)
+ {
+ groupList = electricGroups;
+ pipeDict = electricPipes;
+ color = Config.ElectricityColor;
+ }
+ else
+ {
+ groupList = waterGroups;
+ pipeDict = waterPipes;
+ color = Config.WaterColor;
+ }
+ foreach (var group in groupList)
+ {
+ Vector2 power = GetGroupPower(group, CurrentGrid);
+ float netPower = power.X + power.Y;
+ bool powered = power.X > 0 && netPower >= 0;
+ foreach (var pipe in group.pipes)
+ {
+ if (Utility.isOnScreen(new Vector2(pipe.X * 64 + 32, pipe.Y * 64 + 32), 32))
+ {
+ if (pipe != Game1.currentCursorTile)
+ {
+ if (pipeDict[pipe].index == 4)
+ DrawTile(e.SpriteBatch, pipe, new GridPipe() { index = 1, rotation = 2 }, powered ? color : Color.White);
+ else
+ DrawTile(e.SpriteBatch, pipe, pipeDict[pipe], powered ? color : Color.White);
+ }
+ }
+ }
+ foreach (var kvp in group.objects)
+ {
+ float objPower;
+ bool enough = netPower >= 0;
+ if (CurrentGrid == GridType.electric)
+ {
+ objPower = kvp.Value.electric;
+ }
+ else
+ {
+ objPower = kvp.Value.water;
+ if (kvp.Value.electric < 0 && GetTileNetElectricPower(kvp.Key) < 0)
+ enough = false;
+ }
+
+ if (objPower == 0)
+ continue;
+
+
+ string str = "" + Math.Round(objPower);
+
+ e.SpriteBatch.DrawString(Game1.dialogueFont, str, Game1.GlobalToLocal(Game1.viewport, kvp.Key * 64) - new Vector2(16, 16) + new Vector2(-2, 2), Color.Black, 0, Vector2.Zero, 1f, SpriteEffects.None, 0.999999f);
+ e.SpriteBatch.DrawString(Game1.dialogueFont, str, Game1.GlobalToLocal(Game1.viewport, kvp.Key * 64) - new Vector2(16, 16), enough ? color : Config.InsufficientColor, 0, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f);
+ }
+
+ }
+ if (CurrentTile == 4)
+ DrawTile(e.SpriteBatch, Game1.currentCursorTile, new GridPipe() { index = 1, rotation = 2 }, color);
+ else if(CurrentTile != 5)
+ DrawTile(e.SpriteBatch, Game1.currentCursorTile, new GridPipe() { index = CurrentTile, rotation = CurrentRotation }, color);
+ }
+
+ private void GameLoop_OneSecondUpdateTicked(object sender, StardewModdingAPI.Events.OneSecondUpdateTickedEventArgs e)
+ {
+ if (!Config.EnableMod || !(Game1.currentLocation is Farm))
+ return;
+
+ RemakeAllGroups();
+
+ }
+
+ private void GameLoop_SaveLoaded(object sender, StardewModdingAPI.Events.SaveLoadedEventArgs e)
+ {
+ waterPipes = new Dictionary();
+ electricPipes = new Dictionary();
+ ShowingGrid = false;
+ CurrentRotation = 0;
+ CurrentTile = 0;
+
+ objectDict = SHelper.Content.Load>(dictPath, ContentSource.GameContent);
+ UtilityGridData gridData = Helper.Data.ReadSaveData(saveKey) ?? new UtilityGridData();
+ Monitor.Log($"reading {gridData.electricData.Count} ep and {gridData.waterData.Count} wp from save");
+ foreach (var arr in gridData.waterData)
+ {
+ waterPipes[new Vector2(arr[0], arr[1])] = new GridPipe() { index = arr[2], rotation = arr[3] };
+ }
+ foreach(var arr in gridData.electricData)
+ {
+ electricPipes[new Vector2(arr[0], arr[1])] = new GridPipe() { index = arr[2], rotation = arr[3] };
+ }
+ RemakeAllGroups();
+ }
+ private void GameLoop_Saving(object sender, StardewModdingAPI.Events.SavingEventArgs e)
+ {
+
+ UtilityGridData gridData = new UtilityGridData(waterPipes, electricPipes);
+ Monitor.Log($"writing {gridData.electricData.Count} ep and {gridData.waterData.Count} wp to save");
+ Helper.Data.WriteSaveData(saveKey, gridData);
+ }
+ public void GameLoop_GameLaunched(object sender, StardewModdingAPI.Events.GameLaunchedEventArgs e)
+ {
+ // get Generic Mod Config Menu's API (if it's installed)
+ var configMenu = Helper.ModRegistry.GetApi("spacechase0.GenericModConfigMenu");
+ if (configMenu is null)
+ return;
+
+ // register mod
+ configMenu.Register(
+ mod: ModManifest,
+ reset: () => Config = new ModConfig(),
+ save: () => Helper.WriteConfig(Config)
+ );
+
+ configMenu.AddBoolOption(
+ mod: ModManifest,
+ name: () => "Mod Enabled?",
+ getValue: () => Config.EnableMod,
+ setValue: value => Config.EnableMod = value
+ );
+ configMenu.AddKeybind(
+ mod: ModManifest,
+ name: () => "Toggle Grid Key",
+ getValue: () => Config.ToggleGrid,
+ setValue: value => Config.ToggleGrid = value
+ );
+ configMenu.AddKeybind(
+ mod: ModManifest,
+ name: () => "Switch Grid Key",
+ getValue: () => Config.ToggleGrid,
+ setValue: value => Config.ToggleGrid = value
+ );
+ configMenu.AddKeybind(
+ mod: ModManifest,
+ name: () => "Change Tile Key",
+ getValue: () => Config.SwitchTile,
+ setValue: value => Config.SwitchTile = value
+ );
+ configMenu.AddKeybind(
+ mod: ModManifest,
+ name: () => "Rotate Tile Key",
+ getValue: () => Config.RotateTile,
+ setValue: value => Config.RotateTile = value
+ );
+ configMenu.AddKeybind(
+ mod: ModManifest,
+ name: () => "Place Tile Key",
+ getValue: () => Config.PlaceTile,
+ setValue: value => Config.PlaceTile = value
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/UtilityGrid/MethodPatches.cs b/UtilityGrid/MethodPatches.cs
new file mode 100644
index 00000000..5de9b8c1
--- /dev/null
+++ b/UtilityGrid/MethodPatches.cs
@@ -0,0 +1,58 @@
+using Microsoft.Xna.Framework;
+using StardewValley;
+
+namespace UtilityGrid
+{
+ public partial class ModEntry
+ {
+ // dga_add "aedenthorn.WaterPumpDGA/Bronze Water Pump" 1
+ public static bool Utility_playerCanPlaceItemHere_Prefix(GameLocation location, Item item, int x, int y, ref bool __result)
+ {
+ //SMonitor.Log($"placing {item.Name}, {objectDict.ContainsKey(item.Name)}");
+ if (!Config.EnableMod || !objectDict.ContainsKey(item.Name) || !(location is Farm) || !objectDict[item.Name].onlyInWater || location.Objects.ContainsKey(new Vector2(x, y)))
+ return true;
+ __result = location.isWaterTile(x / 64, y / 64);
+ return false;
+ }
+ public static void Object_IsSprinkler_Postfix(Object __instance, ref bool __result)
+ {
+ //SMonitor.Log($"placing {item.Name}, {objectDict.ContainsKey(item.Name)}");
+ if (!Config.EnableMod || !__result || !objectDict.ContainsKey(__instance.Name))
+ return;
+ __result = IsObjectPowered(__instance.TileLocation, objectDict[__instance.Name]);
+
+ }
+ public static void Object_updateWhenCurrentLocation_Prefix(Object __instance)
+ {
+ //SMonitor.Log($"placing {item.Name}, {objectDict.ContainsKey(item.Name)}");
+ if (!Config.EnableMod || !objectDict.ContainsKey(__instance.Name))
+ return;
+ __instance.IsOn = IsObjectPowered(__instance.TileLocation, objectDict[__instance.Name]);
+
+ }
+ public static Object preItem = null;
+ public static int minutesUntilReady = 0;
+ public static void Object_DayUpdate_Prefix(Object __instance, ref bool __state)
+ {
+ //SMonitor.Log($"placing {item.Name}, {objectDict.ContainsKey(item.Name)}");
+ if (!Config.EnableMod || !objectDict.ContainsKey(__instance.Name))
+ return;
+ if(!IsObjectPowered(__instance.TileLocation, objectDict[__instance.Name]))
+ {
+ preItem = __instance.heldObject.Value;
+ minutesUntilReady = __instance.MinutesUntilReady;
+ __instance.heldObject.Value = null;
+ __state = true;
+ }
+
+ }
+ public static void Object_DayUpdate_Postfix(Object __instance, bool __state)
+ {
+ //SMonitor.Log($"placing {item.Name}, {objectDict.ContainsKey(item.Name)}");
+ if (!__state)
+ return;
+ __instance.MinutesUntilReady = minutesUntilReady;
+ __instance.heldObject.Value = preItem;
+ }
+ }
+}
\ No newline at end of file
diff --git a/UtilityGrid/ModConfig.cs b/UtilityGrid/ModConfig.cs
index 63dbaaa3..cfdefd56 100644
--- a/UtilityGrid/ModConfig.cs
+++ b/UtilityGrid/ModConfig.cs
@@ -15,5 +15,6 @@ public class ModConfig
public SButton PlaceTile { get; set; } = SButton.MouseLeft;
public Color WaterColor { get; set; } = Color.Aqua;
public Color ElectricityColor { get; set; } = Color.Yellow;
+ public Color InsufficientColor { get; set; } = Color.Red;
}
}
diff --git a/UtilityGrid/ModEntry.cs b/UtilityGrid/ModEntry.cs
index 3156a28f..90ea0ab8 100644
--- a/UtilityGrid/ModEntry.cs
+++ b/UtilityGrid/ModEntry.cs
@@ -5,11 +5,12 @@
using StardewValley;
using System;
using System.Collections.Generic;
+using Object = StardewValley.Object;
namespace UtilityGrid
{
/// The mod entry point.
- public partial class ModEntry : Mod
+ public partial class ModEntry : Mod, IAssetLoader
{
public static IMonitor SMonitor;
@@ -19,17 +20,32 @@ public partial class ModEntry : Mod
public static ModEntry context;
public static Texture2D pipeTexture;
+ public static readonly string dictPath = "utility_grid_object_dictionary";
+ public enum GridType {
+ water,
+ electric
+ }
+ public static readonly string saveKey = "utility-grid-data";
+
public static bool ShowingGrid { get; set; } = false;
- public static bool ElectricGrid { get; set; } = false;
+ public static GridType CurrentGrid { get; set; } = GridType.water;
public static int CurrentTile { get; set; } = 0;
public static int CurrentRotation { get; set; } = 0;
- public static int[][] intakeArray = { new int[]{0, 1, 1, 1}, new int[]{1, 0, 0, 1}, new int[]{1, 0, 0, 0}, new int[]{0, 1, 0, 1}, new int[]{1, 1, 1, 1} };
-
- public Dictionary waterPipes = new Dictionary();
- public Dictionary electricPipes = new Dictionary();
- public List waterGroups = new List();
- public List electricGroups = new List();
+ public static int[][] intakeArray = {
+ new int[] { 1, 0, 0, 0 },
+ new int[] { 0, 1, 0, 1 },
+ new int[] { 1, 0, 0, 1 },
+ new int[] { 0, 1, 1, 1 },
+ new int[] { 1, 1, 1, 1 }
+ };
+
+ public static Dictionary waterPipes = new Dictionary();
+ public static Dictionary electricPipes = new Dictionary();
+ public static Dictionary objectDict = new Dictionary();
+
+ public static List waterGroups = new List();
+ public static List electricGroups = new List();
/// The mod entry point, called after the mod is first loaded.
/// Provides simplified APIs for writing mods.
@@ -47,168 +63,53 @@ public override void Entry(IModHelper helper)
helper.Events.Input.ButtonPressed += Input_ButtonPressed;
helper.Events.GameLoop.GameLaunched += GameLoop_GameLaunched;
+ helper.Events.GameLoop.SaveLoaded += GameLoop_SaveLoaded;
+ helper.Events.GameLoop.Saving += GameLoop_Saving;
helper.Events.Display.RenderedWorld += Display_RenderedWorld;
+ helper.Events.GameLoop.OneSecondUpdateTicked += GameLoop_OneSecondUpdateTicked;
var harmony = new Harmony(ModManifest.UniqueID);
- // Game1 Patches
- /*
- harmony.Patch(
- original: AccessTools.Method(typeof(Game1), "_newDayAfterFade"),
- prefix: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.Game1__newDayAfterFade_Prefix))
- );
- */
+ harmony.Patch(
+ original: AccessTools.Method(typeof(Utility), nameof(Utility.playerCanPlaceItemHere)),
+ prefix: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.Utility_playerCanPlaceItemHere_Prefix))
+ );
+ harmony.Patch(
+ original: AccessTools.Method(typeof(Object), nameof(Object.IsSprinkler)),
+ postfix: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.Object_IsSprinkler_Postfix))
+ );
+ harmony.Patch(
+ original: AccessTools.Method(typeof(Object), nameof(Object.updateWhenCurrentLocation)),
+ prefix: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.Object_updateWhenCurrentLocation_Prefix))
+ );
pipeTexture = Helper.Content.Load("assets/pipes.png");
}
- private void Input_ButtonPressed(object sender, StardewModdingAPI.Events.ButtonPressedEventArgs e)
- {
- if (!Config.EnableMod || !(Game1.currentLocation is Farm) || !Game1.currentLocation.IsOutdoors)
- return;
- if (e.Button == Config.ToggleGrid)
- {
- Helper.Input.Suppress(e.Button);
- ShowingGrid = !ShowingGrid;
- Monitor.Log($"Showing grid: {ShowingGrid}");
- }
- if (!ShowingGrid)
- return;
- if (e.Button == Config.SwitchGrid)
- {
- Helper.Input.Suppress(e.Button);
- ElectricGrid = !ElectricGrid;
- Monitor.Log($"Showing Electric grid: {ElectricGrid}");
- }
- else if (e.Button == Config.SwitchTile)
- {
- Helper.Input.Suppress(e.Button);
- CurrentTile++;
- CurrentTile %= 6;
- CurrentRotation = 0;
- Monitor.Log($"Showing tile: {CurrentTile},{CurrentRotation}");
- }
- else if (e.Button == Config.RotateTile)
- {
- Helper.Input.Suppress(e.Button);
- CurrentRotation++;
- if (CurrentTile < 3)
- CurrentRotation %= 4;
- else if (CurrentTile == 3)
- CurrentRotation %= 2;
- else
- CurrentRotation = 0;
- Monitor.Log($"Showing tile: {CurrentTile},{CurrentRotation}");
- }
- else if (e.Button == Config.PlaceTile)
- {
- Helper.Input.Suppress(e.Button);
- Dictionary pipeDict;
- if (ElectricGrid)
- {
- pipeDict = electricPipes;
- }
- else
- {
- pipeDict = waterPipes;
- }
- if(CurrentTile == 5)
- pipeDict.Remove(Game1.lastCursorTile);
- else
- pipeDict[Game1.lastCursorTile] = new Point(CurrentTile, CurrentRotation);
- RemakeGroups(ElectricGrid);
- Monitor.Log($"Placing tile: {CurrentTile},{CurrentRotation} at {Game1.currentCursorTile}; connected? {PipeIsPowered(Game1.currentCursorTile, ElectricGrid)}");
- }
- }
- private void Display_RenderedWorld(object sender, StardewModdingAPI.Events.RenderedWorldEventArgs e)
+
+ public override object GetApi()
{
- if (!Config.EnableMod || !ShowingGrid)
- return;
- Dictionary pipeDict;
- Color color;
- if (ElectricGrid)
- {
- pipeDict = electricPipes;
- color = Config.ElectricityColor;
- }
- else
- {
- pipeDict = waterPipes;
- color = Config.WaterColor;
- }
- foreach (var kvp in pipeDict)
- {
- if (kvp.Key == Game1.currentCursorTile)
- {
- continue;
- }
- if (Utility.isOnScreen(new Vector2(kvp.Key.X * 64 + 32, kvp.Key.Y * 64 + 32), 32))
- {
- if (kvp.Value.X == 4)
- DrawTile(e.SpriteBatch, kvp.Key, new Point(3, 2), ElectricGrid, PipeIsPowered(kvp.Key, ElectricGrid) ? color : Color.White);
- else
- DrawTile(e.SpriteBatch, kvp.Key, kvp.Value, ElectricGrid, PipeIsPowered(kvp.Key, ElectricGrid) ? color : Color.White);
- }
- }
- if (CurrentTile == 4)
- DrawTile(e.SpriteBatch, Game1.currentCursorTile, new Point(3, 2), ElectricGrid, color);
- else if(CurrentTile != 5)
- DrawTile(e.SpriteBatch, Game1.currentCursorTile, new Point(CurrentTile, CurrentRotation), ElectricGrid, color);
+ return new UtilityGridApi();
}
-
-
- private void GameLoop_GameLaunched(object sender, StardewModdingAPI.Events.GameLaunchedEventArgs e)
+ /// Get whether this instance can load the initial version of the given asset.
+ /// Basic metadata about the asset being loaded.
+ public bool CanLoad(IAssetInfo asset)
{
- // get Generic Mod Config Menu's API (if it's installed)
- var configMenu = Helper.ModRegistry.GetApi("spacechase0.GenericModConfigMenu");
- if (configMenu is null)
- return;
+ if (!Config.EnableMod)
+ return false;
- // register mod
- configMenu.Register(
- mod: ModManifest,
- reset: () => Config = new ModConfig(),
- save: () => Helper.WriteConfig(Config)
- );
+ return asset.AssetNameEquals(dictPath);
+ }
- configMenu.AddBoolOption(
- mod: ModManifest,
- name: () => "Mod Enabled?",
- getValue: () => Config.EnableMod,
- setValue: value => Config.EnableMod = value
- );
- configMenu.AddKeybind(
- mod: ModManifest,
- name: () => "Toggle Grid Key",
- getValue: () => Config.ToggleGrid,
- setValue: value => Config.ToggleGrid = value
- );
- configMenu.AddKeybind(
- mod: ModManifest,
- name: () => "Switch Grid Key",
- getValue: () => Config.ToggleGrid,
- setValue: value => Config.ToggleGrid = value
- );
- configMenu.AddKeybind(
- mod: ModManifest,
- name: () => "Change Tile Key",
- getValue: () => Config.SwitchTile,
- setValue: value => Config.SwitchTile = value
- );
- configMenu.AddKeybind(
- mod: ModManifest,
- name: () => "Rotate Tile Key",
- getValue: () => Config.RotateTile,
- setValue: value => Config.RotateTile = value
- );
- configMenu.AddKeybind(
- mod: ModManifest,
- name: () => "Place Tile Key",
- getValue: () => Config.PlaceTile,
- setValue: value => Config.PlaceTile = value
- );
+ /// Load a matched asset.
+ /// Basic metadata about the asset being loaded.
+ public T Load(IAssetInfo asset)
+ {
+ Monitor.Log("Loading dictionary");
+
+ return (T)(object)new Dictionary();
}
}
}
\ No newline at end of file
diff --git a/UtilityGrid/PipeGroup.cs b/UtilityGrid/PipeGroup.cs
index da441209..413e570a 100644
--- a/UtilityGrid/PipeGroup.cs
+++ b/UtilityGrid/PipeGroup.cs
@@ -5,7 +5,7 @@ namespace UtilityGrid
{
public class PipeGroup
{
- public List pipes;
- public float power;
+ public List pipes = new List();
+ public Dictionary objects = new Dictionary();
}
}
\ No newline at end of file
diff --git a/UtilityGrid/UtilityGrid.csproj b/UtilityGrid/UtilityGrid.csproj
index 41b3b4bb..4c9921fa 100644
--- a/UtilityGrid/UtilityGrid.csproj
+++ b/UtilityGrid/UtilityGrid.csproj
@@ -4,6 +4,11 @@
net5.0
true
+
+
+
+
+
diff --git a/UtilityGrid/UtilityGridApi.cs b/UtilityGrid/UtilityGridApi.cs
new file mode 100644
index 00000000..74059fd0
--- /dev/null
+++ b/UtilityGrid/UtilityGridApi.cs
@@ -0,0 +1,25 @@
+using Microsoft.Xna.Framework;
+
+namespace UtilityGrid
+{
+ public class UtilityGridApi
+ {
+ public Vector2 ElectricityToFromTile(int x, int y)
+ {
+ return ModEntry.GetTileElectricPower(new Vector2(x, y));
+ }
+ public Vector2 WaterToFromTile(int x, int y)
+ {
+ return ModEntry.GetTileWaterPower(new Vector2(x, y));
+
+ }
+ public void RefreshElectricGrid()
+ {
+ ModEntry.RemakeGroups(ModEntry.GridType.electric);
+ }
+ public void RefreshWaterGrid()
+ {
+ ModEntry.RemakeGroups(ModEntry.GridType.water);
+ }
+ }
+}
\ No newline at end of file
diff --git a/UtilityGrid/UtilityGridData.cs b/UtilityGrid/UtilityGridData.cs
new file mode 100644
index 00000000..d6803a04
--- /dev/null
+++ b/UtilityGrid/UtilityGridData.cs
@@ -0,0 +1,27 @@
+using Microsoft.Xna.Framework;
+using System.Collections.Generic;
+
+namespace UtilityGrid
+{
+ public class UtilityGridData
+ {
+ public List waterData = new List();
+ public List electricData = new List();
+
+ public UtilityGridData()
+ {
+ }
+
+ public UtilityGridData(Dictionary waterPipes, Dictionary electricPipes)
+ {
+ foreach (var kvp in waterPipes)
+ {
+ waterData.Add(new int[]{ (int)kvp.Key.X, (int)kvp.Key.Y, (int)kvp.Value.index, (int)kvp.Value.rotation });
+ }
+ foreach (var kvp in electricPipes)
+ {
+ electricData.Add(new int[] { (int)kvp.Key.X, (int)kvp.Key.Y, (int)kvp.Value.index, (int)kvp.Value.rotation });
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/UtilityGrid/UtilityObject.cs b/UtilityGrid/UtilityObject.cs
new file mode 100644
index 00000000..8c5243ff
--- /dev/null
+++ b/UtilityGrid/UtilityObject.cs
@@ -0,0 +1,13 @@
+using StardewValley;
+
+namespace UtilityGrid
+{
+ public class UtilityObject
+ {
+ public float water;
+ public float electric;
+ public bool onlyInWater;
+ public bool mustBeOn;
+ public Object worldObj;
+ }
+}
\ No newline at end of file
diff --git a/UtilityGrid/Utils.cs b/UtilityGrid/Utils.cs
index 22bf7eed..0e12550c 100644
--- a/UtilityGrid/Utils.cs
+++ b/UtilityGrid/Utils.cs
@@ -13,35 +13,17 @@ namespace UtilityGrid
public partial class ModEntry
{
- private void DrawTile(SpriteBatch b, Vector2 tile, Point which, bool electric, Color color)
+ public static void DrawTile(SpriteBatch b, Vector2 tile, GridPipe which, Color color)
{
float layerDepth = (tile.Y * (16 * Game1.pixelZoom) + 16 * Game1.pixelZoom) / 10000f;
- b.Draw(pipeTexture, Game1.GlobalToLocal(Game1.viewport, tile * 64), new Rectangle(which.Y * 64, which.X * 64, 64, 64), color, 0, Vector2.Zero, 1, SpriteEffects.None, layerDepth);
+ b.Draw(pipeTexture, Game1.GlobalToLocal(Game1.viewport, tile * 64), new Rectangle(which.rotation * 64, which.index * 64, 64, 64), color, 0, Vector2.Zero, 1, SpriteEffects.None, layerDepth);
}
- private bool PipeIsPowered(Vector2 tile, bool electric)
+ public static bool PipesAreJoined(Vector2 tile, Vector2 tile2, GridType gridType)
{
- List groupList;
- if (electric)
- {
- groupList = electricGroups;
- }
- else
- {
- groupList = waterGroups;
- }
- foreach (var g in groupList)
- {
- if (g.pipes.Contains(tile))
- return g.power > 0;
- }
- return false;
- }
- private bool PipesAreJoined(Vector2 tile, Vector2 tile2, bool electric)
- {
- Dictionary pipeDict;
- if (electric)
+ Dictionary pipeDict;
+ if (gridType == GridType.electric)
{
pipeDict = electricPipes;
}
@@ -69,22 +51,27 @@ private bool PipesAreJoined(Vector2 tile, Vector2 tile2, bool electric)
return false;
}
- private bool HasIntake(Point pipeRot, int which)
+ public static bool HasIntake(GridPipe pipe, int which)
{
- return intakeArray[pipeRot.X][(which + pipeRot.Y) % 4] == 1;
+ return intakeArray[pipe.index][(which + pipe.rotation) % 4] == 1;
}
- private void RemakeGroups(bool electric)
+ public static void RemakeAllGroups()
{
- Dictionary pipeDict;
+ RemakeGroups(GridType.water);
+ RemakeGroups(GridType.electric);
+ }
+ public static void RemakeGroups(GridType gridType)
+ {
+ Dictionary pipeDict;
List groupList;
- if (electric)
+ if (gridType == GridType.electric)
{
- pipeDict = new Dictionary(electricPipes);
+ pipeDict = new Dictionary(electricPipes);
groupList = electricGroups;
}
else
{
- pipeDict = new Dictionary(waterPipes);
+ pipeDict = new Dictionary(waterPipes);
groupList = waterGroups;
}
groupList.Clear();
@@ -92,15 +79,21 @@ private void RemakeGroups(bool electric)
while(pipeDict.Count > 0)
{
var tile = pipeDict.Keys.ToArray()[0];
- var group = new PipeGroup { pipes = new List() { tile }, power = PipePower(tile, electric) };
- Monitor.Log($"Creating new group; power: {group.power}");
+ var group = new PipeGroup { pipes = new List() { tile } };
+ var obj = GetUtilityObjectAtTile(tile);
+ if(obj != null)
+ {
+ group.objects[tile] = obj;
+ }
+
+ //SMonitor.Log($"Creating new group; power: {group.input}");
pipeDict.Remove(tile);
- AddTilesToGroup(tile, ref group, pipeDict, electric);
+ AddTilesToGroup(tile, ref group, pipeDict, gridType);
groupList.Add(group);
}
}
- private void AddTilesToGroup(Vector2 tile, ref PipeGroup group, Dictionary pipeDict, bool electric)
+ public static void AddTilesToGroup(Vector2 tile, ref PipeGroup group, Dictionary pipeDict, GridType gridType)
{
Vector2[] adjecents = new Vector2[] { tile + new Vector2(0,1),tile + new Vector2(1,0),tile + new Vector2(-1,0),tile + new Vector2(0,-1)};
@@ -108,31 +101,138 @@ private void AddTilesToGroup(Vector2 tile, ref PipeGroup group, Dictionary 0)
+ power.X += obj.electric;
+ else if (obj.electric < 0)
+ power.Y += obj.electric;
+ }
+ return power;
+ }
+ public static Vector2 GetTileWaterPower(Vector2 tile)
+ {
+ Vector2 power = Vector2.Zero;
+ foreach (var group in waterGroups)
+ {
+ if (group.objects.ContainsKey(tile))
+ {
+ return GetGroupWaterPower(group);
+ }
+ }
+ return power;
+ }
+ public static Vector2 GetGroupWaterPower(PipeGroup group)
+ {
+ Vector2 power = Vector2.Zero;
+ foreach (var kvp in group.objects)
+ {
+ if (kvp.Value.electric < 0)
+ {
+ Vector2 ePower = GetTileElectricPower(kvp.Key);
+ if (ePower.X + ePower.Y < 0) // unpowered
+ continue;
+ }
+ var obj = kvp.Value;
+
+ if (obj.water > 0)
+ power.X += obj.water;
+ else if (obj.water < 0)
+ power.Y += obj.water;
+ }
+ return power;
+ }
+
+ public static bool IsObjectPowered(Vector2 tile, UtilityObject obj)
+ {
+ if(obj.water < 0)
+ {
+ var netPower = GetTileNetWaterPower(tile);
+ if (netPower < 0)
+ return false;
+ }
+ if(obj.electric < 0)
+ {
+ var netPower = GetTileNetElectricPower(tile);
+ if (netPower < 0)
+ return false;
+ }
+ return true;
+ }
+
+ public static UtilityObject GetUtilityObjectAtTile(Vector2 tile)
+ {
+ if (!Game1.getFarm().Objects.ContainsKey(tile))
+ return null;
+ var obj = Game1.getFarm().Objects[tile];
+ if (!objectDict.ContainsKey(obj.Name) && (obj.modData.ContainsKey("aedenthorn.UtilityGrid/" + GridType.water) || obj.modData.ContainsKey("aedenthorn.UtilityGrid/" + GridType.electric)))
+ {
+ objectDict[obj.Name] = new UtilityObject();
+ if (obj.modData.ContainsKey("aedenthorn.UtilityGrid/" + GridType.water))
+ {
+ objectDict[obj.Name].water = float.Parse(obj.modData["aedenthorn.UtilityGrid/" + GridType.water], CultureInfo.InvariantCulture);
+ }
+ if (obj.modData.ContainsKey("aedenthorn.UtilityGrid/" + GridType.electric))
+ {
+ objectDict[obj.Name].electric = float.Parse(obj.modData["aedenthorn.UtilityGrid/" + GridType.electric], CultureInfo.InvariantCulture);
+ }
+ }
+ if (objectDict.ContainsKey(obj.Name))
+ {
+ UtilityObject outObj = objectDict[obj.Name];
+ outObj.worldObj = obj;
+ return outObj;
+ }
+ return null;
}
}
}
\ No newline at end of file
diff --git a/UtilityGrid/assets/pipes.png b/UtilityGrid/assets/pipes.png
index 99849369..de682c21 100644
Binary files a/UtilityGrid/assets/pipes.png and b/UtilityGrid/assets/pipes.png differ
diff --git a/UtilityGrid/assets/pipes.xcf b/UtilityGrid/assets/pipes.xcf
new file mode 100644
index 00000000..969c7a6a
Binary files /dev/null and b/UtilityGrid/assets/pipes.xcf differ
diff --git a/UtilityGrid/assets/water_pump.png b/UtilityGrid/assets/water_pump.png
new file mode 100644
index 00000000..36852c59
Binary files /dev/null and b/UtilityGrid/assets/water_pump.png differ
diff --git a/UtilityGrid/assets/water_pump.xcf b/UtilityGrid/assets/water_pump.xcf
new file mode 100644
index 00000000..9ac2ef4f
Binary files /dev/null and b/UtilityGrid/assets/water_pump.xcf differ
diff --git a/WaterPump/IGenericModConfigMenuApi.cs b/WaterPump/IGenericModConfigMenuApi.cs
new file mode 100644
index 00000000..eb776cc6
--- /dev/null
+++ b/WaterPump/IGenericModConfigMenuApi.cs
@@ -0,0 +1,49 @@
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using StardewModdingAPI;
+using StardewModdingAPI.Utilities;
+using StardewValley;
+
+namespace GroundhogDay
+{
+ /// The API which lets other mods add a config UI through Generic Mod Config Menu.
+ public interface IGenericModConfigMenuApi
+ {
+ /*********
+ ** Methods
+ *********/
+ /****
+ ** Must be called first
+ ****/
+ /// Register a mod whose config can be edited through the UI.
+ /// The mod's manifest.
+ /// Reset the mod's config to its default values.
+ /// Save the mod's current config to the config.json file.
+ /// Whether the options can only be edited from the title screen.
+ /// Each mod can only be registered once, unless it's deleted via before calling this again.
+ void Register(IManifest mod, Action reset, Action save, bool titleScreenOnly = false);
+
+ /// Add a key binding at the current position in the form.
+ /// The mod's manifest.
+ /// Get the current value from the mod config.
+ /// Set a new value in the mod config.
+ /// The label text to show in the form.
+ /// The tooltip text shown when the cursor hovers on the field, or null to disable the tooltip.
+ /// The unique field ID for use with , or null to auto-generate a randomized ID.
+ void AddKeybind(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string fieldId = null);
+
+ /// Add a boolean option at the current position in the form.
+ /// The mod's manifest.
+ /// Get the current value from the mod config.
+ /// Set a new value in the mod config.
+ /// The label text to show in the form.
+ /// The tooltip text shown when the cursor hovers on the field, or null to disable the tooltip.
+ /// The unique field ID for use with , or null to auto-generate a randomized ID.
+ void AddBoolOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string fieldId = null);
+
+ /// Remove a mod from the config UI and delete all its options and pages.
+ /// The mod's manifest.
+ void Unregister(IManifest mod);
+ }
+}
diff --git a/WaterPump/MethodPatches.cs b/WaterPump/MethodPatches.cs
new file mode 100644
index 00000000..7ec05776
--- /dev/null
+++ b/WaterPump/MethodPatches.cs
@@ -0,0 +1,18 @@
+using StardewValley;
+
+namespace WaterPump
+{
+ /// The mod entry point.
+ public partial class ModEntry
+ {
+
+ private static bool Utility_playerCanPlaceItemHere_Prefix()
+ {
+ if (Config.EnableMod && (Game1.dayOfMonth != 0 || Game1.year != 1 || Game1.currentSeason != "spring"))
+ {
+ SMonitor.Log($"Repeating {Utility.getDateString()}");
+ Game1.dayOfMonth--;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/WaterPump/ModConfig.cs b/WaterPump/ModConfig.cs
new file mode 100644
index 00000000..a156d18d
--- /dev/null
+++ b/WaterPump/ModConfig.cs
@@ -0,0 +1,11 @@
+
+using StardewModdingAPI;
+
+namespace WaterPump
+{
+ public class ModConfig
+ {
+ public bool EnableMod { get; set; } = true;
+
+ }
+}
diff --git a/WaterPump/ModEntry.cs b/WaterPump/ModEntry.cs
new file mode 100644
index 00000000..988b2df0
--- /dev/null
+++ b/WaterPump/ModEntry.cs
@@ -0,0 +1,43 @@
+using HarmonyLib;
+using StardewModdingAPI;
+using StardewValley;
+
+namespace WaterPump
+{
+ /// The mod entry point.
+ public partial class ModEntry : Mod
+ {
+
+ public static IMonitor SMonitor;
+ public static IModHelper SHelper;
+ public static ModConfig Config;
+
+ public static ModEntry context;
+
+ /// The mod entry point, called after the mod is first loaded.
+ /// Provides simplified APIs for writing mods.
+ public override void Entry(IModHelper helper)
+ {
+ Config = Helper.ReadConfig();
+
+ if (!Config.EnableMod)
+ return;
+
+ context = this;
+
+ SMonitor = Monitor;
+ SHelper = helper;
+
+ helper.Events.Input.ButtonPressed += Input_ButtonPressed;
+ helper.Events.GameLoop.GameLaunched += GameLoop_GameLaunched;
+
+ var harmony = new Harmony(ModManifest.UniqueID);
+
+ harmony.Patch(
+ original: AccessTools.Method(typeof(Utility), nameof(Utility.playerCanPlaceItemHere)),
+ prefix: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.Utility_playerCanPlaceItemHere_Prefix))
+ );
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/WaterPump/WaterPump.csproj b/WaterPump/WaterPump.csproj
new file mode 100644
index 00000000..95bd1a14
--- /dev/null
+++ b/WaterPump/WaterPump.csproj
@@ -0,0 +1,20 @@
+
+
+ 1.0.0
+ net5.0
+ true
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
\ No newline at end of file
diff --git a/WaterPump/manifest.json b/WaterPump/manifest.json
new file mode 100644
index 00000000..35a997fd
--- /dev/null
+++ b/WaterPump/manifest.json
@@ -0,0 +1,22 @@
+{
+ "Name": "Water Pump",
+ "Author": "aedenthorn",
+ "Version": "0.1.0",
+ "Description": "Water Pump.",
+ "UniqueID": "aedenthorn.WaterPump",
+ "EntryDll": "WaterPump.dll",
+ "MinimumApiVersion": "3.13.0-beta.20211018",
+ "ModUpdater": {
+ "Repository": "StardewValleyMods",
+ "User": "aedenthorn",
+ "Directory": "_releases",
+ "ModFolder": "WaterPump"
+ },
+ "UpdateKeys": [ "Nexus:" ],
+ "Dependencies": [
+ {
+ "UniqueID": "Platonymous.ModUpdater",
+ "IsRequired": false
+ }
+ ]
+}
\ No newline at end of file