-
Notifications
You must be signed in to change notification settings - Fork 23
/
WorldAssist.cs
389 lines (338 loc) · 12.4 KB
/
WorldAssist.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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Terraria;
using Terraria.Chat;
using Terraria.GameContent.Events;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.ModLoader.IO;
namespace BossChecklist
{
public class WorldAssist : ModSystem
{
// Since only 1 set of records is saved per boss, there is no need to put it into a dictionary
// A separate list of World Records is needed to hold information about unloaded entries
public static WorldRecord[] worldRecords;
public static List<WorldRecord> unloadedWorldRecords;
// Bosses will be set to true when they spawn and will only be set back to false when the boss despawns or dies
public static bool[] Tracker_ActiveEntry;
// Players that are in the server when a boss fight starts
// Prevents players that join a server mid bossfight from messing up records
public static bool[,] Tracker_StartingPlayers;
public static bool[] CheckedRecordIndexes;
public static HashSet<string> HiddenEntries = new HashSet<string>();
public static HashSet<string> MarkedEntries = new HashSet<string>();
public static bool downedBloodMoon;
public static bool downedFrostMoon;
public static bool downedPumpkinMoon;
public static bool downedSolarEclipse;
public static bool downedDarkMage;
public static bool downedOgre;
public static bool downedFlyingDutchman;
public static bool downedMartianSaucer;
public static bool downedInvasionT2Ours;
public static bool downedInvasionT3Ours;
public static bool downedTorchGod;
bool Tracker_BloodMoon = false;
bool Tracker_PumpkinMoon = false;
bool Tracker_FrostMoon = false;
bool Tracker_SolarEclipse = false;
public override void Load() {
On.Terraria.GameContent.Events.DD2Event.WinInvasionInternal += DD2Event_WinInvasionInternal;
}
private void DD2Event_WinInvasionInternal(On.Terraria.GameContent.Events.DD2Event.orig_WinInvasionInternal orig) {
orig();
if (DD2Event.OngoingDifficulty == 2)
downedInvasionT2Ours = true;
if (DD2Event.OngoingDifficulty == 3)
downedInvasionT3Ours = true;
}
private void ClearDownedBools() {
// Events
downedBloodMoon = false;
downedFrostMoon = false;
downedPumpkinMoon = false;
downedSolarEclipse = false;
// Event trackers
Tracker_BloodMoon = false;
Tracker_FrostMoon = false;
Tracker_PumpkinMoon = false;
Tracker_SolarEclipse = false;
// MiniBosses
downedDarkMage = false;
downedOgre = false;
downedFlyingDutchman = false;
downedMartianSaucer = false;
// Vanilla additions
downedInvasionT2Ours = false;
downedInvasionT3Ours = false;
downedTorchGod = false;
}
public override void OnWorldLoad() {
HiddenEntries.Clear();
MarkedEntries.Clear();
ClearDownedBools();
// Record related lists that should be the same count of record tracking entries
worldRecords = new WorldRecord[BossChecklist.bossTracker.BossRecordKeys.Count];
unloadedWorldRecords = new List<WorldRecord>();
CheckedRecordIndexes = new bool[BossChecklist.bossTracker.BossRecordKeys.Count];
Tracker_ActiveEntry = new bool[BossChecklist.bossTracker.BossRecordKeys.Count];
Tracker_StartingPlayers = new bool[BossChecklist.bossTracker.BossRecordKeys.Count, Main.maxPlayers];
// Populate world records list
foreach (string key in BossChecklist.bossTracker.BossRecordKeys) {
worldRecords[BossChecklist.bossTracker.SortedEntries[BossChecklist.bossTracker.SortedEntries.FindIndex(x => x.Key == key)].GetRecordIndex] = new WorldRecord(key);
}
}
public override void OnWorldUnload() {
ClearDownedBools(); // Reset downs and trackers to prevent "defeation" of an entry
}
public override void PreWorldGen() {
ClearDownedBools(); // Reset downs and trackers back to false if creating a new world
}
public override void SaveWorldData(TagCompound tag) {
var HiddenBossesList = new List<string>(HiddenEntries);
var MarkedAsDownedList = new List<string>(MarkedEntries);
var downed = new List<string>();
if (downedBloodMoon)
downed.Add("bloodmoon");
if (downedFrostMoon)
downed.Add("frostmoon");
if (downedPumpkinMoon)
downed.Add("pumpkinmoon");
if (downedSolarEclipse)
downed.Add("solareclipse");
if (downedDarkMage)
downed.Add("darkmage");
if (downedOgre)
downed.Add("ogre");
if (downedFlyingDutchman)
downed.Add("flyingdutchman");
if (downedMartianSaucer)
downed.Add("martiansaucer");
if (downedInvasionT2Ours)
downed.Add("invasionT2Ours");
if (downedInvasionT3Ours)
downed.Add("invasionT3Ours");
if (downedTorchGod)
downed.Add("torchgod");
tag["downed"] = downed;
tag["HiddenBossesList"] = HiddenBossesList;
tag["downed_Forced"] = MarkedAsDownedList;
if (worldRecords != null) {
tag["WorldRecords"] = worldRecords.Concat(unloadedWorldRecords).ToList(); // Combine loaded and unloaded data to prevent lost world record data
}
}
public override void LoadWorldData(TagCompound tag) {
unloadedWorldRecords.Clear();
List<WorldRecord> SavedWorldRecords = tag.Get<List<WorldRecord>>("WorldRecords").ToList();
foreach (WorldRecord record in SavedWorldRecords) {
int sortedIndex = BossChecklist.bossTracker.SortedEntries.FindIndex(x => x.Key == record.bossKey);
if (sortedIndex == -1) {
unloadedWorldRecords.Add(record); // Add any unloaded entries to this list
continue; // Entry is not loaded
}
else if (BossChecklist.bossTracker.SortedEntries[sortedIndex].type != EntryType.Boss)
continue; // Loaded entry is not a boss
// Set record data to list based on record index
// Data here can't be null as the key is checked beforehand
worldRecords[BossChecklist.bossTracker.SortedEntries[sortedIndex].GetRecordIndex] = record;
}
var HiddenBossesList = tag.GetList<string>("HiddenBossesList");
foreach (var bossKey in HiddenBossesList) {
HiddenEntries.Add(bossKey);
}
var MarkedAsDownedList = tag.GetList<string>("downed_Forced");
foreach (var bossKey in MarkedAsDownedList) {
MarkedEntries.Add(bossKey);
}
var downed = tag.GetList<string>("downed");
downedBloodMoon = downed.Contains("bloodmoon");
downedFrostMoon = downed.Contains("frostmoon");
downedPumpkinMoon = downed.Contains("pumpkinmoon");
downedSolarEclipse = downed.Contains("solareclipse");
downedDarkMage = downed.Contains("darkmage");
downedOgre = downed.Contains("ogre");
downedFlyingDutchman = downed.Contains("flyingdutchman");
downedMartianSaucer = downed.Contains("martiansaucer");
downedInvasionT2Ours = downed.Contains("invasionT2Ours");
downedInvasionT3Ours = downed.Contains("invasionT3Ours");
downedTorchGod = downed.Contains("torchgod");
}
public override void NetSend(BinaryWriter writer) {
// BitBytes can have up to 8 values.
// BitsByte flags2 = reader.ReadByte();
BitsByte flags = new BitsByte {
[0] = downedBloodMoon,
[1] = downedFrostMoon,
[2] = downedPumpkinMoon,
[3] = downedSolarEclipse,
[4] = downedDarkMage,
[5] = downedOgre,
[6] = downedFlyingDutchman,
[7] = downedMartianSaucer
};
writer.Write(flags);
// Vanilla doesn't sync these values, so we will.
flags = new BitsByte {
[0] = NPC.downedTowerSolar,
[1] = NPC.downedTowerVortex,
[2] = NPC.downedTowerNebula,
[3] = NPC.downedTowerStardust,
[4] = downedInvasionT2Ours,
[5] = downedInvasionT3Ours,
[6] = downedTorchGod
};
writer.Write(flags);
writer.Write(HiddenEntries.Count);
foreach (var bossKey in HiddenEntries) {
writer.Write(bossKey);
}
writer.Write(MarkedEntries.Count);
foreach (var bossKey in MarkedEntries) {
writer.Write(bossKey);
}
}
public override void NetReceive(BinaryReader reader) {
BitsByte flags = reader.ReadByte();
downedBloodMoon = flags[0];
downedFrostMoon = flags[1];
downedPumpkinMoon = flags[2];
downedSolarEclipse = flags[3];
downedDarkMage = flags[4];
downedOgre = flags[5];
downedFlyingDutchman = flags[6];
downedMartianSaucer = flags[7];
flags = reader.ReadByte();
NPC.downedTowerSolar = flags[0];
NPC.downedTowerVortex = flags[1];
NPC.downedTowerNebula = flags[2];
NPC.downedTowerStardust = flags[3];
downedInvasionT2Ours = flags[4];
downedInvasionT3Ours = flags[5];
downedTorchGod = flags[6];
HiddenEntries.Clear();
int count = reader.ReadInt32();
for (int i = 0; i < count; i++) {
HiddenEntries.Add(reader.ReadString());
}
MarkedEntries.Clear();
count = reader.ReadInt32();
for (int i = 0; i < count; i++) {
MarkedEntries.Add(reader.ReadString());
}
// Update checklist to match Hidden and Marked Downed entries
BossUISystem.Instance.bossChecklistUI.UpdateCheckboxes();
if (BossChecklist.BossLogConfig.HideUnavailable && BossUISystem.Instance.BossLog.PageNum == -1) {
BossUISystem.Instance.BossLog.RefreshPageContent();
}
}
public override void PreUpdateWorld() {
HandleMoonDowns();
if (BossChecklist.DebugConfig.DISABLERECORDTRACKINGCODE)
return;
foreach (NPC npc in Main.npc) {
EntryInfo entry = NPCAssist.GetEntryInfo(npc.type);
if (entry == null)
continue;
int recordIndex = entry.GetRecordIndex;
if (recordIndex == -1 || CheckedRecordIndexes[recordIndex])
continue; // If the NPC's record index is invalid OR was already handled, move on to the next NPC
CheckedRecordIndexes[recordIndex] = true; // record index will be handled, so no need to check it again
// If marked as active...
if (Tracker_ActiveEntry[recordIndex]) {
// ...remove any players that become inactive during the fight
foreach (Player player in Main.player) {
if (!player.active)
Tracker_StartingPlayers[recordIndex, player.whoAmI] = false;
}
// ...check if the npc is actually still active or not and display a despawn message if they are no longer active (but not killed!)
if (NPCAssist.FullyInactive(npc, entry.GetIndex)) {
Tracker_ActiveEntry[recordIndex] = false; // No longer an active boss (only other time this is set to false is NPC.OnKill)
string message = NPCAssist.GetDespawnMessage(npc, entry.GetIndex);
if (!string.IsNullOrEmpty(message)) {
if (Main.netMode == NetmodeID.SinglePlayer) {
Main.NewText(Language.GetTextValue(message, npc.FullName), Colors.RarityPurple);
}
else {
ChatHelper.BroadcastChatMessage(NetworkText.FromKey(message, npc.FullName), Colors.RarityPurple);
}
}
}
}
}
for (int i = 0; i < CheckedRecordIndexes.Length; i++) {
CheckedRecordIndexes[i] = false; // reset all handled record indexes to false after iterating through all NPCs
}
}
public void AnnounceEventEnd(string eventType) {
// TODO: Custom/Generic announcements
NetworkText message = NetworkText.FromKey($"{NPCAssist.LangChat}.EventEnd.{eventType}");
if (Main.netMode == NetmodeID.SinglePlayer) {
Main.NewText(message.ToString(), Colors.RarityGreen);
}
else {
ChatHelper.BroadcastChatMessage(message, Colors.RarityGreen);
}
}
public void HandleMoonDowns() {
// Blood Moon
if (Main.bloodMoon) {
Tracker_BloodMoon = true;
}
else if (Tracker_BloodMoon) {
Tracker_BloodMoon = false;
AnnounceEventEnd("BloodMoon"); // Sends a message to all players that the moon event has ended
if (!downedBloodMoon) {
downedBloodMoon = true;
if (Main.netMode == NetmodeID.Server) {
NetMessage.SendData(MessageID.WorldData);
}
}
}
// Frost Moon
if (Main.snowMoon) {
Tracker_FrostMoon = true;
}
else if (Tracker_FrostMoon) {
Tracker_FrostMoon = false;
AnnounceEventEnd("FrostMoon");
if (!downedFrostMoon) {
downedFrostMoon = true;
if (Main.netMode == NetmodeID.Server) {
NetMessage.SendData(MessageID.WorldData);
}
}
}
// Pumpkin Moon
if (Main.pumpkinMoon) {
Tracker_PumpkinMoon = true;
}
else if (Tracker_PumpkinMoon) {
Tracker_PumpkinMoon = false;
AnnounceEventEnd("PumpkinMoon");
if (!downedPumpkinMoon) {
downedPumpkinMoon = true;
if (Main.netMode == NetmodeID.Server) {
NetMessage.SendData(MessageID.WorldData);
}
}
}
// Solar Eclipse
if (Main.eclipse) {
Tracker_SolarEclipse = true;
}
else if (Tracker_SolarEclipse) {
Tracker_SolarEclipse = false;
AnnounceEventEnd("SolarEclipse");
if (!downedSolarEclipse) {
downedSolarEclipse = true;
if (Main.netMode == NetmodeID.Server) {
NetMessage.SendData(MessageID.WorldData);
}
}
}
}
}
}