ModernUO/Projects/UOContent/Multis/Boats/Plank.cs
Kamron Batman fb915992dd
fix(core): Adds Hashed & Hierarchical Timer Wheel (#655)
- Removes TimerPriority
- Removes TimerThread
- Adds a [Hashed & Hierarchical Timer Wheel](http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf)
2021-07-11 22:42:06 -07:00

357 lines
9.7 KiB
C#

using System;
using Server.Factions;
using Server.Multis;
using Server.Network;
using Server.Spells;
namespace Server.Items
{
public enum PlankSide
{
Port,
Starboard
}
public class Plank : Item, ILockable
{
private Timer m_CloseTimer;
public Plank(BaseBoat boat, PlankSide side, uint keyValue) : base(0x3EB1 + (int)side)
{
Boat = boat;
Side = side;
KeyValue = keyValue;
Locked = true;
Movable = false;
}
public Plank(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public BaseBoat Boat { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public PlankSide Side { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public bool IsOpen => ItemID == 0x3ED5 || ItemID == 0x3ED4 || ItemID == 0x3E84 || ItemID == 0x3E89;
[CommandProperty(AccessLevel.GameMaster)]
public bool Starboard => Side == PlankSide.Starboard;
[CommandProperty(AccessLevel.GameMaster)]
public bool Locked { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public uint KeyValue { get; set; }
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(Boat);
writer.Write((int)Side);
writer.Write(Locked);
writer.Write(KeyValue);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
switch (version)
{
case 0:
{
Boat = reader.ReadEntity<BaseBoat>();
Side = (PlankSide)reader.ReadInt();
Locked = reader.ReadBool();
KeyValue = reader.ReadUInt();
if (Boat == null)
{
Delete();
}
break;
}
}
if (IsOpen)
{
m_CloseTimer = new CloseTimer(this);
m_CloseTimer.Start();
}
}
public void SetFacing(Direction dir)
{
if (IsOpen)
{
ItemID = dir switch
{
Direction.North => Starboard ? 0x3ED4 : 0x3ED5,
Direction.East => Starboard ? 0x3E84 : 0x3E89,
Direction.South => Starboard ? 0x3ED5 : 0x3ED4,
Direction.West => Starboard ? 0x3E89 : 0x3E84,
_ => ItemID
};
}
else
{
ItemID = dir switch
{
Direction.North => Starboard ? 0x3EB2 : 0x3EB1,
Direction.East => Starboard ? 0x3E85 : 0x3E8A,
Direction.South => Starboard ? 0x3EB1 : 0x3EB2,
Direction.West => Starboard ? 0x3E8A : 0x3E85,
_ => ItemID
};
}
}
public void Open()
{
if (IsOpen || Deleted)
{
return;
}
m_CloseTimer?.Stop();
m_CloseTimer = new CloseTimer(this);
m_CloseTimer.Start();
ItemID = ItemID switch
{
0x3EB1 => 0x3ED5,
0x3E8A => 0x3E89,
0x3EB2 => 0x3ED4,
0x3E85 => 0x3E84,
_ => ItemID
};
Boat?.Refresh();
}
public override bool OnMoveOver(Mobile from)
{
if (IsOpen)
{
if (from is BaseFactionGuard)
{
return false;
}
if ((from.Direction & Direction.Running) != 0 || Boat?.Contains(from) == false)
{
return true;
}
var map = Map;
if (map == null)
{
return false;
}
int rx = 0, ry = 0;
if (ItemID == 0x3ED4)
{
rx = 1;
}
else if (ItemID == 0x3ED5)
{
rx = -1;
}
else if (ItemID == 0x3E84)
{
ry = 1;
}
else if (ItemID == 0x3E89)
{
ry = -1;
}
for (var i = 1; i <= 6; ++i)
{
var x = X + i * rx;
var y = Y + i * ry;
int z;
for (var j = -8; j <= 8; ++j)
{
z = from.Z + j;
if (map.CanFit(x, y, z, 16, false, false) && !SpellHelper.CheckMulti(new Point3D(x, y, z), map) &&
!Region.Find(new Point3D(x, y, z), map).IsPartOf<StrongholdRegion>())
{
if (i == 1 && j >= -2 && j <= 2)
{
return true;
}
from.Location = new Point3D(x, y, z);
return false;
}
}
z = map.GetAverageZ(x, y);
if (map.CanFit(x, y, z, 16, false, false) && !SpellHelper.CheckMulti(new Point3D(x, y, z), map) &&
!Region.Find(new Point3D(x, y, z), map).IsPartOf<StrongholdRegion>())
{
if (i == 1)
{
return true;
}
from.Location = new Point3D(x, y, z);
return false;
}
}
return true;
}
return false;
}
public bool CanClose()
{
if (Map == null || Deleted)
{
return false;
}
var eable = GetObjectsInRange(0);
foreach (var obj in eable)
{
if (obj == this)
{
eable.Free();
return true;
}
}
eable.Free();
return false;
}
public void Close()
{
if (!IsOpen || !CanClose() || Deleted)
{
return;
}
m_CloseTimer?.Stop();
m_CloseTimer = null;
ItemID = ItemID switch
{
0x3ED5 => 0x3EB1,
0x3E89 => 0x3E8A,
0x3ED4 => 0x3EB2,
0x3E84 => 0x3E85,
_ => ItemID
};
Boat?.Refresh();
}
public override void OnDoubleClickDead(Mobile from)
{
OnDoubleClick(from);
}
public override void OnDoubleClick(Mobile from)
{
if (Boat == null)
{
return;
}
if (from.InRange(GetWorldLocation(), 8))
{
if (Boat.Contains(from))
{
if (IsOpen)
{
Close();
}
else
{
Open();
}
}
else
{
if (!IsOpen)
{
if (!Locked)
{
Open();
}
else if (from.AccessLevel >= AccessLevel.GameMaster)
{
from.LocalOverheadMessage(
MessageType.Regular,
0x00,
502502
); // That is locked but your godly powers allow access
Open();
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 0x00, 502503); // That is locked.
}
}
else if (!Locked)
{
from.Location = new Point3D(X, Y, Z + 3);
}
else if (from.AccessLevel >= AccessLevel.GameMaster)
{
from.LocalOverheadMessage(
MessageType.Regular,
0x00,
502502
); // That is locked but your godly powers allow access
from.Location = new Point3D(X, Y, Z + 3);
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 0x00, 502503); // That is locked.
}
}
}
}
private class CloseTimer : Timer
{
private readonly Plank m_Plank;
public CloseTimer(Plank plank) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
{
m_Plank = plank;
}
protected override void OnTick()
{
m_Plank.Close();
}
}
}
}