// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.GameLogic.PlayerActions.Skills; using System.Runtime.InteropServices; using MUnique.OpenMU.GameLogic.GuildWar; using MUnique.OpenMU.GameLogic.NPC; using MUnique.OpenMU.GameLogic.PlugIns; using MUnique.OpenMU.Pathfinding; using MUnique.OpenMU.PlugIns; /// /// Handles the dragon roar skill of the rage fighter class. Additionally to the attacked target, it will hit up to seven additional targets. /// [PlugIn] [Display(Name = nameof(PlugInResources.DragonRoarSkillPlugIn_Name), Description = nameof(PlugInResources.DragonRoarSkillPlugIn_Description), ResourceType = typeof(PlugInResources))] [Guid("A797A6AD-AC92-4731-A0FB-D46D4C1DD0DF")] public class DragonRoarSkillPlugIn : IAreaSkillPlugIn { /// public virtual short Key => 264; /// /// Gets the range around the target, in which additional targets are searched. /// protected virtual short Range => 3; /// public async ValueTask AfterTargetGotAttackedAsync(IAttacker attacker, IAttackable target, SkillEntry skillEntry, Point targetAreaCenter, HitInfo? hitInfo) { bool FilterTarget(IAttackable attackable) { if (attackable == target) { return false; } if (attackable is Monster { SummonedBy: null } or Destructible) { return true; } if (attackable is Monster { SummonedBy: not null } summoned) { return FilterTarget(summoned.SummonedBy); } if (attackable is Player { DuelRoom.State: DuelState.DuelStarted } targetPlayer && attacker is Player { DuelRoom.State: DuelState.DuelStarted } duelPlayer && targetPlayer.DuelRoom == duelPlayer.DuelRoom && targetPlayer.DuelRoom.IsDuelist(targetPlayer) && targetPlayer.DuelRoom.IsDuelist(duelPlayer)) { return true; } if (attackable is Player { GuildWarContext.State: GuildWarState.Started } guildWarTarget && attacker is Player { GuildWarContext.State: GuildWarState.Started } guildWarAttacker && guildWarTarget.GuildWarContext == guildWarAttacker.GuildWarContext) { return true; } return false; } var extraTargets = target.CurrentMap?.GetAttackablesInRange(target.Position, this.Range).Where(FilterTarget).Take(7); if (extraTargets is null) { return; } int i = 1; var skill = skillEntry.Skill!; foreach (var extraTarget in extraTargets) { if (i <= 3 || Rand.NextRandomBool()) { // first three 100% chance, others 50% chance await extraTarget.AttackByAsync(attacker, skillEntry, false, 1, false).ConfigureAwait(false); await extraTarget.TryApplyElementalEffectsAsync(attacker, skillEntry).ConfigureAwait(false); for (int hit = 2; hit <= skill.NumberOfHitsPerAttack; hit++) { await extraTarget.AttackByAsync(attacker, skillEntry, false, 1, hit == skill.NumberOfHitsPerAttack).ConfigureAwait(false); } } i++; } } }