using Terraria; using Terraria.ID; using Terraria.ModLoader; namespace SoulHarvest.Common; internal class BossSoulParticipationSystem : ModSystem { private static readonly bool[] TwinParticipants = new bool[Main.maxPlayers]; private static readonly bool[] EaterParticipants = new bool[Main.maxPlayers]; private static readonly bool[] BrainParticipants = new bool[Main.maxPlayers]; private static readonly bool[] GolemParticipants = new bool[Main.maxPlayers]; private static readonly bool[] MoonLordParticipants = new bool[Main.maxPlayers]; private static int twinEncounterLifeMax; private static int eaterEncounterLifeMax; private static int brainEncounterLifeMax; private static int golemEncounterLifeMax; private static int moonLordEncounterLifeMax; public override void OnWorldUnload() { Clear(TwinParticipants); Clear(EaterParticipants); Clear(BrainParticipants); Clear(GolemParticipants); Clear(MoonLordParticipants); twinEncounterLifeMax = 0; eaterEncounterLifeMax = 0; brainEncounterLifeMax = 0; golemEncounterLifeMax = 0; moonLordEncounterLifeMax = 0; } public override void PostUpdateWorld() { int twinLife = SumActiveLifeMax(NPCID.Retinazer, NPCID.Spazmatism); if (twinLife > 0) twinEncounterLifeMax = System.Math.Max(twinEncounterLifeMax, twinLife); else { Clear(TwinParticipants); twinEncounterLifeMax = 0; } int eaterLife = SumActiveLifeMax(NPCID.EaterofWorldsBody, NPCID.EaterofWorldsHead, NPCID.EaterofWorldsTail); if (eaterLife > 0) eaterEncounterLifeMax = System.Math.Max(eaterEncounterLifeMax, eaterLife); else { Clear(EaterParticipants); eaterEncounterLifeMax = 0; } if (!TrackEncounterLife(ref brainEncounterLifeMax, NPCID.BrainofCthulhu, NPCID.Creeper)) Clear(BrainParticipants); if (!TrackEncounterLife(ref golemEncounterLifeMax, NPCID.Golem, NPCID.GolemHead, NPCID.GolemHeadFree)) Clear(GolemParticipants); if (!TrackEncounterLife(ref moonLordEncounterLifeMax, NPCID.MoonLordCore, NPCID.MoonLordHead, NPCID.MoonLordHand)) Clear(MoonLordParticipants); } internal static void RecordCompositeBossHit(NPC npc, int playerIndex) { if (playerIndex < 0 || playerIndex >= Main.maxPlayers) return; if (npc.type is NPCID.Retinazer or NPCID.Spazmatism) TwinParticipants[playerIndex] = true; else if (npc.type is NPCID.EaterofWorldsBody or NPCID.EaterofWorldsHead or NPCID.EaterofWorldsTail) EaterParticipants[playerIndex] = true; else if (npc.type is NPCID.BrainofCthulhu or NPCID.Creeper) BrainParticipants[playerIndex] = true; else if (npc.type is NPCID.Golem or NPCID.GolemHead or NPCID.GolemHeadFree) GolemParticipants[playerIndex] = true; else if (npc.type is NPCID.MoonLordCore or NPCID.MoonLordHead or NPCID.MoonLordHand) MoonLordParticipants[playerIndex] = true; } internal static bool TryTakeCompositeParticipants(NPC npc, out bool[] participants, out int encounterLifeMax) { participants = []; encounterLifeMax = 0; switch (npc.type) { case NPCID.Retinazer: if (NPC.AnyNPCs(NPCID.Spazmatism)) return false; participants = Take(TwinParticipants); encounterLifeMax = System.Math.Max(npc.lifeMax, twinEncounterLifeMax); twinEncounterLifeMax = 0; return true; case NPCID.Spazmatism: if (NPC.AnyNPCs(NPCID.Retinazer)) return false; participants = Take(TwinParticipants); encounterLifeMax = System.Math.Max(npc.lifeMax, twinEncounterLifeMax); twinEncounterLifeMax = 0; return true; case NPCID.EaterofWorldsBody: case NPCID.EaterofWorldsHead: case NPCID.EaterofWorldsTail: if (NPC.AnyNPCs(NPCID.EaterofWorldsBody) || NPC.AnyNPCs(NPCID.EaterofWorldsHead) || NPC.AnyNPCs(NPCID.EaterofWorldsTail)) return false; participants = Take(EaterParticipants); encounterLifeMax = System.Math.Max(npc.lifeMax, eaterEncounterLifeMax); eaterEncounterLifeMax = 0; return true; case NPCID.BrainofCthulhu: participants = Take(BrainParticipants); encounterLifeMax = System.Math.Max(npc.lifeMax, brainEncounterLifeMax); brainEncounterLifeMax = 0; return true; case NPCID.Golem: participants = Take(GolemParticipants); encounterLifeMax = System.Math.Max(npc.lifeMax, golemEncounterLifeMax); golemEncounterLifeMax = 0; return true; case NPCID.MoonLordCore: participants = Take(MoonLordParticipants); encounterLifeMax = System.Math.Max(npc.lifeMax, moonLordEncounterLifeMax); moonLordEncounterLifeMax = 0; return true; default: return false; } } internal static int GetEncounterLifeMax(NPC npc) { int trackedLife = npc.type switch { NPCID.BrainofCthulhu => brainEncounterLifeMax, NPCID.Golem => golemEncounterLifeMax, NPCID.MoonLordCore => moonLordEncounterLifeMax, _ => 0 }; return System.Math.Max(npc.lifeMax, trackedLife); } private static bool TrackEncounterLife(ref int storedLifeMax, params int[] npcTypes) { int currentLifeMax = SumActiveLifeMax(npcTypes); if (currentLifeMax > 0) { storedLifeMax = System.Math.Max(storedLifeMax, currentLifeMax); return true; } else { storedLifeMax = 0; return false; } } private static int SumActiveLifeMax(params int[] npcTypes) { int total = 0; foreach (NPC npc in Main.ActiveNPCs) { for (int index = 0; index < npcTypes.Length; index++) { if (npc.type != npcTypes[index]) continue; total = (int)System.Math.Min(int.MaxValue, (long)total + npc.lifeMax); break; } } return total; } private static bool[] Take(bool[] source) { bool[] result = (bool[])source.Clone(); Clear(source); return result; } private static void Clear(bool[] values) { for (int index = 0; index < values.Length; index++) values[index] = false; } }