### Summary - Add InteractiveTeleporter that teleports on double-click - Add support to decorate command - Add rope teleporters to the New Haven mines in the decoration file
1058 lines
25 KiB
C#
1058 lines
25 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using ModernUO.Serialization;
|
|
using Server.Mobiles;
|
|
using Server.Network;
|
|
using Server.Spells;
|
|
using Server.Text;
|
|
|
|
namespace Server.Items;
|
|
|
|
[Flags]
|
|
public enum TeleporterFlags
|
|
{
|
|
None = 0x00000000,
|
|
Active = 0x00000001,
|
|
Creatures = 0x00000002,
|
|
CombatCheck = 0x00000004,
|
|
CriminalCheck = 0x00000008,
|
|
SourceEffect = 0x00000010,
|
|
DestEffect = 0x00000020
|
|
}
|
|
|
|
[SerializationGenerator(5, false)]
|
|
public partial class Teleporter : Item
|
|
{
|
|
[InvalidateProperties]
|
|
[SerializableField(0)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private TeleporterFlags _flags;
|
|
|
|
[InvalidateProperties]
|
|
[SerializableField(1)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private TimeSpan _delay;
|
|
|
|
[EncodedInt]
|
|
[InvalidateProperties]
|
|
[SerializableField(2)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private int _soundID;
|
|
|
|
[InvalidateProperties]
|
|
[SerializableField(3)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private Point3D _pointDest;
|
|
|
|
[InvalidateProperties]
|
|
[SerializableField(4)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private Map _mapDest;
|
|
|
|
[Constructible]
|
|
public Teleporter() : this(new Point3D(0, 0, 0))
|
|
{
|
|
}
|
|
|
|
[Constructible]
|
|
public Teleporter(Point3D pointDest, Map mapDest = null, bool creatures = false) : base(0x1BC3)
|
|
{
|
|
Movable = false;
|
|
Visible = false;
|
|
|
|
_flags = TeleporterFlags.Active;
|
|
Creatures = creatures;
|
|
|
|
_pointDest = pointDest;
|
|
_mapDest = mapDest;
|
|
}
|
|
|
|
public bool GetFlag(TeleporterFlags flag) => (Flags & flag) != 0;
|
|
|
|
public void SetFlag(TeleporterFlags flag, bool value)
|
|
{
|
|
if (value)
|
|
{
|
|
Flags |= flag;
|
|
}
|
|
else
|
|
{
|
|
Flags &= ~flag;
|
|
}
|
|
|
|
InvalidateProperties();
|
|
this.MarkDirty();
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool SourceEffect
|
|
{
|
|
get => GetFlag(TeleporterFlags.SourceEffect);
|
|
set => SetFlag(TeleporterFlags.SourceEffect, value);
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DestEffect
|
|
{
|
|
get => GetFlag(TeleporterFlags.DestEffect);
|
|
set => SetFlag(TeleporterFlags.DestEffect, value);
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool Active
|
|
{
|
|
get => GetFlag(TeleporterFlags.Active);
|
|
set => SetFlag(TeleporterFlags.Active, value);
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool Creatures
|
|
{
|
|
get => GetFlag(TeleporterFlags.Creatures);
|
|
set => SetFlag(TeleporterFlags.Creatures, value);
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool CombatCheck
|
|
{
|
|
get => GetFlag(TeleporterFlags.CombatCheck);
|
|
set => SetFlag(TeleporterFlags.CombatCheck, value);
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool CriminalCheck
|
|
{
|
|
get => GetFlag(TeleporterFlags.CriminalCheck);
|
|
set => SetFlag(TeleporterFlags.CriminalCheck, value);
|
|
}
|
|
|
|
public override int LabelNumber => 1026095; // teleporter
|
|
|
|
public virtual void AddProperties(IPropertyList list)
|
|
{
|
|
if (Active)
|
|
{
|
|
list.Add(1060742); // active
|
|
}
|
|
else
|
|
{
|
|
list.Add(1060743); // inactive
|
|
}
|
|
|
|
if (_mapDest != null)
|
|
{
|
|
list.Add(1060658, $"{"Map"}\t{_mapDest}");
|
|
}
|
|
|
|
if (_pointDest != Point3D.Zero)
|
|
{
|
|
list.Add(1060659, $"{"Coords"}\t{_pointDest}");
|
|
}
|
|
|
|
list.Add(1060660, $"{"Creatures"}\t{(Creatures ? "Yes" : "No")}");
|
|
}
|
|
|
|
public override void GetProperties(IPropertyList list)
|
|
{
|
|
base.GetProperties(list);
|
|
AddProperties(list);
|
|
}
|
|
|
|
public override void OnSingleClick(Mobile from)
|
|
{
|
|
base.OnSingleClick(from);
|
|
|
|
if (Active)
|
|
{
|
|
if (_mapDest != null && _pointDest != Point3D.Zero)
|
|
{
|
|
LabelTo(from, $"{_pointDest} [{_mapDest}]");
|
|
}
|
|
else if (_mapDest != null)
|
|
{
|
|
LabelTo(from, $"[{_mapDest}]");
|
|
}
|
|
else if (_pointDest != Point3D.Zero)
|
|
{
|
|
LabelTo(from, _pointDest.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LabelTo(from, "(inactive)");
|
|
}
|
|
}
|
|
|
|
public virtual bool CanTeleport(Mobile m)
|
|
{
|
|
if (!Creatures && !m.Player)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (CriminalCheck && m.Criminal)
|
|
{
|
|
m.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily.
|
|
return false;
|
|
}
|
|
|
|
if (CombatCheck && SpellHelper.CheckCombat(m))
|
|
{
|
|
m.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle??
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public virtual void StartTeleport(Mobile m)
|
|
{
|
|
if (_delay == TimeSpan.Zero)
|
|
{
|
|
DoTeleport(m);
|
|
}
|
|
else
|
|
{
|
|
Timer.StartTimer(_delay, () => DoTeleport(m));
|
|
}
|
|
}
|
|
|
|
public virtual void DoTeleport(Mobile m)
|
|
{
|
|
var map = _mapDest;
|
|
|
|
if (map == null || map == Map.Internal)
|
|
{
|
|
map = m.Map;
|
|
}
|
|
|
|
var p = _pointDest;
|
|
|
|
if (p == Point3D.Zero)
|
|
{
|
|
p = m.Location;
|
|
}
|
|
|
|
BaseCreature.TeleportPets(m, p, map);
|
|
|
|
var sendEffect = !m.Hidden || m.AccessLevel == AccessLevel.Player;
|
|
|
|
if (SourceEffect && sendEffect)
|
|
{
|
|
Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10);
|
|
}
|
|
|
|
m.MoveToWorld(p, map);
|
|
|
|
if (DestEffect && sendEffect)
|
|
{
|
|
Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10);
|
|
}
|
|
|
|
if (_soundID > 0 && sendEffect)
|
|
{
|
|
Effects.PlaySound(m.Location, m.Map, _soundID);
|
|
}
|
|
}
|
|
|
|
public override bool OnMoveOver(Mobile m)
|
|
{
|
|
if (Active && CanTeleport(m))
|
|
{
|
|
StartTeleport(m);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void Deserialize(IGenericReader reader, int version)
|
|
{
|
|
if (reader.ReadBool())
|
|
{
|
|
_flags |= TeleporterFlags.CriminalCheck;
|
|
}
|
|
|
|
if (reader.ReadBool())
|
|
{
|
|
_flags |= TeleporterFlags.CombatCheck;
|
|
}
|
|
|
|
if (reader.ReadBool())
|
|
{
|
|
_flags |= TeleporterFlags.SourceEffect;
|
|
}
|
|
|
|
if (reader.ReadBool())
|
|
{
|
|
_flags |= TeleporterFlags.DestEffect;
|
|
}
|
|
|
|
_delay = reader.ReadTimeSpan();
|
|
_soundID = reader.ReadEncodedInt();
|
|
|
|
if (reader.ReadBool())
|
|
{
|
|
_flags |= TeleporterFlags.Creatures;
|
|
}
|
|
|
|
if (reader.ReadBool())
|
|
{
|
|
_flags |= TeleporterFlags.Active;
|
|
}
|
|
|
|
_pointDest = reader.ReadPoint3D();
|
|
_mapDest = reader.ReadMap();
|
|
}
|
|
}
|
|
|
|
[SerializationGenerator(1, false)]
|
|
public partial class SkillTeleporter : Teleporter
|
|
{
|
|
[InvalidateProperties]
|
|
[SerializableField(0)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private SkillName _skill;
|
|
|
|
[InvalidateProperties]
|
|
[SerializableField(1)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private double _required;
|
|
|
|
[CanBeNull]
|
|
[InvalidateProperties]
|
|
[SerializableField(2)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private TextDefinition _message;
|
|
|
|
[Constructible]
|
|
public SkillTeleporter()
|
|
{
|
|
}
|
|
|
|
public override bool CanTeleport(Mobile m)
|
|
{
|
|
if (!base.CanTeleport(m))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var sk = m.Skills[_skill];
|
|
|
|
if (sk?.Base >= _required)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (!m.BeginAction(this))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_message?.Number > 0)
|
|
{
|
|
m.NetState.SendMessageLocalized(
|
|
Serial,
|
|
ItemID,
|
|
MessageType.Regular,
|
|
0x3B2,
|
|
3,
|
|
_message.Number,
|
|
null
|
|
);
|
|
}
|
|
else if (!string.IsNullOrWhiteSpace(_message?.String))
|
|
{
|
|
m.NetState.SendMessage(
|
|
Serial,
|
|
ItemID,
|
|
MessageType.Regular,
|
|
0x3B2,
|
|
3,
|
|
false,
|
|
"ENU",
|
|
null,
|
|
_message.String
|
|
);
|
|
}
|
|
|
|
Timer.StartTimer(TimeSpan.FromSeconds(5.0), () => m.EndAction(this));
|
|
|
|
return false;
|
|
}
|
|
|
|
public override void AddProperties(IPropertyList list)
|
|
{
|
|
var skillIndex = (int)_skill;
|
|
string skillName;
|
|
|
|
if (skillIndex >= 0 && skillIndex < SkillInfo.Table.Length)
|
|
{
|
|
skillName = SkillInfo.Table[skillIndex].Name;
|
|
}
|
|
else
|
|
{
|
|
skillName = "(Invalid)";
|
|
}
|
|
|
|
list.Add(1060661, $"{skillName}\t{_required:F1}");
|
|
|
|
if (_message?.Number > 0)
|
|
{
|
|
list.Add(1060662, $"{"Message"}\t{_message.Number:#}");
|
|
}
|
|
else if (!string.IsNullOrWhiteSpace(_message?.String))
|
|
{
|
|
list.Add(1060662, $"{"Message"}\t{_message.String}");
|
|
}
|
|
}
|
|
|
|
private void Deserialize(IGenericReader reader, int version)
|
|
{
|
|
_skill = (SkillName)reader.ReadInt();
|
|
_required = reader.ReadDouble();
|
|
_message = reader.ReadString();
|
|
|
|
var localNumber = reader.ReadInt();
|
|
if (localNumber > 0)
|
|
{
|
|
_message = localNumber;
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializationGenerator(0, false)]
|
|
public partial class KeywordTeleporter : Teleporter
|
|
{
|
|
[SerializableField(0)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private string _substring;
|
|
|
|
[SerializableField(1)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private int _keyword;
|
|
|
|
[SerializableField(2)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private int _range;
|
|
|
|
[Constructible]
|
|
public KeywordTeleporter()
|
|
{
|
|
_keyword = -1;
|
|
_substring = null;
|
|
}
|
|
|
|
public override bool HandlesOnSpeech => true;
|
|
|
|
public override void OnSpeech(SpeechEventArgs e)
|
|
{
|
|
if (!e.Handled && Active)
|
|
{
|
|
var m = e.Mobile;
|
|
|
|
if (!m.InRange(GetWorldLocation(), _range))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var isMatch = false;
|
|
|
|
if (_keyword >= 0 && e.HasKeyword(_keyword))
|
|
{
|
|
isMatch = true;
|
|
}
|
|
else if (_substring != null && e.Speech.InsensitiveContains(_substring))
|
|
{
|
|
isMatch = true;
|
|
}
|
|
|
|
if (!isMatch || !CanTeleport(m))
|
|
{
|
|
return;
|
|
}
|
|
|
|
e.Handled = true;
|
|
StartTeleport(m);
|
|
}
|
|
}
|
|
|
|
public override void DoTeleport(Mobile m)
|
|
{
|
|
if (!m.InRange(GetWorldLocation(), _range) || m.Map != Map)
|
|
{
|
|
return;
|
|
}
|
|
|
|
base.DoTeleport(m);
|
|
}
|
|
|
|
public override bool OnMoveOver(Mobile m) => true;
|
|
|
|
public override void AddProperties(IPropertyList list)
|
|
{
|
|
list.Add(1060661, $"{"Range"}\t{_range}");
|
|
|
|
if (_keyword >= 0)
|
|
{
|
|
list.Add(1060662, $"{"Keyword"}\t{_keyword}");
|
|
}
|
|
|
|
if (_substring != null)
|
|
{
|
|
list.Add(1060663, $"{"Substring"}\t{_substring}");
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializationGenerator(1, false)]
|
|
public partial class WaitTeleporter : KeywordTeleporter
|
|
{
|
|
private static Dictionary<Mobile, TeleportingInfo> _table = new();
|
|
|
|
[CanBeNull]
|
|
[InvalidateProperties]
|
|
[SerializableField(0)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private TextDefinition _startMessage;
|
|
|
|
[CanBeNull]
|
|
[InvalidateProperties]
|
|
[SerializableField(1)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private TextDefinition _progressMessage;
|
|
|
|
[InvalidateProperties]
|
|
[SerializableField(2)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private bool _showTimeRemaining;
|
|
|
|
[Constructible]
|
|
public WaitTeleporter()
|
|
{
|
|
}
|
|
|
|
public static void Initialize()
|
|
{
|
|
EventSink.Logout += EventSink_Logout;
|
|
}
|
|
|
|
public static void EventSink_Logout(Mobile from)
|
|
{
|
|
if (from != null && _table.Remove(from, out var info))
|
|
{
|
|
info.TimerToken.Cancel();
|
|
}
|
|
}
|
|
|
|
public static string FormatTime(TimeSpan ts)
|
|
{
|
|
if (ts.TotalHours >= 1)
|
|
{
|
|
var h = (int)Math.Round(ts.TotalHours);
|
|
return $"{h} hour{(h == 1 ? "" : "s")}";
|
|
}
|
|
|
|
if (ts.TotalMinutes >= 1)
|
|
{
|
|
var m = (int)Math.Round(ts.TotalMinutes);
|
|
return $"{m} minute{(m == 1 ? "" : "s")}";
|
|
}
|
|
|
|
var s = Math.Max((int)Math.Round(ts.TotalSeconds), 0);
|
|
return $"{s} second{(s == 1 ? "" : "s")}";
|
|
}
|
|
|
|
public override void StartTeleport(Mobile m)
|
|
{
|
|
if (_table.TryGetValue(m, out var info))
|
|
{
|
|
if (info.Teleporter == this)
|
|
{
|
|
if (!m.BeginAction(this))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_progressMessage.SendMessageTo(m);
|
|
|
|
if (_showTimeRemaining)
|
|
{
|
|
m.SendMessage($"Time remaining: {FormatTime(info.TimerToken.Next - Core.Now)}");
|
|
}
|
|
|
|
Timer.StartTimer(TimeSpan.FromSeconds(5), () => m.EndAction(this));
|
|
|
|
return;
|
|
}
|
|
|
|
info.TimerToken.Cancel();
|
|
}
|
|
|
|
_startMessage.SendMessageTo(m);
|
|
|
|
if (Delay == TimeSpan.Zero)
|
|
{
|
|
DoTeleport(m);
|
|
}
|
|
else
|
|
{
|
|
Timer.StartTimer(Delay, () => DoTeleport(m), out var timerToken);
|
|
_table[m] = new TeleportingInfo(this, timerToken);
|
|
}
|
|
}
|
|
|
|
public override void DoTeleport(Mobile m)
|
|
{
|
|
_table.Remove(m);
|
|
|
|
base.DoTeleport(m);
|
|
}
|
|
|
|
private void Deserialize(IGenericReader reader, int version)
|
|
{
|
|
var number = reader.ReadInt();
|
|
var message = reader.ReadString();
|
|
|
|
_startMessage = number > 0 ? number : message;
|
|
|
|
number = reader.ReadInt();
|
|
message = reader.ReadString();
|
|
|
|
_progressMessage = number > 0 ? number : message;
|
|
|
|
_showTimeRemaining = reader.ReadBool();
|
|
}
|
|
|
|
private class TeleportingInfo
|
|
{
|
|
public TeleportingInfo(WaitTeleporter tele, TimerExecutionToken token)
|
|
{
|
|
Teleporter = tele;
|
|
TimerToken = token;
|
|
}
|
|
|
|
public WaitTeleporter Teleporter { get; }
|
|
|
|
public TimerExecutionToken TimerToken { get; }
|
|
}
|
|
}
|
|
|
|
[SerializationGenerator(1, false)]
|
|
public partial class TimeoutTeleporter : Teleporter
|
|
{
|
|
[SerializableField(0)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private TimeSpan _timeoutDelay;
|
|
|
|
private Dictionary<Mobile, TimerExecutionToken> _teleporting;
|
|
|
|
[Constructible]
|
|
public TimeoutTeleporter() : this(new Point3D(0, 0, 0))
|
|
{
|
|
}
|
|
|
|
[Constructible]
|
|
public TimeoutTeleporter(Point3D pointDest, Map mapDest = null, bool creatures = false)
|
|
: base(pointDest, mapDest, creatures) => _teleporting = new Dictionary<Mobile, TimerExecutionToken>();
|
|
|
|
public void StartTimer(Mobile m)
|
|
{
|
|
StartTimer(m, _timeoutDelay);
|
|
}
|
|
|
|
private void StartTimer(Mobile m, TimeSpan delay)
|
|
{
|
|
StopTimer(m);
|
|
Timer.StartTimer(delay, () => StartTeleport(m), out var timerToken);
|
|
_teleporting[m] = timerToken;
|
|
}
|
|
|
|
public void StopTimer(Mobile m)
|
|
{
|
|
if (_teleporting.Remove(m, out var t))
|
|
{
|
|
t.Cancel();
|
|
}
|
|
}
|
|
|
|
public override void DoTeleport(Mobile m)
|
|
{
|
|
_teleporting.Remove(m);
|
|
|
|
base.DoTeleport(m);
|
|
}
|
|
|
|
public override bool OnMoveOver(Mobile m)
|
|
{
|
|
if (Active)
|
|
{
|
|
if (!CanTeleport(m))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
StartTimer(m);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void Deserialize(IGenericReader reader, int version)
|
|
{
|
|
_timeoutDelay = reader.ReadTimeSpan();
|
|
_teleporting = new Dictionary<Mobile, TimerExecutionToken>();
|
|
|
|
var count = reader.ReadInt();
|
|
|
|
for (var i = 0; i < count; ++i)
|
|
{
|
|
reader.ReadEntity<Mobile>();
|
|
reader.ReadDateTime();
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializationGenerator(0, false)]
|
|
public partial class TimeoutGoal : Item
|
|
{
|
|
[SerializableField(0)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private TimeoutTeleporter _teleporter;
|
|
|
|
[Constructible]
|
|
public TimeoutGoal() : base(0x1822)
|
|
{
|
|
Movable = false;
|
|
Visible = false;
|
|
|
|
Hue = 1154;
|
|
}
|
|
|
|
public override string DefaultName => "timeout teleporter goal";
|
|
|
|
public override bool OnMoveOver(Mobile m)
|
|
{
|
|
Teleporter?.StopTimer(m);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
[SerializationGenerator(1, false)]
|
|
public partial class ConditionTeleporter : Teleporter
|
|
{
|
|
[SerializableField(0, getter: "protected", setter: "protected")]
|
|
private ConditionFlag _flags;
|
|
|
|
[Constructible]
|
|
public ConditionTeleporter()
|
|
{
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DenyMounted
|
|
{
|
|
get => GetFlag(ConditionFlag.DenyMounted);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.DenyMounted, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DenyFollowers
|
|
{
|
|
get => GetFlag(ConditionFlag.DenyFollowers);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.DenyFollowers, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DenyPackContents
|
|
{
|
|
get => GetFlag(ConditionFlag.DenyPackContents);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.DenyPackContents, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DenyHolding
|
|
{
|
|
get => GetFlag(ConditionFlag.DenyHolding);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.DenyHolding, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DenyEquipment
|
|
{
|
|
get => GetFlag(ConditionFlag.DenyEquipment);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.DenyEquipment, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DenyTransformed
|
|
{
|
|
get => GetFlag(ConditionFlag.DenyTransformed);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.DenyTransformed, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool StaffOnly
|
|
{
|
|
get => GetFlag(ConditionFlag.StaffOnly);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.StaffOnly, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DenyPackEthereals
|
|
{
|
|
get => GetFlag(ConditionFlag.DenyPackEthereals);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.DenyPackEthereals, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool DeadOnly
|
|
{
|
|
get => GetFlag(ConditionFlag.DeadOnly);
|
|
set
|
|
{
|
|
SetFlag(ConditionFlag.DeadOnly, value);
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
public override bool CanTeleport(Mobile m)
|
|
{
|
|
if (!base.CanTeleport(m))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.StaffOnly) && m.AccessLevel < AccessLevel.Counselor)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyMounted) && m.Mounted)
|
|
{
|
|
m.SendLocalizedMessage(1077252); // You must dismount before proceeding.
|
|
return false;
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyFollowers) && (m.Followers != 0 || m is PlayerMobile { AutoStabled.Count: > 0 }))
|
|
{
|
|
m.SendLocalizedMessage(1077250); // No pets permitted beyond this point.
|
|
return false;
|
|
}
|
|
|
|
var pack = m.Backpack;
|
|
|
|
if (pack != null)
|
|
{
|
|
if (GetFlag(ConditionFlag.DenyPackContents) && pack.TotalItems != 0)
|
|
{
|
|
m.SendMessage("You must empty your backpack before proceeding.");
|
|
return false;
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyPackEthereals) &&
|
|
pack.FindItemByType(new[] { typeof(EtherealMount), typeof(BaseImprisonedMobile) }) != null)
|
|
{
|
|
m.SendMessage("You must empty your backpack of ethereal mounts before proceeding.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyHolding) && m.Holding != null)
|
|
{
|
|
m.SendMessage("You must let go of what you are holding before proceeding.");
|
|
return false;
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyEquipment))
|
|
{
|
|
foreach (var item in m.Items)
|
|
{
|
|
switch (item.Layer)
|
|
{
|
|
case Layer.Hair:
|
|
case Layer.FacialHair:
|
|
case Layer.Backpack:
|
|
case Layer.Mount:
|
|
case Layer.Bank:
|
|
{
|
|
continue; // ignore
|
|
}
|
|
default:
|
|
{
|
|
m.SendMessage("You must remove all equipment before proceeding.");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyTransformed) && m.IsBodyMod)
|
|
{
|
|
m.SendMessage("You cannot go there in this form.");
|
|
return false;
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DeadOnly) && m.Alive)
|
|
{
|
|
m.SendLocalizedMessage(1060014); // Only the dead may pass.
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void AddProperties(IPropertyList list)
|
|
{
|
|
using var props = ValueStringBuilder.Create(128);
|
|
|
|
if (GetFlag(ConditionFlag.DenyMounted))
|
|
{
|
|
props.Append("<BR>Deny Mounted");
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyFollowers))
|
|
{
|
|
props.Append("<BR>Deny Followers");
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyPackContents))
|
|
{
|
|
props.Append("<BR>Deny Pack Contents");
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyPackEthereals))
|
|
{
|
|
props.Append("<BR>Deny Pack Ethereals");
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyHolding))
|
|
{
|
|
props.Append("<BR>Deny Holding");
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyEquipment))
|
|
{
|
|
props.Append("<BR>Deny Equipment");
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DenyTransformed))
|
|
{
|
|
props.Append("<BR>Deny Transformed");
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.StaffOnly))
|
|
{
|
|
props.Append("<BR>Staff Only");
|
|
}
|
|
|
|
if (GetFlag(ConditionFlag.DeadOnly))
|
|
{
|
|
props.Append("<BR>Dead Only");
|
|
}
|
|
|
|
if (props.Length != 0)
|
|
{
|
|
props.Remove(0, 4);
|
|
list.Add(props.ToString());
|
|
}
|
|
}
|
|
|
|
private void Deserialize(IGenericReader reader, int version)
|
|
{
|
|
_flags = (ConditionFlag)reader.ReadInt();
|
|
}
|
|
|
|
protected bool GetFlag(ConditionFlag flag) => (_flags & flag) != 0;
|
|
|
|
protected void SetFlag(ConditionFlag flag, bool value)
|
|
{
|
|
if (value)
|
|
{
|
|
_flags |= flag;
|
|
}
|
|
else
|
|
{
|
|
_flags &= ~flag;
|
|
}
|
|
}
|
|
|
|
[Flags]
|
|
protected enum ConditionFlag
|
|
{
|
|
None = 0x000,
|
|
DenyMounted = 0x001,
|
|
DenyFollowers = 0x002,
|
|
DenyPackContents = 0x004,
|
|
DenyHolding = 0x008,
|
|
DenyEquipment = 0x010,
|
|
DenyTransformed = 0x020,
|
|
StaffOnly = 0x040,
|
|
DenyPackEthereals = 0x080,
|
|
DeadOnly = 0x100
|
|
}
|
|
}
|
|
|
|
[SerializationGenerator(0, false)]
|
|
public partial class InteractionTeleporter : Teleporter
|
|
{
|
|
[Constructible]
|
|
public InteractionTeleporter()
|
|
{
|
|
Visible = true;
|
|
}
|
|
|
|
[Constructible]
|
|
public InteractionTeleporter(Point3D pointDest, Map mapDest = null) : base(pointDest, mapDest)
|
|
{
|
|
Visible = true;
|
|
}
|
|
|
|
public override bool OnMoveOver(Mobile m) => true;
|
|
|
|
public override void AddProperties(IPropertyList list) {}
|
|
|
|
public override void OnDoubleClick(Mobile m)
|
|
{
|
|
base.OnDoubleClick(m);
|
|
|
|
if (Active && CanTeleport(m) && m.InRange(GetWorldLocation(), 2))
|
|
{
|
|
StartTeleport(m);
|
|
}
|
|
}
|
|
|
|
public override void OnDoubleClickDead(Mobile m) => OnDoubleClick(m);
|
|
}
|