using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using WingsAPI.Game.Extensions.ItemExtension.Inventory; using WingsAPI.Game.Extensions.Quicklist; using WingsEmu.Game._i18n; using WingsEmu.Game.Algorithm; using WingsEmu.Game.Extensions; using WingsEmu.Game.Inventory; using WingsEmu.Game.Managers; using WingsEmu.Game.Networking; using WingsEmu.Game.Shops.Event; using WingsEmu.Game.Skills; using WingsEmu.Packets.ClientPackets; using WingsEmu.Packets.Enums; using WingsEmu.Packets.Enums.Chat; namespace WingsEmu.Plugins.PacketHandling.Game.Npc; public class SellPacketHandler : GenericGamePacketHandlerBase { private static readonly HashSet Basics = new() { 200, 201, 220, 221, 240, 241, 260, 261, 1525, 1529 }; private static readonly HashSet Capture = new() { 209, 235, 236, 237, 1565 }; private readonly ICharacterAlgorithm _characterAlgorithm; private readonly IGameLanguageService _language; private readonly IServerManager _serverManager; public SellPacketHandler(IServerManager serverManager, ICharacterAlgorithm characterAlgorithm, IGameLanguageService language) { _characterAlgorithm = characterAlgorithm; _serverManager = serverManager; _language = language; } protected override async Task HandlePacketAsync(IClientSession session, SellPacket sellPacket) { if (session.PlayerEntity.IsInExchange()) { return; } if (session.PlayerEntity.IsShopping) { return; } if (sellPacket.Amount.HasValue && sellPacket.Slot.HasValue) { await HandleItemPacket(session, sellPacket); return; } HandleSkillPacket(session, sellPacket); } private void HandleSkillPacket(IClientSession session, SellPacket sellPacket) { if (session.PlayerEntity.UseSp) { session.SendMsg(session.GetLanguage(GameDialogKey.INFORMATION_SHOUTMESSAGE_REMOVE_SP), MsgMessageType.Middle); return; } if (session.PlayerEntity.IsOnVehicle) { session.SendChatMessage(session.GetLanguage(GameDialogKey.SKILL_CHATMESSAGE_CANT_LEARN_MORPHED), ChatMessageColorType.Yellow); return; } if (session.PlayerEntity.IsInExchange()) { return; } if (session.PlayerEntity.HasShopOpened) { return; } if (session.PlayerEntity.Skills.Any(s => !session.PlayerEntity.SkillCanBeUsed(s, DateTime.UtcNow))) { session.SendMsg(session.GetLanguage(GameDialogKey.SKILL_SHOUTMESSAGE_CANT_LEARN_COOLDOWN), MsgMessageType.Middle); return; } short vnum = sellPacket.Data; if (!session.PlayerEntity.CharacterSkills.TryGetValue(vnum, out CharacterSkill skill)) { return; } if (skill == null || IsBasicSkillOrCapture(vnum)) { session.SendChatMessage(_language.GetLanguage(GameDialogKey.SKILL_CHATMESSAGE_NOT_TO_REFUND, session.UserLanguage), ChatMessageColorType.Yellow); return; } if (skill.Skill.IsPassiveSkill()) { session.SendChatMessage(_language.GetLanguage(GameDialogKey.SKILL_CHATMESSAGE_NOT_TO_REFUND, session.UserLanguage), ChatMessageColorType.Yellow); return; } if (skill.Skill.UpgradeSkill != 0) { if (session.PlayerEntity.SkillComponent.SkillUpgrades.TryGetValue(skill.Skill.UpgradeSkill, out HashSet hashSet)) { hashSet.Remove(skill); } } foreach (CharacterSkill loadedSkill in session.PlayerEntity.CharacterSkills.Values) { if (skill.SkillVNum != loadedSkill.Skill.UpgradeSkill) { continue; } session.PlayerEntity.CharacterSkills.TryRemove(loadedSkill.SkillVNum, out CharacterSkill value); session.PlayerEntity.Skills.Remove(value); } session.PlayerEntity.CharacterSkills.TryRemove(skill.SkillVNum, out CharacterSkill _); session.PlayerEntity.Skills.Remove(skill); if (session.PlayerEntity.SkillComponent.SkillUpgrades.TryGetValue(vnum, out HashSet upgrades)) { upgrades.Clear(); } session.RefreshSkillList(); session.RefreshQuicklist(); session.RefreshLevel(_characterAlgorithm); session.EmitEventAsync(new ShopSkillSoldEvent { SkillVnum = skill.SkillVNum }); } private async Task HandleItemPacket(IClientSession session, SellPacket sellPacket) { var type = (InventoryType)sellPacket.Data; byte slot = sellPacket.Slot.Value; ushort amount = sellPacket.Amount.Value; InventoryItem inv = session.PlayerEntity.GetItemBySlotAndType(slot, type); if (inv == null) { return; } if (amount > inv.ItemInstance.Amount) { return; } if (inv.ItemInstance.GameItem.Type == InventoryType.Miniland && session.PlayerEntity.Miniland != null && session.PlayerEntity.Miniland.MapDesignObjects.Any(s => s.InventorySlot == inv.Slot)) { return; } if (inv.ItemInstance.GameItem.ReputPrice != 0) { return; } if (!inv.ItemInstance.GameItem.IsSoldable) { session.SendSMemo(SmemoType.Error, _language.GetLanguage(GameDialogKey.INTERACTION_LOG_ITEM_NOT_SELLABLE, session.UserLanguage)); return; } long price = inv.ItemInstance.GameItem.ItemType == ItemType.Sell ? inv.ItemInstance.GameItem.Price : inv.ItemInstance.GameItem.Price / 20 <= 0 ? 1 : inv.ItemInstance.GameItem.Price / 20; if (session.PlayerEntity.Gold + price * amount > _serverManager.MaxGold) { session.SendSMemo(SmemoType.Error, _language.GetLanguage(GameDialogKey.INFORMATION_MESSAGE_MAX_GOLD, session.UserLanguage)); return; } session.PlayerEntity.Gold += price * amount; session.RefreshGold(); session.SendSMemo(SmemoType.Balance, _language.GetLanguage(GameDialogKey.SHOP_LOG_SELL_ITEM_VALID, session.UserLanguage)); await session.RemoveItemFromInventory(item: inv, amount: (short)amount); await session.EmitEventAsync(new ShopNpcSoldItemEvent { ItemInstance = inv.ItemInstance, Amount = (short)amount, PricePerItem = price }); } private static bool IsBasicSkillOrCapture(short vnum) => Basics.Contains(vnum) || Capture.Contains(vnum); }