// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.GameLogic.PlayerActions; using MUnique.OpenMU.GameLogic.Views.World; using MUnique.OpenMU.Pathfinding; /// /// Action to warp to another place through a gate. /// public class WizardTeleportAction { private const ushort TeleportSkillId = 6; private const ushort TeleportTargetSkillId = 15; private static readonly byte[] PreventingMagicEffects = { 0x39, // Stone 0x3D, // Stun 0x48, // Sleep 0x92, // Freeze2 0x93, // Earth Binds }; /// /// Tries to teleport to the specified target with the teleport skill. /// /// The player. /// The target. public async ValueTask TryTeleportWithSkillAsync(Player player, Point target) { // todo: additional checks: // - During castle siege, can't teleport over the non-destroyed gates (simple y-axis check) if (!player.IsAtSafezone() && player.IsActive() && player.SkillList?.GetSkill(TeleportSkillId) is { Skill: { } skill } && player.CurrentMap!.Terrain.WalkMap[target.X, target.Y] && !player.CurrentMap.Terrain.SafezoneMap[target.X, target.Y] && player.IsInRange(target, skill.Range) && CanPlayerBeTeleported(player) && await player.TryConsumeForSkillAsync(skill).ConfigureAwait(false)) { _ = Task.Run(() => player.TeleportAsync(target, skill)); } else { await player.InvokeViewPlugInAsync(p => p.ShowTeleportedAsync()).ConfigureAwait(false); } } /// /// Tries to teleport the target with the 'Teleport Ally' skill. /// /// The player. /// The target identifier. /// The target. public async ValueTask TryTeleportTargetWithSkillAsync(Player player, ushort targetId, Point target) { if (!player.IsAtSafezone() && player.IsActive() && player.SkillList?.GetSkill(TeleportTargetSkillId) is { Skill: { } skill } && player.Party is not null && player.CurrentMap!.Terrain.WalkMap[target.X, target.Y] && !player.CurrentMap.Terrain.SafezoneMap[target.X, target.Y] && await player.GetObservingPlayerWithIdAsync(targetId).ConfigureAwait(false) is { } targetPlayer && targetPlayer.Party == player.Party && targetPlayer.IsActive() && CanPlayerBeTeleported(targetPlayer) && targetPlayer.IsInRange(target, skill.Range + 1) && await player.TryConsumeForSkillAsync(skill).ConfigureAwait(false)) { _ = Task.Run(() => targetPlayer.TeleportAsync(target, skill)); } } private static bool CanPlayerBeTeleported(Player player) { var currentEffects = player.MagicEffectList.ActiveEffects; if (currentEffects.Count == 0) { return true; } for (int i = 0; i < PreventingMagicEffects.Length; i++) { if (currentEffects.ContainsKey(PreventingMagicEffects[i])) { return false; } } return true; } }