ModernUO/ToAdd/SecretDoorLink.cs

239 lines
7.5 KiB
C#

using System;
using ModernUO.Serialization;
using Server;
using Server.Commands;
using Server.Items;
using Server.Targeting;
namespace Server.Items
{
[SerializationGenerator(0, false)]
public partial class SecretDoorLink : Item
{
[SerializableField(0)]
private Serial _triggerSerial;
[SerializableField(1)]
private Serial _secretSerial;
[SerializableField(2)]
private Point3D _triggerSpot;
[SerializableField(3)]
private Map _triggerMap;
[SerializableField(4)]
private Point3D _secretHomeLoc;
[SerializableField(5)]
private Map _secretHomeMap;
[SerializableField(6)]
private bool _secretIsHidden;
private Timer _timer;
[Constructible]
public SecretDoorLink() : base(0x1F14)
{
Name = "Secret Door Link (controller)";
Movable = true;
StartTimer();
}
// ✅ This is the key fix for "doesn't work after restart"
[AfterDeserialization(false)]
private void AfterDeserialization()
{
StartTimer();
Timer.DelayCall(TimeSpan.Zero, Tick);
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
_timer?.Stop();
_timer = null;
}
private void StartTimer()
{
_timer?.Stop();
_timer = Timer.DelayCall(TimeSpan.FromMilliseconds(400), TimeSpan.FromMilliseconds(400), Tick);
}
private Item TriggerItem => _triggerSerial.IsValid ? World.FindItem(_triggerSerial) : null;
private Item SecretItem => _secretSerial.IsValid ? World.FindItem(_secretSerial) : null;
private void Tick()
{
if (!_triggerSerial.IsValid || !_secretSerial.IsValid)
return;
var trigger = TriggerItem;
var secret = SecretItem;
if (trigger == null || trigger.Deleted || secret == null || secret.Deleted)
return;
if (_triggerMap == null || _secretHomeMap == null)
return;
bool onSpot =
trigger.Map == _triggerMap &&
trigger.Location == _triggerSpot;
// REVERSED behavior:
// Trigger ON spot => secret disappears
// Trigger OFF spot => secret appears
if (onSpot)
HideSecret(secret);
else
ShowSecret(secret);
}
private void ShowSecret(Item secret)
{
if (!_secretIsHidden)
return;
secret.MoveToWorld(_secretHomeLoc, _secretHomeMap);
secret.Visible = true;
_secretIsHidden = false;
}
private void HideSecret(Item secret)
{
if (_secretIsHidden)
return;
secret.Visible = false;
secret.MoveToWorld(Point3D.Zero, Map.Internal);
_secretIsHidden = true;
}
// ---------- GM Commands ----------
public static void Initialize()
{
CommandSystem.Register("SecretDoorLink", AccessLevel.GameMaster, SecretDoorLinkCommand);
CommandSystem.Register("SecretDoorStatus", AccessLevel.GameMaster, SecretDoorStatusCommand);
}
[Usage("SecretDoorLink")]
[Description("Links a trigger item to a secret item that disappears when the trigger is placed on a chosen tile, and reappears when moved off.")]
private static void SecretDoorLinkCommand(CommandEventArgs e)
{
e.Mobile.SendMessage("Target the TRIGGER item (the one you will move).");
e.Mobile.Target = new PickTriggerTarget();
}
[Usage("SecretDoorStatus")]
[Description("Target a SecretDoorLink controller to print its configuration.")]
private static void SecretDoorStatusCommand(CommandEventArgs e)
{
e.Mobile.SendMessage("Target the SecretDoorLink controller.");
e.Mobile.Target = new StatusTarget();
}
private class PickTriggerTarget : Target
{
public PickTriggerTarget() : base(12, false, TargetFlags.None) { }
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is not Item trigger || trigger.Deleted)
{
from.SendMessage("That is not a valid item.");
return;
}
from.SendMessage("Now target the SECRET item (the door/item that will appear/disappear).");
from.Target = new PickSecretTarget(trigger);
}
}
private class PickSecretTarget : Target
{
private readonly Item _trigger;
public PickSecretTarget(Item trigger) : base(12, false, TargetFlags.None)
{
_trigger = trigger;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is not Item secret || secret.Deleted)
{
from.SendMessage("That is not a valid item.");
return;
}
from.SendMessage("Now target the LOCATION (ground tile) where the trigger must be placed.");
from.Target = new PickLocationTarget(_trigger, secret);
}
}
private class PickLocationTarget : Target
{
private readonly Item _trigger;
private readonly Item _secret;
public PickLocationTarget(Item trigger, Item secret) : base(18, true, TargetFlags.None)
{
_trigger = trigger;
_secret = secret;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is not IPoint3D p)
{
from.SendMessage("Invalid location.");
return;
}
var map = from.Map;
var controller = new SecretDoorLink
{
_triggerSerial = _trigger.Serial,
_secretSerial = _secret.Serial,
_triggerSpot = new Point3D(p),
_triggerMap = map,
_secretHomeLoc = _secret.Location,
_secretHomeMap = _secret.Map,
_secretIsHidden = false
};
controller.MoveToWorld(from.Location, from.Map);
// Force initial evaluation
controller.Tick();
from.SendMessage("Linked! Trigger ON spot => secret disappears. Trigger OFF spot => secret appears.");
}
}
private class StatusTarget : Target
{
public StatusTarget() : base(12, false, TargetFlags.None) { }
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is not SecretDoorLink link || link.Deleted)
{
from.SendMessage("That is not a SecretDoorLink controller.");
return;
}
from.SendMessage($"Trigger: {link._triggerSerial} Secret: {link._secretSerial}");
from.SendMessage($"Spot: {link._triggerSpot} on {link._triggerMap}");
from.SendMessage($"Secret home: {link._secretHomeLoc} on {link._secretHomeMap}");
from.SendMessage($"Hidden now: {link._secretIsHidden}");
}
}
}
}