Some cleanup of contains keys and try get values (#246)

This commit is contained in:
Kamron Batman 2020-09-13 20:20:44 -07:00 committed by GitHub
parent 9cbb0cfd23
commit a236617ad9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
69 changed files with 3508 additions and 350 deletions

View file

@ -31,11 +31,11 @@ namespace Server.ContextMenus
if (target is Mobile mobile)
{
mobile.GetContextMenuEntries(@from, list);
mobile.GetContextMenuEntries(from, list);
}
else if (target is Item item)
{
item.GetContextMenuEntries(@from, list);
item.GetContextMenuEntries(from, list);
}
Entries = list.ToArray();

View file

@ -570,7 +570,7 @@ namespace Server.Items
for (var i = 0; i < stackItems.Count; i++)
{
stackItems[i].m_StackItem.StackWith(@from, stackItems[i].m_DropItem, false);
stackItems[i].m_StackItem.StackWith(from, stackItems[i].m_DropItem, false);
}
return true;
@ -674,7 +674,7 @@ namespace Server.Items
if (CheckContentDisplay(from))
{
LabelTo(@from, "({0} item{2}, {1} stones)", TotalItems, TotalWeight, TotalItems != 1 ? "s" : string.Empty);
LabelTo(from, "({0} item{2}, {1} stones)", TotalItems, TotalWeight, TotalItems != 1 ? "s" : string.Empty);
}
// LabelTo( from, 1050044, String.Format( "{0}\t{1}", TotalItems.ToString(), TotalWeight.ToString() ) );
@ -824,11 +824,11 @@ namespace Server.Items
{
if (from.AccessLevel > AccessLevel.Player || from.InRange(GetWorldLocation(), 2))
{
DisplayTo(@from);
DisplayTo(from);
}
else
{
@from.SendLocalizedMessage(500446); // That is too far away.
from.SendLocalizedMessage(500446); // That is too far away.
}
}

View file

@ -2254,11 +2254,11 @@ namespace Server
{
if (m_Parent is Item parentItem)
{
parentItem.GetChildContextMenuEntries(@from, list, item);
parentItem.GetChildContextMenuEntries(from, list, item);
}
else if (m_Parent is Mobile parentMobile)
{
parentMobile.GetChildContextMenuEntries(@from, list, item);
parentMobile.GetChildContextMenuEntries(from, list, item);
}
}
@ -2266,11 +2266,11 @@ namespace Server
{
if (m_Parent is Item item)
{
item.GetChildContextMenuEntries(@from, list, this);
item.GetChildContextMenuEntries(from, list, this);
}
else if (m_Parent is Mobile mobile)
{
mobile.GetChildContextMenuEntries(@from, list, this);
mobile.GetChildContextMenuEntries(from, list, this);
}
}
@ -3241,7 +3241,7 @@ namespace Server
// OSI sends 1074769, bug!
if (QuestItem)
{
@from.SendLocalizedMessage(
from.SendLocalizedMessage(
1049343
); // You can only drop quest items into the top-most level of your backpack while you still need them for your quest.
}
@ -3667,7 +3667,7 @@ namespace Server
if (target is Container container && p.m_X != -1 && p.m_Y != -1)
{
return OnDroppedInto(@from, container, p);
return OnDroppedInto(from, container, p);
}
return OnDroppedOnto(from, target);
@ -4212,11 +4212,11 @@ namespace Server
{
if (m_Parent is Item parentItem)
{
parentItem.OnItemUsed(@from, item);
parentItem.OnItemUsed(from, item);
}
else if (m_Parent is Mobile parentMobile)
{
parentMobile.OnItemUsed(@from, item);
parentMobile.OnItemUsed(from, item);
}
}
@ -4234,11 +4234,11 @@ namespace Server
{
if (m_Parent is Item parentItem)
{
parentItem.OnItemLifted(@from, item);
parentItem.OnItemLifted(from, item);
}
else if (m_Parent is Mobile parentMobile)
{
parentMobile.OnItemLifted(@from, item);
parentMobile.OnItemLifted(from, item);
}
}
@ -4261,7 +4261,7 @@ namespace Server
{
if (m_Parent is Item parentItem)
{
parentItem.OnSingleClickContained(@from, item);
parentItem.OnSingleClickContained(from, item);
}
}
@ -4271,7 +4271,7 @@ namespace Server
if (opl.Header > 0)
{
@from.Send(
from.Send(
new MessageLocalized(
Serial,
m_ItemID,
@ -4295,7 +4295,7 @@ namespace Server
if (DisplayLootType)
{
LabelLootTypeTo(@from);
LabelLootTypeTo(from);
}
var ns = from.NetState;

View file

@ -3758,7 +3758,7 @@ namespace Server
}
else
{
hue = Notoriety.GetHue(Notoriety.Compute(@from, this));
hue = Notoriety.GetHue(Notoriety.Compute(from, this));
}
from.Send(new MessageLocalized(Serial, Body, MessageType.Label, hue, 3, opl.Header, Name, opl.HeaderArgs));
@ -5571,7 +5571,7 @@ namespace Server
{
if (item.QuestItem)
{
@from.SendLocalizedMessage(1074868); // Stacks of quest items cannot be unstacked.
from.SendLocalizedMessage(1074868); // Stacks of quest items cannot be unstacked.
}
reject = LRReason.CannotLift;
@ -5634,7 +5634,7 @@ namespace Server
foreach (var ns in eable)
{
if (ns.Mobile != @from && ns.Mobile.CanSee(@from) && ns.Mobile.InLOS(@from) &&
if (ns.Mobile != from && ns.Mobile.CanSee(from) && ns.Mobile.InLOS(from) &&
ns.Mobile.CanSee(root))
{
if (p == null)
@ -5645,7 +5645,7 @@ namespace Server
map
);
p = Packet.Acquire(new DragEffect(src, @from, item.ItemID, item.Hue, amount));
p = Packet.Acquire(new DragEffect(src, from, item.ItemID, item.Hue, amount));
}
ns.Send(p);
@ -5671,7 +5671,7 @@ namespace Server
if (liftSound != -1)
{
@from.Send(new PlaySound(liftSound, @from));
from.Send(new PlaySound(liftSound, from));
}
from.NextActionTime = Core.TickCount + ActionDelay;
@ -5845,7 +5845,7 @@ namespace Server
if (to == null || !item.DropToItem(from, to, loc))
{
item.Bounce(@from);
item.Bounce(from);
}
else
{
@ -5882,7 +5882,7 @@ namespace Server
if (!item.DropToWorld(from, loc))
{
item.Bounce(@from);
item.Bounce(from);
}
else
{
@ -5919,7 +5919,7 @@ namespace Server
if (to == null || !item.DropToMobile(from, to, loc))
{
item.Bounce(@from);
item.Bounce(from);
}
else
{
@ -6443,7 +6443,7 @@ namespace Server
if (from != null)
{
RegisterDamage(amount, @from);
RegisterDamage(amount, from);
}
DisruptiveAction();
@ -6473,7 +6473,7 @@ namespace Server
if (informMount)
{
Mount?.OnRiderDamaged(amount, @from, newHits < 0);
Mount?.OnRiderDamaged(amount, from, newHits < 0);
}
if (newHits < 0)
@ -8624,7 +8624,7 @@ namespace Server
{
if (from.Map == Map && Utility.InUpdateRange(this, from) && from.CanSee(this))
{
@from.Send(new MobileStatus(@from, this, m_NetState));
from.Send(new MobileStatus(from, this, m_NetState));
}
if (from == this)
@ -8634,7 +8634,7 @@ namespace Server
if (Party is IParty ip)
{
ip.OnStatsQuery(@from, this);
ip.OnStatsQuery(from, this);
}
}
@ -8708,7 +8708,7 @@ namespace Server
}
else
{
hue = Notoriety.GetHue(Notoriety.Compute(@from, this));
hue = Notoriety.GetHue(Notoriety.Compute(from, this));
}
var name = Name ?? string.Empty;
@ -10143,7 +10143,7 @@ namespace Server
if (CanPaperdollBeOpenedBy(from))
{
DisplayPaperdollTo(@from);
DisplayPaperdollTo(from);
}
}
@ -10175,7 +10175,7 @@ namespace Server
{
if (CanPaperdollBeOpenedBy(from))
{
DisplayPaperdollTo(@from);
DisplayPaperdollTo(from);
}
}
@ -10590,11 +10590,11 @@ namespace Server
{
if (m_CallbackHandlesCancel && m_Callback != null)
{
m_Callback(@from, "");
m_Callback(from, "");
}
else
{
m_CancelCallback?.Invoke(@from, "");
m_CancelCallback?.Invoke(from, "");
}
}
}

View file

@ -433,7 +433,7 @@ namespace Server.Network
if (targ != null)
{
EventSink.InvokeRenameRequest(@from, targ, pvSrc.ReadStringSafe());
EventSink.InvokeRenameRequest(from, targ, pvSrc.ReadStringSafe());
}
}
@ -631,7 +631,7 @@ namespace Server.Network
if (item != null && from.Map == item.Map && Utility.InUpdateRange(item.GetWorldLocation(), from.Location) &&
from.CanSee(item))
{
item.OnHelpRequest(@from);
item.OnHelpRequest(from);
}
}
else if (serial.IsMobile)
@ -668,7 +668,7 @@ namespace Server.Network
if (m != null)
{
@from.Attack(m);
from.Attack(m);
}
}
@ -827,11 +827,11 @@ namespace Server.Network
if (type == 0)
{
p.OnCancel(@from);
p.OnCancel(from);
}
else
{
p.OnResponse(@from, text);
p.OnResponse(from, text);
}
}
}
@ -858,11 +858,11 @@ namespace Server.Network
if (type == 0)
{
p.OnCancel(@from);
p.OnCancel(from);
}
else
{
p.OnResponse(@from, text);
p.OnResponse(from, text);
}
}
}
@ -970,7 +970,7 @@ namespace Server.Network
if (!to.AllowEquipFrom(from) || !to.EquipItem(item))
{
item.Bounce(@from);
item.Bounce(from);
}
item.ClearBounce();
@ -1458,7 +1458,7 @@ namespace Server.Network
if (m?.Deleted == false)
{
@from.Use(m);
from.Use(m);
}
}
else if (s.IsItem)
@ -1467,7 +1467,7 @@ namespace Server.Network
if (item?.Deleted == false)
{
@from.Use(item);
from.Use(item);
}
}
}
@ -1500,7 +1500,7 @@ namespace Server.Network
{
if (from.Region.OnSingleClick(from, m))
{
m.OnSingleClick(@from);
m.OnSingleClick(from);
}
}
}
@ -1520,7 +1520,7 @@ namespace Server.Network
{
if (item.Parent is Item parentItem)
{
parentItem.OnSingleClickContained(@from, item);
parentItem.OnSingleClickContained(from, item);
}
item.OnSingleClick(from);
@ -1581,7 +1581,7 @@ namespace Server.Network
if (from != null && ok && from.Alive && from.Body.IsHuman && !from.Mounted)
{
@from.Animate(action, 7, 1, true, false, 0);
from.Animate(action, 7, 1, true, false, 0);
}
}
@ -1711,7 +1711,7 @@ namespace Server.Network
if (m != null && from.CanSee(m) && Utility.InUpdateRange(from, m))
{
m.SendPropertiesTo(@from);
m.SendPropertiesTo(from);
}
}
else if (s.IsItem)
@ -1721,7 +1721,7 @@ namespace Server.Network
if (item?.Deleted == false && from.CanSee(item) &&
Utility.InUpdateRange(from.Location, item.GetWorldLocation()))
{
item.SendPropertiesTo(@from);
item.SendPropertiesTo(from);
}
}
}
@ -1744,7 +1744,7 @@ namespace Server.Network
if (m != null && from.CanSee(m) && Utility.InUpdateRange(from, m))
{
m.SendPropertiesTo(@from);
m.SendPropertiesTo(from);
}
}
else if (s.IsItem)
@ -1754,7 +1754,7 @@ namespace Server.Network
if (item?.Deleted == false && from.CanSee(item) &&
Utility.InUpdateRange(from.Location, item.GetWorldLocation()))
{
item.SendPropertiesTo(@from);
item.SendPropertiesTo(from);
}
}
}
@ -2031,12 +2031,12 @@ namespace Server.Network
{
case 0x04: // Stats
{
m.OnStatsQuery(@from);
m.OnStatsQuery(from);
break;
}
case 0x05:
{
m.OnSkillsQuery(@from);
m.OnSkillsQuery(from);
break;
}
default:

View file

@ -25,22 +25,22 @@ namespace Server
if (from6017)
{
@from.Send(new SecureTradeEquip6017(To.Container, to));
from.Send(new SecureTradeEquip6017(To.Container, to));
}
else
{
@from.Send(new SecureTradeEquip(To.Container, to));
from.Send(new SecureTradeEquip(To.Container, to));
}
from.Send(new UpdateSecureTrade(From.Container, false, false));
if (from6017)
{
@from.Send(new SecureTradeEquip6017(From.Container, @from));
from.Send(new SecureTradeEquip6017(From.Container, from));
}
else
{
@from.Send(new SecureTradeEquip(From.Container, @from));
from.Send(new SecureTradeEquip(From.Container, from));
}
from.Send(new DisplaySecureTrade(to, From.Container, To.Container, to.Name));
@ -48,12 +48,12 @@ namespace Server
if (from.Account != null && from704565)
{
@from.Send(
from.Send(
new UpdateSecureTrade(
From.Container,
TradeFlag.UpdateLedger,
@from.Account.TotalGold,
@from.Account.TotalPlat
from.Account.TotalGold,
from.Account.TotalPlat
)
);
}
@ -63,11 +63,11 @@ namespace Server
if (to6017)
{
to.Send(new SecureTradeEquip6017(From.Container, @from));
to.Send(new SecureTradeEquip6017(From.Container, from));
}
else
{
to.Send(new SecureTradeEquip(From.Container, @from));
to.Send(new SecureTradeEquip(From.Container, from));
}
to.Send(new UpdateSecureTrade(To.Container, false, false));

View file

@ -168,31 +168,31 @@ namespace Server.Targeting
{
if (!from.CanSee(targeted))
{
OnCantSeeTarget(@from, targeted);
OnCantSeeTarget(from, targeted);
}
else if (CheckLOS && !from.InLOS(targeted))
{
OnTargetOutOfLOS(@from, targeted);
OnTargetOutOfLOS(from, targeted);
}
else if (item?.InSecureTrade == true)
{
OnTargetInSecureTrade(@from, targeted);
OnTargetInSecureTrade(from, targeted);
}
else if (item?.IsAccessibleTo(from) == false)
{
OnTargetNotAccessible(@from, targeted);
OnTargetNotAccessible(from, targeted);
}
else if (item?.CheckTarget(from, this, targeted) == false)
{
OnTargetUntargetable(@from, targeted);
OnTargetUntargetable(from, targeted);
}
else if (mobile?.CheckTarget(from, this, mobile) == false)
{
OnTargetUntargetable(@from, mobile);
OnTargetUntargetable(from, mobile);
}
else if (from.Region.OnTarget(from, this, targeted))
{
OnTarget(@from, targeted);
OnTarget(from, targeted);
}
}

View file

@ -63,7 +63,9 @@ namespace Server.Accounting
// Automatically upgrade plain passwords to current algorithm.
if (!upgraded)
{
SetPassword(Utility.GetText(node["password"], null));
}
}
else
{
@ -85,19 +87,31 @@ namespace Server.Accounting
IPRestrictions = LoadAccessCheck(node);
for (var i = 0; i < m_Mobiles.Length; ++i)
{
if (m_Mobiles[i] != null)
{
m_Mobiles[i].Account = this;
}
}
var totalGameTime = Utility.GetXMLTimeSpan(Utility.GetText(node["totalGameTime"], null), TimeSpan.Zero);
if (totalGameTime == TimeSpan.Zero)
{
for (var i = 0; i < m_Mobiles.Length; i++)
{
if (m_Mobiles[i] is PlayerMobile m)
{
totalGameTime += m.GameTime;
}
}
}
m_TotalGameTime = totalGameTime;
if (Young)
{
CheckYoung();
}
Accounts.Add(this);
}
@ -148,15 +162,19 @@ namespace Server.Accounting
var isBanned = GetFlag(0);
if (!isBanned)
{
return false;
}
if (GetBanTags(out var banTime, out var banDuration))
{
if (banDuration != TimeSpan.MaxValue && DateTime.UtcNow >= banTime + banDuration)
{
SetUnspecifiedBan(null); // clear
Banned = false;
return false;
}
}
return true;
}
@ -197,7 +215,9 @@ namespace Server.Accounting
get
{
if (AccessLevel != AccessLevel.Player)
{
return false;
}
var inactiveLength = DateTime.UtcNow - LastLogin;
@ -214,8 +234,12 @@ namespace Server.Accounting
get
{
for (var i = 0; i < m_Mobiles.Length; i++)
{
if (m_Mobiles[i] is PlayerMobile m && m.NetState != null)
{
return m_TotalGameTime + (DateTime.UtcNow - m.SessionStart);
}
}
return m_TotalGameTime;
}
@ -231,12 +255,16 @@ namespace Server.Accounting
var m = this[i];
if (m == null)
{
continue;
}
var list = BaseHouse.GetHouses(m);
for (var j = 0; j < list.Count; ++j)
{
list[j].Delete();
}
m.Delete();
@ -245,7 +273,9 @@ namespace Server.Accounting
}
if (LoginIPs.Length != 0 && AccountHandler.IPTable.ContainsKey(LoginIPs[0]))
{
--AccountHandler.IPTable[LoginIPs[0]];
}
Accounts.Remove(Username);
}
@ -283,11 +313,15 @@ namespace Server.Accounting
var ok = AccountSecurity.GetPasswordProtection(m_PasswordAlgorithm).ValidatePassword(Password, phrase);
if (!ok)
{
return false;
}
// Upgrade the password protection in case we change the algorithm
if (m_PasswordAlgorithm != AccountSecurity.CurrentAlgorithm)
{
SetPassword(plainPassword);
}
return true;
}
@ -302,8 +336,12 @@ namespace Server.Accounting
var count = 0;
for (var i = 0; i < Length; i++)
{
if (this[i] != null)
{
count++;
}
}
return count;
}
@ -334,7 +372,9 @@ namespace Server.Accounting
var m = m_Mobiles[index];
if (m?.Deleted != true)
{
return m;
}
// This is the only place that clears a mobile for garbage collection
// outside of an entire account deletion.
@ -349,12 +389,16 @@ namespace Server.Accounting
if (index >= 0 && index < m_Mobiles.Length)
{
if (m_Mobiles[index] != null)
{
m_Mobiles[index].Account = null;
}
m_Mobiles[index] = value;
if (m_Mobiles[index] != null)
{
m_Mobiles[index].Account = this;
}
}
}
}
@ -387,7 +431,10 @@ namespace Server.Accounting
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
public bool DepositGold(int amount)
{
if (amount <= 0) return false;
if (amount <= 0)
{
return false;
}
var plat = Math.DivRem(amount, AccountGold.CurrencyThreshold, out var gold);
TotalPlat += plat;
@ -403,7 +450,10 @@ namespace Server.Accounting
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
public bool DepositPlat(int amount)
{
if (amount <= 0) return false;
if (amount <= 0)
{
return false;
}
TotalPlat += amount;
return true;
@ -418,8 +468,15 @@ namespace Server.Accounting
/// <returns>True if successful, false if balance was too low.</returns>
public bool WithdrawGold(int amount)
{
if (amount <= 0) return true;
if (amount > TotalGold) return false;
if (amount <= 0)
{
return true;
}
if (amount > TotalGold)
{
return false;
}
TotalGold -= amount;
@ -433,8 +490,15 @@ namespace Server.Accounting
/// <returns>True if successful, false if balance was too low.</returns>
public bool WithdrawPlat(int amount)
{
if (amount <= 0) return true;
if (amount > TotalPlat) return false;
if (amount <= 0)
{
return true;
}
if (amount > TotalPlat)
{
return false;
}
TotalPlat -= amount;
@ -464,9 +528,13 @@ namespace Server.Accounting
public void SetFlag(int index, bool value)
{
if (value)
{
Flags |= 1 << index;
}
else
{
Flags &= ~(1 << index);
}
}
/// <summary>
@ -488,12 +556,16 @@ namespace Server.Accounting
for (var i = Tags.Count - 1; i >= 0; --i)
{
if (i >= Tags.Count)
{
continue;
}
var tag = Tags[i];
if (tag.Name == name)
{
Tags.RemoveAt(i);
}
}
}
@ -529,7 +601,9 @@ namespace Server.Accounting
var tag = Tags[i];
if (tag.Name == name)
{
return tag.Value;
}
}
return null;
@ -543,19 +617,31 @@ namespace Server.Accounting
public void SetBanTags(Mobile from, DateTime banTime, TimeSpan banDuration)
{
if (from == null)
{
RemoveTag("BanDealer");
}
else
{
SetTag("BanDealer", from.ToString());
}
if (banTime == DateTime.MinValue)
{
RemoveTag("BanTime");
}
else
{
SetTag("BanTime", XmlConvert.ToString(banTime, XmlDateTimeSerializationMode.Utc));
}
if (banDuration == TimeSpan.Zero)
{
RemoveTag("BanDuration");
}
else
{
SetTag("BanDuration", banDuration.ToString());
}
}
public bool GetBanTags(out DateTime banTime, out TimeSpan banDuration)
@ -565,11 +651,17 @@ namespace Server.Accounting
banTime = Utility.GetXMLDateTime(GetTag("BanTime"), DateTime.MinValue);
if (tagDuration == "Infinite")
{
banDuration = TimeSpan.MaxValue;
}
else if (tagDuration != null)
{
banDuration = Utility.ToTimeSpan(tagDuration);
}
else
{
banDuration = TimeSpan.Zero;
}
return banTime != DateTime.MinValue && banDuration != TimeSpan.Zero;
}
@ -584,7 +676,9 @@ namespace Server.Accounting
private static void EventSink_Connected(Mobile m)
{
if (!(m.Account is Account acc))
{
return;
}
if (acc.Young && acc.m_YoungTimer == null)
{
@ -596,7 +690,9 @@ namespace Server.Accounting
private static void EventSink_Disconnected(Mobile m)
{
if (!(m.Account is Account acc))
{
return;
}
if (acc.m_YoungTimer != null)
{
@ -605,7 +701,9 @@ namespace Server.Accounting
}
if (!(m is PlayerMobile pm))
{
return;
}
acc.m_TotalGameTime += DateTime.UtcNow - pm.SessionStart;
}
@ -613,10 +711,14 @@ namespace Server.Accounting
private static void EventSink_Login(Mobile m)
{
if (!(m is PlayerMobile pm))
{
return;
}
if (!(m.Account is Account acc))
{
return;
}
if (pm.Young && acc.Young)
{
@ -636,6 +738,7 @@ namespace Server.Accounting
Young = false;
for (var i = 0; i < m_Mobiles.Length; i++)
{
if (m_Mobiles[i] is PlayerMobile m && m.Young)
{
m.Young = false;
@ -643,26 +746,34 @@ namespace Server.Accounting
if (m.NetState != null)
{
if (message > 0)
{
m.SendLocalizedMessage(message);
}
m.SendLocalizedMessage(
1019039
); // You are no longer considered a young player of Ultima Online, and are no longer subject to the limitations and benefits of being in that caste.
}
}
}
}
public void CheckYoung()
{
if (TotalGameTime >= YoungDuration)
{
RemoveYoungStatus(
1019038
); // You are old enough to be considered an adult, and have outgrown your status as a young player!
}
}
private bool UpgradePassword(string password, PasswordProtectionAlgorithm algorithm)
{
if (password == null || algorithm < m_PasswordAlgorithm) return false;
if (password == null || algorithm < m_PasswordAlgorithm)
{
return false;
}
m_PasswordAlgorithm = algorithm;
Password = password?.Replace("-", string.Empty);
@ -688,7 +799,9 @@ namespace Server.Accounting
var text = Utility.GetText(ip, null);
if (text != null)
{
list.Add(text);
}
}
stringList = list.ToArray();
@ -720,12 +833,16 @@ namespace Server.Accounting
count = 0;
foreach (XmlElement ip in addressList.GetElementsByTagName("ip"))
{
if (count < list.Length)
{
if (IPAddress.TryParse(Utility.GetText(ip, null), out var address))
{
list[count] = Utility.Intern(address);
count++;
}
}
}
if (count != list.Length)
{
@ -733,7 +850,9 @@ namespace Server.Accounting
list = new IPAddress[count];
for (var i = 0; i < count && i < old.Length; ++i)
{
list[i] = old[i];
}
}
}
else
@ -759,19 +878,25 @@ namespace Server.Accounting
// Above is legacy, no longer used
if (chars != null)
{
foreach (XmlElement ele in chars.GetElementsByTagName("char"))
{
try
{
var index = Utility.GetXMLInt32(Utility.GetAttribute(ele, "index", "0"), 0);
var serial = Utility.GetXMLUInt32(Utility.GetText(ele, "0"), 0);
if (index >= 0 && index < list.Length)
{
list[index] = World.FindMobile(serial);
}
}
catch
{
// ignored
}
}
}
return list;
}
@ -791,6 +916,7 @@ namespace Server.Accounting
list = new List<AccountComment>();
foreach (XmlElement comment in comments.GetElementsByTagName("comment"))
{
try
{
list.Add(new AccountComment(comment));
@ -799,6 +925,7 @@ namespace Server.Accounting
{
// ignored
}
}
}
return list;
@ -819,6 +946,7 @@ namespace Server.Accounting
list = new List<AccountTag>();
foreach (XmlElement tag in tags.GetElementsByTagName("tag"))
{
try
{
list.Add(new AccountTag(tag));
@ -827,6 +955,7 @@ namespace Server.Accounting
{
// ignored
}
}
}
return list;
@ -848,26 +977,36 @@ namespace Server.Accounting
var hasAccess = false;
if (m_AccessLevel >= level)
{
hasAccess = true;
}
else
{
for (var i = 0; !hasAccess && i < Length; ++i)
{
var m = this[i];
if (m?.AccessLevel >= level)
{
hasAccess = true;
}
}
}
Console.WriteLine("{0} {1}", hasAccess ? "yes" : "no", m_AccessLevel);
if (!hasAccess)
{
return false;
}
}
var accessAllowed = IPRestrictions.Length == 0 || IPLimiter.IsExempt(ipAddress);
for (var i = 0; !accessAllowed && i < IPRestrictions.Length; ++i)
{
accessAllowed = Utility.IPMatch(IPRestrictions[i], ipAddress);
}
return accessAllowed;
}
@ -878,35 +1017,44 @@ namespace Server.Accounting
/// <param name="ns">NetState instance to record.</param>
public void LogAccess(NetState ns)
{
if (ns != null) LogAccess(ns.Address);
if (ns != null)
{
LogAccess(ns.Address);
}
}
public void LogAccess(IPAddress ipAddress)
{
if (IPLimiter.IsExempt(ipAddress))
{
return;
}
if (LoginIPs.Length == 0)
{
if (AccountHandler.IPTable.ContainsKey(ipAddress))
AccountHandler.IPTable[ipAddress]++;
else
AccountHandler.IPTable[ipAddress] = 1;
AccountHandler.IPTable.TryGetValue(ipAddress, out var result);
AccountHandler.IPTable[ipAddress] = result + 1;
}
var contains = false;
for (var i = 0; !contains && i < LoginIPs.Length; ++i)
{
contains = LoginIPs[i].Equals(ipAddress);
}
if (contains)
{
return;
}
var old = LoginIPs;
LoginIPs = new IPAddress[old.Length + 1];
for (var i = 0; i < old.Length; ++i)
{
LoginIPs[i] = old[i];
}
LoginIPs[old.Length] = ipAddress;
}
@ -924,7 +1072,9 @@ namespace Server.Accounting
var hasAccess = HasAccess(ipAddress);
if (hasAccess)
{
LogAccess(ipAddress);
}
return hasAccess;
}
@ -997,7 +1147,9 @@ namespace Server.Accounting
xml.WriteStartElement("comments");
for (var i = 0; i < m_Comments.Count; ++i)
{
m_Comments[i].Save(xml);
}
xml.WriteEndElement();
}
@ -1007,7 +1159,9 @@ namespace Server.Accounting
xml.WriteStartElement("tags");
for (var i = 0; i < m_Tags.Count; ++i)
{
m_Tags[i].Save(xml);
}
xml.WriteEndElement();
}

View file

@ -65,11 +65,13 @@ namespace Server.Misc
m_IPTable = new Dictionary<IPAddress, int>();
foreach (Account a in Accounts.GetAccounts())
{
if (a.LoginIPs.Length > 0)
{
var ip = a.LoginIPs[0];
m_IPTable[ip] = (m_IPTable.TryGetValue(ip, out var value) ? value : 0) + 1;
}
}
}
return m_IPTable;
@ -93,7 +95,9 @@ namespace Server.Misc
EventSink.GameLogin += EventSink_GameLogin;
if (PasswordCommandEnabled)
{
CommandSystem.Register("Password", AccessLevel.Player, Password_OnCommand);
}
}
[Usage("Password <newPassword> <repeatPassword>")]
@ -105,17 +109,23 @@ namespace Server.Misc
var from = e.Mobile;
if (!(from.Account is Account acct))
{
return;
}
var accessList = acct.LoginIPs;
if (accessList.Length == 0)
{
return;
}
var ns = from.NetState;
if (ns == null)
{
return;
}
if (e.Length == 0)
{
@ -142,7 +152,9 @@ namespace Server.Misc
var isSafe = true;
for (var i = 0; isSafe && i < pass.Length; ++i)
{
isSafe = pass[i] >= 0x20 && pass[i] < 0x7F;
}
if (!isSafe)
{
@ -166,9 +178,13 @@ namespace Server.Misc
if (entry != null)
{
if (entry.Message.StartsWith("[Automated: Change Password]"))
{
from.SendMessage("You already have a password change request in the help system queue.");
}
else
{
from.SendMessage("Your IP address does not match that which created this account.");
}
}
else if (PageQueue.CheckAllowedToPage(from))
{
@ -246,19 +262,18 @@ namespace Server.Misc
}
}
public static bool CanCreate(IPAddress ip)
{
if (!IPTable.ContainsKey(ip))
return true;
return IPTable[ip] < MaxAccountsPerIP;
}
public static bool CanCreate(IPAddress ip) =>
!IPTable.TryGetValue(ip, out var result) || result < MaxAccountsPerIP;
private static bool IsForbiddenChar(char c)
{
for (var i = 0; i < m_ForbiddenChars.Length; ++i)
{
if (c == m_ForbiddenChars[i])
{
return true;
}
}
return false;
}
@ -266,18 +281,26 @@ namespace Server.Misc
private static Account CreateAccount(NetState state, string un, string pw)
{
if (un.Length == 0 || pw.Length == 0)
{
return null;
}
var isSafe = !(un.StartsWith(" ") || un.EndsWith(" ") || un.EndsWith("."));
for (var i = 0; isSafe && i < un.Length; ++i)
{
isSafe = un[i] >= 0x20 && un[i] < 0x7F && !IsForbiddenChar(un[i]);
}
for (var i = 0; isSafe && i < pw.Length; ++i)
{
isSafe = pw[i] >= 0x20 && pw[i] < 0x7F;
}
if (!isSafe)
{
return null;
}
if (!CanCreate(state.Address))
{
@ -307,10 +330,8 @@ namespace Server.Misc
Console.WriteLine("Login: {0}: Past IP limit threshold", e.State);
using (var op = new StreamWriter("ipLimits.log", true))
{
op.WriteLine("{0}\tPast IP limit threshold\t{1}", e.State, DateTime.UtcNow);
}
using var op = new StreamWriter("ipLimits.log", true);
op.WriteLine("{0}\tPast IP limit threshold\t{1}", e.State, DateTime.UtcNow);
return;
}
@ -329,7 +350,9 @@ namespace Server.Misc
e.Accepted = acct?.CheckAccess(e.State) ?? false;
if (!e.Accepted)
{
e.RejectReason = ALRReason.BadComm;
}
}
else
{
@ -362,7 +385,9 @@ namespace Server.Misc
}
if (!e.Accepted)
{
AccountAttackLimiter.RegisterInvalidAccess(e.State);
}
}
public static void EventSink_GameLogin(GameLoginEventArgs e)
@ -414,15 +439,23 @@ namespace Server.Misc
}
if (!e.Accepted)
{
AccountAttackLimiter.RegisterInvalidAccess(e.State);
}
}
public static bool CheckAccount(Mobile mobCheck, Mobile accCheck)
{
if (accCheck?.Account is Account a)
{
for (var i = 0; i < a.Length; ++i)
{
if (a[i] == mobCheck)
{
return true;
}
}
}
return false;
}

View file

@ -36,9 +36,13 @@ namespace Server.Commands
var m = e.Mobile;
if (m.AccessLevel >= c.AccessLevel)
{
m.SendGump(new CommandInfoGump(c));
}
else
{
m.SendMessage("You don't have access to that command.");
}
return;
}
@ -67,17 +71,23 @@ namespace Server.Commands
var attrs = mi.GetCustomAttributes(typeof(UsageAttribute), false);
if (attrs.Length == 0)
{
continue;
}
var usage = attrs[0] as UsageAttribute;
attrs = mi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs.Length == 0)
{
continue;
}
if (usage == null || !(attrs[0] is DescriptionAttribute desc))
{
continue;
}
attrs = mi.GetCustomAttributes(typeof(AliasesAttribute), false);
@ -114,14 +124,18 @@ namespace Server.Commands
var desc = command.Description;
if (usage == null || desc == null)
{
continue;
}
var cmds = command.Commands;
var cmd = cmds[0];
var aliases = new string[cmds.Length - 1];
for (var j = 0; j < aliases.Length; ++j)
{
aliases[j] = cmds[j + 1];
}
desc = desc.Replace("<", "(").Replace(">", ")");
@ -132,25 +146,39 @@ namespace Server.Commands
sb.Append("Modifiers: ");
if ((command.Supports & CommandSupport.Global) != 0)
{
sb.Append("<i>Global</i>, ");
}
if ((command.Supports & CommandSupport.Online) != 0)
{
sb.Append("<i>Online</i>, ");
}
if ((command.Supports & CommandSupport.Region) != 0)
{
sb.Append("<i>Region</i>, ");
}
if ((command.Supports & CommandSupport.Contained) != 0)
{
sb.Append("<i>Contained</i>, ");
}
if ((command.Supports & CommandSupport.Multi) != 0)
{
sb.Append("<i>Multi</i>, ");
}
if ((command.Supports & CommandSupport.Area) != 0)
{
sb.Append("<i>Area</i>, ");
}
if ((command.Supports & CommandSupport.Self) != 0)
{
sb.Append("<i>Self</i>, ");
}
sb.Remove(sb.Length - 2, 2);
sb.Append("<br>");
@ -183,14 +211,18 @@ namespace Server.Commands
var desc = command.Description;
if (usage == null || desc == null)
{
continue;
}
var cmds = command.Accessors;
var cmd = cmds[0];
var aliases = new string[cmds.Length - 1];
for (var j = 0; j < aliases.Length; ++j)
{
aliases[j] = cmds[j + 1];
}
desc = desc.Replace("<", ")").Replace(">", ")");
@ -213,8 +245,9 @@ namespace Server.Commands
SortedHelpInfo = list;
foreach (var c in SortedHelpInfo)
if (!HelpInfos.ContainsKey(c.Name.ToLower()))
HelpInfos.Add(c.Name.ToLower(), c);
{
HelpInfos.TryAdd(c.Name.ToLower(), c);
}
}
public class CommandListGump : BaseGridGump
@ -234,8 +267,12 @@ namespace Server.Commands
m_List = new List<CommandInfo>();
foreach (var c in SortedHelpInfo)
{
if (from.AccessLevel >= c.AccessLevel)
{
m_List.Add(c);
}
}
}
else
{
@ -245,9 +282,13 @@ namespace Server.Commands
AddNewPage();
if (m_Page > 0)
{
AddEntryButton(20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight);
}
else
{
AddEntryHeader(20);
}
AddEntryHtml(
160,
@ -257,9 +298,13 @@ namespace Server.Commands
);
if ((m_Page + 1) * EntriesPerPage < m_List.Count)
{
AddEntryButton(20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight);
}
else
{
AddEntryHeader(20);
}
var last = (int)AccessLevel.Player - 1;
@ -300,14 +345,18 @@ namespace Server.Commands
case 1:
{
if (m_Page > 0)
{
m.SendGump(new CommandListGump(m_Page - 1, m, m_List));
}
break;
}
case 2:
{
if ((m_Page + 1) * EntriesPerPage < SortedHelpInfo.Count)
{
m.SendGump(new CommandListGump(m_Page + 1, m, m_List));
}
break;
}
@ -369,7 +418,9 @@ namespace Server.Commands
for (var i = 0; i < aliases.Length; ++i)
{
if (i != 0)
{
sb.Append(", ");
}
sb.Append(aliases[i]);
}

View file

@ -16,7 +16,9 @@ namespace Server.Engines.Craft
CraftItem = item;
if (Recipes.ContainsKey(id))
{
throw new Exception("Attempting to create recipe with preexisting ID.");
}
Recipes.Add(id, this);
LargestRecipeID = Math.Max(id, LargestRecipeID);

View file

@ -33,18 +33,20 @@ namespace Server.Engines.Spawners
for (var i = 0; i < count; ++i)
// IEntity e = World.FindEntity( reader.ReadInt() );
{
if (reader.ReadEntity() is ISpawnable e)
{
e.Spawner = parent;
if (e is BaseCreature creature)
{
creature.RemoveIfUntamed = true;
}
Spawned.Add(e);
if (!parent.Spawned.ContainsKey(e))
parent.Spawned.Add(e, this);
parent.Spawned.TryAdd(e, this);
}
}
}
[JsonPropertyName("probability")] public int SpawnedProbability { get; set; }
@ -81,11 +83,17 @@ namespace Server.Engines.Spawners
object o = Spawned[i];
if (o is Item item)
{
writer.Write(item);
}
else if (o is Mobile mobile)
{
writer.Write(mobile);
}
else
{
writer.Write(Serial.MinusOne);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -172,7 +172,9 @@ namespace Server.Gumps
m_Object = o;
if (o != null)
{
m_Type = o.GetType();
}
m_List = list;
m_Stack = stack;
@ -189,7 +191,9 @@ namespace Server.Gumps
var lastIndex = page * EntryCount + count - 1;
if (lastIndex >= 0 && lastIndex < m_List.Count && m_List[lastIndex] == null)
{
--count;
}
var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1);
@ -210,24 +214,33 @@ namespace Server.Gumps
var emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4 - (OldStyle ? SetWidth + OffsetSize : 0);
if (OldStyle)
{
AddImageTiled(x, y, TotalWidth - OffsetSize * 3 - SetWidth, EntryHeight, HeaderGumpID);
}
else
{
AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID);
}
if (page > 0)
{
AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1);
if (PrevLabel)
{
AddLabel(x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous");
}
}
x += PrevWidth + OffsetSize;
if (!OldStyle)
{
AddImageTiled(x, y, emptyWidth, EntryHeight, HeaderGumpID);
}
if (TypeLabel && m_Type != null)
{
AddHtml(
x,
y,
@ -235,18 +248,23 @@ namespace Server.Gumps
EntryHeight,
$"<BASEFONT COLOR=#FAFAFA><CENTER>{m_Type.Name}</CENTER></BASEFONT>"
);
}
x += emptyWidth + OffsetSize;
if (!OldStyle)
{
AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID);
}
if ((page + 1) * EntryCount < m_List.Count)
{
AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1);
if (NextLabel)
{
AddLabel(x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next");
}
}
for (int i = 0, index = page * EntryCount; i < count && index < m_List.Count; ++i, ++index)
@ -267,7 +285,9 @@ namespace Server.Gumps
x += TypeWidth + OffsetSize;
if (SetGumpID != 0)
{
AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID);
}
}
else if (o is PropertyInfo prop)
{
@ -279,13 +299,17 @@ namespace Server.Gumps
x += ValueWidth + OffsetSize;
if (SetGumpID != 0)
{
AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID);
}
var cpa = GetCPA(prop);
if ((!prop.GetType().IsValueType || prop.CanWrite) && cpa != null &&
m_Mobile.AccessLevel >= cpa.WriteLevel && !cpa.ReadOnly)
{
AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3);
}
}
}
}
@ -315,14 +339,18 @@ namespace Server.Gumps
case 1: // Previous
{
if (m_Page > 0)
{
from.SendGump(new PropertiesGump(from, m_Object, m_Stack, m_List, m_Page - 1));
}
break;
}
case 2: // Next
{
if ((m_Page + 1) * EntryCount < m_List.Count)
{
from.SendGump(new PropertiesGump(from, m_Object, m_Stack, m_List, m_Page + 1));
}
break;
}
@ -335,13 +363,17 @@ namespace Server.Gumps
var prop = m_List[index] as PropertyInfo;
if (prop == null)
{
return;
}
var attr = GetCPA(prop);
if (prop.GetType().IsValueType && !prop.CanWrite || attr == null ||
from.AccessLevel < attr.WriteLevel || attr.ReadOnly)
{
return;
}
var type = prop.PropertyType;
@ -454,9 +486,13 @@ namespace Server.Gumps
var obj = prop.GetValue(m_Object, null);
if (obj != null)
{
from.SendGump(new PropertiesGump(from, obj, m_Stack, new StackEntry(m_Object, prop)));
}
else
{
from.SendGump(new PropertiesGump(from, m_Object, m_Stack, m_List, m_Page));
}
}
}
@ -470,7 +506,9 @@ namespace Server.Gumps
var list = new object[a.Length];
for (var i = 0; i < list.Length; ++i)
{
list[i] = a.GetValue(i);
}
return list;
}
@ -480,15 +518,21 @@ namespace Server.Gumps
public static void OnValueChanged(object obj, PropertyInfo prop, Stack<StackEntry> stack)
{
if (stack == null || stack.Count == 0)
{
return;
}
if (!prop.PropertyType.IsValueType)
{
return;
}
var peek = stack.Peek();
if (peek.m_Property.CanWrite)
{
peek.m_Property.SetValue(peek.m_Object, obj, null);
}
}
private static string[] GetCustomEnumNames(Type type)
@ -496,10 +540,14 @@ namespace Server.Gumps
var attrs = type.GetCustomAttributes(typeofCustomEnum, false);
if (attrs.Length == 0)
{
return Array.Empty<string>();
}
if (!(attrs[0] is CustomEnumAttribute ce))
{
return Array.Empty<string>();
}
return ce.Names;
}
@ -512,8 +560,12 @@ namespace Server.Gumps
private static bool IsType(Type type, Type[] check)
{
for (var i = 0; i < check.Length; ++i)
{
if (IsType(type, check[i]))
{
return true;
}
}
return false;
}
@ -534,27 +586,68 @@ namespace Server.Gumps
public static string ValueToString(object o)
{
if (o == null) return "-null-";
if (o is string s) return $"\"{s}\"";
if (o is bool) return o.ToString();
if (o is char c) return $"0x{(int)c:X} '{c}'";
if (o == null)
{
return "-null-";
}
if (o is string s)
{
return $"\"{s}\"";
}
if (o is bool)
{
return o.ToString();
}
if (o is char c)
{
return $"0x{(int)c:X} '{c}'";
}
if (o is Serial serial)
{
if (serial.IsValid)
{
if (serial.IsItem) return $"(I) 0x{serial.Value:X}";
if (serial.IsMobile) return $"(M) 0x{serial.Value:X}";
if (serial.IsItem)
{
return $"(I) 0x{serial.Value:X}";
}
if (serial.IsMobile)
{
return $"(M) 0x{serial.Value:X}";
}
}
return $"(?) 0x{serial.Value:X}";
}
if (o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong)
{
return $"{o} (0x{o:X})";
if (o is Mobile mobile) return $"(M) 0x{mobile.Serial.Value:X} \"{mobile.Name}\"";
if (o is Item item) return $"(I) 0x{item.Serial.Value:X}";
if (o is Type type) return type.Name;
if (o is TextDefinition definition) return definition.Format(true);
}
if (o is Mobile mobile)
{
return $"(M) 0x{mobile.Serial.Value:X} \"{mobile.Name}\"";
}
if (o is Item item)
{
return $"(I) 0x{item.Serial.Value:X}";
}
if (o is Type type)
{
return type.Name;
}
if (o is TextDefinition definition)
{
return definition.Format(true);
}
return o.ToString();
}
@ -564,7 +657,9 @@ namespace Server.Gumps
var list = new List<object>();
if (m_Type == null)
{
return list;
}
var props = m_Type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
@ -575,10 +670,14 @@ namespace Server.Gumps
var kvp = groups[i];
if (!HasAttribute(kvp.Key, typeofNoSort, false))
{
kvp.Value.Sort(PropertySorter.Instance);
}
if (i != 0)
{
list.Add(null);
}
list.Add(kvp.Key);
list.AddRange(kvp.Value);
@ -592,7 +691,10 @@ namespace Server.Gumps
var attrs = prop.GetCustomAttributes(typeofCPA, false);
if (attrs.Length > 0)
{
return attrs[0] as CPA;
}
return null;
}
@ -617,15 +719,24 @@ namespace Server.Gumps
var baseType = type?.BaseType;
if (baseType == typeofObject || baseType?.GetProperty(prop.Name, prop.PropertyType) == null)
{
break;
}
type = baseType;
}
if (type != null && !groups.ContainsKey(type))
groups[type] = new List<PropertyInfo> { prop };
else
groups[type].Add(prop);
if (type != null)
{
if (groups.TryGetValue(type, out var result))
{
result.Add(prop);
}
else
{
groups[type] = new List<PropertyInfo> { prop };
}
}
}
}
}
@ -638,7 +749,10 @@ namespace Server.Gumps
public static object GetObjectFromString(Type t, string s)
{
if (t == typeof(string)) return s;
if (t == typeof(string))
{
return s;
}
if (t == typeof(byte) || t == typeof(sbyte) || t == typeof(short) || t == typeof(ushort) || t == typeof(int) ||
t == typeof(uint) || t == typeof(long) || t == typeof(ulong))
@ -646,7 +760,9 @@ namespace Server.Gumps
if (s.StartsWith("0x"))
{
if (t == typeof(ulong) || t == typeof(uint) || t == typeof(ushort) || t == typeof(byte))
{
return Convert.ChangeType(Convert.ToUInt64(s.Substring(2), 16), t);
}
return Convert.ChangeType(Convert.ToInt64(s.Substring(2), 16), t);
}
@ -654,7 +770,11 @@ namespace Server.Gumps
return Convert.ChangeType(s, t);
}
if (t == typeof(double) || t == typeof(float)) return Convert.ChangeType(s, t);
if (t == typeof(double) || t == typeof(float))
{
return Convert.ChangeType(s, t);
}
if (t.IsDefined(typeof(ParsableAttribute), false))
{
var parseMethod = t.GetMethod("Parse", new[] { typeof(string) });
@ -667,26 +787,63 @@ namespace Server.Gumps
private static string GetStringFromObject(object o)
{
if (o == null) return "-null-";
if (o is string s) return $"\"{s}\"";
if (o is bool) return o.ToString();
if (o is char c) return $"0x{(int)c:X} '{c}'";
if (o == null)
{
return "-null-";
}
if (o is string s)
{
return $"\"{s}\"";
}
if (o is bool)
{
return o.ToString();
}
if (o is char c)
{
return $"0x{(int)c:X} '{c}'";
}
if (o is Serial serial)
{
if (serial.IsValid)
{
if (serial.IsItem) return $"(I) 0x{serial.Value:X}";
if (serial.IsMobile) return $"(M) 0x{serial.Value:X}";
if (serial.IsItem)
{
return $"(I) 0x{serial.Value:X}";
}
if (serial.IsMobile)
{
return $"(M) 0x{serial.Value:X}";
}
}
return $"(?) 0x{serial.Value:X}";
}
if (o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong)
{
return $"{o} (0x{o:X})";
if (o is Mobile mobile) return $"(M) 0x{mobile.Serial.Value:X} \"{mobile.Name}\"";
if (o is Item item) return $"(I) 0x{item.Serial.Value:X}";
if (o is Type type) return type.Name;
}
if (o is Mobile mobile)
{
return $"(M) 0x{mobile.Serial.Value:X} \"{mobile.Name}\"";
}
if (o is Item item)
{
return $"(I) 0x{item.Serial.Value:X}";
}
if (o is Type type)
{
return type.Name;
}
return o.ToString();
}
@ -702,9 +859,14 @@ namespace Server.Gumps
public int Compare(PropertyInfo x, PropertyInfo y)
{
if (x == null && y == null)
{
return 0;
}
if (x == null)
{
return -1;
}
return y == null ? 1 : x.Name.CompareTo(x.Name);
}
@ -726,7 +888,9 @@ namespace Server.Gumps
int dist;
for (dist = 0; current != null && current != typeofObject && current != type; ++dist)
{
current = current.BaseType;
}
return dist;
}

View file

@ -69,7 +69,9 @@ namespace Server.Engines.Events
{
if (m is PlayerMobile pm && !pm.Deleted && m_Timer.Running && !m_DeathQueue.Contains(pm) &&
m_DeathQueue.Count < m_DeathQueueLimit)
{
m_DeathQueue.Add(pm);
}
}
private static void Clear_Callback()
@ -78,7 +80,10 @@ namespace Server.Engines.Events
m_DeathQueue.Clear();
if (DateTime.UtcNow <= HolidaySettings.FinishHalloween) m_ClearTimer.Stop();
if (DateTime.UtcNow <= HolidaySettings.FinishHalloween)
{
m_ClearTimer.Stop();
}
}
private static void Timer_Callback()
@ -88,12 +93,15 @@ namespace Server.Engines.Events
if (DateTime.UtcNow <= HolidaySettings.FinishHalloween)
{
for (var index = 0; m_DeathQueue.Count > 0 && index < m_DeathQueue.Count; index++)
if (!ReAnimated.ContainsKey(m_DeathQueue[index]))
{
player = m_DeathQueue[index];
{
var entry = m_DeathQueue[index];
if (!ReAnimated.ContainsKey(entry))
{
player = entry;
break;
}
}
if (player?.Deleted == false && ReAnimated.Count < m_TotalZombieLimit)
{
@ -244,7 +252,9 @@ namespace Server.Engines.Events
public override void OnDelete()
{
if (m_DeadPlayer?.Deleted == false)
{
HalloweenHauntings.ReAnimated?.Remove(m_DeadPlayer);
}
}
public override void Serialize(IGenericWriter writer)

View file

@ -197,7 +197,9 @@ namespace Server.Items
var version = reader.ReadInt();
if (version == 0 && Weight == 1.0)
{
Weight = -1;
}
}
}
@ -263,7 +265,9 @@ namespace Server.Items
public override void DisplayTo(Mobile m)
{
if (DynamicFurniture.Open(this, m))
{
base.DisplayTo(m);
}
}
public override void Serialize(IGenericWriter writer)
@ -295,7 +299,9 @@ namespace Server.Items
public override void DisplayTo(Mobile m)
{
if (DynamicFurniture.Open(this, m))
{
base.DisplayTo(m);
}
}
public override void Serialize(IGenericWriter writer)
@ -349,13 +355,13 @@ namespace Server.Items
public static void Close(Container c)
{
if (m_Table.TryGetValue(c, out var t))
if (m_Table.Remove(c, out var t))
{
t.Stop();
m_Table.Remove(c);
}
if (c is Armoire || c is FancyArmoire)
{
c.ItemID = c.ItemID switch
{
0xA4C => 0xA4D,
@ -364,6 +370,7 @@ namespace Server.Items
0xA52 => 0xA53,
_ => c.ItemID
};
}
}
}
@ -383,7 +390,9 @@ namespace Server.Items
protected override void OnTick()
{
if (m_Mobile.Map != m_Container.Map || !m_Mobile.InRange(m_Container.GetWorldLocation(), 3))
{
DynamicFurniture.Close(m_Container);
}
}
}
}

View file

@ -52,6 +52,7 @@ namespace Server.Items
public override int ComputeItemID()
{
if (!IsEmpty)
{
switch (Content)
{
case BeverageType.Ale: return 0x99F;
@ -61,6 +62,7 @@ namespace Server.Items
case BeverageType.Wine: return 0x9C7;
case BeverageType.Water: return 0x99B;
}
}
return 0;
}
@ -127,7 +129,9 @@ namespace Server.Items
public override int ComputeItemID()
{
if (!IsEmpty)
{
return 0x9C8;
}
return 0;
}
@ -168,9 +172,14 @@ namespace Server.Items
public override int ComputeItemID()
{
if (ItemID >= 0x995 && ItemID <= 0x999)
{
return ItemID;
}
if (ItemID == 0x9CA)
{
return ItemID;
}
return 0x995;
}
@ -211,7 +220,9 @@ namespace Server.Items
public override int ComputeItemID()
{
if (ItemID >= 0xFFF && ItemID <= 0x1002)
{
return ItemID;
}
return 0xFFF;
}
@ -252,7 +263,9 @@ namespace Server.Items
public override int ComputeItemID()
{
if (ItemID == 0x99A || ItemID == 0x9B3 || ItemID == 0x9BF || ItemID == 0x9CB)
{
return ItemID;
}
return 0x99A;
}
@ -302,7 +315,9 @@ namespace Server.Items
public override int ComputeItemID()
{
if (IsEmpty)
{
return ItemID >= 0x1F81 && ItemID <= 0x1F84 ? ItemID : 0x1F81;
}
return Content switch
{
@ -406,7 +421,9 @@ namespace Server.Items
if (IsEmpty)
{
if (ItemID == 0x9A7 || ItemID == 0xFF7)
{
return ItemID;
}
return 0xFF6;
}
@ -416,42 +433,54 @@ namespace Server.Items
case BeverageType.Ale:
{
if (ItemID == 0x1F96)
{
return ItemID;
}
return 0x1F95;
}
case BeverageType.Cider:
{
if (ItemID == 0x1F98)
{
return ItemID;
}
return 0x1F97;
}
case BeverageType.Liquor:
{
if (ItemID == 0x1F9A)
{
return ItemID;
}
return 0x1F99;
}
case BeverageType.Milk:
{
if (ItemID == 0x9AD)
{
return ItemID;
}
return 0x9F0;
}
case BeverageType.Wine:
{
if (ItemID == 0x1F9C)
{
return ItemID;
}
return 0x1F9B;
}
case BeverageType.Water:
{
if (ItemID == 0xFF8 || ItemID == 0xFF9 || ItemID == 0x1F9E)
{
return ItemID;
}
return 0x1F9D;
}
@ -470,9 +499,13 @@ namespace Server.Items
public override void Deserialize(IGenericReader reader)
{
if (CheckType("PitcherWater") || CheckType("GlassPitcher"))
{
InternalDeserialize(reader, false);
}
else
{
InternalDeserialize(reader, true);
}
var version = reader.ReadInt();
@ -565,7 +598,9 @@ namespace Server.Items
var num = BaseLabelNumber;
if (IsEmpty || num == 0)
{
return EmptyLabelNumber;
}
return BaseLabelNumber + (int)m_Content;
}
@ -608,9 +643,13 @@ namespace Server.Items
var itemID = ComputeItemID();
if (itemID > 0)
{
ItemID = itemID;
}
else
{
Delete();
}
}
}
@ -627,9 +666,13 @@ namespace Server.Items
var itemID = ComputeItemID();
if (itemID > 0)
{
ItemID = itemID;
}
else
{
Delete();
}
}
}
@ -640,11 +683,20 @@ namespace Server.Items
var perc = m_Quantity * 100 / MaxQuantity;
if (perc <= 0)
{
return 1042975; // It's empty.
}
if (perc <= 33)
{
return 1042974; // It's nearly empty.
}
if (perc <= 66)
{
return 1042973; // It's half full.
}
return 1042972; // It's full.
}
@ -653,7 +705,9 @@ namespace Server.Items
base.GetProperties(list);
if (ShowQuantity)
{
list.Add(GetQuantityDescription());
}
}
public override void OnSingleClick(Mobile from)
@ -661,13 +715,17 @@ namespace Server.Items
base.OnSingleClick(from);
if (ShowQuantity)
{
LabelTo(from, GetQuantityDescription());
}
}
public virtual bool ValidateUse(Mobile from, bool message)
{
if (Deleted)
{
return false;
}
if (!Movable && !Fillable)
{
@ -676,7 +734,9 @@ namespace Server.Items
if (house?.HasLockedDownItem(this) != true)
{
if (message)
{
from.SendLocalizedMessage(502946, "", 0x59); // That belongs to someone else.
}
return false;
}
@ -685,7 +745,9 @@ namespace Server.Items
if (from.Map != Map || !from.InRange(GetWorldLocation(), 2) || !from.InLOS(this))
{
if (message)
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
}
return false;
}
@ -696,12 +758,16 @@ namespace Server.Items
public virtual void Fill_OnTarget(Mobile from, object targ)
{
if (!IsEmpty || !Fillable || !ValidateUse(from, false))
{
return;
}
if (targ is BaseBeverage bev)
{
if (bev.IsEmpty || !bev.ValidateUse(from, true))
{
return;
}
Content = bev.Content;
Poison = bev.Poison;
@ -739,10 +805,14 @@ namespace Server.Items
var src = item as IWaterSource;
if (src == null && item is AddonComponent component)
{
src = component.Addon as IWaterSource;
}
if (src == null || src.Quantity <= 0)
{
return;
}
if (from.Map != item.Map || !from.InRange(item.GetWorldLocation(), 2) || !from.InLOS(item))
{
@ -785,7 +855,9 @@ namespace Server.Items
var qs = player.Quest;
if (!(qs is WitchApprenticeQuest))
{
return;
}
var obj = qs.FindObjective<FindIngredientObjective>();
@ -794,7 +866,9 @@ namespace Server.Items
var contains = false;
for (var i = 0; !contains && i < m_SwampTiles.Length; i += 2)
{
contains = tileID >= m_SwampTiles[i] && tileID <= m_SwampTiles[i + 1];
}
if (contains)
{
@ -813,12 +887,16 @@ namespace Server.Items
public virtual void Pour_OnTarget(Mobile from, object targ)
{
if (IsEmpty || !Pourable || !ValidateUse(from, false))
{
return;
}
if (targ is BaseBeverage bev)
{
if (!bev.ValidateUse(from, true))
{
return;
}
if (bev.IsFull && bev.Content == Content)
{
@ -851,7 +929,9 @@ namespace Server.Items
else if (from == targ)
{
if (from.Thirst < 20)
{
from.Thirst += 1;
}
if (ContainsAlchohol)
{
@ -872,7 +952,9 @@ namespace Server.Items
from.PlaySound(Utility.RandomList(0x30, 0x2D6));
if (Poison != null)
{
from.ApplyPoison(Poisoner, Poison);
}
--Quantity;
}
@ -908,6 +990,7 @@ namespace Server.Items
Content == BeverageType.Water)
{
if (from is PlayerMobile player)
{
if (player.Quest is SolenMatriarchQuest qs)
{
QuestObjective obj = qs.FindObjective<GatherWaterObjective>();
@ -934,6 +1017,7 @@ namespace Server.Items
}
}
}
}
}
else
{
@ -946,7 +1030,9 @@ namespace Server.Items
if (IsEmpty)
{
if (!Fillable || !ValidateUse(from, true))
{
return;
}
from.BeginTarget(-1, true, TargetFlags.None, Fill_OnTarget);
SendLocalizedMessageTo(from, 500837); // Fill from what?
@ -969,8 +1055,12 @@ namespace Server.Items
var total = 0;
for (var i = 0; i < items.Length; ++i)
{
if (items[i] is BaseBeverage bev && bev.Content == content && !bev.IsEmpty)
{
total += bev.Quantity;
}
}
if (total >= quantity)
{
@ -981,7 +1071,9 @@ namespace Server.Items
for (var i = 0; i < items.Length; ++i)
{
if (!(items[i] is BaseBeverage bev) || bev.Content != content || bev.IsEmpty)
{
continue;
}
var theirQuantity = bev.Quantity;
@ -1026,7 +1118,9 @@ namespace Server.Items
base.Deserialize(reader);
if (!read)
{
return;
}
var version = reader.ReadInt();
@ -1062,20 +1156,23 @@ namespace Server.Items
if (from.BAC > 0 && from.Map != Map.Internal && !from.Deleted)
{
if (m_Table.ContainsKey(from))
{
return;
}
if (from.BAC > 60)
{
from.BAC = 60;
}
Timer t = new HeaveTimer(from);
t.Start();
m_Table[from] = t;
}
else if (m_Table.TryGetValue(from, out var t))
else if (m_Table.Remove(from, out var t))
{
t.Stop();
m_Table.Remove(from);
from.SendLocalizedMessage(500850); // You feel sober.
}
@ -1103,11 +1200,15 @@ namespace Server.Items
else if (m_Drunk.Alive)
{
if (m_Drunk.BAC > 60)
{
m_Drunk.BAC = 60;
}
// chance to get sober
if (Utility.Random(100) < 10)
{
--m_Drunk.BAC;
}
// lose some stats
m_Drunk.Stam -= 1;

View file

@ -147,7 +147,9 @@ namespace Server.Items
}
if (!isBaseCreature && !info.CriminalAggression)
{
Aggressors.Add(info.Attacker);
}
}
for (var i = 0; i < owner.Aggressed.Count; ++i)
@ -161,7 +163,9 @@ namespace Server.Items
}
if (!isBaseCreature)
{
Aggressors.Add(info.Defender);
}
}
if (isBaseCreature)
@ -170,7 +174,9 @@ namespace Server.Items
var master = bc.GetMaster();
if (master != null)
{
Aggressors.Add(master);
}
var rights = BaseCreature.GetLootingRights(bc.DamageEntries, bc.HitsMax);
for (var i = 0; i < rights.Count; ++i)
@ -178,7 +184,9 @@ namespace Server.Items
var ds = rights[i];
if (ds.m_HasRight)
{
Aggressors.Add(ds.m_Mobile);
}
}
}
@ -282,9 +290,13 @@ namespace Server.Items
if (IsCriminalAction(from) && (Map?.Rules & MapRules.HarmfulRestrictions) != 0)
{
if (Owner?.Player != true)
{
from.SendLocalizedMessage(1005035); // You did not earn the right to loot this creature!
}
else
{
from.SendLocalizedMessage(1010049); // You may not loot this corpse.
}
return;
}
@ -315,7 +327,9 @@ namespace Server.Items
ProcessDelta();
if (IsCriminalAction(from))
{
from.CriminalAction(true);
}
}
else if (dead is BaseCreature creature)
{
@ -335,7 +349,9 @@ namespace Server.Items
private void AssignInstancedLoot()
{
if (Aggressors.Count == 0 || Items.Count == 0)
{
return;
}
m_InstancedItems ??= new Dictionary<Item, InstancedItemInfo>();
@ -349,9 +365,13 @@ namespace Server.Items
if (item.LootType != LootType.Cursed) // Don't have cursed items take up someone's item spot.. (?)
{
if (item.Stackable)
{
m_Stackables.Add(item);
}
else
{
m_Unstackables.Add(item);
}
}
}
@ -392,9 +412,13 @@ namespace Server.Items
}
if (remainder == 0)
{
m_InstancedItems.Add(item, new InstancedItemInfo(item, attackers[^1]));
}
else
{
m_Unstackables.Add(item);
}
}
else
{
@ -427,7 +451,9 @@ namespace Server.Items
public void TurnToBones()
{
if (Deleted)
{
return;
}
ProcessDelta();
SendRemovePacket();
@ -481,18 +507,28 @@ namespace Server.Items
var item = initialContent[i];
if (Core.AOS && owner.Player && item.Parent == owner.Backpack)
{
c.AddItem(item);
}
else
{
c.DropItem(item);
}
if (owner.Player && Core.AOS)
{
c.SetRestoreInfo(item, item.Location);
}
}
if (Core.SE && !owner.Player)
{
c.AssignInstancedLoot();
}
else if (Core.AOS && owner is PlayerMobile pm)
{
c.RestoreEquip = pm.EquipSnapshot;
}
var loc = owner.Location;
var map = owner.Map;
@ -539,6 +575,7 @@ namespace Server.Items
writer.Write(count);
if (m_RestoreTable != null)
{
foreach (var (item, loc) in m_RestoreTable)
{
writer.Write(item);
@ -553,11 +590,14 @@ namespace Server.Items
writer.Write(loc);
}
}
}
writer.Write(m_DecayTimer != null);
if (m_DecayTimer != null)
{
writer.WriteDeltaTime(m_DecayTime);
}
writer.Write(Looters);
writer.Write(Killer);
@ -586,7 +626,9 @@ namespace Server.Items
case 12:
{
if (reader.ReadBool())
{
RestoreEquip = reader.ReadStrongItemList();
}
goto case 11;
}
@ -604,13 +646,19 @@ namespace Server.Items
var item = reader.ReadItem();
if (reader.ReadBool())
{
SetRestoreInfo(item, reader.ReadPoint3D());
}
else if (item != null)
{
SetRestoreInfo(item, item.Location);
}
}
if (reader.ReadBool())
{
BeginDecay(reader.ReadDeltaTime() - DateTime.UtcNow);
}
Looters = reader.ReadStrongMobileList();
Killer = reader.ReadMobile();
@ -642,9 +690,13 @@ namespace Server.Items
var item = reader.ReadItem();
if (reader.ReadBool())
{
SetRestoreInfo(item, reader.ReadPoint3D());
}
else if (item != null)
{
SetRestoreInfo(item, item.Location);
}
}
goto case 8;
@ -658,7 +710,9 @@ namespace Server.Items
case 7:
{
if (reader.ReadBool())
{
BeginDecay(reader.ReadDeltaTime() - DateTime.UtcNow);
}
goto case 6;
}
@ -702,16 +756,24 @@ namespace Server.Items
case 0:
{
if (version < 10)
{
TimeOfDeath = DateTime.UtcNow;
}
if (version < 7)
{
BeginDecay(m_DefaultDecayTime);
}
if (version < 6)
{
Looters = new List<Mobile>();
}
if (version < 4)
{
Aggressors = new List<Mobile>();
}
AccessLevel = (AccessLevel)reader.ReadInt();
reader.ReadInt(); // guild reserve
@ -729,7 +791,9 @@ namespace Server.Items
{
if (Devoured || Deleted || Killer?.Deleted != false || !Killer.Alive || !(Killer is IDevourer devourer) ||
Owner?.Deleted != false)
{
return false;
}
m_Devourer = devourer; // Set the devourer the killer
return m_Devourer.Devour(this); // Devour the corpse if it hasn't
@ -740,12 +804,18 @@ namespace Server.Items
base.SendInfoTo(state, sendOplPacket);
if (!(((Body)Amount).IsHuman && ItemID == 0x2006))
{
return;
}
if (state.ContainerGridLines)
{
state.Send(new CorpseContent6017(state.Mobile, this));
}
else
{
state.Send(new CorpseContent(state.Mobile, this));
}
state.Send(new CorpseEquip(state.Mobile, this));
}
@ -753,7 +823,9 @@ namespace Server.Items
public bool IsCriminalAction(Mobile from)
{
if (from == Owner || from.AccessLevel >= AccessLevel.GameMaster)
{
return false;
}
var p = Party.Get(Owner);
@ -762,7 +834,9 @@ namespace Server.Items
var pmi = p[Owner];
if (pmi?.CanLoot == true)
{
return false;
}
}
return NotorietyHandlers.CorpseNotoriety(from, this) == Notoriety.Innocent;
@ -779,16 +853,22 @@ namespace Server.Items
base.OnItemUsed(from, item);
if (item is Food)
{
from.RevealingAction();
}
if (item != this && IsCriminalAction(from))
{
from.CriminalAction(true);
}
if (!Looters.Contains(from))
{
Looters.Add(from);
}
m_InstancedItems?.Remove(item);
if (m_InstancedItems?.ContainsKey(item) == true)
m_InstancedItems.Remove(item);
}
public override void OnItemLifted(Mobile from, Item item)
@ -796,16 +876,21 @@ namespace Server.Items
base.OnItemLifted(from, item);
if (item != this && from != Owner)
{
from.RevealingAction();
}
if (item != this && IsCriminalAction(from))
{
from.CriminalAction(true);
}
if (!Looters.Contains(from))
{
Looters.Add(from);
}
if (m_InstancedItems?.ContainsKey(item) == true)
m_InstancedItems.Remove(item);
m_InstancedItems?.Remove(item);
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
@ -813,7 +898,9 @@ namespace Server.Items
base.GetContextMenuEntries(from, list);
if (Core.AOS && Owner == from && from.Alive)
{
list.Add(new OpenCorpseEntry());
}
}
public bool GetRestoreInfo(Item item, ref Point3D loc) =>
@ -822,7 +909,9 @@ namespace Server.Items
public void SetRestoreInfo(Item item, Point3D loc)
{
if (item == null)
{
return;
}
m_RestoreTable ??= new Dictionary<Item, Point3D>();
@ -832,12 +921,16 @@ namespace Server.Items
public void ClearRestoreInfo(Item item)
{
if (m_RestoreTable == null || item == null)
{
return;
}
m_RestoreTable.Remove(item);
if (m_RestoreTable.Count == 0)
{
m_RestoreTable = null;
}
}
public bool CanLoot(Mobile from, Item item) =>
@ -848,9 +941,13 @@ namespace Server.Items
if (!CanLoot(from, item))
{
if (Owner?.Player != true)
{
from.SendLocalizedMessage(1005035); // You did not earn the right to loot this creature!
}
else
{
from.SendLocalizedMessage(1010049); // You may not loot this corpse.
}
return false;
}
@ -858,9 +955,13 @@ namespace Server.Items
if (IsCriminalAction(from))
{
if (Owner?.Player != true)
{
from.SendLocalizedMessage(1005036); // Looting this monster corpse will be a criminal act!
}
else
{
from.SendLocalizedMessage(1005038); // Looting this corpse will be a criminal act!
}
}
return true;
@ -898,7 +999,9 @@ namespace Server.Items
var packItem = packItems[i];
if (RestoreEquip.Contains(packItem) && packItem.Movable)
{
from.EquipItem(packItem);
}
}
}
@ -913,7 +1016,9 @@ namespace Server.Items
if (item.Layer == Layer.Hair || item.Layer == Layer.FacialHair || !item.Movable ||
!GetRestoreInfo(item, ref loc))
{
continue;
}
if (pack?.CheckHold(from, item, false, true) == true)
{
@ -921,7 +1026,9 @@ namespace Server.Items
pack.AddItem(item);
if (RestoreEquip?.Contains(item) == true)
{
from.EquipItem(item);
}
}
else
{
@ -955,9 +1062,14 @@ namespace Server.Items
}
if (!CheckLoot(from, null))
{
return;
}
if (!(from is PlayerMobile player)) return;
if (!(from is PlayerMobile player))
{
return;
}
var qs = player.Quest;
@ -978,7 +1090,9 @@ namespace Server.Items
); // You rummage through the bones and find a Daemon Bone! You quickly place the item in your pack.
if (!obj.Completed)
{
obj.Complete();
}
}
else
{
@ -1033,9 +1147,13 @@ namespace Server.Items
if (ItemID == 0x2006) // Corpse form
{
if (m_CorpseName != null)
{
list.Add(m_CorpseName);
}
else
{
list.Add(1046414, Name); // the remains of ~1_NAME~
}
}
else // Bone form
{
@ -1049,7 +1167,9 @@ namespace Server.Items
var opl = PropertyList;
if (opl.Header > 0)
{
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, opl.Header, Name, opl.HeaderArgs));
}
}
public override void OnSingleClick(Mobile from)
@ -1059,9 +1179,13 @@ namespace Server.Items
if (ItemID == 0x2006) // Corpse form
{
if (m_CorpseName != null)
{
from.Send(new AsciiMessage(Serial, ItemID, MessageType.Label, hue, 3, "", m_CorpseName));
}
else
{
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1046414, "", Name));
}
}
else // Bone form
{
@ -1085,13 +1209,19 @@ namespace Server.Items
public bool IsOwner(Mobile m)
{
if (m_Item.LootType == LootType.Cursed) // Cursed Items are part of everyone's instanced corpse... (?)
{
return true;
}
if (m == null)
{
return false; // sanity
}
if (m_Mobile == m)
{
return true;
}
var myParty = Party.Get(m_Mobile);
@ -1112,9 +1242,13 @@ namespace Server.Items
protected override void OnTick()
{
if (!m_Corpse.GetFlag(CorpseFlag.NoBones))
{
m_Corpse.TurnToBones();
}
else
{
m_Corpse.Delete();
}
}
}
@ -1127,7 +1261,9 @@ namespace Server.Items
public override void OnClick()
{
if (Owner.Target is Corpse corpse && Owner.From.CheckAlive())
{
corpse.Open(Owner.From, false);
}
}
}
}

View file

@ -75,7 +75,9 @@ namespace Server.Items
public static void RemoveKeys(Mobile m, uint keyValue)
{
if (keyValue == 0)
{
return;
}
RemoveKeys(m.Backpack, keyValue);
RemoveKeys(m.BankBox, keyValue);
@ -84,15 +86,20 @@ namespace Server.Items
public static void RemoveKeys(Container cont, uint keyValue)
{
if (cont == null || keyValue == 0)
{
return;
}
var items = cont.FindItemsByType(new[] { typeof(Key), typeof(KeyRing) });
foreach (var item in items)
{
if (item is Key key)
{
if (key.KeyValue == keyValue)
{
key.Delete();
}
}
else
{
@ -100,28 +107,37 @@ namespace Server.Items
keyRing.RemoveKeys(keyValue);
}
}
}
public static bool ContainsKey(Container cont, uint keyValue)
{
if (cont == null)
{
return false;
}
var items = cont.FindItemsByType(new[] { typeof(Key), typeof(KeyRing) });
foreach (var item in items)
{
if (item is Key key)
{
if (key.KeyValue == keyValue)
{
return true;
}
}
else
{
var keyRing = (KeyRing)item;
if (keyRing.ContainsKey(keyValue))
{
return true;
}
}
}
return false;
}
@ -163,7 +179,9 @@ namespace Server.Items
case 0:
{
if (version < 2 || MaxRange == 0)
{
MaxRange = 3;
}
m_Description = reader.ReadString();
@ -207,12 +225,18 @@ namespace Server.Items
string desc;
if (m_KeyVal == 0)
{
desc = "(blank)";
}
else if ((desc = m_Description) == null || (desc = desc.Trim()).Length <= 0)
{
desc = null;
}
if (desc != null)
{
list.Add(desc);
}
}
public override void OnSingleClick(Mobile from)
@ -222,12 +246,18 @@ namespace Server.Items
string desc;
if (m_KeyVal == 0)
{
desc = "(blank)";
}
else if ((desc = m_Description) == null || (desc = desc.Trim()).Length <= 0)
{
desc = "";
}
if (desc.Length > 0)
{
from.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", "", desc));
}
}
public bool UseOn(Mobile from, ILockable o)
@ -235,30 +265,44 @@ namespace Server.Items
if (o.KeyValue == KeyValue)
{
if (o is BaseDoor door && !door.UseLocks())
{
return false;
}
o.Locked = !o.Locked;
if (o is LockableContainer cont1)
{
if (cont1.LockLevel == -255)
{
cont1.LockLevel = cont1.RequiredSkill - 10;
}
}
if (o is Item item)
{
if (o.Locked)
{
item.SendLocalizedMessageTo(from, 1048000); // You lock it.
}
else
{
item.SendLocalizedMessageTo(from, 1048001); // You unlock it.
}
if (item is LockableContainer cont && cont.TrapType != TrapType.None && cont.TrapOnLockpick)
{
if (o.Locked)
{
cont.SendLocalizedMessageTo(from, 501673); // You re-enable the trap.
}
else
{
cont.SendLocalizedMessageTo(
from,
501672
); // You disable the trap temporarily. Lock it again to re-enable it.
}
}
}
@ -315,16 +359,23 @@ namespace Server.Items
else if (targeted is ILockable lockable)
{
if (m_Key.UseOn(from, lockable))
{
number = -1;
}
else
{
number = 501668; // This key doesn't seem to unlock that.
}
}
else
{
number = 501666; // You can't unlock that!
}
if (number != -1) from.SendLocalizedMessage(number);
if (number != -1)
{
from.SendLocalizedMessage(number);
}
}
}

View file

@ -62,7 +62,10 @@ namespace Server.Items
{
base.OnDelete();
foreach (var key in Keys) key.Delete();
foreach (var key in Keys)
{
key.Delete();
}
Keys.Clear();
}
@ -78,14 +81,18 @@ namespace Server.Items
public void Open(Mobile from)
{
if (!(Parent is Container cont))
{
return;
}
for (var i = Keys.Count - 1; i >= 0; i--)
{
var key = Keys[i];
if (!key.Deleted && !cont.TryDropItem(from, key, true))
{
break;
}
Keys.RemoveAt(i);
}
@ -112,8 +119,12 @@ namespace Server.Items
public bool ContainsKey(uint keyValue)
{
foreach (var key in Keys)
{
if (key.KeyValue == keyValue)
{
return true;
}
}
return false;
}
@ -121,13 +132,21 @@ namespace Server.Items
private void UpdateItemID()
{
if (Keys.Count < 1)
{
ItemID = 0x1011;
}
else if (Keys.Count < 3)
{
ItemID = 0x1769;
}
else if (Keys.Count < 5)
{
ItemID = 0x176A;
}
else
{
ItemID = 0x176B;
}
}
public override void Serialize(IGenericWriter writer)
@ -170,8 +189,12 @@ namespace Server.Items
else if (targeted is ILockable o)
{
foreach (var key in m_KeyRing.Keys)
{
if (key.UseOn(from, o))
{
return;
}
}
from.SendLocalizedMessage(1008140); // You do not have a key for that.
}

View file

@ -652,11 +652,10 @@ namespace Server.Items
public static void EventSink_Logout(Mobile from)
{
if (from == null || !m_Table.TryGetValue(from, out var info))
return;
info.Timer.Stop();
m_Table.Remove(from);
if (from != null && m_Table.Remove(from, out var info))
{
info.Timer.Stop();
}
}
public static string FormatTime(TimeSpan ts)
@ -802,10 +801,9 @@ namespace Server.Items
public void StopTimer(Mobile m)
{
if (m_Teleporting.TryGetValue(m, out var t))
if (m_Teleporting.Remove(m, out var t))
{
t.Stop();
m_Teleporting.Remove(m);
}
}

View file

@ -107,10 +107,9 @@ namespace Server.Items
public static void EndDelay(Mobile m)
{
if (m_Delay.TryGetValue(m, out var timer))
if (m_Delay.Remove(m, out var timer))
{
timer.Stop();
m_Delay.Remove(m);
}
}

View file

@ -123,10 +123,9 @@ namespace Server.Items
public static void EndDelay(Mobile m)
{
if (m_Delay.TryGetValue(m, out var timer))
if (m_Delay.Remove(m, out var timer))
{
timer.Stop();
m_Delay.Remove(m);
}
}

View file

@ -66,12 +66,14 @@ namespace Server.Items
public static void RemoveTimer(Mobile m, bool interrupted = false)
{
if (m_Table.TryGetValue(m, out var timer))
if (m_Table.Remove(m, out var timer))
{
if (interrupted)
{
m.SendLocalizedMessage(1073187); // The invisibility effect is interrupted.
}
timer.Stop();
m_Table.Remove(m);
}
}

View file

@ -283,10 +283,9 @@ namespace Server.Items
public static void RemoveTimer(Mobile m)
{
if (Timers.TryGetValue(m, out var t))
if (Timers.Remove(m, out var t))
{
t.Stop();
Timers.Remove(m);
}
}

View file

@ -21,7 +21,9 @@ namespace Server.Items
public override void OnHit(Mobile attacker, Mobile defender, int damage)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{
return;
}
ClearCurrentAbility(attacker);
@ -73,7 +75,9 @@ namespace Server.Items
var damage = Utility.RandomMinMax(level, level * 2);
if (!m.Player)
{
damage *= 2;
}
m.PlaySound(0x133);
m.Damage(damage, from);
@ -89,14 +93,17 @@ namespace Server.Items
public static void EndBleed(Mobile m, bool message)
{
if (!m_Table.TryGetValue(m, out var t))
if (!m_Table.Remove(m, out var t))
{
return;
}
t.Stop();
m_Table.Remove(m);
if (message)
{
m.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding!
}
}
private class InternalTimer : Timer
@ -117,7 +124,9 @@ namespace Server.Items
DoBleed(m_Mobile, m_From, 5 - m_Count);
if (++m_Count == 5)
{
EndBleed(m_Mobile, true);
}
}
}
}

View file

@ -29,7 +29,9 @@ namespace Server.Items
public override void OnHit(Mobile attacker, Mobile defender, int damage)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{
return;
}
ClearCurrentAbility(attacker);
@ -49,7 +51,9 @@ namespace Server.Items
public static bool GetBonus(Mobile targ, ref int bonus)
{
if (!m_Table.TryGetValue(targ, out var info))
{
return false;
}
bonus = info.m_Bonus;
return true;
@ -63,11 +67,10 @@ namespace Server.Items
public static void EndBlock(Mobile m)
{
if (!m_Table.TryGetValue(m, out var info))
return;
info.m_Timer?.Stop();
m_Table.Remove(m);
if (m_Table.Remove(m, out var info))
{
info.m_Timer?.Stop();
}
}
private class BlockInfo

View file

@ -19,7 +19,10 @@ namespace Server.Items
public override void OnHit(Mobile attacker, Mobile defender, int damage)
{
if (!Validate(attacker) || !CheckMana(attacker, true)) return;
if (!Validate(attacker) || !CheckMana(attacker, true))
{
return;
}
ClearCurrentAbility(attacker);
@ -31,7 +34,9 @@ namespace Server.Items
// Do not reset timer if one is already in place.
if (!IsWounded(defender))
{
BeginWound(defender, defender.Player ? PlayerDuration : NPCDuration);
}
}
public static bool IsWounded(Mobile m) => m_Table.ContainsKey(m);
@ -39,7 +44,9 @@ namespace Server.Items
public static void BeginWound(Mobile m, TimeSpan duration)
{
if (m_Table.TryGetValue(m, out var timer))
{
timer?.Stop();
}
m_Table[m] = timer = new InternalTimer(m, duration);
timer.Start();
@ -49,10 +56,9 @@ namespace Server.Items
public static void EndWound(Mobile m)
{
if (m_Table.TryGetValue(m, out var timer))
if (m_Table.Remove(m, out var timer))
{
timer.Stop();
m_Table.Remove(m);
}
m.YellowHealthbar = false;

View file

@ -91,10 +91,9 @@ namespace Server.Items
public static void EndImmunity(Mobile m)
{
if (m_Table.TryGetValue(m, out var timer))
if (m_Table.Remove(m, out var timer))
{
timer?.Stop();
m_Table.Remove(m);
}
}

File diff suppressed because it is too large Load diff

View file

@ -71,11 +71,15 @@ namespace Server.Items
canSwing = !attacker.Paralyzed && !attacker.Frozen;
if (canSwing)
{
canSwing = !(attacker.Spell is Spell sp) || !sp.IsCasting || !sp.BlocksMovement;
}
}
if ((attacker as PlayerMobile)?.DuelContext?.CheckItemEquip(attacker, this) == false)
{
canSwing = false;
}
if (canSwing && attacker.HarmfulCheck(defender))
{
@ -85,9 +89,13 @@ namespace Server.Items
if (OnFired(attacker, defender))
{
if (CheckHit(attacker, defender))
{
OnHit(attacker, defender);
}
else
{
OnMiss(attacker, defender);
}
}
}
@ -105,7 +113,9 @@ namespace Server.Items
{
if (attacker.Player && !defender.Player && (defender.Body.IsAnimal || defender.Body.IsMonster) &&
Utility.RandomDouble() <= 0.4)
{
defender.AddToBackpack(Ammo);
}
if (Core.ML && m_Velocity > 0)
{
@ -116,10 +126,14 @@ namespace Server.Items
AOS.Damage(defender, attacker, bonus * 3, 100, 0, 0, 0, 0);
if (attacker.Player)
{
attacker.SendLocalizedMessage(1072794); // Your arrow hits its mark with velocity!
}
if (defender.Player)
{
defender.SendLocalizedMessage(1072795); // You have been hit by an arrow with velocity!
}
}
}
@ -136,17 +150,17 @@ namespace Server.Items
{
var ammo = AmmoType;
if (pm.RecoverableAmmo.ContainsKey(ammo))
pm.RecoverableAmmo[ammo]++;
else
pm.RecoverableAmmo.Add(ammo, 1);
pm.RecoverableAmmo.TryGetValue(ammo, out var result);
pm.RecoverableAmmo[ammo] = result + 1;
if (!pm.Warmode)
{
m_RecoveryTimer ??= Timer.DelayCall(TimeSpan.FromSeconds(10), pm.RecoverAmmo);
if (!m_RecoveryTimer.Running)
{
m_RecoveryTimer.Start();
}
}
}
}
@ -177,9 +191,13 @@ namespace Server.Items
{
// consume ammo
if (quiver?.ConsumeTotal(AmmoType) == true)
{
quiver.InvalidateWeight();
}
else if (pack?.ConsumeTotal(AmmoType) != true)
{
return false;
}
}
else if (quiver.FindItemByType(AmmoType) == null && pack?.FindItemByType(AmmoType) == null)
{

View file

@ -100,7 +100,7 @@ namespace Server
if (archer && from != null)
{
quiver = @from.FindItemOnLayer(Layer.Cloak) as BaseQuiver;
quiver = from.FindItemOnLayer(Layer.Cloak) as BaseQuiver;
}
int totalDamage;

View file

@ -66,9 +66,13 @@ namespace Server.Guilds
public void SetFlag(RankFlags flag, bool value)
{
if (value)
{
Flags |= flag;
}
else
{
Flags &= ~flag;
}
}
}
@ -89,8 +93,7 @@ namespace Server.Guilds
leader.Alliance = this;
partner.Alliance = this;
if (!Alliances.ContainsKey(Name.ToLower()))
Alliances.Add(Name.ToLower(), this);
Alliances.TryAdd(Name.ToLower(), this);
}
public AllianceInfo(IGenericReader reader)
@ -126,12 +129,16 @@ namespace Server.Guilds
set
{
if (m_Leader != value && value != null)
{
AllianceMessage(1070765, value.Name); // Your Alliance is now led by ~1_GUILDNAME~
}
m_Leader = value;
if (m_Leader == null)
{
CalculateAllianceLeader();
}
}
}
@ -147,14 +154,18 @@ namespace Server.Guilds
CalculateAllianceLeader();
if (m_Leader == null)
{
Disband();
}
}
}
public bool IsPendingMember(Guild g)
{
if (g.Alliance != this)
{
return false;
}
return m_PendingMembers.Contains(g);
}
@ -162,7 +173,9 @@ namespace Server.Guilds
public bool IsMember(Guild g)
{
if (g.Alliance != this)
{
return false;
}
return m_Members.Contains(g);
}
@ -177,14 +190,15 @@ namespace Server.Guilds
writer.WriteGuildList(m_Members, true);
writer.WriteGuildList(m_PendingMembers, true);
if (!Alliances.ContainsKey(Name.ToLower()))
Alliances.Add(Name.ToLower(), this);
Alliances.TryAdd(Name.ToLower(), this);
}
public void AddPendingGuild(Guild g)
{
if (g.Alliance != this || m_PendingMembers.Contains(g) || m_Members.Contains(g))
{
return;
}
m_PendingMembers.Add(g);
}
@ -192,7 +206,9 @@ namespace Server.Guilds
public void TurnToMember(Guild g)
{
if (g.Alliance != this || !m_PendingMembers.Contains(g) || m_Members.Contains(g))
{
return;
}
g.GuildMessage(1070760, Name); // Your Guild has joined the ~1_ALLIANCENAME~ Alliance.
AllianceMessage(1070761, g.Name); // A new Guild has joined your Alliance: ~1_GUILDNAME~
@ -204,7 +220,10 @@ namespace Server.Guilds
public void RemoveGuild(Guild g)
{
if (m_PendingMembers.Contains(g)) m_PendingMembers.Remove(g);
if (m_PendingMembers.Contains(g))
{
m_PendingMembers.Remove(g);
}
if (m_Members.Contains(g)) // Sanity, just incase someone with a custom script adds a character to BOTH arrays
{
@ -219,10 +238,15 @@ namespace Server.Guilds
// to check on OSI: have 3 guilds, make 2 of them a member, one pending. remove one of the memebers. alliance still exist?
// ANSWER: NO
if (g == m_Leader) CalculateAllianceLeader();
if (g == m_Leader)
{
CalculateAllianceLeader();
}
if (m_Members.Count < 2)
{
Disband();
}
}
public void Disband()
@ -230,13 +254,21 @@ namespace Server.Guilds
AllianceMessage(1070762); // Your Alliance has dissolved.
for (var i = 0; i < m_PendingMembers.Count; i++)
{
m_PendingMembers[i].Alliance = null;
}
for (var i = 0; i < m_Members.Count; i++)
{
m_Members[i].Alliance = null;
}
if (Alliances.TryGetValue(Name.ToLower(), out var aInfo) && aInfo == this)
Alliances.Remove(Name.ToLower());
var lowerName = Name.ToLower();
if (Alliances.TryGetValue(lowerName, out var aInfo) && aInfo == this)
{
Alliances.Remove(lowerName);
}
}
public void InvalidateMemberProperties(bool onlyOPL = false)
@ -252,7 +284,9 @@ namespace Server.Guilds
public void InvalidateMemberNotoriety()
{
for (var i = 0; i < m_Members.Count; i++)
{
m_Members[i].InvalidateMemberNotoriety();
}
}
public void AllianceMessage(int num, bool append, string format, params object[] args)
@ -263,19 +297,25 @@ namespace Server.Guilds
public void AllianceMessage(int number)
{
for (var i = 0; i < m_Members.Count; ++i)
{
m_Members[i].GuildMessage(number);
}
}
public void AllianceMessage(int number, string args, int hue = 0x3B2)
{
for (var i = 0; i < m_Members.Count; ++i)
{
m_Members[i].GuildMessage(number, args, hue);
}
}
public void AllianceMessage(int number, bool append, string affix, string args = "", int hue = 0x3B2)
{
for (var i = 0; i < m_Members.Count; ++i)
{
m_Members[i].GuildMessage(number, append, affix, args, hue);
}
}
public void AllianceTextMessage(string text)
@ -291,7 +331,9 @@ namespace Server.Guilds
public void AllianceTextMessage(int hue, string text)
{
for (var i = 0; i < m_Members.Count; ++i)
{
m_Members[i].GuildTextMessage(hue, text);
}
}
public void AllianceTextMessage(int hue, string format, params object[] args)
@ -383,7 +425,9 @@ namespace Server.Guilds
public override void OnResponse(NetState sender, RelayInfo info)
{
if (info.ButtonID != 8) // So that they can't get to the AdvancedSearch button
{
base.OnResponse(sender, info);
}
}
}
}
@ -451,23 +495,33 @@ namespace Server.Guilds
get
{
if (Opponent?.Disbanded != false)
{
return WarStatus.Win;
}
if (Guild?.Disbanded != false)
{
return WarStatus.Lose;
}
var w = Opponent.FindActiveWar(Guild);
if (Opponent.FindPendingWar(Guild) != null && Guild.FindPendingWar(Opponent) != null)
{
return WarStatus.Pending;
}
if (w == null)
{
return WarStatus.Win;
}
if (WarLength != TimeSpan.Zero && WarBeginning + WarLength < DateTime.UtcNow)
{
if (Kills > w.Kills)
{
return WarStatus.Win;
}
return Kills < w.Kills ? WarStatus.Lose : WarStatus.Draw;
}
@ -475,9 +529,14 @@ namespace Server.Guilds
if (MaxKills > 0)
{
if (Kills >= MaxKills)
{
return WarStatus.Win;
}
if (w.Kills >= w.MaxKills)
{
return WarStatus.Lose;
}
}
return WarStatus.InProgress;
@ -509,13 +568,17 @@ namespace Server.Guilds
public static void Initialize()
{
if (Guild.NewGuildSystem)
{
new WarTimer().Start();
}
}
protected override void OnTick()
{
foreach (var g in BaseGuild.List.Values)
{
(g as Guild)?.CheckExpiredWars();
}
}
}
@ -561,7 +624,9 @@ namespace Server.Guilds
AddMember(m_Leader);
if (m_Leader is PlayerMobile mobile)
{
mobile.GuildRank = RankDefinition.Leader;
}
AcceptedWars = new List<WarDeclaration>();
PendingWars = new List<WarDeclaration>();
@ -580,22 +645,30 @@ namespace Server.Guilds
get
{
if (Disbanded || m_Leader.Guild != this)
{
CalculateGuildmaster();
}
return m_Leader;
}
set
{
if (value != null)
{
AddMember(value); // Also removes from old guild.
}
if (m_Leader is PlayerMobile leader && leader.Guild == this)
{
leader.GuildRank = RankDefinition.Member;
}
m_Leader = value;
if (m_Leader is PlayerMobile mobile)
{
mobile.GuildRank = RankDefinition.Leader;
}
}
}
@ -606,7 +679,9 @@ namespace Server.Guilds
get
{
if (m_AllianceInfo != null)
{
return m_AllianceInfo;
}
return m_AllianceLeader?.m_AllianceInfo;
}
@ -615,16 +690,22 @@ namespace Server.Guilds
var current = Alliance;
if (value == current)
{
return;
}
current?.RemoveGuild(this);
if (value != null)
{
if (value.Leader == this)
{
m_AllianceInfo = value;
}
else
{
m_AllianceLeader = value.Leader;
}
value.AddPendingGuild(this);
}
@ -748,14 +829,18 @@ namespace Server.Guilds
m.InvalidateProperties();
if (!onlyOPL)
{
m.Delta(MobileDelta.Noto);
}
}
}
public void InvalidateMemberNotoriety()
{
for (var i = 0; i < Members?.Count; i++)
{
Members[i].Delta(MobileDelta.Noto);
}
}
public void InvalidateWarNotoriety()
@ -763,21 +848,31 @@ namespace Server.Guilds
var g = GetAllianceLeader(this);
if (g.Alliance != null)
{
g.Alliance.InvalidateMemberNotoriety();
}
else
{
g.InvalidateMemberNotoriety();
}
if (g.AcceptedWars == null)
{
return;
}
foreach (var warDec in g.AcceptedWars)
{
var opponent = warDec.Opponent;
if (opponent.Alliance != null)
{
opponent.Alliance.InvalidateMemberNotoriety();
}
else
{
opponent.InvalidateMemberNotoriety();
}
}
}
@ -797,7 +892,9 @@ namespace Server.Guilds
m.SendLocalizedMessage(502131); // Your guild has disbanded.
if (m is PlayerMobile mobile)
{
mobile.GuildRank = RankDefinition.Lowest;
}
m.Guild = null;
}
@ -805,15 +902,25 @@ namespace Server.Guilds
Members.Clear();
for (var i = Allies.Count - 1; i >= 0; --i)
{
if (i < Allies.Count)
{
RemoveAlly(Allies[i]);
}
}
for (var i = Enemies.Count - 1; i >= 0; --i)
{
if (i < Enemies.Count)
{
RemoveEnemy(Enemies[i]);
}
}
if (!NewGuildSystem)
{
Guildstone?.Delete();
}
Guildstone = null;
@ -846,7 +953,9 @@ namespace Server.Guilds
from.SendGump(new PropertiesGump(from, g));
if (NewGuildSystem && from.AccessLevel >= AccessLevel.GameMaster && from is PlayerMobile mobile)
{
mobile.SendGump(new GuildInfoGump(mobile, g));
}
}
}
}
@ -854,12 +963,18 @@ namespace Server.Guilds
public static void EventSink_GuildGumpRequest(Mobile m)
{
if (!NewGuildSystem || !(m is PlayerMobile pm))
{
return;
}
if (pm.Guild == null)
{
pm.SendGump(new CreateGuildGump(pm));
}
else
{
pm.SendGump(new GuildInfoGump(pm, pm.Guild as Guild));
}
}
public static void EventSink_CreateGuild(CreateGuildEventArgs args)
@ -872,7 +987,9 @@ namespace Server.Guilds
var alliance = g.Alliance;
if (alliance?.Leader != null && alliance.IsMember(g))
{
return alliance.Leader;
}
return g;
}
@ -884,7 +1001,9 @@ namespace Server.Guilds
var w = PendingWars[i];
if (w.Opponent == g)
{
return w;
}
}
return null;
@ -897,7 +1016,9 @@ namespace Server.Guilds
var w = AcceptedWars[i];
if (w.Opponent == g)
{
return w;
}
}
return null;
@ -942,10 +1063,14 @@ namespace Server.Guilds
AcceptedWars.Remove(w);
if (g == null)
{
continue;
}
if (status != WarStatus.Draw)
{
status = (WarStatus)((int)status + 1 % 2);
}
if (otherInAlliance)
{
@ -980,12 +1105,16 @@ namespace Server.Guilds
public static void HandleDeath(Mobile victim, Mobile killer = null)
{
if (!NewGuildSystem)
{
return;
}
killer ??= victim.FindMostRecentDamager(false);
if (killer?.Guild == null || victim.Guild == null)
{
return;
}
var victimGuild = GetAllianceLeader(victim.Guild as Guild);
var killerGuild = GetAllianceLeader(killer.Guild as Guild);
@ -993,14 +1122,20 @@ namespace Server.Guilds
var war = killerGuild.FindActiveWar(victimGuild);
if (war == null)
{
return;
}
war.Kills++;
if (war.Opponent == victimGuild)
{
killerGuild.CheckExpiredWars();
}
else
{
victimGuild.CheckExpiredWars();
}
}
public bool IsMember(Mobile m) => Members.Contains(m);
@ -1014,10 +1149,14 @@ namespace Server.Guilds
public bool IsWar(Guild g)
{
if (g == null)
{
return false;
}
if (!NewGuildSystem)
{
return Enemies.Contains(g);
}
var guild = GetAllianceLeader(this);
var otherGuild = GetAllianceLeader(g);
@ -1028,7 +1167,9 @@ namespace Server.Guilds
public override void Serialize(IGenericWriter writer)
{
if (LastFealty + TimeSpan.FromDays(1.0) < DateTime.UtcNow)
{
CalculateGuildmaster();
}
CheckExpiredWars();
@ -1038,19 +1179,29 @@ namespace Server.Guilds
writer.Write(PendingWars.Count);
for (var i = 0; i < PendingWars.Count; i++) PendingWars[i].Serialize(writer);
for (var i = 0; i < PendingWars.Count; i++)
{
PendingWars[i].Serialize(writer);
}
writer.Write(AcceptedWars.Count);
for (var i = 0; i < AcceptedWars.Count; i++) AcceptedWars[i].Serialize(writer);
for (var i = 0; i < AcceptedWars.Count; i++)
{
AcceptedWars[i].Serialize(writer);
}
var isAllianceLeader = m_AllianceLeader == null && m_AllianceInfo != null;
writer.Write(isAllianceLeader);
if (isAllianceLeader)
{
m_AllianceInfo.Serialize(writer);
}
else
{
writer.Write(m_AllianceLeader);
}
//
@ -1094,18 +1245,28 @@ namespace Server.Guilds
var count = reader.ReadInt();
PendingWars = new List<WarDeclaration>();
for (var i = 0; i < count; i++) PendingWars.Add(new WarDeclaration(reader));
for (var i = 0; i < count; i++)
{
PendingWars.Add(new WarDeclaration(reader));
}
count = reader.ReadInt();
AcceptedWars = new List<WarDeclaration>();
for (var i = 0; i < count; i++) AcceptedWars.Add(new WarDeclaration(reader));
for (var i = 0; i < count; i++)
{
AcceptedWars.Add(new WarDeclaration(reader));
}
var isAllianceLeader = reader.ReadBool();
if (isAllianceLeader)
{
m_AllianceInfo = new AllianceInfo(reader);
}
else
{
m_AllianceLeader = reader.ReadGuild() as Guild;
}
goto case 4;
}
@ -1139,7 +1300,9 @@ namespace Server.Guilds
m_Leader = reader.ReadMobile();
if (m_Leader is PlayerMobile mobile)
{
mobile.GuildRank = RankDefinition.Leader;
}
m_Name = reader.ReadString();
m_Abbreviation = reader.ReadString();
@ -1174,7 +1337,9 @@ namespace Server.Guilds
private void VerifyGuild_Callback()
{
if (!NewGuildSystem && Guildstone == null || Members.Count == 0)
{
Disband();
}
CheckExpiredWars();
@ -1186,7 +1351,9 @@ namespace Server.Guilds
if (alliance?.IsMember(this) == false && !alliance.IsPendingMember(this)
) // This block is there to fix a bug in the code in an older version.
{
Alliance = null; // Will call Alliance.RemoveGuild which will set it null & perform all the pertient checks as far as alliacne disbanding
}
}
public void AddMember(Mobile m)
@ -1194,7 +1361,9 @@ namespace Server.Guilds
if (!Members.Contains(m))
{
if (m.Guild != null && m.Guild != this)
{
((Guild)m.Guild).RemoveMember(m);
}
Members.Add(m);
m.Guild = this;
@ -1202,7 +1371,9 @@ namespace Server.Guilds
m.GuildFealty = !NewGuildSystem ? m_Leader : null;
if (m is PlayerMobile mobile)
{
mobile.GuildRank = RankDefinition.Lowest;
}
((Guild)m.Guild).InvalidateWarNotoriety();
}
@ -1219,21 +1390,29 @@ namespace Server.Guilds
m.Guild = null;
if (m is PlayerMobile mobile)
{
mobile.GuildRank = RankDefinition.Lowest;
}
if (message > 0)
{
m.SendLocalizedMessage(message);
}
if (m == m_Leader)
{
CalculateGuildmaster();
if (m_Leader == null)
{
Disband();
}
}
if (Members.Count == 0)
{
Disband();
}
guild?.InvalidateWarNotoriety();
@ -1289,19 +1468,25 @@ namespace Server.Guilds
public void GuildMessage(int number)
{
for (var i = 0; i < Members.Count; ++i)
{
Members[i].SendLocalizedMessage(number);
}
}
public void GuildMessage(int number, string args, int hue = 0x3B2)
{
for (var i = 0; i < Members.Count; ++i)
{
Members[i].SendLocalizedMessage(number, args, hue);
}
}
public void GuildMessage(int number, bool append, string affix, string args = "", int hue = 0x3B2)
{
for (var i = 0; i < Members.Count; ++i)
{
Members[i].SendLocalizedMessage(number, append, affix, args, hue);
}
}
public void GuildTextMessage(string text)
@ -1317,7 +1502,9 @@ namespace Server.Guilds
public void GuildTextMessage(int hue, string text)
{
for (var i = 0; i < Members.Count; ++i)
{
Members[i].SendMessage(hue, text);
}
}
public void GuildTextMessage(int hue, string format, params object[] args)
@ -1371,20 +1558,28 @@ namespace Server.Guilds
var memb = Members[i];
if (!CanVote(memb))
{
continue;
}
var m = memb.GuildFealty;
if (!CanBeVotedFor(m))
{
if (!Disbanded && m_Leader.Guild == this)
{
m = m_Leader;
}
else
{
m = memb;
}
}
if (m == null)
{
continue;
}
votes[m] = 1 + (votes.TryGetValue(m, out var v) ? v : 0);
votingMembers++;
@ -1407,10 +1602,14 @@ namespace Server.Guilds
if (NewGuildSystem && highVotes * 100 / Math.Max(votingMembers, 1) < MajorityPercentage && !Disbanded &&
winner != m_Leader && m_Leader.Guild == this)
{
winner = m_Leader;
}
if (m_Leader != winner && winner != null)
{
GuildMessage(1018015, true, winner.Name); // Guild Message: Guildmaster changed to:
}
Leader = winner;
LastFealty = DateTime.UtcNow;
@ -1456,7 +1655,9 @@ namespace Server.Guilds
from.SendGump(new PropertiesGump(from, g));
if (NewGuildSystem && from.AccessLevel >= AccessLevel.GameMaster && from is PlayerMobile pm)
{
pm.SendGump(new GuildInfoGump(pm, g));
}
}
}
}

View file

@ -288,7 +288,9 @@ namespace Server.Misc
m_Keywords = value;
m_KeywordHash = new Dictionary<string, string>(m_Keywords.Length, StringComparer.OrdinalIgnoreCase);
for (var i = 0; i < m_Keywords.Length; ++i)
{
m_KeywordHash[m_Keywords[i]] = m_Keywords[i];
}
}
}
@ -307,7 +309,9 @@ namespace Server.Misc
var syllables = new string[syllableCount];
for (var i = 0; i < syllableCount; ++i)
{
syllables[i] = GetRandomSyllable();
}
return string.Concat(syllables);
}
@ -333,33 +337,47 @@ namespace Server.Misc
needUpperCase = true;
if (random > 13)
{
sentance.Append("! ");
}
else
{
sentance.Append(". ");
}
}
}
int syllableCount;
if (Utility.Random(100) < 30)
{
syllableCount = Utility.Random(1, 5);
}
else
{
syllableCount = Utility.Random(1, 3);
}
var word = ConstructWord(syllableCount);
sentance.Append(word);
if (needUpperCase)
{
sentance.Replace(word[0], char.ToUpper(word[0]), sentance.Length - word.Length, 1);
}
needUpperCase = false;
}
if (Utility.RandomMinMax(1, 5) == 1)
{
sentance.Append('!');
}
else
{
sentance.Append('.');
}
return sentance.ToString();
}
@ -380,35 +398,53 @@ namespace Server.Misc
public bool OnSpeech(Mobile mob, Mobile speaker, string text)
{
if ((Flags & IHSFlags.OnSpeech) == 0 || m_Keywords == null || Responses == null || m_KeywordHash == null)
{
return false; // not enabled
}
if (!speaker.Alive)
{
return false;
}
if (!speaker.InRange(mob, 3))
{
return false;
}
if ((speaker.Direction & Direction.Mask) != speaker.GetDirectionTo(mob))
{
return false;
}
if ((mob.Direction & Direction.Mask) != mob.GetDirectionTo(speaker))
{
return false;
}
var split = text.Split(' ');
var keywordsFound = new List<string>();
for (var i = 0; i < split.Length; ++i)
{
if (m_KeywordHash.TryGetValue(split[i], out var keyword))
{
keywordsFound.Add(keyword);
}
}
if (keywordsFound.Count > 0)
{
string responseWord;
if (Utility.RandomBool())
{
responseWord = GetRandomResponseWord(keywordsFound);
}
else
{
responseWord = keywordsFound.RandomElement();
}
var secondResponseWord = GetRandomResponseWord(keywordsFound);
@ -469,9 +505,13 @@ namespace Server.Misc
var maxWords = split.Length / 2 + 1;
if (maxWords < 2)
{
maxWords = 2;
}
else if (maxWords > 6)
{
maxWords = 6;
}
SaySentance(mob, Utility.RandomMinMax(2, maxWords));
mob.Say(response.ToString());
@ -485,10 +525,14 @@ namespace Server.Misc
public void OnDeath(Mobile mob)
{
if ((Flags & IHSFlags.OnDeath) == 0)
{
return; // not enabled
}
if (Utility.Random(100) < 90)
{
return; // 90% chance to do nothing; 10% chance to talk
}
SayRandomTranslate(
mob,
@ -506,16 +550,24 @@ namespace Server.Misc
public void OnMovement(Mobile mob, Mobile mover, Point3D oldLocation)
{
if ((Flags & IHSFlags.OnMovement) == 0)
{
return; // not enabled
}
if (!mover.Player || mover.Hidden && mover.AccessLevel > AccessLevel.Player)
{
return;
}
if (!mob.InRange(mover, 5) || mob.InRange(oldLocation, 5))
{
return; // only talk when they enter 5 tile range
}
if (Utility.Random(100) < 90)
{
return; // 90% chance to do nothing; 10% chance to talk
}
SaySentance(mob, 6);
}
@ -523,12 +575,17 @@ namespace Server.Misc
public void OnDamage(Mobile mob, int amount)
{
if ((Flags & IHSFlags.OnDamaged) == 0)
{
return; // not enabled
}
if (Utility.Random(100) < 90)
{
return; // 90% chance to do nothing; 10% chance to talk
}
if (amount < 5)
{
SayRandomTranslate(
mob,
"Ouch!",
@ -537,7 +594,9 @@ namespace Server.Misc
"Thy blows soft!",
"You bad with weapon!"
);
}
else
{
SayRandomTranslate(
mob,
"Ouch! Me hurt!",
@ -548,6 +607,7 @@ namespace Server.Misc
"Aaah! That hurt...",
"Good blow!"
);
}
}
public void OnConstruct(Mobile mob)

View file

@ -179,7 +179,7 @@ namespace Server
if (m_Table == null)
LoadTable();
return m_Table.ContainsKey(obj.GetType());
return m_Table!.ContainsKey(obj.GetType());
}
public static bool GetSpeeds(object obj, ref double activeSpeed, ref double passiveSpeed)
@ -190,7 +190,7 @@ namespace Server
if (m_Table == null)
LoadTable();
if (!m_Table.TryGetValue(obj.GetType(), out var sp))
if (!m_Table!.TryGetValue(obj.GetType(), out var sp))
return false;
activeSpeed = sp.ActiveSpeed;

View file

@ -146,7 +146,7 @@ namespace Server.Mobiles
public static void StopEffect(Mobile m, bool message)
{
if (m_Table.TryGetValue(m, out var timer))
if (m_Table.Remove(m, out var timer))
{
if (message)
m.PublicOverheadMessage(
@ -157,7 +157,6 @@ namespace Server.Mobiles
);
timer.Stop();
m_Table.Remove(m);
}
}

View file

@ -120,10 +120,9 @@ namespace Server.Mobiles
public static void EndLifeDrain(Mobile m)
{
if (m_Table.TryGetValue(m, out var timer))
if (m_Table.Remove(m, out var timer))
{
timer?.Stop();
m_Table.Remove(m);
m.SendLocalizedMessage(1070849); // The drain on your life force is gone.
}
}

View file

@ -1050,7 +1050,7 @@ namespace Server.Mobiles
if (from.UseSkill(skillId))
{
@from.Target?.Invoke(@from, target);
from.Target?.Invoke(from, target);
}
if (skillId == 35)
@ -1294,7 +1294,7 @@ namespace Server.Mobiles
if (from.NetState != null)
{
Timer.DelayCall(TimeSpan.FromSeconds(1.0), @from.NetState.Dispose);
Timer.DelayCall(TimeSpan.FromSeconds(1.0), from.NetState.Dispose);
}
}
else if (from.AccessLevel >= AccessLevel.Administrator)
@ -1470,11 +1470,11 @@ namespace Server.Mobiles
if (armor is BaseShield)
{
@from.SendLocalizedMessage(1062003, name); // You can no longer equip your ~1_SHIELD~
from.SendLocalizedMessage(1062003, name); // You can no longer equip your ~1_SHIELD~
}
else
{
@from.SendLocalizedMessage(1062002, name); // You can no longer wear your ~1_ARMOR~
from.SendLocalizedMessage(1062002, name); // You can no longer wear your ~1_ARMOR~
}
from.AddToBackpack(armor);
@ -1547,7 +1547,7 @@ namespace Server.Mobiles
if (moved)
{
@from.SendLocalizedMessage(500647); // Some equipment has been moved to your backpack.
from.SendLocalizedMessage(500647); // Some equipment has been moved to your backpack.
}
}
catch (Exception e)
@ -2011,7 +2011,7 @@ namespace Server.Mobiles
{
if (Core.TOL && from.InRange(this, 2))
{
list.Add(new CallbackEntry(1077728, () => OpenTrade(@from))); // Trade
list.Add(new CallbackEntry(1077728, () => OpenTrade(from))); // Trade
}
if (Alive && Core.Expansion >= Expansion.AOS)
@ -2027,11 +2027,11 @@ namespace Server.Mobiles
{
if (ourParty == null)
{
list.Add(new AddToPartyEntry(@from, this));
list.Add(new AddToPartyEntry(from, this));
}
else if (ourParty == theirParty)
{
list.Add(new RemoveFromPartyEntry(@from, this));
list.Add(new RemoveFromPartyEntry(from, this));
}
}
}
@ -2041,7 +2041,7 @@ namespace Server.Mobiles
if (curhouse != null && Alive && Core.Expansion >= Expansion.AOS && curhouse.IsAosRules &&
curhouse.IsFriend(from))
{
list.Add(new EjectPlayerEntry(@from, this));
list.Add(new EjectPlayerEntry(from, this));
}
}
}
@ -2902,11 +2902,11 @@ namespace Server.Mobiles
if (Core.ML)
{
@from.Damage((int)(amount * (1 - (@from.Skills.MagicResist.Value * .5 + 10) / 100)), this);
from.Damage((int)(amount * (1 - (from.Skills.MagicResist.Value * .5 + 10) / 100)), this);
}
else
{
@from.Damage(amount, this);
from.Damage(amount, this);
}
}
@ -2916,7 +2916,7 @@ namespace Server.Mobiles
{
var type = talisman.Protection.Type;
if (type.IsInstanceOfType(@from))
if (type.IsInstanceOfType(from))
{
amount = (int)(amount * (1 - (double)talisman.Protection.Amount / 100));
}
@ -4188,7 +4188,7 @@ namespace Server.Mobiles
if (from != null && result == ApplyPoisonResult.Poisoned && PoisonTimer is PoisonImpl.PoisonTimer timer)
{
timer.From = @from;
timer.From = from;
}
return result;
@ -4207,7 +4207,7 @@ namespace Server.Mobiles
}
else
{
base.OnPoisonImmunity(@from, poison);
base.OnPoisonImmunity(from, poison);
}
}
@ -4685,20 +4685,16 @@ namespace Server.Mobiles
public void RemoveBuff(BuffIcon b)
{
if (m_BuffTable?.ContainsKey(b) != true)
if (!m_BuffTable.Remove(b, out var info))
{
return;
}
var info = m_BuffTable[b];
if (info.Timer?.Running == true)
{
info.Timer.Stop();
}
m_BuffTable.Remove(b);
if (NetState?.BuffIcon == true)
{
NetState.Send(new RemoveBuffPacket(this, b));

View file

@ -149,11 +149,13 @@ namespace Server.Mobiles
var okay = true;
foreach (var obj in quest.Objectives)
{
if (obj is EscortObjective objective && objective.Destination.Contains(reg))
{
okay = false; // We're already there!
break;
}
}
if (okay)
{
@ -175,7 +177,9 @@ namespace Server.Mobiles
if (m_MLQuest == null)
{
if (MLQuestSystem.Debug)
{
Console.WriteLine("Warning: No suitable quest found for escort {0}", Serial);
}
return null;
}
@ -232,7 +236,9 @@ namespace Server.Mobiles
var dest = GetDestination();
if (dest == null || !m.Alive)
{
return false;
}
var escorter = GetEscorter();
@ -262,10 +268,14 @@ namespace Server.Mobiles
var dest = GetDestination();
if (dest == null)
{
return false;
}
if (GetEscorter() != null || !m.Alive)
{
return false;
}
if (EscortTable.TryGetValue(m, out var escortable) && escortable?.Deleted == false &&
escortable.GetEscorter() == m)
@ -288,7 +298,9 @@ namespace Server.Mobiles
m_LastSeenEscorter = DateTime.UtcNow;
if (m is PlayerMobile playerMobile)
{
playerMobile.LastEscortTime = DateTime.UtcNow;
}
Say(
"Lead on! Payment will be made when we arrive in {0}.",
@ -310,12 +322,18 @@ namespace Server.Mobiles
base.OnSpeech(e);
if (GetDestination() == null || e.Handled || !e.Mobile.InRange(Location, 3))
{
return;
}
if (e.HasKeyword(0x1D)) // *destination*
{
e.Handled = SayDestinationTo(e.Mobile);
}
else if (e.HasKeyword(0x1E)) // *i will take thee*
{
e.Handled = AcceptEscorter(e.Mobile);
}
}
public override void OnAfterDelete()
@ -336,7 +354,9 @@ namespace Server.Mobiles
protected override bool OnMove(Direction d)
{
if (!base.OnMove(d))
{
return false;
}
CheckAtDestination();
@ -353,7 +373,9 @@ namespace Server.Mobiles
public virtual void StartFollow(Mobile escorter)
{
if (escorter == null)
{
return;
}
ActiveSpeed = 0.1;
PassiveSpeed = 0.2;
@ -361,7 +383,11 @@ namespace Server.Mobiles
ControlOrder = OrderType.Follow;
ControlTarget = escorter;
if (IsPrisoner && CantWalk) CantWalk = false;
if (IsPrisoner && CantWalk)
{
CantWalk = false;
}
CurrentSpeed = 0.1;
}
@ -379,12 +405,16 @@ namespace Server.Mobiles
public virtual Mobile GetEscorter()
{
if (!Controlled)
{
return null;
}
var master = ControlMaster;
if (MLQuestSystem.Enabled || master == null)
{
return master;
}
if (master.Deleted || master.Map != Map || !master.InRange(Location, 30) || !master.Alive)
{
@ -409,7 +439,9 @@ namespace Server.Mobiles
}
if (ControlOrder != OrderType.Follow)
{
StartFollow(master);
}
m_LastSeenEscorter = DateTime.UtcNow;
return master;
@ -428,17 +460,23 @@ namespace Server.Mobiles
public virtual bool CheckAtDestination()
{
if (MLQuestSystem.Enabled)
{
return false;
}
var dest = GetDestination();
if (dest == null)
{
return false;
}
var escorter = GetEscorter();
if (escorter == null)
{
return false;
}
if (dest.Contains(Location))
{
@ -456,7 +494,9 @@ namespace Server.Mobiles
var gold = new Gold(500, 1000);
if (!cont.TryDropItem(escorter, gold, false))
{
gold.MoveToWorld(escorter.Location, escorter.Map);
}
StopFollow();
SetControlMaster(null);
@ -484,18 +524,24 @@ namespace Server.Mobiles
else if (VirtueHelper.Award(pm, VirtueName.Compassion, IsPrisoner ? 400 : 200, ref gainedPath))
{
if (gainedPath)
{
pm.SendLocalizedMessage(1053005); // You have achieved a path in compassion!
}
else
{
pm.SendLocalizedMessage(1053002); // You have gained in compassion.
}
pm.NextCompassionDay =
DateTime.UtcNow + TimeSpan.FromDays(1.0); // in one day CompassionGains gets reset to 0
++pm.CompassionGains;
if (pm.CompassionGains >= 5)
{
pm.SendLocalizedMessage(
1053004
); // You must wait about a day before you can gain in compassion again.
}
}
else
{
@ -529,12 +575,16 @@ namespace Server.Mobiles
writer.Write(dest != null);
if (dest != null)
{
writer.Write(dest.Name);
}
writer.Write(m_DeleteTimer != null);
if (m_DeleteTimer != null)
{
writer.WriteDeltaTime(m_DeleteTime);
}
MLQuestSystem.WriteQuestRef(writer, StaticMLQuester ? null : m_MLQuest);
}
@ -546,8 +596,10 @@ namespace Server.Mobiles
var version = reader.ReadInt();
if (reader.ReadBool())
{
m_DestinationString =
reader.ReadString(); // NOTE: We cannot EDI.Find here, regions have not yet been loaded :-(
}
if (reader.ReadBool())
{
@ -561,7 +613,9 @@ namespace Server.Mobiles
var quest = MLQuestSystem.ReadQuestRef(reader);
if (MLQuestSystem.Enabled && quest != null && !StaticMLQuester)
{
m_MLQuest = quest;
}
}
}
@ -576,14 +630,20 @@ namespace Server.Mobiles
if (!MLQuestSystem.Enabled && GetDestination() != null)
{
if (escorter == null || escorter == from)
{
list.Add(new AskDestinationEntry(this, from));
}
if (escorter == null)
{
list.Add(new AcceptEscortEntry(this, from));
}
}
if (escorter == from)
{
list.Add(new AbandonEscortEntry(this));
}
}
base.AddCustomContextEntries(from, list);
@ -594,7 +654,9 @@ namespace Server.Mobiles
public virtual string PickRandomDestination()
{
if (Map.Felucca.Regions.Count == 0 || Map == null || Map == Map.Internal || Location == Point3D.Zero)
{
return null; // Not yet fully initialized
}
var possible = GetPossibleDestinations();
string picked = null;
@ -605,7 +667,9 @@ namespace Server.Mobiles
var test = EDI.Find(picked);
if (test.Contains(Location))
{
picked = null;
}
}
return picked;
@ -614,16 +678,24 @@ namespace Server.Mobiles
public EDI GetDestination()
{
if (MLQuestSystem.Enabled)
{
return null;
}
if (m_DestinationString == null && m_DeleteTimer == null)
{
m_DestinationString = PickRandomDestination();
}
if (m_Destination != null && m_Destination.Name == m_DestinationString)
{
return m_Destination;
}
if (Map.Felucca.Regions.Count > 0)
{
return m_Destination = EDI.Find(m_DestinationString);
}
return m_Destination = null;
}
@ -668,22 +740,32 @@ namespace Server.Mobiles
ICollection list = Map.Felucca.Regions.Values;
if (list.Count == 0)
{
return;
}
m_Table = new Dictionary<string, EscortDestinationInfo>();
foreach (Region r in list)
{
if (r.Name != null && (r is DungeonRegion || r is TownRegion))
{
m_Table[r.Name] = new EscortDestinationInfo(r.Name, r);
}
}
}
public static EDI Find(string name)
{
if (m_Table == null)
{
LoadTable();
}
if (name == null || m_Table == null)
{
return null;
}
m_Table.TryGetValue(name, out var info);
return info;

View file

@ -68,10 +68,15 @@ namespace Server.Multis
{
base.OnAfterDelete();
if (Fixtures == null) return;
if (Fixtures == null)
{
return;
}
foreach (var item in Fixtures)
{
item.Delete();
}
}
public override void OnLocationChange(Point3D oldLocation)
@ -82,20 +87,30 @@ namespace Server.Multis
var y = Location.Y - oldLocation.Y;
var z = Location.Z - oldLocation.Z;
if (Fixtures == null) return;
if (Fixtures == null)
{
return;
}
foreach (var item in Fixtures)
{
item.Location = new Point3D(item.X + x, item.Y + y, item.Z + z);
}
}
public override void OnMapChange()
{
base.OnMapChange();
if (Fixtures == null) return;
if (Fixtures == null)
{
return;
}
foreach (var item in Fixtures)
{
item.Map = Map;
}
}
public void AddTeleporters(int id, Point3D offset1, Point3D offset2)
@ -131,12 +146,17 @@ namespace Server.Multis
foreach (var entry in components.List.Where(e => e.Flags == 0))
// Teleporters
{
if (entry.ItemId >= 0x181D && entry.ItemId <= 0x1828)
{
if (teleporters.ContainsKey(entry.ItemId))
teleporters[entry.ItemId].Add(entry);
if (teleporters.TryGetValue(entry.ItemId, out var result))
{
result.Add(entry);
}
else
teleporters[entry.ItemId] = new List<MultiTileEntry> { entry };
{
teleporters.Add(entry.ItemId, new List<MultiTileEntry> { entry });
}
}
else
{
@ -155,14 +175,19 @@ namespace Server.Multis
AddFixture(st);
}
}
}
foreach (var door in Doors)
{
foreach (var check in Doors.Where(d => d != door))
{
if (door.InRange(check.Location, 1))
{
door.Link = check;
check.Link = door;
}
}
}
foreach (var (key, value) in teleporters)
{
@ -195,9 +220,13 @@ namespace Server.Multis
writer.Write((int)HouseType);
if (Fixtures != null)
{
writer.WriteItemList(Fixtures, true);
}
else
{
writer.Write(0);
}
}
public override void Deserialize(IGenericReader reader)
@ -210,7 +239,9 @@ namespace Server.Multis
var count = reader.ReadInt();
for (var i = 0; i < count; i++)
{
AddFixture(reader.ReadItem());
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -311,10 +311,9 @@ namespace Server.Regions
if (IsGuardCandidate(m) &&
(!AllowReds && m.Kills >= 5 && m.Region.IsPartOf(this) || m_GuardCandidates.ContainsKey(m)))
{
if (m_GuardCandidates.TryGetValue(m, out var timer))
if (m_GuardCandidates.Remove(m, out var timer))
{
timer.Stop();
m_GuardCandidates.Remove(m);
}
MakeGuard(m);

View file

@ -36,16 +36,16 @@ namespace Server.SkillHandlers
public static double GetStalkingBonus(Mobile tracker, Mobile target)
{
if (!m_Table.TryGetValue(tracker, out var info) || info.m_Target != target || info.m_Map != target.Map)
if (!m_Table.Remove(tracker, out var info) || info.m_Target != target || info.m_Map != target.Map)
{
return 0.0;
}
var xDelta = info.m_Location.X - target.X;
var yDelta = info.m_Location.Y - target.Y;
var bonus = Math.Sqrt(xDelta * xDelta + yDelta * yDelta);
m_Table.Remove(tracker); // Reset as of Pub 40, counting it as bug for Core.SE.
return Core.ML ? Math.Min(bonus, 10 + tracker.Skills.Tracking.Value / 10) : bonus;
}
@ -108,7 +108,9 @@ namespace Server.SkillHandlers
public override void OnResponse(NetState state, RelayInfo info)
{
if (info.ButtonID >= 1 && info.ButtonID <= 4)
{
TrackWhoGump.DisplayTo(m_Success, m_From, info.ButtonID - 1);
}
}
}
@ -166,7 +168,9 @@ namespace Server.SkillHandlers
AddButton(20 + i % 4 * 100, 130 + i / 4 * 155, 4005, 4007, i + 1);
if (m.Name != null)
{
AddHtml(20 + i % 4 * 100, 90 + i / 4 * 155, 90, 40, m.Name);
}
}
}
@ -181,7 +185,9 @@ namespace Server.SkillHandlers
var map = from.Map;
if (map == null)
{
return;
}
var check = m_Delegates[type];
@ -207,11 +213,17 @@ namespace Server.SkillHandlers
else
{
if (type == 0)
{
from.SendLocalizedMessage(502991); // You see no evidence of animals in the area.
}
else if (type == 1)
{
from.SendLocalizedMessage(502993); // You see no evidence of creatures in the area.
}
else
{
from.SendLocalizedMessage(502995); // You see no evidence of people in the area.
}
}
}
@ -219,13 +231,17 @@ namespace Server.SkillHandlers
private static bool CheckDifficulty(Mobile from, Mobile m)
{
if (!Core.AOS || !m.Player)
{
return true;
}
var tracking = from.Skills.Tracking.Fixed;
var detectHidden = from.Skills.DetectHidden.Fixed;
if (Core.ML && m.Race == Race.Elf)
{
tracking /= 2; // The 'Guide' says that it requires twice as Much tracking SKILL to track an elf. Not the total difficulty to track.
}
var hiding = m.Skills.Hiding.Fixed;
var stealth = m.Skills.Stealth.Fixed;
@ -233,19 +249,29 @@ namespace Server.SkillHandlers
// Necromancy forms affect tracking difficulty
if (TransformationSpellHelper.UnderTransformation(m, typeof(HorrificBeastSpell)))
{
divisor -= 200;
}
else if (TransformationSpellHelper.UnderTransformation(m, typeof(VampiricEmbraceSpell)) && divisor < 500)
{
divisor = 500;
}
else if (TransformationSpellHelper.UnderTransformation(m, typeof(WraithFormSpell)) && divisor <= 2000)
{
divisor += 200;
}
int chance;
if (divisor > 0)
{
if (Core.SE)
{
chance = 50 * (tracking * 2 + detectHidden) / divisor;
}
else
{
chance = 50 * (tracking + detectHidden + 10 * Utility.RandomMinMax(1, 20)) / divisor;
}
}
else
{
@ -274,7 +300,9 @@ namespace Server.SkillHandlers
m_From.QuestArrow = new TrackArrow(m_From, m, m_Range * 2);
if (Core.SE)
{
Tracking.AddInfo(m_From, m);
}
}
}
@ -287,11 +315,19 @@ namespace Server.SkillHandlers
public int Compare(Mobile x, Mobile y)
{
if (x == null && y == null)
{
return 0;
}
if (x == null)
{
return -1;
}
if (y == null)
{
return 1;
}
return m_From.GetDistanceToSqrt(x).CompareTo(m_From.GetDistanceToSqrt(y));
}

View file

@ -34,33 +34,37 @@ namespace Server.Misc
m_MoveHistory = new Dictionary<Mobile, LocationInfo>();
if (Enabled)
{
EventSink.Login += OnLogin;
}
}
public static void OnLogin(Mobile from)
{
if (from == null || from.AccessLevel < AccessLevel.Counselor)
{
return;
}
if (HasDisconnected(from))
{
if (!m_MoveHistory.ContainsKey(from))
{
m_MoveHistory[from] = new LocationInfo(from.Location, from.Map);
}
var dest = GetRandomDestination();
from.Location = dest.Location;
from.Map = dest.Map;
}
else if (m_MoveHistory.TryGetValue(from, out var orig))
else if (m_MoveHistory.Remove(from, out var orig))
{
from.SendMessage(
"Your character was moved from {0} ({1}) due to a detected client crash.",
orig.Location,
orig.Map
);
m_MoveHistory.Remove(from);
}
}

View file

@ -82,7 +82,9 @@ namespace Server.Spells
var scalar = 1.0;
if (!MindRotSpell.GetMindRotScalar(m, ref scalar))
{
scalar = 1.0;
}
// Lower Mana Cost = 40%
var lmc = Math.Min(AosAttributes.GetValue(m, AosAttribute.LowerManaCost), 40);
@ -92,7 +94,9 @@ namespace Server.Spells
var total = (int)(mana * scalar);
if (m.Skills[MoveSkill].Value < 50.0 && GetContext(m) != null)
{
total *= 2;
}
return total;
}
@ -113,7 +117,9 @@ namespace Server.Spells
if (consume)
{
if (!DelayedContext)
{
SetContext(from);
}
from.Mana -= mana;
}
@ -124,6 +130,7 @@ namespace Server.Spells
public virtual void SetContext(Mobile from)
{
if (GetContext(from) == null)
{
if (DelayedContext || from.Skills[MoveSkill].Value < 50.0)
{
Timer timer = new SpecialMoveTimer(from);
@ -131,12 +138,15 @@ namespace Server.Spells
AddContext(from, new SpecialMoveContext(timer, GetType()));
}
}
}
public virtual bool Validate(Mobile from)
{
if (!from.Player)
{
return true;
}
if (HonorableExecution.IsUnderPenalty(from))
{
@ -153,24 +163,42 @@ namespace Server.Spells
string option = null;
if (this is Backstab)
{
option = "Backstab";
}
else if (this is DeathStrike)
{
option = "Death Strike";
}
else if (this is FocusAttack)
{
option = "Focus Attack";
}
else if (this is KiAttack)
{
option = "Ki Attack";
}
else if (this is SurpriseAttack)
{
option = "Surprise Attack";
}
else if (this is HonorableExecution)
{
option = "Honorable Execution";
}
else if (this is LightningStrike)
{
option = "Lightning Strike";
}
else if (this is MomentumStrike)
{
option = "Momentum Strike";
}
if (option != null && !DuelContext.AllowSpecialMove(from, option, this))
{
return false;
}
return CheckSkills(from) && CheckMana(from, false);
}
@ -187,14 +215,18 @@ namespace Server.Spells
var moveID = kvp.Key;
if (moveID != -1)
{
m.Send(new ToggleSpecialAbility(moveID + 1, false));
}
}
}
public static SpecialMove GetCurrentMove(Mobile m)
{
if (m == null)
{
return null;
}
if (!Core.SE)
{
@ -230,7 +262,9 @@ namespace Server.Spells
ClearCurrentMove(m);
if (sameMove)
{
return true;
}
if (move != null)
{
@ -243,7 +277,9 @@ namespace Server.Spells
var moveID = SpellRegistry.GetRegistryNumber(move);
if (moveID > 0)
{
m.Send(new ToggleSpecialAbility(moveID + 1, true));
}
TextDefinition.SendMessageTo(m, move.AbilityMessage);
}
@ -253,17 +289,17 @@ namespace Server.Spells
public static void ClearCurrentMove(Mobile m)
{
if (Table.TryGetValue(m, out var move))
if (Table.Remove(m, out var move))
{
move.OnClearMove(m);
var moveID = SpellRegistry.GetRegistryNumber(move);
if (moveID > 0)
{
m.Send(new ToggleSpecialAbility(moveID + 1, false));
}
}
Table.Remove(m);
}
private static void AddContext(Mobile m, SpecialMoveContext context)

View file

@ -86,7 +86,9 @@ namespace Server.Spells
// Confirm: Monsters and pets cannot be disturbed.
if (Caster.Player && IsCasting && ProtectionSpell.Registry.TryGetValue(Caster, out var d) &&
d <= Utility.RandomDouble() * 100.0)
{
Disturb(DisturbType.Hurt, false, true);
}
}
public virtual void OnCasterKilled()
@ -113,7 +115,9 @@ namespace Server.Spells
public virtual bool OnCasterEquipping(Item item)
{
if (IsCasting)
{
Disturb(DisturbType.EquipRequest);
}
return true;
}
@ -121,7 +125,9 @@ namespace Server.Spells
public virtual bool OnCasterUsingObject(IEntity entity)
{
if (State == SpellState.Sequencing)
{
Disturb(DisturbType.UseRequest);
}
return true;
}
@ -133,16 +139,22 @@ namespace Server.Spells
State = SpellState.None;
if (Caster.Spell == this)
{
Caster.Spell = null;
}
}
public void StartDelayedDamageContext(Mobile m, Timer t)
{
if (DelayedDamageStacking)
{
return; // Sanity
}
if (!m_ContextTable.TryGetValue(GetType(), out var contexts))
{
m_ContextTable[GetType()] = contexts = new DelayedDamageContextWrapper();
}
contexts.Add(m, t);
}
@ -150,7 +162,9 @@ namespace Server.Spells
public void RemoveDelayedDamageContext(Mobile m)
{
if (m_ContextTable.TryGetValue(GetType(), out var contexts))
{
contexts.Remove(m);
}
}
public void HarmfulSpell(Mobile m)
@ -161,6 +175,7 @@ namespace Server.Spells
public virtual int GetNewAosDamage(int bonus, uint dice, uint sides, Mobile singleTarget)
{
if (singleTarget != null)
{
return GetNewAosDamage(
bonus,
dice,
@ -168,6 +183,7 @@ namespace Server.Spells
Caster.Player && singleTarget.Player,
GetDamageScalar(singleTarget)
);
}
return GetNewAosDamage(bonus, dice, sides, false);
}
@ -189,14 +205,18 @@ namespace Server.Spells
var sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage);
// PvP spell damage increase cap of 15% from an item<65>s magic property
if (playerVsPlayer && sdiBonus > 15)
{
sdiBonus = 15;
}
damageBonus += sdiBonus;
var context = TransformationSpellHelper.GetContext(Caster);
if (context?.Spell is ReaperFormSpell spell)
{
damageBonus += spell.SpellDamageBonus;
}
damage = AOS.Scale(damage, 100 + damageBonus);
@ -242,15 +262,21 @@ namespace Server.Spells
// m_Caster.CheckSkill( DamageSkill, 0.0, 120.0 );
if (casterEI > targetRS)
{
scalar = 1.0 + (casterEI - targetRS) / 500.0;
}
else
{
scalar = 1.0 + (casterEI - targetRS) / 200.0;
}
// magery damage bonus, -25% at 0 skill, +0% at 100 skill, +5% at 120 skill
scalar += (Caster.Skills[CastSkill].Value - 100.0) / 400.0;
if (!target.Player && !target.Body.IsHuman /*&& !Core.AOS*/)
{
scalar *= 2.0; // Double magery damage to monsters/animals if not AOS
}
}
(target as BaseCreature)?.AlterDamageScalarFrom(Caster, ref scalar);
@ -258,12 +284,16 @@ namespace Server.Spells
(Caster as BaseCreature)?.AlterDamageScalarTo(target, ref scalar);
if (Core.SE)
{
scalar *= GetSlayerDamageScalar(target);
}
target.Region.SpellDamageScalar(Caster, target, ref scalar);
if (Evasion.CheckSpellEvasion(target)) // Only single target spells an be evaded
{
scalar = 0;
}
return scalar;
}
@ -288,10 +318,14 @@ namespace Server.Spells
if ((atkBook.Slayer == SlayerName.Silver || atkBook.Slayer2 == SlayerName.Silver) && context != null &&
context.Type != typeof(HorrificBeastSpell))
{
scalar += .25; // Every necromancer transformation other than horrific beast take an additional 25% damage
}
if (scalar != 1.0)
{
return scalar;
}
}
var defISlayer = Spellbook.FindEquippedSpellbook(defender) ?? defender.Weapon as ISlayer;
@ -303,7 +337,9 @@ namespace Server.Spells
if (defSlayer?.Group.OppositionSuperSlays(Caster) == true ||
defSlayer2?.Group.OppositionSuperSlays(Caster) == true)
{
scalar = 2.0;
}
}
return scalar;
@ -316,9 +352,13 @@ namespace Server.Spells
if (Caster.Player)
{
if (Core.AOS)
{
Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist);
}
else
{
Caster.FixedEffect(0x3735, 6, 30);
}
Caster.PlaySound(0x5C);
}
@ -330,12 +370,16 @@ namespace Server.Spells
public void Disturb(DisturbType type, bool firstCircle = true, bool resistable = false)
{
if (!CheckDisturb(type, firstCircle, resistable))
{
return;
}
if (State == SpellState.Casting)
{
if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First)
{
return;
}
State = SpellState.None;
Caster.Spell = null;
@ -347,14 +391,18 @@ namespace Server.Spells
m_AnimTimer?.Stop();
if (Core.AOS && Caster.Player && type == DisturbType.Hurt)
{
DoHurtFizzle();
}
Caster.NextSpellTime = Core.TickCount + (int)GetDisturbRecovery().TotalMilliseconds;
}
else if (State == SpellState.Sequencing)
{
if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First)
{
return;
}
State = SpellState.None;
Caster.Spell = null;
@ -364,7 +412,9 @@ namespace Server.Spells
Target.Cancel(Caster);
if (Core.AOS && Caster.Player && type == DisturbType.Hurt)
{
DoHurtFizzle();
}
}
}
@ -377,7 +427,9 @@ namespace Server.Spells
public virtual void OnDisturb(DisturbType type, bool message)
{
if (message)
{
Caster.SendLocalizedMessage(500641); // Your concentration is disturbed, thus ruining thy spell.
}
}
public virtual bool CheckCast() => true;
@ -385,10 +437,14 @@ namespace Server.Spells
public virtual void SayMantra()
{
if (Scroll is BaseWand)
{
return;
}
if (!string.IsNullOrEmpty(Info.Mantra) && Caster.Player)
{
Caster.PublicOverheadMessage(MessageType.Spell, Caster.SpeechHue, true, Info.Mantra, false);
}
}
public bool Cast()
@ -396,9 +452,14 @@ namespace Server.Spells
StartCastTime = Core.TickCount;
if (Core.AOS && Caster.Spell is Spell spell && spell.State == SpellState.Sequencing)
{
spell.Disturb(DisturbType.NewCast);
}
if (!Caster.CheckAlive()) return false;
if (!Caster.CheckAlive())
{
return false;
}
if (Scroll is BaseWand && Caster.Spell?.IsCasting == true)
{
@ -438,7 +499,9 @@ namespace Server.Spells
Caster.Spell = this;
if (!(Scroll is BaseWand) && RevealOnCast)
{
Caster.RevealingAction();
}
SayMantra();
@ -455,17 +518,25 @@ namespace Server.Spells
}
if (Info.LeftHandEffect > 0)
{
Caster.FixedParticles(0, 10, 5, Info.LeftHandEffect, EffectLayer.LeftHand);
}
if (Info.RightHandEffect > 0)
{
Caster.FixedParticles(0, 10, 5, Info.RightHandEffect, EffectLayer.RightHand);
}
}
if (ClearHandsOnCast)
{
Caster.ClearHands();
}
if (Core.ML)
{
WeaponAbility.ClearCurrentAbility(Caster);
}
m_CastTimer = new CastTimer(this, castDelay);
// m_CastTimer.Start();
@ -473,9 +544,13 @@ namespace Server.Spells
OnBeginCast();
if (castDelay > TimeSpan.Zero)
{
m_CastTimer.Start();
}
else
{
m_CastTimer.Tick();
}
return true;
}
@ -504,12 +579,16 @@ namespace Server.Spells
public virtual bool CheckFizzle()
{
if (Scroll is BaseWand)
{
return true;
}
GetCastSkills(out var minSkill, out var maxSkill);
if (DamageSkill != CastSkill)
{
Caster.CheckSkill(DamageSkill, 0.0, Caster.Skills[DamageSkill].Cap);
}
return Caster.CheckSkill(CastSkill, minSkill, maxSkill);
}
@ -521,12 +600,16 @@ namespace Server.Spells
var scalar = 1.0;
if (!MindRotSpell.GetMindRotScalar(Caster, ref scalar))
{
scalar = 1.0;
}
// Lower Mana Cost = 40%
var lmc = AosAttributes.GetValue(Caster, AosAttribute.LowerManaCost);
if (lmc > 40)
{
lmc = 40;
}
scalar -= (double)lmc / 100;
@ -536,7 +619,9 @@ namespace Server.Spells
public virtual TimeSpan GetDisturbRecovery()
{
if (Core.AOS)
{
return TimeSpan.Zero;
}
var delay = Math.Max(
1.0 - Math.Sqrt((Core.TickCount - StartCastTime) / 1000.0 / GetCastDelay().TotalSeconds),
@ -549,7 +634,9 @@ namespace Server.Spells
public virtual TimeSpan GetCastRecovery()
{
if (!Core.AOS)
{
return NextSpellDelay;
}
var fcr = AosAttributes.GetValue(Caster, AosAttribute.CastRecovery) -
ThunderstormSpell.GetCastRecoveryMalus(Caster);
@ -559,7 +646,9 @@ namespace Server.Spells
var delay = CastRecoveryBase + fcrDelay;
if (delay < CastRecoveryMinimum)
{
delay = CastRecoveryMinimum;
}
return TimeSpan.FromSeconds((double)delay / CastRecoveryPerSecond);
}
@ -572,7 +661,9 @@ namespace Server.Spells
public virtual TimeSpan GetCastDelay()
{
if (Scroll is BaseWand)
{
return Core.ML ? CastDelayBase : TimeSpan.Zero; // TODO: Should FC apply to wands?
}
// Faster casting cap of 2 (if not using the protection spell)
// Faster casting cap of 0 (if using the protection spell)
@ -582,15 +673,21 @@ namespace Server.Spells
if (CastSkill == SkillName.Magery || CastSkill == SkillName.Necromancy ||
CastSkill == SkillName.Chivalry && Caster.Skills.Magery.Value >= 70.0)
{
fcMax = 2;
}
var fc = Math.Min(AosAttributes.GetValue(Caster, AosAttribute.CastSpeed), fcMax);
if (ProtectionSpell.Registry.ContainsKey(Caster))
{
fc -= 2;
}
if (EssenceOfWindSpell.IsDebuffed(Caster))
{
fc -= EssenceOfWindSpell.GetFCMalus(Caster);
}
var fcDelay = TimeSpan.FromSeconds(-(CastDelayFastScalar * fc * CastDelaySecondsPerTick));
@ -652,27 +749,35 @@ namespace Server.Spells
Scroll.Movable = false;
if (ClearHandsOnCast)
{
Caster.ClearHands();
}
Scroll.Movable = m;
}
else
{
if (ClearHandsOnCast)
{
Caster.ClearHands();
}
}
var karma = ComputeKarmaAward();
if (karma != 0)
{
Titles.AwardKarma(Caster, karma, true);
}
if (TransformationSpellHelper.UnderTransformation(Caster, typeof(VampiricEmbraceSpell)))
{
var garlic = false;
for (var i = 0; !garlic && i < Info.Reagents.Length; ++i)
{
garlic = Info.Reagents[i] == Reagent.Garlic;
}
if (garlic)
{
@ -770,13 +875,19 @@ namespace Server.Spells
if (!m_Spell.Caster.Mounted && m_Spell.Info.Action >= 0)
{
if (m_Spell.Caster.Body.IsHuman)
{
m_Spell.Caster.Animate(m_Spell.Info.Action, 7, 1, true, false, 0);
}
else if (m_Spell.Caster.Player && m_Spell.Caster.Body.IsMonster)
{
m_Spell.Caster.Animate(12, 7, 1, true, false, 0);
}
}
if (!Running)
{
m_Spell.m_AnimTimer = null;
}
}
}
@ -793,7 +904,10 @@ namespace Server.Spells
protected override void OnTick()
{
if (m_Spell?.Caster == null) return;
if (m_Spell?.Caster == null)
{
return;
}
if (m_Spell.State == SpellState.Casting && m_Spell.Caster.Spell == m_Spell)
{
@ -809,7 +923,9 @@ namespace Server.Spells
m_Spell.OnCast();
if (m_Spell.Caster.Player && m_Spell.Caster.Target != originalTarget)
{
m_Spell.Caster.Target?.BeginTimeout(m_Spell.Caster, TimeSpan.FromSeconds(30.0));
}
m_Spell.m_CastTimer = null;
}

View file

@ -23,7 +23,9 @@ namespace Server
public static void Nullify(Mobile from)
{
if (!from.CanBeginAction<DefensiveSpell>())
{
new InternalTimer(from).Start();
}
}
private class InternalTimer : Timer
@ -155,7 +157,9 @@ namespace Server.Spells
public static bool CheckMulti(Point3D p, Map map, bool houses = true, int housingrange = 0)
{
if (map == null || map == Map.Internal)
{
return false;
}
var sector = map.GetSector(p.X, p.Y);
@ -166,7 +170,9 @@ namespace Server.Spells
if (multi is BaseHouse bh)
{
if (houses && bh.IsInside(p, 16) || housingrange > 0 && bh.InRange(p, housingrange))
{
return true;
}
}
else if (multi.Contains(p))
{
@ -180,12 +186,16 @@ namespace Server.Spells
public static void Turn(Mobile from, object to)
{
if (!(to is IPoint3D target))
{
return;
}
if (target is Item item)
{
if (item.RootParent != from)
{
from.Direction = from.GetDirectionTo(item.GetWorldLocation());
}
}
else if (from != target)
{
@ -196,24 +206,32 @@ namespace Server.Spells
public static bool CheckCombat(Mobile m)
{
if (!RestrictTravelCombat)
{
return false;
}
for (var i = 0; i < m.Aggressed.Count; ++i)
{
var info = m.Aggressed[i];
if (info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay)
{
return true;
}
}
if (Core.Expansion == Expansion.AOS)
{
for (var i = 0; i < m.Aggressors.Count; ++i)
{
var info = m.Aggressors[i];
if (info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay)
{
return true;
}
}
}
return false;
}
@ -221,7 +239,9 @@ namespace Server.Spells
public static bool AdjustField(ref Point3D p, Map map, int height, bool mobsBlock)
{
if (map == null)
{
return false;
}
for (var offset = 0; offset < 10; ++offset)
{
@ -250,7 +270,9 @@ namespace Server.Spells
var z = t.Z;
if ((t.Flags & TileFlag.Surface) == 0)
{
z -= TileData.ItemTable[t.ItemID & TileData.MaxItemValue].CalcHeight;
}
p = new Point3D(t.X, t.Y, z);
}
@ -331,9 +353,13 @@ namespace Server.Spells
double percent;
if (curse)
{
percent = 8 + caster.Skills.EvalInt.Fixed / 100 - target.Skills.MagicResist.Fixed / 100;
}
else
{
percent = 1 + caster.Skills.EvalInt.Fixed / 100;
}
percent *= 0.01;
@ -349,7 +375,9 @@ namespace Server.Spells
caster.CheckSkill(SkillName.EvalInt, 0.0, 120.0);
if (curse)
{
target.CheckSkill(SkillName.MagicResist, 0.0, 120.0);
}
}
var percent = GetOffsetScalar(caster, target, curse);
@ -377,14 +405,18 @@ namespace Server.Spells
m = c.ControlMaster;
if (m != null)
{
g = m.Guild as Guild;
}
if (g == null)
{
m = c.SummonMaster;
if (m != null)
{
g = m.Guild as Guild;
}
}
}
@ -394,10 +426,14 @@ namespace Server.Spells
public static bool ValidIndirectTarget(Mobile from, Mobile to)
{
if (from == to)
{
return true;
}
if (to.Hidden && to.AccessLevel > from.AccessLevel)
{
return false;
}
var bcFrom = from as BaseCreature;
var bcTarg = to as BaseCreature;
@ -406,48 +442,70 @@ namespace Server.Spells
PlayerMobile pmTarg;
if (bcFrom?.Summoned == true)
{
pmFrom = bcFrom.SummonMaster as PlayerMobile;
}
else
{
pmFrom = from as PlayerMobile;
}
if (bcTarg?.Summoned == true)
{
pmTarg = bcTarg.SummonMaster as PlayerMobile;
}
else
{
pmTarg = to as PlayerMobile;
}
if (pmFrom?.DuelContext != null && pmFrom.DuelContext == pmTarg?.DuelContext && pmFrom.DuelContext.Started &&
pmFrom.DuelPlayer != null && pmTarg?.DuelPlayer != null)
{
return pmFrom.DuelPlayer.Participant != pmTarg.DuelPlayer.Participant;
}
var fromGuild = GetGuildFor(from);
var toGuild = GetGuildFor(to);
if (fromGuild != null && toGuild != null && (fromGuild == toGuild || fromGuild.IsAlly(toGuild)))
{
return false;
}
var p = Party.Get(from);
if (p?.Contains(to) == true)
{
return false;
}
if (bcTarg != null && (bcTarg.Controlled || bcTarg.Summoned))
{
if (bcTarg.ControlMaster == from || bcTarg.SummonMaster == from)
{
return false;
}
if (p != null && (p.Contains(bcTarg.ControlMaster) || p.Contains(bcTarg.SummonMaster)))
{
return false;
}
}
if (bcFrom != null && (bcFrom.Controlled || bcFrom.Summoned))
{
if (bcFrom.ControlMaster == to || bcFrom.SummonMaster == to)
{
return false;
}
p = Party.Get(to);
if (p != null && (p.Contains(bcFrom.ControlMaster) || p.Contains(bcFrom.SummonMaster)))
{
return false;
}
}
return bcTarg?.Controlled == false && bcTarg.InitialInnocent ||
@ -462,12 +520,16 @@ namespace Server.Spells
var map = caster.Map;
if (map == null)
{
return;
}
var scale = 1.0 + (caster.Skills.Magery.Value - 100.0) / 200.0;
if (scaleDuration)
{
duration = TimeSpan.FromSeconds(duration.TotalSeconds * scale);
}
if (scaleStats)
{
@ -522,7 +584,9 @@ namespace Server.Spells
public static bool FindValidSpawnLocation(Map map, ref Point3D p, bool surroundingsOnly)
{
if (map == null) // sanity
{
return false;
}
if (!surroundingsOnly)
{
@ -569,11 +633,17 @@ namespace Server.Spells
public static void SendInvalidMessage(Mobile caster, TravelCheckType type)
{
if (type == TravelCheckType.RecallTo || type == TravelCheckType.GateTo)
{
caster.SendLocalizedMessage(1019004); // You are not allowed to travel there.
}
else if (type == TravelCheckType.TeleportTo)
{
caster.SendLocalizedMessage(501035); // You cannot teleport from here to the destination.
}
else
{
caster.SendLocalizedMessage(501802); // Thy spell doth not appear to work...
}
}
public static bool CheckTravel(Mobile caster, TravelCheckType type) =>
@ -586,7 +656,9 @@ namespace Server.Spells
if (IsInvalid(map, loc)) // null, internal, out of bounds
{
if (caster != null)
{
SendInvalidMessage(caster, type);
}
return false;
}
@ -594,7 +666,9 @@ namespace Server.Spells
// Always allow monsters to teleport
if (caster is BaseCreature bc && !bc.Controlled && !bc.Summoned &&
(type == TravelCheckType.TeleportTo || type == TravelCheckType.TeleportFrom))
{
return true;
}
m_TravelCaster = caster;
m_TravelType = type;
@ -608,14 +682,20 @@ namespace Server.Spells
var current = Region.Find(caster.Location, map) as BaseRegion;
if (destination?.CheckTravel(caster, loc, type) == false || current?.CheckTravel(caster, loc, type) == false)
{
isValid = false;
}
}
for (var i = 0; isValid && i < m_Validators.Length; ++i)
{
isValid = m_Rules[v, i] || !m_Validators[i](map, loc);
}
if (!isValid && caster != null)
{
SendInvalidMessage(caster, type);
}
return isValid;
}
@ -669,7 +749,9 @@ namespace Server.Spells
public static bool IsCrystalCave(Map map, Point3D loc)
{
if (map != Map.Malas || loc.Z >= -80)
{
return false;
}
int x = loc.X, y = loc.Y;
@ -691,7 +773,9 @@ namespace Server.Spells
public static bool IsDoomFerry(Map map, Point3D loc)
{
if (map != Map.Malas)
{
return false;
}
int x = loc.X, y = loc.Y;
@ -702,7 +786,9 @@ namespace Server.Spells
{
// The tokuno dungeons are really inside malas
if (map != Map.Malas)
{
return false;
}
int x = loc.X, y = loc.Y, z = loc.Z;
@ -715,7 +801,9 @@ namespace Server.Spells
public static bool IsDoomGauntlet(Map map, Point3D loc)
{
if (map != Map.Malas)
{
return false;
}
int x = loc.X - 256, y = loc.Y - 304;
@ -725,7 +813,9 @@ namespace Server.Spells
public static bool IsLampRoom(Map map, Point3D loc)
{
if (map != Map.Malas)
{
return false;
}
int x = loc.X, y = loc.Y;
@ -735,7 +825,9 @@ namespace Server.Spells
public static bool IsGuardianRoom(Map map, Point3D loc)
{
if (map != Map.Malas)
{
return false;
}
int x = loc.X, y = loc.Y;
@ -754,7 +846,9 @@ namespace Server.Spells
public static bool IsInvalid(Map map, Point3D loc)
{
if (map == null || map == Map.Internal)
{
return true;
}
int x = loc.X, y = loc.Y;
@ -765,7 +859,9 @@ namespace Server.Spells
public static bool IsTown(IPoint3D ip, Mobile caster)
{
if (ip is Item item)
{
ip = item.GetWorldLocation();
}
return IsTown(new Point3D(ip), caster);
}
@ -775,11 +871,17 @@ namespace Server.Spells
var map = caster.Map;
if (map == null)
{
return false;
}
if (Region.Find(loc, map).GetRegion<SafeZone>() != null)
{
if (caster is PlayerMobile pm && (pm.DuelContext?.Started != true || pm.DuelPlayer?.Eliminated != false))
{
return true;
}
}
var reg = Region.Find(loc, map).GetRegion<GuardedRegion>();
@ -789,7 +891,9 @@ namespace Server.Spells
public static bool CheckTown(IPoint3D ip, Mobile caster)
{
if (ip is Item item)
{
ip = item.GetWorldLocation();
}
return CheckTown(new Point3D(ip), caster);
}
@ -953,7 +1057,9 @@ namespace Server.Spells
var damageGiven = AOS.Damage(target, from, dmg, phys, fire, cold, pois, nrgy, chaos);
if (from != null) // sanity check
{
DoLeech(damageGiven, from, target);
}
WeightOverloading.DFA = DFAlgorithm.Standard;
}
@ -974,7 +1080,9 @@ namespace Server.Spells
var context = TransformationSpellHelper.GetContext(from);
if (context == null) /* cleanup */
{
return;
}
if (context.Type == typeof(WraithFormSpell))
{
@ -1019,7 +1127,9 @@ namespace Server.Spells
m_Spell = s;
if (m_Spell?.DelayedDamage == true && !m_Spell.DelayedDamageStacking)
{
m_Spell.StartDelayedDamageContext(target, this);
}
Priority = TimerPriority.TwentyFiveMS;
}
@ -1067,7 +1177,9 @@ namespace Server.Spells
m_DFA = dfa;
m_Spell = s;
if (m_Spell?.DelayedDamage == true && !m_Spell.DelayedDamageStacking)
{
m_Spell.StartDelayedDamageContext(target, this);
}
Priority = TimerPriority.TwentyFiveMS;
}
@ -1078,17 +1190,23 @@ namespace Server.Spells
var bcTarg = m_Target as BaseCreature;
if (bcFrom != null && m_Target != null)
{
bcFrom.AlterSpellDamageTo(m_Target, ref m_Damage);
}
if (bcTarg != null && m_From != null)
{
bcTarg.AlterSpellDamageFrom(m_From, ref m_Damage);
}
WeightOverloading.DFA = m_DFA;
var damageGiven = AOS.Damage(m_Target, m_From, m_Damage, m_Phys, m_Fire, m_Cold, m_Pois, m_Nrgy, m_Chaos);
if (m_From != null) // sanity check
{
DoLeech(damageGiven, m_From, m_Target);
}
WeightOverloading.DFA = DFAlgorithm.Standard;
@ -1133,7 +1251,9 @@ namespace Server.Spells
public static bool OnCast(Mobile caster, Spell spell)
{
if (!(spell is ITransformationSpell transformSpell))
{
return false;
}
if (Sigil.ExistsOn(caster))
{
@ -1180,33 +1300,47 @@ namespace Server.Spells
var mods = new List<ResistanceMod>();
if (transformSpell.PhysResistOffset != 0)
{
mods.Add(new ResistanceMod(ResistanceType.Physical, transformSpell.PhysResistOffset));
}
if (transformSpell.FireResistOffset != 0)
{
mods.Add(new ResistanceMod(ResistanceType.Fire, transformSpell.FireResistOffset));
}
if (transformSpell.ColdResistOffset != 0)
{
mods.Add(new ResistanceMod(ResistanceType.Cold, transformSpell.ColdResistOffset));
}
if (transformSpell.PoisResistOffset != 0)
{
mods.Add(new ResistanceMod(ResistanceType.Poison, transformSpell.PoisResistOffset));
}
if (transformSpell.NrgyResistOffset != 0)
{
mods.Add(new ResistanceMod(ResistanceType.Energy, transformSpell.NrgyResistOffset));
}
if (!((Body)transformSpell.Body).IsHuman)
{
var mt = caster.Mount;
if (mt != null)
{
mt.Rider = null;
}
}
caster.BodyMod = transformSpell.Body;
caster.HueMod = transformSpell.Hue;
for (var i = 0; i < mods.Count; ++i)
{
caster.AddResistanceMod(mods[i]);
}
transformSpell.DoEffect(caster);
@ -1231,20 +1365,24 @@ namespace Server.Spells
var context = GetContext(m);
if (context != null)
{
RemoveContext(m, context, resetGraphics);
}
}
public static void RemoveContext(Mobile m, TransformContext context, bool resetGraphics)
{
if (!m_Table.ContainsKey(m))
if (!m_Table.Remove(m))
{
return;
m_Table.Remove(m);
}
var mods = context.Mods;
for (var i = 0; i < mods.Count; ++i)
{
m.RemoveResistanceMod(mods[i]);
}
if (resetGraphics)
{

View file

@ -75,8 +75,7 @@ namespace Server.Spells
m_Types[spellID] = type;
if (!m_IDsFromTypes.ContainsKey(type))
m_IDsFromTypes.Add(type, spellID);
m_IDsFromTypes.TryAdd(type, spellID);
if (type.IsSubclassOf(typeof(SpecialMove)))
{

View file

@ -62,10 +62,9 @@ namespace Server.Spells.Bushido
public static void EndConfidence(Mobile m)
{
if (m_Table.TryGetValue(m, out var timer))
if (m_Table.Remove(m, out var timer))
{
timer.Stop();
m_Table.Remove(m);
}
OnEffectEnd(m, typeof(Confidence));
@ -85,10 +84,9 @@ namespace Server.Spells.Bushido
public static void StopRegenerating(Mobile m)
{
if (m_RegenTable.TryGetValue(m, out var timer))
if (m_RegenTable.Remove(m, out var timer))
{
timer.Stop();
m_RegenTable.Remove(m);
}
}

View file

@ -77,10 +77,9 @@ namespace Server.Spells.Bushido
public static void StopCountering(Mobile m)
{
if (m_Table.TryGetValue(m, out var timer))
if (m_Table.Remove(m, out var timer))
{
timer.Stop();
m_Table.Remove(m);
}
OnEffectEnd(m, typeof(CounterAttack));

View file

@ -181,10 +181,9 @@ namespace Server.Spells.Bushido
public static void EndEvasion(Mobile m)
{
if (m_Table.TryGetValue(m, out var timer))
if (m_Table.Remove(m, out var timer))
{
timer.Stop();
m_Table.Remove(m);
}
OnEffectEnd(m, typeof(Evasion));

View file

@ -25,7 +25,9 @@ namespace Server.Spells.Bushido
public override void OnHit(Mobile attacker, Mobile defender, int damage)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{
return;
}
ClearCurrentMove(attacker);
@ -64,7 +66,9 @@ namespace Server.Spells.Bushido
var resSpells = attacker.Skills.MagicResist.Value;
if (resSpells > 0.0)
{
mods.Add(new DefaultSkillMod(SkillName.MagicResist, true, -resSpells));
}
info = new HonorableExecutionInfo(attacker, mods);
info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(7.0), RemovePenalty, info.m_Mobile);
@ -81,12 +85,13 @@ namespace Server.Spells.Bushido
public static void RemovePenalty(Mobile target)
{
if (!m_Table.TryGetValue(target, out var info) || !info.m_Penalty)
if (!m_Table.Remove(target, out var info) || !info.m_Penalty)
{
return;
}
info.Clear();
info.m_Timer?.Stop();
m_Table.Remove(target);
}
private class HonorableExecutionInfo
@ -114,32 +119,44 @@ namespace Server.Spells.Bushido
public void Apply()
{
if (m_Mods == null)
{
return;
}
for (var i = 0; i < m_Mods.Count; ++i)
{
var mod = m_Mods[i];
if (mod is ResistanceMod resistanceMod)
{
m_Mobile.AddResistanceMod(resistanceMod);
}
else if (mod is SkillMod skillMod)
{
m_Mobile.AddSkillMod(skillMod);
}
}
}
public void Clear()
{
if (m_Mods == null)
{
return;
}
for (var i = 0; i < m_Mods.Count; ++i)
{
var mod = m_Mods[i];
if (mod is ResistanceMod resistanceMod)
{
m_Mobile.RemoveResistanceMod(resistanceMod);
}
else if (mod is SkillMod skillMod)
{
m_Mobile.RemoveSkillMod(skillMod);
}
}
}
}

View file

@ -25,7 +25,9 @@ namespace Server.Spells.Fifth
public override bool CheckCast()
{
if (Core.AOS)
{
return true;
}
if (Caster.MagicDamageAbsorb > 0)
{
@ -57,15 +59,15 @@ namespace Server.Spells.Fifth
{
var targ = Caster;
if (m_Table.TryGetValue(targ, out var mods))
if (m_Table.Remove(targ, out var mods))
{
targ.PlaySound(0x1ED);
targ.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist);
m_Table.Remove(targ);
for (var i = 0; i < mods.Length; ++i)
{
targ.RemoveResistanceMod(mods[i]);
}
BuffInfo.RemoveBuff(targ, BuffIcon.MagicReflection);
}
@ -89,7 +91,9 @@ namespace Server.Spells.Fifth
m_Table[targ] = mods;
for (var i = 0; i < mods.Length; ++i)
{
targ.AddResistanceMod(mods[i]);
}
var buffFormat = $"{physiMod}\t+{otherMod}\t+{otherMod}\t+{otherMod}\t+{otherMod}";
@ -133,13 +137,16 @@ namespace Server.Spells.Fifth
public static void EndReflect(Mobile m)
{
if (!m_Table.TryGetValue(m, out var mods))
if (!m_Table.Remove(m, out var mods))
{
return;
}
for (var i = 0; i < mods?.Length; ++i)
{
m.RemoveResistanceMod(mods[i]);
}
m_Table.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.MagicReflection);
}
}

View file

@ -26,7 +26,9 @@ namespace Server.Spells.First
public override bool CheckCast()
{
if (Core.AOS)
{
return true;
}
if (Caster.MeleeDamageAbsorb > 0)
{
@ -59,15 +61,15 @@ namespace Server.Spells.First
{
var targ = Caster;
if (m_Table.TryGetValue(targ, out var mods))
if (m_Table.Remove(targ, out var mods))
{
targ.PlaySound(0x1ED);
targ.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist);
m_Table.Remove(targ);
for (var i = 0; i < mods.Length; ++i)
{
targ.RemoveResistanceMod(mods[i]);
}
BuffInfo.RemoveBuff(Caster, BuffIcon.ReactiveArmor);
}
@ -91,7 +93,9 @@ namespace Server.Spells.First
m_Table[targ] = mods;
for (var i = 0; i < mods.Length; ++i)
{
targ.AddResistanceMod(mods[i]);
}
var physresist = 15 + (int)(targ.Skills.Inscribe.Value / 20);
var args = $"{physresist}\t{5}\t{5}\t{5}\t{5}";
@ -140,13 +144,16 @@ namespace Server.Spells.First
public static void EndArmor(Mobile m)
{
if (!m_Table.TryGetValue(m, out var mods))
if (!m_Table.Remove(m, out var mods))
{
return;
}
for (var i = 0; i < mods?.Length; ++i)
{
m.RemoveResistanceMod(mods[i]);
}
m_Table.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.ReactiveArmor);
}
}

View file

@ -97,9 +97,8 @@ namespace Server.Spells.Fourth
public static void RemoveEntry(Mobile m)
{
if (_Table.TryGetValue(m, out var v))
if (_Table.Remove(m, out var v))
{
_Table.Remove(m);
m.EndAction<ArchProtectionSpell>();
m.VirtualArmorMod -= Math.Min(v, m.VirtualArmorMod);
}

View file

@ -95,7 +95,9 @@ namespace Server.Spells.Mysticism
var mount = Caster.Mount;
if (mount != null)
{
mount.Rider = null;
}
Caster.BodyMod = 0x2C1;
Caster.HueMod = 0;
@ -112,7 +114,9 @@ namespace Server.Spells.Mysticism
};
for (var i = 0; i < mods.Length; ++i)
{
Caster.AddResistanceMod(mods[i]);
}
m_Table[Caster] = mods;
@ -141,17 +145,19 @@ namespace Server.Spells.Mysticism
public static void RemoveEffects(Mobile m)
{
if (!m_Table.TryGetValue(m, out var mods))
if (!m_Table.Remove(m, out var mods))
{
return;
}
for (var i = 0; i < mods.Length; ++i)
{
m.RemoveResistanceMod(mods[i]);
}
m.BodyMod = 0;
m.HueMod = -1;
m_Table.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.StoneForm);
}

View file

@ -151,7 +151,10 @@ namespace Server.Spells.Necromancy
{
Type type = null;
if (c.Owner != null) type = c.Owner.GetType();
if (c.Owner != null)
{
type = c.Owner.GetType();
}
if (c.ItemID != 0x2006 || c.Animated || type == typeof(PlayerMobile) || type == null ||
c.Owner != null && c.Owner.Fame < 100 ||
@ -217,10 +220,14 @@ namespace Server.Spells.Necromancy
var contains = types.Length == 0;
for (var j = 0; !contains && j < types.Length; ++j)
{
contains = types[j].IsAssignableFrom(type);
}
if (contains)
return group;
{
return @group;
}
}
return null;
@ -228,41 +235,52 @@ namespace Server.Spells.Necromancy
public static void Unregister(Mobile master, Mobile summoned)
{
if (master == null)
return;
if (!m_Table.TryGetValue(master, out var list))
if (master == null || !m_Table.TryGetValue(master, out var list))
{
return;
}
list.Remove(summoned);
if (list.Count == 0)
{
m_Table.Remove(master);
}
}
public static void Register(Mobile master, Mobile summoned)
{
if (master == null)
{
return;
}
if (!m_Table.TryGetValue(master, out var list))
{
m_Table[master] = list = new List<Mobile>();
}
for (var i = list.Count - 1; i >= 0; --i)
{
if (i >= list.Count)
{
continue;
}
var mob = list[i];
if (mob.Deleted)
{
list.RemoveAt(i--);
}
}
list.Add(summoned);
if (list.Count > 3)
{
Timer.DelayCall(list[0].Kill);
}
Timer.DelayCall(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0), Summoned_Damage, summoned);
}
@ -270,20 +288,28 @@ namespace Server.Spells.Necromancy
private static void Summoned_Damage(Mobile mob)
{
if (mob.Hits > 0)
{
--mob.Hits;
}
else
{
mob.Kill();
}
}
private static void SummonDelay_Callback(Mobile caster, Corpse corpse, Point3D loc, Map map, CreatureGroup group)
{
if (corpse.Animated)
{
return;
}
var owner = corpse.Owner;
if (owner == null)
{
return;
}
var necromancy = caster.Skills.Necromancy.Value;
var spiritSpeak = caster.Skills.SpiritSpeak.Value;
@ -299,7 +325,9 @@ namespace Server.Spells.Necromancy
var entry = entries[i];
if (casterAbility < entry.m_Requirement)
{
continue;
}
var animates = entry.m_ToSummon;
@ -307,7 +335,9 @@ namespace Server.Spells.Necromancy
}
if (toSummon == null)
{
return;
}
Mobile summoned = null;
@ -321,7 +351,9 @@ namespace Server.Spells.Necromancy
}
if (summoned == null)
{
return;
}
if (summoned is BaseCreature bc)
{
@ -336,7 +368,9 @@ namespace Server.Spells.Necromancy
}
if (summoned is SkeletalDragon dragon)
{
Scale(dragon, 50); // lose 50% hp and strength
}
summoned.Fame = 0;
summoned.Karma = -1500;
@ -357,7 +391,9 @@ namespace Server.Spells.Necromancy
toScale = bc.HitsMaxSeed;
if (toScale > 0)
{
bc.HitsMaxSeed = AOS.Scale(toScale, scalar);
}
bc.Hits = bc.Hits; // refresh hits
}

View file

@ -45,9 +45,13 @@ namespace Server.Spells.Necromancy
else if (m_OathTable.ContainsKey(m))
{
if (m.Player)
{
Caster.SendLocalizedMessage(1061608); // That player is already bonded in a Blood Oath.
}
else
{
Caster.SendLocalizedMessage(1061609); // That creature is already bonded in a Blood Oath.
}
}
else if (CheckHSequence(m))
{
@ -128,21 +132,22 @@ namespace Server.Spells.Necromancy
protected override void OnTick()
{
if (m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive ||
DateTime.UtcNow >= m_End) DoExpire();
DateTime.UtcNow >= m_End)
{
DoExpire();
}
}
public void DoExpire()
{
if (m_OathTable.ContainsKey(m_Caster))
if (m_OathTable.Remove(m_Caster))
{
m_Caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
m_OathTable.Remove(m_Caster);
}
if (m_OathTable.ContainsKey(m_Target))
if (m_OathTable.Remove(m_Target))
{
m_Target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
m_OathTable.Remove(m_Target);
}
Stop();

View file

@ -57,7 +57,9 @@ namespace Server.Spells.Necromancy
var mod = new DefaultSkillMod(SkillName.MagicResist, false, 50.0);
if (m.Skills.MagicResist.Base > 50.0)
{
m.AddSkillMod(mod);
}
m_Table[m] = mod;
}
@ -81,10 +83,11 @@ namespace Server.Spells.Necromancy
public static bool TryEndEffect(Mobile m)
{
if (!m_Table.TryGetValue(m, out var mod))
if (!m_Table.Remove(m, out var mod))
{
return false;
}
m_Table.Remove(m);
mod?.Remove();
return true;

View file

@ -73,12 +73,13 @@ namespace Server.Spells.Necromancy
public static void ClearMindRotScalar(Mobile m)
{
if (!m_Table.TryGetValue(m, out var tmpB))
if (!m_Table.Remove(m, out var tmpB))
{
return;
}
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
tmpB.m_MRExpireTimer.Stop();
m_Table.Remove(m);
m.SendLocalizedMessage(1060872); // Your mind feels normal again.
}

View file

@ -29,7 +29,9 @@ namespace Server.Spells.Necromancy
public void Target(Mobile m)
{
if (m == null)
{
return;
}
if (CheckHSequence(m))
{
@ -70,7 +72,10 @@ namespace Server.Spells.Necromancy
// Calculations for the buff bar
var spiritlevel = Caster.Skills.SpiritSpeak.Value / 10;
if (spiritlevel < 4)
{
spiritlevel = 4;
}
var d_MinDamage = 4;
var d_MaxDamage = ((int)spiritlevel + 1) * 3;
var args = $"{d_MinDamage}\t{d_MaxDamage}";
@ -113,13 +118,13 @@ namespace Server.Spells.Necromancy
public static bool RemoveCurse(Mobile m)
{
if (!m_Table.TryGetValue(m, out var timer))
if (!m_Table.Remove(m, out var timer))
{
return false;
}
timer.Stop();
m.SendLocalizedMessage(1061687); // You can breath normally again.
m_Table.Remove(m);
return true;
}
@ -153,7 +158,9 @@ namespace Server.Spells.Necromancy
m_Count = (int)spiritLevel;
if (m_Count < 4)
{
m_Count = 4;
}
m_MaxCount = m_Count;
}
@ -167,7 +174,9 @@ namespace Server.Spells.Necromancy
}
if (!m_Target.Alive || DateTime.UtcNow < m_NextHit)
{
return;
}
--m_Count;
@ -182,9 +191,13 @@ namespace Server.Spells.Necromancy
var delay = (int)Math.Ceiling((1.0 + 5 * m_Count) / m_MaxCount);
if (delay <= 5)
{
m_HitDelay = delay;
}
else
{
m_HitDelay = 5;
}
}
}
@ -203,16 +216,22 @@ namespace Server.Spells.Necromancy
damage *= 3 - (double)m_Target.Stam / m_Target.StamMax * 2;
if (damage < 1)
{
damage = 1;
}
if (!m_Target.Player)
{
damage *= 1.75;
}
AOS.Damage(m_Target, m_From, (int)damage, 0, 0, 0, 100, 0);
if (Utility.RandomDouble() >= 0.60
) // OSI: randomly revealed between first and third damage tick, guessing 60% chance
{
m_Target.RevealingAction();
}
}
}
}

View file

@ -20,7 +20,9 @@ namespace Server.Spells.Ninjitsu
public override void OnHit(Mobile attacker, Mobile defender, int damage)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{
return;
}
ClearCurrentMove(attacker);
@ -32,9 +34,13 @@ namespace Server.Spells.Ninjitsu
var isRanged = attacker.Weapon is BaseRanged;
if (ninjitsu < 100) // This formula is an approximation from OSI data. TODO: find correct formula
{
chance = 30 + (ninjitsu - 85) * 2.2;
}
else
{
chance = 63 + (ninjitsu - 100) * 1.1;
}
if (chance / 100 < Utility.RandomDouble())
{
@ -44,16 +50,16 @@ namespace Server.Spells.Ninjitsu
var damageBonus = 0;
if (m_Table.TryGetValue(defender, out var info))
if (m_Table.Remove(defender, out var info))
{
defender.SendLocalizedMessage(1063092); // Your opponent lands another Death Strike!
if (info.m_Steps > 0)
{
damageBonus = attacker.Skills.Ninjitsu.Fixed / 150;
}
info.m_Timer?.Stop();
m_Table.Remove(defender);
}
else
{
@ -78,13 +84,17 @@ namespace Server.Spells.Ninjitsu
public static void AddStep(Mobile m)
{
if (m_Table.TryGetValue(m, out var info) && ++info.m_Steps >= 5)
{
ProcessDeathStrike(m);
}
}
private static void ProcessDeathStrike(Mobile defender)
{
if (!m_Table.TryGetValue(defender, out var info))
if (!m_Table.Remove(defender, out var info))
{
return;
}
int damage;
@ -97,16 +107,24 @@ namespace Server.Spells.Ninjitsu
info.m_Attacker.Skills.Stealth.Value) / 220;
if (scalar > 1)
{
scalar = 1;
}
// New formula doesn't apply DamageBonus anymore, caps must be, directly, 60/30.
if (info.m_Steps >= 5)
{
damage = (int)Math.Floor(Math.Min(60, ninjitsu / 3 * (0.3 + 0.7 * scalar) + stalkingBonus));
}
else
{
damage = (int)Math.Floor(Math.Min(30, ninjitsu / 9 * (0.3 + 0.7 * scalar) + stalkingBonus));
}
if (info.m_isRanged)
{
damage /= 2;
}
}
else
{
@ -118,8 +136,11 @@ namespace Server.Spells.Ninjitsu
}
if (Core.ML)
{
info.m_Target.Damage(damage, info.m_Attacker); // Damage is direct.
}
else
{
AOS.Damage(
info.m_Target,
info.m_Attacker,
@ -136,10 +157,9 @@ namespace Server.Spells.Ninjitsu
false,
true
); // Damage is physical.
}
info.m_Timer?.Stop();
m_Table.Remove(info.m_Target);
}
private class DeathStrikeInfo

View file

@ -81,11 +81,10 @@ namespace Server.Spells.Ninjitsu
public override void OnClearMove(Mobile from)
{
if (!m_Table.TryGetValue(from, out var info))
return;
info.m_Timer.Stop();
m_Table.Remove(info.m_Mobile);
if (m_Table.Remove(from, out var info))
{
info.m_Timer.Stop();
}
}
public static double GetBonus(Mobile from)

View file

@ -53,11 +53,9 @@ namespace Server.Spells.Ninjitsu
attacker.RevealingAction();
if (m_Table.TryGetValue(defender, out var info))
if (m_Table.Remove(defender, out var info))
{
info.m_Timer?.Stop();
m_Table.Remove(defender);
}
var ninjitsu = attacker.Skills.Ninjitsu.Fixed;

View file

@ -29,7 +29,9 @@ namespace Server.Spells.Second
public override bool CheckCast()
{
if (Core.AOS)
{
return true;
}
if (Registry.ContainsKey(Caster))
{
@ -38,7 +40,9 @@ namespace Server.Spells.Second
}
if (Caster.CanBeginAction<DefensiveSpell>())
{
return true;
}
Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time.
return false;
@ -55,12 +59,11 @@ namespace Server.Spells.Second
* even after dying<EFBFBD>until you <EFBFBD>turn them off<EFBFBD> by casting them again.
*/
if (m_Table.TryGetValue(target, out var mods))
if (m_Table.Remove(target, out var mods))
{
target.PlaySound(0x1ED);
target.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist);
m_Table.Remove(target);
Registry.Remove(target);
target.RemoveResistanceMod(mods.Item1);
@ -100,10 +103,11 @@ namespace Server.Spells.Second
public static void EndProtection(Mobile m)
{
if (!m_Table.TryGetValue(m, out var mods))
if (!m_Table.Remove(m, out var mods))
{
return;
}
m_Table.Remove(m);
Registry.Remove(m);
m.RemoveResistanceMod(mods.Item1);
@ -117,7 +121,9 @@ namespace Server.Spells.Second
if (Core.AOS)
{
if (CheckSequence())
{
Toggle(Caster, Caster);
}
FinishSequence();
}

View file

@ -93,11 +93,10 @@ namespace Server.Spells.Sixth
public static void RemoveTimer(Mobile m)
{
if (!m_Table.TryGetValue(m, out var t))
return;
t.Stop();
m_Table.Remove(m);
if (m_Table.Remove(m, out var t))
{
t.Stop();
}
}
private class InternalTimer : Timer

View file

@ -27,7 +27,9 @@ namespace Server.Spells.Spellweaving
public void Target(Mobile m)
{
if (m == null)
{
return;
}
if (!Caster.CanSee(m))
{
@ -94,10 +96,10 @@ namespace Server.Spells.Spellweaving
public static bool StopEffect(Mobile m)
{
if (!m_Table.TryGetValue(m, out var info))
if (!m_Table.Remove(m, out var info))
{
return false;
m_Table.Remove(m);
}
info.m_Timer.Stop();
BuffInfo.RemoveBuff(m, BuffIcon.GiftOfRenewal);
@ -151,7 +153,9 @@ namespace Server.Spells.Spellweaving
}
if (m.Hits >= m.HitsMax)
{
return;
}
var toHeal = m_GiftInfo.m_HitsPerRound;

View file

@ -77,17 +77,20 @@ namespace Server.Spells.Spellweaving
private static void FinishEffect(DelayedEffectEntry effect)
{
if (m_WeaponDamageTable.TryGetValue(effect.m_Weapon, out var entry))
{
AOS.Damage(effect.m_Target, entry.m_Caster, entry.m_Damage, 0, 100, 0, 0, 0);
}
}
public static void StopImmolating(BaseWeapon weapon)
{
if (!m_WeaponDamageTable.TryGetValue(weapon, out var entry))
if (!m_WeaponDamageTable.Remove(weapon, out var entry))
{
return;
}
entry.m_Caster?.PlaySound(0x27);
entry.m_Timer.Stop();
m_WeaponDamageTable.Remove(weapon);
weapon.InvalidateProperties();
}

View file

@ -48,7 +48,9 @@ namespace Server.Spells.Spellweaving
{
if (Caster == m || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanBeHarmful(m, false) ||
!Caster.InLOS(m))
{
continue;
}
Caster.DoHarmful(m);
@ -57,7 +59,9 @@ namespace Server.Spells.Spellweaving
SpellHelper.Damage(this, m, m.Player && Caster.Player ? pvpDamage : pvmDamage, 0, 0, 0, 0, 100);
if (oldSpell == null || oldSpell == m.Spell || CheckResisted(m))
{
continue;
}
m_Table[m] = Timer.DelayCall(duration, DoExpire, m);
@ -77,11 +81,12 @@ namespace Server.Spells.Spellweaving
public static void DoExpire(Mobile m)
{
if (!m_Table.TryGetValue(m, out var t))
if (!m_Table.Remove(m, out var t))
{
return;
}
t.Stop();
m_Table.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.Thunderstorm);
}