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

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

公开
关注 0 Fork 0 Star 0
UTF-8
using SoulHarvest.Common;
using SoulHarvest.Tiles;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Terraria;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.ModLoader.IO;

namespace SoulHarvest.Items;

public class DeathNecklace : ModItem, IDeathAltarUpgradeable
{
    public const int MaxCoreLevel = 10;
    public const int MaxAbsorbAllLevel = 10;
    public const float RadiusGrowthPerLevel = 42f;

    private static readonly DeathAltarUpgradeType[] UpgradeTypes =
    [
        DeathAltarUpgradeType.NecklaceRadius,
        DeathAltarUpgradeType.NecklaceAbsorbAll,
        DeathAltarUpgradeType.NecklaceSovereignty
    ];

    public int RadiusLevel { get; private set; } = 1;
    public int AbsorbAllLevel { get; private set; } = 1;
    public bool SovereigntyUnlocked { get; private set; }

    // Serialized only so existing necklace items can migrate their combat tree
    // into the new character-owned DeathDomainProgression.
    internal int LegacyFrequencyLevel { get; private set; } = 1;
    internal int LegacyDamageLevel { get; private set; } = 1;
    internal int LegacyVolleyLevel { get; private set; } = 1;
    internal int LegacyLifeStealLevel { get; private set; }

    public float DomainRadius => 160f + (RadiusLevel - 1) * RadiusGrowthPerLevel;
    public float DomainAttractionRadius => DomainRadius + 320f + (AbsorbAllLevel - 1) * 32f;
    public float DomainAttractionStrength => 0.035f + (AbsorbAllLevel - 1) * 0.0075f;
    public float DomainAttractionMaximumSpeed => 0.75f + (AbsorbAllLevel - 1) * 0.09f;
    public float DomainRepulsionStrength => 0.055f + (AbsorbAllLevel - 1) * 0.01f;
    public float DomainRepulsionMaximumSpeed => 1.1f + (AbsorbAllLevel - 1) * 0.12f;
    // Reaching the radius cap only maximizes the finite field. Full-screen
    // coverage is a runtime state granted by the final Death Descends node.
    public bool DeathDescentUnlocked => SovereigntyUnlocked && AllCoreStatsMaxed;
    public bool DeathRequiemUnlocked => DeathDescentUnlocked;
    public int MasteryScore => RadiusLevel + AbsorbAllLevel + (SovereigntyUnlocked ? 30 : 0);
    public IReadOnlyList<DeathAltarUpgradeType> AltarUpgradeTypes => UpgradeTypes;

    protected override bool CloneNewInstances => true;

    public override void PreReforge()
    {
        DeathAltarReforgePreservation.Capture(this);
    }

    public override void PostReforge()
    {
        DeathAltarReforgePreservation.Restore(this);
    }

    public override void SetDefaults()
    {
        Item.width = 30;
        Item.height = 38;
        Item.accessory = true;
        Item.value = Item.sellPrice(gold: 8);
        Item.rare = ItemRarityID.LightRed;
    }

    public override void UpdateAccessory(Player player, bool hideVisual)
    {
        MyPlayer modPlayer = player.GetModPlayer<MyPlayer>();
        modPlayer.MergeLegacyDeathNecklaceProgression(this);
        modPlayer.SetDeathNecklace(this);
        if (!Main.dedServ && SovereigntyUnlocked && Main.rand.NextBool(10))
        {
            Dust soul = Dust.NewDustPerfect(
                player.Center + Main.rand.NextVector2Circular(24f, 34f),
                DustID.DungeonSpirit,
                -player.velocity * 0.04f,
                70,
                new Color(105, 225, 245),
                0.65f);
            soul.noGravity = true;
        }
    }

    public override void UpdateInventory(Player player)
    {
        player.GetModPlayer<MyPlayer>().MergeLegacyDeathNecklaceProgression(this);
    }

    public override void ModifyTooltips(List<TooltipLine> tooltips)
    {
        string key = DeathDescentUnlocked ? "Mods.SoulHarvest.UI.Enabled" : "Mods.SoulHarvest.UI.Disabled";
        tooltips.Add(new TooltipLine(Mod, "DeathDomainStats", Language.GetTextValue(
            "Mods.SoulHarvest.UI.NecklaceStatsV2",
            DomainRadius / 16f,
            AbsorbAllLevel,
            Language.GetTextValue(key))) { OverrideColor = new Color(110, 220, 240) });
        tooltips.Add(new TooltipLine(Mod, "DeathDomainToggle", Language.GetTextValue("Mods.SoulHarvest.UI.DeathDomainToggleHint")));
        tooltips.Add(new TooltipLine(Mod, "SoulHarvestAltarHint", Language.GetTextValue("Mods.SoulHarvest.UI.AltarHint")));
    }

    public DeathAltarPrice GetUpgradePrice(DeathAltarUpgradeType type)
    {
        return type switch
        {
            DeathAltarUpgradeType.NecklaceRadius => RadiusLevel >= MaxCoreLevel ? DeathAltarPrice.Unavailable : DeathAltarPrice.Essence((RadiusLevel + 1) / 2),
            DeathAltarUpgradeType.NecklaceAbsorbAll => AbsorbAllLevel >= MaxAbsorbAllLevel ? DeathAltarPrice.Unavailable : DeathAltarPrice.Essence((AbsorbAllLevel + 1) / 2),
            DeathAltarUpgradeType.NecklaceSovereignty => SovereigntyUnlocked || !AllCoreStatsMaxed ? DeathAltarPrice.Unavailable : DeathAltarPrice.Essence(30),
            _ => DeathAltarPrice.Unavailable
        };
    }

    public bool ApplyAltarUpgrade(Item item, DeathAltarUpgradeType type)
    {
        if (!GetUpgradePrice(type).IsAvailable)
            return false;
        switch (type)
        {
            case DeathAltarUpgradeType.NecklaceRadius:
                RadiusLevel++;
                break;
            case DeathAltarUpgradeType.NecklaceAbsorbAll:
                AbsorbAllLevel++;
                break;
            case DeathAltarUpgradeType.NecklaceSovereignty:
                SovereigntyUnlocked = true;
                break;
            default:
                return false;
        }
        return true;
    }

    public string GetCurrentUpgradeValue(DeathAltarUpgradeType type) => type switch
    {
        DeathAltarUpgradeType.NecklaceRadius => $"{DomainRadius / 16f:0.#} tiles",
        DeathAltarUpgradeType.NecklaceAbsorbAll => $"Lv. {AbsorbAllLevel}",
        DeathAltarUpgradeType.NecklaceSovereignty => ToggleValue(SovereigntyUnlocked),
        _ => string.Empty
    };

    public string GetNextUpgradeValue(DeathAltarUpgradeType type) => type switch
    {
        DeathAltarUpgradeType.NecklaceRadius => $"{(DomainRadius + RadiusGrowthPerLevel) / 16f:0.#} tiles",
        DeathAltarUpgradeType.NecklaceAbsorbAll => $"Lv. {AbsorbAllLevel + 1}",
        DeathAltarUpgradeType.NecklaceSovereignty => Language.GetTextValue("Mods.SoulHarvest.UI.DeathDescent"),
        _ => string.Empty
    };

    public DeathAltarUnavailableReason GetUnavailableReason(DeathAltarUpgradeType type)
    {
        if (type == DeathAltarUpgradeType.NecklaceSovereignty && !SovereigntyUnlocked && !AllCoreStatsMaxed)
            return DeathAltarUnavailableReason.RequiresNecklaceMastery;
        return DeathAltarUnavailableReason.Maxed;
    }

    public override void SaveData(TagCompound tag)
    {
        tag[nameof(RadiusLevel)] = RadiusLevel;
        tag[nameof(AbsorbAllLevel)] = AbsorbAllLevel;
        tag["FrequencyLevel"] = LegacyFrequencyLevel;
        tag["DamageLevel"] = LegacyDamageLevel;
        tag["VolleyLevel"] = LegacyVolleyLevel;
        tag["LifeStealLevel"] = LegacyLifeStealLevel;
        tag[nameof(SovereigntyUnlocked)] = SovereigntyUnlocked;
    }

    public override void LoadData(TagCompound tag)
    {
        RadiusLevel = Math.Clamp(tag.GetInt(nameof(RadiusLevel)), 1, MaxCoreLevel);
        SovereigntyUnlocked = tag.GetBool(nameof(SovereigntyUnlocked));
        LegacyFrequencyLevel = Math.Clamp(tag.GetInt("FrequencyLevel"), 1, DeathDomainProgression.MaxCoreLevel);
        LegacyDamageLevel = Math.Clamp(tag.GetInt("DamageLevel"), 1, DeathDomainProgression.MaxCoreLevel);
        LegacyVolleyLevel = Math.Clamp(tag.GetInt("VolleyLevel"), 1, DeathDomainProgression.MaxVolleyLevel);
        LegacyLifeStealLevel = Math.Clamp(tag.GetInt("LifeStealLevel"), 0, DeathDomainProgression.MaxLifeStealLevel);
        AbsorbAllLevel = tag.ContainsKey(nameof(AbsorbAllLevel))
            ? Math.Clamp(tag.GetInt(nameof(AbsorbAllLevel)), 1, MaxAbsorbAllLevel)
            : SovereigntyUnlocked
                ? MaxAbsorbAllLevel
                : 1;
    }

    public override void NetSend(BinaryWriter writer)
    {
        writer.Write((byte)RadiusLevel);
        writer.Write((byte)AbsorbAllLevel);
        writer.Write((byte)LegacyFrequencyLevel);
        writer.Write((byte)LegacyDamageLevel);
        writer.Write((byte)LegacyVolleyLevel);
        writer.Write((byte)LegacyLifeStealLevel);
        writer.Write(SovereigntyUnlocked);
    }

    public override void NetReceive(BinaryReader reader)
    {
        RadiusLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxCoreLevel);
        AbsorbAllLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxAbsorbAllLevel);
        LegacyFrequencyLevel = Math.Clamp((int)reader.ReadByte(), 1, DeathDomainProgression.MaxCoreLevel);
        LegacyDamageLevel = Math.Clamp((int)reader.ReadByte(), 1, DeathDomainProgression.MaxCoreLevel);
        LegacyVolleyLevel = Math.Clamp((int)reader.ReadByte(), 1, DeathDomainProgression.MaxVolleyLevel);
        LegacyLifeStealLevel = Math.Clamp((int)reader.ReadByte(), 0, DeathDomainProgression.MaxLifeStealLevel);
        SovereigntyUnlocked = reader.ReadBoolean();
    }

    public override void AddRecipes()
    {
        CreateRecipe()
            .AddIngredient(ItemID.PanicNecklace)
            .AddIngredient(ItemID.ObsidianRose)
            .AddIngredient<Soul>(3)
            .AddTile(ModContent.TileType<DeathAltarTile>())
            .Register();
    }

    private bool AllCoreStatsMaxed => RadiusLevel >= MaxCoreLevel
        && AbsorbAllLevel >= MaxAbsorbAllLevel;

    private static string ToggleValue(bool enabled) => Language.GetTextValue(
        enabled ? "Mods.SoulHarvest.UI.Enabled" : "Mods.SoulHarvest.UI.Disabled");

}