Cleanup and adds configuration for crashguard (#240)

This commit is contained in:
Kamron Batman 2020-09-12 01:57:07 -07:00 • committed by GitHub
parent 55ae0f8778
commit 7dbfa086bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 1248 additions and 97 deletions

View file

@ -25,8 +25,6 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Server.Json; using Server.Json;
using Server.Network; using Server.Network;

View file

@ -387,7 +387,7 @@ namespace Server.Network
if (from.Mobile == Mobile && to.Mobile == m) if (from.Mobile == Mobile && to.Mobile == m)
{ {
return @from.Container; return from.Container;
} }
if (from.Mobile == m && to.Mobile == Mobile) if (from.Mobile == m && to.Mobile == Mobile)

View file

@ -6,7 +6,7 @@ using Server.Network;
namespace Server.Accounting namespace Server.Accounting
{ {
public class AccountAttackLimiter public static class AccountAttackLimiter
{ {
public static bool Enabled; public static bool Enabled;
@ -20,7 +20,9 @@ namespace Server.Accounting
public static void Initialize() public static void Initialize()
{ {
if (!Enabled) if (!Enabled)
{
return; return;
}
PacketHandlers.RegisterThrottler(0x80, Throttle_Callback); PacketHandlers.RegisterThrottler(0x80, Throttle_Callback);
PacketHandlers.RegisterThrottler(0x91, Throttle_Callback); PacketHandlers.RegisterThrottler(0x91, Throttle_Callback);
@ -32,7 +34,9 @@ namespace Server.Accounting
var accessLog = FindAccessLog(ns); var accessLog = FindAccessLog(ns);
if (accessLog == null) if (accessLog == null)
{
return TimeSpan.Zero; return TimeSpan.Zero;
}
var date = DateTime.UtcNow; var date = DateTime.UtcNow;
var access = accessLog.LastAccessTime + ComputeThrottle(accessLog.Counts); var access = accessLog.LastAccessTime + ComputeThrottle(accessLog.Counts);
@ -42,7 +46,9 @@ namespace Server.Accounting
public static InvalidAccountAccessLog FindAccessLog(NetState ns) public static InvalidAccountAccessLog FindAccessLog(NetState ns)
{ {
if (ns == null) if (ns == null)
{
return null; return null;
}
var ipAddress = ns.Address; var ipAddress = ns.Address;
@ -51,9 +57,13 @@ namespace Server.Accounting
var accessLog = m_List[i]; var accessLog = m_List[i];
if (accessLog.HasExpired) if (accessLog.HasExpired)
{
m_List.RemoveAt(i--); m_List.RemoveAt(i--);
}
else if (accessLog.Address.Equals(ipAddress)) else if (accessLog.Address.Equals(ipAddress))
{
return accessLog; return accessLog;
}
} }
return null; return null;
@ -62,17 +72,22 @@ namespace Server.Accounting
public static void RegisterInvalidAccess(NetState ns) public static void RegisterInvalidAccess(NetState ns)
{ {
if (ns == null || !Enabled) if (ns == null || !Enabled)
{
return; return;
}
var accessLog = FindAccessLog(ns); var accessLog = FindAccessLog(ns);
if (accessLog == null) if (accessLog == null)
{
m_List.Add(accessLog = new InvalidAccountAccessLog(ns.Address)); m_List.Add(accessLog = new InvalidAccountAccessLog(ns.Address));
}
accessLog.Counts += 1; accessLog.Counts += 1;
accessLog.RefreshAccessTime(); accessLog.RefreshAccessTime();
if (accessLog.Counts >= 3) if (accessLog.Counts >= 3)
{
try try
{ {
using var op = new StreamWriter("throttle.log", true); using var op = new StreamWriter("throttle.log", true);
@ -87,24 +102,35 @@ namespace Server.Accounting
{ {
// ignored // ignored
} }
}
} }
public static TimeSpan ComputeThrottle(int counts) public static TimeSpan ComputeThrottle(int counts)
{ {
if (counts >= 15) if (counts >= 15)
{
return TimeSpan.FromMinutes(5.0); return TimeSpan.FromMinutes(5.0);
}
if (counts >= 10) if (counts >= 10)
{
return TimeSpan.FromMinutes(1.0); return TimeSpan.FromMinutes(1.0);
}
if (counts >= 5) if (counts >= 5)
{
return TimeSpan.FromSeconds(20.0); return TimeSpan.FromSeconds(20.0);
}
if (counts >= 3) if (counts >= 3)
{
return TimeSpan.FromSeconds(10.0); return TimeSpan.FromSeconds(10.0);
}
if (counts >= 1) if (counts >= 1)
{
return TimeSpan.FromSeconds(2.0); return TimeSpan.FromSeconds(2.0);
}
return TimeSpan.Zero; return TimeSpan.Zero;
} }

View file

@ -33,7 +33,9 @@ namespace Server.Ethics
if ((item.SavedFlags & 0x100) != 0) if ((item.SavedFlags & 0x100) != 0)
{ {
if (item.Hue == Hero.Definition.PrimaryHue) if (item.Hue == Hero.Definition.PrimaryHue)
{
return Hero; return Hero;
}
item.SavedFlags &= ~0x100; item.SavedFlags &= ~0x100;
} }
@ -41,7 +43,9 @@ namespace Server.Ethics
if ((item.SavedFlags & 0x200) != 0) if ((item.SavedFlags & 0x200) != 0)
{ {
if (item.Hue == Evil.Definition.PrimaryHue) if (item.Hue == Evil.Definition.PrimaryHue)
{
return Evil; return Evil;
}
item.SavedFlags &= ~0x200; item.SavedFlags &= ~0x200;
} }
@ -54,12 +58,18 @@ namespace Server.Ethics
var itemEthic = Find(item); var itemEthic = Find(item);
if (itemEthic == null || Find(newOwner) == itemEthic) if (itemEthic == null || Find(newOwner) == itemEthic)
{
return true; return true;
}
if (itemEthic == Hero) if (itemEthic == Hero)
{
(from == newOwner ? to : from).SendMessage("Only heros may receive this item."); (from == newOwner ? to : from).SendMessage("Only heros may receive this item.");
}
else if (itemEthic == Evil) else if (itemEthic == Evil)
{
(from == newOwner ? to : from).SendMessage("Only the evil may receive this item."); (from == newOwner ? to : from).SendMessage("Only the evil may receive this item.");
}
return false; return false;
} }
@ -69,12 +79,18 @@ namespace Server.Ethics
var itemEthic = Find(item); var itemEthic = Find(item);
if (itemEthic == null || Find(from) == itemEthic) if (itemEthic == null || Find(from) == itemEthic)
{
return true; return true;
}
if (itemEthic == Hero) if (itemEthic == Hero)
{
from.SendMessage("Only heros may wear this item."); from.SendMessage("Only heros may wear this item.");
}
else if (itemEthic == Evil) else if (itemEthic == Evil)
{
from.SendMessage("Only the evil may wear this item."); from.SendMessage("Only the evil may wear this item.");
}
return false; return false;
} }
@ -84,28 +100,43 @@ namespace Server.Ethics
public static bool IsImbued(Item item, bool recurse) public static bool IsImbued(Item item, bool recurse)
{ {
if (Find(item) != null) if (Find(item) != null)
{
return true; return true;
}
if (recurse) if (recurse)
{
foreach (var child in item.Items) foreach (var child in item.Items)
{
if (IsImbued(child, true)) if (IsImbued(child, true))
{
return true; return true;
}
}
}
return false; return false;
} }
public static void Initialize() public static void Configure()
{ {
Enabled = ServerConfiguration.GetOrUpdateSetting("ethics.enable", false); Enabled = ServerConfiguration.GetOrUpdateSetting("ethics.enable", false);
}
public static void Initialize()
{
if (Enabled) if (Enabled)
{
EventSink.Speech += EventSink_Speech; EventSink.Speech += EventSink_Speech;
}
} }
public static void EventSink_Speech(SpeechEventArgs e) public static void EventSink_Speech(SpeechEventArgs e)
{ {
if (e.Blocked || e.Handled) if (e.Blocked || e.Handled)
{
return; return;
}
var pl = Player.Find(e.Mobile); var pl = Player.Find(e.Mobile);
@ -116,13 +147,19 @@ namespace Server.Ethics
var ethic = Ethics[i]; var ethic = Ethics[i];
if (!ethic.IsEligible(e.Mobile)) if (!ethic.IsEligible(e.Mobile))
{
continue; continue;
}
if (!Insensitive.Equals(ethic.Definition.JoinPhrase.String, e.Speech)) if (!Insensitive.Equals(ethic.Definition.JoinPhrase.String, e.Speech))
{
continue; continue;
}
if (!e.Mobile.GetItemsInRange(2).Any(item => item is AnkhNorth || item is AnkhWest)) if (!e.Mobile.GetItemsInRange(2).Any(item => item is AnkhNorth || item is AnkhWest))
{
continue; continue;
}
pl = new Player(ethic, e.Mobile); pl = new Player(ethic, e.Mobile);
@ -138,7 +175,9 @@ namespace Server.Ethics
else else
{ {
if (e.Mobile is PlayerMobile mobile && mobile.DuelContext != null) if (e.Mobile is PlayerMobile mobile && mobile.DuelContext != null)
{
return; return;
}
var ethic = pl.Ethic; var ethic = pl.Ethic;
@ -147,10 +186,14 @@ namespace Server.Ethics
var power = ethic.Definition.Powers[i]; var power = ethic.Definition.Powers[i];
if (!Insensitive.Equals(power.Definition.Phrase.String, e.Speech)) if (!Insensitive.Equals(power.Definition.Phrase.String, e.Speech))
{
continue; continue;
}
if (!power.CheckInvoke(pl)) if (!power.CheckInvoke(pl))
{
continue; continue;
}
power.BeginInvoke(pl); power.BeginInvoke(pl);
e.Handled = true; e.Handled = true;
@ -169,16 +212,26 @@ namespace Server.Ethics
var pl = Player.Find(mob); var pl = Player.Find(mob);
if (pl != null) if (pl != null)
{
return pl.Ethic; return pl.Ethic;
}
if (inherit && mob is BaseCreature bc) if (inherit && mob is BaseCreature bc)
{ {
if (bc.Controlled) if (bc.Controlled)
{
return Find(bc.ControlMaster, false); return Find(bc.ControlMaster, false);
}
if (bc.Summoned) if (bc.Summoned)
{
return Find(bc.SummonMaster, false); return Find(bc.SummonMaster, false);
}
if (allegiance) if (allegiance)
{
return bc.EthicAllegiance; return bc.EthicAllegiance;
}
} }
return null; return null;
@ -201,7 +254,9 @@ namespace Server.Ethics
var pl = new Player(this, reader); var pl = new Player(this, reader);
if (pl.Mobile != null) if (pl.Mobile != null)
{
Timer.DelayCall(pl.CheckAttach); Timer.DelayCall(pl.CheckAttach);
}
} }
break; break;
@ -216,7 +271,9 @@ namespace Server.Ethics
writer.WriteEncodedInt(m_Players.Count); writer.WriteEncodedInt(m_Players.Count);
for (var i = 0; i < m_Players.Count; ++i) for (var i = 0; i < m_Players.Count; ++i)
{
m_Players[i].Serialize(writer); m_Players[i].Serialize(writer);
}
} }
} }
} }

View file

@ -41,7 +41,7 @@ namespace Server.Factions
if (faction == null && from.AccessLevel < AccessLevel.GameMaster) if (faction == null && from.AccessLevel < AccessLevel.GameMaster)
return; // TODO: Message? return; // TODO: Message?
if (m_Town.Owner == null || @from.AccessLevel < AccessLevel.GameMaster && faction != m_Town.Owner) if (m_Town.Owner == null || from.AccessLevel < AccessLevel.GameMaster && faction != m_Town.Owner)
from.SendLocalizedMessage(1010332); // Your faction does not control this town from.SendLocalizedMessage(1010332); // Your faction does not control this town
else if (!m_Town.Owner.IsCommander(from)) else if (!m_Town.Owner.IsCommander(from))
from.SendLocalizedMessage(1005242); // Only faction Leaders can use townstones from.SendLocalizedMessage(1005242); // Only faction Leaders can use townstones

View file

@ -43,7 +43,9 @@ namespace Server.Engines.MLQuests
while ((line = sr.ReadLine()) != null) while ((line = sr.ReadLine()) != null)
{ {
if (line.Length == 0 || line.StartsWith("#")) if (line.Length == 0 || line.StartsWith("#"))
{
continue; continue;
}
var split = line.Split('\t'); var split = line.Split('\t');
@ -52,11 +54,13 @@ namespace Server.Engines.MLQuests
if (type == null || !baseQuestType.IsAssignableFrom(type)) if (type == null || !baseQuestType.IsAssignableFrom(type))
{ {
if (Debug) if (Debug)
{
Console.WriteLine( Console.WriteLine(
"Warning: {1} quest type '{0}'", "Warning: {1} quest type '{0}'",
split[0], split[0],
type == null ? "Unknown" : "Invalid" type == null ? "Unknown" : "Invalid"
); );
}
continue; continue;
} }
@ -73,7 +77,9 @@ namespace Server.Engines.MLQuests
} }
if (quest == null) if (quest == null)
{
continue; continue;
}
Register(type, quest); Register(type, quest);
@ -84,11 +90,13 @@ namespace Server.Engines.MLQuests
if (questerType == null || !baseQuesterType.IsAssignableFrom(questerType)) if (questerType == null || !baseQuesterType.IsAssignableFrom(questerType))
{ {
if (Debug) if (Debug)
{
Console.WriteLine( Console.WriteLine(
"Warning: {1} quester type '{0}'", "Warning: {1} quester type '{0}'",
split[i], split[i],
questerType == null ? "Unknown" : "Invalid" questerType == null ? "Unknown" : "Invalid"
); );
}
continue; continue;
} }
@ -115,7 +123,9 @@ namespace Server.Engines.MLQuests
private static void RegisterQuestGiver(MLQuest quest, Type questerType) private static void RegisterQuestGiver(MLQuest quest, Type questerType)
{ {
if (!QuestGivers.TryGetValue(questerType, out var questList)) if (!QuestGivers.TryGetValue(questerType, out var questList))
{
QuestGivers[questerType] = questList = new List<MLQuest>(); QuestGivers[questerType] = questList = new List<MLQuest>();
}
questList.Add(quest); questList.Add(quest);
} }
@ -125,20 +135,33 @@ namespace Server.Engines.MLQuests
Register(quest.GetType(), quest); Register(quest.GetType(), quest);
foreach (var questerType in questerTypes) foreach (var questerType in questerTypes)
{
RegisterQuestGiver(quest, questerType); RegisterQuestGiver(quest, questerType);
}
}
public static void Configure()
{
Enabled = ServerConfiguration.GetOrUpdateSetting("questSystem.enableMLQuests", Core.ML);
} }
public static void Initialize() public static void Initialize()
{ {
Enabled = ServerConfiguration.GetOrUpdateSetting("questSystem.enableMLQuests", Core.ML);
if (!Enabled) if (!Enabled)
{
return; return;
}
if (AutoGenerateNew) if (AutoGenerateNew)
{
foreach (var quest in Quests.Values) foreach (var quest in Quests.Values)
{
if (quest?.Deserialized == false) if (quest?.Deserialized == false)
{
quest.Generate(); quest.Generate();
}
}
}
MLQuestPersistence.EnsureExistence(); MLQuestPersistence.EnsureExistence();
@ -205,9 +228,11 @@ namespace Server.Engines.MLQuests
m.SendMessage("Serialization for quest {0} is now {1}.", quest.GetType().Name, enable ? "enabled" : "disabled"); m.SendMessage("Serialization for quest {0} is now {1}.", quest.GetType().Name, enable ? "enabled" : "disabled");
if (AutoGenerateNew && !enable) if (AutoGenerateNew && !enable)
{
m.SendMessage( m.SendMessage(
"Please note that automatic generation of new quests is ON. This quest will be regenerated on the next server start." "Please note that automatic generation of new quests is ON. This quest will be regenerated on the next server start."
); );
}
} }
[Usage("SaveAllQuests [saveEnabled=true]")] [Usage("SaveAllQuests [saveEnabled=true]")]
@ -225,14 +250,18 @@ namespace Server.Engines.MLQuests
var enable = e.Length == 1 ? e.GetBoolean(0) : true; var enable = e.Length == 1 ? e.GetBoolean(0) : true;
foreach (var quest in Quests.Values) foreach (var quest in Quests.Values)
{
quest.SaveEnabled = enable; quest.SaveEnabled = enable;
}
m.SendMessage("Serialization for all quests is now {0}.", enable ? "enabled" : "disabled"); m.SendMessage("Serialization for all quests is now {0}.", enable ? "enabled" : "disabled");
if (AutoGenerateNew && !enable) if (AutoGenerateNew && !enable)
{
m.SendMessage( m.SendMessage(
"Please note that automatic generation of new quests is ON. All quests will be regenerated on the next server start." "Please note that automatic generation of new quests is ON. All quests will be regenerated on the next server start."
); );
}
} }
[Usage("InvalidQuestItems")] [Usage("InvalidQuestItems")]
@ -244,19 +273,29 @@ namespace Server.Engines.MLQuests
var found = new List<object>(); var found = new List<object>();
foreach (var item in World.Items.Values) foreach (var item in World.Items.Values)
{
if (item.QuestItem) if (item.QuestItem)
{ {
if (item.Parent is Backpack pack) if (item.Parent is Backpack pack)
{
if (pack.Parent is PlayerMobile player && player.Backpack == pack) if (pack.Parent is PlayerMobile player && player.Backpack == pack)
{
continue; continue;
}
}
found.Add(item); found.Add(item);
} }
}
if (found.Count == 0) if (found.Count == 0)
{
m.SendMessage("No matching objects found."); m.SendMessage("No matching objects found.");
}
else else
{
m.SendGump(new InterfaceGump(m, new[] { "Object" }, found, 0, null)); m.SendGump(new InterfaceGump(m, new[] { "Object" }, found, 0, null));
}
} }
private static bool FindQuest( private static bool FindQuest(
@ -272,6 +311,7 @@ namespace Server.Engines.MLQuests
// 1. Check quests in progress with this NPC (overriding deliveries is intended) // 1. Check quests in progress with this NPC (overriding deliveries is intended)
if (context != null) if (context != null)
{
foreach (var questEntry in quests) foreach (var questEntry in quests)
{ {
var instance = context.FindInstance(questEntry); var instance = context.FindInstance(questEntry);
@ -284,6 +324,7 @@ namespace Server.Engines.MLQuests
return true; return true;
} }
} }
}
// 2. Check deliveries (overriding chain offers is intended) // 2. Check deliveries (overriding chain offers is intended)
if ((entry = HandleDelivery(pm, quester, questerType)) != null) if ((entry = HandleDelivery(pm, quester, questerType)) != null)
@ -294,12 +335,16 @@ namespace Server.Engines.MLQuests
// 3. Check chain quest offers // 3. Check chain quest offers
if (context != null) if (context != null)
{
foreach (var questEntry in quests) foreach (var questEntry in quests)
{
if (questEntry.IsChainTriggered && context.ChainOffers.Contains(questEntry)) if (questEntry.IsChainTriggered && context.ChainOffers.Contains(questEntry))
{ {
quest = questEntry; quest = questEntry;
return true; return true;
} }
}
}
// 4. Random quest // 4. Random quest
quest = RandomStarterQuest(quester, pm, context); quest = RandomStarterQuest(quester, pm, context);
@ -310,7 +355,9 @@ namespace Server.Engines.MLQuests
public static void OnDoubleClick(IQuestGiver quester, PlayerMobile pm) public static void OnDoubleClick(IQuestGiver quester, PlayerMobile pm)
{ {
if (quester.Deleted || !pm.Alive) if (quester.Deleted || !pm.Alive)
{
return; return;
}
var context = GetContext(pm); var context = GetContext(pm);
@ -325,13 +372,22 @@ namespace Server.Engines.MLQuests
TurnToFace(quester, pm); TurnToFace(quester, pm);
if (entry.Failed) if (entry.Failed)
{
return; // Note: OSI sends no gump at all for failed quests, they have to be cancelled in the quest overview return; // Note: OSI sends no gump at all for failed quests, they have to be cancelled in the quest overview
}
if (entry.ClaimReward) if (entry.ClaimReward)
{
entry.SendRewardOffer(); entry.SendRewardOffer();
}
else if (entry.IsCompleted()) else if (entry.IsCompleted())
{
entry.SendReportBackGump(); entry.SendReportBackGump();
}
else else
{
entry.SendProgressGump(); entry.SendProgressGump();
}
} }
else if (quest.CanOffer(quester, pm, context, true)) else if (quest.CanOffer(quester, pm, context, true))
{ {
@ -346,9 +402,15 @@ namespace Server.Engines.MLQuests
var context = GetContext(pm); var context = GetContext(pm);
if (context != null) if (context != null)
{
foreach (var quest in context.QuestInstances) foreach (var quest in context.QuestInstances)
{
if (!quest.ClaimReward && quest.AllowsQuestItem(item, type)) if (!quest.ClaimReward && quest.AllowsQuestItem(item, type))
{
return true; return true;
}
}
}
return false; return false;
} }
@ -358,7 +420,9 @@ namespace Server.Engines.MLQuests
var context = GetContext(pm); var context = GetContext(pm);
if (context == null) if (context == null)
{
return; return;
}
var instances = context.QuestInstances; var instances = context.QuestInstances;
@ -368,14 +432,18 @@ namespace Server.Engines.MLQuests
var instance = instances[i]; var instance = instances[i];
if (instance.ClaimReward) if (instance.ClaimReward)
{
continue; continue;
}
foreach (var objective in instance.Objectives) foreach (var objective in instance.Objectives)
{
if (!objective.Expired && objective.AllowsQuestItem(item, type)) if (!objective.Expired && objective.AllowsQuestItem(item, type))
{ {
objective.CheckComplete(); // yes, this can happen multiple times (for multiple quests) objective.CheckComplete(); // yes, this can happen multiple times (for multiple quests)
break; break;
} }
}
} }
} }
@ -399,7 +467,9 @@ namespace Server.Engines.MLQuests
var context = GetContext(pm); var context = GetContext(pm);
if (context == null) if (context == null)
{
return; return;
}
var instances = context.QuestInstances; var instances = context.QuestInstances;
@ -408,15 +478,19 @@ namespace Server.Engines.MLQuests
var instance = instances[i]; var instance = instances[i];
if (instance.ClaimReward) if (instance.ClaimReward)
{
continue; continue;
}
foreach (var objective in instance.Objectives) foreach (var objective in instance.Objectives)
{
if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance && if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance &&
objectiveInstance.Handles(skill)) objectiveInstance.Handles(skill))
{ {
objectiveInstance.CheckComplete(); objectiveInstance.CheckComplete();
break; break;
} }
}
} }
} }
@ -425,7 +499,9 @@ namespace Server.Engines.MLQuests
var context = GetContext(pm); var context = GetContext(pm);
if (context == null) if (context == null)
{
return; return;
}
var instances = context.QuestInstances; var instances = context.QuestInstances;
@ -436,13 +512,16 @@ namespace Server.Engines.MLQuests
var instance = instances[i]; var instance = instances[i];
if (instance.ClaimReward) if (instance.ClaimReward)
{
continue; continue;
}
/* A kill only counts for a single objective within a quest, /* A kill only counts for a single objective within a quest,
* but it can count for multiple quests. This is something not * but it can count for multiple quests. This is something not
* currently observable on OSI, so it is assumed behavior. * currently observable on OSI, so it is assumed behavior.
*/ */
foreach (var objective in instance.Objectives) foreach (var objective in instance.Objectives)
{
if (!objective.Expired && objective is KillObjectiveInstance kill) if (!objective.Expired && objective is KillObjectiveInstance kill)
{ {
type ??= mob.GetType(); type ??= mob.GetType();
@ -453,6 +532,7 @@ namespace Server.Engines.MLQuests
break; break;
} }
} }
}
} }
} }
@ -461,7 +541,9 @@ namespace Server.Engines.MLQuests
var context = GetContext(pm); var context = GetContext(pm);
if (context == null) if (context == null)
{
return null; return null;
}
var instances = context.QuestInstances; var instances = context.QuestInstances;
MLQuestInstance deliverInstance = null; MLQuestInstance deliverInstance = null;
@ -476,6 +558,7 @@ namespace Server.Engines.MLQuests
foreach (var objective in instance.Objectives) foreach (var objective in instance.Objectives)
// Note: On OSI, expired deliveries can still be completed. Bug? // Note: On OSI, expired deliveries can still be completed. Bug?
{
if (!objective.Expired && objective is DeliverObjectiveInstance deliver && if (!objective.Expired && objective is DeliverObjectiveInstance deliver &&
deliver.IsDestination(quester, questerType)) deliver.IsDestination(quester, questerType))
{ {
@ -492,6 +575,7 @@ namespace Server.Engines.MLQuests
break; // don't return, we may have to complete more deliveries break; // don't return, we may have to complete more deliveries
} }
}
} }
return deliverInstance; return deliverInstance;
@ -507,7 +591,9 @@ namespace Server.Engines.MLQuests
public static MLQuestContext GetOrCreateContext(PlayerMobile pm) public static MLQuestContext GetOrCreateContext(PlayerMobile pm)
{ {
if (!Contexts.TryGetValue(pm, out var context)) if (!Contexts.TryGetValue(pm, out var context))
{
Contexts[pm] = context = new MLQuestContext(pm); Contexts[pm] = context = new MLQuestContext(pm);
}
return context; return context;
} }
@ -541,7 +627,9 @@ namespace Server.Engines.MLQuests
var instance = instances[i]; var instance = instances[i];
if (instance.Quester == quester) if (instance.Quester == quester)
{
instance.OnQuesterDeleted(); instance.OnQuesterDeleted();
}
} }
} }
} }
@ -549,7 +637,9 @@ namespace Server.Engines.MLQuests
public static void EventSink_QuestGumpRequest(Mobile m) public static void EventSink_QuestGumpRequest(Mobile m)
{ {
if (!Enabled || !(m is PlayerMobile pm)) if (!Enabled || !(m is PlayerMobile pm))
{
return; return;
}
pm.SendGump(new QuestLogGump(pm)); pm.SendGump(new QuestLogGump(pm));
} }
@ -559,7 +649,9 @@ namespace Server.Engines.MLQuests
var quests = quester.MLQuests; var quests = quester.MLQuests;
if (quests.Count == 0) if (quests.Count == 0)
{
return null; return null;
}
m_EligiblePool.Clear(); m_EligiblePool.Clear();
MLQuest fallback = null; MLQuest fallback = null;
@ -567,7 +659,9 @@ namespace Server.Engines.MLQuests
foreach (var quest in quests) foreach (var quest in quests)
{ {
if (quest.IsChainTriggered || context?.IsDoingQuest(quest) == true) if (quest.IsChainTriggered || context?.IsDoingQuest(quest) == true)
{
continue; continue;
}
/* /*
* Save first quest that reaches the CanOffer call. * Save first quest that reaches the CanOffer call.
@ -576,7 +670,9 @@ namespace Server.Engines.MLQuests
fallback ??= quest; fallback ??= quest;
if (quest.CanOffer(quester, pm, context, false)) if (quest.CanOffer(quester, pm, context, false))
{
m_EligiblePool.Add(quest); m_EligiblePool.Add(quest);
}
} }
return m_EligiblePool.Count == 0 ? fallback : m_EligiblePool.RandomElement(); return m_EligiblePool.Count == 0 ? fallback : m_EligiblePool.RandomElement();
@ -585,7 +681,9 @@ namespace Server.Engines.MLQuests
public static void TurnToFace(IQuestGiver quester, Mobile mob) public static void TurnToFace(IQuestGiver quester, Mobile mob)
{ {
if (quester is Mobile m) if (quester is Mobile m)
{
m.Direction = m.GetDirectionTo(mob); m.Direction = m.GetDirectionTo(mob);
}
} }
public static void Tell(IQuestGiver quester, PlayerMobile pm, int cliloc) public static void Tell(IQuestGiver quester, PlayerMobile pm, int cliloc)
@ -593,11 +691,17 @@ namespace Server.Engines.MLQuests
TurnToFace(quester, pm); TurnToFace(quester, pm);
if (quester is Mobile mobile) if (quester is Mobile mobile)
{
mobile.PrivateOverheadMessage(MessageType.Regular, SpeechColor, cliloc, pm.NetState); mobile.PrivateOverheadMessage(MessageType.Regular, SpeechColor, cliloc, pm.NetState);
}
else if (quester is Item item) else if (quester is Item item)
{
MessageHelper.SendLocalizedMessageTo(item, pm, cliloc, SpeechColor); MessageHelper.SendLocalizedMessageTo(item, pm, cliloc, SpeechColor);
}
else else
{
pm.SendLocalizedMessage(cliloc); pm.SendLocalizedMessage(cliloc);
}
} }
public static void Tell(IQuestGiver quester, PlayerMobile pm, int cliloc, string args) public static void Tell(IQuestGiver quester, PlayerMobile pm, int cliloc, string args)
@ -605,11 +709,17 @@ namespace Server.Engines.MLQuests
TurnToFace(quester, pm); TurnToFace(quester, pm);
if (quester is Mobile mobile) if (quester is Mobile mobile)
{
mobile.PrivateOverheadMessage(MessageType.Regular, SpeechColor, cliloc, args, pm.NetState); mobile.PrivateOverheadMessage(MessageType.Regular, SpeechColor, cliloc, args, pm.NetState);
}
else if (quester is Item item) else if (quester is Item item)
{
MessageHelper.SendLocalizedMessageTo(item, pm, cliloc, args, SpeechColor); MessageHelper.SendLocalizedMessageTo(item, pm, cliloc, args, SpeechColor);
}
else else
{
pm.SendLocalizedMessage(cliloc, args); pm.SendLocalizedMessage(cliloc, args);
}
} }
public static void Tell(IQuestGiver quester, PlayerMobile pm, string message) public static void Tell(IQuestGiver quester, PlayerMobile pm, string message)
@ -617,22 +727,34 @@ namespace Server.Engines.MLQuests
TurnToFace(quester, pm); TurnToFace(quester, pm);
if (quester is Mobile mobile) if (quester is Mobile mobile)
{
mobile.PrivateOverheadMessage(MessageType.Regular, SpeechColor, false, message, pm.NetState); mobile.PrivateOverheadMessage(MessageType.Regular, SpeechColor, false, message, pm.NetState);
}
else if (quester is Item item) else if (quester is Item item)
{
MessageHelper.SendMessageTo(item, pm, message, SpeechColor); MessageHelper.SendMessageTo(item, pm, message, SpeechColor);
}
else else
{
pm.SendMessage(SpeechColor, message); pm.SendMessage(SpeechColor, message);
}
} }
public static void TellDef(IQuestGiver quester, PlayerMobile pm, TextDefinition def) public static void TellDef(IQuestGiver quester, PlayerMobile pm, TextDefinition def)
{ {
if (def == null) if (def == null)
{
return; return;
}
if (def.Number > 0) if (def.Number > 0)
{
Tell(quester, pm, def.Number); Tell(quester, pm, def.Number);
}
else if (def.String != null) else if (def.String != null)
{
Tell(quester, pm, def.String); Tell(quester, pm, def.String);
}
} }
public static void WriteQuestRef(IGenericWriter writer, MLQuest quest) public static void WriteQuestRef(IGenericWriter writer, MLQuest quest)
@ -645,12 +767,16 @@ namespace Server.Engines.MLQuests
var typeName = reader.ReadString(); var typeName = reader.ReadString();
if (typeName == null) if (typeName == null)
{
return null; // not serialized return null; // not serialized
}
var questType = AssemblyHandler.FindFirstTypeForName(typeName); var questType = AssemblyHandler.FindFirstTypeForName(typeName);
if (questType == null) if (questType == null)
{
return null; // no longer a type return null; // no longer a type
}
return FindQuest(questType); return FindQuest(questType);
} }
@ -713,9 +839,13 @@ namespace Server.Engines.MLQuests
public override void Execute(CommandEventArgs e, object obj) public override void Execute(CommandEventArgs e, object obj)
{ {
if (!(obj is PlayerMobile pm)) if (!(obj is PlayerMobile pm))
{
LogFailure("They have no ML quest context."); LogFailure("They have no ML quest context.");
}
else else
{
e.Mobile.SendGump(new PropertiesGump(e.Mobile, GetOrCreateContext(pm))); e.Mobile.SendGump(new PropertiesGump(e.Mobile, GetOrCreateContext(pm)));
}
} }
} }
} }

View file

@ -18,38 +18,38 @@ namespace Server.Engines.PartySystem
if (from == m) if (from == m)
{ {
@from.SendLocalizedMessage(1005439); // You cannot add yourself to a party. from.SendLocalizedMessage(1005439); // You cannot add yourself to a party.
} }
else if (p != null && p.Leader != from) else if (p != null && p.Leader != from)
{ {
@from.SendLocalizedMessage(1005453); // You may only add members to the party if you are the leader. from.SendLocalizedMessage(1005453); // You may only add members to the party if you are the leader.
} }
else if (m.Party is Mobile) else if (m.Party is Mobile)
{ {
} }
else if (p != null && p.Members.Count + p.Candidates.Count >= Party.Capacity) else if (p != null && p.Members.Count + p.Candidates.Count >= Party.Capacity)
{ {
@from.SendLocalizedMessage(1008095); // You may only have 10 in your party (this includes candidates). from.SendLocalizedMessage(1008095); // You may only have 10 in your party (this includes candidates).
} }
else if (!m.Player && m.Body.IsHuman) else if (!m.Player && m.Body.IsHuman)
{ {
m.SayTo(@from, 1005443); // Nay, I would rather stay here and watch a nail rust. m.SayTo(from, 1005443); // Nay, I would rather stay here and watch a nail rust.
} }
else if (!m.Player) else if (!m.Player)
{ {
@from.SendLocalizedMessage(1005444); // The creature ignores your offer. from.SendLocalizedMessage(1005444); // The creature ignores your offer.
} }
else if (mp != null && mp == p) else if (mp != null && mp == p)
{ {
@from.SendLocalizedMessage(1005440); // This person is already in your party! from.SendLocalizedMessage(1005440); // This person is already in your party!
} }
else if (mp != null) else if (mp != null)
{ {
@from.SendLocalizedMessage(1005441); // This person is already in a party! from.SendLocalizedMessage(1005441); // This person is already in a party!
} }
else else
{ {
Party.Invite(@from, m); Party.Invite(from, m);
} }
} }
else else

View file

@ -24,7 +24,7 @@ namespace Server
public IPoint3D Goal { get; } public IPoint3D Goal { get; }
public static void Initialize() public static void Configure()
{ {
Enabled = ServerConfiguration.GetOrUpdateSetting("pathfinding.enable", true); Enabled = ServerConfiguration.GetOrUpdateSetting("pathfinding.enable", true);
} }

View file

@ -284,8 +284,8 @@ namespace Server.Engines.Plants
} }
public bool IsUsableBy(Mobile from) => public bool IsUsableBy(Mobile from) =>
IsChildOf(from.Backpack) || IsChildOf(from.FindBankNoCreate()) || IsLockedDown && IsAccessibleTo(@from) || IsChildOf(from.Backpack) || IsChildOf(from.FindBankNoCreate()) || IsLockedDown && IsAccessibleTo(from) ||
RootParent is Item root && root.IsSecure && root.IsAccessibleTo(@from); RootParent is Item root && root.IsSecure && root.IsAccessibleTo(from);
public override void OnDoubleClick(Mobile from) public override void OnDoubleClick(Mobile from)
{ {

View file

@ -95,7 +95,7 @@ namespace Server.Engines.Quests.Doom
); );
Effects.PlaySound(loc, Map, 0x1FE); Effects.PlaySound(loc, Map, 0x1FE);
Chyloth = new Chyloth { Direction = (Direction)(7 & (4 + (int)@from.GetDirectionTo(loc))) }; Chyloth = new Chyloth { Direction = (Direction)(7 & (4 + (int)from.GetDirectionTo(loc))) };
Chyloth.MoveToWorld(loc, Map); Chyloth.MoveToWorld(loc, Map);

View file

@ -22,7 +22,9 @@ namespace Server.Engines.VeteranRewards
get get
{ {
if (m_Categories == null) if (m_Categories == null)
{
SetupRewardTables(); SetupRewardTables();
}
return m_Categories; return m_Categories;
} }
@ -33,7 +35,9 @@ namespace Server.Engines.VeteranRewards
get get
{ {
if (m_Lists == null) if (m_Lists == null)
{
SetupRewardTables(); SetupRewardTables();
}
return m_Lists; return m_Lists;
} }
@ -45,15 +49,22 @@ namespace Server.Engines.VeteranRewards
for (var j = 0; j < entries.Count; ++j) for (var j = 0; j < entries.Count; ++j)
// RewardEntry entry = entries[j]; // RewardEntry entry = entries[j];
{
if (HasAccess(mob, entries[j])) if (HasAccess(mob, entries[j]))
{
return true; return true;
}
}
return false; return false;
} }
public static bool HasAccess(Mobile mob, RewardEntry entry) public static bool HasAccess(Mobile mob, RewardEntry entry)
{ {
if (Core.Expansion < entry.RequiredExpansion) if (Core.Expansion < entry.RequiredExpansion)
{
return false; return false;
}
return HasAccess(mob, entry.List, out var _); return HasAccess(mob, entry.List, out var _);
} }
@ -77,7 +88,9 @@ namespace Server.Engines.VeteranRewards
ts = list.Age - totalTime; ts = list.Age - totalTime;
if (ts <= TimeSpan.Zero) if (ts <= TimeSpan.Zero)
{
return true; return true;
}
return false; return false;
} }
@ -85,7 +98,9 @@ namespace Server.Engines.VeteranRewards
public static int GetRewardLevel(Mobile mob) public static int GetRewardLevel(Mobile mob)
{ {
if (!(mob.Account is Account acct)) if (!(mob.Account is Account acct))
{
return 0; return 0;
}
return GetRewardLevel(acct); return GetRewardLevel(acct);
} }
@ -100,7 +115,9 @@ namespace Server.Engines.VeteranRewards
public static bool HasHalfLevel(Mobile mob) public static bool HasHalfLevel(Mobile mob)
{ {
if (!(mob.Account is Account acct)) if (!(mob.Account is Account acct))
{
return false; return false;
}
return HasHalfLevel(acct); return HasHalfLevel(acct);
} }
@ -119,10 +136,14 @@ namespace Server.Engines.VeteranRewards
ComputeRewardInfo(mob, out var cur, out var max); ComputeRewardInfo(mob, out var cur, out var max);
if (cur >= max) if (cur >= max)
{
return false; return false;
}
if (!(mob.Account is Account acct)) if (!(mob.Account is Account acct))
{
return false; return false;
}
// if (mob.AccessLevel < AccessLevel.GameMaster) // if (mob.AccessLevel < AccessLevel.GameMaster)
acct.SetTag("numRewardsChosen", (cur + 1).ToString()); acct.SetTag("numRewardsChosen", (cur + 1).ToString());
@ -154,14 +175,22 @@ namespace Server.Engines.VeteranRewards
var tag = acct.GetTag("numRewardsChosen"); var tag = acct.GetTag("numRewardsChosen");
if (string.IsNullOrEmpty(tag)) if (string.IsNullOrEmpty(tag))
{
cur = 0; cur = 0;
}
else else
{
cur = Utility.ToInt32(tag); cur = Utility.ToInt32(tag);
}
if (level >= 6) if (level >= 6)
{
max = 9 + (level - 6) * 2; max = 9 + (level - 6) * 2;
}
else else
{
max = 2 + level; max = 2 + level;
}
} }
public static bool CheckIsUsableBy(Mobile from, Item item, object[] args = null) public static bool CheckIsUsableBy(Mobile from, Item item, object[] args = null)
@ -178,12 +207,16 @@ namespace Server.Engines.VeteranRewards
for (var j = 0; j < entries.Length; ++j) for (var j = 0; j < entries.Length; ++j)
{ {
if (entries[j].ItemType != type) if (entries[j].ItemType != type)
{
continue; continue;
}
if (args == null && entries[j].Args.Length == 0) if (args == null && entries[j].Args.Length == 0)
{ {
if (isRelaxedRules && i <= 0 || HasAccess(from, list, out var ts)) if (isRelaxedRules && i <= 0 || HasAccess(from, list, out var ts))
{
return true; return true;
}
from.SendLocalizedMessage( from.SendLocalizedMessage(
1008126, 1008126,
@ -195,17 +228,23 @@ namespace Server.Engines.VeteranRewards
} }
if (args?.Length != entries[j].Args.Length) if (args?.Length != entries[j].Args.Length)
{
continue; continue;
}
var match = true; var match = true;
for (var k = 0; match && k < args.Length; ++k) for (var k = 0; match && k < args.Length; ++k)
{
match = args[k].Equals(entries[j].Args[k]); match = args[k].Equals(entries[j].Args[k]);
}
if (match) if (match)
{ {
if (isRelaxedRules && i <= 0 || HasAccess(from, list, out var ts)) if (isRelaxedRules && i <= 0 || HasAccess(from, list, out var ts))
{
return true; return true;
}
from.SendLocalizedMessage( from.SendLocalizedMessage(
1008126, 1008126,
@ -240,22 +279,30 @@ namespace Server.Engines.VeteranRewards
var entries = list.Entries; var entries = list.Entries;
for (var j = 0; j < entries.Length; ++j) for (var j = 0; j < entries.Length; ++j)
{
if (entries[j].ItemType == type) if (entries[j].ItemType == type)
{ {
if (args == null && entries[j].Args.Length == 0) if (args == null && entries[j].Args.Length == 0)
{
return i + 1; return i + 1;
}
if (args?.Length == entries[j].Args.Length) if (args?.Length == entries[j].Args.Length)
{ {
var match = true; var match = true;
for (var k = 0; match && k < args.Length; ++k) for (var k = 0; match && k < args.Length; ++k)
{
match = args[k].Equals(entries[j].Args[k]); match = args[k].Equals(entries[j].Args[k]);
}
if (match) if (match)
{
return i + 1; return i + 1;
}
} }
} }
}
} }
// no entry? // no entry?
@ -532,20 +579,27 @@ namespace Server.Engines.VeteranRewards
}; };
} }
public static void Initialize() public static void Configure()
{ {
Enabled = ServerConfiguration.GetOrUpdateSetting("vetRewards.enable", true); Enabled = ServerConfiguration.GetOrUpdateSetting("vetRewards.enable", true);
SkillCapRewards = ServerConfiguration.GetOrUpdateSetting("vetRewards.skillCapRewards", true); SkillCapRewards = ServerConfiguration.GetOrUpdateSetting("vetRewards.skillCapRewards", true);
RewardInterval = ServerConfiguration.GetOrUpdateSetting("vetRewards.rewardInterval", TimeSpan.FromDays(30.0)); RewardInterval = ServerConfiguration.GetOrUpdateSetting("vetRewards.rewardInterval", TimeSpan.FromDays(30.0));
}
public static void Initialize()
{
if (Enabled) if (Enabled)
{
EventSink.Login += EventSink_Login; EventSink.Login += EventSink_Login;
}
} }
private static void EventSink_Login(Mobile m) private static void EventSink_Login(Mobile m)
{ {
if (!m.Alive) if (!m.Alive)
{
return; return;
}
ComputeRewardInfo(m, out var cur, out var max, out var level); ComputeRewardInfo(m, out var cur, out var max, out var level);
@ -555,9 +609,13 @@ namespace Server.Engines.VeteranRewards
level = Math.Clamp(level, 0, 4); level = Math.Clamp(level, 0, 4);
if (SkillCapRewards) if (SkillCapRewards)
{
m.SkillsCap = 7000 + level * 50; m.SkillsCap = 7000 + level * 50;
}
else else
{
m.SkillsCap = 7000; m.SkillsCap = 7000;
}
} }
if (Core.ML && m is PlayerMobile pm && !pm.HasStatReward && HasHalfLevel(pm)) if (Core.ML && m is PlayerMobile pm && !pm.HasStatReward && HasHalfLevel(pm))
@ -567,7 +625,9 @@ namespace Server.Engines.VeteranRewards
} }
if (cur < max) if (cur < max)
{
m.SendGump(new RewardNoticeGump(m)); m.SendGump(new RewardNoticeGump(m));
}
} }
} }

View file

@ -273,7 +273,7 @@ namespace Server.Gumps
from.SendGump(new WhoGump(from, m_Mobiles, m_Page)); from.SendGump(new WhoGump(from, m_Mobiles, m_Page));
} }
else if (m == from || !m.Hidden || from.AccessLevel >= m.AccessLevel || else if (m == from || !m.Hidden || from.AccessLevel >= m.AccessLevel ||
m is PlayerMobile mobile && mobile.VisibilityList.Contains(@from)) m is PlayerMobile mobile && mobile.VisibilityList.Contains(from))
{ {
from.SendGump(new ClientGump(from, m.NetState)); from.SendGump(new ClientGump(from, m.NetState));
} }

View file

@ -234,7 +234,7 @@ namespace Server.Items
base.CheckHold(m, item, false, checkItems, plusItems, plusWeight); base.CheckHold(m, item, false, checkItems, plusItems, plusWeight);
public override bool CheckContentDisplay(Mobile from) => public override bool CheckContentDisplay(Mobile from) =>
RootParent is BaseCreature creature && creature.Controlled && creature.ControlMaster == @from || RootParent is BaseCreature creature && creature.Controlled && creature.ControlMaster == from ||
base.CheckContentDisplay(from); base.CheckContentDisplay(from);
public override void Serialize(IGenericWriter writer) public override void Serialize(IGenericWriter writer)

View file

@ -180,8 +180,8 @@ namespace Server.Items
if (item?.Deleted != false) if (item?.Deleted != false)
continue; continue;
if (item is BaseArmor armor && Resmelt(@from, armor, armor.Resource) || if (item is BaseArmor armor && Resmelt(from, armor, armor.Resource) ||
item is BaseWeapon weapon && Resmelt(@from, weapon, weapon.Resource) || item is BaseWeapon weapon && Resmelt(from, weapon, weapon.Resource) ||
item is DragonBardingDeed) item is DragonBardingDeed)
salvaged++; salvaged++;
else else

View file

@ -102,10 +102,10 @@ namespace Server.Items
} }
public static bool ValidateDefault(Mobile from, BaseBoard board) => public static bool ValidateDefault(Mobile from, BaseBoard board) =>
!board.Deleted && (from.AccessLevel >= AccessLevel.GameMaster || @from.Alive && !board.Deleted && (from.AccessLevel >= AccessLevel.GameMaster || from.Alive &&
(board.IsChildOf(@from.Backpack) || !(board.RootParent is Mobile) && (board.IsChildOf(from.Backpack) || !(board.RootParent is Mobile) &&
board.Map == @from.Map && @from.InRange(board.GetWorldLocation(), 1) && board.Map == from.Map && from.InRange(board.GetWorldLocation(), 1) &&
BaseHouse.FindHouseAt(board)?.IsOwner(@from) == true)); BaseHouse.FindHouseAt(board)?.IsOwner(from) == true));
public class DefaultEntry : ContextMenuEntry public class DefaultEntry : ContextMenuEntry
{ {

View file

@ -71,7 +71,7 @@ namespace Server.Items
var contains = false; var contains = false;
if (house == null && m_BeforeChangeover || if (house == null && m_BeforeChangeover ||
house?.IsOwner(@from) == true && (contains = house.Addons.Contains(this))) house?.IsOwner(from) == true && (contains = house.Addons.Contains(this)))
{ {
Effects.PlaySound(GetWorldLocation(), Map, 0x3B3); Effects.PlaySound(GetWorldLocation(), Map, 0x3B3);
from.SendLocalizedMessage(500461); // You destroy the item. from.SendLocalizedMessage(500461); // You destroy the item.

View file

@ -69,7 +69,7 @@ namespace Server.Items
{ {
from.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. from.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil.
} }
else if (from.Map == GetTargetMap() || @from.Map != Map.Trammel && @from.Map != Map.Felucca) else if (from.Map == GetTargetMap() || from.Map != Map.Trammel && from.Map != Map.Felucca)
{ {
from.SendLocalizedMessage(1005401); // You cannot bury the stone here. from.SendLocalizedMessage(1005401); // You cannot bury the stone here.
} }

View file

@ -49,7 +49,7 @@ namespace Server.Items
{ {
var root = item.RootParent; var root = item.RootParent;
if (root != null && root != @from || item.Parent == from) if (root != null && root != from || item.Parent == from)
{ {
message = "You decide that item's current location is too awkward to get an accurate result."; message = "You decide that item's current location is too awkward to get an accurate result.";
} }

View file

@ -157,8 +157,8 @@ namespace Server.Items
public virtual void BeginConfirmation(Mobile from) public virtual void BeginConfirmation(Mobile from)
{ {
if (IsInTown(@from.Location, @from.Map) && !IsInTown(Target, TargetMap) || if (IsInTown(from.Location, from.Map) && !IsInTown(Target, TargetMap) ||
@from.Map != Map.Felucca && TargetMap == Map.Felucca && ShowFeluccaWarning) from.Map != Map.Felucca && TargetMap == Map.Felucca && ShowFeluccaWarning)
{ {
if (from.AccessLevel == AccessLevel.Player || !from.Hidden) if (from.AccessLevel == AccessLevel.Player || !from.Hidden)
from.Send(new PlaySound(0x20E, from.Location)); from.Send(new PlaySound(0x20E, from.Location));

View file

@ -188,8 +188,8 @@ namespace Server.Items
var toExplode = eable.Where( var toExplode = eable.Where(
o => o =>
{ {
if (!(o is Mobile mobile) || @from != null && if (!(o is Mobile mobile) || from != null &&
(!SpellHelper.ValidIndirectTarget(@from, mobile) || !@from.CanBeHarmful(mobile, false))) (!SpellHelper.ValidIndirectTarget(from, mobile) || !from.CanBeHarmful(mobile, false)))
return o is BaseExplosionPotion && o != this; return o is BaseExplosionPotion && o != this;
++toDamage; ++toDamage;

View file

@ -104,7 +104,7 @@ namespace Server.Items
m => m =>
{ {
if (from == m || !SpellHelper.ValidIndirectTarget(from, m) || !from.CanBeHarmful(m, false) if (from == m || !SpellHelper.ValidIndirectTarget(from, m) || !from.CanBeHarmful(m, false)
|| Core.AOS && !@from.InLOS(m)) || Core.AOS && !from.InLOS(m))
return false; return false;
if (m.Player) if (m.Player)

View file

@ -111,7 +111,7 @@ namespace Server.Items
return; return;
} }
if ((item.IsChildOf(from.Backpack) || Core.ML && item.Parent == @from) && if ((item.IsChildOf(from.Backpack) || Core.ML && item.Parent == from) &&
m_Powder.IsChildOf(from.Backpack)) m_Powder.IsChildOf(from.Backpack))
{ {
var origMaxHP = wearable.MaxHitPoints; var origMaxHP = wearable.MaxHitPoints;

View file

@ -51,10 +51,14 @@ namespace Server
) )
{ {
if (m?.Deleted != false || !m.Alive || damage <= 0) if (m?.Deleted != false || !m.Alive || damage <= 0)
{
return 0; return 0;
}
if (phys == 0 && fire == 100 && cold == 0 && pois == 0 && nrgy == 0) if (phys == 0 && fire == 100 && cold == 0 && pois == 0 && nrgy == 0)
{
MeerMage.StopEffect(m, true); MeerMage.StopEffect(m, true);
}
if (!Core.AOS) if (!Core.AOS)
{ {
@ -71,6 +75,7 @@ namespace Server
Fix(ref direct); Fix(ref direct);
if (Core.ML && chaos > 0) if (Core.ML && chaos > 0)
{
switch (Utility.Random(5)) switch (Utility.Random(5))
{ {
case 0: case 0:
@ -89,11 +94,14 @@ namespace Server
nrgy += chaos; nrgy += chaos;
break; break;
} }
}
BaseQuiver quiver = null; BaseQuiver quiver = null;
if (archer && from != null) if (archer && from != null)
quiver = from.FindItemOnLayer(Layer.Cloak) as BaseQuiver; {
quiver = @from.FindItemOnLayer(Layer.Cloak) as BaseQuiver;
}
int totalDamage; int totalDamage;
@ -119,31 +127,44 @@ namespace Server
totalDamage += damage * direct / 100; totalDamage += damage * direct / 100;
if (quiver != null) if (quiver != null)
{
totalDamage += totalDamage * quiver.DamageIncrease / 100; totalDamage += totalDamage * quiver.DamageIncrease / 100;
}
} }
if (totalDamage < 1) if (totalDamage < 1)
{
totalDamage = 1; totalDamage = 1;
}
} }
else if (Core.ML && m is PlayerMobile && from is PlayerMobile) else if (Core.ML && m is PlayerMobile && from is PlayerMobile)
{ {
if (quiver != null) if (quiver != null)
{
damage += damage * quiver.DamageIncrease / 100; damage += damage * quiver.DamageIncrease / 100;
}
if (!deathStrike) if (!deathStrike)
{
totalDamage = Math.Min(damage, 35); // Direct Damage cap of 35 totalDamage = Math.Min(damage, 35); // Direct Damage cap of 35
}
else else
{
totalDamage = Math.Min(damage, 70); // Direct Damage cap of 70 totalDamage = Math.Min(damage, 70); // Direct Damage cap of 70
}
} }
else else
{ {
totalDamage = damage; totalDamage = damage;
if (Core.ML && quiver != null) if (Core.ML && quiver != null)
{
totalDamage += totalDamage * quiver.DamageIncrease / 100; totalDamage += totalDamage * quiver.DamageIncrease / 100;
}
} }
if (from?.Player != true && m.Player && m.Mount is SwampDragon pet) if (from?.Player != true && m.Player && m.Mount is SwampDragon pet)
{
if (pet.HasBarding) if (pet.HasBarding)
{ {
var percent = pet.BardingExceptional ? 20 : 10; var percent = pet.BardingExceptional ? 20 : 10;
@ -160,9 +181,12 @@ namespace Server
m.SendLocalizedMessage(1053031); // Your dragon's barding has been destroyed! m.SendLocalizedMessage(1053031); // Your dragon's barding has been destroyed!
} }
} }
}
if (keepAlive && totalDamage > m.Hits) if (keepAlive && totalDamage > m.Hits)
{
totalDamage = m.Hits; totalDamage = m.Hits;
}
if (from?.Deleted == false && from.Alive) if (from?.Deleted == false && from.Alive)
{ {
@ -194,7 +218,9 @@ namespace Server
public static void Fix(ref int val) public static void Fix(ref int val)
{ {
if (val < 0) if (val < 0)
{
val = 0; val = 0;
}
} }
public static int Scale(int input, int percent) => input * percent / 100; public static int Scale(int input, int percent) => input * percent / 100;
@ -447,7 +473,9 @@ namespace Server
public static int GetValue(Mobile m, AosAttribute attribute) public static int GetValue(Mobile m, AosAttribute attribute)
{ {
if (!Core.AOS) if (!Core.AOS)
{
return 0; return 0;
}
var items = m.Items; var items = m.Items;
var value = 0; var value = 0;
@ -461,55 +489,73 @@ namespace Server
var attrs = weapon.Attributes; var attrs = weapon.Attributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
if (attribute == AosAttribute.Luck) if (attribute == AosAttribute.Luck)
{
value += weapon.GetLuckBonus(); value += weapon.GetLuckBonus();
}
} }
else if (obj is BaseArmor armor) else if (obj is BaseArmor armor)
{ {
var attrs = armor.Attributes; var attrs = armor.Attributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
if (attribute == AosAttribute.Luck) if (attribute == AosAttribute.Luck)
{
value += armor.GetLuckBonus(); value += armor.GetLuckBonus();
}
} }
else if (obj is BaseJewel jewel) else if (obj is BaseJewel jewel)
{ {
var attrs = jewel.Attributes; var attrs = jewel.Attributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
else if (obj is BaseClothing clothing) else if (obj is BaseClothing clothing)
{ {
var attrs = clothing.Attributes; var attrs = clothing.Attributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
else if (obj is Spellbook spellbook) else if (obj is Spellbook spellbook)
{ {
var attrs = spellbook.Attributes; var attrs = spellbook.Attributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
else if (obj is BaseQuiver quiver) else if (obj is BaseQuiver quiver)
{ {
var attrs = quiver.Attributes; var attrs = quiver.Attributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
else if (obj is BaseTalisman talisman) else if (obj is BaseTalisman talisman)
{ {
var attrs = talisman.Attributes; var attrs = talisman.Attributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
} }
@ -529,13 +575,19 @@ namespace Server
var modName = Owner.Serial.ToString(); var modName = Owner.Serial.ToString();
if (strBonus != 0) if (strBonus != 0)
{
to.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); to.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero));
}
if (dexBonus != 0) if (dexBonus != 0)
{
to.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); to.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero));
}
if (intBonus != 0) if (intBonus != 0)
{
to.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); to.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero));
}
} }
to.CheckStatTimers(); to.CheckStatTimers();
@ -784,7 +836,9 @@ namespace Server
public static int GetValue(Mobile m, AosWeaponAttribute attribute) public static int GetValue(Mobile m, AosWeaponAttribute attribute)
{ {
if (!Core.AOS) if (!Core.AOS)
{
return 0; return 0;
}
var items = m.Items; var items = m.Items;
var value = 0; var value = 0;
@ -798,14 +852,18 @@ namespace Server
var attrs = weapon.WeaponAttributes; var attrs = weapon.WeaponAttributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
else if (obj is ElvenGlasses glasses) else if (obj is ElvenGlasses glasses)
{ {
var attrs = glasses.WeaponAttributes; var attrs = glasses.WeaponAttributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
} }
@ -878,7 +936,9 @@ namespace Server
public static int GetValue(Mobile m, AosArmorAttribute attribute) public static int GetValue(Mobile m, AosArmorAttribute attribute)
{ {
if (!Core.AOS) if (!Core.AOS)
{
return 0; return 0;
}
var items = m.Items; var items = m.Items;
var value = 0; var value = 0;
@ -892,14 +952,18 @@ namespace Server
var attrs = armor.ArmorAttributes; var attrs = armor.ArmorAttributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
else if (obj is BaseClothing clothing) else if (obj is BaseClothing clothing)
{ {
var attrs = clothing.ClothingAttributes; var attrs = clothing.ClothingAttributes;
if (attrs != null) if (attrs != null)
{
value += attrs[attribute]; value += attrs[attribute];
}
} }
} }
@ -1001,8 +1065,12 @@ namespace Server
public void GetProperties(ObjectPropertyList list) public void GetProperties(ObjectPropertyList list)
{ {
for (var i = 0; i < 5; ++i) for (var i = 0; i < 5; ++i)
{
if (GetValues(i, out var skill, out var bonus)) if (GetValues(i, out var skill, out var bonus))
{
list.Add(1060451 + i, "#{0}\t{1}", GetLabel(skill), bonus); list.Add(1060451 + i, "#{0}\t{1}", GetLabel(skill), bonus);
}
}
} }
public static int GetLabel(SkillName skill) public static int GetLabel(SkillName skill)
@ -1023,7 +1091,9 @@ namespace Server
for (var i = 0; i < 5; ++i) for (var i = 0; i < 5; ++i)
{ {
if (!GetValues(i, out var skill, out var bonus)) if (!GetValues(i, out var skill, out var bonus))
{
continue; continue;
}
m_Mods ??= new List<SkillMod>(); m_Mods ??= new List<SkillMod>();
@ -1037,7 +1107,9 @@ namespace Server
public void Remove() public void Remove()
{ {
if (m_Mods == null) if (m_Mods == null)
{
return; return;
}
for (var i = 0; i < m_Mods.Count; ++i) for (var i = 0; i < m_Mods.Count; ++i)
{ {
@ -1045,7 +1117,9 @@ namespace Server
m_Mods[i].Remove(); m_Mods[i].Remove();
if (Core.ML) if (Core.ML)
{
CheckCancelMorph(m); CheckCancelMorph(m);
}
} }
m_Mods = null; m_Mods = null;
@ -1123,7 +1197,9 @@ namespace Server
public void CheckCancelMorph(Mobile m) public void CheckCancelMorph(Mobile m)
{ {
if (m == null) if (m == null)
{
return; return;
}
var acontext = AnimalForm.GetContext(m); var acontext = AnimalForm.GetContext(m);
var context = TransformationSpellHelper.GetContext(m); var context = TransformationSpellHelper.GetContext(m);
@ -1132,17 +1208,26 @@ namespace Server
{ {
spell.GetCastSkills(out var minSkill, out _); spell.GetCastSkills(out var minSkill, out _);
if (m.Skills[spell.CastSkill].Value < minSkill) if (m.Skills[spell.CastSkill].Value < minSkill)
{
TransformationSpellHelper.RemoveContext(m, context, true); TransformationSpellHelper.RemoveContext(m, context, true);
}
} }
if (acontext != null) if (acontext != null)
{ {
int i; int i;
for (i = 0; i < AnimalForm.Entries.Length; ++i) for (i = 0; i < AnimalForm.Entries.Length; ++i)
{
if (AnimalForm.Entries[i].Type == acontext.Type) if (AnimalForm.Entries[i].Type == acontext.Type)
{
break; break;
}
}
if (m.Skills.Ninjitsu.Value < AnimalForm.Entries[i].ReqSkill) if (m.Skills.Ninjitsu.Value < AnimalForm.Entries[i].ReqSkill)
{
AnimalForm.RemoveContext(m, true); AnimalForm.RemoveContext(m, true);
}
} }
if (!m.CanBeginAction<PolymorphSpell>() && m.Skills.Magery.Value < 66.1) if (!m.CanBeginAction<PolymorphSpell>() && m.Skills.Magery.Value < 66.1)
@ -1158,7 +1243,10 @@ namespace Server
if (!m.CanBeginAction<IncognitoSpell>() && m.Skills.Magery.Value < 38.1) if (!m.CanBeginAction<IncognitoSpell>() && m.Skills.Magery.Value < 38.1)
{ {
if (m is PlayerMobile mobile) if (m is PlayerMobile mobile)
{
mobile.SetHairMods(-1, -1); mobile.SetHairMods(-1, -1);
}
m.BodyMod = 0; m.BodyMod = 0;
m.HueMod = -1; m.HueMod = -1;
m.NameMod = null; m.NameMod = null;
@ -1292,7 +1380,9 @@ namespace Server
m_Values = new int[reader.ReadEncodedInt()]; m_Values = new int[reader.ReadEncodedInt()];
for (var i = 0; i < m_Values.Length; ++i) for (var i = 0; i < m_Values.Length; ++i)
{
m_Values[i] = reader.ReadEncodedInt(); m_Values[i] = reader.ReadEncodedInt();
}
break; break;
} }
@ -1302,7 +1392,9 @@ namespace Server
m_Values = new int[reader.ReadInt()]; m_Values = new int[reader.ReadInt()];
for (var i = 0; i < m_Values.Length; ++i) for (var i = 0; i < m_Values.Length; ++i)
{
m_Values[i] = reader.ReadInt(); m_Values[i] = reader.ReadInt();
}
break; break;
} }
@ -1320,23 +1412,31 @@ namespace Server
writer.WriteEncodedInt(m_Values.Length); writer.WriteEncodedInt(m_Values.Length);
for (var i = 0; i < m_Values.Length; ++i) for (var i = 0; i < m_Values.Length; ++i)
{
writer.WriteEncodedInt(m_Values[i]); writer.WriteEncodedInt(m_Values[i]);
}
} }
public int GetValue(int bitmask) public int GetValue(int bitmask)
{ {
if (!Core.AOS) if (!Core.AOS)
{
return 0; return 0;
}
var mask = (uint)bitmask; var mask = (uint)bitmask;
if ((m_Names & mask) == 0) if ((m_Names & mask) == 0)
{
return 0; return 0;
}
var index = GetIndex(mask); var index = GetIndex(mask);
if (index >= 0 && index < m_Values.Length) if (index >= 0 && index < m_Values.Length)
{
return m_Values[index]; return m_Values[index];
}
return 0; return 0;
} }
@ -1346,14 +1446,20 @@ namespace Server
if (bitmask == (int)AosWeaponAttribute.DurabilityBonus && this is AosWeaponAttributes) if (bitmask == (int)AosWeaponAttribute.DurabilityBonus && this is AosWeaponAttributes)
{ {
if (Owner is BaseWeapon weapon) if (Owner is BaseWeapon weapon)
{
weapon.UnscaleDurability(); weapon.UnscaleDurability();
}
} }
else if (bitmask == (int)AosArmorAttribute.DurabilityBonus && this is AosArmorAttributes) else if (bitmask == (int)AosArmorAttribute.DurabilityBonus && this is AosArmorAttributes)
{ {
if (Owner is BaseArmor armor) if (Owner is BaseArmor armor)
{
armor.UnscaleDurability(); armor.UnscaleDurability();
}
else if (Owner is BaseClothing clothing) else if (Owner is BaseClothing clothing)
{
clothing.UnscaleDurability(); clothing.UnscaleDurability();
}
} }
var mask = (uint)bitmask; var mask = (uint)bitmask;
@ -1365,7 +1471,9 @@ namespace Server
var index = GetIndex(mask); var index = GetIndex(mask);
if (index >= 0 && index < m_Values.Length) if (index >= 0 && index < m_Values.Length)
{
m_Values[index] = value; m_Values[index] = value;
}
} }
else else
{ {
@ -1377,12 +1485,16 @@ namespace Server
m_Values = new int[old.Length + 1]; m_Values = new int[old.Length + 1];
for (var i = 0; i < index; ++i) for (var i = 0; i < index; ++i)
{
m_Values[i] = old[i]; m_Values[i] = old[i];
}
m_Values[index] = value; m_Values[index] = value;
for (var i = index; i < old.Length; ++i) for (var i = index; i < old.Length; ++i)
{
m_Values[i + 1] = old[i]; m_Values[i + 1] = old[i];
}
m_Names |= mask; m_Names |= mask;
} }
@ -1406,10 +1518,14 @@ namespace Server
m_Values = new int[old.Length - 1]; m_Values = new int[old.Length - 1];
for (var i = 0; i < index; ++i) for (var i = 0; i < index; ++i)
{
m_Values[i] = old[i]; m_Values[i] = old[i];
}
for (var i = index + 1; i < old.Length; ++i) for (var i = index + 1; i < old.Length; ++i)
{
m_Values[i - 1] = old[i]; m_Values[i - 1] = old[i];
}
} }
} }
} }
@ -1417,14 +1533,20 @@ namespace Server
if (bitmask == (int)AosWeaponAttribute.DurabilityBonus && this is AosWeaponAttributes) if (bitmask == (int)AosWeaponAttribute.DurabilityBonus && this is AosWeaponAttributes)
{ {
if (Owner is BaseWeapon weapon) if (Owner is BaseWeapon weapon)
{
weapon.ScaleDurability(); weapon.ScaleDurability();
}
} }
else if (bitmask == (int)AosArmorAttribute.DurabilityBonus && this is AosArmorAttributes) else if (bitmask == (int)AosArmorAttribute.DurabilityBonus && this is AosArmorAttributes)
{ {
if (Owner is BaseArmor armor) if (Owner is BaseArmor armor)
{
armor.ScaleDurability(); armor.ScaleDurability();
}
else if (Owner is BaseClothing clothing) else if (Owner is BaseClothing clothing)
{
clothing.ScaleDurability(); clothing.ScaleDurability();
}
} }
if (Owner.Parent is Mobile m) if (Owner.Parent is Mobile m)
@ -1455,10 +1577,14 @@ namespace Server
while (currentBit != mask) while (currentBit != mask)
{ {
if ((ourNames & currentBit) != 0) if ((ourNames & currentBit) != 0)
{
++index; ++index;
}
if (currentBit == 0x80000000) if (currentBit == 0x80000000)
{
return -1; return -1;
}
currentBit <<= 1; currentBit <<= 1;
} }

View file

@ -108,36 +108,49 @@ namespace Server
public TextDefinition Args { get; } public TextDefinition Args { get; }
public static void Initialize() public static void Configure()
{ {
Enabled = ServerConfiguration.GetOrUpdateSetting("buffIcons.enable", Core.ML); Enabled = ServerConfiguration.GetOrUpdateSetting("buffIcons.enable", Core.ML);
}
public static void Initialize()
{
if (Enabled) if (Enabled)
{
EventSink.ClientVersionReceived += ResendBuffsOnClientVersionReceived; EventSink.ClientVersionReceived += ResendBuffsOnClientVersionReceived;
}
} }
public static void ResendBuffsOnClientVersionReceived(NetState ns, ClientVersion cv) public static void ResendBuffsOnClientVersionReceived(NetState ns, ClientVersion cv)
{ {
if (ns.Mobile is PlayerMobile pm) if (ns.Mobile is PlayerMobile pm)
{
Timer.DelayCall(pm.ResendBuffs); Timer.DelayCall(pm.ResendBuffs);
}
} }
public static void AddBuff(Mobile m, BuffInfo b) public static void AddBuff(Mobile m, BuffInfo b)
{ {
if (m is PlayerMobile pm) if (m is PlayerMobile pm)
{
pm.AddBuff(b); pm.AddBuff(b);
}
} }
public static void RemoveBuff(Mobile m, BuffInfo b) public static void RemoveBuff(Mobile m, BuffInfo b)
{ {
if (m is PlayerMobile pm) if (m is PlayerMobile pm)
{
pm.RemoveBuff(b); pm.RemoveBuff(b);
}
} }
public static void RemoveBuff(Mobile m, BuffIcon b) public static void RemoveBuff(Mobile m, BuffIcon b)
{ {
if (m is PlayerMobile pm) if (m is PlayerMobile pm)
{
pm.RemoveBuff(b); pm.RemoveBuff(b);
}
} }
} }
@ -235,7 +248,9 @@ namespace Server
Stream.Fill(4); Stream.Fill(4);
if (length < TimeSpan.Zero) if (length < TimeSpan.Zero)
{
length = TimeSpan.Zero; length = TimeSpan.Zero;
}
Stream.Write((short)length.TotalSeconds); // Time in seconds Stream.Write((short)length.TotalSeconds); // Time in seconds

View file

@ -7,7 +7,7 @@ using Server.Network;
namespace Server.Misc namespace Server.Misc
{ {
public class ClientVerification public static class ClientVerification
{ {
private static bool m_DetectClientRequirement; private static bool m_DetectClientRequirement;
private static OldClientResponse m_OldClientResponse; private static OldClientResponse m_OldClientResponse;
@ -25,7 +25,7 @@ namespace Server.Misc
public static TimeSpan KickDelay { get; set; } public static TimeSpan KickDelay { get; set; }
public static void Initialize() public static void Configure()
{ {
m_DetectClientRequirement = ServerConfiguration.GetOrUpdateSetting("clientVerification.enable", true); m_DetectClientRequirement = ServerConfiguration.GetOrUpdateSetting("clientVerification.enable", true);
m_OldClientResponse = m_OldClientResponse =
@ -36,7 +36,10 @@ namespace Server.Misc
TimeSpan.FromHours(25) TimeSpan.FromHours(25)
); );
KickDelay = ServerConfiguration.GetOrUpdateSetting("clientVerification.kickDelay", TimeSpan.FromSeconds(20.0)); KickDelay = ServerConfiguration.GetOrUpdateSetting("clientVerification.kickDelay", TimeSpan.FromSeconds(20.0));
}
public static void Initialize()
{
EventSink.ClientVersionReceived += EventSink_ClientVersionReceived; EventSink.ClientVersionReceived += EventSink_ClientVersionReceived;
if (m_DetectClientRequirement) if (m_DetectClientRequirement)
@ -49,12 +52,14 @@ namespace Server.Misc
if (info.FileMajorPart != 0 || info.FileMinorPart != 0 || info.FileBuildPart != 0 || if (info.FileMajorPart != 0 || info.FileMinorPart != 0 || info.FileBuildPart != 0 ||
info.FilePrivatePart != 0) info.FilePrivatePart != 0)
{
Required = new ClientVersion( Required = new ClientVersion(
info.FileMajorPart, info.FileMajorPart,
info.FileMinorPart, info.FileMinorPart,
info.FileBuildPart, info.FileBuildPart,
info.FilePrivatePart info.FilePrivatePart
); );
}
} }
} }
@ -75,7 +80,9 @@ namespace Server.Misc
string kickMessage = null; string kickMessage = null;
if (state.Mobile?.AccessLevel != AccessLevel.Player) if (state.Mobile?.AccessLevel != AccessLevel.Player)
{
return; return;
}
if (Required != null && version < Required && (m_OldClientResponse == OldClientResponse.Kick || if (Required != null && version < Required && (m_OldClientResponse == OldClientResponse.Kick ||
m_OldClientResponse == OldClientResponse.LenientKick && m_OldClientResponse == OldClientResponse.LenientKick &&
@ -88,11 +95,17 @@ namespace Server.Misc
else if (!AllowGod || !AllowRegular || !AllowUOTD) else if (!AllowGod || !AllowRegular || !AllowUOTD)
{ {
if (!AllowGod && version.Type == ClientType.God) if (!AllowGod && version.Type == ClientType.God)
{
kickMessage = "This server does not allow god clients to connect."; kickMessage = "This server does not allow god clients to connect.";
}
else if (!AllowRegular && version.Type == ClientType.Regular) else if (!AllowRegular && version.Type == ClientType.Regular)
{
kickMessage = "This server does not allow regular clients to connect."; kickMessage = "This server does not allow regular clients to connect.";
}
else if (!AllowUOTD && state.IsUOTDClient) else if (!AllowUOTD && state.IsUOTDClient)
{
kickMessage = "This server does not allow UO:TD clients to connect."; kickMessage = "This server does not allow UO:TD clients to connect.";
}
if (!AllowGod && !AllowRegular && !AllowUOTD) if (!AllowGod && !AllowRegular && !AllowUOTD)
{ {
@ -105,11 +118,17 @@ namespace Server.Misc
else if (kickMessage != null) else if (kickMessage != null)
{ {
if (AllowRegular && AllowUOTD) if (AllowRegular && AllowUOTD)
{
kickMessage += " You can use regular or UO:TD clients."; kickMessage += " You can use regular or UO:TD clients.";
}
else if (AllowRegular) else if (AllowRegular)
{
kickMessage += " You can use regular clients."; kickMessage += " You can use regular clients.";
}
else if (AllowUOTD) else if (AllowUOTD)
{
kickMessage += " You can use UO:TD clients."; kickMessage += " You can use UO:TD clients.";
}
} }
} }
@ -162,11 +181,13 @@ namespace Server.Misc
from.SendMessage("You will be reminded of this again."); from.SendMessage("You will be reminded of this again.");
if (m_OldClientResponse == OldClientResponse.LenientKick) if (m_OldClientResponse == OldClientResponse.LenientKick)
{
from.SendMessage( from.SendMessage(
"Old clients will be kicked after {0} days of character age and {1} hours of play time", "Old clients will be kicked after {0} days of character age and {1} hours of play time",
m_AgeLeniency, m_AgeLeniency,
m_GameTimeLeniency m_GameTimeLeniency
); );
}
Timer.DelayCall(TimeSpan.FromMinutes(Utility.Random(5, 15)), SendAnnoyGump, from); Timer.DelayCall(TimeSpan.FromMinutes(Utility.Random(5, 15)), SendAnnoyGump, from);
} }

View file

@ -8,11 +8,18 @@ namespace Server.Misc
{ {
public static class CrashGuard public static class CrashGuard
{ {
// TODO: Make this configurable private static bool Enabled;
private const bool Enabled = true; private static bool SaveBackup;
private const bool SaveBackup = true; private static bool RestartServer; // Disable this if using a daemon/service
private const bool RestartServer = true; private static bool GenerateReport;
private const bool GenerateReport = true;
public static void Configure()
{
Enabled = ServerConfiguration.GetOrUpdateSetting("crashGuard.enabled", true);
SaveBackup = ServerConfiguration.GetOrUpdateSetting("crashGuard.saveBackup", true);
RestartServer = ServerConfiguration.GetOrUpdateSetting("crashGuard.restartServer", true);
GenerateReport = ServerConfiguration.GetOrUpdateSetting("crashGuard.generateReport", true);
}
public static void Initialize() public static void Initialize()
{ {

View file

@ -18,7 +18,10 @@ namespace Server.Misc
/// <param name="pageType"></param> /// <param name="pageType"></param>
public static void SendQueueEmail(PageEntry entry, string pageType) public static void SendQueueEmail(PageEntry entry, string pageType)
{ {
if (!EmailConfiguration.EmailEnabled) return; if (!EmailConfiguration.EmailEnabled)
{
return;
}
var sender = entry.Sender; var sender = entry.Sender;
var time = DateTime.UtcNow; var time = DateTime.UtcNow;
@ -75,7 +78,10 @@ namespace Server.Misc
/// <param name="filePath"></param> /// <param name="filePath"></param>
public static void SendCrashEmail(string filePath) public static void SendCrashEmail(string filePath)
{ {
if (EmailConfiguration.EmailEnabled) return; if (EmailConfiguration.EmailEnabled)
{
return;
}
var message = new MimeMessage(); var message = new MimeMessage();
message.From.Add(EmailConfiguration.FromAddress); message.From.Add(EmailConfiguration.FromAddress);
@ -96,7 +102,10 @@ namespace Server.Misc
/// <param name="message"></param> /// <param name="message"></param>
private static async void SendAsync(MimeMessage message) private static async void SendAsync(MimeMessage message)
{ {
if (!EmailConfiguration.EmailEnabled) return; if (!EmailConfiguration.EmailEnabled)
{
return;
}
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var messageID = $"<{now:yyyyMMdd}.{now:HHmmssff}@{EmailConfiguration.EmailServer}>"; var messageID = $"<{now:yyyyMMdd}.{now:HHmmssff}@{EmailConfiguration.EmailServer}>";
@ -106,6 +115,7 @@ namespace Server.Misc
var delay = EmailConfiguration.EmailSendRetryDelay; var delay = EmailConfiguration.EmailSendRetryDelay;
for (var i = 0; i < EmailConfiguration.EmailSendRetryCount; i++) for (var i = 0; i < EmailConfiguration.EmailSendRetryCount; i++)
{
try try
{ {
using var client = new SmtpClient(); using var client = new SmtpClient();
@ -130,6 +140,7 @@ namespace Server.Misc
await Task.Delay(delay * 1000); await Task.Delay(delay * 1000);
} }
}
} }
} }
} }

View file

@ -7,24 +7,16 @@ namespace Server
{ {
public class AssemblyEmitter public class AssemblyEmitter
{ {
private readonly AssemblyBuilder m_AssemblyBuilder;
private readonly ModuleBuilder m_ModuleBuilder; private readonly ModuleBuilder m_ModuleBuilder;
private AppDomain m_AppDomain;
private string m_AssemblyName;
public AssemblyEmitter(string assemblyName) public AssemblyEmitter(string assemblyName)
{ {
m_AssemblyName = assemblyName; var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
m_AppDomain = AppDomain.CurrentDomain;
m_AssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName(assemblyName), new AssemblyName(assemblyName),
AssemblyBuilderAccess.Run AssemblyBuilderAccess.Run
); );
m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule(assemblyName); m_ModuleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName);
} }
public TypeBuilder DefineType(string typeName, TypeAttributes attrs, Type parentType) => public TypeBuilder DefineType(string typeName, TypeAttributes attrs, Type parentType) =>

View file

@ -193,7 +193,7 @@ namespace Server.Misc
(fromGuild == targetGuild || fromGuild.IsAlly(targetGuild) || fromGuild.IsEnemy(targetGuild))) (fromGuild == targetGuild || fromGuild.IsAlly(targetGuild) || fromGuild.IsEnemy(targetGuild)))
return true; // Guild allies or enemies can be harmful return true; // Guild allies or enemies can be harmful
if (bcTarg?.Controlled == true || bcTarg?.Summoned == true && bcTarg?.SummonMaster != @from) if (bcTarg?.Controlled == true || bcTarg?.Summoned == true && bcTarg?.SummonMaster != from)
return false; // Cannot harm other controlled mobiles return false; // Cannot harm other controlled mobiles
if (target.Player) if (target.Player)

View file

@ -82,7 +82,7 @@ namespace Server.Misc
var points = (int)(from.Skills.Focus.Value * 0.1); var points = (int)(from.Skills.Focus.Value * 0.1);
if (@from is BaseCreature creature && creature.IsParagon || from is Leviathan) if (from is BaseCreature creature && creature.IsParagon || from is Leviathan)
points += 40; points += 40;
var cappedPoints = AosAttributes.GetValue(from, AosAttribute.RegenStam); var cappedPoints = AosAttributes.GetValue(from, AosAttribute.RegenStam);
@ -130,7 +130,7 @@ namespace Server.Misc
var totalPoints = focusPoints + medPoints + (from.Meditating ? medPoints > 13.0 ? 13.0 : medPoints : 0.0); var totalPoints = focusPoints + medPoints + (from.Meditating ? medPoints > 13.0 ? 13.0 : medPoints : 0.0);
if (@from is BaseCreature creature && creature.IsParagon || from is Leviathan) if (from is BaseCreature creature && creature.IsParagon || from is Leviathan)
totalPoints += 40; totalPoints += 40;
var cappedPoints = AosAttributes.GetValue(from, AosAttribute.RegenMana); var cappedPoints = AosAttributes.GetValue(from, AosAttribute.RegenMana);

View file

@ -43,16 +43,21 @@ namespace Server.Misc
public static bool AutoDetect { get; private set; } public static bool AutoDetect { get; private set; }
public static void Initialize() public static void Configure()
{ {
Address = ServerConfiguration.GetOrUpdateSetting("serverListing.address", null); Address = ServerConfiguration.GetOrUpdateSetting("serverListing.address", null);
AutoDetect = ServerConfiguration.GetOrUpdateSetting("serverListing.autoDetect", true); AutoDetect = ServerConfiguration.GetOrUpdateSetting("serverListing.autoDetect", true);
ServerName = ServerConfiguration.GetOrUpdateSetting("serverListing.serverName", "ModernUO"); ServerName = ServerConfiguration.GetOrUpdateSetting("serverListing.serverName", "ModernUO");
}
public static void Initialize()
{
if (Address == null) if (Address == null)
{ {
if (AutoDetect) if (AutoDetect)
{
AutoDetection(); AutoDetection();
}
} }
else else
{ {
@ -77,7 +82,9 @@ namespace Server.Misc
{ {
ipep = (IPEndPoint)ns.Connection.RemoteEndPoint; ipep = (IPEndPoint)ns.Connection.RemoteEndPoint;
if (!IsPrivateNetwork(ipep.Address) && m_PublicAddress != null) if (!IsPrivateNetwork(ipep.Address) && m_PublicAddress != null)
{
localAddress = m_PublicAddress; localAddress = m_PublicAddress;
}
} }
e.AddServer(ServerName, new IPEndPoint(localAddress, localPort)); e.AddServer(ServerName, new IPEndPoint(localAddress, localPort));
@ -97,23 +104,31 @@ namespace Server.Misc
m_PublicAddress = FindPublicAddress(); m_PublicAddress = FindPublicAddress();
if (m_PublicAddress != null) if (m_PublicAddress != null)
{
Console.WriteLine("done ({0})", m_PublicAddress); Console.WriteLine("done ({0})", m_PublicAddress);
}
else else
{
Console.WriteLine("failed"); Console.WriteLine("failed");
}
} }
} }
private static void Resolve(string addr, out IPAddress outValue) private static void Resolve(string addr, out IPAddress outValue)
{ {
if (IPAddress.TryParse(addr, out outValue)) if (IPAddress.TryParse(addr, out outValue))
{
return; return;
}
try try
{ {
var iphe = Dns.GetHostEntry(addr); var iphe = Dns.GetHostEntry(addr);
if (iphe.AddressList.Length > 0) if (iphe.AddressList.Length > 0)
{
outValue = iphe.AddressList[^1]; outValue = iphe.AddressList[^1];
}
} }
catch catch
{ {

View file

@ -156,7 +156,7 @@ namespace Server.Misc
if (from is BaseCreature creature && creature.Controlled) if (from is BaseCreature creature && creature.Controlled)
gc *= 2; gc *= 2;
if (from.Alive && (gc >= Utility.RandomDouble() && AllowGain(@from, skill, amObj) || skill.Base < 10.0)) if (from.Alive && (gc >= Utility.RandomDouble() && AllowGain(from, skill, amObj) || skill.Base < 10.0))
Gain(from, skill); Gain(from, skill);
return success; return success;

View file

@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using Server.Engines.Spawners; using Server.Engines.Spawners;
// Version 0.8
namespace Server namespace Server
{ {
public class UOAMVendorGenerator public class UOAMVendorGenerator

View file

@ -232,8 +232,8 @@ namespace Server.Mobiles
if (from.InRange(this, 1)) if (from.InRange(this, 1))
{ {
var canAccess = from.AccessLevel >= AccessLevel.GameMaster var canAccess = from.AccessLevel >= AccessLevel.GameMaster
|| Controlled && ControlMaster == @from || Controlled && ControlMaster == from
|| Summoned && SummonMaster == @from; || Summoned && SummonMaster == from;
if (canAccess) if (canAccess)
{ {

File diff suppressed because it is too large Load diff

View file

@ -1087,7 +1087,7 @@ namespace Server.Mobiles
public virtual bool CheckVendorAccess(Mobile from) => public virtual bool CheckVendorAccess(Mobile from) =>
Region.GetRegion<GuardedRegion>()?.CheckVendorAccess(this, from) != false || Region.GetRegion<GuardedRegion>()?.CheckVendorAccess(this, from) != false ||
Region != @from.Region && @from.Region.GetRegion<GuardedRegion>()?.CheckVendorAccess(this, @from) != false; Region != from.Region && from.Region.GetRegion<GuardedRegion>()?.CheckVendorAccess(this, from) != false;
public override void Serialize(IGenericWriter writer) public override void Serialize(IGenericWriter writer)
{ {

View file

@ -127,7 +127,7 @@ namespace Server.Multis
{ {
if (okay && Owner != null && Owner.Owner == null && Owner.DecayLevel != DecayLevel.DemolitionPending) if (okay && Owner != null && Owner.Owner == null && Owner.DecayLevel != DecayLevel.DemolitionPending)
{ {
var canClaim = Owner.CoOwners?.Count > 0 && Owner.IsCoOwner(@from) || Owner.IsFriend(from); var canClaim = Owner.CoOwners?.Count > 0 && Owner.IsCoOwner(from) || Owner.IsFriend(from);
if (canClaim && !BaseHouse.HasAccountHouse(from)) if (canClaim && !BaseHouse.HasAccountHouse(from))
{ {

View file

@ -164,8 +164,8 @@ namespace Server.SkillHandlers
else if (target is Mobile targ) else if (target is Mobile targ)
{ {
if (targ == from || targ is BaseCreature bc && if (targ == from || targ is BaseCreature bc &&
(bc.BardImmune || !@from.CanBeHarmful(bc, false)) && (bc.BardImmune || !from.CanBeHarmful(bc, false)) &&
bc.ControlMaster != @from) bc.ControlMaster != from)
{ {
from.SendLocalizedMessage(1049535); // A song of discord would have no effect on that. from.SendLocalizedMessage(1049535); // A song of discord would have no effect on that.
} }

View file

@ -94,8 +94,8 @@ namespace Server.SkillHandlers
} }
else else
{ {
if (Core.ML && isOwner || @from.CheckTargetSkill(SkillName.RemoveTrap, trap, 80.0, 100.0) && if (Core.ML && isOwner || from.CheckTargetSkill(SkillName.RemoveTrap, trap, 80.0, 100.0) &&
@from.CheckTargetSkill(SkillName.Tinkering, trap, 80.0, 100.0)) from.CheckTargetSkill(SkillName.Tinkering, trap, 80.0, 100.0))
{ {
from.PrivateOverheadMessage( from.PrivateOverheadMessage(
MessageType.Regular, MessageType.Regular,