using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using WingsEmu.Game._enum; using WingsEmu.Game._i18n; using WingsEmu.Game._NpcDialog; using WingsEmu.Game._NpcDialog.Event; using WingsEmu.Game.Entities; using WingsEmu.Game.Entities.Extensions; using WingsEmu.Game.Extensions; using WingsEmu.Game.Extensions.Mates; using WingsEmu.Game.Items; using WingsEmu.Game.Managers.StaticData; using WingsEmu.Game.Mates; using WingsEmu.Game.Mates.Events; using WingsEmu.Game.Networking; using WingsEmu.Game.Npcs; using WingsEmu.Game.TimeSpaces; using WingsEmu.Game.TimeSpaces.Events; using WingsEmu.Packets.Enums; using WingsEmu.Packets.Enums.Battle; using WingsEmu.Packets.Enums.Chat; namespace WingsEmu.Plugins.BasicImplementations.NpcDialogs.TimeSpace; public class GetPartnerHandler : INpcDialogAsyncHandler { private readonly IGameItemInstanceFactory _gameItemInstanceFactory; private readonly IGameLanguageService _gameLanguage; private readonly IMateEntityFactory _mateEntityFactory; private readonly INpcMonsterManager _npcMonsterManager; public GetPartnerHandler(INpcMonsterManager npcMonsterManager, IMateEntityFactory mateEntityFactory, IGameItemInstanceFactory gameItemInstanceFactory, IGameLanguageService gameLanguage) { _npcMonsterManager = npcMonsterManager; _mateEntityFactory = mateEntityFactory; _gameItemInstanceFactory = gameItemInstanceFactory; _gameLanguage = gameLanguage; } public NpcRunType[] NpcRunTypes => new[] { NpcRunType.GET_PARTNER }; public async Task Execute(IClientSession session, NpcDialogEvent e) { if (!session.HasCurrentMapInstance) { return; } if (!session.PlayerEntity.TimeSpaceComponent.IsInTimeSpaceParty) { return; } TimeSpaceParty timeSpace = session.PlayerEntity.TimeSpaceComponent.TimeSpace; List partners = session.PlayerEntity.TimeSpaceComponent.Partners; if (timeSpace.Instance.StartTimeFreeze.HasValue) { await session.EmitEventAsync(new TimeSpaceAddTimeToTimerEvent { Time = DateTime.UtcNow - timeSpace.Instance.StartTimeFreeze.Value }); timeSpace.Instance.StartTimeFreeze = null; } if (!timeSpace.Instance.TimeSpaceSubInstances.TryGetValue(session.CurrentMapInstance.Id, out TimeSpaceSubInstance timeSpaceSubInstance)) { return; } await session.EmitEventAsync(new TimeSpaceStartTaskEvent { TimeSpaceSubInstance = timeSpaceSubInstance }); if (timeSpaceSubInstance.Task != null && timeSpaceSubInstance.Task.StartDialog.HasValue) { timeSpaceSubInstance.Task.StartDialog = null; if (timeSpaceSubInstance.Task.StartDialogIsObjective) { timeSpaceSubInstance.Task.StartDialogIsObjective = false; timeSpace.Instance.TimeSpaceObjective.ConversationsHad++; await session.EmitEventAsync(new TimeSpaceRefreshObjectiveProgressEvent()); } } if (timeSpace.Instance.ObtainablePartnerVnum == null) { return; } INpcEntity timeSpacePartner = partners.FirstOrDefault(x => x.MonsterVNum == timeSpace.Instance.ObtainablePartnerVnum.Value); if (!partners.Any() || timeSpacePartner == null) { return; } IMonsterData partner = _npcMonsterManager.GetNpc(timeSpace.Instance.ObtainablePartnerVnum.Value); if (partner == null) { return; } if (session.PlayerEntity.MateComponent.GetMates(x => x.MonsterVNum == partner.MonsterVNum && x.MateType == MateType.Partner).Any()) { session.SendChatMessage(session.GetLanguage(GameDialogKey.PARTNER_SHOUTMESSAGE_ALREADY_HAVE_SAME_PARTNER), ChatMessageColorType.Yellow); return; } if (!session.PlayerEntity.CanReceiveMate(MateType.Partner)) { session.SendChatMessage(session.GetLanguage(GameDialogKey.INFORMATION_SHOUTMESSAGE_MAX_PARTNER_COUNT), ChatMessageColorType.Yellow); return; } session.PlayerEntity.BroadcastEffectInRange(EffectType.NormalLevelUpSubEffect); timeSpacePartner.BroadcastEffectInRange(EffectType.NormalLevelUpSubEffect); timeSpacePartner.MapInstance.Broadcast(timeSpacePartner.GenerateOut()); timeSpacePartner.MapInstance.RemoveNpc(timeSpacePartner); session.PlayerEntity.TimeSpaceComponent.Partners.Remove(timeSpacePartner); byte partnerLevel = session.PlayerEntity.Level < partner.BaseLevel ? session.PlayerEntity.Level : partner.BaseLevel; IMateEntity mateEntity = _mateEntityFactory.CreateMateEntity(session.PlayerEntity, new MonsterData(partner), MateType.Partner, partnerLevel); await session.EmitEventAsync(new MateInitializeEvent { MateEntity = mateEntity }); CreatePartnerEquipment(session, mateEntity); if (session.PlayerEntity.MateComponent.GetTeamMember(x => x.MateType == MateType.Partner) != null) { return; } await session.EmitEventAsync(new MateJoinTeamEvent { MateEntity = mateEntity, IsNewCreated = true }); } private void CreatePartnerEquipment(IClientSession session, IMateEntity mateEntity) { if (mateEntity.Level < 15) { return; } int weapon = 0; int armor = 0; switch (mateEntity.AttackType) { case AttackType.Melee: switch (mateEntity.Level) { case >= 20 and <= 30: weapon = 19; // Short Sword armor = 162; // Durable Armour break; case > 30 and <= 48: weapon = 21; // Short Sword armor = 97; // Leather Armour break; default: weapon = 139; // Katzbalger armor = 102; // Armour of Morale break; } break; case AttackType.Ranged: switch (mateEntity.Level) { case >= 20 and <= 30: weapon = 33; // Small Bow armor = 108; // Lambskin Tunic break; case > 30 and <= 49: weapon = 143; // Flame Bow armor = 169; // Tunic of Nature break; default: weapon = 146; // Wild Bow armor = 116; // Peccary Tunic break; } break; case AttackType.Magical: switch (mateEntity.Level) { case >= 20 and <= 30: weapon = 47; // Red Bead Wand armor = 121; // Cotton Robe break; case > 30 and <= 49: weapon = 150; // Magic Wand of Flame armor = 175; // Soft Robe break; default: weapon = 153; // Magic Spell Wand armor = 129; // Silk Robe break; } break; } GameItemInstance weaponItem = _gameItemInstanceFactory.CreateItem(weapon, 1, 5, 5); switch (weaponItem.GameItem.EquipmentSlot) { case EquipmentType.SecondaryWeapon: case EquipmentType.MainWeapon: switch (weaponItem.GameItem.Class) { case (int)ItemClassType.Swordsman: weaponItem.ItemVNum = weaponItem.GameItem.EquipmentSlot == (int)EquipmentType.MainWeapon ? (int)ItemVnums.PARTNER_WEAPON_MELEE : (int)ItemVnums.PARTNER_WEAPON_RANGED; break; case (int)ItemClassType.Archer: weaponItem.ItemVNum = weaponItem.GameItem.EquipmentSlot == (int)EquipmentType.MainWeapon ? (int)ItemVnums.PARTNER_WEAPON_RANGED : (int)ItemVnums.PARTNER_WEAPON_MELEE; break; case (int)ItemClassType.Mage: weaponItem.ItemVNum = weaponItem.GameItem.EquipmentSlot == (int)EquipmentType.MainWeapon ? (int)ItemVnums.PARTNER_WEAPON_MAGIC : (int)ItemVnums.PARTNER_WEAPON_RANGED; break; case (int)ItemClassType.MartialArtist: weaponItem.ItemVNum = (int)ItemVnums.PARTNER_WEAPON_MELEE; break; default: session.SendShopEndPacket(ShopEndType.Npc); return; } break; } weaponItem.EquipmentOptions?.Clear(); weaponItem.OriginalItemVnum = weapon; weaponItem.BoundCharacterId = null; GameItemInstance armorItem = _gameItemInstanceFactory.CreateItem(armor, 1, 5, 5); switch (armorItem.GameItem.Class) { case (int)ItemClassType.Swordsman: case (int)ItemClassType.MartialArtist: armorItem.ItemVNum = (int)ItemVnums.PARTNER_ARMOR_MELEE; break; case (int)ItemClassType.Archer: armorItem.ItemVNum = (int)ItemVnums.PARTNER_ARMOR_RANGED; break; case (int)ItemClassType.Mage: armorItem.ItemVNum = (int)ItemVnums.PARTNER_ARMOR_MAGIC; break; } armorItem.EquipmentOptions?.Clear(); armorItem.OriginalItemVnum = armor; armorItem.BoundCharacterId = null; session.PlayerEntity.PartnerEquipItem(weaponItem, mateEntity.PetSlot); session.PlayerEntity.PartnerEquipItem(armorItem, mateEntity.PetSlot); session.SendScpPackets(); session.SendScnPackets(); mateEntity.RefreshEquipmentValues(weaponItem, false); mateEntity.RefreshEquipmentValues(armorItem, false); session.SendPetInfo(mateEntity, _gameLanguage); session.SendCondMate(mateEntity); } }