Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
159
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AccountExt.cs
Normal file
159
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AccountExt.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Accounting;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class AccountExtUtility
|
||||
{
|
||||
public static bool IsOnline(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, m => m.IsOnline()).Any();
|
||||
}
|
||||
|
||||
public static Mobile GetOnlineMobile(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, m => m.IsOnline()).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static TMob GetOnlineMobile<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles<TMob>(acc, m => m.IsOnline()).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static Mobile[] GetMobiles(this IAccount acc)
|
||||
{
|
||||
return GetMobiles(acc, null);
|
||||
}
|
||||
|
||||
public static Mobile[] GetMobiles(this IAccount acc, Func<Mobile, bool> predicate)
|
||||
{
|
||||
return FindMobiles(acc, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Mobile> FindMobiles(this IAccount acc)
|
||||
{
|
||||
return FindMobiles(acc, null);
|
||||
}
|
||||
|
||||
public static IEnumerable<Mobile> FindMobiles(this IAccount acc, Func<Mobile, bool> predicate)
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var i = 0; i < acc.Length; i++)
|
||||
{
|
||||
if (acc[i] != null && (predicate == null || predicate(acc[i])))
|
||||
{
|
||||
yield return acc[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TMob[] GetMobiles<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return GetMobiles<TMob>(acc, null);
|
||||
}
|
||||
|
||||
public static TMob[] GetMobiles<TMob>(this IAccount acc, Func<TMob, bool> predicate)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles(acc, predicate).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<TMob> FindMobiles<TMob>(this IAccount acc)
|
||||
where TMob : Mobile
|
||||
{
|
||||
return FindMobiles<TMob>(acc, null);
|
||||
}
|
||||
|
||||
public static IEnumerable<TMob> FindMobiles<TMob>(this IAccount acc, Func<TMob, bool> predicate)
|
||||
where TMob : Mobile
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var i = 0; i < acc.Length; i++)
|
||||
{
|
||||
if (acc[i] is TMob && (predicate == null || predicate((TMob)acc[i])))
|
||||
{
|
||||
yield return (TMob)acc[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Account[] GetSharedAccounts(this IAccount acc)
|
||||
{
|
||||
return GetSharedAccounts(acc as Account);
|
||||
}
|
||||
|
||||
public static Account[] GetSharedAccounts(this Account acc)
|
||||
{
|
||||
return FindSharedAccounts(acc).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Account> FindSharedAccounts(this IAccount acc)
|
||||
{
|
||||
return FindSharedAccounts(acc as Account);
|
||||
}
|
||||
|
||||
public static IEnumerable<Account> FindSharedAccounts(this Account acc)
|
||||
{
|
||||
if (acc == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var a in Accounts.GetAccounts().AsParallel().OfType<Account>().Where(a => IsSharedWith(acc, a)))
|
||||
{
|
||||
yield return a;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSharedWith(this IAccount acc, IAccount a)
|
||||
{
|
||||
return IsSharedWith(acc as Account, a as Account);
|
||||
}
|
||||
|
||||
public static bool IsSharedWith(this Account acc, Account a)
|
||||
{
|
||||
return acc != null && a != null && (acc == a || acc.LoginIPs.Any(a.LoginIPs.Contains));
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this Mobile a, Mobile b)
|
||||
{
|
||||
return a != null && b != null && (a == b || a.Account == b.Account);
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this Mobile a, IAccount b)
|
||||
{
|
||||
return a != null && b != null && a.Account == b;
|
||||
}
|
||||
|
||||
public static bool CheckAccount(this IAccount a, Mobile b)
|
||||
{
|
||||
return a != null && b != null && a == b.Account;
|
||||
}
|
||||
}
|
||||
}
|
||||
116
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AddonExt.cs
Normal file
116
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AddonExt.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class AddonExtUtility
|
||||
{
|
||||
static AddonExtUtility()
|
||||
{
|
||||
ComponentsCache = new Dictionary<int, MultiComponentList>();
|
||||
}
|
||||
|
||||
public static Dictionary<int, MultiComponentList> ComponentsCache { get; private set; }
|
||||
|
||||
public static int ComputeHash(IAddon addon)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = -1;
|
||||
|
||||
hash = (hash * 397) ^ addon.GetTypeHashCode();
|
||||
|
||||
|
||||
if (addon.GetPropertyValue("Components", out
|
||||
IList comp))
|
||||
{
|
||||
hash = (hash * 397) ^ comp.Count;
|
||||
|
||||
hash = comp.Cast<Item>().Aggregate(hash, (h, c) => (h * 397) ^ c.GetTypeHashCode());
|
||||
hash = comp.Cast<Item>().Aggregate(hash, (h, c) => (h * 397) ^ c.ItemID);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(this IAddon addon)
|
||||
{
|
||||
if (addon == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var hash = ComputeHash(addon);
|
||||
|
||||
var mcl = ComponentsCache.GetValue(hash);
|
||||
|
||||
if (mcl != null)
|
||||
{
|
||||
return mcl;
|
||||
}
|
||||
|
||||
mcl = new MultiComponentList(MultiComponentList.Empty);
|
||||
|
||||
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
|
||||
|
||||
if (addon.GetPropertyValue("Components", out
|
||||
IList comp))
|
||||
{
|
||||
|
||||
foreach (var c in comp)
|
||||
{
|
||||
if (c.GetPropertyValue("Offset", out Point3D off))
|
||||
{
|
||||
x1 = Math.Min(off.X, x1);
|
||||
y1 = Math.Min(off.Y, y1);
|
||||
|
||||
x2 = Math.Max(off.X, x2);
|
||||
y2 = Math.Max(off.Y, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mcl.Resize(1 + (x2 - x1), 1 + (y2 - y1));
|
||||
|
||||
if (comp != null)
|
||||
{
|
||||
|
||||
foreach (var c in comp.OfType<Item>())
|
||||
{
|
||||
if (c.GetPropertyValue("Offset", out Point3D off))
|
||||
{
|
||||
off = off.Clone3D(Math.Abs(x1), Math.Abs(y1));
|
||||
|
||||
mcl.Add(c.ItemID, off.X, off.Y, off.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addon is Item)
|
||||
{
|
||||
((Item)addon).Delete();
|
||||
}
|
||||
|
||||
return ComponentsCache[hash] = mcl;
|
||||
}
|
||||
}
|
||||
}
|
||||
2083
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AttributesExt.cs
Normal file
2083
Scripts/SubSystem/VitaNex/Core/Extensions/Server/AttributesExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
193
Scripts/SubSystem/VitaNex/Core/Extensions/Server/BodyExt.cs
Normal file
193
Scripts/SubSystem/VitaNex/Core/Extensions/Server/BodyExt.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class BodyExtUtility
|
||||
{
|
||||
public static Dictionary<int, string> Names { get; private set; }
|
||||
|
||||
static BodyExtUtility()
|
||||
{
|
||||
Names = new Dictionary<int, string>();
|
||||
}
|
||||
|
||||
public static string GetName(this Body body)
|
||||
{
|
||||
if (body.IsEmpty)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
|
||||
if (Names.TryGetValue(body.BodyID, out var name) && !String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
var itemID = ShrinkTable.Lookup(body.BodyID) & TileData.MaxItemValue;
|
||||
|
||||
if (itemID == ShrinkTable.DefaultItemID)
|
||||
{
|
||||
name = String.Empty;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = ClilocLNG.NULL.GetRawString(itemID + (itemID < 0x4000 ? 1020000 : 1078872));
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = TileData.ItemTable[itemID].Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = body.Type.ToString();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = name.SpaceWords().ToUpperWords();
|
||||
|
||||
name = String.Concat(" ", name, " ");
|
||||
|
||||
if (body.IsHuman || body.IsGhost)
|
||||
{
|
||||
if (body >= 400 && body <= 403)
|
||||
{
|
||||
name = "Human";
|
||||
}
|
||||
else if (body >= 605 && body <= 608)
|
||||
{
|
||||
name = "Elf";
|
||||
}
|
||||
else if ((body >= 666 && body <= 667) || (body >= 694 && body <= 695))
|
||||
{
|
||||
name = "Gargoyle";
|
||||
}
|
||||
|
||||
if (body.IsMale && !Insensitive.Contains(name, "Male"))
|
||||
{
|
||||
name += " Male";
|
||||
}
|
||||
else if (body.IsFemale && !Insensitive.Contains(name, "Female"))
|
||||
{
|
||||
name += " Female";
|
||||
}
|
||||
|
||||
if (body.IsGhost && !Insensitive.Contains(name, "Ghost"))
|
||||
{
|
||||
name += " Ghost";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (itemID)
|
||||
{
|
||||
case 9611:
|
||||
name = "Evil Mage";
|
||||
break;
|
||||
case 9776:
|
||||
name = "Wanderer Of The Void";
|
||||
break;
|
||||
case 11676:
|
||||
name = "Charger";
|
||||
break;
|
||||
case 38990:
|
||||
name = "Baby Dragon Turtle";
|
||||
break;
|
||||
case 40369:
|
||||
name = "Aztec Golem";
|
||||
break;
|
||||
case 40374:
|
||||
name = "Myrmadex Queen";
|
||||
break;
|
||||
case 40420:
|
||||
name = "Spector";
|
||||
break;
|
||||
case 40429:
|
||||
name = "T-Rex";
|
||||
break;
|
||||
case 40501:
|
||||
name = "Rainbow Unicorn";
|
||||
break;
|
||||
case 40661:
|
||||
name = "Windrunner";
|
||||
break;
|
||||
case 40704:
|
||||
name = "Sabertooth Tiger";
|
||||
break;
|
||||
case 40705:
|
||||
name = "Small Platinum Dragon";
|
||||
break;
|
||||
case 40706:
|
||||
name = "Platinum Dragon";
|
||||
break;
|
||||
case 40710:
|
||||
name = "Small Crimson Dragon";
|
||||
break;
|
||||
case 40711:
|
||||
name = "Crimson Dragon";
|
||||
break;
|
||||
case 40713:
|
||||
name = "Small Fox";
|
||||
break;
|
||||
case 40714:
|
||||
name = "Small Stygian Dragon";
|
||||
break;
|
||||
case 40718:
|
||||
name = "Stygian Dragon";
|
||||
break;
|
||||
case 40976:
|
||||
name = "Eastern Dragon";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
name = name.Replace(" Fr ", " Frame ");
|
||||
|
||||
name = name.Replace("Frame", String.Empty);
|
||||
name = name.Replace("Statuette", String.Empty);
|
||||
name = name.Replace("Statue", String.Empty);
|
||||
|
||||
name = name.StripExcessWhiteSpace().Trim();
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
name = body.Type.ToString();
|
||||
}
|
||||
|
||||
Names[body.BodyID] = name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public static int GetPaperdoll(this Body body)
|
||||
{
|
||||
return ArtworkSupport.LookupGump(body);
|
||||
}
|
||||
|
||||
public static bool HasPaperdoll(this Body body)
|
||||
{
|
||||
return GetPaperdoll(body) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ContainerExt.cs
Normal file
155
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ContainerExt.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class ContainerExtUtility
|
||||
{
|
||||
public static bool HasItem<TItem>(
|
||||
this Container container,
|
||||
int amount = 1,
|
||||
bool children = true,
|
||||
Func<TItem, bool> predicate = null)
|
||||
where TItem : Item
|
||||
{
|
||||
return predicate == null
|
||||
? HasItem(container, typeof(TItem), amount, children)
|
||||
: HasItem(container, typeof(TItem), amount, children, i => predicate(i as TItem));
|
||||
}
|
||||
|
||||
public static bool HasItem(
|
||||
this Container container,
|
||||
Type type,
|
||||
int amount = 1,
|
||||
bool children = true,
|
||||
Func<Item, bool> predicate = null)
|
||||
{
|
||||
if (container == null || type == null || amount < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long total = 0;
|
||||
|
||||
total = container.FindItemsByType(type, true)
|
||||
.Where(i => i != null && !i.Deleted && i.TypeEquals(type, children) && (predicate == null || predicate(i)))
|
||||
.Aggregate(total, (c, i) => c + i.Amount);
|
||||
|
||||
return total >= amount;
|
||||
}
|
||||
|
||||
public static bool HasItems(
|
||||
this Container container,
|
||||
Type[] types,
|
||||
int[] amounts = null,
|
||||
bool children = true,
|
||||
Func<Item, bool> predicate = null)
|
||||
{
|
||||
if (container == null || types == null || types.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (amounts == null)
|
||||
{
|
||||
amounts = new int[0];
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < types.Length; i++)
|
||||
{
|
||||
var t = types[i];
|
||||
var amount = amounts.InBounds(i) ? amounts[i] : 1;
|
||||
|
||||
if (HasItem(container, t, amount, children, predicate))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count >= types.Length;
|
||||
}
|
||||
|
||||
public static bool DropItemStack(this Container c, Item item)
|
||||
{
|
||||
if (c == null || c.Deleted || item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return DropItemStack(c, c.RootParent as Mobile, item);
|
||||
}
|
||||
|
||||
public static bool DropItemStack(this Container c, Mobile m, Item item)
|
||||
{
|
||||
if (c == null || c.Deleted || item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
c.DropItem(item);
|
||||
|
||||
if (item.Stackable)
|
||||
{
|
||||
MergeStacks(c, item.GetType(), m);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void MergeStacks<T>(this Container c, Mobile m)
|
||||
where T : Item
|
||||
{
|
||||
MergeStacks(c, typeof(T), m);
|
||||
}
|
||||
|
||||
public static void MergeStacks(this Container c, Mobile m)
|
||||
{
|
||||
MergeStacks(c, null, m);
|
||||
}
|
||||
|
||||
public static void MergeStacks(this Container c, Type t, Mobile m)
|
||||
{
|
||||
if (c == null || c.Deleted || (t != null && t.TypeEquals<Container>(true)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var i = c.Items.Count;
|
||||
|
||||
while (--i >= 1)
|
||||
{
|
||||
var o = c.Items[i];
|
||||
|
||||
if (!o.Stackable || (t != null && !o.TypeEquals(t, false)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var s in c.Items.Take(i).NotType<Item, Container>().Where(s => t == null || s.TypeEquals(t, false)))
|
||||
{
|
||||
if (s.StackWith(m, o))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class CreatureExtUtility
|
||||
{
|
||||
public static TMobile GetMaster<TMobile>(this BaseCreature creature)
|
||||
where TMobile : Mobile
|
||||
{
|
||||
return creature != null ? creature.GetMaster() as TMobile : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
268
Scripts/SubSystem/VitaNex/Core/Extensions/Server/EntityExt.cs
Normal file
268
Scripts/SubSystem/VitaNex/Core/Extensions/Server/EntityExt.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Network;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class EntityExtUtility
|
||||
{
|
||||
public static ObjectPropertyList GetOPL(this IEntity e)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, Mobile viewer)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, viewer);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, bool headerOnly)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, headerOnly);
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPL(this IEntity e, Mobile viewer, bool headerOnly)
|
||||
{
|
||||
return ExtendedOPL.ResolveOPL(e, viewer, headerOnly);
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader();
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader(lng);
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLHeader(this IEntity e, Mobile viewer)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, viewer, true);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyListHeader(viewer);
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList();
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList(lng);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetOPLStrings(this IEntity e, Mobile viewer)
|
||||
{
|
||||
ObjectPropertyList opl = null;
|
||||
|
||||
try
|
||||
{
|
||||
opl = GetOPL(e, viewer);
|
||||
|
||||
if (opl != null)
|
||||
{
|
||||
return opl.DecodePropertyList(viewer);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (opl != null)
|
||||
{
|
||||
opl.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e));
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e, ClilocLNG lng)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e, lng));
|
||||
}
|
||||
|
||||
public static string GetOPLString(this IEntity e, Mobile viewer)
|
||||
{
|
||||
return String.Join("\n", GetOPLStrings(e, viewer));
|
||||
}
|
||||
|
||||
public static string ResolveName(this IEntity e, Mobile viewer = null)
|
||||
{
|
||||
if (e is Item)
|
||||
{
|
||||
return ((Item)e).ResolveName(viewer);
|
||||
}
|
||||
|
||||
if (e is Mobile)
|
||||
{
|
||||
return ((Mobile)e).GetFullName(viewer);
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(e.Name))
|
||||
{
|
||||
return e.GetTypeName(false);
|
||||
}
|
||||
|
||||
return e.Name;
|
||||
}
|
||||
|
||||
public static bool IsInside(this IEntity e)
|
||||
{
|
||||
if (e != null && e.Map != null && e.Map != Map.Internal)
|
||||
{
|
||||
return e.IsInside(e.Map);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IEntity e)
|
||||
{
|
||||
return !IsInside(e);
|
||||
}
|
||||
|
||||
public static bool Intersects(this IEntity e, IPoint3D o)
|
||||
{
|
||||
return Block3D.Intersects(e, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
765
Scripts/SubSystem/VitaNex/Core/Extensions/Server/GeoExt.cs
Normal file
765
Scripts/SubSystem/VitaNex/Core/Extensions/Server/GeoExt.cs
Normal file
@@ -0,0 +1,765 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class GeoExtUtility
|
||||
{
|
||||
public static Point3D ToPoint3D(this IPoint3D p)
|
||||
{
|
||||
return new Point3D(p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public static Point3D ToPoint3D(this IPoint2D p, int z = 0)
|
||||
{
|
||||
return new Point3D(p.X, p.Y, z);
|
||||
}
|
||||
|
||||
public static Point2D ToPoint2D(this IPoint3D p)
|
||||
{
|
||||
return new Point2D(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static Point2D ToPoint2D(this StaticTile t)
|
||||
{
|
||||
return new Point2D(t.X, t.Y);
|
||||
}
|
||||
|
||||
public static Point3D ToPoint3D(this StaticTile t)
|
||||
{
|
||||
return new Point3D(t.X, t.Y, t.Z);
|
||||
}
|
||||
|
||||
public static string ToCoordsString(this IPoint2D p, Map map)
|
||||
{
|
||||
return ToCoords(p, map).ToString();
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this IPoint2D p, Map m)
|
||||
{
|
||||
return new Coords(m, p);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this IEntity e)
|
||||
{
|
||||
return e == null ? Coords.Zero : new Coords(e.Map, e.Location);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this PlayerMobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return Coords.Zero;
|
||||
}
|
||||
|
||||
var online = m.IsOnline();
|
||||
return new Coords(online ? m.Map : m.LogoutMap, online ? m.Location : m.LogoutLocation);
|
||||
}
|
||||
|
||||
public static Coords ToCoords(this StaticTile t, Map m)
|
||||
{
|
||||
return new Coords(m, ToPoint3D(t));
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IPoint2D p, Map m, int z = 0)
|
||||
{
|
||||
return new MapPoint(m, p, z);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IPoint3D p, Map m)
|
||||
{
|
||||
return new MapPoint(m, p);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this IEntity e)
|
||||
{
|
||||
return e == null ? MapPoint.Empty : new MapPoint(e.Map, e.Location);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this PlayerMobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
return MapPoint.Empty;
|
||||
}
|
||||
|
||||
var online = m.IsOnline();
|
||||
|
||||
return new MapPoint(online ? m.Map : m.LogoutMap, online ? m.Location : m.LogoutLocation);
|
||||
}
|
||||
|
||||
public static MapPoint ToMapPoint(this StaticTile t, Map m)
|
||||
{
|
||||
return new MapPoint(m, ToPoint3D(t));
|
||||
}
|
||||
|
||||
public static IEnumerable<Block3D> Flatten(this IEnumerable<Block3D> blocks)
|
||||
{
|
||||
foreach (var o in blocks.GroupBy(o => o.ToPoint2D()))
|
||||
{
|
||||
var v = new Block3D(o.Key.X, o.Key.Y, o.Min(b => b.Z), 0);
|
||||
|
||||
v.H = o.Max(b => b.Z + b.H) - v.Z;
|
||||
|
||||
yield return v;
|
||||
}
|
||||
}
|
||||
|
||||
public static Direction GetDirection(this IPoint2D from, IPoint2D to)
|
||||
{
|
||||
int dx = to.X - from.X, dy = to.Y - from.Y, adx = Math.Abs(dx), ady = Math.Abs(dy);
|
||||
|
||||
if (adx >= ady * 3)
|
||||
{
|
||||
if (dx > 0)
|
||||
{
|
||||
return Direction.East;
|
||||
}
|
||||
|
||||
return Direction.West;
|
||||
}
|
||||
|
||||
if (ady >= adx * 3)
|
||||
{
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.South;
|
||||
}
|
||||
|
||||
return Direction.North;
|
||||
}
|
||||
|
||||
if (dx > 0)
|
||||
{
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.Down;
|
||||
}
|
||||
|
||||
return Direction.Right;
|
||||
}
|
||||
|
||||
if (dy > 0)
|
||||
{
|
||||
return Direction.Left;
|
||||
}
|
||||
|
||||
return Direction.Up;
|
||||
}
|
||||
|
||||
public static Direction4 GetDirection4(this Direction dir, bool clockwise = true)
|
||||
{
|
||||
dir = dir & Direction.Mask;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case Direction.Up:
|
||||
return clockwise ? Direction4.North : Direction4.West;
|
||||
case Direction.Right:
|
||||
return clockwise ? Direction4.East : Direction4.North;
|
||||
case Direction.Down:
|
||||
return clockwise ? Direction4.South : Direction4.East;
|
||||
case Direction.Left:
|
||||
return clockwise ? Direction4.West : Direction4.South;
|
||||
}
|
||||
|
||||
return (Direction4)dir;
|
||||
}
|
||||
|
||||
public static Point2D[] GetLine2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return PlotLine2D(start, end).ToArray();
|
||||
}
|
||||
|
||||
public static Point3D[] GetLine3D(this IPoint3D start, IPoint3D end, bool avgZ = true)
|
||||
{
|
||||
Map map = null;
|
||||
|
||||
if (avgZ && start is IEntity)
|
||||
{
|
||||
map = ((IEntity)start).Map;
|
||||
}
|
||||
|
||||
return GetLine3D(start, end, map, avgZ);
|
||||
}
|
||||
|
||||
public static Point3D[] GetLine3D(this IPoint3D start, IPoint3D end, Map map, bool avgZ = true)
|
||||
{
|
||||
return PlotLine3D(start, end, map, avgZ).ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> PlotLine2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return Line2D.Plot(start, end);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> PlotLine3D(this IPoint3D start, IPoint3D end, bool avgZ = true)
|
||||
{
|
||||
Map map = null;
|
||||
|
||||
if (avgZ && start is IEntity)
|
||||
{
|
||||
map = ((IEntity)start).Map;
|
||||
}
|
||||
|
||||
return PlotLine3D(start, end, map, avgZ);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> PlotLine3D(this IPoint3D start, IPoint3D end, Map map, bool avgZ = true)
|
||||
{
|
||||
var dist = GetDistance(start, end);
|
||||
var dZ = end.Z - start.Z;
|
||||
|
||||
return Line2D.Plot(start, end)
|
||||
.Select(
|
||||
(p, i) =>
|
||||
{
|
||||
var z = start.Z;
|
||||
|
||||
if (avgZ && map != null)
|
||||
{
|
||||
z = map.GetAverageZ(p.X, p.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
z += (int)(dZ * (i / dist));
|
||||
}
|
||||
|
||||
return new Point3D(p, z);
|
||||
});
|
||||
}
|
||||
|
||||
public static Point2D Rotate2D(this IPoint2D from, IPoint2D to, int count)
|
||||
{
|
||||
var rx = from.X - to.X;
|
||||
var ry = from.Y - to.Y;
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var temp = rx;
|
||||
rx = -ry;
|
||||
ry = temp;
|
||||
}
|
||||
|
||||
return new Point2D(to.X + rx, to.Y + ry);
|
||||
}
|
||||
|
||||
public static Point3D Rotate3D(this IPoint3D from, IPoint3D to, int count)
|
||||
{
|
||||
return new Point3D(Rotate2D(from, to, count), from.Z);
|
||||
}
|
||||
|
||||
public static Point2D Clone2D(this IPoint2D p, IPoint2D t)
|
||||
{
|
||||
return new Point2D(p.X + t.X, p.Y + t.Y);
|
||||
}
|
||||
|
||||
public static Point2D Clone2D(this IPoint2D p, int xOffset = 0, int yOffset = 0)
|
||||
{
|
||||
return new Point2D(p.X + xOffset, p.Y + yOffset);
|
||||
}
|
||||
|
||||
public static Point3D Clone3D(this IPoint3D p, IPoint3D t)
|
||||
{
|
||||
return new Point3D(p.X + t.X, p.Y + t.Y, p.Z + t.Z);
|
||||
}
|
||||
|
||||
public static Point3D Clone3D(this IPoint3D p, int xOffset = 0, int yOffset = 0, int zOffset = 0)
|
||||
{
|
||||
return new Point3D(p.X + xOffset, p.Y + yOffset, p.Z + zOffset);
|
||||
}
|
||||
|
||||
public static Point2D Lerp2D(this IPoint2D start, IPoint2D end, double percent)
|
||||
{
|
||||
return Lerp2D(start, end.X, end.Y, percent);
|
||||
}
|
||||
|
||||
public static Point2D Lerp2D(this IPoint2D start, int x, int y, double percent)
|
||||
{
|
||||
return Clone2D(start, (int)((x - start.X) * percent), (int)((y - start.Y) * percent));
|
||||
}
|
||||
|
||||
public static Point3D Lerp3D(this IPoint3D start, IPoint3D end, double percent)
|
||||
{
|
||||
return Lerp3D(start, end.X, end.Y, end.Z, percent);
|
||||
}
|
||||
|
||||
public static Point3D Lerp3D(this IPoint3D start, int x, int y, int z, double percent)
|
||||
{
|
||||
return Clone3D(
|
||||
start,
|
||||
(int)((x - start.X) * percent),
|
||||
(int)((y - start.Y) * percent),
|
||||
(int)((z - start.Z) * percent));
|
||||
}
|
||||
|
||||
public static Point2D Delta2D(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return new Point2D(start.X - end.X, start.Y - end.Y);
|
||||
}
|
||||
|
||||
public static Point2D Delta2D(this IPoint2D start, int endX, int endY)
|
||||
{
|
||||
return new Point2D(start.X - endX, start.Y - endY);
|
||||
}
|
||||
|
||||
public static Point3D Delta3D(this IPoint3D start, IPoint3D end)
|
||||
{
|
||||
return new Point3D(start.X - end.X, start.Y - end.Y, start.Z - end.Z);
|
||||
}
|
||||
|
||||
public static Point3D Delta3D(this IPoint3D start, int endX, int endY, int endZ)
|
||||
{
|
||||
return new Point3D(start.X - endX, start.Y - endY, start.Z - endZ);
|
||||
}
|
||||
|
||||
public static double GetDistance(this IPoint2D start, IPoint2D end)
|
||||
{
|
||||
return Math.Abs(Math.Sqrt(Math.Pow(end.X - start.X, 2) + Math.Pow(end.Y - start.Y, 2)));
|
||||
}
|
||||
|
||||
public static double GetDistance(this IPoint3D start, IPoint3D end)
|
||||
{
|
||||
return Math.Abs(
|
||||
Math.Sqrt(Math.Pow(end.X - start.X, 2) + Math.Pow(end.Y - start.Y, 2) + (Math.Pow(end.Z - start.Z, 2) / 44.0)));
|
||||
}
|
||||
|
||||
public static TimeSpan GetTravelTime(this IPoint2D start, IPoint2D end, double speed)
|
||||
{
|
||||
var span = GetDistance(start, end) / (speed * 1.25);
|
||||
|
||||
span = Math.Max(0, Math.Min(TimeSpan.MaxValue.TotalSeconds, span));
|
||||
|
||||
return TimeSpan.FromSeconds(span);
|
||||
}
|
||||
|
||||
public static TimeSpan GetTravelTime(this IPoint3D start, IPoint3D end, double speed)
|
||||
{
|
||||
var span = GetDistance(start, end) / (speed * 1.25);
|
||||
|
||||
var z1 = (double)start.Z;
|
||||
var z2 = (double)end.Z;
|
||||
|
||||
var zDiff = Math.Abs(z2 - z1);
|
||||
|
||||
if (zDiff >= 5)
|
||||
{
|
||||
span -= (zDiff / 5.0) * 0.1;
|
||||
}
|
||||
|
||||
span = Math.Max(0, Math.Min(TimeSpan.MaxValue.TotalSeconds, span));
|
||||
|
||||
return TimeSpan.FromSeconds(span);
|
||||
}
|
||||
|
||||
public static object GetTopSurface(this Map map, Point3D p, bool multis)
|
||||
{
|
||||
if (map == Map.Internal)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
object surface = null;
|
||||
var surfaceZ = Int32.MinValue;
|
||||
|
||||
var lt = map.Tiles.GetLandTile(p.X, p.Y);
|
||||
|
||||
if (!lt.Ignored)
|
||||
{
|
||||
var avgZ = map.GetAverageZ(p.X, p.Y);
|
||||
|
||||
if (avgZ <= p.Z)
|
||||
{
|
||||
surface = lt;
|
||||
surfaceZ = avgZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var staticTiles = map.Tiles.GetStaticTiles(p.X, p.Y, multis);
|
||||
|
||||
ItemData id;
|
||||
int tileZ;
|
||||
|
||||
foreach (var tile in staticTiles)
|
||||
{
|
||||
id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
|
||||
if (!id.Surface && (id.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tileZ = tile.Z + id.CalcHeight;
|
||||
|
||||
if (tileZ <= surfaceZ || tileZ > p.Z)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
surface = tile;
|
||||
surfaceZ = tileZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
|
||||
var sector = map.GetSector(p.X, p.Y);
|
||||
|
||||
int itemZ;
|
||||
|
||||
var items = sector.Items.Where(
|
||||
o => o.ItemID <= TileData.MaxItemValue && !o.Movable && !(o is BaseMulti) && o.AtWorldPoint(p.X, p.Y));
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
id = item.ItemData;
|
||||
|
||||
if (!id.Surface && (id.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
itemZ = item.Z + id.CalcHeight;
|
||||
|
||||
if (itemZ <= surfaceZ || itemZ > p.Z)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
surface = item;
|
||||
surfaceZ = itemZ;
|
||||
|
||||
if (surfaceZ == p.Z)
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
public static Point3D GetSurfaceTop(this IPoint2D p, Map map, bool items = true, bool multis = true)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
return GetSurfaceTop(ToPoint3D(p, Region.MaxZ), map, items, multis);
|
||||
}
|
||||
|
||||
public static Point3D GetSurfaceTop(this IPoint3D p, Map map, bool items = true, bool multis = true)
|
||||
{
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
var o = GetTopSurface(map, ToPoint3D(p, Region.MaxZ), multis);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
if (o is LandTile)
|
||||
{
|
||||
var t = (LandTile)o;
|
||||
return ToPoint3D(p, t.Z + t.Height);
|
||||
}
|
||||
|
||||
if (o is StaticTile)
|
||||
{
|
||||
var t = (StaticTile)o;
|
||||
return ToPoint3D(p, t.Z + TileData.ItemTable[t.ID].CalcHeight);
|
||||
}
|
||||
|
||||
if (o is Item && items)
|
||||
{
|
||||
var t = (Item)o;
|
||||
return ToPoint3D(p, t.Z + t.ItemData.CalcHeight);
|
||||
}
|
||||
}
|
||||
|
||||
return ToPoint3D(p);
|
||||
}
|
||||
|
||||
public static Point3D GetWorldTop(this IPoint2D p, Map map)
|
||||
{
|
||||
return GetSurfaceTop(p, map, false);
|
||||
}
|
||||
|
||||
public static Point3D GetWorldTop(this IPoint3D p, Map map)
|
||||
{
|
||||
return GetSurfaceTop(p, map, false);
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Rectangle2D b, Map map)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Rectangle3D b, Map map)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this IPoint2D p, Map map, int range)
|
||||
{
|
||||
return GetTopZ(new Rectangle2D(p.X - range, p.Y - range, (range * 2) + 1, (range * 2) + 1), map);
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, Rectangle2D b)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, Rectangle3D b)
|
||||
{
|
||||
return GetTopZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, params Point2D[] points)
|
||||
{
|
||||
return GetTopZ(map, points.Ensure());
|
||||
}
|
||||
|
||||
public static int GetTopZ(this Map map, IEnumerable<Point2D> points)
|
||||
{
|
||||
try
|
||||
{
|
||||
return points.Max(p => GetTopZ(p, map));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetTopZ(this IPoint2D p, Map map)
|
||||
{
|
||||
|
||||
GetAverageZ(p, map, out var c, out var a, out var t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this IPoint2D p, Map map, int range)
|
||||
{
|
||||
return GetAverageZ(new Rectangle2D(p.X - range, p.Y - range, (range * 2) + 1, (range * 2) + 1), map);
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Rectangle2D b, Map map)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Rectangle3D b, Map map)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, Rectangle2D b)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, Rectangle3D b)
|
||||
{
|
||||
return GetAverageZ(map, b.EnumeratePoints2D());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, params Point2D[] points)
|
||||
{
|
||||
return GetAverageZ(map, points.Ensure());
|
||||
}
|
||||
|
||||
public static int GetAverageZ(this Map map, IEnumerable<Point2D> points)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (int)points.Average(p => GetAverageZ(p, map));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (( ,A,_,A,
|
||||
/// )) ,{=^;^=}
|
||||
/// (( {,,}#{,,}
|
||||
/// `{,,}{,,}
|
||||
/// </summary>
|
||||
public static int GetAverageZ(this IPoint2D p, Map map)
|
||||
{
|
||||
|
||||
GetAverageZ(p, map, out var c, out var a, out var t);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public static void GetAverageZ(this IPoint2D p, Map map, out int cur, out int avg, out int top)
|
||||
{
|
||||
var land = new
|
||||
{
|
||||
T = map.Tiles.GetLandTile(p.X, p.Y),
|
||||
L = map.Tiles.GetLandTile(p.X, p.Y + 1),
|
||||
R = map.Tiles.GetLandTile(p.X + 1, p.Y),
|
||||
B = map.Tiles.GetLandTile(p.X + 1, p.Y + 1)
|
||||
};
|
||||
|
||||
var surf = new
|
||||
{
|
||||
T = GetSurfaceTop(p, map, false, false),
|
||||
L = GetSurfaceTop(Clone2D(p, 0, 1), map, false, false),
|
||||
R = GetSurfaceTop(Clone2D(p, 1), map, false, false),
|
||||
B = GetSurfaceTop(Clone2D(p, 1, 1), map, false, false)
|
||||
};
|
||||
|
||||
var zT = (land.T.Ignored || surf.T.Z > Region.MinZ) ? surf.T.Z : land.T.Z;
|
||||
var zL = (land.L.Ignored || surf.L.Z > Region.MinZ) ? surf.L.Z : land.L.Z;
|
||||
var zR = (land.R.Ignored || surf.R.Z > Region.MinZ) ? surf.R.Z : land.R.Z;
|
||||
var zB = (land.B.Ignored || surf.B.Z > Region.MinZ) ? surf.B.Z : land.B.Z;
|
||||
|
||||
cur = zT;
|
||||
|
||||
if (zL > Region.MinZ && zL < cur)
|
||||
{
|
||||
cur = zL;
|
||||
}
|
||||
|
||||
if (zR > Region.MinZ && zR < cur)
|
||||
{
|
||||
cur = zR;
|
||||
}
|
||||
|
||||
if (zB > Region.MinZ && zB < cur)
|
||||
{
|
||||
cur = zB;
|
||||
}
|
||||
|
||||
top = zT;
|
||||
|
||||
if (zL > Region.MinZ && zL > top)
|
||||
{
|
||||
top = zL;
|
||||
}
|
||||
|
||||
if (zR > Region.MinZ && zR > top)
|
||||
{
|
||||
top = zR;
|
||||
}
|
||||
|
||||
if (zB > Region.MinZ && zB > top)
|
||||
{
|
||||
top = zB;
|
||||
}
|
||||
|
||||
if (cur <= Region.MinZ)
|
||||
{
|
||||
cur = 0;
|
||||
}
|
||||
|
||||
if (top <= Region.MinZ)
|
||||
{
|
||||
top = 0;
|
||||
}
|
||||
|
||||
if (zT <= Region.MinZ)
|
||||
{
|
||||
zT = 0;
|
||||
}
|
||||
|
||||
if (zL <= Region.MinZ)
|
||||
{
|
||||
zL = 0;
|
||||
}
|
||||
|
||||
if (zR <= Region.MinZ)
|
||||
{
|
||||
zR = 0;
|
||||
}
|
||||
|
||||
if (zB <= Region.MinZ)
|
||||
{
|
||||
zB = 0;
|
||||
}
|
||||
|
||||
var vL = zL + zR;
|
||||
|
||||
if (vL < 0)
|
||||
{
|
||||
--vL;
|
||||
}
|
||||
|
||||
var vR = zT + zB;
|
||||
|
||||
if (vR < 0)
|
||||
{
|
||||
--vR;
|
||||
}
|
||||
|
||||
avg = Math.Abs(zT - zB) > Math.Abs(zL - zR) ? vL / 2 : vR / 2;
|
||||
}
|
||||
|
||||
public static bool IsInside(this IPoint3D p, Map map)
|
||||
{
|
||||
if (p != null && map != null && map != Map.Internal)
|
||||
{
|
||||
return IsInside(p, p.Z, map);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IPoint3D p, Map map)
|
||||
{
|
||||
return !IsInside(p, map);
|
||||
}
|
||||
|
||||
public static bool IsInside(this IPoint2D p, int z, Map map)
|
||||
{
|
||||
if (p == null || map == null || map == Map.Internal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p is Item)
|
||||
{
|
||||
z += Math.Max(0, ((Item)p).ItemData.Height) + 1;
|
||||
}
|
||||
|
||||
z = Math.Max(Region.MinZ, Math.Min(Region.MaxZ, z));
|
||||
|
||||
return !map.CanFit(p.X, p.Y, z, Region.MaxZ - z, true, false, false);
|
||||
}
|
||||
|
||||
public static bool IsOutside(this IPoint2D p, int z, Map map)
|
||||
{
|
||||
return !IsInside(p, z, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using VitaNex.SuperGumps;
|
||||
#endregion
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public static class GumpExtUtility
|
||||
{
|
||||
public static bool TryGetX(this GumpEntry e, out int x)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
x = ((IGumpEntryPoint)e).X;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x);
|
||||
}
|
||||
|
||||
public static bool TrySetX(this GumpEntry e, int x)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).X = x;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x);
|
||||
}
|
||||
|
||||
public static bool TryOffsetX(this GumpEntry e, int x)
|
||||
{
|
||||
|
||||
if (TryGetX(e, out var ox))
|
||||
{
|
||||
return TrySetX(e, ox + x);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetY(this GumpEntry e, out int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
y = ((IGumpEntryPoint)e).Y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Y", out y);
|
||||
}
|
||||
|
||||
public static bool TrySetY(this GumpEntry e, int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).Y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Y", y);
|
||||
}
|
||||
|
||||
public static bool TryOffsetY(this GumpEntry e, int y)
|
||||
{
|
||||
|
||||
if (TryGetY(e, out var oy))
|
||||
{
|
||||
return TrySetY(e, oy + y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetWidth(this GumpEntry e, out int width)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
width = ((IGumpEntrySize)e).Width;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Width", out width);
|
||||
}
|
||||
|
||||
public static bool TrySetWidth(this GumpEntry e, int width)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Width = width;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Width", width);
|
||||
}
|
||||
|
||||
public static bool TryOffsetWidth(this GumpEntry e, int width)
|
||||
{
|
||||
|
||||
if (TryGetWidth(e, out var ow))
|
||||
{
|
||||
return TrySetWidth(e, ow + width);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetHeight(this GumpEntry e, out int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
height = ((IGumpEntrySize)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetHeight(this GumpEntry e, int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetHeight(this GumpEntry e, int height)
|
||||
{
|
||||
|
||||
if (TryGetHeight(e, out var oh))
|
||||
{
|
||||
return TrySetHeight(e, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetPosition(this GumpEntry e, out int x, out int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
x = ((IGumpEntryPoint)e).X;
|
||||
y = ((IGumpEntryPoint)e).Y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x) & e.GetPropertyValue("Y", out y);
|
||||
}
|
||||
|
||||
public static bool TrySetPosition(this GumpEntry e, int x, int y)
|
||||
{
|
||||
if (e is IGumpEntryPoint)
|
||||
{
|
||||
((IGumpEntryPoint)e).X = x;
|
||||
((IGumpEntryPoint)e).Y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x) & e.SetPropertyValue("Y", y);
|
||||
}
|
||||
|
||||
public static bool TryOffsetPosition(this GumpEntry e, int x, int y)
|
||||
{
|
||||
|
||||
if (TryGetPosition(e, out var ox, out var oy))
|
||||
{
|
||||
return TrySetPosition(e, ox + x, oy + y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetSize(this GumpEntry e, out int width, out int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
width = ((IGumpEntrySize)e).Width;
|
||||
height = ((IGumpEntrySize)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("Width", out width) & e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetSize(this GumpEntry e, int width, int height)
|
||||
{
|
||||
if (e is IGumpEntrySize)
|
||||
{
|
||||
((IGumpEntrySize)e).Width = width;
|
||||
((IGumpEntrySize)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("Width", width) & e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetSize(this GumpEntry e, int width, int height)
|
||||
{
|
||||
|
||||
if (TryGetSize(e, out var ow, out var oh))
|
||||
{
|
||||
return TrySetSize(e, ow + width, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetBounds(this GumpEntry e, out int x, out int y, out int width, out int height)
|
||||
{
|
||||
if (e is IGumpEntryVector)
|
||||
{
|
||||
x = ((IGumpEntryVector)e).X;
|
||||
y = ((IGumpEntryVector)e).Y;
|
||||
width = ((IGumpEntryVector)e).Width;
|
||||
height = ((IGumpEntryVector)e).Height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.GetPropertyValue("X", out x) & e.GetPropertyValue("Y", out y) & //
|
||||
e.GetPropertyValue("Width", out width) & e.GetPropertyValue("Height", out height);
|
||||
}
|
||||
|
||||
public static bool TrySetBounds(this GumpEntry e, int x, int y, int width, int height)
|
||||
{
|
||||
if (e is IGumpEntryVector)
|
||||
{
|
||||
((IGumpEntryVector)e).X = x;
|
||||
((IGumpEntryVector)e).Y = y;
|
||||
((IGumpEntryVector)e).Width = width;
|
||||
((IGumpEntryVector)e).Height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return e.SetPropertyValue("X", x) & e.SetPropertyValue("Y", y) & //
|
||||
e.SetPropertyValue("Width", width) & e.SetPropertyValue("Height", height);
|
||||
}
|
||||
|
||||
public static bool TryOffsetBounds(this GumpEntry e, int x, int y, int width, int height)
|
||||
{
|
||||
|
||||
if (TryGetBounds(e, out var ox, out var oy, out var ow, out var oh))
|
||||
{
|
||||
return TrySetBounds(e, ox + x, oy + y, ow + width, oh + height);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Rectangle2D GetBounds(this Gump g)
|
||||
{
|
||||
int x = g.X, y = g.Y, w = 0, h = 0;
|
||||
|
||||
if (g is SuperGump)
|
||||
{
|
||||
var sg = (SuperGump)g;
|
||||
|
||||
x += sg.XOffset;
|
||||
y += sg.YOffset;
|
||||
|
||||
if (sg.Modal)
|
||||
{
|
||||
x += sg.ModalXOffset;
|
||||
y += sg.ModalYOffset;
|
||||
}
|
||||
|
||||
w = sg.OuterWidth;
|
||||
h = sg.OuterHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var e in g.Entries)
|
||||
{
|
||||
e.TryGetPosition(out var ex, out var ey);
|
||||
|
||||
e.TryGetSize(out var ew, out var eh);
|
||||
|
||||
w = Math.Max(ex + ew, w);
|
||||
h = Math.Max(ey + eh, h);
|
||||
}
|
||||
}
|
||||
|
||||
return new Rectangle2D(x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
926
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ItemExt.cs
Normal file
926
Scripts/SubSystem/VitaNex/Core/Extensions/Server/ItemExt.cs
Normal file
@@ -0,0 +1,926 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Multis;
|
||||
using Server.Network;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Collections;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[Flags]
|
||||
public enum GiveFlags
|
||||
{
|
||||
None = 0x0,
|
||||
Pack = 0x1,
|
||||
Bank = 0x2,
|
||||
Corpse = 0x4,
|
||||
Feet = 0x8,
|
||||
|
||||
Delete = 0x40000000,
|
||||
|
||||
PackBank = Pack | Bank,
|
||||
PackCorpse = Pack | Corpse,
|
||||
PackFeet = Pack | Feet,
|
||||
PackDelete = Pack | Delete,
|
||||
|
||||
PackBankCorpse = PackBank | Corpse,
|
||||
PackBankFeet = PackBank | Feet,
|
||||
PackBankDelete = PackBank | Delete,
|
||||
|
||||
PackBankCorpseFeet = PackBankCorpse | Feet,
|
||||
PackBankCorpseDelete = PackBankCorpse | Delete,
|
||||
PackBankFeetDelete = PackBankFeet | Delete,
|
||||
|
||||
PackBankCorpseFeetDelete = PackBankCorpseFeet | Delete,
|
||||
|
||||
PackCorpseFeet = PackCorpse | Feet,
|
||||
PackCorpseDelete = PackCorpse | Delete,
|
||||
PackCorpseFeetDelete = PackCorpseFeet | Delete,
|
||||
|
||||
PackFeetDelete = PackFeet | Delete,
|
||||
|
||||
BankCorpse = Bank | Corpse,
|
||||
BankFeet = Bank | Feet,
|
||||
BankDelete = Bank | Delete,
|
||||
|
||||
BankCorpseFeet = BankCorpse | Feet,
|
||||
BankCorpseDelete = BankCorpse | Delete,
|
||||
BankFeetDelete = BankFeet | Delete,
|
||||
|
||||
BankCorpseFeetDelete = BankCorpseFeet | Delete,
|
||||
|
||||
CorpseFeet = Corpse | Feet,
|
||||
CorpseDelete = Corpse | Delete,
|
||||
|
||||
CorpseFeetDelete = CorpseFeet | Delete,
|
||||
|
||||
FeetDelete = Feet | Delete,
|
||||
|
||||
All = ~None
|
||||
}
|
||||
|
||||
public static class ItemExtUtility
|
||||
{
|
||||
public static T BinaryClone<T>(this T item)
|
||||
where T : Item
|
||||
{
|
||||
var t = item.GetType();
|
||||
|
||||
var o = t.CreateInstanceSafe<T>(Serial.NewItem);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var w = ms.GetBinaryWriter();
|
||||
|
||||
item.Serialize(w);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
var r = ms.GetBinaryReader();
|
||||
|
||||
o.Deserialize(r);
|
||||
|
||||
w.Close();
|
||||
r.Close();
|
||||
}
|
||||
|
||||
var m = o.Parent as Mobile;
|
||||
|
||||
o.Amount = 1;
|
||||
|
||||
if (o.Items != null)
|
||||
{
|
||||
o.Items.Clear();
|
||||
}
|
||||
|
||||
o.Internalize();
|
||||
|
||||
o.Parent = null;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
o.OnRemoved(m);
|
||||
|
||||
m.OnItemRemoved(o);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
o.Delete();
|
||||
o = null;
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
public static void InvalidateProperties<T>(this Item item)
|
||||
{
|
||||
if (item is T)
|
||||
{
|
||||
item.InvalidateProperties();
|
||||
}
|
||||
|
||||
var i = item.Items.Count;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
InvalidateProperties<T>(item.Items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void InvalidateProperties(this Item item, Type type)
|
||||
{
|
||||
if (item.TypeEquals(type))
|
||||
{
|
||||
item.InvalidateProperties();
|
||||
}
|
||||
|
||||
var i = item.Items.Count;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
InvalidateProperties(item.Items[i], type);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetAnimID(this Item item)
|
||||
{
|
||||
return item != null && item.Layer.IsValid() ? ArtworkSupport.LookupAnimation(item.ItemID) : 0;
|
||||
}
|
||||
|
||||
public static int GetGumpID(this Item item, bool female)
|
||||
{
|
||||
return item != null && item.Layer.IsValid() ? ArtworkSupport.LookupGump(item.ItemID, female) : 0;
|
||||
}
|
||||
|
||||
public static PaperdollBounds GetGumpBounds(this Item item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return PaperdollBounds.Empty;
|
||||
}
|
||||
|
||||
if (item.Layer == Layer.TwoHanded)
|
||||
{
|
||||
if (item is BaseRanged)
|
||||
{
|
||||
return PaperdollBounds.MainHand;
|
||||
}
|
||||
|
||||
if (item is BaseEquipableLight || item is BaseShield)
|
||||
{
|
||||
return PaperdollBounds.OffHand;
|
||||
}
|
||||
}
|
||||
|
||||
return PaperdollBounds.Find(item.Layer);
|
||||
}
|
||||
|
||||
public static Mobile FindOwner(this Item item)
|
||||
{
|
||||
return FindOwner<Mobile>(item);
|
||||
}
|
||||
|
||||
public static TMobile FindOwner<TMobile>(this Item item)
|
||||
where TMobile : Mobile
|
||||
{
|
||||
if (item == null || item.Deleted)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var owner = item.RootParent as TMobile;
|
||||
|
||||
if (owner == null)
|
||||
{
|
||||
var h = BaseHouse.FindHouseAt(item);
|
||||
|
||||
if (h != null)
|
||||
{
|
||||
owner = h.Owner as TMobile;
|
||||
}
|
||||
}
|
||||
|
||||
return owner;
|
||||
}
|
||||
|
||||
public static GiveFlags GiveTo(this Item item, Mobile m, GiveFlags flags = GiveFlags.All, bool message = true)
|
||||
{
|
||||
if (item == null || item.Deleted || m == null || m.Deleted || flags == GiveFlags.None)
|
||||
{
|
||||
return GiveFlags.None;
|
||||
}
|
||||
|
||||
var pack = flags.HasFlag(GiveFlags.Pack);
|
||||
var bank = flags.HasFlag(GiveFlags.Bank);
|
||||
var feet = flags.HasFlag(GiveFlags.Feet);
|
||||
var corpse = flags.HasFlag(GiveFlags.Corpse);
|
||||
var delete = flags.HasFlag(GiveFlags.Delete);
|
||||
|
||||
if (pack && (m.Backpack == null || m.Backpack.Deleted || !m.Backpack.CheckHold(m, item, false)))
|
||||
{
|
||||
pack = false;
|
||||
flags &= ~GiveFlags.Pack;
|
||||
}
|
||||
|
||||
if (bank && (!m.Player || !m.BankBox.CheckHold(m, item, false)))
|
||||
{
|
||||
bank = false;
|
||||
flags &= ~GiveFlags.Bank;
|
||||
}
|
||||
|
||||
if (corpse && (m.Alive || m.Corpse == null || m.Corpse.Deleted))
|
||||
{
|
||||
corpse = false;
|
||||
flags &= ~GiveFlags.Corpse;
|
||||
}
|
||||
|
||||
if (feet && (m.Map == null || m.Map == Map.Internal) && (m.LogoutMap == null || m.LogoutMap == Map.Internal))
|
||||
{
|
||||
feet = false;
|
||||
flags &= ~GiveFlags.Feet;
|
||||
}
|
||||
|
||||
var result = VitaNexCore.TryCatchGet(
|
||||
f =>
|
||||
{
|
||||
if (pack && m.Backpack.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Pack;
|
||||
}
|
||||
|
||||
if (bank && m.BankBox.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Bank;
|
||||
}
|
||||
|
||||
if (corpse && m.Corpse.DropItemStack(m, item))
|
||||
{
|
||||
return GiveFlags.Corpse;
|
||||
}
|
||||
|
||||
if (feet)
|
||||
{
|
||||
if (m.Map != null && m.Map != Map.Internal)
|
||||
{
|
||||
item.MoveToWorld(m.Location, m.Map);
|
||||
|
||||
if (m.Player)
|
||||
{
|
||||
item.SendInfoTo(m.NetState);
|
||||
}
|
||||
|
||||
return GiveFlags.Feet;
|
||||
}
|
||||
|
||||
if (m.LogoutMap != null && m.LogoutMap != Map.Internal)
|
||||
{
|
||||
item.MoveToWorld(m.LogoutLocation, m.LogoutMap);
|
||||
|
||||
return GiveFlags.Feet;
|
||||
}
|
||||
}
|
||||
|
||||
if (delete)
|
||||
{
|
||||
item.Delete();
|
||||
|
||||
return GiveFlags.Delete;
|
||||
}
|
||||
|
||||
return GiveFlags.None;
|
||||
},
|
||||
flags);
|
||||
|
||||
if (!message || result == GiveFlags.None || result == GiveFlags.Delete)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var amount = String.Empty;
|
||||
var name = ResolveName(item, m);
|
||||
|
||||
var p = item.Stackable && item.Amount > 1;
|
||||
|
||||
if (p)
|
||||
{
|
||||
amount = item.Amount.ToString("#,0") + " ";
|
||||
|
||||
if (!Insensitive.EndsWith(name, "s") && !Insensitive.EndsWith(name, "z"))
|
||||
{
|
||||
name += "s";
|
||||
}
|
||||
}
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case GiveFlags.Pack:
|
||||
m.SendMessage("{0}{1} {2} been placed in your pack.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Bank:
|
||||
m.SendMessage("{0}{1} {2} been placed in your bank.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Corpse:
|
||||
m.SendMessage("{0}{1} {2} been placed in your corpse.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
case GiveFlags.Feet:
|
||||
m.SendMessage("{0}{1} {2} been placed at your feet.", amount, name, p ? "have" : "has");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool WasReceived(this GiveFlags flags)
|
||||
{
|
||||
return flags != GiveFlags.None && flags != GiveFlags.Delete;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Item, List<object>> _Actions = new Dictionary<Item, List<object>>();
|
||||
|
||||
public static bool BeginAction(this Item item, object toLock)
|
||||
{
|
||||
|
||||
if (!_Actions.TryGetValue(item, out var actions) || actions == null)
|
||||
{
|
||||
ObjectPool.Acquire(out actions);
|
||||
|
||||
_Actions[item] = actions;
|
||||
}
|
||||
|
||||
if (!actions.Contains(toLock))
|
||||
{
|
||||
actions.Add(toLock);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CanBeginAction(this Item item, object toLock)
|
||||
{
|
||||
var actions = _Actions.GetValue(item);
|
||||
|
||||
return actions == null || !actions.Contains(toLock);
|
||||
}
|
||||
|
||||
public static void EndAction(this Item item, object toLock)
|
||||
{
|
||||
var actions = _Actions.GetValue(item);
|
||||
|
||||
if (actions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
actions.Remove(toLock);
|
||||
|
||||
if (actions.Count == 0)
|
||||
{
|
||||
_Actions.Remove(item);
|
||||
|
||||
ObjectPool.Free(ref actions);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration, Action<Item> callback)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker, callback));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T, Action<Item>> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
|
||||
if (t.Item3 != null)
|
||||
{
|
||||
t.Item3(t.Item1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BeginAction<T>(this Item item, T locker, TimeSpan duration, Action<Item, T> callback)
|
||||
{
|
||||
var o = BeginAction(item, locker);
|
||||
|
||||
if (o)
|
||||
{
|
||||
Timer.DelayCall(duration, EndAction, Tuple.Create(item, locker, callback));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void EndAction<T>(Tuple<Item, T, Action<Item, T>> t)
|
||||
{
|
||||
if (!CanBeginAction(t.Item1, t.Item2))
|
||||
{
|
||||
EndAction(t.Item1, t.Item2);
|
||||
|
||||
if (t.Item3 != null)
|
||||
{
|
||||
t.Item3(t.Item1, t.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item)
|
||||
{
|
||||
return ResolveName(item, Clilocs.DefaultLanguage);
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item, Mobile viewer)
|
||||
{
|
||||
return ResolveName(item, viewer.GetLanguage());
|
||||
}
|
||||
|
||||
public static string ResolveName(this Item item, ClilocLNG lng)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
var label = item.GetOPLHeader(lng);
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.Replace("\t", " ").Replace("\u0009", " ").Replace("<br>", "\n").Replace("<BR>", "\n").Trim();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.StripHtml(false);
|
||||
label = label.Trim();
|
||||
|
||||
int idx;
|
||||
|
||||
if ((idx = label.IndexOf('\n')) >= 0)
|
||||
{
|
||||
if (idx > 0)
|
||||
{
|
||||
label = label.Substring(0, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
label = label.TrimStart('\n');
|
||||
}
|
||||
}
|
||||
|
||||
label = label.Trim();
|
||||
|
||||
if ((idx = label.IndexOf(' ')) >= 0)
|
||||
{
|
||||
if (idx > 0)
|
||||
{
|
||||
|
||||
if (Int32.TryParse(label.Substring(0, idx), NumberStyles.Number, CultureInfo.InvariantCulture, out var amount))
|
||||
{
|
||||
label = label.Substring(idx + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
label = label.TrimStart(' ');
|
||||
}
|
||||
}
|
||||
|
||||
label = label.Trim();
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.Name != null)
|
||||
{
|
||||
label = item.Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.DefaultName != null)
|
||||
{
|
||||
label = item.DefaultName;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && item.LabelNumber > 0)
|
||||
{
|
||||
label = lng.GetString(item.LabelNumber);
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label) && TileData.ItemTable.InBounds(item.ItemID))
|
||||
{
|
||||
label = TileData.ItemTable[item.ItemID].Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(label))
|
||||
{
|
||||
label = item.GetType().Name.SpaceWords();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(label))
|
||||
{
|
||||
label = label.StripExcessWhiteSpace().Trim();
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
public static bool HasUsesRemaining(this Item item)
|
||||
{
|
||||
|
||||
return CheckUsesRemaining(item, false, out var uses);
|
||||
}
|
||||
|
||||
public static bool HasUsesRemaining(this Item item, out int uses)
|
||||
{
|
||||
return CheckUsesRemaining(item, false, out uses);
|
||||
}
|
||||
|
||||
public static bool CheckUsesRemaining(this Item item, bool deplete, out int uses)
|
||||
{
|
||||
return CheckUsesRemaining(item, deplete ? 1 : 0, out uses);
|
||||
}
|
||||
|
||||
public static bool CheckUsesRemaining(this Item item, int deplete, out int uses)
|
||||
{
|
||||
uses = -1;
|
||||
|
||||
if (item == null || item.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(item is IUsesRemaining))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var u = (IUsesRemaining)item;
|
||||
|
||||
if (u.UsesRemaining <= 0)
|
||||
{
|
||||
uses = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deplete > 0)
|
||||
{
|
||||
if (u.UsesRemaining < deplete)
|
||||
{
|
||||
uses = u.UsesRemaining;
|
||||
return false;
|
||||
}
|
||||
|
||||
u.UsesRemaining = Math.Max(0, u.UsesRemaining - deplete);
|
||||
}
|
||||
|
||||
uses = u.UsesRemaining;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CheckUse(
|
||||
this Item item,
|
||||
Mobile from,
|
||||
bool handle = true,
|
||||
bool allowDead = false,
|
||||
int range = -1,
|
||||
bool packOnly = false,
|
||||
bool inTrade = false,
|
||||
bool inDisplay = true,
|
||||
AccessLevel access = AccessLevel.Player)
|
||||
{
|
||||
return CheckDoubleClick(item, from, handle, allowDead, range, packOnly, inTrade, inDisplay, access);
|
||||
}
|
||||
|
||||
public static bool CheckDoubleClick(
|
||||
this Item item,
|
||||
Mobile from,
|
||||
bool handle = true,
|
||||
bool allowDead = false,
|
||||
int range = -1,
|
||||
bool packOnly = false,
|
||||
bool inTrade = false,
|
||||
bool inDisplay = true,
|
||||
AccessLevel access = AccessLevel.Player)
|
||||
{
|
||||
if (item == null || item.Deleted || from == null || from.Deleted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from.AccessLevel < access)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("You do not have sufficient access to use this item.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.CanSee(item) && !(item is IAddon))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("This item can't be seen.");
|
||||
item.OnDoubleClickCantSee(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item.IsAccessibleTo(from))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickNotAccessible(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.InSecureTrade && !inTrade)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickSecureTrade(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((item.Parent == null && !item.Movable && !item.IsLockedDown && !item.IsSecure && !item.InSecureTrade) ||
|
||||
IsShopItem(item)) && !inDisplay)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
from.SendMessage("This item can not be accessed because it is part of a display.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.Alive && !allowDead)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
item.OnDoubleClickDead(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (range >= 0 && !packOnly && !from.InRange(item, range))
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
if (range > 0)
|
||||
{
|
||||
from.SendMessage("You must be within {0:#,0} paces to use this item.", range);
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("You must be standing on this item to use it.");
|
||||
}
|
||||
|
||||
item.OnDoubleClickOutOfRange(from);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packOnly && item.RootParent != from)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
// This item must be in your backpack.
|
||||
from.SendLocalizedMessage(1054107);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsShopItem(this Item item)
|
||||
{
|
||||
return HasParent(item, "Server.Mobiles.GenericBuyInfo+DisplayCache");
|
||||
}
|
||||
|
||||
public static bool IsParentOf(this Item item, Item child)
|
||||
{
|
||||
if (item == null || child == null || item == child)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var p = child.Parent as Item;
|
||||
|
||||
while (p != null && p != item)
|
||||
{
|
||||
p = p.Parent as Item;
|
||||
}
|
||||
|
||||
return item == p;
|
||||
}
|
||||
|
||||
public static bool HasParent<TEntity>(this Item item)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return HasParent(item, typeof(TEntity));
|
||||
}
|
||||
|
||||
public static bool HasParent(this Item item, string typeName)
|
||||
{
|
||||
if (item == null || String.IsNullOrWhiteSpace(typeName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var t = Type.GetType(typeName, false, false) ?? ScriptCompiler.FindTypeByFullName(typeName, false) ??
|
||||
ScriptCompiler.FindTypeByName(typeName, false);
|
||||
|
||||
return HasParent(item, t);
|
||||
}
|
||||
|
||||
public static bool HasParent(this Item item, Type t)
|
||||
{
|
||||
if (item == null || t == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var p = item.Parent;
|
||||
|
||||
while (p is Item)
|
||||
{
|
||||
if (p.GetType().IsEqualOrChildOf(t))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var i = (Item)p;
|
||||
|
||||
if (i.Parent == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p = i.Parent;
|
||||
}
|
||||
|
||||
return p is Mobile && p.GetType().IsEqualOrChildOf(t);
|
||||
}
|
||||
|
||||
public static bool IsEquipped(this Item item)
|
||||
{
|
||||
return item != null && item.Parent is Mobile && ((Mobile)item.Parent).FindItemOnLayer(item.Layer) == item;
|
||||
}
|
||||
|
||||
public static bool IsEquippedBy(this Item item, Mobile m)
|
||||
{
|
||||
return item != null && item.Parent == m && m.FindItemOnLayer(item.Layer) == item;
|
||||
}
|
||||
|
||||
#region *OverheadMessage
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, bool ascii, string text, NetState state)
|
||||
{
|
||||
if (state == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ascii)
|
||||
{
|
||||
state.Send(new AsciiMessage(item.Serial, item.ItemID, type, hue, 3, item.Name, text));
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Send(new UnicodeMessage(item.Serial, item.ItemID, type, hue, 3, "ENU", item.Name, text));
|
||||
}
|
||||
}
|
||||
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, int number, NetState state)
|
||||
{
|
||||
PrivateOverheadMessage(item, type, hue, number, "", state);
|
||||
}
|
||||
|
||||
public static void PrivateOverheadMessage(this Item item, MessageType type, int hue, int number, string args, NetState state)
|
||||
{
|
||||
if (state != null)
|
||||
{
|
||||
state.Send(new MessageLocalized(item.Serial, item.ItemID, type, hue, 3, number, item.Name, args));
|
||||
}
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, int number)
|
||||
{
|
||||
NonlocalOverheadMessage(item, type, hue, number, "");
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, int number, string args)
|
||||
{
|
||||
if (item == null || item.Map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var p = Packet.Acquire(new MessageLocalized(item.Serial, item.ItemID, type, hue, 3, number, item.Name, args));
|
||||
|
||||
var eable = item.GetClientsInRange(Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var state in eable)
|
||||
{
|
||||
if (state.Mobile.InUpdateRange(item) && state.Mobile.CanSee(item))
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
Packet.Release(p);
|
||||
}
|
||||
|
||||
public static void NonlocalOverheadMessage(this Item item, MessageType type, int hue, bool ascii, string text)
|
||||
{
|
||||
if (item == null || item.Map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Packet p;
|
||||
|
||||
if (ascii)
|
||||
{
|
||||
p = new AsciiMessage(item.Serial, item.ItemID, type, hue, 3, item.Name, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new UnicodeMessage(item.Serial, item.ItemID, type, hue, 3, "ENU", item.Name, text);
|
||||
}
|
||||
|
||||
p.Acquire();
|
||||
|
||||
var eable = item.GetClientsInRange(Core.GlobalMaxUpdateRange);
|
||||
|
||||
foreach (var state in eable)
|
||||
{
|
||||
if (state.Mobile.InUpdateRange(item) && state.Mobile.CanSee(item))
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
Packet.Release(p);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
221
Scripts/SubSystem/VitaNex/Core/Extensions/Server/LayerExt.cs
Normal file
221
Scripts/SubSystem/VitaNex/Core/Extensions/Server/LayerExt.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class LayerExtUtility
|
||||
{
|
||||
private const Layer _Face = (Layer)15;
|
||||
private const Layer _ShopMax = (Layer)30;
|
||||
|
||||
private const Layer _PlateArms = (Layer)255;
|
||||
private const Layer _ChainTunic = (Layer)254;
|
||||
private const Layer _LeatherShorts = (Layer)253;
|
||||
|
||||
public static Layer[] LayerOrder =
|
||||
{
|
||||
Layer.Cloak, Layer.Bracelet, Layer.Ring, Layer.Shirt, Layer.Pants, Layer.InnerLegs, Layer.Shoes, _LeatherShorts,
|
||||
Layer.Arms, Layer.InnerTorso, _LeatherShorts, _PlateArms, Layer.MiddleTorso, Layer.OuterLegs, Layer.Neck,
|
||||
Layer.Gloves, Layer.OuterTorso, Layer.Waist, Layer.OneHanded, Layer.TwoHanded, _Face, Layer.FacialHair, Layer.Hair,
|
||||
Layer.Helm, Layer.Talisman
|
||||
};
|
||||
|
||||
public static Layer[] EquipLayers =
|
||||
{
|
||||
Layer.Arms, Layer.Bracelet, Layer.Cloak, Layer.Earrings, Layer.Gloves, Layer.Helm, Layer.InnerLegs, Layer.InnerTorso,
|
||||
Layer.MiddleTorso, Layer.Neck, Layer.OneHanded, Layer.OuterLegs, Layer.OuterTorso, Layer.Pants, Layer.Ring,
|
||||
Layer.Shirt, Layer.Shoes, Layer.Talisman, Layer.TwoHanded, Layer.Waist, Layer.Mount
|
||||
};
|
||||
|
||||
public static int[] LayerTable { get; private set; }
|
||||
|
||||
static LayerExtUtility()
|
||||
{
|
||||
LayerTable = new int[256];
|
||||
|
||||
for (var i = 0; i < LayerOrder.Length; ++i)
|
||||
{
|
||||
LayerTable[(int)LayerOrder[i]] = LayerOrder.Length - i;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetOrderIndex(this Layer layer)
|
||||
{
|
||||
return LayerOrder.IndexOf(layer);
|
||||
}
|
||||
|
||||
public static bool IsEquip(this Layer layer)
|
||||
{
|
||||
return EquipLayers.Contains(layer);
|
||||
}
|
||||
|
||||
public static bool IsMount(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Mount;
|
||||
}
|
||||
|
||||
public static bool IsPack(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Backpack;
|
||||
}
|
||||
|
||||
public static bool IsBank(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Bank;
|
||||
}
|
||||
|
||||
public static bool IsPackOrBank(this Layer layer)
|
||||
{
|
||||
return IsPack(layer) || IsBank(layer);
|
||||
}
|
||||
|
||||
public static bool IsFace(this Layer layer)
|
||||
{
|
||||
return layer == _Face;
|
||||
}
|
||||
|
||||
public static bool IsHair(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Hair;
|
||||
}
|
||||
|
||||
public static bool IsFacialHair(this Layer layer)
|
||||
{
|
||||
return layer == Layer.FacialHair;
|
||||
}
|
||||
|
||||
public static bool IsHairOrFacialHair(this Layer layer)
|
||||
{
|
||||
return IsHair(layer) || IsFacialHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsFaceOrHair(this Layer layer)
|
||||
{
|
||||
return IsFace(layer) || IsHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsFaceOrHairOrFacialHair(this Layer layer)
|
||||
{
|
||||
return IsFace(layer) || IsHair(layer) || IsFacialHair(layer);
|
||||
}
|
||||
|
||||
public static bool IsShop(this Layer layer)
|
||||
{
|
||||
return layer == Layer.ShopBuy || layer == Layer.ShopResale || layer == Layer.ShopSell || layer == _ShopMax;
|
||||
}
|
||||
|
||||
public static bool IsInvalid(this Layer layer)
|
||||
{
|
||||
return layer == Layer.Invalid;
|
||||
}
|
||||
|
||||
public static bool IsValid(this Layer layer)
|
||||
{
|
||||
return IsEquip(layer) || IsPackOrBank(layer) || IsFaceOrHair(layer);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Item> OrderByLayer(this IEnumerable<Item> items)
|
||||
{
|
||||
return items.OrderBy(item => item == null ? 0 : LayerTable[(int)Fix(item.Layer, item.ItemID)]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Item> OrderByLayerDescending(this IEnumerable<Item> items)
|
||||
{
|
||||
return items.OrderByDescending(item => item == null ? 0 : LayerTable[(int)Fix(item.Layer, item.ItemID)]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Layer> OrderByLayer(this IEnumerable<Layer> layers)
|
||||
{
|
||||
return layers.OrderBy(layer => LayerTable[(int)layer]);
|
||||
}
|
||||
|
||||
public static IOrderedEnumerable<Layer> OrderByLayerDescending(this IEnumerable<Layer> layers)
|
||||
{
|
||||
return layers.OrderByDescending(layer => LayerTable[(int)layer]);
|
||||
}
|
||||
|
||||
public static void SortLayers(this List<Item> items)
|
||||
{
|
||||
if (items != null && items.Count > 1)
|
||||
{
|
||||
items.Sort(CompareLayer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SortLayers(this List<Layer> layers)
|
||||
{
|
||||
if (layers != null && layers.Count > 1)
|
||||
{
|
||||
layers.Sort(CompareLayer);
|
||||
}
|
||||
}
|
||||
|
||||
public static int CompareLayer(this Item item, Item other)
|
||||
{
|
||||
var res = 0;
|
||||
|
||||
if (item.CompareNull(other, ref res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
return CompareLayer(Fix(item.Layer, item.ItemID), Fix(other.Layer, other.ItemID));
|
||||
}
|
||||
|
||||
public static int CompareLayer(this Layer layer, Layer other)
|
||||
{
|
||||
return LayerTable[(int)other] - LayerTable[(int)layer];
|
||||
}
|
||||
|
||||
public static bool IsOrdered(this Layer layer)
|
||||
{
|
||||
return LayerTable[(int)layer] > 0;
|
||||
}
|
||||
|
||||
public static Layer Fix(this Layer layer, int itemID)
|
||||
{
|
||||
if (itemID == 0x1410 || itemID == 0x1417) // platemail arms
|
||||
{
|
||||
return _PlateArms;
|
||||
}
|
||||
|
||||
if (itemID == 0x13BF || itemID == 0x13C4) // chainmail tunic
|
||||
{
|
||||
return _ChainTunic;
|
||||
}
|
||||
|
||||
if (itemID == 0x1C08 || itemID == 0x1C09) // leather skirt
|
||||
{
|
||||
return _LeatherShorts;
|
||||
}
|
||||
|
||||
if (itemID == 0x1C00 || itemID == 0x1C01) // leather shorts
|
||||
{
|
||||
return _LeatherShorts;
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
public static PaperdollBounds GetPaperdollBounds(this Layer layer)
|
||||
{
|
||||
return PaperdollBounds.Find(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
322
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MapExt.cs
Normal file
322
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MapExt.cs
Normal file
@@ -0,0 +1,322 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class MapExtUtility
|
||||
{
|
||||
#region StaticWaterTiles
|
||||
public static List<int> StaticWaterTiles = new List<int>
|
||||
{
|
||||
5465,
|
||||
6038,
|
||||
6039,
|
||||
6040,
|
||||
6041,
|
||||
6042,
|
||||
6043,
|
||||
6044,
|
||||
13422,
|
||||
13423,
|
||||
13424,
|
||||
13425,
|
||||
13426,
|
||||
13427,
|
||||
13428,
|
||||
13429,
|
||||
13430,
|
||||
13431,
|
||||
13432,
|
||||
13433,
|
||||
13434,
|
||||
13435,
|
||||
13436,
|
||||
13437,
|
||||
13438,
|
||||
13439,
|
||||
13440,
|
||||
13441,
|
||||
13442,
|
||||
13443,
|
||||
13445,
|
||||
13456,
|
||||
13457,
|
||||
13458,
|
||||
13459,
|
||||
13460,
|
||||
13461,
|
||||
13462,
|
||||
13463,
|
||||
13464,
|
||||
13465,
|
||||
13466,
|
||||
13467,
|
||||
13468,
|
||||
13469,
|
||||
13470,
|
||||
13471,
|
||||
13472,
|
||||
13473,
|
||||
13474,
|
||||
13475,
|
||||
13476,
|
||||
13477,
|
||||
13478,
|
||||
13479,
|
||||
13480,
|
||||
13481,
|
||||
13482,
|
||||
13483,
|
||||
13494,
|
||||
13495,
|
||||
13496,
|
||||
13497,
|
||||
13498,
|
||||
13499,
|
||||
13500,
|
||||
13501,
|
||||
13502,
|
||||
13503,
|
||||
13504,
|
||||
13505,
|
||||
13506,
|
||||
13507,
|
||||
13508,
|
||||
13509,
|
||||
13510,
|
||||
13511,
|
||||
13512,
|
||||
13513,
|
||||
13514,
|
||||
13515,
|
||||
13516,
|
||||
13517,
|
||||
13518,
|
||||
13519,
|
||||
13520,
|
||||
13521,
|
||||
13522,
|
||||
13523,
|
||||
13524,
|
||||
13525,
|
||||
13597,
|
||||
13598,
|
||||
13599,
|
||||
13600,
|
||||
13601,
|
||||
13602,
|
||||
13603,
|
||||
13604,
|
||||
13605,
|
||||
13606,
|
||||
13607,
|
||||
13608,
|
||||
13609,
|
||||
13610,
|
||||
13611,
|
||||
13612,
|
||||
13613,
|
||||
13614,
|
||||
13615,
|
||||
13616
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region LandWaterTiles
|
||||
public static List<int> LandWaterTiles = new List<int>
|
||||
{
|
||||
168,
|
||||
169,
|
||||
170,
|
||||
171,
|
||||
310,
|
||||
311,
|
||||
|
||||
#region Coastlines
|
||||
76,
|
||||
77,
|
||||
78,
|
||||
79,
|
||||
80,
|
||||
81,
|
||||
82,
|
||||
83,
|
||||
84,
|
||||
85,
|
||||
86,
|
||||
87,
|
||||
88,
|
||||
89,
|
||||
90,
|
||||
91,
|
||||
92,
|
||||
93,
|
||||
94,
|
||||
95,
|
||||
96,
|
||||
97,
|
||||
98,
|
||||
99,
|
||||
100,
|
||||
101,
|
||||
102,
|
||||
103,
|
||||
104,
|
||||
105,
|
||||
106,
|
||||
107,
|
||||
108,
|
||||
109,
|
||||
110,
|
||||
111
|
||||
#endregion
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region LandCoastlineTiles
|
||||
public static List<int> LandCoastlineTiles = new List<int>
|
||||
{
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
40,
|
||||
41,
|
||||
42,
|
||||
43,
|
||||
44,
|
||||
45,
|
||||
46,
|
||||
47,
|
||||
48,
|
||||
49,
|
||||
50
|
||||
};
|
||||
#endregion
|
||||
|
||||
public static bool IsWater(this Item item)
|
||||
{
|
||||
return StaticWaterTiles.Contains(item.ItemID) || item.ItemData.Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(item.Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this LandTarget targ)
|
||||
{
|
||||
return LandWaterTiles.Contains(targ.TileID) || TileData.LandTable[targ.TileID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.LandTable[targ.TileID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this StaticTarget targ)
|
||||
{
|
||||
return StaticWaterTiles.Contains(targ.ItemID) || TileData.ItemTable[targ.ItemID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.ItemTable[targ.ItemID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this LandTile tile)
|
||||
{
|
||||
return LandWaterTiles.Contains(tile.ID) || TileData.LandTable[tile.ID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.LandTable[tile.ID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsWater(this StaticTile tile)
|
||||
{
|
||||
return StaticWaterTiles.Contains(tile.ID) || TileData.ItemTable[tile.ID].Flags.HasFlag(TileFlag.Wet) ||
|
||||
Insensitive.Contains(TileData.ItemTable[tile.ID].Name, "water");
|
||||
}
|
||||
|
||||
public static bool IsCoastline(this LandTile tile)
|
||||
{
|
||||
return LandCoastlineTiles.Contains(tile.ID) || (TileData.LandTable[tile.ID].Flags == TileFlag.Impassable &&
|
||||
Insensitive.Contains(TileData.LandTable[tile.ID].Name, "sand"));
|
||||
}
|
||||
|
||||
public static bool HasWater(this Map map, IPoint2D p)
|
||||
{
|
||||
return IsWater(GetLandTile(map, p)) || GetStaticTiles(map, p).Any(IsWater);
|
||||
}
|
||||
|
||||
public static bool HasLand(this Map map, IPoint2D p)
|
||||
{
|
||||
return !GetLandTile(map, p).Ignored;
|
||||
}
|
||||
|
||||
public static LandTile GetLandTile(this Map map, IPoint2D p)
|
||||
{
|
||||
return map.Tiles.GetLandTile(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static StaticTile[] GetStaticTiles(this Map map, IPoint2D p)
|
||||
{
|
||||
return map.Tiles.GetStaticTiles(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static StaticTile[] GetStaticTiles(this Map map, IPoint2D p, bool multis)
|
||||
{
|
||||
return map.Tiles.GetStaticTiles(p.X, p.Y, multis);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetInnerBounds2D(this Map map)
|
||||
{
|
||||
switch (map.MapID)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return new Rectangle2D(0, 0, Math.Min(5120, map.Width), map.Height);
|
||||
case 3:
|
||||
return new Rectangle2D(512, 0, map.Width - 512, map.Height);
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, map.Width, map.Height);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetInnerBounds3D(this Map map)
|
||||
{
|
||||
switch (map.MapID)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return new Rectangle3D(0, 0, Region.MinZ, Math.Min(5120, map.Width), map.Height, Region.MaxZ - Region.MinZ);
|
||||
case 3:
|
||||
return new Rectangle3D(512, 0, Region.MinZ, map.Width - 512, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
|
||||
return new Rectangle3D(0, 0, Region.MinZ, map.Width, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetBounds2D(this Map map)
|
||||
{
|
||||
return new Rectangle2D(0, 0, map.Width, map.Height);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds3D(this Map map)
|
||||
{
|
||||
return new Rectangle3D(0, 0, Region.MinZ, map.Width, map.Height, Region.MaxZ - Region.MinZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
1780
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MobileExt.cs
Normal file
1780
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MobileExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
331
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MultiExt.cs
Normal file
331
Scripts/SubSystem/VitaNex/Core/Extensions/Server/MultiExt.cs
Normal file
@@ -0,0 +1,331 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class MultiExtUtility
|
||||
{
|
||||
static MultiExtUtility()
|
||||
{
|
||||
ComponentsCache = new Dictionary<int, MultiComponentList>();
|
||||
WireframeCache = new Dictionary<int, Wireframe>();
|
||||
BoundsCache = new Dictionary<int, Rectangle3D>();
|
||||
}
|
||||
|
||||
#region Components
|
||||
public static Dictionary<int, MultiComponentList> ComponentsCache { get; private set; }
|
||||
|
||||
public static MultiComponentList GetComponents(this BaseMulti multi)
|
||||
{
|
||||
return GetComponents(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID <= 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetComponents(multiID);
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (ComponentsCache.TryGetValue(multiID, out var mcl) && mcl != null)
|
||||
{
|
||||
return mcl;
|
||||
}
|
||||
|
||||
ComponentsCache[multiID] = mcl = MultiData.GetComponents(multiID);
|
||||
|
||||
// Minax Fortress
|
||||
if (multiID == 0x1388)
|
||||
{
|
||||
// That tree...
|
||||
mcl.Remove(3405, 17, -13, 15);
|
||||
mcl.Remove(3406, 18, -14, 15);
|
||||
mcl.Remove(3393, 18, -14, 17);
|
||||
}
|
||||
|
||||
if (mcl.List.Length == 0)
|
||||
{
|
||||
mcl.Resize(1, 1);
|
||||
mcl.Add(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
return mcl;
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, int x, int y, int w, int h, int z = 0, int d = 1)
|
||||
{
|
||||
TileAdd(mcl, itemID, new Rectangle2D(x, y, w, h), z, d);
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, Rectangle2D bounds, int z = 0, int d = 1)
|
||||
{
|
||||
TileAdd(mcl, itemID, bounds.ToRectangle3D(z, d));
|
||||
}
|
||||
|
||||
public static void TileAdd(this MultiComponentList mcl, int itemID, Rectangle3D bounds)
|
||||
{
|
||||
for (var z = bounds.Start.Z; z < bounds.End.Z; z++)
|
||||
{
|
||||
for (var x = bounds.Start.X; x < bounds.End.X; x++)
|
||||
{
|
||||
for (var y = bounds.Start.Y; y < bounds.End.Y; y++)
|
||||
{
|
||||
mcl.Add(itemID, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Wireframes
|
||||
public static Dictionary<int, Wireframe> WireframeCache { get; private set; }
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IPoint3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IPoint3D offset, int hOffset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset, hOffset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, IBlock3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID, offset);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IPoint3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multiID, offset, 0);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IBlock3D offset)
|
||||
{
|
||||
return GetWireframe(multi, multiID, offset, offset.H);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID, IPoint3D offset, int hOffset)
|
||||
{
|
||||
var o = GetWireframe(multi, multiID);
|
||||
|
||||
return new Wireframe(o.Select(b => b.Offset(offset.X, offset.Y, offset.Z, hOffset)));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi)
|
||||
{
|
||||
return GetWireframe(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID < 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetWireframe(multiID);
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (WireframeCache.TryGetValue(multiID, out var frame))
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
|
||||
frame = GetWireframe(GetComponents(multiID));
|
||||
|
||||
WireframeCache[multiID] = frame;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl, IPoint3D offset)
|
||||
{
|
||||
return new Wireframe(GetWireframe(mcl).Select(b => b.Offset(offset.X, offset.Y, offset.Z)));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl, IBlock3D offset)
|
||||
{
|
||||
return new Wireframe(GetWireframe(mcl).Offset(offset.X, offset.Y, offset.Z, offset.H));
|
||||
}
|
||||
|
||||
public static Wireframe GetWireframe(this MultiComponentList mcl)
|
||||
{
|
||||
if (mcl == null)
|
||||
{
|
||||
return Wireframe.Empty;
|
||||
}
|
||||
|
||||
var frame = new Block3D[mcl.List.Length];
|
||||
|
||||
frame.SetAll(
|
||||
i =>
|
||||
{
|
||||
var o = mcl.List[i];
|
||||
var h = Math.Max(5, TileData.ItemTable[o.m_ItemID].Height);
|
||||
|
||||
return new Block3D(o.m_OffsetX, o.m_OffsetY, o.m_OffsetZ, h);
|
||||
});
|
||||
|
||||
return new Wireframe(frame);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Bounds
|
||||
public static Dictionary<int, Rectangle3D> BoundsCache { get; private set; }
|
||||
|
||||
public static Rectangle3D GetBoundsOffset(this BaseMulti multi)
|
||||
{
|
||||
return GetBoundsOffset(multi, multi.Location);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBoundsOffset(this BaseMulti multi, Point3D offset)
|
||||
{
|
||||
return GetBounds(multi).Resize(offset.X, offset.Y, offset.Z);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(this BaseMulti multi)
|
||||
{
|
||||
return GetBounds(multi, multi.ItemID);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(this BaseMulti multi, int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
if (multiID <= 0)
|
||||
{
|
||||
multiID = multi.ItemID;
|
||||
}
|
||||
|
||||
return GetBounds(multiID);
|
||||
}
|
||||
|
||||
public static Rectangle3D GetBounds(int multiID)
|
||||
{
|
||||
multiID &= 0x3FFF;
|
||||
|
||||
|
||||
if (BoundsCache.TryGetValue(multiID, out var bounds))
|
||||
{
|
||||
return bounds;
|
||||
}
|
||||
|
||||
var mcl = GetComponents(multiID);
|
||||
|
||||
int minZ = mcl.List.Min(t => t.m_OffsetZ);
|
||||
var maxZ = mcl.List.Max(t => t.m_OffsetZ + Math.Max(1, TileData.ItemTable[t.m_ItemID].Height));
|
||||
|
||||
if (multiID >= 24 && multiID <= 71)
|
||||
{
|
||||
if (multiID >= 24 && multiID <= 35)
|
||||
{
|
||||
maxZ = Math.Max(80, maxZ);
|
||||
}
|
||||
else if (multiID >= 36 && multiID <= 47)
|
||||
{
|
||||
maxZ = Math.Max(100, maxZ);
|
||||
}
|
||||
else if (multiID >= 48 && multiID <= 59)
|
||||
{
|
||||
maxZ = Math.Max(90, maxZ);
|
||||
}
|
||||
else if (multiID >= 60 && multiID <= 63)
|
||||
{
|
||||
maxZ = Math.Max(20, maxZ);
|
||||
}
|
||||
else if (multiID >= 64 && multiID <= 71)
|
||||
{
|
||||
maxZ = Math.Max(110, maxZ);
|
||||
}
|
||||
}
|
||||
|
||||
bounds = new Rectangle3D(mcl.Min.X, mcl.Min.Y, minZ, mcl.Width + 1, mcl.Height + 1, maxZ - minZ);
|
||||
|
||||
BoundsCache[multiID] = bounds;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/*
|
||||
public static bool Contains(Point2D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public static bool Contains(Point3D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public static bool Contains(IPoint3D p)
|
||||
{
|
||||
return Contains(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static bool Contains(int x, int y)
|
||||
{
|
||||
MultiComponentList mcl = Components;
|
||||
|
||||
x -= X + mcl.Min.m_X;
|
||||
y -= Y + mcl.Min.m_Y;
|
||||
|
||||
return x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height && mcl.Tiles[x][y].Length > 0;
|
||||
}
|
||||
*/
|
||||
|
||||
public static bool IsEmpty(this MultiComponentList mcl, int x, int y)
|
||||
{
|
||||
return x < 0 || x >= mcl.Width || y < 0 || y >= mcl.Height || mcl.Tiles[x][y].Length == 0;
|
||||
}
|
||||
|
||||
public static bool HasEntry(this MultiComponentList mcl, int x, int y, int z)
|
||||
{
|
||||
return !IsEmpty(mcl, x, y) && mcl.Tiles[x][y].Any(t => t.Z == z);
|
||||
}
|
||||
|
||||
public static bool HasEntry(this MultiComponentList mcl, int itemID, int x, int y, int z)
|
||||
{
|
||||
return !IsEmpty(mcl, x, y) && mcl.Tiles[x][y].Any(t => t.ID == itemID && t.Z == z);
|
||||
}
|
||||
|
||||
public static Rectangle2D GetAbsoluteBounds(this MultiComponentList mcl)
|
||||
{
|
||||
return new Rectangle2D(mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
#if !ServUOX
|
||||
using System;
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static class NetStateExtUtility
|
||||
{
|
||||
private static readonly ClientVersion _70500 = new ClientVersion(7, 0, 50, 0);
|
||||
private static readonly ClientVersion _70610 = new ClientVersion(7, 0, 61, 0);
|
||||
|
||||
public static bool IsEnhanced(this NetState state)
|
||||
{
|
||||
#if ServUOX
|
||||
return state?.IsEnhancedClient == true;
|
||||
#else
|
||||
var v = state.Version;
|
||||
|
||||
if (v == null || (v.Major == 0 && v.Minor == 0 && v.Revision == 0 && v.Patch == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!state.GetPropertyValue("IsEnhancedClient", out bool ec))
|
||||
{
|
||||
ec = v.Major >= 67 || v.Type == ClientType.UOTD;
|
||||
}
|
||||
|
||||
return ec;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool SupportsUltimaStore(this NetState state)
|
||||
{
|
||||
return state != null && state.Version >= _70500;
|
||||
}
|
||||
|
||||
public static bool SupportsEndlessJourney(this NetState state)
|
||||
{
|
||||
return state != null && state.Version >= _70610;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System.Drawing;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum NotorietyType
|
||||
{
|
||||
None = 0,
|
||||
Innocent = Notoriety.Innocent,
|
||||
Ally = Notoriety.Ally,
|
||||
CanBeAttacked = Notoriety.CanBeAttacked,
|
||||
Criminal = Notoriety.Criminal,
|
||||
Enemy = Notoriety.Enemy,
|
||||
Murderer = Notoriety.Murderer,
|
||||
Invulnerable = Notoriety.Invulnerable
|
||||
}
|
||||
|
||||
public static class NotorietyExtUtility
|
||||
{
|
||||
public static int GetHue(this NotorietyType noto)
|
||||
{
|
||||
return Notoriety.GetHue((int)noto);
|
||||
}
|
||||
|
||||
public static Color GetColor(this NotorietyType noto)
|
||||
{
|
||||
switch ((int)noto)
|
||||
{
|
||||
case Notoriety.Innocent:
|
||||
return Color.SkyBlue;
|
||||
case Notoriety.Ally:
|
||||
return Color.LawnGreen;
|
||||
case Notoriety.CanBeAttacked:
|
||||
case Notoriety.Criminal:
|
||||
return Color.Silver;
|
||||
case Notoriety.Enemy:
|
||||
return Color.Orange;
|
||||
case Notoriety.Murderer:
|
||||
return Color.IndianRed;
|
||||
case Notoriety.Invulnerable:
|
||||
return Color.Yellow;
|
||||
}
|
||||
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Scripts/SubSystem/VitaNex/Core/Extensions/Server/PacketExt.cs
Normal file
217
Scripts/SubSystem/VitaNex/Core/Extensions/Server/PacketExt.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Network;
|
||||
#endregion
|
||||
|
||||
namespace VitaNex.Network
|
||||
{
|
||||
public static class PacketExtUtility
|
||||
{
|
||||
#if ServUOX
|
||||
public static bool RewriteItemID(this WorldItem p, int itemID, bool reset = true)
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int offset;
|
||||
|
||||
if (p.PacketID == 0x1A)
|
||||
{
|
||||
offset = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 8;
|
||||
}
|
||||
|
||||
return Rewrite(p, offset, (ushort)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncoming p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncoming p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
#else
|
||||
public static bool RewriteItemID(this WorldItem p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteItemID(this WorldItemSA p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 8, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteItemID(this WorldItemHS p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 8, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncomingOld p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncomingOld p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncoming p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncoming p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteBody(this MobileIncomingSA p, int itemID, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 7, (short)itemID, reset);
|
||||
}
|
||||
|
||||
public static bool RewriteHue(this MobileIncomingSA p, int hue, bool reset = true)
|
||||
{
|
||||
return Rewrite(p, 15, (short)hue, reset);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, bool value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, sbyte value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, byte value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, short value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, ushort value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, int value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
public static bool Rewrite(this Packet packet, int offset, uint value, bool reset = true)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
return writer != null && Rewrite(writer, offset, reset, writer.Write, value);
|
||||
}
|
||||
|
||||
private static bool Rewrite<T>(PacketWriter writer, int offset, bool reset, Action<T> write, T value)
|
||||
{
|
||||
var pos = -1L;
|
||||
|
||||
try
|
||||
{
|
||||
pos = writer.Position;
|
||||
|
||||
writer.Position = offset;
|
||||
|
||||
write(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (reset && pos >= 0)
|
||||
{
|
||||
writer.Position = pos;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static byte[] GetBuffer(this Packet packet)
|
||||
{
|
||||
var writer = GetWriter(packet);
|
||||
|
||||
if (writer != null)
|
||||
{
|
||||
return writer.ToArray();
|
||||
}
|
||||
|
||||
if (GetCompiledBuffer(packet, out var buffer))
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
|
||||
public static bool GetCompiledBuffer(this Packet packet, out byte[] buffer)
|
||||
{
|
||||
return packet.GetFieldValue("m_CompiledBuffer", out buffer);
|
||||
}
|
||||
|
||||
public static bool SetCompiledBuffer(this Packet packet, byte[] buffer)
|
||||
{
|
||||
return packet.SetFieldValue("m_CompiledBuffer", buffer);
|
||||
}
|
||||
|
||||
public static PacketWriter GetWriter(this Packet packet)
|
||||
{
|
||||
#if ServUOX
|
||||
return packet?.Stream;
|
||||
#else
|
||||
return packet?.UnderlyingStream;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public static class PlayerMobileExtUtility
|
||||
{
|
||||
public static ClientVersion GetClientVersion(this PlayerMobile player)
|
||||
{
|
||||
return player.IsOnline() ? player.NetState.Version : new ClientVersion(null);
|
||||
}
|
||||
|
||||
public static ClientType GetClientType(this PlayerMobile player)
|
||||
{
|
||||
return player.IsOnline() ? player.NetState.Version.Type : ClientType.Regular;
|
||||
}
|
||||
|
||||
public static bool HasClient(this PlayerMobile player, ClientType type)
|
||||
{
|
||||
return player.IsOnline() && player.NetState.Version.Type == type;
|
||||
}
|
||||
|
||||
public static void FixMap(this PlayerMobile m, MapPoint mp)
|
||||
{
|
||||
FixMap(m, mp.Map, mp.Location);
|
||||
}
|
||||
|
||||
public static void FixMap(this PlayerMobile m, Map def, Point3D loc)
|
||||
{
|
||||
if (m == null || m.Deleted || def == null || def == Map.Internal || loc == Point3D.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.LogoutMap == null || m.LogoutMap == Map.Internal)
|
||||
{
|
||||
m.LogoutLocation = loc.ToPoint3D();
|
||||
m.LogoutMap = def;
|
||||
}
|
||||
|
||||
if (m.Map != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.IsOnline())
|
||||
{
|
||||
BaseCreature.TeleportPets(m, loc, def);
|
||||
m.MoveToWorld(loc, def);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.Location = loc;
|
||||
m.Internalize();
|
||||
m.AutoStablePets();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1232
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RangeExt.cs
Normal file
1232
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RangeExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,247 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Rectangle2DExtUtility
|
||||
{
|
||||
public static Point2D GetRandomPoint(this Rectangle2D bounds)
|
||||
{
|
||||
return new Point2D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y));
|
||||
}
|
||||
|
||||
public static Rectangle2D Combine(this IEnumerable<Rectangle2D> bounds)
|
||||
{
|
||||
int count = 0, minX = Int32.MaxValue, minY = Int32.MaxValue, maxX = Int32.MinValue, maxY = Int32.MinValue;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle2D(new Point2D(minX, minY), new Point2D(maxX, maxY));
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static Rectangle3D ToRectangle3D(this Rectangle2D r, int floor = 0, int roof = 0)
|
||||
{
|
||||
return new Rectangle3D(r.X, r.Y, floor, r.Width, r.Height, roof);
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this Rectangle2D r)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = r.Width * r.Height;
|
||||
|
||||
hash = (hash * 397) ^ r.Start.GetHashCode();
|
||||
hash = (hash * 397) ^ r.End.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this IEnumerable<Rectangle2D> list)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return list.Aggregate(0, (hash, r) => (hash * 397) ^ GetBoundsHashCode(r));
|
||||
}
|
||||
}
|
||||
|
||||
public static Point2D GetCenter(this Rectangle2D r)
|
||||
{
|
||||
return r.Start.Clone2D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static int GetArea(this Rectangle2D r)
|
||||
{
|
||||
return r.Width * r.Height;
|
||||
}
|
||||
|
||||
public static Rectangle2D Resize(this Rectangle2D r, int xOff = 0, int yOff = 0, int wOff = 0, int hOff = 0)
|
||||
{
|
||||
return new Rectangle2D(r.X + xOff, r.Y + yOff, r.Width + wOff, r.Height + hOff);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle2D> Slice(this Rectangle2D rect, int w, int h)
|
||||
{
|
||||
if (rect.Width <= w && rect.Height <= h)
|
||||
{
|
||||
yield return rect;
|
||||
yield break;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
int ow, oh;
|
||||
|
||||
x = rect.Start.X;
|
||||
|
||||
while (x < rect.End.X)
|
||||
{
|
||||
ow = Math.Min(w, rect.End.X - x);
|
||||
|
||||
y = rect.Start.Y;
|
||||
|
||||
while (y < rect.End.Y)
|
||||
{
|
||||
oh = Math.Min(h, rect.End.Y - y);
|
||||
|
||||
yield return new Rectangle2D(x, y, ow, oh);
|
||||
|
||||
y += oh;
|
||||
}
|
||||
|
||||
x += ow;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindObjects<T>(this Rectangle2D r, Map m)
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r);
|
||||
|
||||
foreach (var e in o.OfType<T>())
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<TEntity> FindEntities<TEntity>(this Rectangle2D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r);
|
||||
|
||||
foreach (var e in o.OfType<TEntity>().Where(e => e.Map == m && r.Contains(e)))
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<IEntity> FindEntities(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m);
|
||||
}
|
||||
|
||||
public static List<TEntity> GetEntities<TEntity>(this Rectangle2D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return FindEntities<TEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<IEntity> GetEntities(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Item> GetItems(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<Item>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Mobile> GetMobiles(this Rectangle2D r, Map m)
|
||||
{
|
||||
return FindEntities<Mobile>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> EnumeratePoints(this Rectangle2D r)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach(this Rectangle2D r, Action<Point2D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder(this Rectangle2D r, int size)
|
||||
{
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size;
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder(this Rectangle2D r)
|
||||
{
|
||||
return GetBorder(r, 1);
|
||||
}
|
||||
|
||||
public static bool Intersects(this Rectangle2D r, Rectangle2D or)
|
||||
{
|
||||
return GetBorder(r).Union(GetBorder(or)).GroupBy(p => p).Any(g => g.Count() > 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Rectangle3DExtUtility
|
||||
{
|
||||
public static Point3D GetRandomPoint(this Rectangle3D bounds)
|
||||
{
|
||||
return new Point3D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y),
|
||||
Utility.RandomMinMax(bounds.Start.Z, bounds.End.Z));
|
||||
}
|
||||
|
||||
public static Point2D GetRandomPoint2D(this Rectangle3D bounds)
|
||||
{
|
||||
return new Point2D(
|
||||
Utility.RandomMinMax(bounds.Start.X, bounds.End.X),
|
||||
Utility.RandomMinMax(bounds.Start.Y, bounds.End.Y));
|
||||
}
|
||||
|
||||
public static Rectangle2D Combine2D(this IEnumerable<Rectangle3D> bounds)
|
||||
{
|
||||
int count = 0, minX = Int32.MaxValue, minY = Int32.MaxValue, maxX = Int32.MinValue, maxY = Int32.MinValue;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle2D(new Point2D(minX, minY), new Point2D(maxX, maxY));
|
||||
}
|
||||
|
||||
return new Rectangle2D(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static Rectangle3D Combine(this IEnumerable<Rectangle3D> bounds)
|
||||
{
|
||||
int count = 0,
|
||||
minX = Int32.MaxValue,
|
||||
minY = Int32.MaxValue,
|
||||
maxX = Int32.MinValue,
|
||||
maxY = Int32.MinValue,
|
||||
minZ = Region.MaxZ,
|
||||
maxZ = Region.MinZ;
|
||||
|
||||
foreach (var r in bounds)
|
||||
{
|
||||
minX = Math.Min(minX, Math.Min(r.Start.X, r.End.X));
|
||||
minY = Math.Min(minY, Math.Min(r.Start.Y, r.End.Y));
|
||||
minZ = Math.Min(minZ, Math.Min(r.Start.Z, r.End.Z));
|
||||
|
||||
maxX = Math.Max(maxX, Math.Max(r.Start.X, r.End.X));
|
||||
maxY = Math.Max(maxY, Math.Max(r.Start.Y, r.End.Y));
|
||||
maxZ = Math.Max(maxZ, Math.Max(r.Start.Z, r.End.Z));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
return new Rectangle3D(new Point3D(minX, minY, minZ), new Point3D(maxX, maxY, maxZ));
|
||||
}
|
||||
|
||||
return new Rectangle3D(0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> ZFix(this IEnumerable<Rectangle3D> rects)
|
||||
{
|
||||
return ZFix(rects, Region.MinZ, Region.MaxZ);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> ZFix(this IEnumerable<Rectangle3D> rects, int zMin, int zMax)
|
||||
{
|
||||
if (rects == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var r in rects.Select(r => r.ZFix(zMin, zMax)))
|
||||
{
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
|
||||
public static Rectangle3D ZFix(this Rectangle3D rect)
|
||||
{
|
||||
return ZFix(rect, Region.MinZ, Region.MaxZ);
|
||||
}
|
||||
|
||||
public static Rectangle3D ZFix(this Rectangle3D rect, int zMin, int zMax)
|
||||
{
|
||||
return new Rectangle3D(rect.Start.ToPoint3D(Math.Min(zMin, zMax)), rect.End.ToPoint3D(Math.Max(zMin, zMax)));
|
||||
}
|
||||
|
||||
public static Rectangle2D ToRectangle2D(this Rectangle3D r)
|
||||
{
|
||||
return new Rectangle2D(r.Start, r.End);
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this Rectangle3D r)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = r.Width * r.Height * r.Depth;
|
||||
|
||||
hash = (hash * 397) ^ r.Start.GetHashCode();
|
||||
hash = (hash * 397) ^ r.End.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetBoundsHashCode(this IEnumerable<Rectangle3D> list)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return list.Aggregate(0, (hash, r) => (hash * 397) ^ GetBoundsHashCode(r));
|
||||
}
|
||||
}
|
||||
|
||||
#if !ServUOX
|
||||
public static bool Contains(this RegionRect[] rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this RegionRect[] rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, IPoint2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D[] rects, Point2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
#if !ServUOX
|
||||
public static bool Contains(this List<RegionRect> rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<RegionRect> rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect.Rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, IPoint3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, Point3D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, IPoint2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this List<Rectangle3D> rects, Point2D p)
|
||||
{
|
||||
return rects.Any(rect => Contains(rect, p.X, p.Y));
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, IPoint2D p)
|
||||
{
|
||||
return Contains(rect, p.X, p.Y);
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, IPoint3D p)
|
||||
{
|
||||
return Contains(rect, p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, int x, int y)
|
||||
{
|
||||
return x >= rect.Start.X && y >= rect.Start.Y && x < rect.End.X && y < rect.End.Y;
|
||||
}
|
||||
|
||||
public static bool Contains(this Rectangle3D rect, int x, int y, int z)
|
||||
{
|
||||
return Contains(rect, x, y) && z >= rect.Start.Z && z < rect.End.Z;
|
||||
}
|
||||
|
||||
public static Point2D GetCenter2D(this Rectangle3D r)
|
||||
{
|
||||
return r.Start.Clone2D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static Point3D GetCenter(this Rectangle3D r)
|
||||
{
|
||||
return r.Start.Clone3D(r.Width / 2, r.Height / 2);
|
||||
}
|
||||
|
||||
public static int GetArea(this Rectangle3D r)
|
||||
{
|
||||
return r.Width * r.Height;
|
||||
}
|
||||
|
||||
public static int GetVolume(this Rectangle3D r)
|
||||
{
|
||||
return r.Width * r.Height * r.Depth;
|
||||
}
|
||||
|
||||
public static Rectangle2D Resize2D(
|
||||
this Rectangle3D r,
|
||||
int xOff = 0,
|
||||
int yOff = 0,
|
||||
int zOff = 0,
|
||||
int wOff = 0,
|
||||
int hOff = 0,
|
||||
int dOff = 0)
|
||||
{
|
||||
return ToRectangle2D(r).Resize(xOff, yOff, wOff, hOff);
|
||||
}
|
||||
|
||||
public static Rectangle3D Resize(
|
||||
this Rectangle3D r,
|
||||
int xOff = 0,
|
||||
int yOff = 0,
|
||||
int zOff = 0,
|
||||
int wOff = 0,
|
||||
int hOff = 0,
|
||||
int dOff = 0)
|
||||
{
|
||||
var s = r.Start;
|
||||
|
||||
return new Rectangle3D(s.X + xOff, s.Y + yOff, s.Z + zOff, r.Width + wOff, r.Height + hOff, r.Depth + dOff);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle2D> Slice2D(this Rectangle3D rect, int w, int h)
|
||||
{
|
||||
return ToRectangle2D(rect).Slice(w, h);
|
||||
}
|
||||
|
||||
public static IEnumerable<Rectangle3D> Slice(this Rectangle3D rect, int w, int h)
|
||||
{
|
||||
if (rect.Width <= w && rect.Height <= h)
|
||||
{
|
||||
yield return rect;
|
||||
yield break;
|
||||
}
|
||||
|
||||
int x, y, z = Math.Min(rect.Start.Z, rect.End.Z);
|
||||
int ow, oh, od = rect.Depth;
|
||||
|
||||
x = rect.Start.X;
|
||||
|
||||
while (x < rect.End.X)
|
||||
{
|
||||
ow = Math.Min(w, rect.End.X - x);
|
||||
|
||||
y = rect.Start.Y;
|
||||
|
||||
while (y < rect.End.Y)
|
||||
{
|
||||
oh = Math.Min(h, rect.End.Y - y);
|
||||
|
||||
yield return new Rectangle3D(x, y, z, ow, oh, od);
|
||||
|
||||
y += oh;
|
||||
}
|
||||
|
||||
x += ow;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindObjects<T>(this Rectangle3D r, Map m)
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r.ToRectangle2D());
|
||||
|
||||
foreach (var e in o.OfType<T>())
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<TEntity> FindEntities<TEntity>(this Rectangle3D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
if (m == null || m == Map.Internal)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var o = m.GetObjectsInBounds(r.ToRectangle2D());
|
||||
|
||||
foreach (var e in o.OfType<TEntity>().Where(e => e.Map == m && r.Contains(e)))
|
||||
{
|
||||
yield return e;
|
||||
}
|
||||
|
||||
o.Free();
|
||||
}
|
||||
|
||||
public static IEnumerable<IEntity> FindEntities(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m);
|
||||
}
|
||||
|
||||
public static List<TEntity> GetEntities<TEntity>(this Rectangle3D r, Map m)
|
||||
where TEntity : IEntity
|
||||
{
|
||||
return FindEntities<TEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<IEntity> GetEntities(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<IEntity>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Item> GetItems(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<Item>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static List<Mobile> GetMobiles(this Rectangle3D r, Map m)
|
||||
{
|
||||
return FindEntities<Mobile>(r, m).ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> EnumeratePoints2D(this Rectangle3D r)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> EnumeratePoints(this Rectangle3D r)
|
||||
{
|
||||
if (r.Depth > 10)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Yellow);
|
||||
"> Warning!".ToConsole();
|
||||
"> Rectangle3DExtUtility.EnumeratePoints() called on Rectangle3D with depth exceeding 10;".ToConsole();
|
||||
"> This may cause serious performance issues.".ToConsole();
|
||||
Utility.PopColor();
|
||||
}
|
||||
|
||||
for (var z = r.Start.Z; z <= r.End.Z; z++)
|
||||
{
|
||||
for (var x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
for (var y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
yield return new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach2D(this Rectangle3D r, Action<Point2D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints2D(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach(this Rectangle3D r, Action<Point3D> action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in EnumeratePoints(r))
|
||||
{
|
||||
action(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder2D(this Rectangle3D r, int size)
|
||||
{
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size;
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point2D(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point2D> GetBorder2D(this Rectangle3D r)
|
||||
{
|
||||
return GetBorder2D(r, 1);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> GetBorder(this Rectangle3D r, int size)
|
||||
{
|
||||
if (r.Depth > 10)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Yellow);
|
||||
"> Warning!".ToConsole();
|
||||
"> Rectangle3DExtUtility.EnumeratePoints() called on Rectangle3D with depth exceeding 10;".ToConsole();
|
||||
"> This may cause serious performance issues.".ToConsole();
|
||||
Utility.PopColor();
|
||||
}
|
||||
|
||||
size = Math.Max(1, size);
|
||||
|
||||
int x, y;
|
||||
int x1 = r.Start.X + size, y1 = r.Start.Y + size, z1 = r.Start.Z + size;
|
||||
int x2 = r.End.X - size, y2 = r.End.Y - size, z2 = r.End.Z - size;
|
||||
|
||||
for (var z = r.Start.Z; z <= r.End.Z; z++)
|
||||
{
|
||||
if (z >= z1 || z <= z2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (x = r.Start.X; x <= r.End.X; x++)
|
||||
{
|
||||
if (x >= x1 || x <= x2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (y = r.Start.Y; y <= r.End.Y; y++)
|
||||
{
|
||||
if (y >= y1 || y <= y2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point3D> GetBorder(this Rectangle3D r)
|
||||
{
|
||||
return GetBorder(r, 1);
|
||||
}
|
||||
|
||||
public static bool Intersects2D(this Rectangle3D r, Rectangle3D or)
|
||||
{
|
||||
return GetBorder2D(r).Any(GetBorder2D(or).Contains);
|
||||
}
|
||||
|
||||
public static bool Intersects(this Rectangle3D r, Rectangle3D or)
|
||||
{
|
||||
var minZL = Math.Min(r.Start.Z, r.End.Z);
|
||||
var maxZL = Math.Max(r.Start.Z, r.End.Z);
|
||||
|
||||
var minZR = Math.Min(or.Start.Z, or.End.Z);
|
||||
var maxZR = Math.Max(or.Start.Z, or.End.Z);
|
||||
|
||||
if (minZL > maxZR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maxZL < minZR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetBorder2D(r).Union(GetBorder2D(or)).GroupBy(p => p).Any(g => g.Count() > 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
618
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RegionExt.cs
Normal file
618
Scripts/SubSystem/VitaNex/Core/Extensions/Server/RegionExt.cs
Normal file
@@ -0,0 +1,618 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#if ServUO58
|
||||
#define ServUOX
|
||||
#endif
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using VitaNex;
|
||||
using VitaNex.Crypto;
|
||||
using VitaNex.FX;
|
||||
using VitaNex.Network;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class RegionExtUtility
|
||||
{
|
||||
public class RegionSerial : CryptoHashCode
|
||||
{
|
||||
public override string Value => base.Value.Replace("-", String.Empty);
|
||||
|
||||
public RegionSerial(Region r)
|
||||
: base(
|
||||
CryptoHashType.MD5,
|
||||
r.GetType().FullName + r.Map.Name + r.Name + r.Area.GetBoundsHashCode() + TimeStamp.UtcNow.Stamp +
|
||||
Utility.RandomDouble())
|
||||
{ }
|
||||
|
||||
public RegionSerial(GenericReader reader)
|
||||
: base(reader)
|
||||
{ }
|
||||
}
|
||||
|
||||
public class PreviewRegion : Region, IEquatable<Region>
|
||||
{
|
||||
private static ulong _UID;
|
||||
|
||||
public RegionSerial Serial { get; private set; }
|
||||
|
||||
public PollTimer Timer { get; private set; }
|
||||
public EffectInfo[] Effects { get; private set; }
|
||||
|
||||
public DateTime Expire { get; set; }
|
||||
public int EffectID { get; set; }
|
||||
public int EffectHue { get; set; }
|
||||
public EffectRender EffectRender { get; set; }
|
||||
|
||||
public PreviewRegion(Region r)
|
||||
: this(r.Name, r.Map, r.Area)
|
||||
{
|
||||
Serial = GetSerial(r);
|
||||
}
|
||||
|
||||
public PreviewRegion(string name, Map map, params Rectangle2D[] area)
|
||||
: base(name + " " + _UID++, map, null, area)
|
||||
{
|
||||
Serial = new RegionSerial(this);
|
||||
EnsureDefaults();
|
||||
}
|
||||
|
||||
public PreviewRegion(string name, Map map, params Rectangle3D[] area)
|
||||
: base(name + " " + _UID++, map, null, area)
|
||||
{
|
||||
Serial = new RegionSerial(this);
|
||||
EnsureDefaults();
|
||||
}
|
||||
|
||||
public void EnsureDefaults()
|
||||
{
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
EffectID = 1801;
|
||||
EffectHue = 85;
|
||||
EffectRender = EffectRender.ShadowOutline;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
Register();
|
||||
}
|
||||
|
||||
public override void OnRegister()
|
||||
{
|
||||
base.OnRegister();
|
||||
|
||||
Expire = DateTime.UtcNow.AddSeconds(300.0);
|
||||
|
||||
if (Effects == null)
|
||||
{
|
||||
var effects = new EffectInfo[Area.Length][,];
|
||||
|
||||
effects.SetAll(i => new EffectInfo[Area[i].Width, Area[i].Height]);
|
||||
|
||||
for (var index = 0; index < Area.Length; index++)
|
||||
{
|
||||
var b = Area[index];
|
||||
|
||||
var xSpacing = Math.Max(1, Math.Min(16, b.Width / 8));
|
||||
var ySpacing = Math.Max(1, Math.Min(16, b.Height / 8));
|
||||
|
||||
var minX = Math.Min(b.Start.X, b.End.X);
|
||||
var maxX = Math.Max(b.Start.X, b.End.X);
|
||||
|
||||
var minY = Math.Min(b.Start.Y, b.End.Y);
|
||||
var maxY = Math.Max(b.Start.Y, b.End.Y);
|
||||
|
||||
Parallel.For(
|
||||
minX,
|
||||
maxX,
|
||||
x => Parallel.For(
|
||||
minY,
|
||||
maxY,
|
||||
y =>
|
||||
{
|
||||
if (x != b.Start.X && x != b.End.X - 1 && x % xSpacing != 0 //
|
||||
&& y != b.Start.Y && y != b.End.Y - 1 && y % ySpacing != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var idxX = x - minX;
|
||||
var idxY = y - minY;
|
||||
|
||||
effects[index][idxX, idxY] = new EffectInfo(
|
||||
new Point3D(x, y, 0),
|
||||
Map,
|
||||
EffectID,
|
||||
EffectHue,
|
||||
1,
|
||||
25,
|
||||
EffectRender);
|
||||
}));
|
||||
}
|
||||
|
||||
Effects = effects.SelectMany(list => list.OfType<EffectInfo>()).ToArray();
|
||||
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.SetSource(e.Source.ToPoint3D(e.Source.GetAverageZ(e.Map)));
|
||||
}
|
||||
}
|
||||
|
||||
if (Timer == null)
|
||||
{
|
||||
Timer = PollTimer.FromSeconds(
|
||||
1.0,
|
||||
() =>
|
||||
{
|
||||
if (DateTime.UtcNow > Expire)
|
||||
{
|
||||
Unregister();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.Send();
|
||||
}
|
||||
},
|
||||
() => Registered);
|
||||
}
|
||||
else
|
||||
{
|
||||
Timer.Running = true;
|
||||
}
|
||||
|
||||
_Previews.Update(Serial, this);
|
||||
}
|
||||
|
||||
public override void OnUnregister()
|
||||
{
|
||||
base.OnUnregister();
|
||||
|
||||
if (Timer != null)
|
||||
{
|
||||
Timer.Running = false;
|
||||
Timer = null;
|
||||
}
|
||||
|
||||
if (Effects != null)
|
||||
{
|
||||
foreach (var e in Effects)
|
||||
{
|
||||
e.Dispose();
|
||||
}
|
||||
|
||||
Effects.SetAll(i => null);
|
||||
Effects = null;
|
||||
}
|
||||
|
||||
Expire = DateTime.UtcNow;
|
||||
|
||||
_Previews.Remove(Serial);
|
||||
}
|
||||
|
||||
public bool Equals(Region other)
|
||||
{
|
||||
return !ReferenceEquals(other, null) && Serial.Equals(GetSerial(other));
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<RegionSerial, Region> _Regions;
|
||||
private static readonly Dictionary<RegionSerial, PreviewRegion> _Previews;
|
||||
|
||||
static RegionExtUtility()
|
||||
{
|
||||
_Regions = new Dictionary<RegionSerial, Region>();
|
||||
_Previews = new Dictionary<RegionSerial, PreviewRegion>();
|
||||
}
|
||||
|
||||
public static RegionSerial GetSerial(this Region r)
|
||||
{
|
||||
if (r == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
return ((PreviewRegion)r).Serial;
|
||||
}
|
||||
|
||||
lock (_Regions)
|
||||
{
|
||||
if (_Regions.ContainsValue(r))
|
||||
{
|
||||
return _Regions.GetKey(r);
|
||||
}
|
||||
|
||||
var s = new RegionSerial(r);
|
||||
|
||||
_Regions.Update(s, r);
|
||||
|
||||
//Console.WriteLine("Region Serial: ('{0}', '{1}', '{2}') = {3}", r.GetType().Name, r.Map, r.Name, s.ValueHash);
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
string name,
|
||||
Map map,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent,
|
||||
params Rectangle2D[] bounds)
|
||||
{
|
||||
return DisplayPreview(new PreviewRegion(name, map, bounds), hue, effect, render);
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
string name,
|
||||
Map map,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent,
|
||||
params Rectangle3D[] bounds)
|
||||
{
|
||||
return DisplayPreview(new PreviewRegion(name, map, bounds), hue, effect, render);
|
||||
}
|
||||
|
||||
public static PreviewRegion DisplayPreview(
|
||||
this Region r,
|
||||
int hue = 85,
|
||||
int effect = 1801,
|
||||
EffectRender render = EffectRender.SemiTransparent)
|
||||
{
|
||||
if (r == null || r.Area == null || r.Area.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hue < 0)
|
||||
{
|
||||
hue = 0;
|
||||
}
|
||||
|
||||
if (effect <= 0)
|
||||
{
|
||||
effect = 1801;
|
||||
}
|
||||
|
||||
PreviewRegion pr;
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
pr = (PreviewRegion)r;
|
||||
pr.EffectID = effect;
|
||||
pr.EffectHue = hue;
|
||||
pr.EffectRender = render;
|
||||
pr.Register();
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
var s = GetSerial(r);
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_Previews.TryGetValue(s, out pr) && pr != null && pr.Area.GetBoundsHashCode() != r.Area.GetBoundsHashCode())
|
||||
{
|
||||
pr.Unregister();
|
||||
pr = null;
|
||||
}
|
||||
|
||||
if (pr == null)
|
||||
{
|
||||
pr = new PreviewRegion(r)
|
||||
{
|
||||
EffectHue = hue,
|
||||
EffectID = effect,
|
||||
EffectRender = render
|
||||
};
|
||||
}
|
||||
|
||||
pr.Register();
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
public static void ClearPreview(this Region r)
|
||||
{
|
||||
if (r == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PreviewRegion pr;
|
||||
|
||||
if (r is PreviewRegion)
|
||||
{
|
||||
pr = (PreviewRegion)r;
|
||||
pr.Unregister();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var s = GetSerial(r);
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_Previews.TryGetValue(s, out pr) && pr != null)
|
||||
{
|
||||
pr.Unregister();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Contains(this Sector s, Point3D p, Map m)
|
||||
{
|
||||
return s.Owner == m && s.Contains(p);
|
||||
}
|
||||
|
||||
public static bool Contains(this Region r, Point3D p, Map m)
|
||||
{
|
||||
return r.Map == m && r.Contains(p);
|
||||
}
|
||||
|
||||
#if ServUOX
|
||||
public static bool Contains(this Sector s, Point3D p)
|
||||
{
|
||||
foreach (var r in s.RegionRects.Values.SelectMany(o => o))
|
||||
{
|
||||
if (r.Contains(p))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
public static bool Contains(this RegionRect r, Point3D p, Map m)
|
||||
{
|
||||
return r.Region.Map == m && r.Contains(p);
|
||||
}
|
||||
|
||||
public static bool Contains(this Sector s, Point3D p)
|
||||
{
|
||||
foreach (var r in s.RegionRects)
|
||||
{
|
||||
if (r.Contains(p))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Contains(this RegionRect r, Point3D p)
|
||||
{
|
||||
return r.Rect.Contains(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static TRegion Create<TRegion>(params object[] args)
|
||||
where TRegion : Region
|
||||
{
|
||||
return Create(typeof(TRegion), args) as TRegion;
|
||||
}
|
||||
|
||||
public static Region Create(Type type, params object[] args)
|
||||
{
|
||||
return type.CreateInstanceSafe<Region>(args);
|
||||
}
|
||||
|
||||
public static TRegion Clone<TRegion>(this TRegion region, params object[] args)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (region == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var fields = region.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
var remove = new[]
|
||||
{
|
||||
"Serial",
|
||||
"Name",
|
||||
"Map",
|
||||
"Parent",
|
||||
"Area",
|
||||
"Sectors",
|
||||
"ChildLevel",
|
||||
"Registered"
|
||||
};
|
||||
|
||||
foreach (var entry in remove)
|
||||
{
|
||||
if (!fields.Remove("m_" + entry))
|
||||
{
|
||||
fields.Remove("_" + entry);
|
||||
}
|
||||
}
|
||||
|
||||
region.Unregister();
|
||||
|
||||
var reg = Create(region.GetType(), args) as TRegion;
|
||||
|
||||
if (reg != null)
|
||||
{
|
||||
fields.Serialize(reg);
|
||||
reg.Register();
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
#if ServUOX
|
||||
public static bool IsPartOf<TRegion>(Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null && region.IsPartOf<TRegion>();
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null ? region.GetRegion<TRegion>() : null;
|
||||
}
|
||||
#else
|
||||
public static bool IsPartOf<TRegion>(this Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null && region.IsPartOf(typeof(TRegion));
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Region region)
|
||||
where TRegion : Region
|
||||
{
|
||||
return region != null ? region.GetRegion(typeof(TRegion)) as TRegion : null;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Mobile m)
|
||||
where TRegion : Region
|
||||
{
|
||||
return m != null ? GetRegion<TRegion>(m.Region) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Mobile m, Type type)
|
||||
{
|
||||
return m != null && m.Region != null ? m.Region.GetRegion(type) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Mobile m, string name)
|
||||
{
|
||||
return m != null && m.Region != null ? m.Region.GetRegion(name) : null;
|
||||
}
|
||||
|
||||
public static bool InRegion<TRegion>(this Mobile m)
|
||||
where TRegion : Region
|
||||
{
|
||||
return m != null && GetRegion<TRegion>(m.Region) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, Type type)
|
||||
{
|
||||
return m != null && GetRegion(m, type) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, string name)
|
||||
{
|
||||
return m != null && GetRegion(m, name) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Mobile m, Region r)
|
||||
{
|
||||
return m != null && m.Region != null && m.Region.IsPartOf(r);
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Region.Find(i.GetWorldLocation(), i.Map);
|
||||
}
|
||||
|
||||
public static TRegion GetRegion<TRegion>(this Item i)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? GetRegion<TRegion>(reg) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i, string name)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? reg.GetRegion(name) : null;
|
||||
}
|
||||
|
||||
public static Region GetRegion(this Item i, Type type)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null ? reg.GetRegion(type) : null;
|
||||
}
|
||||
|
||||
public static bool InRegion<TRegion>(this Item i)
|
||||
where TRegion : Region
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null && GetRegion<TRegion>(reg) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, Type type)
|
||||
{
|
||||
return i != null && GetRegion(i, type) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, string name)
|
||||
{
|
||||
return i != null && GetRegion(i, name) != null;
|
||||
}
|
||||
|
||||
public static bool InRegion(this Item i, Region r)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var reg = Region.Find(i.GetWorldLocation(), i.Map);
|
||||
|
||||
return reg != null && reg.IsPartOf(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
1830
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SerializeExt.cs
Normal file
1830
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SerializeExt.cs
Normal file
File diff suppressed because it is too large
Load Diff
431
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SkillExt.cs
Normal file
431
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SkillExt.cs
Normal file
@@ -0,0 +1,431 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum SkillCategory
|
||||
{
|
||||
None = 0,
|
||||
Combat,
|
||||
Healing,
|
||||
Magic,
|
||||
Bardic,
|
||||
Rogue,
|
||||
Knowledge,
|
||||
Craft,
|
||||
Harvest
|
||||
}
|
||||
|
||||
public enum SkillIcon
|
||||
{
|
||||
None = 1033,
|
||||
Combat = 1008,
|
||||
Healing = 1037,
|
||||
Magic = 1006,
|
||||
Bardic = 1031,
|
||||
Rogue = 1002,
|
||||
Knowledge = 1034,
|
||||
Craft = 1030,
|
||||
Harvest = 1036
|
||||
}
|
||||
|
||||
public static class SkillExtUtility
|
||||
{
|
||||
public static readonly SkillName[] EmptySkills = new SkillName[0];
|
||||
|
||||
public static readonly SkillName[] AllSkills = default(SkillName).GetValues<SkillName>();
|
||||
|
||||
public static readonly SkillName[] CombatSkills =
|
||||
{
|
||||
SkillName.Archery, SkillName.Fencing, SkillName.Focus, SkillName.Macing, SkillName.Parry, SkillName.Swords,
|
||||
SkillName.Tactics, SkillName.Wrestling, SkillName.Bushido
|
||||
};
|
||||
|
||||
public static readonly SkillName[] HealingSkills =
|
||||
{
|
||||
SkillName.Healing, SkillName.Veterinary
|
||||
};
|
||||
|
||||
public static readonly SkillName[] MagicSkills =
|
||||
{
|
||||
SkillName.EvalInt, SkillName.Inscribe, SkillName.Magery, SkillName.Meditation, SkillName.Chivalry,
|
||||
SkillName.Necromancy, SkillName.MagicResist, SkillName.Spellweaving, SkillName.SpiritSpeak
|
||||
};
|
||||
|
||||
public static readonly SkillName[] BardicSkills =
|
||||
{SkillName.Discordance, SkillName.Musicianship, SkillName.Peacemaking, SkillName.Provocation};
|
||||
|
||||
public static readonly SkillName[] RogueSkills =
|
||||
{
|
||||
SkillName.Begging, SkillName.DetectHidden, SkillName.Hiding, SkillName.Lockpicking, SkillName.Poisoning,
|
||||
SkillName.RemoveTrap, SkillName.Snooping, SkillName.Stealing, SkillName.Stealth, SkillName.Ninjitsu
|
||||
};
|
||||
|
||||
public static readonly SkillName[] KnowledgeSkills =
|
||||
{
|
||||
SkillName.Anatomy, SkillName.AnimalLore, SkillName.AnimalTaming, SkillName.ArmsLore, SkillName.Camping,
|
||||
SkillName.Forensics, SkillName.Herding, SkillName.ItemID, SkillName.TasteID, SkillName.Tracking
|
||||
};
|
||||
|
||||
public static readonly SkillName[] CraftSkills =
|
||||
{
|
||||
SkillName.Alchemy, SkillName.Blacksmith, SkillName.Fletching, SkillName.Carpentry, SkillName.Cooking,
|
||||
SkillName.Cartography, SkillName.Tailoring, SkillName.Tinkering, SkillName.Imbuing
|
||||
};
|
||||
|
||||
public static readonly SkillName[] HarvestSkills =
|
||||
{
|
||||
SkillName.Fishing, SkillName.Mining, SkillName.Lumberjacking
|
||||
};
|
||||
|
||||
public static readonly SkillCategory[] Categories =
|
||||
{
|
||||
SkillCategory.Combat, SkillCategory.Healing, SkillCategory.Magic, SkillCategory.Bardic, SkillCategory.Rogue,
|
||||
SkillCategory.Knowledge, SkillCategory.Craft, SkillCategory.Harvest
|
||||
};
|
||||
|
||||
public static readonly SkillIcon[] Icons =
|
||||
{
|
||||
SkillIcon.None, SkillIcon.Combat, SkillIcon.Healing, SkillIcon.Magic, SkillIcon.Bardic, SkillIcon.Rogue,
|
||||
SkillIcon.Knowledge, SkillIcon.Craft, SkillIcon.Harvest
|
||||
};
|
||||
|
||||
public static IEnumerable<Skill> OfExpansion(this Skills skills)
|
||||
{
|
||||
return OfExpansion(skills.Select(sk => sk.SkillName)).Select(sk => skills[sk]);
|
||||
}
|
||||
|
||||
public static IEnumerable<Skill> OfExpansion(this Skills skills, Expansion ex)
|
||||
{
|
||||
return OfExpansion(skills.Select(sk => sk.SkillName), ex).Select(sk => skills[sk]);
|
||||
}
|
||||
|
||||
public static IEnumerable<SkillName> OfExpansion(this IEnumerable<SkillName> skills)
|
||||
{
|
||||
return OfExpansion(skills, Core.Expansion);
|
||||
}
|
||||
|
||||
public static IEnumerable<SkillName> OfExpansion(this IEnumerable<SkillName> skills, Expansion ex)
|
||||
{
|
||||
foreach (var sk in skills)
|
||||
{
|
||||
switch (sk)
|
||||
{
|
||||
case SkillName.Chivalry:
|
||||
case SkillName.Focus:
|
||||
case SkillName.Necromancy:
|
||||
case SkillName.SpiritSpeak:
|
||||
{
|
||||
if (ex >= Expansion.AOS)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Bushido:
|
||||
case SkillName.Ninjitsu:
|
||||
{
|
||||
if (ex >= Expansion.SE)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Spellweaving:
|
||||
{
|
||||
if (ex >= Expansion.ML)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SkillName.Imbuing:
|
||||
case SkillName.Throwing:
|
||||
case SkillName.Mysticism:
|
||||
{
|
||||
if (ex >= Expansion.SA)
|
||||
{
|
||||
yield return sk;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
yield return sk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SkillName[] GetSkills(this SkillCategory cat)
|
||||
{
|
||||
switch (cat)
|
||||
{
|
||||
case SkillCategory.Combat:
|
||||
return CombatSkills;
|
||||
case SkillCategory.Healing:
|
||||
return HealingSkills;
|
||||
case SkillCategory.Magic:
|
||||
return MagicSkills;
|
||||
case SkillCategory.Bardic:
|
||||
return BardicSkills;
|
||||
case SkillCategory.Rogue:
|
||||
return RogueSkills;
|
||||
case SkillCategory.Knowledge:
|
||||
return KnowledgeSkills;
|
||||
case SkillCategory.Craft:
|
||||
return CraftSkills;
|
||||
case SkillCategory.Harvest:
|
||||
return HarvestSkills;
|
||||
}
|
||||
|
||||
return EmptySkills;
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillCategory cat)
|
||||
{
|
||||
return Icons[(int)cat];
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillInfo info)
|
||||
{
|
||||
return GetIcon((SkillName)info.SkillID);
|
||||
}
|
||||
|
||||
public static SkillIcon GetIcon(this SkillName skill)
|
||||
{
|
||||
return GetIcon(GetCategory(skill));
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillInfo info)
|
||||
{
|
||||
return (int)GetIcon(info);
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillCategory cat)
|
||||
{
|
||||
return (int)GetIcon(cat);
|
||||
}
|
||||
|
||||
public static int GetIconID(this SkillName skill)
|
||||
{
|
||||
return (int)GetIcon(skill);
|
||||
}
|
||||
|
||||
public static bool IsLocked(this Skill skill, SkillLock locked)
|
||||
{
|
||||
return skill.Lock == locked;
|
||||
}
|
||||
|
||||
public static bool IsCapped(this Skill skill)
|
||||
{
|
||||
return skill.Base >= skill.Cap;
|
||||
}
|
||||
|
||||
public static bool IsZero(this Skill skill)
|
||||
{
|
||||
return skill.Base <= 0;
|
||||
}
|
||||
|
||||
public static bool IsZeroOrCapped(this Skill skill)
|
||||
{
|
||||
return IsZero(skill) || IsCapped(skill);
|
||||
}
|
||||
|
||||
public static bool WillCap(this Skill skill, double value, bool isEqual = true)
|
||||
{
|
||||
return isEqual ? (skill.Base + value >= skill.Cap) : (skill.Base + value > skill.Cap);
|
||||
}
|
||||
|
||||
public static bool WillZero(this Skill skill, double value, bool isEqual = true)
|
||||
{
|
||||
return isEqual ? (skill.Base - value <= 0) : (skill.Base - value < 0);
|
||||
}
|
||||
|
||||
public static bool DecreaseBase(this Skill skill, double value, bool ignoreZero = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Min(skill.Base, value);
|
||||
}
|
||||
|
||||
if (ignoreZero || (!IsZero(skill) && !WillZero(skill, value, false)))
|
||||
{
|
||||
skill.Base -= value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IncreaseBase(this Skill skill, double value, bool ignoreCap = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Min(skill.Cap - skill.Base, value);
|
||||
}
|
||||
|
||||
if (ignoreCap || (!IsCapped(skill) && !WillCap(skill, value, false)))
|
||||
{
|
||||
skill.Base += value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetBase(this Skill skill, double value, bool ignoreLimits = false, bool trim = true)
|
||||
{
|
||||
if (trim)
|
||||
{
|
||||
value = Math.Max(0, Math.Min(skill.Cap, value));
|
||||
}
|
||||
|
||||
if (ignoreLimits || (value < skill.Base && !IsZero(skill) && !WillZero(skill, skill.Base - value, false)) ||
|
||||
(value > skill.Base && !IsCapped(skill) && !WillCap(skill, value - skill.Base, false)))
|
||||
{
|
||||
skill.Base = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void DecreaseCap(this Skill skill, double value)
|
||||
{
|
||||
SetCap(skill, skill.Cap - value);
|
||||
}
|
||||
|
||||
public static void IncreaseCap(this Skill skill, double value)
|
||||
{
|
||||
SetCap(skill, skill.Cap + value);
|
||||
}
|
||||
|
||||
public static void SetCap(this Skill skill, double value)
|
||||
{
|
||||
skill.Cap = Math.Max(0, value);
|
||||
Normalize(skill);
|
||||
}
|
||||
|
||||
public static void Normalize(this Skill skill)
|
||||
{
|
||||
if (IsCapped(skill))
|
||||
{
|
||||
skill.BaseFixedPoint = skill.CapFixedPoint;
|
||||
}
|
||||
|
||||
if (IsZero(skill))
|
||||
{
|
||||
skill.BaseFixedPoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetName(this SkillName skill)
|
||||
{
|
||||
return SkillInfo.Table[(int)skill].Name;
|
||||
}
|
||||
|
||||
public static bool CheckCategory(this SkillName skill, SkillCategory category)
|
||||
{
|
||||
return GetCategory(skill) == category;
|
||||
}
|
||||
|
||||
public static SkillCategory GetCategory(this SkillName skill)
|
||||
{
|
||||
if (IsCombat(skill))
|
||||
{
|
||||
return SkillCategory.Combat;
|
||||
}
|
||||
|
||||
if (IsHealing(skill))
|
||||
{
|
||||
return SkillCategory.Healing;
|
||||
}
|
||||
|
||||
if (IsMagic(skill))
|
||||
{
|
||||
return SkillCategory.Magic;
|
||||
}
|
||||
|
||||
if (IsBardic(skill))
|
||||
{
|
||||
return SkillCategory.Bardic;
|
||||
}
|
||||
|
||||
if (IsRogue(skill))
|
||||
{
|
||||
return SkillCategory.Rogue;
|
||||
}
|
||||
|
||||
if (IsKnowledge(skill))
|
||||
{
|
||||
return SkillCategory.Knowledge;
|
||||
}
|
||||
|
||||
if (IsCraft(skill))
|
||||
{
|
||||
return SkillCategory.Craft;
|
||||
}
|
||||
|
||||
if (IsHarvest(skill))
|
||||
{
|
||||
return SkillCategory.Harvest;
|
||||
}
|
||||
|
||||
return SkillCategory.None;
|
||||
}
|
||||
|
||||
public static bool IsCombat(this SkillName skill)
|
||||
{
|
||||
return CombatSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsHealing(this SkillName skill)
|
||||
{
|
||||
return HealingSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsMagic(this SkillName skill)
|
||||
{
|
||||
return MagicSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsBardic(this SkillName skill)
|
||||
{
|
||||
return BardicSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsRogue(this SkillName skill)
|
||||
{
|
||||
return RogueSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsKnowledge(this SkillName skill)
|
||||
{
|
||||
return KnowledgeSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsCraft(this SkillName skill)
|
||||
{
|
||||
return CraftSkills.Contains(skill);
|
||||
}
|
||||
|
||||
public static bool IsHarvest(this SkillName skill)
|
||||
{
|
||||
return HarvestSkills.Contains(skill);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SpellExt.cs
Normal file
27
Scripts/SubSystem/VitaNex/Core/Extensions/Server/SpellExt.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
#region Header
|
||||
// _,-'/-'/
|
||||
// . __,-; ,'( '/
|
||||
// \. `-.__`-._`:_,-._ _ , . ``
|
||||
// `:-._,------' ` _,`--` -: `_ , ` ,' :
|
||||
// `---..__,,--' (C) 2023 ` -'. -'
|
||||
// # Vita-Nex [http://core.vita-nex.com] #
|
||||
// {o)xxx|===============- # -===============|xxx(o}
|
||||
// # #
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using Server.Spells;
|
||||
|
||||
using VitaNex;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class SpellExtUtility
|
||||
{
|
||||
public static SpellInfo GetSpellInfo(this ISpell s)
|
||||
{
|
||||
return SpellUtility.GetSpellInfo(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user