-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4439dd1
commit 35b7772
Showing
12 changed files
with
695 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
using DeluxeAutoPetter.helpers; | ||
using HarmonyLib; | ||
using Microsoft.Xna.Framework; | ||
using StardewModdingAPI; | ||
using StardewModdingAPI.Events; | ||
using StardewValley; | ||
|
||
namespace DeluxeAutoPetter | ||
{ | ||
internal sealed class DeluxeAutoPetter : Mod | ||
{ | ||
private static bool IS_DATA_LOADED = false; | ||
|
||
public override void Entry(IModHelper helper) | ||
{ | ||
I18n.Init(helper.Translation); | ||
|
||
helper.Events.Multiplayer.ModMessageReceived += OnModMessageReceived; | ||
helper.Events.Multiplayer.PeerConnected += OnPeerConnected; | ||
|
||
helper.Events.GameLoop.GameLaunched += OnGameLaunched; | ||
helper.Events.GameLoop.ReturnedToTitle += OnReturnedToTitle; | ||
|
||
helper.Events.GameLoop.UpdateTicked += OnUpdateTicked; | ||
helper.Events.Input.ButtonPressed += OnButtonPressed; | ||
helper.Events.GameLoop.SaveLoaded += OnSaveLoaded; | ||
helper.Events.Player.InventoryChanged += OnPlayerInventoryChanged; | ||
helper.Events.GameLoop.DayStarted += OnDayStarted; | ||
helper.Events.GameLoop.DayEnding += OnDayEnding; | ||
} | ||
|
||
private void OnModMessageReceived(object? sender, ModMessageReceivedEventArgs e) | ||
{ | ||
if (e.FromModID.Equals(ModManifest.UniqueID)) | ||
{ | ||
if (e.Type.Equals(nameof(MultiplayerHandler.QuestData))) | ||
{ | ||
if (Context.IsMainPlayer) | ||
{ | ||
MultiplayerHandler.SetPlayerQuestData(e.FromPlayerID, e.ReadAs<MultiplayerHandler.QuestData>()); | ||
MultiplayerHandler.SavePerPlayerQuestData(Helper); | ||
} | ||
else | ||
{ | ||
MultiplayerHandler.SetPlayerQuestData(Game1.player.UniqueMultiplayerID, e.ReadAs<MultiplayerHandler.QuestData>()); | ||
QuestDetails.LoadQuestData(Game1.player.UniqueMultiplayerID); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void OnPeerConnected(object? sender, PeerConnectedEventArgs e) | ||
{ | ||
if (!Context.IsMainPlayer) return; | ||
|
||
Helper.Multiplayer.SendMessage(MultiplayerHandler.GetPlayerQuestData(e.Peer.PlayerID), nameof(MultiplayerHandler.QuestData), new[] { ModManifest.UniqueID }, new[] { e.Peer.PlayerID }); | ||
} | ||
|
||
private void OnReturnedToTitle(object? sender, ReturnedToTitleEventArgs e) | ||
{ | ||
IS_DATA_LOADED = false; | ||
} | ||
|
||
private void OnGameLaunched(object? sender, GameLaunchedEventArgs e) | ||
{ | ||
DeluxeAutoPetterDrawPatcher.Initialize(Monitor); | ||
Harmony harmony = new(ModManifest.UniqueID); | ||
DeluxeAutoPetterDrawPatcher.ApplyPatch(harmony); | ||
} | ||
|
||
private void OnUpdateTicked(object? sender, UpdateTickedEventArgs e) | ||
{ | ||
if (!Context.IsWorldReady) return; | ||
|
||
if (Game1.player.hasQuest(QuestDetails.GetQuestID())) | ||
{ | ||
QuestDetails.ShowDropboxLocator(true); | ||
if (Game1.activeClickableMenu is null && QuestDetails.IsMouseOverDropbox(Game1.currentCursorTile)) Game1.mouseCursor = Game1.cursor_grab; | ||
} | ||
} | ||
|
||
private void OnButtonPressed(object? sender, ButtonPressedEventArgs e) | ||
{ | ||
if (!(Context.IsWorldReady && | ||
Game1.currentLocation.Equals(Game1.getLocationFromName(QuestDetails.GetDropBoxGameLocationString())) && | ||
Game1.player.hasQuest(QuestDetails.GetQuestID()) && | ||
e.Button.IsActionButton())) | ||
return; | ||
|
||
Vector2 distanceVector = QuestDetails.GetInteractionDistanceFromDropboxVector(Game1.player.GetToolLocation()); | ||
|
||
if (Math.Abs(distanceVector.X) < (Game1.tileSize * 1.5) && Math.Abs(distanceVector.Y) < Game1.tileSize / 2) | ||
Game1.activeClickableMenu ??= QuestDetails.CreateQuestContainerMenu(); | ||
} | ||
|
||
private void OnSaveLoaded(object? sender, SaveLoadedEventArgs e) | ||
{ | ||
QuestDetails.Initialize(ModManifest.UniqueID); | ||
QuestMail.Initialize(ModManifest.UniqueID); | ||
ObjectDetails.Initialize(ModManifest.UniqueID, Helper.DirectoryPath); | ||
ShopDetails.Initialize(); | ||
MultiplayerHandler.Initialize(ModManifest.UniqueID); | ||
|
||
QuestDetails.LoadQuest(); | ||
QuestMail.LoadMail(QuestMail.GetQuestMailID(), QuestMail.GetQuestMailDetails()); | ||
QuestMail.LoadMail(QuestMail.GetQuestRewardMailID(), QuestMail.GetQuestRewardMailDetails()); | ||
ObjectDetails.LoadObject(); | ||
ShopDetails.LoadShopItem(); | ||
|
||
if (Context.IsMainPlayer) | ||
{ | ||
MultiplayerHandler.LoadPerPlayerQuestData(Helper, Game1.player.UniqueMultiplayerID); | ||
QuestDetails.LoadQuestData(Game1.player.UniqueMultiplayerID); | ||
IS_DATA_LOADED = true; | ||
} | ||
else Monitor.Log("You are not the host. If the host does not have this mod, then all data for this mod will be ignored.", LogLevel.Info); | ||
} | ||
|
||
private void OnPlayerInventoryChanged(object? sender, InventoryChangedEventArgs e) | ||
{ | ||
if (QuestDetails.IsQuestDataNull() && !Context.IsMainPlayer) return; | ||
|
||
if (!QuestDetails.GetIsTriggered() && e.Added.Any(item => item.QualifiedItemId.Equals(QuestDetails.GetAutoPetterID()))) | ||
{ | ||
e.Player.mailForTomorrow.Add(QuestMail.GetQuestMailID()); | ||
QuestDetails.SetIsTriggered(true); | ||
} | ||
} | ||
|
||
private void OnDayStarted(object? sender, DayStartedEventArgs e) | ||
{ | ||
if (!Context.IsMainPlayer) return; | ||
|
||
foreach (StardewValley.Buildings.Building building in Game1.getFarm().buildings) | ||
{ | ||
if (building.GetIndoors()?.Objects.Values.FirstOrDefault(sObject => sObject?.QualifiedItemId.Equals($"(BC){ObjectDetails.GetDeluxeAutoPetterID()}") ?? false, null) is not null) | ||
{ | ||
foreach (FarmAnimal animal in building.GetIndoors().Animals.Values) | ||
{ | ||
animal.pet(Game1.getFarmer(animal.ownerID.Value), true); | ||
animal.pet(Game1.getFarmer(animal.ownerID.Value)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void OnDayEnding(object? sender, DayEndingEventArgs e) | ||
{ | ||
if (!IS_DATA_LOADED && Context.IsMainPlayer) return; | ||
else if (Context.IsMainPlayer) MultiplayerHandler.SavePerPlayerQuestData(Helper); | ||
else Helper.Multiplayer.SendMessage(MultiplayerHandler.GetPlayerQuestData(Game1.player.UniqueMultiplayerID), nameof(MultiplayerHandler.QuestData), new[] { ModManifest.UniqueID }); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<EnableHarmony>true</EnableHarmony> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.1.1" /> | ||
<PackageReference Include="Pathoschild.Stardew.ModTranslationClassBuilder" Version="2.0.1" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Folder Include="assets\TileSheets\" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.9.34728.123 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeluxeAutoPetter", "DeluxeAutoPetter.csproj", "{B84F31E5-4B70-4A26-99DC-3DBE25913667}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{B84F31E5-4B70-4A26-99DC-3DBE25913667}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{B84F31E5-4B70-4A26-99DC-3DBE25913667}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{B84F31E5-4B70-4A26-99DC-3DBE25913667}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{B84F31E5-4B70-4A26-99DC-3DBE25913667}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {EA18B832-0783-4A98-8994-1E43C1DDC272} | ||
EndGlobalSection | ||
EndGlobal |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using HarmonyLib; | ||
using Microsoft.Xna.Framework; | ||
using Microsoft.Xna.Framework.Graphics; | ||
using StardewModdingAPI; | ||
using StardewValley; | ||
using StardewValley.ItemTypeDefinitions; | ||
|
||
namespace DeluxeAutoPetter.helpers | ||
{ | ||
internal class DeluxeAutoPetterDrawPatcher | ||
{ | ||
private static IMonitor? MONITOR; | ||
|
||
internal static void Initialize(IMonitor monitor) | ||
{ | ||
MONITOR = monitor; | ||
} | ||
|
||
internal static void ApplyPatch(Harmony harmony) | ||
{ | ||
harmony.Patch( | ||
AccessTools.Method(typeof(StardewValley.Object), nameof(StardewValley.Object.draw), new Type[] { typeof(SpriteBatch), typeof(int), typeof(int), typeof(float) }), | ||
new HarmonyMethod(typeof(DeluxeAutoPetterDrawPatcher), nameof(Draw_Prefix))); | ||
} | ||
|
||
internal static bool Draw_Prefix(StardewValley.Object __instance, SpriteBatch spriteBatch, int x, int y, float alpha) | ||
{ | ||
try | ||
{ | ||
// all of this code is taken from the source code for drawing an auto-petter. | ||
// the only difference is the addition of drawing a second set of rotating hands. | ||
|
||
if (__instance.isTemporarilyInvisible) | ||
{ | ||
return true; | ||
} | ||
|
||
if (__instance.QualifiedItemId.Equals($"(BC){ObjectDetails.GetDeluxeAutoPetterID()}")) | ||
{ | ||
ParsedItemData dataOrErrorItem = ItemRegistry.GetDataOrErrorItem(__instance.QualifiedItemId); | ||
Texture2D texture = dataOrErrorItem.GetTexture(); | ||
Vector2 vector = __instance.getScale(); | ||
vector *= 4f; | ||
Vector2 vector2 = Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64, y * 64 - 64)); | ||
Rectangle destinationRectangle = new((int)(vector2.X - vector.X / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(vector2.Y - vector.Y / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(64f + vector.X), (int)(128f + vector.Y / 2f)); | ||
float num = Math.Max(0f, (float)((y + 1) * 64 - 24) / 10000f) + (float)x * 1E-05f; | ||
|
||
spriteBatch.Draw(texture, destinationRectangle, dataOrErrorItem.GetSourceRect(1, __instance.ParentSheetIndex), Color.White * alpha, 0f, Vector2.Zero, SpriteEffects.None, num); | ||
spriteBatch.Draw(texture, vector2 + new Vector2(8.5f, 12f) * 4f, dataOrErrorItem.GetSourceRect(2, __instance.ParentSheetIndex), Color.White * alpha, (float)Game1.currentGameTime.TotalGameTime.TotalSeconds * -1.5f, new Vector2(7.5f, 15.5f), 4f, SpriteEffects.None, num + 1E-05f); | ||
// this is the second set of rotating hands | ||
spriteBatch.Draw(texture, vector2 + new Vector2(8.5f, 12f) * 4f, dataOrErrorItem.GetSourceRect(2, __instance.ParentSheetIndex), Color.White * alpha, (float)Game1.currentGameTime.TotalGameTime.TotalSeconds * -1.5f - 1.5f, new Vector2(7.5f, 15.5f), 4f, SpriteEffects.None, num + 1E-05f); | ||
|
||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
catch (Exception ex) | ||
{ | ||
MONITOR?.Log($"Failed in {nameof(Draw_Prefix)}:\n{ex.Message}", LogLevel.Error); | ||
return true; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using StardewModdingAPI; | ||
|
||
namespace DeluxeAutoPetter.helpers | ||
{ | ||
internal static class MultiplayerHandler | ||
{ | ||
public class QuestData | ||
{ | ||
public bool IsTriggered { get; set; } = false; | ||
public Dictionary<string, int> DonationCounts { get; set; } = new() { | ||
{ QuestDetails.GetAutoPetterID(), 0 }, | ||
{ QuestDetails.GetHardwoodID(), 0 }, | ||
{ QuestDetails.GetIridiumBarID(), 0 } | ||
}; | ||
} | ||
|
||
private static string? PER_PLAYER_QUEST_DATA_KEY; | ||
private static Dictionary<long, QuestData>? PER_PLAYER_QUEST_DATA; | ||
|
||
public static void Initialize(string modID) | ||
{ | ||
PER_PLAYER_QUEST_DATA_KEY = $"{modID}.Quest.PER_PLAYER_QUEST_DATA_KEY"; | ||
} | ||
|
||
public static void LoadPerPlayerQuestData(IModHelper helper, long hostID) | ||
{ | ||
if (PER_PLAYER_QUEST_DATA_KEY is null) throw new ArgumentNullException($"{nameof(PER_PLAYER_QUEST_DATA_KEY)} has not been initialized! The {nameof(Initialize)} method must be called first!"); | ||
|
||
PER_PLAYER_QUEST_DATA = helper.Data.ReadSaveData<Dictionary<long, QuestData>>(PER_PLAYER_QUEST_DATA_KEY); | ||
PER_PLAYER_QUEST_DATA ??= new() { { hostID, new() } }; | ||
} | ||
|
||
public static void SavePerPlayerQuestData(IModHelper helper) | ||
{ | ||
if (PER_PLAYER_QUEST_DATA_KEY is null) throw new ArgumentNullException($"{nameof(PER_PLAYER_QUEST_DATA_KEY)} has not been initialized! The {nameof(Initialize)} method must be called first!"); | ||
if (PER_PLAYER_QUEST_DATA is null) throw new ArgumentNullException($"{nameof(PER_PLAYER_QUEST_DATA)} has not been initialized! The {nameof(LoadPerPlayerQuestData)} method must be called first!"); | ||
|
||
helper.Data.WriteSaveData(PER_PLAYER_QUEST_DATA_KEY, PER_PLAYER_QUEST_DATA); | ||
} | ||
|
||
public static QuestData GetPlayerQuestData(long playerID) | ||
{ | ||
if (PER_PLAYER_QUEST_DATA is null) throw new ArgumentNullException($"{nameof(PER_PLAYER_QUEST_DATA)} has not been initialized! The {nameof(LoadPerPlayerQuestData)} method must be called first!"); | ||
if (!PER_PLAYER_QUEST_DATA.ContainsKey(playerID) && !Context.IsMainPlayer) throw new ArgumentNullException($"Your {nameof(PER_PLAYER_QUEST_DATA)} does not have any quest data for your player ID!"); | ||
|
||
if (!PER_PLAYER_QUEST_DATA.ContainsKey(playerID) && Context.IsMainPlayer) CreatePlayerQuestData(playerID); | ||
|
||
return PER_PLAYER_QUEST_DATA[playerID]; | ||
} | ||
|
||
public static void SetPlayerQuestData(long playerID, QuestData questData) | ||
{ | ||
if (PER_PLAYER_QUEST_DATA is null && Context.IsMainPlayer) throw new ArgumentNullException($"{nameof(PER_PLAYER_QUEST_DATA)} has not been initialized! The {nameof(LoadPerPlayerQuestData)} method must be called first!"); | ||
else if (PER_PLAYER_QUEST_DATA is null) PER_PLAYER_QUEST_DATA = new() { { playerID, questData } }; | ||
|
||
if (!PER_PLAYER_QUEST_DATA.ContainsKey(playerID)) throw new ArgumentNullException($"{nameof(PER_PLAYER_QUEST_DATA)} has no data associated with the playerID '{playerID}'."); | ||
|
||
PER_PLAYER_QUEST_DATA[playerID] = questData; | ||
} | ||
|
||
private static void CreatePlayerQuestData(long playerID) | ||
{ | ||
if (PER_PLAYER_QUEST_DATA is null) throw new ArgumentNullException($"{nameof(PER_PLAYER_QUEST_DATA)} has not been initialized! The {nameof(LoadPerPlayerQuestData)} method must be called first!"); | ||
|
||
PER_PLAYER_QUEST_DATA.Add(playerID, new()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using StardewValley; | ||
using StardewValley.GameData.BigCraftables; | ||
|
||
namespace DeluxeAutoPetter.helpers | ||
{ | ||
internal static class ObjectDetails | ||
{ | ||
/** ********************** | ||
* Class Variables | ||
********************** **/ | ||
private static string? DELUXE_AUTO_PETTER_ID; | ||
private static BigCraftableData? DELUXE_AUTO_PETTER_DETAILS; | ||
|
||
/** ********************** | ||
* Variable Getters | ||
********************** **/ | ||
public static string GetDeluxeAutoPetterID() | ||
{ | ||
if (DELUXE_AUTO_PETTER_ID is null) throw new ArgumentNullException($"{nameof(DELUXE_AUTO_PETTER_ID)} has not been initialized! The {nameof(Initialize)} method must be called first!"); | ||
|
||
return DELUXE_AUTO_PETTER_ID; | ||
} | ||
|
||
|
||
/** ********************** | ||
* Public Methods | ||
********************** **/ | ||
public static void Initialize(string modID, string modDirectoryPath) | ||
{ | ||
DELUXE_AUTO_PETTER_ID = $"{modID}.DeluxeAutoPetterObject"; | ||
DELUXE_AUTO_PETTER_DETAILS = new() | ||
{ | ||
Name = "Deluxe Auto-Petter", | ||
DisplayName = I18n.DeluxeAutoPetterDisplayName(), | ||
Description = I18n.DeluxeAutoPetterDescription(), | ||
Texture = Path.Combine(modDirectoryPath, "assets", "TileSheets", "DeluxeAutoPetter.xnb") | ||
}; | ||
} | ||
|
||
public static void LoadObject() | ||
{ | ||
if (DELUXE_AUTO_PETTER_DETAILS is null) throw new ArgumentNullException($"{nameof(DELUXE_AUTO_PETTER_DETAILS)} has not been initialized! The {nameof(Initialize)} method must be called first!"); | ||
|
||
DataLoader.BigCraftables(Game1.content)[GetDeluxeAutoPetterID()] = DELUXE_AUTO_PETTER_DETAILS; | ||
} | ||
} | ||
} |
Oops, something went wrong.