-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathModEntry.cs
175 lines (153 loc) · 6.15 KB
/
ModEntry.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
using HarmonyLib;
using Microsoft.Xna.Framework;
using Shockah.CommonModCode.GMCM;
using Shockah.Kokoro;
using Shockah.Kokoro.GMCM;
using Shockah.Kokoro.Stardew;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewModdingAPI.Utilities;
using StardewValley;
using StardewValley.Objects;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Shockah.JunimoWarp;
public class ModEntry : BaseMod<ModConfig>
{
internal static ModEntry Instance { get; private set; } = null!;
private readonly PerScreen<Dictionary<Guid, Action<GameLocation, IntPoint>>> AwaitingNextWarpResponse = new(() => []);
public override void MigrateConfig(ISemanticVersion? configVersion, ISemanticVersion modVersion)
{
// do nothing, for now
}
public override void OnEntry(IModHelper helper)
{
Instance = this;
helper.Events.GameLoop.GameLaunched += OnGameLaunched;
RegisterModMessageHandler<NetMessage.NextWarpRequest>(OnNextWarpRequestMessageReceived);
RegisterModMessageHandler<NetMessage.NextWarpResponse>(OnNextWarpResponseMessageReceived);
var harmony = new Harmony(ModManifest.UniqueID);
ItemGrabMenuPatches.Apply(harmony);
}
private void SetupConfig()
{
var api = Helper.ModRegistry.GetApi<IGenericModConfigMenuApi>("spacechase0.GenericModConfigMenu");
if (api is null)
return;
GMCMI18nHelper helper = new(api, ModManifest, Helper.Translation);
api.Register(
ModManifest,
reset: () => Config = new(),
save: () =>
{
WriteConfig();
LogConfig();
}
);
helper.AddBoolOption("config.requiredEmptyChest", () => Config.RequiredEmptyChest);
}
private void OnGameLaunched(object? sender, GameLaunchedEventArgs e)
{
SetupConfig();
}
private void OnNextWarpRequestMessageReceived(Farmer sender, NetMessage.NextWarpRequest message)
{
if (GameExt.GetMultiplayerMode() == MultiplayerMode.Client)
{
Monitor.Log($"Received message of type {message.GetType()}, but did not expect one - ignoring it.", LogLevel.Warn);
return;
}
var (warpLocation, warpPoint) = GetNextWarp(Game1.getLocationFromName(message.LocationName), message.Point);
SendModMessage(new NetMessage.NextWarpResponse(message.ID, warpLocation.NameOrUniqueName, warpPoint), sender);
}
private void OnNextWarpResponseMessageReceived(NetMessage.NextWarpResponse message)
{
if (GameExt.GetMultiplayerMode() != MultiplayerMode.Client)
{
Monitor.Log($"Received message of type {message.GetType()}, but did not expect one - ignoring it.", LogLevel.Warn);
return;
}
if (!AwaitingNextWarpResponse.Value.TryGetValue(message.ID, out var callback))
{
Monitor.Log($"Received message of type {message.GetType()}, but did not expect one - ignoring it.", LogLevel.Warn);
return;
}
AwaitingNextWarpResponse.Value.Remove(message.ID);
callback(Game1.getLocationFromName(message.LocationName), message.Point);
}
private static IEnumerable<(GameLocation Location, IntPoint Point)> GetPossibleWarpLocations()
{
foreach (var location in GameExt.GetAllLocations())
if (location.NameOrUniqueName is not null)
foreach (var @object in location.Objects.Values.OrderBy(o => o.TileLocation.Y).ThenBy(o => o.TileLocation.X))
if (@object is Chest chest && chest.SpecialChestType == Chest.SpecialChestTypes.JunimoChest)
yield return (location, new((int)@object.TileLocation.X, (int)@object.TileLocation.Y));
}
private static (GameLocation Location, IntPoint Point) GetNextWarp(GameLocation location, IntPoint point)
{
var allWarps = GetPossibleWarpLocations().ToList();
for (int i = 0; i < allWarps.Count; i++)
if (allWarps[i].Location == location && allWarps[i].Point == point)
{
var warp = allWarps[(i + 1) % allWarps.Count];
foreach (var neighbor in new IntPoint[] { warp.Point + IntPoint.Bottom, warp.Point + IntPoint.Top, warp.Point + IntPoint.Left, warp.Point + IntPoint.Right })
if (warp.Location.isTilePassable(new(neighbor.X, neighbor.Y)))
return (warp.Location, neighbor);
}
return (location, point);
}
internal void RequestNextWarp(GameLocation location, IntPoint point, Action<GameLocation, IntPoint> callback)
{
if (GameExt.GetMultiplayerMode() == MultiplayerMode.Client)
{
var messageID = Guid.NewGuid();
AwaitingNextWarpResponse.Value[messageID] = callback;
SendModMessage(new NetMessage.NextWarpRequest(messageID, location.NameOrUniqueName, point), GameExt.GetHostPlayer());
}
else
{
var (warpLocation, warpPoint) = GetNextWarp(location, point);
callback(warpLocation, warpPoint);
}
}
internal static void AnimatePlayerWarp(GameLocation location, IntPoint point)
{
for (int i = 0; i < 12; i++)
Game1.Multiplayer.broadcastSprites(Game1.player.currentLocation, new TemporaryAnimatedSprite(354, Game1.random.Next(25, 75), 6, 1, new Vector2(Game1.random.Next((int)Game1.player.position.X - 256, (int)Game1.player.position.X + 192), Game1.random.Next((int)Game1.player.position.Y - 256, (int)Game1.player.position.Y + 192)), flicker: false, Game1.random.NextDouble() < 0.5));
Game1.player.currentLocation.playSound("wand");
Game1.displayFarmer = false;
Game1.player.temporarilyInvincible = true;
Game1.player.temporaryInvincibilityTimer = -2000;
Game1.player.Halt();
Game1.player.faceDirection(2);
Game1.player.CanMove = false;
Game1.player.freezePause = 2000;
Game1.flashAlpha = 1f;
DelayedAction.fadeAfterDelay(() =>
{
Game1.warpFarmer(location.NameOrUniqueName, point.X, point.Y, false);
if (!Game1.isStartingToGetDarkOut(location) && !Game1.isRaining)
Game1.playMorningSong();
else
Game1.changeMusicTrack("none");
Game1.fadeToBlackAlpha = 0.99f;
Game1.screenGlow = false;
Game1.player.temporarilyInvincible = false;
Game1.player.temporaryInvincibilityTimer = 0;
Game1.displayFarmer = true;
Game1.player.CanMove = true;
}, 1000);
int j = 0;
for (int xTile = Game1.player.TilePoint.X + 8; xTile >= Game1.player.TilePoint.X - 8; xTile--)
{
Game1.Multiplayer.broadcastSprites(Game1.player.currentLocation, new TemporaryAnimatedSprite(6, new Vector2(xTile, Game1.player.Tile.Y) * 64f, Color.White, 8, flipped: false, 50f)
{
layerDepth = 1f,
delayBeforeAnimationStart = j * 25,
motion = new Vector2(-0.25f, 0f)
});
j++;
}
}
}