// // UseSkillOperation.cs // // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Xml.XPath; using NosSmooth.Extensions.Combat.Errors; using NosSmooth.Game.Data.Characters; using NosSmooth.Game.Data.Entities; using NosSmooth.Packets.Client.Battle; using Remora.Results; namespace NosSmooth.Extensions.Combat.Operations; /// /// A combat operation to use a skill. /// /// The skill to use. /// The target entity to use the skill at. public record UseSkillOperation(Skill Skill, ILivingEntity Target) : ICombatOperation { /// public Result CanBeUsed(ICombatState combatState) { if (Skill.Info is null) { return new MissingInfoError("skill", Skill.SkillVNum); } var character = combatState.Game.Character; if (character is not null && character.Mp is not null && character.Mp.Amount is not null) { if (character.Mp.Amount < Skill.Info.MpCost) { // The character is in combat, mp won't restore. return CanBeUsedResponse.WontBeUsable; } } return Skill.IsOnCooldown ? CanBeUsedResponse.MustWait : CanBeUsedResponse.CanBeUsed; } /// public async Task UseAsync(ICombatState combatState, CancellationToken ct = default) { if (Skill.Info is null) { return new MissingInfoError("skill", Skill.SkillVNum); } // TODO: support for area skills, support skills that use x, y coordinates (like dashes or teleports) using var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(ct); await combatState.CombatManager.RegisterSkillCancellationTokenAsync(linkedSource, ct); var sendResponse = await combatState.Client.SendPacketAsync ( new UseSkillPacket ( Skill.Info.CastId, Target.Type, Target.Id, null, null ), ct ); if (!sendResponse.IsSuccess) { await combatState.CombatManager.UnregisterSkillCancellationTokenAsync(linkedSource, ct); return sendResponse; } try { // wait 10 times the cast delay in case su is not received. await Task.Delay(Skill.Info.CastTime * 1000, linkedSource.Token); } catch (TaskCanceledException) { // ignored } await combatState.CombatManager.UnregisterSkillCancellationTokenAsync(linkedSource, ct); await Task.Delay(1000, ct); return Result.FromSuccess(); } }