server-master/srcs/_plugins/WingsEmu.Plugins.PacketHandling/Game/Battle/UseAtSkillPacketHandler.cs
2026-02-10 18:21:30 +01:00

232 lines
No EOL
9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WingsAPI.Game.Extensions.Quicklist;
using WingsEmu.DTOs.Skills;
using WingsEmu.Game._i18n;
using WingsEmu.Game.Battle;
using WingsEmu.Game.Buffs;
using WingsEmu.Game.Characters;
using WingsEmu.Game.Characters.Events;
using WingsEmu.Game.Configurations;
using WingsEmu.Game.Extensions;
using WingsEmu.Game.Helpers.Damages;
using WingsEmu.Game.Managers.StaticData;
using WingsEmu.Game.Maps;
using WingsEmu.Game.Networking;
using WingsEmu.Game.Skills;
using WingsEmu.Packets.ClientPackets;
using WingsEmu.Packets.Enums;
using WingsEmu.Packets.Enums.Battle;
using WingsEmu.Packets.Enums.Chat;
namespace WingsEmu.Plugins.PacketHandling.Game.Battle;
public class UseAtSkillPacketHandler : GenericGamePacketHandlerBase<UseAtSkillPacket>
{
private readonly ICardsManager _cardsManager;
private readonly IGameLanguageService _gameLanguage;
private readonly RainbowBattleConfiguration _rainbowBattleConfiguration;
private readonly ISkillsManager _skillsManager;
public UseAtSkillPacketHandler(IGameLanguageService gameLanguage, ICardsManager cardsManager, ISkillsManager skillsManager, RainbowBattleConfiguration rainbowBattleConfiguration)
{
_gameLanguage = gameLanguage;
_cardsManager = cardsManager;
_skillsManager = skillsManager;
_rainbowBattleConfiguration = rainbowBattleConfiguration;
}
protected override async Task HandlePacketAsync(IClientSession session, UseAtSkillPacket packet)
{
IPlayerEntity character = session.PlayerEntity;
if (!character.CanFight() || packet == null)
{
session.SendCancelPacket(CancelType.NotInCombatMode);
session.SendDebugMessage("[U_AS] !canFight, packet null");
return;
}
if (session.CurrentMapInstance.IsPvp && session.CurrentMapInstance.PvpZone(session.PlayerEntity.PositionX, session.PlayerEntity.PositionY) &&
session.CurrentMapInstance.PvpZone(packet.MapX, packet.MapY))
{
session.SendCancelPacket(CancelType.NotInCombatMode);
session.SendDebugMessage("[U_AS] Character no-PvP zone / !map.IsPvp");
return;
}
if (session.CurrentMapInstance.IsBlockedZone(packet.MapX, packet.MapY))
{
session.SendDebugMessage("[U_AS] character.IsBlockedZone()");
session.SendCancelPacket(CancelType.NotInCombatMode);
return;
}
if (session.IsMuted())
{
session.SendMuteMessage();
session.SendCancelPacket(CancelType.NotInCombatMode);
return;
}
if (session.PlayerEntity.IsOnVehicle || session.PlayerEntity.CheatComponent.IsInvisible)
{
session.SendDebugMessage("[U_AS] character.IsVehicled, InvisibleGm");
session.SendCancelPacket(CancelType.NotInCombatMode);
return;
}
if (!session.PlayerEntity.CanPerformAttack())
{
session.SendDebugMessage("[U_AS] !CanPerformAttack");
session.SendCancelPacket(CancelType.NotInCombatMode);
return;
}
if ((DateTime.UtcNow - session.PlayerEntity.LastTransform).TotalSeconds < 3)
{
session.SendDebugMessage("[U_AS] Under transformation cooldown");
session.SendCancelPacket(CancelType.NotInCombatMode);
session.SendMsg(_gameLanguage.GetLanguage(GameDialogKey.SPECIALIST_SHOUTMESSAGE_CANT_ATTACK_YET, session.UserLanguage), MsgMessageType.Middle);
return;
}
if (character.IsCastingSkill)
{
session.SendCancelPacket(CancelType.NotInCombatMode);
session.SendDebugMessage("[U_AS] Already using a skill");
return;
}
List<IBattleEntitySkill> skills = session.PlayerEntity.Skills;
var characterSkill = skills.FirstOrDefault(s => s.Skill?.CastId == packet.CastId &&
(s.Skill?.UpgradeSkill == 0 || s.Skill?.SkillType == SkillType.NormalPlayerSkill) && s.Skill.TargetType == TargetType.NonTarget) as CharacterSkill;
SkillDTO skill = characterSkill?.Skill;
if (skill == null)
{
session.SendDebugMessage("[U_AS] Skill does not exist");
session.SendCancelPacket(CancelType.NotInCombatMode);
return;
}
SkillInfo skillInfo = session.PlayerEntity.GetUpgradedSkill(skill, _cardsManager, _skillsManager) ?? skill.GetInfo();
bool canBeUsed = session.PlayerEntity.CharacterCanCastOrCancel(characterSkill, _gameLanguage, skillInfo, false);
if (!canBeUsed)
{
session.SendDebugMessage("[U_AS] !skill.canBeUsed");
return;
}
if (!session.PlayerEntity.CanPerformAttack(skillInfo))
{
session.SendCancelPacket(CancelType.NotInCombatMode);
return;
}
if (session.PlayerEntity.IsSitting)
{
await session.RestAsync();
}
var position = new Position(packet.MapX, packet.MapY);
if (!session.PlayerEntity.Position.IsInRange(position, skillInfo.Range + 3))
{
session.SendDebugMessage("[U_AS] !character.IsInRange");
session.SendCancelPacket(CancelType.NotInCombatMode);
return;
}
if (session.PlayerEntity.RainbowBattleComponent.IsFrozen)
{
session.SendCancelPacket(CancelType.NotInCombatMode);
return;
}
if (!session.PlayerEntity.CheatComponent.HasGodMode)
{
skillInfo.ManaCost = session.PlayerEntity.BCardComponent.HasBCard(BCardType.TimeCircleSkills, (byte)AdditionalTypes.TimeCircleSkills.DisableMPConsumption) ? 0 : skillInfo.ManaCost;
if (session.PlayerEntity.AdditionalMp > 0)
{
int removedAdditionalMp;
if (session.PlayerEntity.AdditionalMp > skillInfo.ManaCost)
{
removedAdditionalMp = skillInfo.ManaCost;
}
else
{
removedAdditionalMp = session.PlayerEntity.AdditionalMp;
int overflow = Math.Abs(session.PlayerEntity.AdditionalMp - skillInfo.ManaCost);
session.PlayerEntity.Mp -= overflow;
}
await session.EmitEventAsync(new RemoveAdditionalHpMpEvent
{
Mp = removedAdditionalMp
});
}
else
{
session.PlayerEntity.RemoveEntityMp((short)skillInfo.ManaCost, skill);
}
(int firstDataNegative, int _) = session.PlayerEntity.BCardComponent.GetAllBCardsInformation(BCardType.HealingBurningAndCasting,
(byte)AdditionalTypes.HealingBurningAndCasting.HPDecreasedByConsumingMP, session.PlayerEntity.Level);
(int firstDataPositive, int _) = session.PlayerEntity.BCardComponent.GetAllBCardsInformation(BCardType.HealingBurningAndCasting,
(byte)AdditionalTypes.HealingBurningAndCasting.HPIncreasedByConsumingMP, session.PlayerEntity.Level);
int hpRemoved = (int)(firstDataPositive / 100.0 * skillInfo.ManaCost - firstDataNegative / 100.0 * skillInfo.ManaCost);
if (hpRemoved > 0)
{
await session.PlayerEntity.EmitEventAsync(new BattleEntityHealEvent
{
Entity = session.PlayerEntity,
HpHeal = hpRemoved
});
}
else
{
if (session.PlayerEntity.Hp - hpRemoved <= 0)
{
session.PlayerEntity.BroadcastDamage(session.PlayerEntity.Hp - 1);
session.PlayerEntity.Hp = 1;
}
else
{
session.PlayerEntity.BroadcastDamage(hpRemoved);
session.PlayerEntity.Hp -= hpRemoved;
}
}
session.RefreshStat();
}
session.SendDebugMessage($"Hit {skill.HitType} / Target {skill.TargetType} / Attack Type {skill.AttackType} / Affected entities {skill.TargetAffectedEntities}");
session.SendCancelPacket(CancelType.NotInCombatMode);
session.PlayerEntity.CleanComboState();
session.SendMsCPacket(0);
session.RefreshQuicklist();
session.RefreshStat();
session.PlayerEntity.ClearFoodBuffer();
if (session.PlayerEntity.RainbowBattleComponent.IsInRainbowBattle)
{
session.PlayerEntity.RainbowBattleComponent.ActivityPoints += _rainbowBattleConfiguration.UsingSkillActivityPoints;
}
character.WeaponLoaded(characterSkill, _gameLanguage, true);
character.LastSkillUse = DateTime.UtcNow;
DateTime castTime = character.GenerateSkillCastTime(skillInfo);
character.SkillComponent.CanBeInterrupted = character.CanBeInterrupted(skillInfo);
await character.EmitEventAsync(new BattleExecuteSkillEvent(character, null, skillInfo, castTime, position));
}
}