fix: Fixes region priority and resolution. (#1254)

- [X] Fixes world location JSON deserializer.
- [X] Fixes region resolver and priorities.
- [X] Removes DynamicJson from regions.
- [X] Adds missing region music.
This commit is contained in:
Kamron Batman 2022-11-21 10:38:20 -08:00 committed by GitHub
parent 139be1bc23
commit 18c4459e6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 3809 additions and 3677 deletions

View file

@ -1,178 +1,170 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using Server.Gumps;
using Server.Json;
using Server.Mobiles;
using Server.Spells;
namespace Server.Regions
namespace Server.Regions;
public class BaseRegion : Region
{
public class BaseRegion : Region
private static readonly List<Rectangle3D> m_RectBuffer1 = new();
private static readonly List<Rectangle3D> m_RectBuffer2 = new();
public BaseRegion(string name, Map map, int priority, params Rectangle2D[] area) : base(name, map, priority, area)
{
private static readonly List<Rectangle3D> m_RectBuffer1 = new();
private static readonly List<Rectangle3D> m_RectBuffer2 = new();
}
public BaseRegion(string name, Map map, int priority, params Rectangle2D[] area) : base(name, map, priority, area)
{
}
public BaseRegion(string name, Map map, int priority, params Rectangle3D[] area) : base(name, map, priority, area)
{
}
public BaseRegion(string name, Map map, int priority, params Rectangle3D[] area) : base(name, map, priority, area)
{
}
public BaseRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
}
public BaseRegion(string name, Map map, Region parent, params Rectangle2D[] area) : base(name, map, parent, area)
{
}
public BaseRegion(string name, Map map, Region parent, params Rectangle2D[] area) : base(name, map, parent, area)
{
}
public BaseRegion(string name, Map map, Region parent, params Rectangle3D[] area) : base(name, map, parent, area)
{
}
public BaseRegion(string name, Map map, Region parent, params Rectangle3D[] area) : base(name, map, parent, area)
{
}
public BaseRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
public bool ExcludeFromParentSpawns { get; set; }
public Rectangle3D[] Rectangles { get; private set; }
public int[] RectangleWeights { get; private set; }
public int TotalWeight { get; private set; }
public virtual bool YoungProtected => true;
public virtual bool YoungMayEnter => true;
public virtual bool MountsAllowed => true;
public virtual bool DeadMayEnter => true;
public virtual bool ResurrectionAllowed => true;
public virtual bool LogoutAllowed => true;
public string RuneName { get; set; }
public bool NoLogoutDelay { get; set; }
public static string GetRuneNameFor(Region region)
{
while (region != null)
{
if (json.GetProperty<string>("rune", options, out var runeName))
var br = region as BaseRegion;
if (br?.RuneName != null)
{
RuneName = runeName;
return br.RuneName;
}
NoLogoutDelay = json.GetProperty<bool>("logoutDelay", options, out var logoutDelay) && !logoutDelay;
region = region.Parent;
}
public bool ExcludeFromParentSpawns { get; set; }
return null;
}
public Rectangle3D[] Rectangles { get; private set; }
public int[] RectangleWeights { get; private set; }
public int TotalWeight { get; private set; }
public override TimeSpan GetLogoutDelay(Mobile m) =>
NoLogoutDelay && m.Aggressors.Count == 0 && m.Aggressed.Count == 0 && !m.Criminal
? TimeSpan.Zero
: base.GetLogoutDelay(m);
public virtual bool YoungProtected => true;
public virtual bool YoungMayEnter => true;
public virtual bool MountsAllowed => true;
public virtual bool DeadMayEnter => true;
public virtual bool ResurrectionAllowed => true;
public virtual bool LogoutAllowed => true;
public string RuneName { get; set; }
public bool NoLogoutDelay { get; set; }
public static string GetRuneNameFor(Region region)
public override void OnEnter(Mobile m)
{
if (m is PlayerMobile mobile && mobile.Young && !YoungProtected)
{
while (region != null)
{
var br = region as BaseRegion;
mobile.SendGump(new YoungDungeonWarning());
}
}
if (br?.RuneName != null)
public override bool AcceptsSpawnsFrom(Region region) =>
(region == this || !ExcludeFromParentSpawns) && base.AcceptsSpawnsFrom(region);
// TODO: Clean this up
public void InitRectangles()
{
if (Rectangles != null)
{
return;
}
// Test if area rectangles are overlapping, and in that case break them into smaller non overlapping rectangles
for (var i = 0; i < Area.Length; i++)
{
m_RectBuffer2.Add(Area[i]);
for (var j = 0; j < m_RectBuffer1.Count && m_RectBuffer2.Count > 0; j++)
{
var comp = m_RectBuffer1[j];
for (var k = m_RectBuffer2.Count - 1; k >= 0; k--)
{
return br.RuneName;
}
var rect = m_RectBuffer2[k];
region = region.Parent;
}
int l1 = rect.Start.X, r1 = rect.End.X, t1 = rect.Start.Y, b1 = rect.End.Y;
int l2 = comp.Start.X, r2 = comp.End.X, t2 = comp.Start.Y, b2 = comp.End.Y;
return null;
}
public override TimeSpan GetLogoutDelay(Mobile m) =>
NoLogoutDelay && m.Aggressors.Count == 0 && m.Aggressed.Count == 0 && !m.Criminal
? TimeSpan.Zero
: base.GetLogoutDelay(m);
public override void OnEnter(Mobile m)
{
if (m is PlayerMobile mobile && mobile.Young && !YoungProtected)
{
mobile.SendGump(new YoungDungeonWarning());
}
}
public override bool AcceptsSpawnsFrom(Region region) =>
(region == this || !ExcludeFromParentSpawns) && base.AcceptsSpawnsFrom(region);
// TODO: Clean this up
public void InitRectangles()
{
if (Rectangles != null)
{
return;
}
// Test if area rectangles are overlapping, and in that case break them into smaller non overlapping rectangles
for (var i = 0; i < Area.Length; i++)
{
m_RectBuffer2.Add(Area[i]);
for (var j = 0; j < m_RectBuffer1.Count && m_RectBuffer2.Count > 0; j++)
{
var comp = m_RectBuffer1[j];
for (var k = m_RectBuffer2.Count - 1; k >= 0; k--)
if (l1 < r2 && r1 > l2 && t1 < b2 && b1 > t2)
{
var rect = m_RectBuffer2[k];
m_RectBuffer2.RemoveAt(k);
int l1 = rect.Start.X, r1 = rect.End.X, t1 = rect.Start.Y, b1 = rect.End.Y;
int l2 = comp.Start.X, r2 = comp.End.X, t2 = comp.Start.Y, b2 = comp.End.Y;
var sz = rect.Start.Z;
var ez = rect.End.X;
if (l1 < r2 && r1 > l2 && t1 < b2 && b1 > t2)
if (l1 < l2)
{
m_RectBuffer2.RemoveAt(k);
m_RectBuffer2.Add(new Rectangle3D(new Point3D(l1, t1, sz), new Point3D(l2, b1, ez)));
}
var sz = rect.Start.Z;
var ez = rect.End.X;
if (r1 > r2)
{
m_RectBuffer2.Add(new Rectangle3D(new Point3D(r2, t1, sz), new Point3D(r1, b1, ez)));
}
if (l1 < l2)
{
m_RectBuffer2.Add(new Rectangle3D(new Point3D(l1, t1, sz), new Point3D(l2, b1, ez)));
}
if (t1 < t2)
{
m_RectBuffer2.Add(
new Rectangle3D(
new Point3D(Math.Max(l1, l2), t1, sz),
new Point3D(Math.Min(r1, r2), t2, ez)
)
);
}
if (r1 > r2)
{
m_RectBuffer2.Add(new Rectangle3D(new Point3D(r2, t1, sz), new Point3D(r1, b1, ez)));
}
if (t1 < t2)
{
m_RectBuffer2.Add(
new Rectangle3D(
new Point3D(Math.Max(l1, l2), t1, sz),
new Point3D(Math.Min(r1, r2), t2, ez)
)
);
}
if (b1 > b2)
{
m_RectBuffer2.Add(
new Rectangle3D(
new Point3D(Math.Max(l1, l2), b2, sz),
new Point3D(Math.Min(r1, r2), b1, ez)
)
);
}
if (b1 > b2)
{
m_RectBuffer2.Add(
new Rectangle3D(
new Point3D(Math.Max(l1, l2), b2, sz),
new Point3D(Math.Min(r1, r2), b1, ez)
)
);
}
}
}
m_RectBuffer1.AddRange(m_RectBuffer2);
m_RectBuffer2.Clear();
}
Rectangles = m_RectBuffer1.ToArray();
m_RectBuffer1.Clear();
RectangleWeights = new int[Rectangles.Length];
for (var i = 0; i < Rectangles.Length; i++)
{
var rect = Rectangles[i];
var weight = rect.Width * rect.Height;
RectangleWeights[i] = weight;
TotalWeight += weight;
}
m_RectBuffer1.AddRange(m_RectBuffer2);
m_RectBuffer2.Clear();
}
public override string ToString() => Name ?? RuneName ?? GetType().Name;
Rectangles = m_RectBuffer1.ToArray();
m_RectBuffer1.Clear();
public virtual bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) => true;
RectangleWeights = new int[Rectangles.Length];
for (var i = 0; i < Rectangles.Length; i++)
{
var rect = Rectangles[i];
var weight = rect.Width * rect.Height;
RectangleWeights[i] = weight;
TotalWeight += weight;
}
}
public override string ToString() => Name ?? RuneName ?? GetType().Name;
public virtual bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) => true;
}

View file

@ -1,36 +1,26 @@
using System.Text.Json;
using Server.Json;
namespace Server.Regions;
namespace Server.Regions
public class DungeonRegion : BaseRegion
{
public class DungeonRegion : BaseRegion
public DungeonRegion(string name, Map map, Region parent, params Rectangle3D[] area) : base(name, map, parent, area)
{
public DungeonRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
{
if (json.GetProperty("map", options, out Map map))
{
EntranceMap = map;
}
if (json.GetProperty("entrance", options, out Point3D entrance))
{
EntranceLocation = entrance;
}
}
public override bool YoungProtected => false;
public Point3D EntranceLocation { get; set; }
public Map EntranceMap { get; set; }
public override bool AllowHousing(Mobile from, Point3D p) => false;
public override void AlterLightLevel(Mobile m, ref int global, ref int personal)
{
global = LightCycle.DungeonLevel;
}
public override bool CanUseStuckMenu(Mobile m) => Map != Map.Felucca && base.CanUseStuckMenu(m);
}
public DungeonRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
}
public override bool YoungProtected => false;
public Point3D Entrance { get; set; }
public override bool AllowHousing(Mobile from, Point3D p) => false;
public override void AlterLightLevel(Mobile m, ref int global, ref int personal)
{
global = LightCycle.DungeonLevel;
}
public override bool CanUseStuckMenu(Mobile m) => Map != Map.Felucca && base.CanUseStuckMenu(m);
}

View file

@ -1,31 +1,33 @@
using System.Text.Json;
using Server.Json;
using Server.Spells;
using Server.Spells.Sixth;
namespace Server.Regions
namespace Server.Regions;
public class GreenAcresRegion : BaseRegion
{
public class GreenAcresRegion : BaseRegion
public GreenAcresRegion(string name, Map map, Region parent, params Rectangle3D[] area) : base(name, map, parent, area)
{
public GreenAcresRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
}
public GreenAcresRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
}
public override bool AllowHousing(Mobile from, Point3D p) =>
from.AccessLevel != AccessLevel.Player && base.AllowHousing(from, p);
public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) =>
m.AccessLevel != AccessLevel.Player;
public override bool OnBeginSpellCast(Mobile m, ISpell s)
{
if (m.AccessLevel == AccessLevel.Player && s is MarkSpell)
{
m.SendLocalizedMessage(501802); // Thy spell doth not appear to work...
return false;
}
public override bool AllowHousing(Mobile from, Point3D p) =>
from.AccessLevel != AccessLevel.Player && base.AllowHousing(from, p);
public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) =>
m.AccessLevel != AccessLevel.Player;
public override bool OnBeginSpellCast(Mobile m, ISpell s)
{
if (m.AccessLevel == AccessLevel.Player && s is MarkSpell)
{
m.SendLocalizedMessage(501802); // Thy spell doth not appear to work...
return false;
}
return base.OnBeginSpellCast(m, s);
}
return base.OnBeginSpellCast(m, s);
}
}

View file

@ -1,131 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Server.Json;
using Server.Logging;
using Server.Mobiles;
using Server.Utilities;
namespace Server.Regions
namespace Server.Regions;
public class GuardedRegion : BaseRegion
{
public class GuardedRegion : BaseRegion
private static readonly ILogger logger = LogFactory.GetLogger(typeof(GuardedRegion));
private static readonly object[] m_GuardParams = new object[1];
private readonly Dictionary<Mobile, GuardTimer> m_GuardCandidates = new();
public GuardedRegion(string name, Map map, int priority, params Rectangle3D[] area) :
base(name, map, priority, area) => GuardType = DefaultGuardType;
public GuardedRegion(string name, Map map, int priority, params Rectangle2D[] area) :
base(name, map, priority, area) => GuardType = DefaultGuardType;
public GuardedRegion(string name, Map map, Region parent, params Rectangle3D[] area) : base(name, map, parent, area) =>
GuardType = DefaultGuardType;
public GuardedRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area) => GuardType = DefaultGuardType;
public GuardedRegion(string name, Map map, Region parent, int priority, Type guardType, params Rectangle3D[] area)
: base(name, map, parent, priority, area) => GuardType = guardType ?? DefaultGuardType;
public Type GuardType { get; set; }
public bool GuardsDisabled { get; set; }
public virtual bool AllowReds => Core.AOS;
public virtual Type DefaultGuardType
{
private static readonly ILogger logger = LogFactory.GetLogger(typeof(GuardedRegion));
private static readonly object[] m_GuardParams = new object[1];
private readonly Dictionary<Mobile, GuardTimer> m_GuardCandidates = new();
private readonly Type m_GuardType;
public GuardedRegion(string name, Map map, int priority, params Rectangle3D[] area) :
base(name, map, priority, area) =>
m_GuardType = DefaultGuardType;
public GuardedRegion(string name, Map map, int priority, params Rectangle2D[] area) :
base(name, map, priority, area) =>
m_GuardType = DefaultGuardType;
public GuardedRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
get
{
if (json.GetProperty("guardsType", options, out string guardType))
if (Map == Map.Ilshenar || Map == Map.Malas)
{
m_GuardType = AssemblyHandler.FindTypeByName(guardType);
if (!typeof(BaseGuard).IsAssignableFrom(m_GuardType))
{
logger.Warning("Invalid guard type for region '{Region}'", this);
m_GuardType = DefaultGuardType;
}
}
else
{
m_GuardType = DefaultGuardType;
return typeof(ArcherGuard);
}
Disabled = json.GetProperty("guardsDisabled", options, out bool disabled) && disabled;
return typeof(WarriorGuard);
}
}
public bool Disabled { get; set; }
public virtual bool IsDisabled() => GuardsDisabled;
public virtual bool AllowReds => Core.AOS;
public static void Initialize()
{
CommandSystem.Register("CheckGuarded", AccessLevel.GameMaster, CheckGuarded_OnCommand);
CommandSystem.Register("SetGuarded", AccessLevel.Administrator, SetGuarded_OnCommand);
CommandSystem.Register("ToggleGuarded", AccessLevel.Administrator, ToggleGuarded_OnCommand);
}
public virtual Type DefaultGuardType
[Usage("CheckGuarded"), Description("Returns a value indicating if the current region is guarded or not.")]
private static void CheckGuarded_OnCommand(CommandEventArgs e)
{
var from = e.Mobile;
var reg = from.Region.GetRegion<GuardedRegion>();
if (reg == null)
{
get
{
if (Map == Map.Ilshenar || Map == Map.Malas)
{
return typeof(ArcherGuard);
}
return typeof(WarriorGuard);
}
from.SendMessage("You are not in a guardable region.");
}
public virtual bool IsDisabled() => Disabled;
public static void Initialize()
else if (reg.GuardsDisabled)
{
CommandSystem.Register("CheckGuarded", AccessLevel.GameMaster, CheckGuarded_OnCommand);
CommandSystem.Register("SetGuarded", AccessLevel.Administrator, SetGuarded_OnCommand);
CommandSystem.Register("ToggleGuarded", AccessLevel.Administrator, ToggleGuarded_OnCommand);
from.SendMessage("The guards in this region have been disabled.");
}
[Usage("CheckGuarded"), Description("Returns a value indicating if the current region is guarded or not.")]
private static void CheckGuarded_OnCommand(CommandEventArgs e)
else
{
var from = e.Mobile;
var reg = from.Region.GetRegion<GuardedRegion>();
if (reg == null)
{
from.SendMessage("You are not in a guardable region.");
}
else if (reg.Disabled)
{
from.SendMessage("The guards in this region have been disabled.");
}
else
{
from.SendMessage("This region is actively guarded.");
}
from.SendMessage("This region is actively guarded.");
}
}
[Usage("SetGuarded <true|false>"), Description("Enables or disables guards for the current region.")]
private static void SetGuarded_OnCommand(CommandEventArgs e)
[Usage("SetGuarded <true|false>"), Description("Enables or disables guards for the current region.")]
private static void SetGuarded_OnCommand(CommandEventArgs e)
{
var from = e.Mobile;
if (e.Length == 1)
{
var from = e.Mobile;
if (e.Length == 1)
{
var reg = from.Region.GetRegion<GuardedRegion>();
if (reg == null)
{
from.SendMessage("You are not in a guardable region.");
}
else
{
reg.Disabled = !e.GetBoolean(0);
from.SendMessage(
reg.Disabled
? "The guards in this region have been disabled."
: "The guards in this region have been enabled."
);
}
}
else
{
from.SendMessage("Format: SetGuarded <true|false>");
}
}
[Usage("ToggleGuarded"), Description("Toggles the state of guards for the current region.")]
private static void ToggleGuarded_OnCommand(CommandEventArgs e)
{
var from = e.Mobile;
var reg = from.Region.GetRegion<GuardedRegion>();
if (reg == null)
@ -134,252 +93,278 @@ namespace Server.Regions
}
else
{
reg.Disabled = !reg.Disabled;
reg.GuardsDisabled = !e.GetBoolean(0);
from.SendMessage(
reg.Disabled
reg.GuardsDisabled
? "The guards in this region have been disabled."
: "The guards in this region have been enabled."
);
}
}
public static GuardedRegion Disable(GuardedRegion reg)
else
{
reg.Disabled = true;
return reg;
from.SendMessage("Format: SetGuarded <true|false>");
}
}
[Usage("ToggleGuarded"), Description("Toggles the state of guards for the current region.")]
private static void ToggleGuarded_OnCommand(CommandEventArgs e)
{
var from = e.Mobile;
var reg = from.Region.GetRegion<GuardedRegion>();
if (reg == null)
{
from.SendMessage("You are not in a guardable region.");
}
else
{
reg.GuardsDisabled = !reg.GuardsDisabled;
from.SendMessage(
reg.GuardsDisabled
? "The guards in this region have been disabled."
: "The guards in this region have been enabled."
);
}
}
public static GuardedRegion Disable(GuardedRegion reg)
{
reg.GuardsDisabled = true;
return reg;
}
public virtual bool CheckVendorAccess(BaseVendor vendor, Mobile from) =>
from.AccessLevel >= AccessLevel.GameMaster || IsDisabled() || from.Kills < 5;
public override bool OnBeginSpellCast(Mobile m, ISpell s)
{
if (!IsDisabled() && !s.OnCastInTown(this))
{
m.SendLocalizedMessage(500946); // You cannot cast this in town!
return false;
}
public virtual bool CheckVendorAccess(BaseVendor vendor, Mobile from) =>
from.AccessLevel >= AccessLevel.GameMaster || IsDisabled() || from.Kills < 5;
return base.OnBeginSpellCast(m, s);
}
public override bool OnBeginSpellCast(Mobile m, ISpell s)
public override bool AllowHousing(Mobile from, Point3D p) => false;
public override void MakeGuard(Mobile focus)
{
var eable = focus.GetMobilesInRange<BaseGuard>(8);
var useGuard = eable.FirstOrDefault(m => m.Focus == null);
eable.Free();
if (useGuard == null)
{
if (!IsDisabled() && !s.OnCastInTown(this))
m_GuardParams[0] = focus;
try
{
m.SendLocalizedMessage(500946); // You cannot cast this in town!
return false;
GuardType.CreateInstance<object>(m_GuardParams);
}
return base.OnBeginSpellCast(m, s);
}
public override bool AllowHousing(Mobile from, Point3D p) => false;
public override void MakeGuard(Mobile focus)
{
var eable = focus.GetMobilesInRange<BaseGuard>(8);
var useGuard = eable.FirstOrDefault(m => m.Focus == null);
eable.Free();
if (useGuard == null)
catch
{
m_GuardParams[0] = focus;
try
{
m_GuardType.CreateInstance<object>(m_GuardParams);
}
catch
{
// ignored
}
}
else
{
useGuard.Focus = focus;
// ignored
}
}
public override void OnEnter(Mobile m)
else
{
if (IsDisabled())
useGuard.Focus = focus;
}
}
public override void OnEnter(Mobile m)
{
if (IsDisabled())
{
return;
}
if (!AllowReds && m.Kills >= 5)
{
CheckGuardCandidate(m);
}
}
public override void OnExit(Mobile m)
{
}
public override void OnSpeech(SpeechEventArgs args)
{
base.OnSpeech(args);
if (IsDisabled())
{
return;
}
if (args.Mobile.Alive && args.HasKeyword(0x0007)) // *guards*
{
CallGuards(args.Mobile.Location);
}
}
public override void OnAggressed(Mobile aggressor, Mobile aggressed, bool criminal)
{
base.OnAggressed(aggressor, aggressed, criminal);
if (!IsDisabled() && aggressor != aggressed && criminal)
{
CheckGuardCandidate(aggressor);
}
}
public override void OnGotBeneficialAction(Mobile helper, Mobile helped)
{
base.OnGotBeneficialAction(helper, helped);
if (IsDisabled())
{
return;
}
var noto = Notoriety.Compute(helper, helped);
if (helper != helped && noto is Notoriety.Criminal or Notoriety.Murderer)
{
CheckGuardCandidate(helper);
}
}
public override void OnCriminalAction(Mobile m, bool message)
{
base.OnCriminalAction(m, message);
if (!IsDisabled())
{
CheckGuardCandidate(m);
}
}
public void CheckGuardCandidate(Mobile m)
{
if (IsDisabled() || !IsGuardCandidate(m))
{
return;
}
if (!m_GuardCandidates.TryGetValue(m, out var timer))
{
timer = new GuardTimer(m, m_GuardCandidates);
timer.Start();
m_GuardCandidates[m] = timer;
m.SendLocalizedMessage(502275); // Guards can now be called on you!
var map = m.Map;
if (map == null)
{
return;
}
if (!AllowReds && m.Kills >= 5)
Mobile fakeCall = null;
var prio = 0.0;
foreach (var v in m.GetMobilesInRange(8))
{
CheckGuardCandidate(m);
}
}
public override void OnExit(Mobile m)
{
}
public override void OnSpeech(SpeechEventArgs args)
{
base.OnSpeech(args);
if (IsDisabled())
{
return;
}
if (args.Mobile.Alive && args.HasKeyword(0x0007)) // *guards*
{
CallGuards(args.Mobile.Location);
}
}
public override void OnAggressed(Mobile aggressor, Mobile aggressed, bool criminal)
{
base.OnAggressed(aggressor, aggressed, criminal);
if (!IsDisabled() && aggressor != aggressed && criminal)
{
CheckGuardCandidate(aggressor);
}
}
public override void OnGotBeneficialAction(Mobile helper, Mobile helped)
{
base.OnGotBeneficialAction(helper, helped);
if (IsDisabled())
{
return;
}
var noto = Notoriety.Compute(helper, helped);
if (helper != helped && noto is Notoriety.Criminal or Notoriety.Murderer)
{
CheckGuardCandidate(helper);
}
}
public override void OnCriminalAction(Mobile m, bool message)
{
base.OnCriminalAction(m, message);
if (!IsDisabled())
{
CheckGuardCandidate(m);
}
}
public void CheckGuardCandidate(Mobile m)
{
if (IsDisabled() || !IsGuardCandidate(m))
{
return;
}
if (!m_GuardCandidates.TryGetValue(m, out var timer))
{
timer = new GuardTimer(m, m_GuardCandidates);
timer.Start();
m_GuardCandidates[m] = timer;
m.SendLocalizedMessage(502275); // Guards can now be called on you!
var map = m.Map;
if (map == null)
if (!v.Player && v != m && !IsGuardCandidate(v) &&
((v as BaseCreature)?.IsHumanInTown() ?? v.Body.IsHuman && v.Region.IsPartOf(this)))
{
return;
}
var dist = m.GetDistanceToSqrt(v);
Mobile fakeCall = null;
var prio = 0.0;
foreach (var v in m.GetMobilesInRange(8))
{
if (!v.Player && v != m && !IsGuardCandidate(v) &&
((v as BaseCreature)?.IsHumanInTown() ?? v.Body.IsHuman && v.Region.IsPartOf(this)))
if (fakeCall == null || dist < prio)
{
var dist = m.GetDistanceToSqrt(v);
if (fakeCall == null || dist < prio)
{
fakeCall = v;
prio = dist;
}
fakeCall = v;
prio = dist;
}
}
if (fakeCall != null)
{
fakeCall.Say(
Utility.RandomList(
1007037,
501603,
1013037,
1013038,
1013039,
1013041,
1013042,
1013043,
1013052
)
);
MakeGuard(m);
timer.Stop();
m_GuardCandidates.Remove(m);
m.SendLocalizedMessage(502276); // Guards can no longer be called on you.
}
}
else
if (fakeCall != null)
{
fakeCall.Say(
Utility.RandomList(
1007037,
501603,
1013037,
1013038,
1013039,
1013041,
1013042,
1013043,
1013052
)
);
MakeGuard(m);
timer.Stop();
timer.Start();
m_GuardCandidates.Remove(m);
m.SendLocalizedMessage(502276); // Guards can no longer be called on you.
}
}
else
{
timer.Stop();
timer.Start();
}
}
public void CallGuards(Point3D p)
{
if (IsDisabled())
{
return;
}
var eable = Map.GetMobilesInRange(p, 14);
foreach (var m in eable)
{
if (IsGuardCandidate(m) &&
(!AllowReds && m.Kills >= 5 && m.Region.IsPartOf(this) || m_GuardCandidates.ContainsKey(m)))
{
if (m_GuardCandidates.Remove(m, out var timer))
{
timer.Stop();
}
MakeGuard(m);
m.SendLocalizedMessage(502276); // Guards can no longer be called on you.
break;
}
}
public void CallGuards(Point3D p)
eable.Free();
}
public bool IsGuardCandidate(Mobile m) =>
m is not BaseGuard && m.Alive && m.AccessLevel <= AccessLevel.Player && !m.Blessed &&
(m is not BaseCreature creature || !creature.IsInvulnerable) && !IsDisabled() &&
(!AllowReds && m.Kills >= 5 || m.Criminal);
private class GuardTimer : Timer
{
private readonly Mobile m_Mobile;
private readonly Dictionary<Mobile, GuardTimer> m_Table;
public GuardTimer(Mobile m, Dictionary<Mobile, GuardTimer> table) : base(TimeSpan.FromSeconds(15.0))
{
if (IsDisabled())
{
return;
}
var eable = Map.GetMobilesInRange(p, 14);
foreach (var m in eable)
{
if (IsGuardCandidate(m) &&
(!AllowReds && m.Kills >= 5 && m.Region.IsPartOf(this) || m_GuardCandidates.ContainsKey(m)))
{
if (m_GuardCandidates.Remove(m, out var timer))
{
timer.Stop();
}
MakeGuard(m);
m.SendLocalizedMessage(502276); // Guards can no longer be called on you.
break;
}
}
eable.Free();
m_Mobile = m;
m_Table = table;
}
public bool IsGuardCandidate(Mobile m) =>
m is not BaseGuard && m.Alive && m.AccessLevel <= AccessLevel.Player && !m.Blessed &&
(m is not BaseCreature creature || !creature.IsInvulnerable) && !IsDisabled() &&
(!AllowReds && m.Kills >= 5 || m.Criminal);
private class GuardTimer : Timer
protected override void OnTick()
{
private readonly Mobile m_Mobile;
private readonly Dictionary<Mobile, GuardTimer> m_Table;
public GuardTimer(Mobile m, Dictionary<Mobile, GuardTimer> table) : base(TimeSpan.FromSeconds(15.0))
if (m_Table.Remove(m_Mobile))
{
m_Mobile = m;
m_Table = table;
}
protected override void OnTick()
{
if (m_Table.Remove(m_Mobile))
{
m_Mobile.SendLocalizedMessage(502276); // Guards can no longer be called on you.
}
m_Mobile.SendLocalizedMessage(502276); // Guards can no longer be called on you.
}
}
}

View file

@ -4,407 +4,406 @@ using Server.Items;
using Server.Mobiles;
using Server.Multis;
namespace Server.Regions
namespace Server.Regions;
public class HouseRegion : BaseRegion
{
public class HouseRegion : BaseRegion
public static readonly int HousePriority = DefaultPriority + 1;
public static TimeSpan CombatHeatDelay = TimeSpan.FromSeconds(30.0);
private bool m_Recursion;
public HouseRegion(BaseHouse house) : base(null, house.Map, HousePriority, GetArea(house))
{
public static readonly int HousePriority = DefaultPriority + 1;
House = house;
public static TimeSpan CombatHeatDelay = TimeSpan.FromSeconds(30.0);
var ban = house.RelativeBanLocation;
private bool m_Recursion;
GoLocation = new Point3D(house.X + ban.X, house.Y + ban.Y, house.Z + ban.Z);
}
public HouseRegion(BaseHouse house) : base(null, house.Map, HousePriority, GetArea(house))
public BaseHouse House { get; }
public static void Initialize()
{
EventSink.Login += OnLogin;
}
public static void OnLogin(Mobile m)
{
var house = BaseHouse.FindHouseAt(m);
if (house?.Public == false && !house.IsFriend(m))
{
House = house;
m.Location = house.BanLocation;
}
}
var ban = house.RelativeBanLocation;
public override bool AllowHousing(Mobile from, Point3D p) => false;
GoLocation = new Point3D(house.X + ban.X, house.Y + ban.Y, house.Z + ban.Z);
private static Rectangle3D[] GetArea(BaseHouse house)
{
var x = house.X;
var y = house.Y;
// int z = house.Z;
var houseArea = house.Area;
var area = new Rectangle3D[houseArea.Length];
for (var i = 0; i < area.Length; i++)
{
var rect = houseArea[i];
area[i] = ConvertTo3D(new Rectangle2D(x + rect.Start.X, y + rect.Start.Y, rect.Width, rect.Height));
}
public BaseHouse House { get; }
return area;
}
public static void Initialize()
public override bool SendInaccessibleMessage(Item item, Mobile from)
{
if (item is Container)
{
EventSink.Login += OnLogin;
item.SendLocalizedMessageTo(from, 501647); // That is secure.
}
else
{
item.SendLocalizedMessageTo(from, 1061637); // You are not allowed to access this.
}
public static void OnLogin(Mobile m)
{
var house = BaseHouse.FindHouseAt(m);
return true;
}
if (house?.Public == false && !house.IsFriend(m))
{
m.Location = house.BanLocation;
}
public override bool CheckAccessibility(Item item, Mobile from) => House.CheckAccessibility(item, from);
// Use OnLocationChanged instead of OnEnter because it can be that we enter a house region even though we're not actually inside the house
public override void OnLocationChanged(Mobile m, Point3D oldLocation)
{
if (m_Recursion)
{
return;
}
public override bool AllowHousing(Mobile from, Point3D p) => false;
base.OnLocationChanged(m, oldLocation);
private static Rectangle3D[] GetArea(BaseHouse house)
m_Recursion = true;
var bc = m as BaseCreature;
if (bc?.NoHouseRestrictions != true &&
(bc?.IsHouseSummonable != true || BaseCreature.Summoning || House.IsInside(oldLocation, 16)))
{
var x = house.X;
var y = house.Y;
// int z = house.Z;
var houseArea = house.Area;
var area = new Rectangle3D[houseArea.Length];
for (var i = 0; i < area.Length; i++)
if ((House.Public || !House.IsAosRules) && House.IsBanned(m) && House.IsInside(m))
{
var rect = houseArea[i];
area[i] = ConvertTo3D(new Rectangle2D(x + rect.Start.X, y + rect.Start.Y, rect.Width, rect.Height));
}
m.Location = House.BanLocation;
return area;
}
public override bool SendInaccessibleMessage(Item item, Mobile from)
{
if (item is Container)
{
item.SendLocalizedMessageTo(from, 501647); // That is secure.
}
else
{
item.SendLocalizedMessageTo(from, 1061637); // You are not allowed to access this.
}
return true;
}
public override bool CheckAccessibility(Item item, Mobile from) => House.CheckAccessibility(item, from);
// Use OnLocationChanged instead of OnEnter because it can be that we enter a house region even though we're not actually inside the house
public override void OnLocationChanged(Mobile m, Point3D oldLocation)
{
if (m_Recursion)
{
return;
}
base.OnLocationChanged(m, oldLocation);
m_Recursion = true;
var bc = m as BaseCreature;
if (bc?.NoHouseRestrictions != true &&
(bc?.IsHouseSummonable != true || BaseCreature.Summoning || House.IsInside(oldLocation, 16)))
{
if ((House.Public || !House.IsAosRules) && House.IsBanned(m) && House.IsInside(m))
if (!Core.SE)
{
m.Location = House.BanLocation;
if (!Core.SE)
{
m.SendLocalizedMessage(501284); // You may not enter.
}
}
else if (House.IsAosRules && !House.Public && !House.HasAccess(m) && House.IsInside(m))
{
m.Location = House.BanLocation;
if (!Core.SE)
{
m.SendLocalizedMessage(501284); // You may not enter.
}
}
else if (House.IsCombatRestricted(m) && House.IsInside(m) && !House.IsInside(oldLocation, 16))
{
m.Location = House.BanLocation;
m.SendLocalizedMessage(1061637); // You are not allowed to access this.
}
else if (House is HouseFoundation foundation && foundation.Customizer != null &&
foundation.Customizer != m &&
House.IsInside(m))
{
m.Location = House.BanLocation;
m.SendLocalizedMessage(501284); // You may not enter.
}
}
if (House.InternalizedVendors.Count > 0 && House.IsInside(m) && !House.IsInside(oldLocation, 16) &&
House.IsOwner(m) && m.Alive && !m.HasGump<NoticeGump>())
else if (House.IsAosRules && !House.Public && !House.HasAccess(m) && House.IsInside(m))
{
m.SendGump(new NoticeGump(1060635, 30720, 1061826, 32512, 320, 180));
}
m.Location = House.BanLocation;
m_Recursion = false;
if (!Core.SE)
{
m.SendLocalizedMessage(501284); // You may not enter.
}
}
else if (House.IsCombatRestricted(m) && House.IsInside(m) && !House.IsInside(oldLocation, 16))
{
m.Location = House.BanLocation;
m.SendLocalizedMessage(1061637); // You are not allowed to access this.
}
else if (House is HouseFoundation foundation && foundation.Customizer != null &&
foundation.Customizer != m &&
House.IsInside(m))
{
m.Location = House.BanLocation;
}
}
public override bool OnMoveInto(Mobile from, Direction d, Point3D newLocation, Point3D oldLocation)
if (House.InternalizedVendors.Count > 0 && House.IsInside(m) && !House.IsInside(oldLocation, 16) &&
House.IsOwner(m) && m.Alive && !m.HasGump<NoticeGump>())
{
if (!base.OnMoveInto(from, d, newLocation, oldLocation))
m.SendGump(new NoticeGump(1060635, 30720, 1061826, 32512, 320, 180));
}
m_Recursion = false;
}
public override bool OnMoveInto(Mobile from, Direction d, Point3D newLocation, Point3D oldLocation)
{
if (!base.OnMoveInto(from, d, newLocation, oldLocation))
{
return false;
}
var bc = from as BaseCreature;
if (bc?.NoHouseRestrictions != true)
{
if (bc?.Controlled == false) // Untamed creatures cannot enter public houses
{
return false;
}
var bc = from as BaseCreature;
if (bc?.NoHouseRestrictions != true)
if (bc?.IsHouseSummonable == true &&
!(BaseCreature.Summoning || House.IsInside(oldLocation, 16)))
{
if (bc?.Controlled == false) // Untamed creatures cannot enter public houses
{
return false;
}
if (bc?.IsHouseSummonable == true &&
!(BaseCreature.Summoning || House.IsInside(oldLocation, 16)))
{
return false;
}
if (bc?.Controlled == false && House.IsAosRules && !House.Public)
{
return false;
}
if ((House.Public || !House.IsAosRules) && House.IsBanned(from) && House.IsInside(newLocation, 16))
{
from.Location = House.BanLocation;
if (!Core.SE)
{
from.SendLocalizedMessage(501284); // You may not enter.
}
return false;
}
if (House.IsAosRules && !House.Public && !House.HasAccess(from) && House.IsInside(newLocation, 16))
{
if (!Core.SE)
{
from.SendLocalizedMessage(501284); // You may not enter.
}
return false;
}
if (House.IsCombatRestricted(from) && !House.IsInside(oldLocation, 16) && House.IsInside(newLocation, 16))
{
from.SendLocalizedMessage(1061637); // You are not allowed to access this.
return false;
}
if (House is HouseFoundation foundation && foundation.Customizer != null && foundation.Customizer != from &&
House.IsInside(newLocation, 16))
{
return false;
}
return false;
}
if (House.InternalizedVendors.Count > 0 && House.IsInside(from) && !House.IsInside(oldLocation, 16) &&
House.IsOwner(from) && from.Alive &&
!from.HasGump<NoticeGump>())
if (bc?.Controlled == false && House.IsAosRules && !House.Public)
{
from.SendGump(new NoticeGump(1060635, 30720, 1061826, 32512, 320, 180));
return false;
}
return true;
if ((House.Public || !House.IsAosRules) && House.IsBanned(from) && House.IsInside(newLocation, 16))
{
from.Location = House.BanLocation;
if (!Core.SE)
{
from.SendLocalizedMessage(501284); // You may not enter.
}
return false;
}
if (House.IsAosRules && !House.Public && !House.HasAccess(from) && House.IsInside(newLocation, 16))
{
if (!Core.SE)
{
from.SendLocalizedMessage(501284); // You may not enter.
}
return false;
}
if (House.IsCombatRestricted(from) && !House.IsInside(oldLocation, 16) && House.IsInside(newLocation, 16))
{
from.SendLocalizedMessage(1061637); // You are not allowed to access this.
return false;
}
if (House is HouseFoundation foundation && foundation.Customizer != null && foundation.Customizer != from &&
House.IsInside(newLocation, 16))
{
return false;
}
}
public override bool OnDecay(Item item) =>
(!House.HasLockedDownItem(item) && !House.HasSecureItem(item) || !House.IsInside(item)) && base.OnDecay(item);
public override TimeSpan GetLogoutDelay(Mobile m)
if (House.InternalizedVendors.Count > 0 && House.IsInside(from) && !House.IsInside(oldLocation, 16) &&
House.IsOwner(from) && from.Alive &&
!from.HasGump<NoticeGump>())
{
if (!House.IsFriend(m) || !House.IsInside(m))
from.SendGump(new NoticeGump(1060635, 30720, 1061826, 32512, 320, 180));
}
return true;
}
public override bool OnDecay(Item item) =>
(!House.HasLockedDownItem(item) && !House.HasSecureItem(item) || !House.IsInside(item)) && base.OnDecay(item);
public override TimeSpan GetLogoutDelay(Mobile m)
{
if (!House.IsFriend(m) || !House.IsInside(m))
{
return base.GetLogoutDelay(m);
}
foreach (var info in m.Aggressed)
{
if (info.Defender.Player && Core.Now - info.LastCombatTime < CombatHeatDelay)
{
return base.GetLogoutDelay(m);
}
foreach (var info in m.Aggressed)
{
if (info.Defender.Player && Core.Now - info.LastCombatTime < CombatHeatDelay)
{
return base.GetLogoutDelay(m);
}
}
return TimeSpan.Zero;
}
public override void OnSpeech(SpeechEventArgs e)
return TimeSpan.Zero;
}
public override void OnSpeech(SpeechEventArgs e)
{
base.OnSpeech(e);
var from = e.Mobile;
Item sign = House.Sign;
var isOwner = House.IsOwner(from);
var isCoOwner = isOwner || House.IsCoOwner(from);
var isFriend = isCoOwner || House.IsFriend(from);
if (!isFriend)
{
base.OnSpeech(e);
return;
}
var from = e.Mobile;
Item sign = House.Sign;
if (!from.Alive)
{
return;
}
var isOwner = House.IsOwner(from);
var isCoOwner = isOwner || House.IsCoOwner(from);
var isFriend = isCoOwner || House.IsFriend(from);
if (!isFriend)
if (Core.ML && e.Speech.InsensitiveEquals("I wish to resize my house"))
{
if (from.Map != sign.Map || !from.InRange(sign, 0))
{
return;
from.SendLocalizedMessage(500295); // you are too far away to do that.
}
if (!from.Alive)
else if (Core.Now <= House.BuiltOn.AddHours(1))
{
return;
from.SendLocalizedMessage(1080178); // You must wait one hour between each house demolition.
}
if (Core.ML && e.Speech.InsensitiveEquals("I wish to resize my house"))
else if (isOwner)
{
if (from.Map != sign.Map || !from.InRange(sign, 0))
{
from.SendLocalizedMessage(500295); // you are too far away to do that.
}
else if (Core.Now <= House.BuiltOn.AddHours(1))
{
from.SendLocalizedMessage(1080178); // You must wait one hour between each house demolition.
}
else if (isOwner)
{
from.CloseGump<ConfirmHouseResize>();
from.CloseGump<HouseGumpAOS>();
from.SendGump(new ConfirmHouseResize(from, House));
}
else
{
from.SendLocalizedMessage(501320); // Only the house owner may do this.
}
from.CloseGump<ConfirmHouseResize>();
from.CloseGump<HouseGumpAOS>();
from.SendGump(new ConfirmHouseResize(from, House));
}
if (!House.IsInside(from) || !House.IsActive)
else
{
return;
}
if (e.HasKeyword(0x33)) // remove thyself
{
from.SendLocalizedMessage(501326); // Target the individual to eject from this house.
from.Target = new HouseKickTarget(House);
}
else if (e.HasKeyword(0x34)) // I ban thee
{
if (!House.Public && House.IsAosRules)
{
from.SendLocalizedMessage(
1062521
); // You cannot ban someone from a private house. Revoke their access instead.
}
else
{
from.SendLocalizedMessage(501325); // Target the individual to ban from this house.
from.Target = new HouseBanTarget(true, House);
}
}
else if (e.HasKeyword(0x23)) // I wish to lock this down
{
if (isCoOwner)
{
from.SendLocalizedMessage(502097); // Lock what down?
from.Target = new LockdownTarget(false, House);
}
else
{
from.SendLocalizedMessage(1010587); // You are not a co-owner of this house.
}
}
else if (e.HasKeyword(0x24)) // I wish to release this
{
if (isCoOwner)
{
from.SendLocalizedMessage(502100); // Choose the item you wish to release
from.Target = new LockdownTarget(true, House);
}
else
{
from.SendLocalizedMessage(1010587); // You are not a co-owner of this house.
}
}
else if (e.HasKeyword(0x25)) // I wish to secure this
{
if (isOwner)
{
from.SendLocalizedMessage(502103); // Choose the item you wish to secure
from.Target = new SecureTarget(false, House);
}
else
{
from.SendLocalizedMessage(502094); // You must be in your house to do this.
}
}
else if (e.HasKeyword(0x26)) // I wish to unsecure this
{
if (isOwner)
{
from.SendLocalizedMessage(502106); // Choose the item you wish to unsecure
from.Target = new SecureTarget(true, House);
}
else
{
from.SendLocalizedMessage(502094); // You must be in your house to do this.
}
}
else if (e.HasKeyword(0x27)) // I wish to place a strongbox
{
if (isOwner)
{
from.SendLocalizedMessage(502109); // Owners do not get a strongbox of their own.
}
else if (isCoOwner)
{
House.AddStrongBox(from);
}
else
{
from.SendLocalizedMessage(1010587); // You are not a co-owner of this house.
}
}
else if (e.HasKeyword(0x28)) // trash barrel
{
if (isCoOwner)
{
House.AddTrashBarrel(from);
}
else
{
from.SendLocalizedMessage(1010587); // You are not a co-owner of this house.
}
from.SendLocalizedMessage(501320); // Only the house owner may do this.
}
}
public override bool OnDoubleClick(Mobile from, object o)
if (!House.IsInside(from) || !House.IsActive)
{
if (o is Container c)
{
var res = House.CheckSecureAccess(from, c);
if (res == SecureAccessResult.Accessible)
{
return true;
}
if (res == SecureAccessResult.Inaccessible)
{
c.SendLocalizedMessageTo(from, 1010563);
return false;
}
}
return base.OnDoubleClick(from, o);
return;
}
public override bool OnSingleClick(Mobile from, object o)
if (e.HasKeyword(0x33)) // remove thyself
{
if (o is Item item)
from.SendLocalizedMessage(501326); // Target the individual to eject from this house.
from.Target = new HouseKickTarget(House);
}
else if (e.HasKeyword(0x34)) // I ban thee
{
if (!House.Public && House.IsAosRules)
{
if (House.HasLockedDownItem(item))
{
item.LabelTo(from, 501643); // [locked down]
}
else if (House.HasSecureItem(item))
{
item.LabelTo(from, 501644); // [locked down & secure]
}
from.SendLocalizedMessage(
1062521
); // You cannot ban someone from a private house. Revoke their access instead.
}
else
{
from.SendLocalizedMessage(501325); // Target the individual to ban from this house.
from.Target = new HouseBanTarget(true, House);
}
}
else if (e.HasKeyword(0x23)) // I wish to lock this down
{
if (isCoOwner)
{
from.SendLocalizedMessage(502097); // Lock what down?
from.Target = new LockdownTarget(false, House);
}
else
{
from.SendLocalizedMessage(1010587); // You are not a co-owner of this house.
}
}
else if (e.HasKeyword(0x24)) // I wish to release this
{
if (isCoOwner)
{
from.SendLocalizedMessage(502100); // Choose the item you wish to release
from.Target = new LockdownTarget(true, House);
}
else
{
from.SendLocalizedMessage(1010587); // You are not a co-owner of this house.
}
}
else if (e.HasKeyword(0x25)) // I wish to secure this
{
if (isOwner)
{
from.SendLocalizedMessage(502103); // Choose the item you wish to secure
from.Target = new SecureTarget(false, House);
}
else
{
from.SendLocalizedMessage(502094); // You must be in your house to do this.
}
}
else if (e.HasKeyword(0x26)) // I wish to unsecure this
{
if (isOwner)
{
from.SendLocalizedMessage(502106); // Choose the item you wish to unsecure
from.Target = new SecureTarget(true, House);
}
else
{
from.SendLocalizedMessage(502094); // You must be in your house to do this.
}
}
else if (e.HasKeyword(0x27)) // I wish to place a strongbox
{
if (isOwner)
{
from.SendLocalizedMessage(502109); // Owners do not get a strongbox of their own.
}
else if (isCoOwner)
{
House.AddStrongBox(from);
}
else
{
from.SendLocalizedMessage(1010587); // You are not a co-owner of this house.
}
}
else if (e.HasKeyword(0x28)) // trash barrel
{
if (isCoOwner)
{
House.AddTrashBarrel(from);
}
else
{
from.SendLocalizedMessage(1010587); // You are not a co-owner of this house.
}
return base.OnSingleClick(from, o);
}
}
}
public override bool OnDoubleClick(Mobile from, object o)
{
if (o is Container c)
{
var res = House.CheckSecureAccess(from, c);
if (res == SecureAccessResult.Accessible)
{
return true;
}
if (res == SecureAccessResult.Inaccessible)
{
c.SendLocalizedMessageTo(from, 1010563);
return false;
}
}
return base.OnDoubleClick(from, o);
}
public override bool OnSingleClick(Mobile from, object o)
{
if (o is Item item)
{
if (House.HasLockedDownItem(item))
{
item.LabelTo(from, 501643); // [locked down]
}
else if (House.HasSecureItem(item))
{
item.LabelTo(from, 501644); // [locked down & secure]
}
}
return base.OnSingleClick(from, o);
}
}

View file

@ -1,77 +1,80 @@
using System.Text.Json;
using Server.Json;
using Server.Spells;
namespace Server.Regions
namespace Server.Regions;
public class JailRegion : BaseRegion
{
public class JailRegion : BaseRegion
public JailRegion(string name, Map map, Region parent, params Rectangle3D[] area)
: base(name, map, parent, area)
{
public JailRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
{
}
public override bool AllowBeneficial(Mobile from, Mobile target)
{
if (from.AccessLevel == AccessLevel.Player)
{
from.SendMessage("You may not do that in jail.");
return false;
}
return true;
}
public override bool AllowHarmful(Mobile from, Mobile target)
{
if (from.AccessLevel == AccessLevel.Player)
{
from.SendMessage("You may not do that in jail.");
return false;
}
return true;
}
public override bool AllowHousing(Mobile from, Point3D p) => false;
public override void AlterLightLevel(Mobile m, ref int global, ref int personal)
{
global = LightCycle.JailLevel;
}
public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType)
{
if (m?.AccessLevel == AccessLevel.Player)
{
m.SendLocalizedMessage(1114345); // You'll need a better jailbreak plan than that!
return false;
}
return base.CheckTravel(m, newLocation, travelType);
}
public override bool OnBeginSpellCast(Mobile from, ISpell s)
{
if (from.AccessLevel == AccessLevel.Player)
{
from.SendLocalizedMessage(502629); // You cannot cast spells here.
return false;
}
return true;
}
public override bool OnSkillUse(Mobile from, int Skill)
{
if (from.AccessLevel == AccessLevel.Player)
{
from.SendMessage("You may not use skills in jail.");
return false;
}
return true;
}
public override bool OnCombatantChange(Mobile from, Mobile Old, Mobile New) => from.AccessLevel > AccessLevel.Player;
}
public JailRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
}
public override bool AllowBeneficial(Mobile from, Mobile target)
{
if (from.AccessLevel == AccessLevel.Player)
{
from.SendMessage("You may not do that in jail.");
return false;
}
return true;
}
public override bool AllowHarmful(Mobile from, Mobile target)
{
if (from.AccessLevel == AccessLevel.Player)
{
from.SendMessage("You may not do that in jail.");
return false;
}
return true;
}
public override bool AllowHousing(Mobile from, Point3D p) => false;
public override void AlterLightLevel(Mobile m, ref int global, ref int personal)
{
global = LightCycle.JailLevel;
}
public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType)
{
if (m?.AccessLevel == AccessLevel.Player)
{
m.SendLocalizedMessage(1114345); // You'll need a better jailbreak plan than that!
return false;
}
return base.CheckTravel(m, newLocation, travelType);
}
public override bool OnBeginSpellCast(Mobile from, ISpell s)
{
if (from.AccessLevel == AccessLevel.Player)
{
from.SendLocalizedMessage(502629); // You cannot cast spells here.
return false;
}
return true;
}
public override bool OnSkillUse(Mobile from, int Skill)
{
if (from.AccessLevel == AccessLevel.Player)
{
from.SendMessage("You may not use skills in jail.");
return false;
}
return true;
}
public override bool OnCombatantChange(Mobile from, Mobile Old, Mobile New) => from.AccessLevel > AccessLevel.Player;
}

View file

@ -0,0 +1,29 @@
namespace Server.Regions;
public class BaseRegionJsonDto<TRegion> : GenericRegionJsonDto<TRegion> where TRegion : BaseRegion
{
public string RuneName { get; set; }
public bool NoLogoutDelay { get; set; }
public override void FromRegion(Region region)
{
base.FromRegion(region);
if (region is BaseRegion baseRegion)
{
RuneName = baseRegion.RuneName;
NoLogoutDelay = baseRegion.NoLogoutDelay;
}
}
protected override void HydrateRegion(Region region)
{
base.HydrateRegion(region);
if (region is BaseRegion baseRegion)
{
baseRegion.RuneName = RuneName;
baseRegion.NoLogoutDelay = NoLogoutDelay;
}
}
}

View file

@ -0,0 +1,26 @@
namespace Server.Regions;
public class DungeonRegionJsonDto<TRegion> : BaseRegionJsonDto<TRegion> where TRegion : DungeonRegion
{
public Point3D Entrance { get; set; }
public override void FromRegion(Region region)
{
base.FromRegion(region);
if (region is DungeonRegion dungeonRegion)
{
Entrance = dungeonRegion.Entrance;
}
}
protected override void HydrateRegion(Region region)
{
base.HydrateRegion(region);
if (region is DungeonRegion dungeonRegion)
{
dungeonRegion.Entrance = Entrance;
}
}
}

View file

@ -0,0 +1,34 @@
using System;
using System.Text.Json.Serialization;
namespace Server.Regions;
public class GenericRegionJsonDto<TRegion> : RegionJsonDto where TRegion : BaseRegion
{
[JsonIgnore]
public override Type RegionType => typeof(TRegion);
public string RuneName { get; set; }
public bool NoLogoutDelay { get; set; }
public override void FromRegion(Region region)
{
base.FromRegion(region);
if (region is BaseRegion baseRegion)
{
RuneName = baseRegion.RuneName;
NoLogoutDelay = baseRegion.NoLogoutDelay;
}
}
protected override void HydrateRegion(Region region)
{
base.HydrateRegion(region);
if (region is BaseRegion baseRegion)
{
baseRegion.RuneName = RuneName;
baseRegion.NoLogoutDelay = NoLogoutDelay;
}
}
}

View file

@ -0,0 +1,30 @@
using System;
namespace Server.Regions;
public class GuardedRegionJsonDto<TRegion> : BaseRegionJsonDto<TRegion> where TRegion : GuardedRegion
{
public bool GuardsDisabled { get; set; }
public Type? GuardType { get; set; }
public override void FromRegion(Region region)
{
base.FromRegion(region);
if (region is GuardedRegion guardedRegion)
{
GuardsDisabled = guardedRegion.GuardsDisabled;
GuardType = guardedRegion.GuardType == guardedRegion.DefaultGuardType ? null : guardedRegion.GuardType;
}
}
protected override void HydrateRegion(Region region)
{
base.HydrateRegion(region);
if (region is GuardedRegion guardedRegion)
{
guardedRegion.GuardsDisabled = GuardsDisabled;
guardedRegion.GuardType = GuardType ?? guardedRegion.DefaultGuardType;
}
}
}

View file

@ -0,0 +1,21 @@
namespace Server.Regions;
public static class RegionJsonDtoExt
{
public static void Configure()
{
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<BaseRegion>, BaseRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<DungeonRegionJsonDto<DungeonRegion>, DungeonRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<GuardedRegionJsonDto<GuardedRegion>, GuardedRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<GreenAcresRegion>, GreenAcresRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<JailRegion>, JailRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<MondainRegion>, MondainRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<NewMaginciaRegion>, NewMaginciaRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<NoHousingRegion>, NoHousingRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<NoTravelSpellsAllowedRegion>, NoTravelSpellsAllowedRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<TownRegion>, TownRegion>();
RegionJsonSerializer.RegisterRegionForSerialization<BaseRegionJsonDto<TwistedWealdDesertRegion>, TwistedWealdDesertRegion>();
}
}

View file

@ -1,24 +1,27 @@
using System.Text.Json;
using Server.Json;
using Server.Spells.Sixth;
namespace Server.Regions
namespace Server.Regions;
public class MondainRegion : NoTravelSpellsAllowedRegion
{
public class MondainRegion : NoTravelSpellsAllowedRegion
public MondainRegion(string name, Map map, Region parent, params Rectangle3D[] area)
: base(name, map, parent, area)
{
public MondainRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
}
public MondainRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
}
public override bool OnBeginSpellCast(Mobile m, ISpell s)
{
if (m.Player && s is MarkSpell)
{
m.SendLocalizedMessage(501802); // Thy spell doth not appear to work...
return false;
}
public override bool OnBeginSpellCast(Mobile m, ISpell s)
{
if (m.Player && s is MarkSpell)
{
m.SendLocalizedMessage(501802); // Thy spell doth not appear to work...
return false;
}
return base.OnBeginSpellCast(m, s);
}
return base.OnBeginSpellCast(m, s);
}
}

View file

@ -1,13 +1,14 @@
using System.Text.Json;
using Server.Json;
using Server.Regions;
namespace Server.Regions;
namespace Server.Engines.NewMagincia
public class NewMaginciaRegion : TownRegion
{
public class NewMaginciaRegion : TownRegion
public NewMaginciaRegion(string name, Map map, Region parent, params Rectangle3D[] area)
: base(name, map, parent, area)
{
}
public NewMaginciaRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
public NewMaginciaRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
{
}
}
}

View file

@ -1,18 +1,16 @@
using System.Text.Json;
using Server.Json;
namespace Server.Regions;
namespace Server.Regions
public class NoHousingRegion : BaseRegion
{
public class NoHousingRegion : BaseRegion
public NoHousingRegion(string name, Map map, Region parent, params Rectangle3D[] area)
: base(name, map, parent, area)
{
public NoHousingRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) =>
SmartChecking = json.GetProperty("smartNoHousing", options, out bool smartNoHousing) && smartNoHousing;
/* False: this uses 'stupid OSI' house placement checking: part of the house may be placed here provided that the center is not in the region
* True: this uses 'smart RunUO' house placement checking: no part of the house may be in the region
*/
public bool SmartChecking { get; }
public override bool AllowHousing(Mobile from, Point3D p) => SmartChecking;
}
public NoHousingRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
}
public override bool AllowHousing(Mobile from, Point3D p) => true;
}

View file

@ -1,12 +1,16 @@
using System.Text.Json;
using Server;
using Server.Json;
using Server.Regions;
using Server.Spells;
public class NoTravelSpellsAllowedRegion : DungeonRegion
{
public NoTravelSpellsAllowedRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
public NoTravelSpellsAllowedRegion(string name, Map map, Region parent, params Rectangle3D[] area)
: base(name, map, parent, area)
{
}
public NoTravelSpellsAllowedRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
}

View file

@ -1,12 +1,14 @@
using System.Text.Json;
using Server.Json;
namespace Server.Regions;
namespace Server.Regions
public class TownRegion : GuardedRegion
{
public class TownRegion : GuardedRegion
public TownRegion(string name, Map map, Region parent, params Rectangle3D[] area)
: base(name, map, parent, area)
{
}
public TownRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
public TownRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
{
}
}
}

View file

@ -1,47 +1,50 @@
using System.Text.Json;
using Server.Json;
using Server.Network;
using Server.Spells;
using Server.Spells.Ninjitsu;
namespace Server.Regions
namespace Server.Regions;
public class TwistedWealdDesertRegion : MondainRegion
{
public class TwistedWealdDesertRegion : MondainRegion
public TwistedWealdDesertRegion(string name, Map map, Region parent, params Rectangle3D[] area)
: base(name, map, parent, area)
{
public TwistedWealdDesertRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options)
{
}
}
public static void Initialize()
{
EventSink.Login += Desert_OnLogin;
}
public TwistedWealdDesertRegion(string name, Map map, Region parent, int priority, params Rectangle3D[] area)
: base(name, map, parent, priority, area)
{
}
public override void OnEnter(Mobile m)
{
var ns = m.NetState;
if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm)) &&
m.AccessLevel == AccessLevel.Player)
{
ns.SendSpeedControl(SpeedControlSetting.Walk);
}
}
public static void Initialize()
{
EventSink.Login += Desert_OnLogin;
}
public override void OnExit(Mobile m)
public override void OnEnter(Mobile m)
{
var ns = m.NetState;
if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm)) &&
m.AccessLevel == AccessLevel.Player)
{
var ns = m.NetState;
if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm)))
{
ns.SendSpeedControl(SpeedControlSetting.Disable);
}
ns.SendSpeedControl(SpeedControlSetting.Walk);
}
}
private static void Desert_OnLogin(Mobile m)
public override void OnExit(Mobile m)
{
var ns = m.NetState;
if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm)))
{
if (m.Region.IsPartOf<TwistedWealdDesertRegion>() && m.AccessLevel == AccessLevel.Player)
{
m.NetState.SendSpeedControl(SpeedControlSetting.Walk);
}
ns.SendSpeedControl(SpeedControlSetting.Disable);
}
}
private static void Desert_OnLogin(Mobile m)
{
if (m.Region.IsPartOf<TwistedWealdDesertRegion>() && m.AccessLevel == AccessLevel.Player)
{
m.NetState.SendSpeedControl(SpeedControlSetting.Walk);
}
}
}