using Terraria; using Terraria.ID; using Terraria.Net; using Terraria.Localization; using TShockAPI; using TShockAPI.Hooks; using TerrariaApi.Server; using TerrariaHealingPlugin.Mappings; namespace TerrariaHealingPlugin; [ApiVersion(2, 1)] public class HealingPlugin : TerrariaPlugin { public override string Author => "Sneefaria Maintainers"; public override string Name => "HealingPlugin"; public override string Description => "A healing plugin, duh"; public override Version Version => new Version(1, 0, 0); private DateTime _lastHealCheck = DateTime.UtcNow; private DateTime _lastBuffCheck = DateTime.UtcNow; private List _players = new List(); private HealingMappings _healingItemMappings = new HealingMappings(); private EquipMappings _equipMappings = new EquipMappings(); public HealingPlugin(Main game) : base(game) { } public override void Initialize() { TShock.Log.Info($"Initializing {Name} v{Version} by {Author}"); ServerApi.Hooks.ServerJoin.Register(this, OnServerJoin); ServerApi.Hooks.GameUpdate.Register(this, OnUpdate); ServerApi.Hooks.NetSendData.Register(this, OnSendNetData); ServerApi.Hooks.NetGetData.Register(this, OnGetNetData); GetDataHandlers.PlayerSlot.Register(OnPlayerSlot); // GetDataHandlers.PlayerHP.Register(OnPlayerHPChange); GetDataHandlers.PlayerBuff.Register(OnPlayerBuff); PlayerHooks.PlayerPostLogin += OnPlayerPostLogin; } protected override void Dispose(bool disposing) { if (disposing) { ServerApi.Hooks.ServerJoin.Deregister(this, OnServerJoin); // ServerApi.Hooks.GameUpdate.Deregister(this, OnUpdate); ServerApi.Hooks.NetSendData.Deregister(this, OnSendNetData); ServerApi.Hooks.NetGetData.Deregister(this, OnGetNetData); PlayerHooks.PlayerPostLogin -= OnPlayerPostLogin; } base.Dispose(disposing); } private void OnPlayerPostLogin(PlayerPostLoginEventArgs e) { ApplyRegenerationBuff(e.Player); } private void OnPlayerBuff(object sender, GetDataHandlers.PlayerBuffEventArgs args) { // Console.WriteLine($"Player buff arguments: {args}"); TSPlayer player = args.Player; int buffType = args.Type; Console.WriteLine($"Buff type: {buffType}"); bool isEquippableBuff = _equipMappings.mappings.ContainsKey(buffType); bool isHealingItemBuff = _healingItemMappings.mappings.ContainsKey(buffType); Console.WriteLine($"Player: {player.Name}, Buff Type: {buffType}, Is Equippable Buff: {isEquippableBuff}"); if (isEquippableBuff) { var multiplier = _equipMappings.GetHealingMultiplier(buffType); player.SendSuccessMessage($"Equippable buff detected! Applying x{multiplier} multiplier to healing effects."); args.Handled = true; } } private void OnGetNetData(GetDataEventArgs args) { // nothing here, yet ;) } private void OnPlayerHPChange(object sender, GetDataHandlers.PlayerHPEventArgs args) { TSPlayer player = args.Player; int previousHP = player.TPlayer.statLife; int newHP = args.Current; short healingAmount = (short)(newHP - previousHP); bool isHealingItem = IsHealingValueValid(healingAmount); Console.WriteLine($"Player: {player.Name}, Previous HP: {previousHP}, New HP: {newHP}, Healing Amount: {healingAmount}"); if (healingAmount > 0 && isHealingItem) { args.Handled = true; } } private void OnPlayerSlot(object sender, GetDataHandlers.PlayerSlotEventArgs args) { Console.WriteLine("In OnPlayerSlot method"); TSPlayer player = args.Player; short slot = args.Slot; short newStack = args.Stack; short itemType = args.Type; Console.WriteLine($"Player: {player.Name}, Slot: {slot}, New Stack: {newStack}, Item Type: {itemType}"); var isHealingItem = IsHealingItem(itemType); var isItemConsumed = IsItemBeingConsumed(player, slot, newStack); Console.WriteLine($"Is Healing Item: {isHealingItem}, Is Item Being Consumed: {isItemConsumed}"); if (isHealingItem && isItemConsumed) { var multiplier = _healingItemMappings.GetHealingMultiplier(itemType); var baseHeal = GetBaseHealAmount(itemType); var enhancedHeal = (int)(baseHeal * multiplier); var totalHealing = enhancedHeal + baseHeal; Console.WriteLine($"Base Heal: {baseHeal}, Multiplier: {multiplier}, Enhanced Heal: {enhancedHeal}"); player.Heal(enhancedHeal); player.SendSuccessMessage($"Enhanced healing! Restored {enhancedHeal} HP (x{multiplier} multiplier)"); args.Handled = true; } } private bool IsHealingItem(int itemType) { return _healingItemMappings.mappings.ContainsKey(itemType); } private bool IsHealingValueValid(short healAmount) { return _healingItemMappings.mappings.ContainsValue(healAmount); } private int GetBaseHealAmount(int itemType) { return _healingItemMappings.mappings.TryGetValue(itemType, out var healAmount) ? healAmount : 0; } private bool IsItemBeingConsumed(TSPlayer player, int slot, short newStack) { var item = player.TPlayer.inventory[slot]; return item.stack > newStack; } private void OnSendNetData(SendDataEventArgs args) { // empty, on purpose :D } private void OnUpdate(EventArgs args) { if ((DateTime.UtcNow - _lastHealCheck).TotalSeconds >= 1) { foreach (var player in TShock.Players) { // Console.WriteLine($"Player {player.Name} has the following HP: {player.TPlayer.statLife}"); // if (player != null && player.Active && player.TPlayer.statLife < player.TPlayer.statLifeMax) // { // Console.WriteLine($"Player {player.Name} is not healed all the way, let's increase the regen"); // player.TPlayer.statLife += 10; // player.SendData(PacketTypes.EffectHeal, "", player.Index, 10f); // Console.WriteLine("Increased health via regen"); // } // else if (player != null && player.TPlayer.statLife == player.TPlayer.statLifeMax) // { // Console.WriteLine($"Player {player.Name} is fully healed."); // } } _lastHealCheck = DateTime.UtcNow; } if ((DateTime.UtcNow - _lastBuffCheck).TotalSeconds >= 30) { foreach (TSPlayer player in TShock.Players) { if (player?.Active == true) { ApplyRegenerationBuff(player); } } _lastBuffCheck = DateTime.UtcNow; } } // private void ApplyRegenerationToAllPlayers() // { // foreach (TSPlayer player in TShock.Players) // { // if (player?.Active == true && player.ConnectionAlive) // { // ApplyRegenerationBuff(player); // } // } // } private void ApplyRegenerationBuff(TSPlayer player) { if (player?.Active == true && player.ConnectionAlive) { player.SetBuff(2, 3600, bypass: true); Console.WriteLine($"set buff for player {player.Name}"); } } private void OnServerJoin(JoinEventArgs args) { var player = TShock.Players[args.Who]; if (player != null) { _players.Add(new Player(player)); TShock.Log.Info($"Player {player.Name} joined with IP: {player.IP}"); } } }