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);
}
}
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);
}
}