using System; using System.Runtime.CompilerServices; using Server.Gumps; using Server.Mobiles; using Server.Regions; using Server.Targeting; namespace Server.Engines.Virtues; public static class HonorVirtue { public static readonly TimeSpan UseDelay = TimeSpan.FromMinutes(5.0); public static void Initialize() { VirtueGump.Register(107, OnVirtueUsed); } private static void OnVirtueUsed(Mobile from) { if (from.Alive) { from.SendLocalizedMessage(1063160); // Target what you wish to honor. from.Target = new InternalTarget(); } } private static int GetHonorDuration(PlayerMobile from) => VirtueSystem.GetLevel(from, VirtueName.Honor) switch { VirtueLevel.Seeker => 30, VirtueLevel.Follower => 90, VirtueLevel.Knight => 300, _ => 0 }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool CanUse(VirtueContext context) => Core.Now - context.LastHonorUse >= UseDelay; private static void EmbraceHonor(PlayerMobile pm) { var virtues = VirtueSystem.GetVirtues(pm); if (virtues?.HonorActive == true) { pm.SendLocalizedMessage(1063230); // You must wait awhile before you can embrace honor again. return; } if (GetHonorDuration(pm) == 0) { pm.SendLocalizedMessage(1063234); // You do not have enough honor to do that return; } if (virtues != null) { var waitTime = Core.Now - virtues.LastHonorUse; if (waitTime < UseDelay) { var remainingTime = UseDelay - waitTime; var remainingMinutes = (int)Math.Ceiling(remainingTime.TotalMinutes); // You must wait ~1_HONOR_WAIT~ minutes before embracing honor again pm.SendLocalizedMessage(1063240, remainingMinutes.ToString()); return; } } pm.SendGump(new HonorSelfGump(pm)); } public static void ActivateEmbrace(PlayerMobile pm) { var duration = GetHonorDuration(pm); var virtues = VirtueSystem.GetOrCreateVirtues(pm); var usedPoints = virtues.Honor switch { < 4399 => 400, < 10599 => 600, _ => 1000 }; VirtueSystem.Atrophy(pm, VirtueName.Honor, usedPoints); virtues.HonorActive = true; pm.SendLocalizedMessage(1063235); // You embrace your honor Timer.DelayCall( TimeSpan.FromSeconds(duration), m => { // We get the virtues again, in case it was deleted/dereferenced var v = VirtueSystem.GetOrCreateVirtues(m); v.HonorActive = false; v.LastHonorUse = Core.Now; m.SendLocalizedMessage(1063236); // You no longer embrace your honor }, pm ); } private static void Honor(PlayerMobile source, Mobile target) { if (target is not IHonorTarget honorTarget) { return; } var reg = source.Region.GetRegion(); var map = source.Map; if (honorTarget.ReceivedHonorContext != null) { if (honorTarget.ReceivedHonorContext.Source == source) { return; } if (honorTarget.ReceivedHonorContext.CheckDistance()) { source.SendLocalizedMessage(1063233); // Somebody else is honoring this opponent return; } } if (Core.ML && target is PlayerMobile) { source.SendLocalizedMessage(1075614); // You cannot honor other players. return; } if (target.Hits < target.HitsMax) { source.SendLocalizedMessage(1063166); // You cannot honor this monster because it is too damaged. return; } // Allow honor on blue if not in a guarded region or blue in Felucca if (target.Body.IsHuman && (target is not BaseCreature cret || !cret.AlwaysAttackable && !cret.AlwaysMurderer) && reg?.IsDisabled() == true && (map?.Rules & MapRules.HarmfulRestrictions) != 0) { source.SendLocalizedMessage(1001018); // You cannot perform negative acts return; } source.SentHonorContext?.Cancel(); _ = new HonorContext(source, target); source.Direction = source.GetDirectionTo(target); if (!source.Mounted) { source.Animate(32, 5, 1, true, true, 0); } } private class InternalTarget : Target { public InternalTarget() : base(12, false, TargetFlags.None) => CheckLOS = true; protected override void OnTarget(Mobile from, object targeted) { if (from is not PlayerMobile pm) { return; } if (targeted == pm) { EmbraceHonor(pm); } else if (targeted is Mobile mobile) { Honor(pm, mobile); } } protected override void OnTargetOutOfRange(Mobile from, object targeted) { from.SendLocalizedMessage(1063232); // You are too far away to honor your opponent } } }