diff --git a/CustomFixedDialogue/CustomFixedDialogue.csproj b/CustomFixedDialogue/CustomFixedDialogue.csproj new file mode 100644 index 00000000..950e707d --- /dev/null +++ b/CustomFixedDialogue/CustomFixedDialogue.csproj @@ -0,0 +1,69 @@ + + + + + Debug + AnyCPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2} + Library + Properties + CustomFixedDialogue + CustomFixedDialogue + v4.5.2 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + G:\ga\Stardew Valley\smapi-internal\0Harmony.dll + + + G:\ga\Stardew Valley\StardewModdingAPI.exe + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/CustomFixedDialogue/DialoguePatches.cs b/CustomFixedDialogue/DialoguePatches.cs new file mode 100644 index 00000000..4f8a57f5 --- /dev/null +++ b/CustomFixedDialogue/DialoguePatches.cs @@ -0,0 +1,89 @@ +using StardewModdingAPI; +using StardewValley; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace CustomFixedDialogue +{ + internal class DialoguePatches + { + private static IMonitor Monitor; + private static IModHelper Helper; + private static string prefix = "CustomFixedDialogue"; + public static void Initialize(IMonitor monitor, IModHelper helper) + { + Monitor = monitor; + Helper = helper; + } + public static void LocalizedContentManager_LoadString_Postfix(string path, ref string __result) + { + try + { + if (path.StartsWith("Data\\ExtraDialogue")) + { + __result = $"{prefix}{path.Replace("Data\\ExtraDialogue:", "ExtraDialogue_")}^{__result}"; + Monitor.Log($"edited dialogue: {__result}"); + } + else if (path.StartsWith("Strings\\StringsFromCSFiles:NPC.cs.")) + { + __result = $"{prefix}{path.Replace("Strings\\StringsFromCSFiles:", "")}^{__result}"; + Monitor.Log($"edited dialogue: {__result}"); + } + } + catch (Exception ex) + { + Monitor.Log($"Failed in {nameof(LocalizedContentManager_LoadString_Postfix)}:\n{ex}", LogLevel.Error); + } + } + + + public static void LocalizedContentManager_LoadString_Postfix2(string path, ref string __result) + { + try + { + if (path.StartsWith("Data\\ExtraDialogue")) + { + __result = $"{prefix}{path.Replace("Data\\ExtraDialogue:", "ExtraDialogue_")}^{__result}"; + } + else if (path.StartsWith("Strings\\StringsFromCSFiles:NPC.cs.")) + { + __result = $"{prefix}{path.Replace("Strings\\StringsFromCSFiles:", "")}^{__result}"; + } + } + catch (Exception ex) + { + Monitor.Log($"Failed in {nameof(LocalizedContentManager_LoadString_Postfix2)}:\n{ex}", LogLevel.Error); + } + } + + public static void Dialogue_parseDialogueString_Prefix(Dialogue __instance, ref string masterString) + { + try + { + if (masterString.StartsWith(prefix)) + { + Dictionary dialogueDic = Helper.Content.Load>($"Characters/Dialogue/{__instance.speaker.Name}", ContentSource.GameContent); + string key = masterString.Substring(prefix.Length).Split('^')[0]; + if (dialogueDic.ContainsKey(key)) + { + Monitor.Log($"{__instance.speaker.Name} has dialogue for {key}", LogLevel.Debug); + masterString = dialogueDic[key]; + } + else + { + masterString = string.Join("^", masterString.Split('^').Skip(1)); + } + } + } + catch (Exception ex) + { + Monitor.Log($"Failed in {nameof(Dialogue_parseDialogueString_Prefix)}:\n{ex}", LogLevel.Error); + } + } + public static void Dialogue_CTOR_Prefix() + { + Monitor.Log($"WORKING NOW", LogLevel.Error); + } + } +} \ No newline at end of file diff --git a/CustomFixedDialogue/ModConfig.cs b/CustomFixedDialogue/ModConfig.cs new file mode 100644 index 00000000..8e04dbe1 --- /dev/null +++ b/CustomFixedDialogue/ModConfig.cs @@ -0,0 +1,6 @@ +namespace CustomFixedDialogue +{ + public class ModConfig + { + } +} \ No newline at end of file diff --git a/CustomFixedDialogue/ModEntry.cs b/CustomFixedDialogue/ModEntry.cs new file mode 100644 index 00000000..4abaa467 --- /dev/null +++ b/CustomFixedDialogue/ModEntry.cs @@ -0,0 +1,50 @@ +using Harmony; +using StardewModdingAPI; +using StardewValley; +using System; +using System.Reflection; + +namespace CustomFixedDialogue +{ + public class ModEntry : Mod + { + public static ModEntry context; + + internal static ModConfig Config; + + + /// 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(); + + DialoguePatches.Initialize(Monitor, helper); + + var harmony = HarmonyInstance.Create(ModManifest.UniqueID); + HarmonyInstance.DEBUG = true; + + /* + harmony.Patch( + original: AccessTools.Constructor(typeof(Dialogue), new Type[] { typeof(string), typeof(NPC) }), + prefix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.Dialogue_CTOR_Prefix)), + postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.Dialogue_CTOR_Prefix)) + ); + */ + harmony.Patch( + original: AccessTools.Method(typeof(Dialogue), "parseDialogueString"), + prefix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.Dialogue_parseDialogueString_Prefix)) + ); + + harmony.Patch( + original: AccessTools.Method(typeof(LocalizedContentManager), nameof(LocalizedContentManager.LoadString), new Type[] { typeof(string) }), + postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.LocalizedContentManager_LoadString_Postfix)) + ); + harmony.Patch( + original: AccessTools.Method(typeof(LocalizedContentManager), nameof(LocalizedContentManager.LoadString), new Type[] { typeof(string), typeof(object) }), + postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.LocalizedContentManager_LoadString_Postfix2)) + ); + } + } +} diff --git a/CustomFixedDialogue/Properties/AssemblyInfo.cs b/CustomFixedDialogue/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..4d0beb31 --- /dev/null +++ b/CustomFixedDialogue/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CustomFixedDialogue")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CustomFixedDialogue")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5cfbc975-48dc-40a0-9478-e81f76d7c8c2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CustomFixedDialogue/manifest.json b/CustomFixedDialogue/manifest.json new file mode 100644 index 00000000..395ff14a --- /dev/null +++ b/CustomFixedDialogue/manifest.json @@ -0,0 +1,22 @@ +{ + "Name": "Custom Fixed Dialogue", + "Author": "aedenthorn", + "Version": "0.1.1", + "Description": "Customize fixed dialogue for each NPC.", + "UniqueID": "aedenthorn.CustomFixedDialogue", + "EntryDll": "CustomFixedDialogue.dll", + "MinimumApiVersion": "3.4.0", + "ModUpdater": { + "Repository": "StardewValleyMods", + "User": "aedenthorn", + "Directory": "_releases", + "ModFolder": "CustomFixedDialogue" + }, + "UpdateKeys": ["Nexus:6358"], + "Dependencies": [ + { + "UniqueID": "Platonymous.ModUpdater", + "IsRequired": false + }, + ] +} \ No newline at end of file diff --git a/CustomFixedDialogue/packages.config b/CustomFixedDialogue/packages.config new file mode 100644 index 00000000..02bb7162 --- /dev/null +++ b/CustomFixedDialogue/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/MultipleSpouses 1.0.4.zip b/MultipleSpouses 1.0.4.zip new file mode 100644 index 00000000..af916125 Binary files /dev/null and b/MultipleSpouses 1.0.4.zip differ diff --git a/MultipleSpouses/HelperEvents.cs b/MultipleSpouses/HelperEvents.cs index b8163911..30345a00 100644 --- a/MultipleSpouses/HelperEvents.cs +++ b/MultipleSpouses/HelperEvents.cs @@ -273,6 +273,7 @@ public static void GameLoop_OneSecondUpdateTicked(object sender, OneSecondUpdate { if (allSpouses.Contains(character.Name)) { + if (Misc.IsInBed(fh, character.GetBoundingBox())) { character.farmerPassesThrough = true; diff --git a/ProceduralDungeons/ProceduralDungeons.csproj b/ProceduralDungeons/ProceduralDungeons.csproj index e4b7802f..49e94823 100644 --- a/ProceduralDungeons/ProceduralDungeons.csproj +++ b/ProceduralDungeons/ProceduralDungeons.csproj @@ -14,6 +14,7 @@ true + true true diff --git a/RandomNPC/ModEntry.cs b/RandomNPC/ModEntry.cs index 55454b17..57a3759a 100644 --- a/RandomNPC/ModEntry.cs +++ b/RandomNPC/ModEntry.cs @@ -205,6 +205,8 @@ private void UpdateTicking(object sender, UpdateTickingEventArgs e) foreach (RNPC rnpc in RNPCs) { NPC npc = Game1.getCharacterFromName(rnpc.nameID); + if (npc == null) + continue; GameLocation currentLocation = npc.currentLocation; int dir = npc.getDirection(); if (currentLocation.isCollidingPosition(npc.nextPosition(dir), Game1.viewport, false, 0, false, npc)) diff --git a/StardewValleyMods.sln b/StardewValleyMods.sln index d08a8ef0..515f8fc2 100644 --- a/StardewValleyMods.sln +++ b/StardewValleyMods.sln @@ -37,11 +37,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutdoorButterflyHutch", "Ou EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Swim", "Swim\Swim.csproj", "{D06D6A79-D6AA-45E4-9E39-9D150F8A5365}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "_releases", "_releases\_releases.shproj", "{DAE274FA-6F23-42E4-B235-DF130EED1A00}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomFixedDialogue", "CustomFixedDialogue\CustomFixedDialogue.csproj", "{5CFBC975-48DC-40A0-9478-E81F76D7C8C2}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "_releases", "_releases\_releases.shproj", "{047040E0-3D07-46E5-852B-D1D45CD57BB8}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution - _releases\_releases.projitems*{dae274fa-6f23-42e4-b235-df130eed1a00}*SharedItemsImports = 13 + _releases\_releases.projitems*{047040e0-3d07-46e5-852b-d1d45cd57bb8}*SharedItemsImports = 13 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -186,6 +188,14 @@ Global {D06D6A79-D6AA-45E4-9E39-9D150F8A5365}.Release|Any CPU.Build.0 = Release|Any CPU {D06D6A79-D6AA-45E4-9E39-9D150F8A5365}.Release|x86.ActiveCfg = Release|Any CPU {D06D6A79-D6AA-45E4-9E39-9D150F8A5365}.Release|x86.Build.0 = Release|Any CPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2}.Debug|x86.ActiveCfg = Debug|Any CPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2}.Debug|x86.Build.0 = Debug|Any CPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2}.Release|Any CPU.Build.0 = Release|Any CPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2}.Release|x86.ActiveCfg = Release|Any CPU + {5CFBC975-48DC-40A0-9478-E81F76D7C8C2}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/_releases/Swim 0.9.1.zip b/Swim 0.9.2.zip similarity index 91% rename from _releases/Swim 0.9.1.zip rename to Swim 0.9.2.zip index 5105c8ba..4609428b 100644 Binary files a/_releases/Swim 0.9.1.zip and b/Swim 0.9.2.zip differ diff --git a/Swim/AbigailProjectile.cs b/Swim/AbigailProjectile.cs new file mode 100644 index 00000000..eba35319 --- /dev/null +++ b/Swim/AbigailProjectile.cs @@ -0,0 +1,85 @@ +using Microsoft.Xna.Framework; +using StardewValley; +using StardewValley.Monsters; +using StardewValley.Network; +using StardewValley.Projectiles; +using StardewValley.TerrainFeatures; + +namespace Swim +{ + public class AbigailProjectile : BasicProjectile + { + private string myCollisionSound; + private bool myExplode; + + public AbigailProjectile(int damageToFarmer, int parentSheetIndex, int bouncesTillDestruct, int tailLength, float rotationVelocity, float xVelocity, float yVelocity, Vector2 startingPosition, string collisionSound, string firingSound, bool explode, bool damagesMonsters = false, GameLocation location = null, Character firer = null, bool spriteFromObjectSheet = false, BasicProjectile.onCollisionBehavior collisionBehavior = null) : base(damageToFarmer, parentSheetIndex, bouncesTillDestruct, tailLength, rotationVelocity, xVelocity, yVelocity, startingPosition, collisionSound, firingSound, explode, true, location, firer, true, null) + { + IgnoreLocationCollision = true; + myCollisionSound = collisionSound; + myExplode = explode; + } + + public override void behaviorOnCollisionWithMonster(NPC n, GameLocation location) + { + this.explosionAnimation(location); + if (n is Monster) + { + location.characters.Remove(n); + return; + } + } + private void explosionAnimation(GameLocation location) + { + Rectangle sourceRect = Game1.getSourceRectForStandardTileSheet(this.spriteFromObjectSheet ? Game1.objectSpriteSheet : Projectile.projectileSheet, this.currentTileSheetIndex, -1, -1); + sourceRect.X += 28; + sourceRect.Y += 28; + sourceRect.Width = 8; + sourceRect.Height = 8; + int whichDebris = 12; + int value = this.currentTileSheetIndex.Value; + switch (value) + { + case 378: + whichDebris = 0; + break; + case 379: + case 381: + case 383: + case 385: + break; + case 380: + whichDebris = 2; + break; + case 382: + whichDebris = 4; + break; + case 384: + whichDebris = 6; + break; + case 386: + whichDebris = 10; + break; + default: + if (value == 390) + { + whichDebris = 14; + } + break; + } + if (this.spriteFromObjectSheet) + { + Game1.createRadialDebris(location, whichDebris, (int)(this.position.X + 32f) / 64, (int)(this.position.Y + 32f) / 64, 6, false, -1, false, -1); + } + else + { + Game1.createRadialDebris(location, "TileSheets\\Projectiles", sourceRect, 4, (int)this.position.X + 32, (int)this.position.Y + 32, 12, (int)(this.position.Y / 64f) + 1); + } + if (myCollisionSound != null && !this.myCollisionSound.Equals("")) + { + location.playSound(this.myCollisionSound, NetAudio.SoundContext.Default); + } + destroyMe = true; + + } + } +} \ No newline at end of file diff --git a/Swim/DiveMapData.cs b/Swim/DiveMapData.cs index 9e928cb0..fe454ce6 100644 --- a/Swim/DiveMapData.cs +++ b/Swim/DiveMapData.cs @@ -13,6 +13,7 @@ public class DiveMap public string Name { get; set; } public List Features { get; set; } = new List(); public List DiveLocations { get; set; } = new List(); + public List EdgeWarps { get; set; } = new List(); } public class DiveLocation @@ -34,4 +35,15 @@ public class DivePosition public int X { get; set; } public int Y { get; set; } } + public class EdgeWarp + { + public string ThisMapEdge { get; set; } = null; + public int FirstTile { get; set; } + public int LastTile { get; set; } + public string OtherMapName { get; set; } + public bool DestinationHorizontal { get; set; } + public int OtherMapIndex { get; set; } + public int OtherMapFirstTile { get; set; } + public int OtherMapLastTile { get; set; } + } } \ No newline at end of file diff --git a/Swim/ModEntry.cs b/Swim/ModEntry.cs index 6d4414c5..54a55bf2 100644 --- a/Swim/ModEntry.cs +++ b/Swim/ModEntry.cs @@ -183,6 +183,11 @@ public override void Entry(IModHelper helper) prefix: new HarmonyMethod(typeof(SwimPatches), nameof(SwimPatches.GameLocation_isCollidingPosition_Prefix)) ); + harmony.Patch( + original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.performTouchAction)), + prefix: new HarmonyMethod(typeof(SwimPatches), nameof(SwimPatches.GameLocation_performTouchAction_Prefix)) + ); + harmony.Patch( original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.checkAction)), prefix: new HarmonyMethod(typeof(SwimPatches), nameof(SwimPatches.GameLocation_checkAction_Prefix)) @@ -249,16 +254,16 @@ private void GameLoop_SaveLoaded(object sender, SaveLoadedEventArgs e) } } - Monitor.Log($"Reading content pack from assets/underwater-map-content.json"); + Monitor.Log($"Reading content pack from assets/swim-map-content.json"); try { - DiveMapData myData = Helper.Data.ReadJsonFile("assets/underwater-map-content.json"); + DiveMapData myData = Helper.Data.ReadJsonFile("assets/swim-map-content.json"); ReadDiveMapData(myData); } catch (Exception ex) { - Monitor.Log($"assets/underwater-map-content.json file read error. Exception: {ex}", LogLevel.Warn); + Monitor.Log($"assets/swim-map-content.json file read error. Exception: {ex}", LogLevel.Warn); } @@ -308,6 +313,32 @@ private void GameLoop_SaveLoaded(object sender, SaveLoadedEventArgs e) Game1.player.changeIntoSwimsuit(); } + public void ReadDiveMapData(DiveMapData data) + { + foreach (DiveMap map in data.Maps) + { + if (Game1._locationLookup.ContainsKey(map.Name)) + { + if (!diveMaps.ContainsKey(map.Name)) + { + diveMaps.Add(map.Name, map); + Monitor.Log($"added dive map info for {map.Name}", LogLevel.Debug); + } + else + { + Monitor.Log($"dive map info already exists for {map.Name}", LogLevel.Warn); + } + + } + else + { + Monitor.Log($"dive map info not loaded for {map.Name}, check you have the map installed", LogLevel.Warn); + } + } + } + + + public static int ticksUnderwater = 0; public static int bubbleOffset = 0; @@ -377,28 +408,25 @@ private void GameLoop_GameLaunched(object sender, GameLaunchedEventArgs e) JsonAssets.LoadAssets(Path.Combine(base.Helper.DirectoryPath, "assets/json-assets")); } - } + // fix dive maps - public void ReadDiveMapData(DiveMapData data) - { - foreach (DiveMap map in data.Maps) + foreach (IContentPack contentPack in Helper.ContentPacks.GetOwned()) { - if (Game1._locationLookup.ContainsKey(map.Name)) + try { - if (!diveMaps.ContainsKey(map.Name)) - { - diveMaps.Add(map.Name, map); - Monitor.Log($"added dive map info for {map.Name}", LogLevel.Debug); - } - else + Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}"); + DiveMapData data = contentPack.ReadJsonFile("content.json"); + foreach(DiveMap map in data.Maps) { - Monitor.Log($"dive map info already exists for {map.Name}", LogLevel.Warn); + if (map.Features.Contains("FixWaterTiles") && !changeLocations.ContainsKey(map.Name)) + { + changeLocations.Add(map.Name, false); + } } - } - else + catch { - Monitor.Log($"dive map info not loaded for {map.Name}, check you have the map installed", LogLevel.Warn); + Monitor.Log($"couldn't read content.json in content pack {contentPack.Manifest.Name}", LogLevel.Warn); } } } @@ -534,7 +562,7 @@ private void Input_ButtonPressed(object sender, ButtonPressedEventArgs e) Game1.currentLocation.overlayObjects[Game1.player.getTileLocation() + new Vector2(0, 1)] = new Chest(0, new List() { Helper.Input.IsDown(SButton.LeftShift) ? (Item)(new StardewValley.Object(434, 1)) : (new Hat(scubaMaskID)) }, Game1.player.getTileLocation() + new Vector2(0, 1), false, 0); } - if (e.Button == config.DiveKey && diveMaps.ContainsKey(Game1.currentLocation.Name)) + if (e.Button == config.DiveKey && diveMaps.ContainsKey(Game1.currentLocation.Name) && diveMaps[Game1.currentLocation.Name].DiveLocations.Count > 0) { Point pos = Game1.player.getTileLocationPoint(); Location loc = new Location(pos.X, pos.Y); @@ -544,56 +572,31 @@ private void Input_ButtonPressed(object sender, ButtonPressedEventArgs e) return; } - string newName = null; - DivePosition dp = null; - DiveMap dm = diveMaps[Game1.currentLocation.Name]; - + DiveLocation diveLocation = null; foreach(DiveLocation dl in dm.DiveLocations) { if (dl.GetRectangle().X == -1 || dl.GetRectangle().Contains(loc)) { - newName = dl.OtherMapName; - dp = dl.OtherMapPos; + diveLocation = dl; break; } } - if (newName == null) + if (diveLocation == null) { Monitor.Log($"No dive destination for this point on this map", LogLevel.Debug); return; } - if (!Game1._locationLookup.ContainsKey(newName)) + if (!Game1._locationLookup.ContainsKey(diveLocation.OtherMapName)) { - Monitor.Log($"Can't find destination map named {newName}", LogLevel.Warn); + Monitor.Log($"Can't find destination map named {diveLocation.OtherMapName}", LogLevel.Warn); return; } - Monitor.Log($"warping to {newName}", LogLevel.Debug); - - if (dp == null) - { - Monitor.Log($"warping to current position"); - dp = new DivePosition() - { - X = pos.X, - Y = pos.Y - }; - } - - Game1.playSound("pullItemFromWater"); - Game1.warpFarmer(newName, dp.X, dp.Y, false); - if (!IsMapUnderwater(Game1.currentLocation.Name)) - { - bubbles.Clear(); - isUnderwater = true; - } - else - { - isUnderwater = false; - } + Monitor.Log($"warping to {diveLocation.OtherMapName}", LogLevel.Debug); + DiveTo(diveLocation); return; } @@ -601,6 +604,7 @@ private void Input_ButtonPressed(object sender, ButtonPressedEventArgs e) { config.ReadyToSwim = !config.ReadyToSwim; Helper.WriteConfig(config); + Monitor.Log($"Ready to swim: {config.ReadyToSwim}"); return; } @@ -655,6 +659,67 @@ private void GameLoop_UpdateTicked(object sender, UpdateTickedEventArgs e) AbigailCaveTick(); } + if (Game1.activeClickableMenu == null) + { + if (IsMapUnderwater(Game1.currentLocation.Name)) + { + if (isUnderwater) + { + if (oxygen > 0) + { + if (!IsWearingScubaGear()) + oxygen--; + } + else + { + Game1.playSound("pullItemFromWater"); + isUnderwater = false; + DiveLocation diveLocation = diveMaps[Game1.currentLocation.Name].DiveLocations.Last(); + DiveTo(diveLocation); + } + } + } + else + { + if (oxygen < MaxOxygen()) + oxygen++; + if (oxygen < MaxOxygen()) + oxygen++; + } + } + + if (isJumping) + { + float difx = endJumpLoc.X - startJumpLoc.X; + float dify = endJumpLoc.Y - startJumpLoc.Y; + float completed = Game1.player.freezePause / (float)config.JumpTimeInMilliseconds; + if (Game1.player.freezePause <= 0) + { + Game1.player.position.Value = endJumpLoc; + isJumping = false; + if (willSwim) + { + Game1.currentLocation.playSound("waterSlosh", NetAudio.SoundContext.Default); + Game1.player.swimming.Value = true; + } + else + { + if (!config.SwimSuitAlways) + Game1.player.changeOutOfSwimSuit(); + } + return; + } + Game1.player.position.Value = new Vector2(endJumpLoc.X - (difx * completed), endJumpLoc.Y - (dify * completed) - (float)Math.Sin(completed * Math.PI) * 64); + return; + } + + + + if (!config.ReadyToSwim) + { + return; + } + if (Game1.player.swimming) { if (!IsInWater() && !isJumping) { @@ -664,54 +729,105 @@ private void GameLoop_UpdateTicked(object sender, UpdateTickedEventArgs e) Game1.player.changeOutOfSwimSuit(); } - if(Game1.player.position.Y > Game1.viewport.Y + Game1.viewport.Height - 16) + DiveMap dm = null; + Point edgePos = Game1.player.getTileLocationPoint(); + + if (diveMaps.ContainsKey(Game1.currentLocation.Name)) + { + dm = diveMaps[Game1.currentLocation.Name]; + } + + if (Game1.player.position.Y > Game1.viewport.Y + Game1.viewport.Height - 16) { + Game1.player.position.Value = new Vector2(Game1.player.position.X, Game1.viewport.Y + Game1.viewport.Height - 17); - if (Game1.currentLocation.Name == "Mountain") + if (dm != null) { - Game1.warpFarmer("Town",94,0, false); - } - else if (Game1.currentLocation.Name == "Town") - { - Game1.warpFarmer("Beach", 59, 0, false); + EdgeWarp edge = dm.EdgeWarps.Find((x) => x.ThisMapEdge == "Bottom" && x.FirstTile <= edgePos.X && x.LastTile >= edgePos.X); + if (edge != null) + { + Point pos = GetEdgeWarpDestination(edgePos.X, edge); + if (pos != Point.Zero) + { + Monitor.Log("warping south"); + Game1.warpFarmer(edge.OtherMapName, pos.X, pos.Y, false); + } + } } } - else if(Game1.player.position.Y < Game1.viewport.Y - 16) + else if (Game1.player.position.Y < Game1.viewport.Y - 16) { Game1.player.position.Value = new Vector2(Game1.player.position.X, Game1.viewport.Y - 15); - if (Game1.currentLocation.Name == "Town") - { - Game1.warpFarmer("Mountain",72,40, false); - } - else if (Game1.currentLocation.Name == "Beach" && Game1.player.position.X / 64 < 93) + + if (dm != null) { - Game1.warpFarmer("Town", 90, 109, false); + EdgeWarp edge = dm.EdgeWarps.Find((x) => x.ThisMapEdge == "Top" && x.FirstTile <= edgePos.X && x.LastTile >= edgePos.X); + if (edge != null) + { + Point pos = GetEdgeWarpDestination(edgePos.X, edge); + if (pos != Point.Zero) + { + Monitor.Log("warping north"); + Game1.warpFarmer(edge.OtherMapName, pos.X, pos.Y, false); + } + } } } - else if(Game1.player.position.X > Game1.viewport.X + Game1.viewport.Width - 32) + else if (Game1.player.position.X > Game1.viewport.X + Game1.viewport.Width - 32) { Game1.player.position.Value = new Vector2(Game1.viewport.X + Game1.viewport.Width - 33, Game1.player.position.Y); + + if (dm != null) + { + EdgeWarp edge = dm.EdgeWarps.Find((x) => x.ThisMapEdge == "Right" && x.FirstTile <= edgePos.Y && x.LastTile >= edgePos.Y); + if (edge != null) + { + Point pos = GetEdgeWarpDestination(edgePos.Y, edge); + if (pos != Point.Zero) + { + Monitor.Log("warping east"); + Game1.warpFarmer(edge.OtherMapName, pos.X, pos.Y, false); + } + } + } + if (Game1.currentLocation.Name == "Forest") { - if(Game1.player.position.Y / 64 > 74) - Game1.warpFarmer("Beach", 0,13, false); + if (Game1.player.position.Y / 64 > 74) + Game1.warpFarmer("Beach", 0, 13, false); else - Game1.warpFarmer("Town", 0,100, false); + Game1.warpFarmer("Town", 0, 100, false); } } - else if(Game1.player.position.X < Game1.viewport.X - 32) + else if (Game1.player.position.X < Game1.viewport.X - 32) { Game1.player.position.Value = new Vector2(Game1.viewport.X - 31, Game1.player.position.Y); + + if (dm != null) + { + EdgeWarp edge = dm.EdgeWarps.Find((x) => x.ThisMapEdge == "Left" && x.FirstTile <= edgePos.X && x.LastTile >= edgePos.X); + if (edge != null) + { + Point pos = GetEdgeWarpDestination(edgePos.Y, edge); + if (pos != Point.Zero) + { + Monitor.Log("warping west"); + Game1.warpFarmer(edge.OtherMapName, pos.X, pos.Y, false); + } + } + } + if (Game1.currentLocation.Name == "Town") { - Game1.warpFarmer("Forest",119,43, false); + Game1.warpFarmer("Forest", 119, 43, false); } else if (Game1.currentLocation.Name == "Beach") { - Game1.warpFarmer("Forest",119,111, false); + Game1.warpFarmer("Forest", 119, 111, false); } } + if (Game1.player.bathingClothes && IsWearingScubaGear() && !config.SwimSuitAlways) Game1.player.changeOutOfSwimSuit(); else if (!Game1.player.bathingClothes && (!IsWearingScubaGear() || config.SwimSuitAlways)) @@ -744,59 +860,6 @@ private void GameLoop_UpdateTicked(object sender, UpdateTickedEventArgs e) } - if (Game1.activeClickableMenu == null) - { - if (IsMapUnderwater(Game1.currentLocation.Name)) - { - if (isUnderwater) - { - if (oxygen > 0) - { - if(!IsWearingScubaGear()) - oxygen--; - } - else - { - Game1.playSound("pullItemFromWater"); - isUnderwater = false; - Point pos = Game1.player.getTileLocationPoint(); - Game1.warpFarmer(diveMaps[Game1.currentLocation.Name].DiveLocations.Last().OtherMapName, pos.X, pos.Y, false); - } - } - } - else - { - if (oxygen < MaxOxygen()) - oxygen++; - if (oxygen < MaxOxygen()) - oxygen++; - } - } - - if (isJumping) - { - float difx = endJumpLoc.X - startJumpLoc.X; - float dify = endJumpLoc.Y - startJumpLoc.Y; - float completed = Game1.player.freezePause / (float)config.JumpTimeInMilliseconds; - if(Game1.player.freezePause <= 0) - { - Game1.player.position.Value = endJumpLoc; - isJumping = false; - if (willSwim) - { - Game1.currentLocation.playSound("waterSlosh", NetAudio.SoundContext.Default); - Game1.player.swimming.Value = true; - } - else - { - if(!config.SwimSuitAlways) - Game1.player.changeOutOfSwimSuit(); - } - return; - } - Game1.player.position.Value = new Vector2(endJumpLoc.X - (difx * completed), endJumpLoc.Y - (dify * completed) - (float)Math.Sin(completed * Math.PI) * 64); - return; - } CheckIfMyButtonDown(); if (!myButtonDown || Game1.player.millisecondsPlayed - lastJump < 250 || IsMapUnderwater(Game1.currentLocation.Name)) @@ -924,9 +987,62 @@ private void GameLoop_UpdateTicked(object sender, UpdateTickedEventArgs e) } + private Point GetEdgeWarpDestination(int idxPos, EdgeWarp edge) + { + try + { + int idx = 1 + idxPos - edge.FirstTile; + int length = 1 + edge.LastTile - edge.FirstTile; + int otherLength = 1 + edge.OtherMapLastTile - edge.OtherMapFirstTile; + int otherIdx = (int)Math.Round((idx / (float)length) * otherLength); + int tileIdx = edge.OtherMapFirstTile - 1 + otherIdx; + if (edge.DestinationHorizontal == true) + { + Monitor.Log($"idx {idx} length {length} otherIdx {otherIdx} tileIdx {tileIdx} warp point: {tileIdx},{edge.OtherMapIndex}"); + return new Point(tileIdx, edge.OtherMapIndex); + } + else + { + Monitor.Log($"warp point: {edge.OtherMapIndex},{tileIdx}"); + return new Point(edge.OtherMapIndex, tileIdx); + } + } + catch + { + + } + return Point.Zero; + } + + private void DiveTo(DiveLocation diveLocation) + { + DivePosition dp = diveLocation.OtherMapPos; + if (dp == null) + { + Point pos = Game1.player.getTileLocationPoint(); + dp = new DivePosition() + { + X = pos.X, + Y = pos.Y + }; + } + if (!IsMapUnderwater(Game1.currentLocation.Name)) + { + bubbles.Clear(); + isUnderwater = true; + } + else + { + isUnderwater = false; + } + + Game1.playSound("pullItemFromWater"); + Game1.warpFarmer(diveLocation.OtherMapName, dp.X, dp.Y, false); + } + private bool IsMapUnderwater(string name) { - return diveMaps.ContainsKey(Game1.currentLocation.Name) && diveMaps[Game1.currentLocation.Name].Features.Contains("Underwater"); + return diveMaps.ContainsKey(name) && diveMaps[name].Features.Contains("Underwater"); } public static int abigailTicks; @@ -1070,12 +1186,9 @@ private void AbigailCaveTick() } } - if (v != Vector2.Zero && Game1.player.millisecondsPlayed - lastProjectile > 500) + if (v != Vector2.Zero && Game1.player.millisecondsPlayed - lastProjectile > 350) { - Game1.currentLocation.projectiles.Add(new BasicProjectile(1, 383, 0, 0, 0, v.X * 6, v.Y * 6, new Vector2(Game1.player.getStandingX() - 24, Game1.player.getStandingY() - 48), "Cowboy_monsterDie", "Cowboy_gunshot", false, true, Game1.currentLocation, Game1.player, true, null) - { - IgnoreLocationCollision = true - }); + Game1.currentLocation.projectiles.Add(new AbigailProjectile(1, 383, 0, 0, 0, v.X * 6, v.Y * 6, new Vector2(Game1.player.getStandingX() - 24, Game1.player.getStandingY() - 48), "Cowboy_monsterDie", "Cowboy_gunshot", false, true, Game1.currentLocation, Game1.player, true)); lastProjectile = Game1.player.millisecondsPlayed; } @@ -1171,12 +1284,12 @@ private bool IsInWater() return IsMapUnderwater(Game1.currentLocation.Name) || - (tiles != null + (tiles != null && ( - (tiles.GetLength(0) > p.X && tiles.GetLength(1) > p.Y && tiles[p.X, p.Y]) + (p.X >= 0 && p.Y >= 0 && tiles.GetLength(0) > p.X && tiles.GetLength(1) > p.Y && tiles[p.X, p.Y]) || (Game1.player.swimming && - (tiles.GetLength(0) <= p.X || tiles.GetLength(1) <= p.Y) + (p.X < 0 || p.Y < 0 || tiles.GetLength(0) <= p.X || tiles.GetLength(1) <= p.Y) ) ) ); @@ -1878,7 +1991,7 @@ public bool CanEdit(IAssetInfo asset) /// A helper which encapsulates metadata about an asset and enables changes to it. public void Edit(IAssetData asset) { - Monitor.Log("Editing asset" + asset.AssetName); + Monitor.Log("Editing asset: " + asset.AssetName); string mapName = asset.AssetName.Replace("Maps/", "").Replace("Maps\\", ""); @@ -1904,7 +2017,7 @@ public void Edit(IAssetData asset) { if (tile.TileIndexProperties.ContainsKey("Passable")) { - tile.TileIndexProperties.Remove("Passable"); + //tile.TileIndexProperties.Remove("Passable"); } } if (map.Data.GetLayer("AlwaysFront") != null) @@ -1914,7 +2027,7 @@ public void Edit(IAssetData asset) { if (tile.TileIndexProperties.ContainsKey("Passable")) { - tile.TileIndexProperties.Remove("Passable"); + //tile.TileIndexProperties.Remove("Passable"); } } } diff --git a/Swim/Swim.csproj b/Swim/Swim.csproj index daf62ea0..ba873fa5 100644 --- a/Swim/Swim.csproj +++ b/Swim/Swim.csproj @@ -44,6 +44,7 @@ + @@ -68,7 +69,7 @@ - + diff --git a/Swim/SwimPatches.cs b/Swim/SwimPatches.cs index aa3acdf4..77ae8ca4 100644 --- a/Swim/SwimPatches.cs +++ b/Swim/SwimPatches.cs @@ -100,7 +100,7 @@ public static void Farmer_updateCommon_Prefix(Farmer __instance, ref float[] __s try { __state = new float[0]; - if(__instance.swimming && ModEntry.changeLocations.ContainsKey(Game1.currentLocation.Name)) + if(__instance.swimming && ModEntry.changeLocations.ContainsKey(Game1.currentLocation.Name) && Config.ReadyToSwim) { __state = new float[]{ __instance.stamina, @@ -261,6 +261,48 @@ public static void GameLocation_UpdateWhenCurrentLocation_Postfix(GameLocation _ Monitor.Log($"Failed in {nameof(GameLocation_UpdateWhenCurrentLocation_Postfix)}:\n{ex}", LogLevel.Error); } } + public static void GameLocation_performTouchAction_Prefix(string fullActionString) + { + try + { + string text = fullActionString.Split(new char[] + { + ' ' + })[0]; + if (text == "PoolEntrance") + { + if (!Game1.player.swimming) + { + Config.ReadyToSwim = false; + } + } + } + catch (Exception ex) + { + Monitor.Log($"Failed in {nameof(GameLocation_performTouchAction_Prefix)}:\n{ex}", LogLevel.Error); + } + } + public static void GameLocation_performTouchAction_Postfix(string fullActionString) + { + try + { + string text = fullActionString.Split(new char[] + { + ' ' + })[0]; + if (text == "PoolEntrance") + { + if (Game1.player.swimming) + { + Config = Helper.ReadConfig(); + } + } + } + catch (Exception ex) + { + Monitor.Log($"Failed in {nameof(GameLocation_performTouchAction_Postfix)}:\n{ex}", LogLevel.Error); + } + } public static void GameLocation_checkAction_Prefix(GameLocation __instance, Location tileLocation, xTile.Dimensions.Rectangle viewport, Farmer who) { try diff --git a/Swim/assets/underwater-map-content.json b/Swim/assets/swim-map-content.json similarity index 51% rename from Swim/assets/underwater-map-content.json rename to Swim/assets/swim-map-content.json index 260a8955..a9d94e99 100644 --- a/Swim/assets/underwater-map-content.json +++ b/Swim/assets/swim-map-content.json @@ -33,6 +33,28 @@ "OtherMapName":"UnderwaterBeach", }, ], + "EdgeWarps":[ + { + "ThisMapEdge":"Top", + "FirstTile": 57, + "LastTile": 62, + "DestinationHorizontal": true, + "OtherMapIndex": 109, + "OtherMapFirstTile": 88, + "OtherMapLastTile": 92, + "OtherMapName":"Town", + }, + { + "ThisMapEdge":"Right", + "FirstTile": 14, + "LastTile": 26, + "DestinationHorizontal": false, + "OtherMapIndex": 119, + "OtherMapFirstTile": 106, + "OtherMapLastTile": 119, + "OtherMapName":"Beach", + }, + ] }, { "Name":"ScubaCrystalCave", @@ -64,7 +86,29 @@ } }, ], - }, + "EdgeWarps":[ + { + "ThisMapEdge":"Right", + "FirstTile": 39, + "LastTile": 48, + "DestinationHorizontal": false, + "OtherMapIndex": 0, + "OtherMapFirstTile": 96, + "OtherMapLastTile": 103, + "OtherMapName":"Town", + }, + { + "ThisMapEdge":"Right", + "FirstTile": 106, + "LastTile": 119, + "DestinationHorizontal": false, + "OtherMapIndex": 0, + "OtherMapFirstTile": 14, + "OtherMapLastTile": 26, + "OtherMapName":"Beach", + }, + ] + }, { "Name":"ScubaCave", "Features":[ @@ -118,11 +162,61 @@ }, { "Name":"Mountain", + "Features":[ + "FixWaterTiles" + ], "DiveLocations": [ { "OtherMapName":"UnderwaterMountain", }, ], + "EdgeWarps":[ + { + "ThisMapEdge":"Bottom", + "FirstTile": 64, + "LastTile": 78, + "DestinationHorizontal": true, + "OtherMapIndex": 0, + "OtherMapFirstTile": 92, + "OtherMapLastTile": 96, + "OtherMapName":"Town", + }, + ], + }, + { + "Name":"Town", + "EdgeWarps":[ + { + "ThisMapEdge":"Bottom", + "FirstTile": 88, + "LastTile": 92, + "DestinationHorizontal": true, + "OtherMapIndex": 0, + "OtherMapFirstTile": 57, + "OtherMapLastTile": 62, + "OtherMapName":"Beach", + }, + { + "ThisMapEdge":"Top", + "FirstTile": 92, + "LastTile": 96, + "DestinationHorizontal": true, + "OtherMapIndex": 40, + "OtherMapFirstTile": 64, + "OtherMapLastTile": 78, + "OtherMapName":"Mountain", + }, + { + "ThisMapEdge":"Left", + "FirstTile": 96, + "LastTile": 103, + "DestinationHorizontal": false, + "OtherMapIndex": 119, + "OtherMapFirstTile": 39, + "OtherMapLastTile": 48, + "OtherMapName":"Town", + }, + ] }, ] } \ No newline at end of file diff --git a/Swim/manifest.json b/Swim/manifest.json index 6e698214..2bc7a37d 100644 --- a/Swim/manifest.json +++ b/Swim/manifest.json @@ -1,7 +1,7 @@ { "Name": "Swim Mod", "Author": "aedenthorn", - "Version": "0.9.2", + "Version": "0.9.6", "Description": "Allows you to swim.", "UniqueID": "aedenthorn.Swim", "EntryDll": "Swim.dll", diff --git a/_releases/CustomFixedDialogue 0.1.0.zip b/_releases/CustomFixedDialogue 0.1.0.zip new file mode 100644 index 00000000..d6a0a02b Binary files /dev/null and b/_releases/CustomFixedDialogue 0.1.0.zip differ diff --git a/_releases/CustomFixedDialogue 0.1.1.zip b/_releases/CustomFixedDialogue 0.1.1.zip new file mode 100644 index 00000000..a4eb6afe Binary files /dev/null and b/_releases/CustomFixedDialogue 0.1.1.zip differ diff --git a/_releases/MultipleSpouses 1.0.3.zip b/_releases/MultipleSpouses 1.0.3.zip deleted file mode 100644 index 88b550b3..00000000 Binary files a/_releases/MultipleSpouses 1.0.3.zip and /dev/null differ diff --git a/_releases/Swim 0.9.6.zip b/_releases/Swim 0.9.6.zip new file mode 100644 index 00000000..15032c6f Binary files /dev/null and b/_releases/Swim 0.9.6.zip differ diff --git a/_releases/_releases.projitems b/_releases/_releases.projitems new file mode 100644 index 00000000..10fcc700 --- /dev/null +++ b/_releases/_releases.projitems @@ -0,0 +1,18 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 047040e0-3d07-46e5-852b-d1d45cd57bb8 + + + _releases + + + + + + + + + \ No newline at end of file diff --git a/_releases/_releases.shproj b/_releases/_releases.shproj new file mode 100644 index 00000000..fe0a5da6 --- /dev/null +++ b/_releases/_releases.shproj @@ -0,0 +1,13 @@ + + + + 047040e0-3d07-46e5-852b-d1d45cd57bb8 + 14.0 + + + + + + + +