From c2135f524c138f892d054e7aeb6ea02ca0246f68 Mon Sep 17 00:00:00 2001 From: aedenthorn Date: Wed, 16 Mar 2022 09:52:41 -0400 Subject: [PATCH] email app --- AdvancedSigns/AdvancedMenuPositioning.csproj | 17 ++ AdvancedSigns/CodePatches.cs | 9 + AdvancedSigns/IGenericModConfigMenuApi.cs | 75 +++++ AdvancedSigns/Methods.cs | 160 ++++++++++ AdvancedSigns/ModConfig.cs | 16 + AdvancedSigns/ModEntry.cs | 295 +++++++++++++++++++ AdvancedSigns/manifest.json | 22 ++ Email/Catalogues.cs | 70 +++++ Email/Email.csproj | 21 ++ Email/EmailApp.cs | 42 +++ Email/HelperEvents.cs | 57 ++++ Email/IMobilePhoneApi.cs | 31 ++ Email/ModConfig.cs | 53 ++++ Email/ModEntry.cs | 41 +++ Email/Visuals.cs | 119 ++++++++ Email/assets/app_icon.png | Bin 0 -> 17817 bytes Email/i18n/default.json | 3 + Email/manifest.json | 26 ++ MoveableMailbox/ModEntry.cs | 10 +- StardewValleyMods.sln | 10 + 20 files changed, 1072 insertions(+), 5 deletions(-) create mode 100644 AdvancedSigns/AdvancedMenuPositioning.csproj create mode 100644 AdvancedSigns/CodePatches.cs create mode 100644 AdvancedSigns/IGenericModConfigMenuApi.cs create mode 100644 AdvancedSigns/Methods.cs create mode 100644 AdvancedSigns/ModConfig.cs create mode 100644 AdvancedSigns/ModEntry.cs create mode 100644 AdvancedSigns/manifest.json create mode 100644 Email/Catalogues.cs create mode 100644 Email/Email.csproj create mode 100644 Email/EmailApp.cs create mode 100644 Email/HelperEvents.cs create mode 100644 Email/IMobilePhoneApi.cs create mode 100644 Email/ModConfig.cs create mode 100644 Email/ModEntry.cs create mode 100644 Email/Visuals.cs create mode 100644 Email/assets/app_icon.png create mode 100644 Email/i18n/default.json create mode 100644 Email/manifest.json diff --git a/AdvancedSigns/AdvancedMenuPositioning.csproj b/AdvancedSigns/AdvancedMenuPositioning.csproj new file mode 100644 index 00000000..dc882f9d --- /dev/null +++ b/AdvancedSigns/AdvancedMenuPositioning.csproj @@ -0,0 +1,17 @@ + + + 1.0.0 + net5.0 + true + + + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/AdvancedSigns/CodePatches.cs b/AdvancedSigns/CodePatches.cs new file mode 100644 index 00000000..a1a2eec1 --- /dev/null +++ b/AdvancedSigns/CodePatches.cs @@ -0,0 +1,9 @@ +using StardewValley; +using StardewValley.Menus; + +namespace AdvancedMenuPositioning +{ + public partial class ModEntry + { + } +} \ No newline at end of file diff --git a/AdvancedSigns/IGenericModConfigMenuApi.cs b/AdvancedSigns/IGenericModConfigMenuApi.cs new file mode 100644 index 00000000..fc93c00e --- /dev/null +++ b/AdvancedSigns/IGenericModConfigMenuApi.cs @@ -0,0 +1,75 @@ +using StardewModdingAPI; +using System; + +namespace AdvancedMenuPositioning +{ + /// 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 section title at the current position in the form. + /// The mod's manifest. + /// The title text shown in the form. + /// The tooltip text shown when the cursor hovers on the title, or null to disable the tooltip. + void AddSectionTitle(IManifest mod, Func text, Func tooltip = null); + + /// 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); + + + /// Add an integer 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 minimum allowed value, or null to allow any. + /// The maximum allowed value, or null to allow any. + /// The interval of values that can be selected. + /// The unique field ID for use with , or null to auto-generate a randomized ID. + void AddNumberOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, int? min = null, int? max = null, int? interval = null, string fieldId = null); + + /// Add a string 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 values that can be selected, or null to allow any. + /// Get the display text to show for a value from , or null to show the values as-is. + /// The unique field ID for use with , or null to auto-generate a randomized ID. + void AddTextOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string[] allowedValues = null, Func formatAllowedValue = 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/AdvancedSigns/Methods.cs b/AdvancedSigns/Methods.cs new file mode 100644 index 00000000..b1c13c8b --- /dev/null +++ b/AdvancedSigns/Methods.cs @@ -0,0 +1,160 @@ +using HarmonyLib; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using StardewModdingAPI; +using StardewValley; +using StardewValley.Menus; +using System; +using System.Collections.Generic; +using System.Linq; +using Rectangle = Microsoft.Xna.Framework.Rectangle; + +namespace AdvancedMenuPositioning +{ + public partial class ModEntry : Mod + { + + private static void AdjustMenu(IClickableMenu menu, Point delta, bool first = false) + { + if (first) + { + adjustedMenus.Clear(); + adjustedComponents.Clear(); + } + if (menu is null || adjustedMenus.Contains(menu)) + return; + menu.xPositionOnScreen += delta.X; + menu.yPositionOnScreen += delta.Y; + var types = AccessTools.GetDeclaredFields(menu.GetType()); + if (menu is ItemGrabMenu) + { + types.AddRange(AccessTools.GetDeclaredFields(typeof(MenuWithInventory))); + } + foreach (var f in types) + { + + if (f.FieldType.IsSubclassOf(typeof(ClickableComponent)) || f.FieldType == typeof(ClickableComponent)) + { + AdjustComponent((ClickableComponent)f.GetValue(menu), delta); + + } + else if (f.FieldType.IsSubclassOf(typeof(IClickableMenu)) || f.FieldType == typeof(IClickableMenu)) + { + AdjustMenu((IClickableMenu)f.GetValue(menu), delta); + + } + else if (f.FieldType == typeof(InventoryMenu)) + { + AdjustMenu((IClickableMenu)f.GetValue(menu), delta); + } + else if (f.Name == "scrollBarRunner") + { + var c = (Rectangle)f.GetValue(menu); + c = new Rectangle(c.X + delta.X, c.Y + delta.Y, c.Width, c.Height); + f.SetValue(menu, c); + } + else if (f.FieldType == typeof(List)) + { + var ol = (List)f.GetValue(menu); + if (ol is null) + continue; + foreach (var o in ol) + { + AdjustComponent(o, delta); + } + } + else if (f.FieldType == typeof(List)) + { + var ol = (List)f.GetValue(menu); + if (ol is null) + continue; + foreach (var o in ol) + { + AdjustMenu(o, delta); + } + } + else if (f.FieldType == typeof(Dictionary)) + { + var ol = (Dictionary)f.GetValue(menu); + if (ol is null) + continue; + foreach (var o in ol.Values) + { + AdjustComponent(o, delta); + } + } + else if (f.FieldType == typeof(Dictionary)) + { + var ol = (Dictionary)f.GetValue(menu); + if (ol is null) + continue; + foreach (var o in ol.Values) + { + AdjustComponent(o, delta); + } + } + else if (f.FieldType == typeof(Dictionary>>)) + { + var ol = (Dictionary>>)f.GetValue(menu); + if (ol is null) + continue; + foreach (var o in ol.Values) + { + foreach (var o2 in o) + { + foreach (var o3 in o2) + { + AdjustComponent(o3, delta); + } + } + } + } + else if (f.FieldType == typeof(Dictionary>>)) + { + var ol = (Dictionary>>)f.GetValue(menu); + if (ol is null) + continue; + foreach (var o in ol.Values) + { + foreach (var o2 in o) + { + foreach (var o3 in o2) + { + AdjustComponent(o3, delta); + } + } + } + } + else if (f.FieldType == typeof(List)) + { + var ol = (List)f.GetValue(menu); + if (ol is null) + continue; + foreach (var o in ol) + { + AdjustComponent(o, delta); + } + } + } + if (menu is GameMenu) + { + for (int i = 0; i < (menu as GameMenu).pages.Count; i++) + { + if (i != (menu as GameMenu).currentTab) + AdjustMenu((menu as GameMenu).pages[i], delta); + } + } + AdjustComponent(menu.upperRightCloseButton, delta); + adjustedMenus.Add(menu); + } + + private static void AdjustComponent(ClickableComponent c, Point delta) + { + if (c is not null && !adjustedComponents.Contains(c)) + { + c.bounds = new Rectangle(c.bounds.X + delta.X, c.bounds.Y + delta.Y, c.bounds.Width, c.bounds.Height); + adjustedComponents.Add(c); + } + } + } +} \ No newline at end of file diff --git a/AdvancedSigns/ModConfig.cs b/AdvancedSigns/ModConfig.cs new file mode 100644 index 00000000..93844be4 --- /dev/null +++ b/AdvancedSigns/ModConfig.cs @@ -0,0 +1,16 @@ + +using StardewModdingAPI; + +namespace AdvancedMenuPositioning +{ + public class ModConfig + { + public bool EnableMod { get; set; } = true; + public SButton DetachKey { get; set; } = SButton.X; + public SButton MoveKey { get; set; } = SButton.MouseLeft; + public SButton CloseKey { get; set; } = SButton.Z; + public SButton DetachModKey { get; set; } = SButton.LeftShift; + public SButton MoveModKey { get; set; } = SButton.LeftShift; + public SButton CloseModKey { get; set; } = SButton.LeftShift; + } +} diff --git a/AdvancedSigns/ModEntry.cs b/AdvancedSigns/ModEntry.cs new file mode 100644 index 00000000..e224b8dc --- /dev/null +++ b/AdvancedSigns/ModEntry.cs @@ -0,0 +1,295 @@ +using Force.DeepCloner; +using HarmonyLib; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using StardewModdingAPI; +using StardewValley; +using StardewValley.Menus; +using StardewValley.Objects; +using System; +using System.Collections.Generic; +using System.Linq; +using Rectangle = Microsoft.Xna.Framework.Rectangle; + +namespace AdvancedMenuPositioning +{ + /// 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; + private static Point lastMousePosition; + private static IClickableMenu currentlyDragging; + + private static List adjustedComponents = new List(); + private static List adjustedMenus = new List(); + private static List detachedMenus = new List(); + + /// 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(); + + context = this; + + SMonitor = Monitor; + SHelper = helper; + + helper.Events.GameLoop.GameLaunched += GameLoop_GameLaunched; + helper.Events.GameLoop.UpdateTicking += GameLoop_UpdateTicking; + helper.Events.Input.ButtonPressed += Input_ButtonPressed; + helper.Events.Input.MouseWheelScrolled += Input_MouseWheelScrolled; + helper.Events.Display.RenderedWorld += Display_RenderedWorld; + + } + + private void Input_MouseWheelScrolled(object sender, StardewModdingAPI.Events.MouseWheelScrolledEventArgs e) + { + foreach (var m in detachedMenus) + { + m.receiveScrollWheelAction(e.Delta); + } + } + + private void Display_RenderedWorld(object sender, StardewModdingAPI.Events.RenderedWorldEventArgs e) + { + if (detachedMenus.Any()) + { + var back = Game1.options.showMenuBackground; + Game1.options.showMenuBackground = true; + foreach (var m in detachedMenus) + { + var f = AccessTools.Field(m.GetType(), "drawBG"); + if (f != null) + f.SetValue(m, false); + m.draw(e.SpriteBatch); + } + Game1.options.showMenuBackground = back; + } + } + + private void Input_ButtonPressed(object sender, StardewModdingAPI.Events.ButtonPressedEventArgs e) + { + if (!Config.EnableMod) + return; + if (Game1.activeClickableMenu != null && Helper.Input.IsDown(Config.DetachModKey) && e.Button == Config.DetachKey && new Rectangle(Game1.activeClickableMenu.xPositionOnScreen, Game1.activeClickableMenu.yPositionOnScreen, Game1.activeClickableMenu.width, Game1.activeClickableMenu.height).Contains(Game1.getMouseX(), Game1.getMouseY())) + { + detachedMenus.Add(Game1.activeClickableMenu); + Game1.activeClickableMenu = null; + Helper.Input.Suppress(e.Button); + Game1.playSound("bigDeSelect"); + return; + } + else if(detachedMenus.Count > 0) + { + if (Helper.Input.IsDown(Config.CloseModKey) && e.Button == Config.CloseKey) + { + for (int i = 0; i < detachedMenus.Count; i++) + { + if(detachedMenus[i].isWithinBounds(Game1.getMouseX(), Game1.getMouseY())) + { + detachedMenus.RemoveAt(i); + Helper.Input.Suppress(e.Button); + Game1.playSound("bigDeSelect"); + return; + } + } + } + if (Helper.Input.IsDown(Config.DetachModKey) && e.Button == Config.DetachKey && Game1.activeClickableMenu == null) + { + for (int i = 0; i < detachedMenus.Count; i++) + { + if(detachedMenus[i].isWithinBounds(Game1.getMouseX(), Game1.getMouseY())) + { + Game1.activeClickableMenu = detachedMenus[i]; + detachedMenus.RemoveAt(i); + Helper.Input.Suppress(e.Button); + Game1.playSound("bigSelect"); + return; + } + } + } + else if (e.Button == SButton.MouseLeft) + { + for (int i = 0; i < detachedMenus.Count; i++) + { + bool toBreak = detachedMenus[i].isWithinBounds(Game1.getMouseX(), Game1.getMouseY()); + + var menu = Game1.activeClickableMenu; + Game1.activeClickableMenu = detachedMenus[i]; + Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(), Game1.getMouseY()); + if (Game1.activeClickableMenu != null) + { + var d = new Point(detachedMenus[i].xPositionOnScreen - Game1.activeClickableMenu.xPositionOnScreen, detachedMenus[i].yPositionOnScreen - Game1.activeClickableMenu.yPositionOnScreen); + if (d != Point.Zero) + { + detachedMenus[i] = Game1.activeClickableMenu; + AdjustMenu(detachedMenus[i], d, true); + Game1.activeClickableMenu = menu; + } + + } + else + detachedMenus.RemoveAt(i); + Game1.activeClickableMenu = menu; + if (toBreak) + { + Helper.Input.Suppress(e.Button); + return; + } + + } + } + else if (e.Button == SButton.MouseRight) + { + for (int i = 0; i < detachedMenus.Count; i++) + { + bool toBreak = detachedMenus[i].isWithinBounds(Game1.getMouseX(), Game1.getMouseY()); + + var menu = Game1.activeClickableMenu; + Game1.activeClickableMenu = detachedMenus[i]; + Game1.activeClickableMenu.receiveRightClick(Game1.getMouseX(), Game1.getMouseY()); + if (Game1.activeClickableMenu != null) + { + var d = new Point(detachedMenus[i].xPositionOnScreen - Game1.activeClickableMenu.xPositionOnScreen, detachedMenus[i].yPositionOnScreen - Game1.activeClickableMenu.yPositionOnScreen); + if(d != Point.Zero) + { + detachedMenus[i] = Game1.activeClickableMenu; + AdjustMenu(detachedMenus[i], d, true); + Game1.activeClickableMenu = menu; + } + } + else + detachedMenus.RemoveAt(i); + Game1.activeClickableMenu = menu; + if (toBreak) + { + Helper.Input.Suppress(e.Button); + return; + } + } + } + } + } + + private void GameLoop_UpdateTicking(object sender, StardewModdingAPI.Events.UpdateTickingEventArgs e) + { + if(Config.EnableMod && Helper.Input.IsDown(Config.MoveModKey) && (Helper.Input.IsDown(Config.MoveKey) || Helper.Input.IsSuppressed(Config.MoveKey))) + { + if(Game1.activeClickableMenu != null) + { + if (currentlyDragging == Game1.activeClickableMenu || Game1.activeClickableMenu.isWithinBounds(Game1.getMouseX(), Game1.getMouseY())) + { + currentlyDragging = Game1.activeClickableMenu; + AdjustMenu(Game1.activeClickableMenu, Game1.getMousePosition() - lastMousePosition, true); + Helper.Input.Suppress(Config.MoveKey); + if (Game1.activeClickableMenu is ItemGrabMenu && Helper.ModRegistry.IsLoaded("Pathoschild.ChestsAnywhere")) + { + Game1.activeClickableMenu = Game1.activeClickableMenu.ShallowClone(); + } + goto next; + } + } + foreach (var menu in Game1.onScreenMenus) + { + if (menu is null) + continue; + if (currentlyDragging == menu || menu.isWithinBounds(Game1.getMouseX(), Game1.getMouseY())) + { + currentlyDragging = menu; + + AdjustMenu(menu, Game1.getMousePosition() - lastMousePosition, true); + Helper.Input.Suppress(Config.MoveKey); + goto next; + } + } + foreach (var menu in detachedMenus) + { + if (menu is null) + continue; + if (currentlyDragging == menu || menu.isWithinBounds(Game1.getMouseX(), Game1.getMouseY())) + { + currentlyDragging = menu; + + AdjustMenu(menu, Game1.getMousePosition() - lastMousePosition, true); + Helper.Input.Suppress(Config.MoveKey); + goto next; + } + } + } + currentlyDragging = null; + next: + lastMousePosition = Game1.getMousePosition(); + foreach (var menu in detachedMenus) + { + if (menu.isWithinBounds(Game1.getMouseX(), Game1.getMouseY())) + { + menu.performHoverAction(Game1.getMouseX(), Game1.getMouseY()); + } + } + } + + + private 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: () => "Move Key", + getValue: () => Config.MoveKey, + setValue: value => Config.MoveKey = value + ); + configMenu.AddKeybind( + mod: ModManifest, + name: () => "Detach Key", + getValue: () => Config.DetachKey, + setValue: value => Config.DetachKey = value + ); + configMenu.AddKeybind( + mod: ModManifest, + name: () => "Close Key", + getValue: () => Config.CloseKey, + setValue: value => Config.CloseKey = value + ); + configMenu.AddKeybind( + mod: ModManifest, + name: () => "Move Mod Key", + getValue: () => Config.MoveModKey, + setValue: value => Config.MoveModKey = value + ); + configMenu.AddKeybind( + mod: ModManifest, + name: () => "DetachModKey Key", + getValue: () => Config.DetachModKey, + setValue: value => Config.DetachModKey = value + ); + configMenu.AddKeybind( + mod: ModManifest, + name: () => "CloseModKey Key", + getValue: () => Config.CloseModKey, + setValue: value => Config.CloseModKey = value + ); + } + } +} \ No newline at end of file diff --git a/AdvancedSigns/manifest.json b/AdvancedSigns/manifest.json new file mode 100644 index 00000000..90375821 --- /dev/null +++ b/AdvancedSigns/manifest.json @@ -0,0 +1,22 @@ +{ + "Name": "Advanced Menu Positioning", + "Author": "aedenthorn", + "Version": "0.2.0", + "Description": "Advanced Menu Positioning.", + "UniqueID": "aedenthorn.AdvancedMenuPositioning", + "EntryDll": "AdvancedMenuPositioning.dll", + "MinimumApiVersion": "3.13.0", + "ModUpdater": { + "Repository": "StardewValleyMods", + "User": "aedenthorn", + "Directory": "_releases", + "ModFolder": "AdvancedMenuPositioning" + }, + "UpdateKeys": [ "Nexus:11315" ], + "Dependencies": [ + { + "UniqueID": "Platonymous.ModUpdater", + "IsRequired": false + } + ] +} \ No newline at end of file diff --git a/Email/Catalogues.cs b/Email/Catalogues.cs new file mode 100644 index 00000000..d36f012a --- /dev/null +++ b/Email/Catalogues.cs @@ -0,0 +1,70 @@ +using StardewValley; +using StardewValley.Menus; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Email +{ + public partial class ModEntry + { + public void OpenMail(int index) + { + string id = Game1.player.mailbox[index]; + if (!Game1.player.mailReceived.Contains(id) && !id.Contains("passedOut") && !id.Contains("Cooking")) + { + Game1.player.mailReceived.Add(id); + } + string mailTitle = id; + Game1.mailbox.RemoveAt(index); + Dictionary mails = Game1.content.Load>("Data\\mail"); + string mail = mails.ContainsKey(mailTitle) ? mails[mailTitle] : ""; + if (mailTitle.StartsWith("passedOut ")) + { + string[] split = mailTitle.Split(' ', StringSplitOptions.None); + int moneyTaken = (split.Length > 1) ? Convert.ToInt32(split[1]) : 0; + switch (new Random(moneyTaken).Next((Game1.player.getSpouse() != null && Game1.player.getSpouse().Name.Equals("Harvey")) ? 2 : 3)) + { + case 0: + if (Game1.MasterPlayer.hasCompletedCommunityCenter() && !Game1.MasterPlayer.mailReceived.Contains("JojaMember")) + { + mail = string.Format(mails["passedOut4"], moneyTaken); + } + else + { + mail = string.Format(mails["passedOut1_" + ((moneyTaken > 0) ? "Billed" : "NotBilled") + "_" + (Game1.player.IsMale ? "Male" : "Female")], moneyTaken); + } + break; + case 1: + mail = string.Format(mails["passedOut2"], moneyTaken); + break; + case 2: + mail = string.Format(mails["passedOut3_" + ((moneyTaken > 0) ? "Billed" : "NotBilled")], moneyTaken); + break; + } + } + else if (mailTitle.StartsWith("passedOut")) + { + string[] split2 = mailTitle.Split(' ', StringSplitOptions.None); + if (split2.Length > 1) + { + int moneyTaken2 = Convert.ToInt32(split2[1]); + mail = string.Format(mails[split2[0]], moneyTaken2); + } + } + if (mail.Length == 0) + { + return; + } + Game1.activeClickableMenu = new LetterViewerMenu(mail, mailTitle, false); + } + + + private async void DelayedOpen(ShopMenu menu) + { + await Task.Delay(100); + Monitor.Log("Really opening email"); + Game1.activeClickableMenu = menu; + } + } +} diff --git a/Email/Email.csproj b/Email/Email.csproj new file mode 100644 index 00000000..eed00f01 --- /dev/null +++ b/Email/Email.csproj @@ -0,0 +1,21 @@ + + + 1.0.0 + net5.0 + true + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + \ No newline at end of file diff --git a/Email/EmailApp.cs b/Email/EmailApp.cs new file mode 100644 index 00000000..730e09dd --- /dev/null +++ b/Email/EmailApp.cs @@ -0,0 +1,42 @@ +using Microsoft.Xna.Framework; +using StardewModdingAPI; +using StardewValley; +using StardewValley.Menus; +using System; +using System.Collections.Generic; + +namespace Email +{ + public partial class ModEntry + { + public bool opening; + + public void OpenEmailApp() + { + Helper.Events.Input.ButtonPressed += Input_ButtonPressed; + api.SetAppRunning(true); + api.SetRunningApp(Helper.ModRegistry.ModID); + Helper.Events.Display.RenderedWorld += Display_RenderedWorld; + opening = true; + } + + public void CloseApp() + { + api.SetAppRunning(false); + api.SetRunningApp(null); + Helper.Events.Input.ButtonPressed -= Input_ButtonPressed; + Helper.Events.Display.RenderedWorld -= Display_RenderedWorld; + } + + + public void ClickRow(Point mousePos) + { + int idx = (int)((mousePos.Y - api.GetScreenPosition().Y - Config.MarginY - offsetY - Config.AppHeaderHeight) / (Config.MarginY + Config.AppRowHeight)); + Monitor.Log($"clicked index: {idx}"); + if (idx < Game1.player.mailbox.Count && idx >= 0) + { + OpenMail(idx); + } + } + } +} \ No newline at end of file diff --git a/Email/HelperEvents.cs b/Email/HelperEvents.cs new file mode 100644 index 00000000..1372f648 --- /dev/null +++ b/Email/HelperEvents.cs @@ -0,0 +1,57 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI; +using StardewModdingAPI.Events; +using StardewValley; +using System.IO; + +namespace Email +{ + public partial class ModEntry + { + public void GameLoop_GameLaunched(object sender, GameLaunchedEventArgs e) + { + if (!Config.EnableMod) + return; + api = Helper.ModRegistry.GetApi("aedenthorn.MobilePhone"); + if (api != null) + { + Texture2D appIcon; + bool success; + + appIcon = Helper.Content.Load(Path.Combine("assets", "app_icon.png")); + success = api.AddApp(Helper.ModRegistry.ModID, Helper.Translation.Get("email"), OpenEmailApp, appIcon); + Monitor.Log($"loaded email app successfully: {success}", LogLevel.Debug); + + MakeTextures(); + } + } + public void Input_ButtonPressed(object sender, ButtonPressedEventArgs e) + { + if (api.IsCallingNPC() || api.GetRunningApp() != Helper.ModRegistry.ModID) + return; + + if (e.Button == SButton.MouseLeft) + { + Point mousePos = Game1.getMousePosition(); + if (!api.GetScreenRectangle().Contains(mousePos)) + { + return; + } + + Helper.Input.Suppress(SButton.MouseLeft); + Vector2 screenPos = api.GetScreenPosition(); + Vector2 screenSize = api.GetScreenSize(); + if (!opening && new Rectangle((int)(screenPos.X + screenSize.X - Config.AppHeaderHeight), (int)(screenPos.Y), (int)Config.AppHeaderHeight, (int)Config.AppHeaderHeight).Contains(mousePos)) + { + Monitor.Log($"Closing app"); + CloseApp(); + return; + } + opening = false; + clicking = true; + lastMousePosition = mousePos; + } + } + } +} diff --git a/Email/IMobilePhoneApi.cs b/Email/IMobilePhoneApi.cs new file mode 100644 index 00000000..e4515761 --- /dev/null +++ b/Email/IMobilePhoneApi.cs @@ -0,0 +1,31 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using StardewValley; +using System; + +namespace Email +{ + public interface IMobilePhoneApi + { + bool AddApp(string id, string name, Action action, Texture2D icon); + + Vector2 GetScreenPosition(); + Vector2 GetScreenSize(); + Vector2 GetScreenSize(bool rotated); + Rectangle GetPhoneRectangle(); + Rectangle GetScreenRectangle(); + bool GetPhoneRotated(); + void SetPhoneRotated(bool value); + bool GetPhoneOpened(); + void SetPhoneOpened(bool value); + bool GetAppRunning(); + void SetAppRunning(bool value); + string GetRunningApp(); + void SetRunningApp(string value); + + void PlayRingTone(); + void PlayNotificationTone(); + NPC GetCallingNPC(); + bool IsCallingNPC(); + } +} \ No newline at end of file diff --git a/Email/ModConfig.cs b/Email/ModConfig.cs new file mode 100644 index 00000000..09715497 --- /dev/null +++ b/Email/ModConfig.cs @@ -0,0 +1,53 @@ +using Microsoft.Xna.Framework; + +namespace Email +{ + public class ModConfig + { + public bool EnableMod { get; set; } = true; + public bool EnableCatalogue { get; set; } = true; + public bool EnableFurnitureCatalogue { get; set; } = true; + public bool EnableSeedCatalogue { get; set; } = true; + public bool EnableTravelingCatalogue { get; set; } = true; + public bool LimitTravelingCatalogToInTown { get; set; } = true; + public bool EnableDesertCatalogue { get; set; } = true; + public bool LimitDesertCatalogToBusFixed { get; set; } = true; + public bool EnableHatCatalogue { get; set; } = true; + public bool EnableClothingCatalogue { get; set; } = true; + public bool EnableDwarfCatalogue { get; set; } = true; + public bool EnableKrobusCatalogue { get; set; } = true; + public bool EnableGuildCatalogue { get; set; } = true; + public bool RequireCataloguePurchase { get; set; } = true; + public int PriceCatalogue { get; set; } = 30000; + public int PriceFurnitureCatalogue { get; set; } = 100000; + public int PriceSeedCatalogue { get; set; } = 300000; + public int PriceTravelingCatalogue { get; set; } = 500000; + public int PriceDesertCatalogue { get; set; } = 500000; + public int PriceHatCatalogue { get; set; } = 10000; + public int PriceClothingCatalogue { get; set; } = 200000; + public int PriceDwarfCatalogue { get; set; } = 200000; + public int PriceKrobusCatalogue { get; set; } = 200000; + public int PriceGuildCatalogue { get; set; } = 100000; + public bool FreeCatalogue { get; set; } = false; + public bool FreeFurnitureCatalogue { get; set; } = false; + public bool FreeSeedCatalogue { get; set; } = false; + public bool FreeDesertCatalogue { get; set; } = false; + public bool FreeTravelingCatalogue { get; set; } = false; + public bool FreeHatCatalogue { get; set; } = false; + public bool FreeClothingCatalogue { get; set; } = false; + public string SeedsToInclude { get; set; } = "season"; + public float PriceMult { get; set; } = 1f; + public int AppHeaderHeight { get; set; } = 32; + public int AppRowHeight { get; set; } = 32; + public Color BackgroundColor { get; set; } = Color.White; + public Color HighlightColor { get; set; } = new Color(230,230,255); + public Color GreyedColor { get; set; } = new Color(230, 230, 230); + public Color HeaderColor { get; set; } = new Color(100, 100, 200); + public Color TextColor { get; set; } = Color.Black; + public Color HeaderTextColor { get; set; } = Color.White; + public int MarginX { get; set; } = 4; + public int MarginY { get; set; } = 4; + public float HeaderTextScale { get; set; } = 0.5f; + public float TextScale { get; set; } = 0.5f; + } +} diff --git a/Email/ModEntry.cs b/Email/ModEntry.cs new file mode 100644 index 00000000..0ebbe88e --- /dev/null +++ b/Email/ModEntry.cs @@ -0,0 +1,41 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI; +using StardewModdingAPI.Events; +using StardewValley; +using StardewValley.Locations; +using StardewValley.Menus; +using StardewValley.Objects; +using StardewValley.Util; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Object = StardewValley.Object; + +namespace Email +{ + public partial class ModEntry : Mod + { + public static ModEntry context; + + public static ModConfig Config; + public static IModHelper SHelper; + public static IMonitor SMonitor; + public static IMobilePhoneApi api; + + /// The mod entry point, called after the mod is first loaded. + /// Provides simplified APIs for writing mods. + public override void Entry(IModHelper helper) + { + context = this; + Config = Helper.ReadConfig(); + SHelper = Helper; + SMonitor = Monitor; + + Helper.Events.GameLoop.GameLaunched += GameLoop_GameLaunched; + } + + } +} diff --git a/Email/Visuals.cs b/Email/Visuals.cs new file mode 100644 index 00000000..19bbf00e --- /dev/null +++ b/Email/Visuals.cs @@ -0,0 +1,119 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI; +using StardewModdingAPI.Events; +using StardewValley; +using System; +using System.IO; + +namespace Email +{ + public partial class ModEntry + { + private static Texture2D backgroundTexture; + private static Texture2D hightlightTexture; + private static Texture2D headerTexture; + public static bool clicking; + private static bool dragging; + public static Point lastMousePosition; + public static float offsetY; + + public void MakeTextures() + { + Vector2 screenSize = api.GetScreenSize(); + Texture2D texture = new Texture2D(Game1.graphics.GraphicsDevice, (int)screenSize.X, (int)screenSize.Y); + Color[] data = new Color[texture.Width * texture.Height]; + for (int pixel = 0; pixel < data.Length; pixel++) + { + data[pixel] = Config.BackgroundColor; + } + texture.SetData(data); + backgroundTexture = texture; + texture = new Texture2D(Game1.graphics.GraphicsDevice, (int)screenSize.X, Config.AppRowHeight); + data = new Color[texture.Width * texture.Height]; + for (int pixel = 0; pixel < data.Length; pixel++) + { + data[pixel] = Config.HighlightColor; + } + texture.SetData(data); + hightlightTexture = texture; + + texture = new Texture2D(Game1.graphics.GraphicsDevice, (int)screenSize.X, Config.AppHeaderHeight); + data = new Color[texture.Width * texture.Height]; + for (int pixel = 0; pixel < data.Length; pixel++) + { + data[pixel] = Config.HeaderColor; + } + texture.SetData(data); + headerTexture = texture; + + } + + public void Display_RenderedWorld(object sender, RenderedWorldEventArgs e) + { + + if (api.IsCallingNPC()) + return; + + Vector2 screenPos = api.GetScreenPosition(); + Vector2 screenSize = api.GetScreenSize(); + if (!api.GetPhoneOpened() || !api.GetAppRunning() || api.GetRunningApp() != Helper.ModRegistry.ModID) + { + Monitor.Log($"Closing app: phone opened {api.GetPhoneOpened()} app running {api.GetAppRunning()} running app {api.GetRunningApp()}"); + CloseApp(); + return; + } + + if (!clicking) + dragging = false; + + Point mousePos = Game1.getMousePosition(); + if (clicking) + { + if (mousePos.Y != lastMousePosition.Y && (dragging || api.GetScreenRectangle().Contains(mousePos))) + { + dragging = true; + offsetY += mousePos.Y - lastMousePosition.Y; + //Monitor.Log($"offsetY {offsetY} max {screenSize.Y - Config.MarginY + (Config.MarginY + Game1.dialogueFont.LineSpacing * 0.9f) * audio.Length}"); + offsetY = Math.Min(0, Math.Max(offsetY, (int)(screenSize.Y - (Config.AppHeaderHeight + Config.MarginY + (Config.MarginY + Config.AppRowHeight) * Game1.player.mailbox.Count)))); + lastMousePosition = mousePos; + } + } + + if (clicking && !Helper.Input.IsSuppressed(SButton.MouseLeft)) + { + Monitor.Log($"unclicking; dragging = {dragging}"); + if (dragging) + dragging = false; + else if (api.GetScreenRectangle().Contains(mousePos) && !new Rectangle((int)screenPos.X, (int)screenPos.Y, (int)screenSize.X, Config.AppHeaderHeight).Contains(mousePos)) + { + ClickRow(mousePos); + } + clicking = false; + } + + + e.SpriteBatch.Draw(backgroundTexture, new Rectangle((int)screenPos.X, (int)screenPos.Y, (int)screenSize.X, (int)screenSize.Y), Color.White); + for (int i = 0; i < Game1.player.mailbox.Count; i++) + { + string a = Game1.player.mailbox[i]; + float posY = screenPos.Y + Config.AppHeaderHeight + Config.MarginY * (i + 1) + i * Config.AppRowHeight + offsetY; + Rectangle r = new Rectangle((int)screenPos.X, (int)posY, (int)screenSize.X, Config.AppRowHeight); + + if(r.Contains(mousePos)) + e.SpriteBatch.Draw(hightlightTexture, r, Color.White); + + float textHeight = Game1.dialogueFont.MeasureString(a).Y * Config.TextScale; + if (posY > screenPos.Y && posY < screenPos.Y + screenSize.Y - Config.AppRowHeight / 2f + textHeight / 2f) + { + e.SpriteBatch.DrawString(Game1.dialogueFont, a, new Vector2(screenPos.X + Config.MarginX, posY + Config.AppRowHeight / 2f - textHeight / 2f), Config.TextColor, 0f, Vector2.Zero, Config.TextScale, SpriteEffects.None, 0.86f); + } + } + e.SpriteBatch.Draw(headerTexture, new Rectangle((int)screenPos.X, (int)screenPos.Y, (int)screenSize.X, Config.AppHeaderHeight), Color.White); + float headerTextHeight = Game1.dialogueFont.MeasureString(Helper.Translation.Get("email")).Y * Config.HeaderTextScale; + Vector2 xSize = Game1.dialogueFont.MeasureString("x") * Config.HeaderTextScale; + e.SpriteBatch.DrawString(Game1.dialogueFont, Helper.Translation.Get("email"), new Vector2(screenPos.X + Config.MarginX, screenPos.Y + Config.AppHeaderHeight / 2f - headerTextHeight / 2f), Config.HeaderTextColor, 0f, Vector2.Zero, Config.HeaderTextScale, SpriteEffects.None, 0.86f); + e.SpriteBatch.DrawString(Game1.dialogueFont, "x", new Vector2(screenPos.X + screenSize.X - Config.AppHeaderHeight / 2f - xSize.X / 2f, screenPos.Y + Config.AppHeaderHeight / 2f - xSize.Y / 2f), Config.HeaderTextColor, 0f, Vector2.Zero, Config.HeaderTextScale, SpriteEffects.None, 0.86f); + } + } +} diff --git a/Email/assets/app_icon.png b/Email/assets/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8af180f2dd42435fce5f8cbcab9727b86a870bb8 GIT binary patch literal 17817 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

-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 literal 0 HcmV?d00001 diff --git a/Email/i18n/default.json b/Email/i18n/default.json new file mode 100644 index 00000000..acf7aa0b --- /dev/null +++ b/Email/i18n/default.json @@ -0,0 +1,3 @@ +{ + "email": "Email" +} \ No newline at end of file diff --git a/Email/manifest.json b/Email/manifest.json new file mode 100644 index 00000000..73e74e59 --- /dev/null +++ b/Email/manifest.json @@ -0,0 +1,26 @@ +{ + "Name": "Email", + "Author": "aedenthorn", + "Version": "0.1.0", + "Description": "Check mail on your mobile phone.", + "UniqueID": "aedenthorn.Email", + "EntryDll": "Email.dll", + "MinimumApiVersion": "3.13.0", + "UpdateKeys": [ "Nexus:" ], + "ModUpdater": { + "Repository": "StardewValleyMods", + "User": "aedenthorn", + "Directory": "_releases", + "ModFolder": "Email" + }, + "Dependencies": [ + { + "UniqueID": "Platonymous.ModUpdater", + "IsRequired": false + }, + { + "UniqueID": "aedenthorn.MobilePhone", + "IsRequired": true + } + ] +} \ No newline at end of file diff --git a/MoveableMailbox/ModEntry.cs b/MoveableMailbox/ModEntry.cs index a540234b..cca3872b 100644 --- a/MoveableMailbox/ModEntry.cs +++ b/MoveableMailbox/ModEntry.cs @@ -1,4 +1,4 @@ -using Harmony; +using HarmonyLib; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI; @@ -39,7 +39,7 @@ public override void Entry(IModHelper helper) Helper.Events.GameLoop.SaveLoaded += GameLoop_SaveLoaded; Helper.Events.GameLoop.SaveLoaded += GameLoop_SaveLoaded; - var harmony = HarmonyInstance.Create(ModManifest.UniqueID); + var harmony = new Harmony(ModManifest.UniqueID); harmony.Patch( original: AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)), @@ -58,7 +58,7 @@ public override void Entry(IModHelper helper) harmony.Patch( original: AccessTools.Method(typeof(Object), nameof(Object.performRemoveAction)), - prefix: new HarmonyMethod(typeof(ModEntry), nameof(performRemoveAction_Prefix)) { prioritiy = Priority.First } + prefix: new HarmonyMethod(typeof(ModEntry), nameof(performRemoveAction_Prefix)) ); } @@ -142,7 +142,7 @@ private static void loadForNewGame_Postfix() private static void placementAction_Postfix(Object __instance, bool __result, int x, int y, Farmer who) { - if (!__result || !__instance.Name.EndsWith("Mailbox") || who == null || !(who.currentLocation is Farm)) + if (!__result || !__instance.Name.EndsWith("Mailbox") || who == null) return; (who.currentLocation as Farm).mapMainMailboxPosition = new Point(x / 64, y / 64); @@ -152,7 +152,7 @@ private static void placementAction_Postfix(Object __instance, bool __result, in private static bool checkForAction_Prefix(Object __instance, ref bool __result, Farmer who, bool justCheckingForActivity) { - if (__instance.Name.EndsWith("Mailbox") && who.currentLocation is Farm && !justCheckingForActivity) + if (__instance.Name.EndsWith("Mailbox") && !justCheckingForActivity) { PMonitor.Log("Clicked on mailbox"); Point mailbox_position = Game1.player.getMailboxPosition(); diff --git a/StardewValleyMods.sln b/StardewValleyMods.sln index 9d6cd8c9..c772e1e0 100644 --- a/StardewValleyMods.sln +++ b/StardewValleyMods.sln @@ -264,6 +264,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdvancedMenuPositioning", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomToolbar", "CustomToolbar\CustomToolbar.csproj", "{8AD9149E-CA85-4C62-B549-6CA594FE5AA2}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Email", "Email\Email.csproj", "{9C00F8E7-2094-454F-8F95-955E9EFBDA3C}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution _releases\_releases.projitems*{047040e0-3d07-46e5-852b-d1d45cd57bb8}*SharedItemsImports = 13 @@ -1291,6 +1293,14 @@ Global {8AD9149E-CA85-4C62-B549-6CA594FE5AA2}.Release|Any CPU.Build.0 = Release|Any CPU {8AD9149E-CA85-4C62-B549-6CA594FE5AA2}.Release|x86.ActiveCfg = Release|Any CPU {8AD9149E-CA85-4C62-B549-6CA594FE5AA2}.Release|x86.Build.0 = Release|Any CPU + {9C00F8E7-2094-454F-8F95-955E9EFBDA3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C00F8E7-2094-454F-8F95-955E9EFBDA3C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C00F8E7-2094-454F-8F95-955E9EFBDA3C}.Debug|x86.ActiveCfg = Debug|Any CPU + {9C00F8E7-2094-454F-8F95-955E9EFBDA3C}.Debug|x86.Build.0 = Debug|Any CPU + {9C00F8E7-2094-454F-8F95-955E9EFBDA3C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C00F8E7-2094-454F-8F95-955E9EFBDA3C}.Release|Any CPU.Build.0 = Release|Any CPU + {9C00F8E7-2094-454F-8F95-955E9EFBDA3C}.Release|x86.ActiveCfg = Release|Any CPU + {9C00F8E7-2094-454F-8F95-955E9EFBDA3C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE