fix: Cleans up Point checks and removes statics (#966)
- [X] Removes static freezing/unfreezing. Use other tools for this. - [X] Cleans up IPoint3D allocations - [X] Removes IPoint3D constructors since the compiler may not optimize the constructor path and allow allocations. Note: Instead of `new Point3D(m)`, do something like `new Point3D(m.Location)`. Sorry for the inconvenience. In the long run this will prevent abuse of hot paths that will cause performance issues.
This commit is contained in:
parent
23532db603
commit
0925a2d435
18 changed files with 184 additions and 958 deletions
|
|
@ -47,7 +47,7 @@ namespace Server
|
||||||
m_Y = y;
|
m_Y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point2D(IPoint2D p) : this(p.X, p.Y)
|
public Point2D(Point2D p) : this(p.X, p.Y)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Server
|
namespace Server
|
||||||
{
|
{
|
||||||
|
|
@ -49,11 +50,16 @@ namespace Server
|
||||||
set => m_Z = value;
|
set => m_Z = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Point3D(IPoint3D p) : this(p.X, p.Y, p.Z)
|
public Point3D(IPoint3D p) : this(p.X, p.Y, p.Z)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point3D(IPoint2D p, int z) : this(p.X, p.Y, z)
|
public Point3D(Point3D p) : this(p.X, p.Y, p.Z)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point3D(Point2D p, int z) : this(p.X, p.Y, z)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using Server.Items;
|
using Server.Items;
|
||||||
using Server.Logging;
|
using Server.Logging;
|
||||||
using Server.Network;
|
using Server.Network;
|
||||||
|
|
@ -809,17 +810,22 @@ namespace Server
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Bound(int x, int y, out int newX, out int newY)
|
public void Bound(int x, int y, out int newX, out int newY)
|
||||||
{
|
{
|
||||||
newX = Math.Clamp(x, 0, Width - 1);
|
newX = Math.Clamp(x, 0, Width - 1);
|
||||||
newY = Math.Clamp(y, 0, Height - 1);
|
newY = Math.Clamp(y, 0, Height - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Point2D Bound(Point3D p)
|
||||||
|
{
|
||||||
|
Bound(p.m_X, p.m_Y, out var x, out var y);
|
||||||
|
return new Point2D(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
public Point2D Bound(Point2D p)
|
public Point2D Bound(Point2D p)
|
||||||
{
|
{
|
||||||
var x = Math.Clamp(p.m_X, 0, Width - 1);
|
Bound(p.m_X, p.m_Y, out var x, out var y);
|
||||||
var y = Math.Clamp(p.m_Y, 0, Height - 1);
|
|
||||||
|
|
||||||
return new Point2D(x, y);
|
return new Point2D(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1086,7 +1092,7 @@ namespace Server
|
||||||
}
|
}
|
||||||
else if (o is IPoint3D d)
|
else if (o is IPoint3D d)
|
||||||
{
|
{
|
||||||
p = new Point3D(d);
|
p = new Point3D(d.X, d.Y, d.Z);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -330,8 +330,8 @@ namespace Server
|
||||||
{
|
{
|
||||||
var rect = Area[i];
|
var rect = Area[i];
|
||||||
|
|
||||||
var start = Map.Bound(new Point2D(rect.Start));
|
var start = Map.Bound(new Point2D(rect.Start.X, rect.Start.Y));
|
||||||
var end = Map.Bound(new Point2D(rect.End));
|
var end = Map.Bound(new Point2D(rect.End.X, rect.Start.Y));
|
||||||
|
|
||||||
var startSector = Map.GetSector(start);
|
var startSector = Map.GetSector(start);
|
||||||
var endSector = Map.GetSector(end);
|
var endSector = Map.GetSector(end);
|
||||||
|
|
|
||||||
|
|
@ -37,20 +37,22 @@ namespace Server
|
||||||
|
|
||||||
protected override void OnTarget(Mobile from, object targeted)
|
protected override void OnTarget(Mobile from, object targeted)
|
||||||
{
|
{
|
||||||
if (targeted is not IPoint3D p)
|
if (targeted is not IPoint3D ip)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p is Item item)
|
Point3D p = ip switch
|
||||||
{
|
{
|
||||||
p = item.GetWorldTop();
|
Item item => item.GetWorldTop(),
|
||||||
}
|
Mobile m => m.Location,
|
||||||
|
_ => new Point3D(ip)
|
||||||
|
};
|
||||||
|
|
||||||
if (m_First)
|
if (m_First)
|
||||||
{
|
{
|
||||||
from.SendMessage("Target another location to complete the bounding box.");
|
from.SendMessage("Target another location to complete the bounding box.");
|
||||||
from.Target = new PickTarget(new Point3D(p), false, from.Map, m_Callback);
|
from.Target = new PickTarget(p, false, from.Map, m_Callback);
|
||||||
}
|
}
|
||||||
else if (from.Map != m_Map)
|
else if (from.Map != m_Map)
|
||||||
{
|
{
|
||||||
|
|
@ -59,7 +61,7 @@ namespace Server
|
||||||
else if (m_Map != null && m_Map != Map.Internal && m_Callback != null)
|
else if (m_Map != null && m_Map != Map.Internal && m_Callback != null)
|
||||||
{
|
{
|
||||||
var start = m_Store;
|
var start = m_Store;
|
||||||
var end = new Point3D(p);
|
var end = p;
|
||||||
|
|
||||||
Utility.FixPoints(ref start, ref end);
|
Utility.FixPoints(ref start, ref end);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -554,21 +554,19 @@ namespace Server.Commands.Generic
|
||||||
|
|
||||||
public override void Execute(CommandEventArgs e, object obj)
|
public override void Execute(CommandEventArgs e, object obj)
|
||||||
{
|
{
|
||||||
if (obj is not IPoint3D p)
|
if (obj is not IPoint3D ip)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p is Item item)
|
Point3D p = ip switch
|
||||||
{
|
{
|
||||||
p = item.GetWorldTop();
|
Item item => item.GetWorldTop(),
|
||||||
}
|
Mobile m => m.Location,
|
||||||
else if (p is Mobile m)
|
_ => new Point3D(ip)
|
||||||
{
|
};
|
||||||
p = m.Location;
|
|
||||||
}
|
|
||||||
|
|
||||||
Add.Invoke(e.Mobile, new Point3D(p), new Point3D(p), e.Arguments);
|
Add.Invoke(e.Mobile, p, p, e.Arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -282,19 +282,21 @@ namespace Server.Gumps
|
||||||
|
|
||||||
protected override void OnTarget(Mobile from, object o)
|
protected override void OnTarget(Mobile from, object o)
|
||||||
{
|
{
|
||||||
if (o is IPoint3D p)
|
if (o is not IPoint3D ip)
|
||||||
{
|
{
|
||||||
p = p switch
|
return;
|
||||||
{
|
|
||||||
Item item => item.GetWorldTop(),
|
|
||||||
Mobile m => m.Location,
|
|
||||||
_ => p
|
|
||||||
};
|
|
||||||
|
|
||||||
Commands.Add.Invoke(from, new Point3D(p), new Point3D(p), new[] { m_Type.Name });
|
|
||||||
|
|
||||||
from.Target = new InternalTarget(m_Type, m_SearchResults, m_SearchString, m_Page);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point3D p = ip switch
|
||||||
|
{
|
||||||
|
Item item => item.GetWorldTop(),
|
||||||
|
Mobile m => m.Location,
|
||||||
|
_ => new Point3D(ip)
|
||||||
|
};
|
||||||
|
|
||||||
|
Commands.Add.Invoke(from, new Point3D(p), new Point3D(p), new[] { m_Type.Name });
|
||||||
|
|
||||||
|
from.Target = new InternalTarget(m_Type, m_SearchResults, m_SearchString, m_Page);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
|
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
|
||||||
|
|
|
||||||
|
|
@ -1,780 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using Server.Commands;
|
|
||||||
using Server.Gumps;
|
|
||||||
using Server.Items;
|
|
||||||
|
|
||||||
namespace Server
|
|
||||||
{
|
|
||||||
public static class Statics
|
|
||||||
{
|
|
||||||
public delegate void FreezeCallback(Mobile from, bool okay, StateInfo si);
|
|
||||||
|
|
||||||
private const string BaseFreezeWarning = "{0} " +
|
|
||||||
"Those items <u>will be removed from the world</u> and placed into the server data files. " +
|
|
||||||
"Other players <u>will not see the changes</u> unless you distribute your data files to them.<br><br>" +
|
|
||||||
"This operation may not complete unless the server and client are using different data files. " +
|
|
||||||
"If you receive a message stating 'output data files could not be opened,' then you are probably sharing data files. " +
|
|
||||||
"Create a new directory for the world data files (statics*.mul and staidx*.mul) and add that to Scritps/Misc/DataPath.cs.<br><br>" +
|
|
||||||
"The change will be in effect immediately on the server, however, you must restart your client and update it's data files for the changes to become visible. " +
|
|
||||||
"It is strongly recommended that you make backup of the data files mentioned above. " +
|
|
||||||
"Do you wish to proceed?";
|
|
||||||
|
|
||||||
private const string BaseUnfreezeWarning = "{0} " +
|
|
||||||
"Those items <u>will be removed from the static files</u> and exchanged with unmovable dynamic items. " +
|
|
||||||
"Other players <u>will not see the changes</u> unless you distribute your data files to them.<br><br>" +
|
|
||||||
"This operation may not complete unless the server and client are using different data files. " +
|
|
||||||
"If you receive a message stating 'output data files could not be opened,' then you are probably sharing data files. " +
|
|
||||||
"Create a new directory for the world data files (statics*.mul and staidx*.mul) and add that to Scritps/Misc/DataPath.cs.<br><br>" +
|
|
||||||
"The change will be in effect immediately on the server, however, you must restart your client and update it's data files for the changes to become visible. " +
|
|
||||||
"It is strongly recommended that you make backup of the data files mentioned above. " +
|
|
||||||
"Do you wish to proceed?";
|
|
||||||
|
|
||||||
private static readonly Point3D NullP3D = new(int.MinValue, int.MinValue, int.MinValue);
|
|
||||||
|
|
||||||
private static byte[] m_Buffer;
|
|
||||||
|
|
||||||
private static StaticTile[] m_TileBuffer = new StaticTile[128];
|
|
||||||
|
|
||||||
public static void Initialize()
|
|
||||||
{
|
|
||||||
CommandSystem.Register("Freeze", AccessLevel.Administrator, Freeze_OnCommand);
|
|
||||||
CommandSystem.Register("FreezeMap", AccessLevel.Administrator, FreezeMap_OnCommand);
|
|
||||||
CommandSystem.Register("FreezeWorld", AccessLevel.Administrator, FreezeWorld_OnCommand);
|
|
||||||
|
|
||||||
CommandSystem.Register("Unfreeze", AccessLevel.Administrator, Unfreeze_OnCommand);
|
|
||||||
CommandSystem.Register("UnfreezeMap", AccessLevel.Administrator, UnfreezeMap_OnCommand);
|
|
||||||
CommandSystem.Register("UnfreezeWorld", AccessLevel.Administrator, UnfreezeWorld_OnCommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Usage("Freeze")]
|
|
||||||
[Description("Makes a targeted area of dynamic items static.")]
|
|
||||||
public static void Freeze_OnCommand(CommandEventArgs e)
|
|
||||||
{
|
|
||||||
var from = e.Mobile;
|
|
||||||
BoundingBoxPicker.Begin(from, (map, start, end) => FreezeBox_Callback(from, map, start, end));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Usage("FreezeMap")]
|
|
||||||
[Description("Makes every dynamic item in your map static.")]
|
|
||||||
public static void FreezeMap_OnCommand(CommandEventArgs e)
|
|
||||||
{
|
|
||||||
var from = e.Mobile;
|
|
||||||
var map = from.Map;
|
|
||||||
|
|
||||||
if (map != null && map != Map.Internal)
|
|
||||||
{
|
|
||||||
SendWarning(
|
|
||||||
from,
|
|
||||||
"You are about to freeze <u>all items in {0}</u>.",
|
|
||||||
BaseFreezeWarning,
|
|
||||||
map,
|
|
||||||
NullP3D,
|
|
||||||
NullP3D,
|
|
||||||
FreezeWarning_Callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Usage("FreezeWorld")]
|
|
||||||
[Description("Makes every dynamic item on all maps static.")]
|
|
||||||
public static void FreezeWorld_OnCommand(CommandEventArgs e)
|
|
||||||
{
|
|
||||||
SendWarning(
|
|
||||||
e.Mobile,
|
|
||||||
"You are about to freeze <u>every item on every map</u>.",
|
|
||||||
BaseFreezeWarning,
|
|
||||||
null,
|
|
||||||
NullP3D,
|
|
||||||
NullP3D,
|
|
||||||
FreezeWarning_Callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendWarning(
|
|
||||||
Mobile m, string header, string baseWarning, Map map, Point3D start, Point3D end,
|
|
||||||
FreezeCallback callback
|
|
||||||
)
|
|
||||||
{
|
|
||||||
m.SendGump(
|
|
||||||
new WarningGump(
|
|
||||||
1060635,
|
|
||||||
30720,
|
|
||||||
string.Format(baseWarning, string.Format(header, map)),
|
|
||||||
0xFFC000,
|
|
||||||
420,
|
|
||||||
400,
|
|
||||||
okay => callback(m, okay, new StateInfo(map, start, end))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void FreezeBox_Callback(Mobile from, Map map, Point3D start, Point3D end)
|
|
||||||
{
|
|
||||||
SendWarning(
|
|
||||||
from,
|
|
||||||
"You are about to freeze a section of items.",
|
|
||||||
BaseFreezeWarning,
|
|
||||||
map,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
FreezeWarning_Callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void FreezeWarning_Callback(Mobile from, bool okay, StateInfo si)
|
|
||||||
{
|
|
||||||
if (!okay)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Freeze(from, si.m_Map, si.m_Start, si.m_End);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Freeze(Mobile from, Map targetMap, Point3D start3d, Point3D end3d)
|
|
||||||
{
|
|
||||||
var mapTable = new Dictionary<Map, Dictionary<Point2D, DeltaState>>();
|
|
||||||
|
|
||||||
if (start3d == NullP3D && end3d == NullP3D)
|
|
||||||
{
|
|
||||||
if (targetMap == null)
|
|
||||||
{
|
|
||||||
CommandLogging.WriteLine(
|
|
||||||
from,
|
|
||||||
"{0} {1} invoking freeze for every item in every map",
|
|
||||||
from.AccessLevel,
|
|
||||||
CommandLogging.Format(from)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CommandLogging.WriteLine(
|
|
||||||
from,
|
|
||||||
"{0} {1} invoking freeze for every item in {0}",
|
|
||||||
from.AccessLevel,
|
|
||||||
CommandLogging.Format(from),
|
|
||||||
targetMap
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in World.Items.Values)
|
|
||||||
{
|
|
||||||
if (targetMap != null && item.Map != targetMap)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.Parent != null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item is Static or BaseFloor or BaseWall)
|
|
||||||
{
|
|
||||||
var itemMap = item.Map;
|
|
||||||
|
|
||||||
if (itemMap == null || itemMap == Map.Internal)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mapTable.TryGetValue(itemMap, out var table))
|
|
||||||
{
|
|
||||||
mapTable[itemMap] = table = new Dictionary<Point2D, DeltaState>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var p = new Point2D(item.X >> 3, item.Y >> 3);
|
|
||||||
|
|
||||||
if (!table.TryGetValue(p, out var state))
|
|
||||||
{
|
|
||||||
table[p] = state = new DeltaState(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.m_List.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (targetMap != null)
|
|
||||||
{
|
|
||||||
Point2D start = targetMap.Bound(new Point2D(start3d)), end = targetMap.Bound(new Point2D(end3d));
|
|
||||||
|
|
||||||
CommandLogging.WriteLine(
|
|
||||||
from,
|
|
||||||
"{0} {1} invoking freeze from {2} to {3} in {4}",
|
|
||||||
from.AccessLevel,
|
|
||||||
CommandLogging.Format(from),
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
targetMap
|
|
||||||
);
|
|
||||||
|
|
||||||
var eable =
|
|
||||||
targetMap.GetItemsInBounds(new Rectangle2D(start.X, start.Y, end.X - start.X + 1, end.Y - start.Y + 1));
|
|
||||||
|
|
||||||
foreach (var item in eable)
|
|
||||||
{
|
|
||||||
if (item is Static or BaseFloor or BaseWall)
|
|
||||||
{
|
|
||||||
var itemMap = item.Map;
|
|
||||||
|
|
||||||
if (itemMap == null || itemMap == Map.Internal)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mapTable.TryGetValue(itemMap, out var table))
|
|
||||||
{
|
|
||||||
mapTable[itemMap] = table = new Dictionary<Point2D, DeltaState>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var p = new Point2D(item.X >> 3, item.Y >> 3);
|
|
||||||
|
|
||||||
if (!table.TryGetValue(p, out var state))
|
|
||||||
{
|
|
||||||
table[p] = state = new DeltaState(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.m_List.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eable.Free();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapTable.Count == 0)
|
|
||||||
{
|
|
||||||
from.SendGump(
|
|
||||||
new NoticeGump(
|
|
||||||
1060637,
|
|
||||||
30720,
|
|
||||||
"No freezable items were found. Only the following item types are frozen:<br> - Static<br> - BaseFloor<br> - BaseWall",
|
|
||||||
0xFFC000,
|
|
||||||
320,
|
|
||||||
240
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var badDataFile = false;
|
|
||||||
|
|
||||||
var totalFrozen = 0;
|
|
||||||
|
|
||||||
foreach (var de in mapTable)
|
|
||||||
{
|
|
||||||
var map = de.Key;
|
|
||||||
var table = de.Value;
|
|
||||||
|
|
||||||
var matrix = map.Tiles;
|
|
||||||
|
|
||||||
using var idxStream = OpenWrite(matrix.IndexStream);
|
|
||||||
using var mulStream = OpenWrite(matrix.DataStream);
|
|
||||||
if (idxStream == null || mulStream == null)
|
|
||||||
{
|
|
||||||
badDataFile = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var idxReader = new BinaryReader(idxStream);
|
|
||||||
|
|
||||||
var idxWriter = new BinaryWriter(idxStream);
|
|
||||||
var mulWriter = new BinaryWriter(mulStream);
|
|
||||||
|
|
||||||
foreach (var state in table.Values)
|
|
||||||
{
|
|
||||||
var oldTiles = ReadStaticBlock(
|
|
||||||
idxReader,
|
|
||||||
mulStream,
|
|
||||||
state.m_X,
|
|
||||||
state.m_Y,
|
|
||||||
matrix.BlockWidth,
|
|
||||||
matrix.BlockHeight,
|
|
||||||
out var oldTileCount
|
|
||||||
);
|
|
||||||
|
|
||||||
if (oldTileCount < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var newTileCount = 0;
|
|
||||||
var newTiles = new StaticTile[state.m_List.Count];
|
|
||||||
|
|
||||||
for (var i = 0; i < state.m_List.Count; ++i)
|
|
||||||
{
|
|
||||||
var item = state.m_List[i];
|
|
||||||
|
|
||||||
var xOffset = item.X - state.m_X * 8;
|
|
||||||
var yOffset = item.Y - state.m_Y * 8;
|
|
||||||
|
|
||||||
if (xOffset is < 0 or >= 8 || yOffset is < 0 or >= 8)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var newTile = new StaticTile(
|
|
||||||
(ushort)item.ItemID,
|
|
||||||
(byte)xOffset,
|
|
||||||
(byte)yOffset,
|
|
||||||
(sbyte)item.Z,
|
|
||||||
(short)item.Hue
|
|
||||||
);
|
|
||||||
|
|
||||||
newTiles[newTileCount++] = newTile;
|
|
||||||
|
|
||||||
item.Delete();
|
|
||||||
|
|
||||||
++totalFrozen;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mulPos = -1;
|
|
||||||
var length = -1;
|
|
||||||
var extra = 0;
|
|
||||||
|
|
||||||
if (oldTileCount + newTileCount > 0)
|
|
||||||
{
|
|
||||||
mulWriter.Seek(0, SeekOrigin.End);
|
|
||||||
|
|
||||||
mulPos = (int)mulWriter.BaseStream.Position;
|
|
||||||
length = (oldTileCount + newTileCount) * 7;
|
|
||||||
extra = 1;
|
|
||||||
|
|
||||||
for (var i = 0; i < oldTileCount; ++i)
|
|
||||||
{
|
|
||||||
var toWrite = oldTiles[i];
|
|
||||||
|
|
||||||
mulWriter.Write((ushort)toWrite.ID);
|
|
||||||
mulWriter.Write((byte)toWrite.X);
|
|
||||||
mulWriter.Write((byte)toWrite.Y);
|
|
||||||
mulWriter.Write((sbyte)toWrite.Z);
|
|
||||||
mulWriter.Write((short)toWrite.Hue);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < newTileCount; ++i)
|
|
||||||
{
|
|
||||||
var toWrite = newTiles[i];
|
|
||||||
|
|
||||||
mulWriter.Write((ushort)toWrite.ID);
|
|
||||||
mulWriter.Write((byte)toWrite.X);
|
|
||||||
mulWriter.Write((byte)toWrite.Y);
|
|
||||||
mulWriter.Write((sbyte)toWrite.Z);
|
|
||||||
mulWriter.Write((short)toWrite.Hue);
|
|
||||||
}
|
|
||||||
|
|
||||||
mulWriter.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
var idxPos = (state.m_X * matrix.BlockHeight + state.m_Y) * 12;
|
|
||||||
|
|
||||||
idxWriter.Seek(idxPos, SeekOrigin.Begin);
|
|
||||||
idxWriter.Write(mulPos);
|
|
||||||
idxWriter.Write(length);
|
|
||||||
idxWriter.Write(extra);
|
|
||||||
|
|
||||||
idxWriter.Flush();
|
|
||||||
|
|
||||||
matrix.SetStaticBlock(state.m_X, state.m_Y, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalFrozen == 0 && badDataFile)
|
|
||||||
{
|
|
||||||
from.SendGump(
|
|
||||||
new NoticeGump(
|
|
||||||
1060637,
|
|
||||||
30720,
|
|
||||||
"Output data files could not be opened and the freeze operation has been aborted.<br><br>This probably means your server and client are using the same data files. Instructions on how to resolve this can be found in the first warning window.",
|
|
||||||
0xFFC000,
|
|
||||||
320,
|
|
||||||
240
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
from.SendGump(
|
|
||||||
new NoticeGump(
|
|
||||||
1060637,
|
|
||||||
30720,
|
|
||||||
$"Freeze operation completed successfully.<br><br>{totalFrozen} item{(totalFrozen != 1 ? "s were" : " was")} frozen.<br><br>You must restart your client and update it's data files to see the changes.",
|
|
||||||
0xFFC000,
|
|
||||||
320,
|
|
||||||
240
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Usage("Unfreeze")]
|
|
||||||
[Description("Makes a targeted area of static items dynamic.")]
|
|
||||||
public static void Unfreeze_OnCommand(CommandEventArgs e)
|
|
||||||
{
|
|
||||||
var from = e.Mobile;
|
|
||||||
BoundingBoxPicker.Begin(from, (map, start, end) => UnfreezeBox_Callback(from, map, start, end));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Usage("UnfreezeMap")]
|
|
||||||
[Description("Makes every static item in your map dynamic.")]
|
|
||||||
public static void UnfreezeMap_OnCommand(CommandEventArgs e)
|
|
||||||
{
|
|
||||||
var map = e.Mobile.Map;
|
|
||||||
|
|
||||||
if (map != null && map != Map.Internal)
|
|
||||||
{
|
|
||||||
SendWarning(
|
|
||||||
e.Mobile,
|
|
||||||
"You are about to unfreeze <u>all items in {0}</u>.",
|
|
||||||
BaseUnfreezeWarning,
|
|
||||||
map,
|
|
||||||
NullP3D,
|
|
||||||
NullP3D,
|
|
||||||
UnfreezeWarning_Callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Usage("UnfreezeWorld")]
|
|
||||||
[Description("Makes every static item on all maps dynamic.")]
|
|
||||||
public static void UnfreezeWorld_OnCommand(CommandEventArgs e)
|
|
||||||
{
|
|
||||||
SendWarning(
|
|
||||||
e.Mobile,
|
|
||||||
"You are about to unfreeze <u>every item on every map</u>.",
|
|
||||||
BaseUnfreezeWarning,
|
|
||||||
null,
|
|
||||||
NullP3D,
|
|
||||||
NullP3D,
|
|
||||||
UnfreezeWarning_Callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UnfreezeBox_Callback(Mobile from, Map map, Point3D start, Point3D end)
|
|
||||||
{
|
|
||||||
SendWarning(
|
|
||||||
from,
|
|
||||||
"You are about to unfreeze a section of items.",
|
|
||||||
BaseUnfreezeWarning,
|
|
||||||
map,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
UnfreezeWarning_Callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UnfreezeWarning_Callback(Mobile from, bool okay, StateInfo si)
|
|
||||||
{
|
|
||||||
if (!okay)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Unfreeze(from, si.m_Map, si.m_Start, si.m_End);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DoUnfreeze(Map map, Point2D start, Point2D end, ref bool badDataFile, ref int totalUnfrozen)
|
|
||||||
{
|
|
||||||
start = map.Bound(start);
|
|
||||||
end = map.Bound(end);
|
|
||||||
|
|
||||||
var xStartBlock = start.X >> 3;
|
|
||||||
var yStartBlock = start.Y >> 3;
|
|
||||||
var xEndBlock = end.X >> 3;
|
|
||||||
var yEndBlock = end.Y >> 3;
|
|
||||||
|
|
||||||
int xTileStart = start.X, yTileStart = start.Y;
|
|
||||||
int xTileWidth = end.X - start.X + 1, yTileHeight = end.Y - start.Y + 1;
|
|
||||||
|
|
||||||
var matrix = map.Tiles;
|
|
||||||
|
|
||||||
using var idxStream = OpenWrite(matrix.IndexStream);
|
|
||||||
using var mulStream = OpenWrite(matrix.DataStream);
|
|
||||||
if (idxStream == null || mulStream == null)
|
|
||||||
{
|
|
||||||
badDataFile = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var idxReader = new BinaryReader(idxStream);
|
|
||||||
|
|
||||||
var idxWriter = new BinaryWriter(idxStream);
|
|
||||||
var mulWriter = new BinaryWriter(mulStream);
|
|
||||||
|
|
||||||
for (var x = xStartBlock; x <= xEndBlock; ++x)
|
|
||||||
{
|
|
||||||
for (var y = yStartBlock; y <= yEndBlock; ++y)
|
|
||||||
{
|
|
||||||
var oldTiles = ReadStaticBlock(
|
|
||||||
idxReader,
|
|
||||||
mulStream,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
matrix.BlockWidth,
|
|
||||||
matrix.BlockHeight,
|
|
||||||
out var oldTileCount
|
|
||||||
);
|
|
||||||
|
|
||||||
if (oldTileCount < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var newTileCount = 0;
|
|
||||||
var newTiles = new StaticTile[oldTileCount];
|
|
||||||
|
|
||||||
int baseX = (x << 3) - xTileStart, baseY = (y << 3) - yTileStart;
|
|
||||||
|
|
||||||
for (var i = 0; i < oldTileCount; ++i)
|
|
||||||
{
|
|
||||||
var oldTile = oldTiles[i];
|
|
||||||
|
|
||||||
var px = baseX + oldTile.X;
|
|
||||||
var py = baseY + oldTile.Y;
|
|
||||||
|
|
||||||
if (px < 0 || px >= xTileWidth || py < 0 || py >= yTileHeight)
|
|
||||||
{
|
|
||||||
newTiles[newTileCount++] = oldTile;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++totalUnfrozen;
|
|
||||||
|
|
||||||
Item item = new Static(oldTile.ID);
|
|
||||||
|
|
||||||
item.Hue = oldTile.Hue;
|
|
||||||
|
|
||||||
item.MoveToWorld(new Point3D(px + xTileStart, py + yTileStart, oldTile.Z), map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var mulPos = -1;
|
|
||||||
var length = -1;
|
|
||||||
var extra = 0;
|
|
||||||
|
|
||||||
if (newTileCount > 0)
|
|
||||||
{
|
|
||||||
mulWriter.Seek(0, SeekOrigin.End);
|
|
||||||
|
|
||||||
mulPos = (int)mulWriter.BaseStream.Position;
|
|
||||||
length = newTileCount * 7;
|
|
||||||
extra = 1;
|
|
||||||
|
|
||||||
for (var i = 0; i < newTileCount; ++i)
|
|
||||||
{
|
|
||||||
var toWrite = newTiles[i];
|
|
||||||
|
|
||||||
mulWriter.Write((ushort)toWrite.ID);
|
|
||||||
mulWriter.Write((byte)toWrite.X);
|
|
||||||
mulWriter.Write((byte)toWrite.Y);
|
|
||||||
mulWriter.Write((sbyte)toWrite.Z);
|
|
||||||
mulWriter.Write((short)toWrite.Hue);
|
|
||||||
}
|
|
||||||
|
|
||||||
mulWriter.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
var idxPos = (x * matrix.BlockHeight + y) * 12;
|
|
||||||
|
|
||||||
idxWriter.Seek(idxPos, SeekOrigin.Begin);
|
|
||||||
idxWriter.Write(mulPos);
|
|
||||||
idxWriter.Write(length);
|
|
||||||
idxWriter.Write(extra);
|
|
||||||
|
|
||||||
idxWriter.Flush();
|
|
||||||
|
|
||||||
matrix.SetStaticBlock(x, y, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DoUnfreeze(Map map, ref bool badDataFile, ref int totalUnfrozen)
|
|
||||||
{
|
|
||||||
DoUnfreeze(map, Point2D.Zero, new Point2D(map.Width - 1, map.Height - 1), ref badDataFile, ref totalUnfrozen);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Unfreeze(Mobile from, Map map, Point3D start, Point3D end)
|
|
||||||
{
|
|
||||||
var totalUnfrozen = 0;
|
|
||||||
var badDataFile = false;
|
|
||||||
|
|
||||||
if (map == null)
|
|
||||||
{
|
|
||||||
CommandLogging.WriteLine(
|
|
||||||
from,
|
|
||||||
"{0} {1} invoking unfreeze for every item in every map",
|
|
||||||
from.AccessLevel,
|
|
||||||
CommandLogging.Format(from)
|
|
||||||
);
|
|
||||||
|
|
||||||
DoUnfreeze(Map.Felucca, ref badDataFile, ref totalUnfrozen);
|
|
||||||
DoUnfreeze(Map.Trammel, ref badDataFile, ref totalUnfrozen);
|
|
||||||
DoUnfreeze(Map.Ilshenar, ref badDataFile, ref totalUnfrozen);
|
|
||||||
DoUnfreeze(Map.Malas, ref badDataFile, ref totalUnfrozen);
|
|
||||||
DoUnfreeze(Map.Tokuno, ref badDataFile, ref totalUnfrozen);
|
|
||||||
}
|
|
||||||
else if (start == NullP3D && end == NullP3D)
|
|
||||||
{
|
|
||||||
CommandLogging.WriteLine(
|
|
||||||
from,
|
|
||||||
"{0} {1} invoking unfreeze for every item in {2}",
|
|
||||||
from.AccessLevel,
|
|
||||||
CommandLogging.Format(from),
|
|
||||||
map
|
|
||||||
);
|
|
||||||
|
|
||||||
DoUnfreeze(map, ref badDataFile, ref totalUnfrozen);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CommandLogging.WriteLine(
|
|
||||||
from,
|
|
||||||
"{0} {1} invoking unfreeze from {2} to {3} in {4}",
|
|
||||||
from.AccessLevel,
|
|
||||||
CommandLogging.Format(from),
|
|
||||||
new Point2D(start),
|
|
||||||
new Point2D(end),
|
|
||||||
map
|
|
||||||
);
|
|
||||||
|
|
||||||
DoUnfreeze(map, new Point2D(start), new Point2D(end), ref badDataFile, ref totalUnfrozen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalUnfrozen == 0 && badDataFile)
|
|
||||||
{
|
|
||||||
from.SendGump(
|
|
||||||
new NoticeGump(
|
|
||||||
1060637,
|
|
||||||
30720,
|
|
||||||
"Output data files could not be opened and the unfreeze operation has been aborted.<br><br>This probably means your server and client are using the same data files. Instructions on how to resolve this can be found in the first warning window.",
|
|
||||||
0xFFC000,
|
|
||||||
320,
|
|
||||||
240
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
from.SendGump(
|
|
||||||
new NoticeGump(
|
|
||||||
1060637,
|
|
||||||
30720,
|
|
||||||
$"Unfreeze operation completed successfully.<br><br>{totalUnfrozen} item{(totalUnfrozen != 1 ? "s were" : " was")} unfrozen.<br><br>You must restart your client and update it's data files to see the changes.",
|
|
||||||
0xFFC000,
|
|
||||||
320,
|
|
||||||
240
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FileStream OpenWrite(FileStream orig)
|
|
||||||
{
|
|
||||||
if (orig == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new FileStream(orig.Name, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StaticTile[] ReadStaticBlock(
|
|
||||||
BinaryReader idxReader, FileStream mulStream, int x, int y, int width,
|
|
||||||
int height, out int count
|
|
||||||
)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
|
||||||
{
|
|
||||||
count = -1;
|
|
||||||
return m_TileBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
idxReader.BaseStream.Seek((x * height + y) * 12, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
var lookup = idxReader.ReadInt32();
|
|
||||||
var length = idxReader.ReadInt32();
|
|
||||||
|
|
||||||
if (lookup < 0 || length <= 0)
|
|
||||||
{
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = length / 7;
|
|
||||||
|
|
||||||
mulStream.Seek(lookup, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
if (m_TileBuffer.Length < count)
|
|
||||||
{
|
|
||||||
m_TileBuffer = new StaticTile[count];
|
|
||||||
}
|
|
||||||
|
|
||||||
var staTiles = m_TileBuffer;
|
|
||||||
|
|
||||||
if (m_Buffer == null || length > m_Buffer.Length)
|
|
||||||
{
|
|
||||||
m_Buffer = GC.AllocateUninitializedArray<byte>(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
mulStream.Read(m_Buffer, 0, length);
|
|
||||||
|
|
||||||
var index = 0;
|
|
||||||
|
|
||||||
for (var i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
staTiles[i]
|
|
||||||
.Set(
|
|
||||||
(ushort)(m_Buffer[index++] | (m_Buffer[index++] << 8)),
|
|
||||||
m_Buffer[index++],
|
|
||||||
m_Buffer[index++],
|
|
||||||
(sbyte)m_Buffer[index++],
|
|
||||||
(short)(m_Buffer[index++] | (m_Buffer[index++] << 8))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
count = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_TileBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DeltaState
|
|
||||||
{
|
|
||||||
public readonly List<Item> m_List;
|
|
||||||
public readonly int m_X;
|
|
||||||
public readonly int m_Y;
|
|
||||||
|
|
||||||
public DeltaState(Point2D p)
|
|
||||||
{
|
|
||||||
m_X = p.X;
|
|
||||||
m_Y = p.Y;
|
|
||||||
m_List = new List<Item>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StateInfo
|
|
||||||
{
|
|
||||||
public Map m_Map;
|
|
||||||
public Point3D m_Start, m_End;
|
|
||||||
|
|
||||||
public StateInfo(Map map, Point3D start, Point3D end)
|
|
||||||
{
|
|
||||||
m_Map = map;
|
|
||||||
m_Start = start;
|
|
||||||
m_End = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -95,7 +95,7 @@ namespace Server
|
||||||
foreach (var m in eable)
|
foreach (var m in eable)
|
||||||
{
|
{
|
||||||
if (from.CanBeHarmful(m, false) &&
|
if (from.CanBeHarmful(m, false) &&
|
||||||
m.InLOS(new Point3D(origin, origin.Z + 1)) &&
|
m.InLOS(new Point3D(origin.X, origin.Y, origin.Z + 1)) &&
|
||||||
Faction.Find(m) != null)
|
Faction.Find(m) != null)
|
||||||
{
|
{
|
||||||
targets.Add(from);
|
targets.Add(from);
|
||||||
|
|
@ -118,7 +118,7 @@ namespace Server
|
||||||
}
|
}
|
||||||
|
|
||||||
Effects.SendMovingEffect(
|
Effects.SendMovingEffect(
|
||||||
new Entity(Serial.Zero, new Point3D(origin, origin.Z + 4), facet),
|
new Entity(Serial.Zero, new Point3D(origin.X, origin.Y, origin.Z + 4), facet),
|
||||||
mob,
|
mob,
|
||||||
14068,
|
14068,
|
||||||
1,
|
1,
|
||||||
|
|
|
||||||
|
|
@ -261,16 +261,6 @@ namespace Server.Gumps
|
||||||
AddButtonLabeled(20, 225, GetButtonID(3, 104), "Doors");
|
AddButtonLabeled(20, 225, GetButtonID(3, 104), "Doors");
|
||||||
AddButtonLabeled(220, 225, GetButtonID(3, 105), "Signs");
|
AddButtonLabeled(220, 225, GetButtonID(3, 105), "Signs");
|
||||||
|
|
||||||
AddHtml(20, 275, 400, 30, Color(Center("Statics"), LabelColor32));
|
|
||||||
|
|
||||||
AddButtonLabeled(20, 300, GetButtonID(3, 110), "Freeze (Target)");
|
|
||||||
AddButtonLabeled(20, 325, GetButtonID(3, 111), "Freeze (World)");
|
|
||||||
AddButtonLabeled(20, 350, GetButtonID(3, 112), "Freeze (Map)");
|
|
||||||
|
|
||||||
AddButtonLabeled(220, 300, GetButtonID(3, 120), "Unfreeze (Target)");
|
|
||||||
AddButtonLabeled(220, 325, GetButtonID(3, 121), "Unfreeze (World)");
|
|
||||||
AddButtonLabeled(220, 350, GetButtonID(3, 122), "Unfreeze (Map)");
|
|
||||||
|
|
||||||
goto case AdminGumpPage.Administer;
|
goto case AdminGumpPage.Administer;
|
||||||
}
|
}
|
||||||
case AdminGumpPage.Administer_Server:
|
case AdminGumpPage.Administer_Server:
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ namespace Server.Gumps
|
||||||
{
|
{
|
||||||
case 1: // Current location
|
case 1: // Current location
|
||||||
{
|
{
|
||||||
toSet = new Point2D(m_Mobile.Location);
|
toSet = new Point2D(m_Mobile.Location.X, m_Mobile.Location.Y);
|
||||||
shouldSet = true;
|
shouldSet = true;
|
||||||
shouldSend = true;
|
shouldSend = true;
|
||||||
|
|
||||||
|
|
@ -194,12 +194,13 @@ namespace Server.Gumps
|
||||||
|
|
||||||
protected override void OnTarget(Mobile from, object targeted)
|
protected override void OnTarget(Mobile from, object targeted)
|
||||||
{
|
{
|
||||||
if (targeted is IPoint3D p)
|
if (targeted is IPoint3D point3D)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, new Point2D(p).ToString());
|
var p = new Point2D(point3D.X, point3D.Y);
|
||||||
m_Property.SetValue(m_Object, new Point2D(p), null);
|
CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, p.ToString());
|
||||||
|
m_Property.SetValue(m_Object, p, null);
|
||||||
m_PropertiesGump.OnValueChanged(m_Object, m_Property);
|
m_PropertiesGump.OnValueChanged(m_Object, m_Property);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,7 @@ namespace Server.Items
|
||||||
|
|
||||||
if (floorZ > int.MinValue && item.Z < floorZ + 15) // Confirmed : no height checks here
|
if (floorZ > int.MinValue && item.Z < floorZ + 15) // Confirmed : no height checks here
|
||||||
{
|
{
|
||||||
item.Location = new Point3D(item.Location, item.Z + 1);
|
item.Location = new Point3D(item.Location.X, item.Location.Y, item.Z + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -334,7 +334,7 @@ namespace Server.Items
|
||||||
|
|
||||||
if (floorZ > int.MinValue && item.Z > GetFloorZ(item))
|
if (floorZ > int.MinValue && item.Z > GetFloorZ(item))
|
||||||
{
|
{
|
||||||
item.Location = new Point3D(item.Location, item.Z - 1);
|
item.Location = new Point3D(item.Location.X, item.Location.Y, item.Z - 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ namespace Server.Multis
|
||||||
{
|
{
|
||||||
if (ip is Item item)
|
if (ip is Item item)
|
||||||
{
|
{
|
||||||
ip = item.GetWorldTop();
|
ip = from;
|
||||||
}
|
}
|
||||||
|
|
||||||
var p = new Point3D(ip);
|
var p = new Point3D(ip);
|
||||||
|
|
|
||||||
|
|
@ -194,29 +194,31 @@ namespace Server.Multis
|
||||||
|
|
||||||
protected override void OnTarget(Mobile from, object o)
|
protected override void OnTarget(Mobile from, object o)
|
||||||
{
|
{
|
||||||
if (o is IPoint3D ip)
|
if (o is not IPoint3D ip)
|
||||||
{
|
{
|
||||||
if (ip is Item item)
|
return;
|
||||||
{
|
}
|
||||||
ip = item.GetWorldTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
var p = new Point3D(ip);
|
Point3D p = ip switch
|
||||||
|
{
|
||||||
|
Item item => item.GetWorldTop(),
|
||||||
|
Mobile m => m.Location,
|
||||||
|
_ => new Point3D(ip)
|
||||||
|
};
|
||||||
|
|
||||||
var region = Region.Find(p, from.Map);
|
var region = Region.Find(p, from.Map);
|
||||||
|
|
||||||
if (region.IsPartOf<DungeonRegion>())
|
if (region.IsPartOf<DungeonRegion>())
|
||||||
{
|
{
|
||||||
from.SendLocalizedMessage(502488); // You can not place a ship inside a dungeon.
|
from.SendLocalizedMessage(502488); // You can not place a ship inside a dungeon.
|
||||||
}
|
}
|
||||||
else if (region.IsPartOf<HouseRegion>() || region.IsPartOf<ChampionSpawnRegion>())
|
else if (region.IsPartOf<HouseRegion>() || region.IsPartOf<ChampionSpawnRegion>())
|
||||||
{
|
{
|
||||||
from.SendLocalizedMessage(1042549); // A boat may not be placed in this area.
|
from.SendLocalizedMessage(1042549); // A boat may not be placed in this area.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_Model.OnPlacement(from, p);
|
m_Model.OnPlacement(from, p);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,41 +11,41 @@ namespace Server.Multis.Deeds
|
||||||
|
|
||||||
protected override void OnTarget(Mobile from, object o)
|
protected override void OnTarget(Mobile from, object o)
|
||||||
{
|
{
|
||||||
if (o is IPoint3D ip)
|
if (o is not IPoint3D ip)
|
||||||
{
|
{
|
||||||
if (ip is Item item)
|
return;
|
||||||
{
|
}
|
||||||
ip = item.GetWorldTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
var p = new Point3D(ip);
|
Point3D p = ip switch
|
||||||
|
{
|
||||||
|
Item item => item.GetWorldTop(),
|
||||||
|
Mobile m => m.Location,
|
||||||
|
_ => new Point3D(ip)
|
||||||
|
};
|
||||||
|
|
||||||
var reg = Region.Find(new Point3D(p), from.Map);
|
var reg = Region.Find(p, from.Map);
|
||||||
|
|
||||||
if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p))
|
if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p))
|
||||||
{
|
{
|
||||||
m_Deed.OnPlacement(from, p);
|
m_Deed.OnPlacement(from, p);
|
||||||
}
|
}
|
||||||
else if (reg.IsPartOf<TempNoHousingRegion>())
|
else if (reg.IsPartOf<TempNoHousingRegion>())
|
||||||
{
|
{
|
||||||
from.SendLocalizedMessage(
|
// Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
|
||||||
501270
|
from.SendLocalizedMessage(501270);
|
||||||
); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
|
}
|
||||||
}
|
else if (reg.IsPartOf<TreasureRegion>() || reg.IsPartOf<HouseRegion>())
|
||||||
else if (reg.IsPartOf<TreasureRegion>() || reg.IsPartOf<HouseRegion>())
|
{
|
||||||
{
|
// The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
|
||||||
from.SendLocalizedMessage(
|
from.SendLocalizedMessage(1043287);
|
||||||
1043287
|
}
|
||||||
); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
|
else if (reg.IsPartOf<HouseRaffleRegion>())
|
||||||
}
|
{
|
||||||
else if (reg.IsPartOf<HouseRaffleRegion>())
|
from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here.
|
||||||
{
|
}
|
||||||
from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here.
|
else
|
||||||
}
|
{
|
||||||
else
|
from.SendLocalizedMessage(501265); // Housing can not be created in this area.
|
||||||
{
|
|
||||||
from.SendLocalizedMessage(501265); // Housing can not be created in this area.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,9 +184,8 @@ namespace Server.Multis.Deeds
|
||||||
case HousePlacementResult.BadStatic:
|
case HousePlacementResult.BadStatic:
|
||||||
case HousePlacementResult.BadRegionHidden:
|
case HousePlacementResult.BadRegionHidden:
|
||||||
{
|
{
|
||||||
from.SendLocalizedMessage(
|
// The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
|
||||||
1043287
|
from.SendLocalizedMessage(1043287);
|
||||||
); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HousePlacementResult.NoSurface:
|
case HousePlacementResult.NoSurface:
|
||||||
|
|
@ -203,16 +202,14 @@ namespace Server.Multis.Deeds
|
||||||
}
|
}
|
||||||
case HousePlacementResult.BadRegionTemp:
|
case HousePlacementResult.BadRegionTemp:
|
||||||
{
|
{
|
||||||
from.SendLocalizedMessage(
|
// Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
|
||||||
501270
|
from.SendLocalizedMessage(501270);
|
||||||
); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HousePlacementResult.BadRegionRaffle:
|
case HousePlacementResult.BadRegionRaffle:
|
||||||
{
|
{
|
||||||
from.SendLocalizedMessage(
|
// You must have a deed for this plot of land in order to build here.
|
||||||
1150493
|
from.SendLocalizedMessage(1150493);
|
||||||
); // You must have a deed for this plot of land in order to build here.
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -250,46 +250,46 @@ namespace Server.Items
|
||||||
|
|
||||||
protected override void OnTarget(Mobile from, object o)
|
protected override void OnTarget(Mobile from, object o)
|
||||||
{
|
{
|
||||||
|
if (o is not IPoint3D ip)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!from.CheckAlive() || from.Backpack?.FindItemByType<HousePlacementTool>() == null)
|
if (!from.CheckAlive() || from.Backpack?.FindItemByType<HousePlacementTool>() == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o is IPoint3D ip)
|
Point3D p = ip switch
|
||||||
{
|
{
|
||||||
if (ip is Item item)
|
Item item => item.GetWorldTop(),
|
||||||
{
|
Mobile m => m.Location,
|
||||||
ip = item.GetWorldTop();
|
_ => new Point3D(ip)
|
||||||
}
|
};
|
||||||
|
|
||||||
var p = new Point3D(ip);
|
var reg = Region.Find(p, from.Map);
|
||||||
|
|
||||||
var reg = Region.Find(new Point3D(p), from.Map);
|
if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p))
|
||||||
|
{
|
||||||
if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p))
|
m_Placed = m_Entry.OnPlacement(from, p);
|
||||||
{
|
}
|
||||||
m_Placed = m_Entry.OnPlacement(from, p);
|
else if (reg.IsPartOf<TempNoHousingRegion>())
|
||||||
}
|
{
|
||||||
else if (reg.IsPartOf<TempNoHousingRegion>())
|
// Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
|
||||||
{
|
from.SendLocalizedMessage(501270);
|
||||||
from.SendLocalizedMessage(
|
}
|
||||||
501270
|
else if (reg.IsPartOf<TreasureRegion>() || reg.IsPartOf<HouseRegion>())
|
||||||
); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
|
{
|
||||||
}
|
// The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
|
||||||
else if (reg.IsPartOf<TreasureRegion>() || reg.IsPartOf<HouseRegion>())
|
from.SendLocalizedMessage(1043287);
|
||||||
{
|
}
|
||||||
from.SendLocalizedMessage(
|
else if (reg.IsPartOf<HouseRaffleRegion>())
|
||||||
1043287
|
{
|
||||||
); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
|
from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here.
|
||||||
}
|
}
|
||||||
else if (reg.IsPartOf<HouseRaffleRegion>())
|
else
|
||||||
{
|
{
|
||||||
from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here.
|
from.SendLocalizedMessage(501265); // Housing can not be created in this area.
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
from.SendLocalizedMessage(501265); // Housing can not be created in this area.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,7 @@ namespace Server.Items
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var m = m_Mobile;
|
if (m_Mobile.Location != m_Teleporter.Location || m_Mobile.Map != m_Teleporter.Map)
|
||||||
|
|
||||||
if (m.Location != m_Teleporter.Location || m.Map != m_Teleporter.Map)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -165,11 +163,11 @@ namespace Server.Items
|
||||||
var p = target.GetWorldTop();
|
var p = target.GetWorldTop();
|
||||||
var map = target.Map;
|
var map = target.Map;
|
||||||
|
|
||||||
BaseCreature.TeleportPets(m, p, map);
|
BaseCreature.TeleportPets(m_Mobile, p, map);
|
||||||
|
|
||||||
m.MoveToWorld(p, map);
|
m_Mobile.MoveToWorld(p, map);
|
||||||
|
|
||||||
if (m.Hidden && m.AccessLevel != AccessLevel.Player)
|
if (m_Mobile.Hidden && m_Mobile.AccessLevel != AccessLevel.Player)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,41 +12,45 @@ namespace Server.Targets
|
||||||
|
|
||||||
protected override void OnTarget(Mobile from, object o)
|
protected override void OnTarget(Mobile from, object o)
|
||||||
{
|
{
|
||||||
if (o is IPoint3D p)
|
if (o is not IPoint3D ip)
|
||||||
{
|
{
|
||||||
if (!BaseCommand.IsAccessible(from, m_Object))
|
return;
|
||||||
{
|
}
|
||||||
from.SendLocalizedMessage(500447); // That is not accessible.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p is Item pItem)
|
if (!BaseCommand.IsAccessible(from, m_Object))
|
||||||
{
|
{
|
||||||
p = pItem.GetWorldTop();
|
from.SendLocalizedMessage(500447); // That is not accessible.
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CommandLogging.WriteLine(
|
Point3D p = ip switch
|
||||||
from,
|
{
|
||||||
"{0} {1} moving {2} to {3}",
|
Item i => i.GetWorldTop(),
|
||||||
from.AccessLevel,
|
Mobile m => m.Location,
|
||||||
CommandLogging.Format(from),
|
_ => new Point3D(ip)
|
||||||
CommandLogging.Format(m_Object),
|
};
|
||||||
new Point3D(p)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (m_Object is Item item)
|
CommandLogging.WriteLine(
|
||||||
|
from,
|
||||||
|
"{0} {1} moving {2} to {3}",
|
||||||
|
from.AccessLevel,
|
||||||
|
CommandLogging.Format(from),
|
||||||
|
CommandLogging.Format(m_Object),
|
||||||
|
p
|
||||||
|
);
|
||||||
|
|
||||||
|
if (m_Object is Item item)
|
||||||
|
{
|
||||||
|
if (!item.Deleted)
|
||||||
{
|
{
|
||||||
if (!item.Deleted)
|
item.MoveToWorld(p, from.Map);
|
||||||
{
|
|
||||||
item.MoveToWorld(new Point3D(p), from.Map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (m_Object is Mobile m)
|
}
|
||||||
|
else if (m_Object is Mobile m)
|
||||||
|
{
|
||||||
|
if (!m.Deleted)
|
||||||
{
|
{
|
||||||
if (!m.Deleted)
|
m.MoveToWorld(p, from.Map);
|
||||||
{
|
|
||||||
m.MoveToWorld(new Point3D(p), from.Map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue