Files
abysmal-isle/Scripts/Services/MondainsLegacyQuests/BaseEscort.cs
Unstable Kitsune b918192e4e Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
2023-11-28 23:20:26 -05:00

418 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Server.ContextMenus;
using Server.Mobiles;
using Server.Services.Virtues;
namespace Server.Engines.Quests
{
public class BaseEscort : MondainQuester
{
private static readonly TimeSpan m_EscortDelay = TimeSpan.FromMinutes(5.0);
private static readonly Dictionary<Mobile, Mobile> m_EscortTable = new Dictionary<Mobile, Mobile>();
private Timer m_DeleteTimer;
private bool m_Checked;
public BaseQuest Quest { get; set; }
public DateTime LastSeenEscorter { get; set; }
public BaseEscort()
: base()
{
AI = AIType.AI_Melee;
FightMode = FightMode.Aggressor;
RangePerception = 22;
RangeFight = 1;
ActiveSpeed = 0.2;
PassiveSpeed = 1.0;
ControlSlots = 0;
}
public BaseEscort(Serial serial)
: base(serial)
{
}
public override bool InitialInnocent { get { return true; } }
public override bool IsInvulnerable { get { return false; } }
public override bool Commandable { get { return false; } }
public override Type[] Quests { get { return null; } }
public override bool CanAutoStable { get { return false; } }
public override bool CanDetectHidden { get { return false; } }
public override void OnTalk(PlayerMobile player)
{
if (AcceptEscorter(player))
base.OnTalk(player);
}
public override bool CanBeRenamedBy(Mobile from)
{
return (from.AccessLevel >= AccessLevel.GameMaster);
}
public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
{
if (from.Alive && from == ControlMaster)
list.Add(new AbandonEscortEntry(this));
base.AddCustomContextEntries(from, list);
}
public override void OnAfterDelete()
{
if (Quest != null)
{
Quest.RemoveQuest();
if (Quest.Owner != null)
m_EscortTable.Remove(Quest.Owner);
}
base.OnAfterDelete();
}
public override void OnThink()
{
base.OnThink();
CheckAtDestination();
}
public override bool CanBeDamaged()
{
return true;
}
public override void InitBody()
{
SetStr(90, 100);
SetDex(90, 100);
SetInt(15, 25);
Hue = Utility.RandomSkinHue();
Female = Utility.RandomBool();
Name = NameList.RandomName(Female ? "female" : "male");
Race = Race.Human;
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write(m_DeleteTimer != null);
if (m_DeleteTimer != null)
writer.WriteDeltaTime(m_DeleteTimer.Next);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (reader.ReadBool())
{
DateTime deleteTime = reader.ReadDeltaTime();
m_DeleteTimer = Timer.DelayCall(deleteTime - DateTime.UtcNow, new TimerCallback(Delete));
}
}
public void AddHash(PlayerMobile player)
{
m_EscortTable[player] = this;
}
public virtual void StartFollow()
{
StartFollow(ControlMaster);
}
public virtual void StartFollow(Mobile escorter)
{
ActiveSpeed = 0.1;
PassiveSpeed = 0.2;
ControlOrder = OrderType.Follow;
ControlTarget = escorter;
CurrentSpeed = 0.1;
}
public virtual void StopFollow()
{
ActiveSpeed = 0.2;
PassiveSpeed = 1.0;
ControlOrder = OrderType.None;
ControlTarget = null;
CurrentSpeed = 1.0;
SetControlMaster(null);
}
public virtual void BeginDelete(Mobile m)
{
StopFollow();
if (m != null)
m_EscortTable.Remove(m);
m_DeleteTimer = Timer.DelayCall(TimeSpan.FromSeconds(45.0), new TimerCallback(Delete));
}
public virtual bool AcceptEscorter(Mobile m)
{
if (!m.Alive)
{
return false;
}
else if (m_DeleteTimer != null)
{
Say(500898); // I am sorry, but I do not wish to go anywhere.
return false;
}
else if (Controlled)
{
if (m == ControlMaster)
m.SendGump(new MondainQuestGump(Quest, MondainQuestGump.Section.InProgress, false));
else
Say(500897); // I am already being led!
return false;
}
else if (!m.InRange(Location, 5))
{
Say(500348); // I am too far away to do that.
return false;
}
else if (m_EscortTable.ContainsKey(m))
{
Say(500896); // I see you already have an escort.
return false;
}
else if (m is PlayerMobile && (((PlayerMobile)m).LastEscortTime + m_EscortDelay) >= DateTime.UtcNow)
{
int minutes = (int)Math.Ceiling(((((PlayerMobile)m).LastEscortTime + m_EscortDelay) - DateTime.UtcNow).TotalMinutes);
Say("You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s");
return false;
}
return true;
}
public virtual EscortObjective GetObjective()
{
if (Quest != null)
{
for (int i = 0; i < Quest.Objectives.Count; i++)
{
EscortObjective escort = Quest.Objectives[i] as EscortObjective;
if (escort != null && !escort.Completed && !escort.Failed)
return escort;
}
}
return null;
}
public virtual Mobile GetEscorter()
{
Mobile master = ControlMaster;
if (master == null || !Controlled)
{
return master;
}
else if (master.Map != Map || !master.InRange(Location, 30) || !master.Alive)
{
TimeSpan lastSeenDelay = DateTime.UtcNow - LastSeenEscorter;
if (lastSeenDelay >= TimeSpan.FromMinutes(2.0))
{
EscortObjective escort = GetObjective();
if (escort != null)
{
master.SendLocalizedMessage(1071194); // You have failed your escort quest…
master.PlaySound(0x5B3);
escort.Fail();
}
master.SendLocalizedMessage(1042473); // You have lost the person you were escorting.
Say(1005653); // Hmmm. I seem to have lost my master.
StopFollow();
m_EscortTable.Remove(master);
m_DeleteTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerCallback(Delete));
return null;
}
else
{
ControlOrder = OrderType.Stay;
}
}
else
{
if (ControlOrder != OrderType.Follow)
StartFollow(master);
LastSeenEscorter = DateTime.UtcNow;
}
return master;
}
public virtual Region GetDestination()
{
return null;
}
public virtual bool CheckAtDestination()
{
if (Quest != null)
{
EscortObjective escort = GetObjective();
if (escort == null)
return false;
Mobile escorter = GetEscorter();
if (escorter == null)
return false;
if (escort.Region != null && escort.Region.Contains(Location))
{
Say(1042809, escorter.Name); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay.
escort.Complete();
if (Quest.Completed)
{
escorter.SendLocalizedMessage(1046258, null, 0x23); // Your quest is complete.
if (QuestHelper.AnyRewards(Quest))
escorter.SendGump(new MondainQuestGump(Quest, MondainQuestGump.Section.Rewards, false, true));
else
Quest.GiveRewards();
escorter.PlaySound(Quest.CompleteSound);
StopFollow();
m_EscortTable.Remove(escorter);
m_DeleteTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerCallback(Delete));
// fame
Misc.Titles.AwardFame(escorter, escort.Fame, true);
// compassion
bool gainedPath = false;
PlayerMobile pm = escorter as PlayerMobile;
if (pm != null)
{
if (pm.CompassionGains > 0 && DateTime.UtcNow > pm.NextCompassionDay)
{
pm.NextCompassionDay = DateTime.MinValue;
pm.CompassionGains = 0;
}
if (pm.CompassionGains >= 5) // have already gained 5 times in one day, can gain no more
{
pm.SendLocalizedMessage(1053004); // You must wait about a day before you can gain in compassion again.
}
else if (VirtueHelper.Award(pm, VirtueName.Compassion, escort.Compassion, ref gainedPath))
{
pm.SendLocalizedMessage(1074949, null, 0x2A); // You have demonstrated your compassion! Your kind actions have been noted.
if (gainedPath)
pm.SendLocalizedMessage(1053005); // You have achieved a path in compassion!
else
pm.SendLocalizedMessage(1053002); // You have gained in compassion.
pm.NextCompassionDay = DateTime.UtcNow + TimeSpan.FromDays(1.0); // in one day CompassionGains gets reset to 0
++pm.CompassionGains;
}
else
{
pm.SendLocalizedMessage(1053003); // You have achieved the highest path of compassion and can no longer gain any further.
}
}
}
else
{
escorter.PlaySound(Quest.UpdateSound);
}
return true;
}
}
else if (!m_Checked)
{
Region region = GetDestination();
if (region != null && region.Contains(Location))
{
m_DeleteTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerCallback(Delete));
m_Checked = true;
}
}
return false;
}
private class AbandonEscortEntry : ContextMenuEntry
{
private readonly BaseEscort m_Mobile;
public AbandonEscortEntry(BaseEscort m)
: base(6102, 3)
{
m_Mobile = m;
}
public override void OnClick()
{
Owner.From.SendLocalizedMessage(1071194); // You have failed your escort quest…
Owner.From.PlaySound(0x5B3);
m_Mobile.Delete();
}
}
public static void DeleteEscort(Mobile owner)
{
PlayerMobile pm = owner as PlayerMobile;
foreach (var escortquest in pm.Quests.Where(x => x.Quester is BaseEscort))
{
BaseEscort escort = (BaseEscort)escortquest.Quester;
Timer.DelayCall(TimeSpan.FromSeconds(3), new TimerCallback(
delegate
{
escort.Say(500901); // Ack! My escort has come to haunt me!
owner.SendLocalizedMessage(1071194); // You have failed your escort quest…
owner.PlaySound(0x5B3);
escort.Delete();
}));
}
}
}
}