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().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() || Vector2.Distance(player.Center, altarPosition) > MaximumAltarDistance) { SoulHarvest.SendOperationResult(player, SoulHarvest.OperationResult.TooFarFromAltar); return false; } MyPlayer soulPlayer = player.GetModPlayer(); bool characterDeathDomain = itemReference.Storage == DeathAltarItemStorage.CharacterDeathDomain; Item targetItem; IDeathAltarUpgradeable upgradeable; if (characterDeathDomain) { targetItem = new Item(); targetItem.SetDefaults(ModContent.ItemType()); 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(); 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 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 ConsumeEssence(Player player, int essenceType, int amount) { List 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); } }