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

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

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

namespace SoulHarvest.Common;

internal static class DeathAltarUpgradeService
{
    private const float MaximumAltarDistance = 12f * 16f;

    public static bool TryUpgrade(Player player, DeathAltarUpgradeType upgradeType, DeathAltarItemReference itemReference, int tileX, int tileY)
    {
        if (Main.netMode == NetmodeID.MultiplayerClient
            || !player.GetModPlayer<MyPlayer>().ServerCharacterStateReady)
            return false;

        if (!Enum.IsDefined(typeof(DeathAltarUpgradeType), upgradeType))
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.UpgradeMaxed);
            return false;
        }

        if (!Enum.IsDefined(typeof(DeathAltarItemStorage), itemReference.Storage))
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.HoldSickle);
            return false;
        }

        if (!WorldGen.InWorld(tileX, tileY, 1))
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.TooFarFromAltar);
            return false;
        }

        Tile tile = Framing.GetTileSafely(tileX, tileY);
        Vector2 altarPosition = new((tileX + 0.5f) * 16f, (tileY + 0.5f) * 16f);
        if (!tile.HasTile || tile.TileType != ModContent.TileType<DeathAltarTile>() || Vector2.Distance(player.Center, altarPosition) > MaximumAltarDistance)
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.TooFarFromAltar);
            return false;
        }

        MyPlayer soulPlayer = player.GetModPlayer<MyPlayer>();
        bool characterDeathDomain = itemReference.Storage == DeathAltarItemStorage.CharacterDeathDomain;
        Item targetItem;
        IDeathAltarUpgradeable upgradeable;
        if (characterDeathDomain)
        {
            targetItem = new Item();
            targetItem.SetDefaults(ModContent.ItemType<DeathDomain>());
            if (itemReference.ExpectedItemType != targetItem.type)
            {
                SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.HoldSickle);
                return false;
            }
            upgradeable = soulPlayer.DeathDomainProgression;
        }
        else if (!itemReference.TryResolve(player, out targetItem)
            || targetItem.ModItem is not IDeathAltarUpgradeable resolvedUpgradeable)
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.HoldSickle);
            return false;
        }
        else
        {
            upgradeable = resolvedUpgradeable;
        }

        DeathAltarPrice price = upgradeable.GetUpgradePrice(upgradeType);
        if (!price.IsAvailable)
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.UpgradeMaxed);
            return false;
        }

        int essenceType = ModContent.ItemType<Soul>();
        if (price.Currency == DeathAltarCurrency.Souls && soulPlayer.Souls < price.Amount)
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.NotEnoughUpgradeSouls);
            return false;
        }

        if (price.Currency == DeathAltarCurrency.SoulEssence && player.CountItem(essenceType, price.Amount) < price.Amount)
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.NotEnoughEssence);
            return false;
        }

        bool upgraded = upgradeable.ApplyAltarUpgrade(targetItem, upgradeType);

        if (!upgraded)
        {
            SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.UpgradeMaxed);
            return false;
        }

        List<int> changedEssenceSlots = price.Currency == DeathAltarCurrency.SoulEssence
            ? ConsumeEssence(player, essenceType, price.Amount)
            : [];
        if (price.Currency == DeathAltarCurrency.Souls && !soulPlayer.TrySpendSouls(price.Amount))
            return false;
        if (price.Currency == DeathAltarCurrency.SoulEssenceRefund)
        {
            player.QuickSpawnItem(
                player.GetSource_Misc("SoulHarvest:SickleRegression"),
                essenceType,
                price.Amount);
        }

        if (characterDeathDomain)
            soulPlayer.SyncPlayer(-1, -1, false);
        else
            SyncUpgradeableItem(player, itemReference);
        foreach (int slot in changedEssenceSlots)
            SyncInventorySlot(player, slot);

        SoulHarvest.SendOperationResult(
            player,
            price.Currency == DeathAltarCurrency.SoulEssenceRefund
                ? SoulHarvest.OperationResult.SickleRegressed
                : SoulHarvest.OperationResult.UpgradeSucceeded);
        return true;
    }

    private static List<int> ConsumeEssence(Player player, int essenceType, int amount)
    {
        List<int> changedSlots = [];
        for (int slot = 0; slot < 58 && amount > 0; slot++)
        {
            Item item = player.inventory[slot];
            if (item.type != essenceType || item.stack <= 0)
                continue;

            int consumed = Math.Min(item.stack, amount);
            item.stack -= consumed;
            amount -= consumed;
            if (item.stack <= 0)
                item.TurnToAir();
            changedSlots.Add(slot);
        }

        return changedSlots;
    }

    private static void SyncInventorySlot(Player player, int slot)
    {
        if (Main.netMode != NetmodeID.Server)
            return;

        NetMessage.SendData(
            MessageID.SyncEquipment,
            -1,
            -1,
            null,
            player.whoAmI,
            PlayerItemSlotID.Inventory0 + slot,
            player.inventory[slot].prefix);
        SoulHarvest.SendInventorySlot(player, slot);
    }

    private static void SyncUpgradeableItem(Player player, DeathAltarItemReference itemReference)
    {
        if (Main.netMode != NetmodeID.Server || !itemReference.TryGetSlotItem(player, out Item item))
            return;

        int networkSlot = itemReference.Storage == DeathAltarItemStorage.Inventory
            ? PlayerItemSlotID.Inventory0 + itemReference.Slot
            : PlayerItemSlotID.Armor0 + itemReference.Slot;
        NetMessage.SendData(MessageID.SyncEquipment, -1, -1, null, player.whoAmI, networkSlot, item.prefix);
        SoulHarvest.SendAltarItem(player, itemReference);
    }
}