XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

公开
关注 0 Fork 0 Star 0
UTF-8
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;
    }
}