using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using WingsEmu.DTOs.Skills; using WingsEmu.Game._enum; using WingsEmu.Game.Battle; using WingsEmu.Game.Characters; using WingsEmu.Game.Entities; using WingsEmu.Game.Extensions; using WingsEmu.Game.Extensions.Mates; using WingsEmu.Game.Helpers.Damages; using WingsEmu.Game.Maps; using WingsEmu.Game.Mates; using WingsEmu.Game.Networking; using WingsEmu.Game.Skills; using WingsEmu.Packets.ClientPackets; using WingsEmu.Packets.Enums; namespace WingsEmu.Plugins.PacketHandling.Game.Mate; public class UpetPacketHandler : GenericGamePacketHandlerBase { protected override async Task HandlePacketAsync(IClientSession session, UpetPacket packet) { if (session.IsMuted()) { session.SendMuteMessage(); return; } if (!session.PlayerEntity.CanFight() || packet == null) { session.SendDebugMessage("[U_PET] !CanFight or packet == null"); return; } // check, if owner of mate is in PvP cell if (session.CurrentMapInstance.IsPvp && session.CurrentMapInstance.PvpZone(session.PlayerEntity.PositionX, session.PlayerEntity.PositionY)) { session.SendDebugMessage("[U_PET] Character in No-PvP zone"); return; } IMateEntity attacker = session.PlayerEntity.MateComponent.GetMate(x => x.Id == packet.MateTransportId && x.MateType == MateType.Pet); if (attacker == null) { session.SendDebugMessage("[U_PET] Mate == null"); return; } if (!attacker.IsAlive()) { session.SendDebugMessage("[U_PET] Mate is dead"); return; } if (attacker.IsCastingSkill) { session.SendDebugMessage("[U_PET] Mate IsCasting"); return; } if (attacker.IsSitting) { session.SendDebugMessage("[U_PET] Mate IsSitting"); return; } if (!attacker.CanAttack()) { session.SendDebugMessage("[U_PET] !canAttack()"); return; } // check, if mate is in PvP cell if (attacker.MapInstance.IsPvp && attacker.MapInstance.PvpZone(attacker.PositionX, attacker.PositionY)) { session.SendDebugMessage("[U_PET] Mate in No-PvP zone"); return; } if (session.PlayerEntity.IsOnVehicle || session.PlayerEntity.CheatComponent.IsInvisible) { session.SendDebugMessage("[U_PET] Mate - session.IsVehicled, InvisibleGm"); return; } if (session.PlayerEntity.IsInvisible()) { return; } IBattleEntity target = session.PlayerEntity.MapInstance.GetBattleEntity(packet.TargetType, packet.TargetId); switch (target) { case null: session.SendDebugMessage("[U_PET] Target == null"); return; case IMonsterEntity { MonsterRaceType: MonsterRaceType.Fixed }: case IPlayerEntity { IsSeal: true }: return; } // check, if target is in PvP cell if (target.MapInstance.IsPvp && target.MapInstance.PvpZone(target.PositionX, target.PositionY)) { session.SendDebugMessage("[U_PET] Target in No-PvP zone"); return; } // check, if target owner is in PvP cell IPlayerEntity targetMateOwner = (target as IMateEntity)?.Owner; if (targetMateOwner != null && target.MapInstance.PvpZone(targetMateOwner.PositionX, targetMateOwner.PositionY) && target.MapInstance.IsPvp) { session.SendDebugMessage("[U_PET] Target Mate Owner in No-PvP zone"); return; } if (!target.IsAlive()) { session.SendDebugMessage("[U_PET] Target is dead"); return; } IEnumerable mateSkills = attacker.Skills; if (mateSkills == null) { session.SendDebugMessage("[U_PET] mateSkills == null"); return; } IBattleEntitySkill ski = mateSkills.FirstOrDefault(s => s.Skill.SkillType == SkillType.PartnerSkill); if (ski == null) { session.SendDebugMessage("[U_PET] skill == null"); return; } SkillDTO skill = ski.Skill; SkillInfo skillInfo = skill.GetInfo(battleEntity: attacker); if (!attacker.SkillCanBeUsed(ski, DateTime.UtcNow)) { session.SendDebugMessage("[U_PET] !skill.CanBeUsed()"); return; } if (!attacker.IsEnemyWith(target) && attacker.IsMate() && skillInfo.TargetType != TargetType.Self) { session.SendDebugMessage("[U_PET] !attacker.IsEnemyWith(target)"); return; } if (attacker.Mp < skill.MpCost) { session.SendDebugMessage("[U_PET] attacker.Mp < MpCost"); return; } if (!session.PlayerEntity.CheatComponent.HasGodMode) { attacker.RemoveEntityMp(skill.MpCost, skill); } int cellSizeBonus = 3; if (target is INpcMonsterEntity npcMonsterEntity) { cellSizeBonus += npcMonsterEntity.CellSize; } if (!attacker.Position.IsInRange(target.Position, skillInfo.Range + cellSizeBonus)) { session.SendDebugMessage("[U_PET] !attacker.IsInRange"); return; } attacker.LastSkillUse = DateTime.UtcNow; DateTime castTime = attacker.GenerateSkillCastTime(skillInfo); session.SendDebugMessage("[U_PET] Casting u_pet"); await attacker.EmitEventAsync(new BattleExecuteSkillEvent(attacker, target, skillInfo, castTime)); } }