Merge branch 'main' into addon-tutorial
This commit is contained in:
commit
158a43a168
42 changed files with 715 additions and 308 deletions
|
|
@ -375,7 +375,6 @@ public class GenericEntityPersistence<T> : GenericPersistence, IGenericEntityPer
|
|||
// Skip this entry
|
||||
if (t == null)
|
||||
{
|
||||
dataReader.Seek(entry.Length, SeekOrigin.Current);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +382,9 @@ public class GenericEntityPersistence<T> : GenericPersistence, IGenericEntityPer
|
|||
|
||||
try
|
||||
{
|
||||
var pos = dataReader.Position;
|
||||
dataReader.Seek(entry.Position, SeekOrigin.Begin);
|
||||
var pos = entry.Position;
|
||||
|
||||
t.Deserialize(dataReader);
|
||||
var lengthDeserialized = dataReader.Position - pos;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ using System.Collections.Generic;
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Server.Buffers;
|
||||
using Server.Text;
|
||||
|
||||
namespace Server;
|
||||
|
||||
|
|
@ -286,4 +287,18 @@ public static class StringHelpers
|
|||
str.CopyTo(chars);
|
||||
return chars;
|
||||
}
|
||||
|
||||
public static void AppendSpaceWithArticle(this ref ValueStringBuilder builder, string text, bool articleAn)
|
||||
{
|
||||
if (builder.Length != 0)
|
||||
{
|
||||
builder.Append(' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(articleAn ? "an " : "a ");
|
||||
}
|
||||
|
||||
builder.Append(text);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Net;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Xml;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Accounting.Security;
|
||||
using Server.Misc;
|
||||
|
|
@ -768,31 +769,24 @@ public partial class Account : IAccount, IComparable<Account>
|
|||
acc.TotalGameTime += Core.Now - pm.SessionStart;
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (m is not PlayerMobile pm)
|
||||
if (pm.Account is not Account acc || !pm.Young || !acc.Young)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.Account is not Account acc)
|
||||
var ts = YoungDuration - acc.TotalGameTime;
|
||||
var hours = Math.Max((int)ts.TotalHours, 0);
|
||||
|
||||
if (hours == 1)
|
||||
{
|
||||
return;
|
||||
pm.SendAsciiMessage($"You will enjoy the benefits and relatively safe status of a young player for {hours} more hour.");
|
||||
}
|
||||
|
||||
if (pm.Young && acc.Young)
|
||||
else
|
||||
{
|
||||
var ts = YoungDuration - acc.TotalGameTime;
|
||||
var hours = Math.Max((int)ts.TotalHours, 0);
|
||||
|
||||
if (hours == 1)
|
||||
{
|
||||
m.SendAsciiMessage($"You will enjoy the benefits and relatively safe status of a young player for {hours} more hour.");
|
||||
}
|
||||
else
|
||||
{
|
||||
m.SendAsciiMessage($"You will enjoy the benefits and relatively safe status of a young player for {hours} more hours.");
|
||||
}
|
||||
pm.SendAsciiMessage($"You will enjoy the benefits and relatively safe status of a young player for {hours} more hours.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Assistants;
|
||||
|
|
@ -45,22 +47,23 @@ public static class AssistantHandler
|
|||
m.NetState.LogInfo("Failed to negotiate assistant features.");
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (m?.NetState?.Running != true || !Enabled)
|
||||
if (pm?.NetState?.Running != true || !Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m.NetState.SendAssistVersionReq();
|
||||
m.NetState.SendAssistHandshake();
|
||||
pm.NetState.SendAssistVersionReq();
|
||||
pm.NetState.SendAssistHandshake();
|
||||
|
||||
if (_handshakes.TryGetValue(m, out var t))
|
||||
if (_handshakes.TryGetValue(pm, out var t))
|
||||
{
|
||||
t?.Stop();
|
||||
}
|
||||
|
||||
_handshakes[m] = Timer.DelayCall(TimeSpan.FromSeconds(30), OnTimeout, m);
|
||||
_handshakes[pm] = Timer.DelayCall(TimeSpan.FromSeconds(30), OnTimeout, pm);
|
||||
}
|
||||
|
||||
public static void AssistVersion(NetState state, SpanReader reader)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
|
@ -15,10 +16,8 @@ namespace Server.Commands
|
|||
CommandSystem.Register("VisClear", AccessLevel.Counselor, VisClear_OnCommand);
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
{
|
||||
(m as PlayerMobile)?.VisibilityList.Clear();
|
||||
}
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm) => pm.VisibilityList.Clear();
|
||||
|
||||
[Usage("Vis")]
|
||||
[Description("Adds or removes a targeted player from your visibility list. Anyone on your visibility list will be able to see you at all times, even when you're hidden.")]
|
||||
|
|
|
|||
|
|
@ -1291,13 +1291,9 @@ namespace Server.Engines.ConPVP
|
|||
return false;
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (m is not PlayerMobile pm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dc = pm.DuelContext;
|
||||
|
||||
if (dc == null)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Mobiles;
|
||||
using Server.Regions;
|
||||
|
||||
|
|
@ -14,12 +15,13 @@ namespace Server.Engines.Doom
|
|||
Register();
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
var rect = LeverPuzzleController.lr_Rect;
|
||||
if (m.X >= rect.X && m.X <= rect.X + 10 && m.Y >= rect.Y && m.Y <= rect.Y + 10 && m.Map == Map.Internal)
|
||||
if (pm.X >= rect.X && pm.X <= rect.X + 10 && pm.Y >= rect.Y && pm.Y <= rect.Y + 10 && pm.Map == Map.Internal)
|
||||
{
|
||||
Timer kick = new LeverPuzzleController.LampRoomKickTimer(m);
|
||||
Timer kick = new LeverPuzzleController.LampRoomKickTimer(pm);
|
||||
kick.Start();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Accounting;
|
||||
using Server.Commands.Generic;
|
||||
using Server.Engines.ConPVP;
|
||||
|
|
@ -1259,7 +1261,9 @@ public abstract class Faction : IComparable<Faction>
|
|||
}
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m) => CheckLeaveTimer(m);
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void OnLogin(PlayerMobile pm) => CheckLeaveTimer(pm);
|
||||
|
||||
public static void WriteReference(IGenericWriter writer, Faction fact)
|
||||
{
|
||||
|
|
|
|||
27
Projects/UOContent/Engines/Help/HelpEvents.cs
Normal file
27
Projects/UOContent/Engines/Help/HelpEvents.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server.Engines.Help;
|
||||
|
||||
public static class HelpEvents
|
||||
{
|
||||
public static event Action<PageEntry> PageEnqueued;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void InvokePageEnqueued(PageEntry e) => PageEnqueued?.Invoke(e);
|
||||
|
||||
public static event Action<PageEntry> PageRemoved;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void InvokePageRemoved(PageEntry e) => PageRemoved?.Invoke(e);
|
||||
|
||||
public static event Action<Mobile, Mobile, PageEntry> PageHandlerChanged;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void InvokePageHandlerChanged(Mobile old, Mobile value, PageEntry e) => PageHandlerChanged?.Invoke(old, value, e);
|
||||
|
||||
public static event Action<PageEntry> PageWaiting;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void InvokePageWaiting(PageEntry e) => PageWaiting?.Invoke(e);
|
||||
|
||||
public static event Action<Mobile> StuckMenu;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void InvokeStuckMenu(Mobile m) => StuckMenu?.Invoke(m);
|
||||
}
|
||||
|
|
@ -103,6 +103,8 @@ namespace Server.Engines.Help
|
|||
{
|
||||
m_Entry.Handler = null;
|
||||
}
|
||||
|
||||
HelpEvents.InvokePageWaiting(m_Entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -171,6 +173,13 @@ namespace Server.Engines.Help
|
|||
{
|
||||
m_KeyedByHandler[value] = entry;
|
||||
}
|
||||
|
||||
if (old == null || value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HelpEvents.InvokePageHandlerChanged(old, value, entry);
|
||||
}
|
||||
|
||||
[Usage("Pages"), Description("Opens the page queue menu.")]
|
||||
|
|
@ -212,6 +221,8 @@ namespace Server.Engines.Help
|
|||
{
|
||||
m_KeyedByHandler.Remove(e.Handler);
|
||||
}
|
||||
|
||||
HelpEvents.InvokePageRemoved(e);
|
||||
}
|
||||
|
||||
public static PageEntry GetEntry(Mobile sender)
|
||||
|
|
@ -258,6 +269,8 @@ namespace Server.Engines.Help
|
|||
{
|
||||
Email.SendQueueEmail(entry, GetPageTypeName(entry.Type));
|
||||
}
|
||||
|
||||
HelpEvents.InvokePageEnqueued(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Server.Engines.Help;
|
||||
using Server.Factions;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
|
|
@ -194,16 +195,16 @@ namespace Server.Menus.Questions
|
|||
m_Mobile.SendLocalizedMessage(1010588); // You choose not to go to any city.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = info.ButtonID - 1;
|
||||
var entries = IsInSecondAgeArea(m_Mobile) ? m_T2AEntries : m_Entries;
|
||||
|
||||
if (index >= 0 && index < entries.Length)
|
||||
{
|
||||
Teleport(entries[index]);
|
||||
}
|
||||
var index = info.ButtonID - 1;
|
||||
var entries = IsInSecondAgeArea(m_Mobile) ? m_T2AEntries : m_Entries;
|
||||
|
||||
if (index >= 0 && index < entries.Length)
|
||||
{
|
||||
Teleport(entries[index]);
|
||||
}
|
||||
|
||||
HelpEvents.InvokeStuckMenu(m_Mobile);
|
||||
}
|
||||
|
||||
private void Teleport(StuckMenuEntry entry)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,8 @@ namespace Server.Engines.PartySystem
|
|||
}
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile from)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile from)
|
||||
{
|
||||
var p = Get(from);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Items;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Plants
|
||||
{
|
||||
|
|
@ -432,7 +434,8 @@ namespace Server.Engines.Plants
|
|||
}
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile from)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile from)
|
||||
{
|
||||
Container cont = from.Backpack;
|
||||
if (cont != null)
|
||||
|
|
|
|||
|
|
@ -80,9 +80,10 @@ public class PlayerMurderSystem : GenericPersistence
|
|||
UpdateMurderContext(context);
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (m is not PlayerMobile pm || !GetMurderContext(pm, out var context))
|
||||
if (!GetMurderContext(pm, out var context))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Accounting;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
|
|
@ -562,35 +563,31 @@ namespace Server.Engines.VeteranRewards
|
|||
RewardInterval = ServerConfiguration.GetOrUpdateSetting("vetRewards.rewardInterval", TimeSpan.FromDays(30.0));
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (!Enabled)
|
||||
if (!Enabled || !pm.Alive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m.Alive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ComputeRewardInfo(pm, out var cur, out var max, out var level);
|
||||
|
||||
ComputeRewardInfo(m, out var cur, out var max, out var level);
|
||||
|
||||
if (m.SkillsCap is 7000 or 7050 or 7100 or 7150 or 7200)
|
||||
if (pm.SkillsCap is 7000 or 7050 or 7100 or 7150 or 7200)
|
||||
{
|
||||
level = Math.Clamp(level, 0, 4);
|
||||
|
||||
if (SkillCapRewards)
|
||||
{
|
||||
m.SkillsCap = 7000 + level * 50;
|
||||
pm.SkillsCap = 7000 + level * 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
m.SkillsCap = 7000;
|
||||
pm.SkillsCap = 7000;
|
||||
}
|
||||
}
|
||||
|
||||
if (Core.ML && m is PlayerMobile pm && !pm.HasStatReward && HasHalfLevel(pm))
|
||||
if (Core.ML && !pm.HasStatReward && HasHalfLevel(pm))
|
||||
{
|
||||
pm.HasStatReward = true;
|
||||
pm.StatCap += 5;
|
||||
|
|
@ -598,7 +595,7 @@ namespace Server.Engines.VeteranRewards
|
|||
|
||||
if (cur < max)
|
||||
{
|
||||
m.SendGump(new RewardNoticeGump(m));
|
||||
pm.SendGump(new RewardNoticeGump(pm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,10 +52,9 @@ public class AddDoorGump : DynamicGump
|
|||
]
|
||||
];
|
||||
|
||||
private static int _maxCount;
|
||||
|
||||
private Type _type;
|
||||
private int _baseId;
|
||||
private int _page;
|
||||
|
||||
public AddDoorGump() : base(50, 40)
|
||||
{
|
||||
|
|
@ -72,66 +71,38 @@ public class AddDoorGump : DynamicGump
|
|||
AddBlueBack(ref builder, 155, 174);
|
||||
|
||||
builder.AddItem(25, 24, _baseId);
|
||||
builder.AddButton(26, 37, 0x5782, 0x5782, 1);
|
||||
builder.AddButton(26, 37, 0x5782, 0x5782, 10);
|
||||
|
||||
builder.AddItem(47, 45, _baseId + 2);
|
||||
builder.AddButton(43, 57, 0x5783, 0x5783, 2);
|
||||
builder.AddButton(43, 57, 0x5783, 0x5783, 11);
|
||||
|
||||
builder.AddItem(87, 22, _baseId + 10);
|
||||
builder.AddButton(116, 35, 0x5785, 0x5785, 6);
|
||||
builder.AddButton(116, 35, 0x5785, 0x5785, 15);
|
||||
|
||||
builder.AddItem(65, 45, _baseId + 8);
|
||||
builder.AddButton(96, 55, 0x5784, 0x5784, 5);
|
||||
builder.AddButton(96, 55, 0x5784, 0x5784, 14);
|
||||
|
||||
builder.AddButton(73, 36, 0x2716, 0x2716, 9);
|
||||
builder.AddButton(73, 36, 0x2716, 0x2716, 18);
|
||||
}
|
||||
else
|
||||
{
|
||||
var pages = _types.Length;
|
||||
if (_maxCount == 0)
|
||||
{
|
||||
for (var i = 0; i < pages; i++)
|
||||
{
|
||||
_maxCount = Math.Max(_maxCount, _types[i].Length);
|
||||
}
|
||||
}
|
||||
var types = _types[_page];
|
||||
|
||||
AddBlueBack(ref builder, 20 + (_maxCount + 1) * 50, 165);
|
||||
AddBlueBack(ref builder, 20 + (types.Length + 1) * 50, 165);
|
||||
|
||||
builder.AddHtmlLocalized(30, 45, 60, 20, 1043353, 0x7FFF); // Next
|
||||
builder.AddHtmlLocalized(30, 85, 60, 20, 1011393, 0x7FFF); // Back
|
||||
|
||||
for (var i = 0; i < pages; ++i)
|
||||
builder.AddButton(30, 60, 0xFA5, 0xFA7, 1);
|
||||
builder.AddButton(30, 100, 0xFAE, 0xFB0, 2);
|
||||
|
||||
for (var i = 0; i < types.Length; i++)
|
||||
{
|
||||
var page = i + 1;
|
||||
var x = (i + 1) * 50;
|
||||
|
||||
builder.AddPage(page);
|
||||
|
||||
if (page < pages)
|
||||
{
|
||||
builder.AddButton(30, 60, 0xFA5, 0xFA7, 0, GumpButtonType.Page, page + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddButton(30, 60, 0xFA5, 0xFA7, 0, GumpButtonType.Page, 1);
|
||||
}
|
||||
|
||||
if (page > 1)
|
||||
{
|
||||
builder.AddButton(30, 100, 0xFAE, 0xFB0, 0, GumpButtonType.Page, page - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddButton(30, 100, 0xFAE, 0xFB0, 0, GumpButtonType.Page, pages);
|
||||
}
|
||||
|
||||
for (var j = 0; j < _types[i].Length; j++)
|
||||
{
|
||||
var x = (j + 1) * 50;
|
||||
|
||||
builder.AddButton(30 + x, 20, 0x2624, 0x2625, i * _maxCount + j + 1);
|
||||
builder.AddItem(15 + x, 30, _types[i][j].BaseID);
|
||||
}
|
||||
builder.AddButton(30 + x, 20, 0x2624, 0x2625, _page * types.Length + i + 10);
|
||||
builder.AddItem(15 + x, 30, types[i].BaseID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -147,35 +118,64 @@ public class AddDoorGump : DynamicGump
|
|||
public override void OnResponse(NetState sender, in RelayInfo info)
|
||||
{
|
||||
var from = sender.Mobile;
|
||||
var button = info.ButtonID - 1;
|
||||
var button = info.ButtonID;
|
||||
|
||||
if (_type == null)
|
||||
if (button == 0)
|
||||
{
|
||||
if (button < 0 || button >= _types.Length)
|
||||
if (_type != null)
|
||||
{
|
||||
_type = null;
|
||||
_baseId = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var page = Math.DivRem(button, _maxCount, out var pos);
|
||||
var door = _types[page][pos];
|
||||
_type = door.Type;
|
||||
_baseId = door.BaseID;
|
||||
}
|
||||
else if (button is >= 0 and < 8)
|
||||
else if (button == 1) // Next
|
||||
{
|
||||
CommandSystem.Handle(
|
||||
from,
|
||||
$"{CommandSystem.Prefix}Add {_type.Name} {(DoorFacing)button}"
|
||||
);
|
||||
_page++;
|
||||
if (_page >= _types.Length)
|
||||
{
|
||||
_page = 0;
|
||||
}
|
||||
}
|
||||
else if (button == 8)
|
||||
else if (button == 2) // Prev
|
||||
{
|
||||
CommandSystem.Handle(from, $"{CommandSystem.Prefix}Link");
|
||||
_page--;
|
||||
if (_page < 0)
|
||||
{
|
||||
_page = _types.Length - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_type = null;
|
||||
_baseId = 0;
|
||||
button -= 10;
|
||||
if (_type == null)
|
||||
{
|
||||
var types = _types[_page];
|
||||
var page = Math.DivRem(button, types.Length, out var pos);
|
||||
|
||||
if (page < 0 || pos >= types.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var door = types[pos];
|
||||
_type = door.Type;
|
||||
_baseId = door.BaseID;
|
||||
}
|
||||
else if (button is >= 0 and < 8)
|
||||
{
|
||||
CommandSystem.Handle(
|
||||
from,
|
||||
$"{CommandSystem.Prefix}Add {_type.Name} {(DoorFacing)button}"
|
||||
);
|
||||
}
|
||||
else if (button == 8)
|
||||
{
|
||||
CommandSystem.Handle(from, $"{CommandSystem.Prefix}Link");
|
||||
}
|
||||
}
|
||||
|
||||
from.SendGump(this);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Server.Misc;
|
|||
using Server.Multis;
|
||||
using Server.Network;
|
||||
using Server.Prompts;
|
||||
using Server.Saves;
|
||||
using Server.Text;
|
||||
|
||||
namespace Server.Gumps
|
||||
|
|
@ -295,6 +296,9 @@ namespace Server.Gumps
|
|||
|
||||
AddButtonLabeled(20, 230, GetButtonID(3, 203), "Shutdown & Restart (With Save)");
|
||||
AddButtonLabeled(20, 250, GetButtonID(3, 204), "Shutdown & Restart (Without Save)");
|
||||
|
||||
AddButtonLabeled(20, 270, GetButtonID(3, 205), "Shutdown (With 15m Delay & Save)");
|
||||
|
||||
/*}
|
||||
else
|
||||
{
|
||||
|
|
@ -2147,6 +2151,12 @@ namespace Server.Gumps
|
|||
Shutdown(true, false);
|
||||
break;
|
||||
}
|
||||
case 205: // shutdown with delay and save
|
||||
{
|
||||
var t = new ShutdownTimer(this);
|
||||
t.Start();
|
||||
break;
|
||||
}
|
||||
case 210:
|
||||
case 211:
|
||||
{
|
||||
|
|
@ -3927,32 +3937,32 @@ namespace Server.Gumps
|
|||
var availableMaps = ExpansionInfo.CoreExpansion.MapSelectionFlags;
|
||||
if (Core.SA && availableMaps.Includes(MapSelectionFlags.TerMur))
|
||||
{
|
||||
InvokeCommand("GenerateSpawners Data/Spawns/post-uoml/termur/*.json");
|
||||
InvokeCommand("GenerateSpawners Data/Spawns/post-uoml/termur/**.json");
|
||||
}
|
||||
|
||||
if (availableMaps.Includes(MapSelectionFlags.Malas))
|
||||
{
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/malas/*.json");
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/malas/**.json");
|
||||
}
|
||||
|
||||
if (availableMaps.Includes(MapSelectionFlags.Tokuno))
|
||||
{
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/tokuno/*.json");
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/tokuno/**.json");
|
||||
}
|
||||
|
||||
if (availableMaps.Includes(MapSelectionFlags.Ilshenar))
|
||||
{
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/ilshenar/*.json");
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/ilshenar/**.json");
|
||||
}
|
||||
|
||||
if (availableMaps.Includes(MapSelectionFlags.Trammel))
|
||||
{
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/trammel/*.json");
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/trammel/**.json");
|
||||
}
|
||||
|
||||
if (availableMaps.Includes(MapSelectionFlags.Felucca))
|
||||
{
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/felucca/*.json");
|
||||
InvokeCommand($"GenerateSpawners Data/Spawns/{folder}/felucca/**.json");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4251,5 +4261,30 @@ namespace Server.Gumps
|
|||
|
||||
public AdminNoticeGump(string content, Action callback) : base(callback) => Content = content;
|
||||
}
|
||||
|
||||
public class ShutdownTimer : Timer
|
||||
{
|
||||
private readonly AdminGump _adminGump;
|
||||
|
||||
public ShutdownTimer(AdminGump gump) : base(TimeSpan.Zero, TimeSpan.Zero, 8) =>
|
||||
_adminGump = gump;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (Index >= 7)
|
||||
{
|
||||
AutoSave.SavesEnabled = false;
|
||||
_adminGump.Shutdown(false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
ReadOnlySpan<int> times = [15, 10, 5, 4, 3, 2, 1, 0];
|
||||
var time = times[Index];
|
||||
_adminGump.m_From.SendMessage(
|
||||
$"The shard will shutdown in {time} minute{(time == 1 ? "s" : "")} for maintenance."
|
||||
);
|
||||
Interval = TimeSpan.FromMinutes(time - times[Index + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Engines.Craft;
|
||||
using Server.Ethics;
|
||||
using Server.Factions;
|
||||
using Server.Network;
|
||||
using Server.Text;
|
||||
using AMA = Server.Items.ArmorMeditationAllowance;
|
||||
using AMT = Server.Items.ArmorMaterialType;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
[SerializationGenerator(9, false)]
|
||||
public abstract partial class BaseArmor : Item, IScissorable, IFactionItem, ICraftable, IWearableDurability, IAosItem
|
||||
public abstract partial class BaseArmor
|
||||
: Item, IScissorable, IFactionItem, ICraftable, IWearableDurability, IAosItem, IIdentifiable
|
||||
{
|
||||
[SerializedIgnoreDupe]
|
||||
[SerializableField(0, setter: "private")]
|
||||
|
|
@ -101,7 +104,7 @@ namespace Server.Items
|
|||
private string _crafter;
|
||||
|
||||
[SerializableFieldSaveFlag(10)]
|
||||
private bool ShouldSerializeCrafter() => _crafter != null;
|
||||
private bool ShouldSerializeCrafter() => !string.IsNullOrEmpty(_crafter);
|
||||
|
||||
[SerializableFieldSaveFlag(14)]
|
||||
private bool ShouldSerializeResource() => _resource != DefaultResource;
|
||||
|
|
@ -559,6 +562,7 @@ namespace Server.Items
|
|||
|
||||
Resource = CraftResources.GetFromType(resourceType);
|
||||
PlayerConstructed = true;
|
||||
Identified = true;
|
||||
|
||||
var context = craftSystem.GetContext(from);
|
||||
|
||||
|
|
@ -1451,6 +1455,12 @@ namespace Server.Items
|
|||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
if (!Core.UOTD)
|
||||
{
|
||||
OnSingleClickPreUOTD(from);
|
||||
return;
|
||||
}
|
||||
|
||||
var attrs = new List<EquipInfoAttribute>();
|
||||
|
||||
if (DisplayLootType)
|
||||
|
|
@ -1482,13 +1492,12 @@ namespace Server.Items
|
|||
attrs.Add(new EquipInfoAttribute(1038000 + (int)_durability));
|
||||
}
|
||||
|
||||
if (_protectionLevel > ArmorProtectionLevel.Regular && _protectionLevel <= ArmorProtectionLevel.Invulnerability)
|
||||
if (_protectionLevel != ArmorProtectionLevel.Regular)
|
||||
{
|
||||
attrs.Add(new EquipInfoAttribute(1038005 + (int)_protectionLevel));
|
||||
}
|
||||
}
|
||||
else if (_durability != ArmorDurabilityLevel.Regular || _protectionLevel > ArmorProtectionLevel.Regular &&
|
||||
_protectionLevel <= ArmorProtectionLevel.Invulnerability)
|
||||
else if (_durability != ArmorDurabilityLevel.Regular || _protectionLevel != ArmorProtectionLevel.Regular)
|
||||
{
|
||||
attrs.Add(new EquipInfoAttribute(1038000)); // Unidentified
|
||||
}
|
||||
|
|
@ -1513,6 +1522,100 @@ namespace Server.Items
|
|||
from.NetState.SendDisplayEquipmentInfo(Serial, number, _crafter, false, attrs);
|
||||
}
|
||||
|
||||
public void OnSingleClickPreUOTD(Mobile from)
|
||||
{
|
||||
var isMagicItem = _durability != ArmorDurabilityLevel.Regular ||
|
||||
_protectionLevel != ArmorProtectionLevel.Regular;
|
||||
|
||||
if (isMagicItem && !_identified)
|
||||
{
|
||||
LabelTo(from, $"an unidentified {Name ?? Localization.GetText(LabelNumber).ToLowerInvariant()}");
|
||||
return;
|
||||
}
|
||||
|
||||
var name = Name;
|
||||
var articleAnName = (TileData.ItemTable[ItemID].Flags & TileFlag.ArticleAn) != 0;
|
||||
|
||||
if (isMagicItem)
|
||||
{
|
||||
var builder = ValueStringBuilder.Create(128);
|
||||
|
||||
var durabilityText = DurabilityText(out var articleAnDurability);
|
||||
if (durabilityText != null)
|
||||
{
|
||||
builder.AppendSpaceWithArticle(durabilityText, articleAnDurability);
|
||||
}
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
builder.AppendSpaceWithArticle(Localization.GetText(LabelNumber).ToLowerInvariant(), articleAnName);
|
||||
}
|
||||
else if (builder.Length != 0)
|
||||
{
|
||||
builder.Append($" {name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(name);
|
||||
}
|
||||
|
||||
var protectionText = ProtectionText;
|
||||
if (protectionText != null)
|
||||
{
|
||||
builder.Append($" of {protectionText}");
|
||||
}
|
||||
|
||||
LabelTo(from, builder.ToString());
|
||||
builder.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
name ??= $"{(articleAnName ? "an" : "a")} {Localization.GetText(LabelNumber).ToLowerInvariant()}";
|
||||
|
||||
if (Crafter == null)
|
||||
{
|
||||
LabelTo(from, Quality == ArmorQuality.Exceptional ? $"{name} of exceptional quality" : name);
|
||||
return;
|
||||
}
|
||||
|
||||
LabelTo(
|
||||
from,
|
||||
Quality == ArmorQuality.Exceptional
|
||||
? $"{name} crafted with exceptional quality by {Crafter}"
|
||||
: $"{name} crafted by {Crafter}"
|
||||
);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private string DurabilityText(out bool articleAn)
|
||||
{
|
||||
articleAn = _durability is ArmorDurabilityLevel.Indestructible;
|
||||
return _durability switch
|
||||
{
|
||||
ArmorDurabilityLevel.Durable => "durable",
|
||||
ArmorDurabilityLevel.Substantial => "substantial",
|
||||
ArmorDurabilityLevel.Massive => "massive",
|
||||
ArmorDurabilityLevel.Fortified => "fortified",
|
||||
ArmorDurabilityLevel.Indestructible => "indestructable",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private string ProtectionText
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get =>
|
||||
_protectionLevel switch
|
||||
{
|
||||
ArmorProtectionLevel.Defense => "defense",
|
||||
ArmorProtectionLevel.Guarding => "guarding",
|
||||
ArmorProtectionLevel.Hardening => "hardening",
|
||||
ArmorProtectionLevel.Fortification => "fortification",
|
||||
ArmorProtectionLevel.Invulnerability => "invulnerability",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum OldSaveFlag
|
||||
{
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ namespace Server.Items
|
|||
private string _crafter;
|
||||
|
||||
[SerializableFieldSaveFlag(8)]
|
||||
private bool ShouldSerializeCrafter() => _crafter != null;
|
||||
private bool ShouldSerializeCrafter() => !string.IsNullOrEmpty(_crafter);
|
||||
|
||||
[InvalidateProperties]
|
||||
[SerializableField(9)]
|
||||
|
|
@ -907,8 +907,13 @@ namespace Server.Items
|
|||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
var attrs = new List<EquipInfoAttribute>();
|
||||
if (!Core.UOTD)
|
||||
{
|
||||
OnSingleClickPreUOTD(from);
|
||||
return;
|
||||
}
|
||||
|
||||
var attrs = new List<EquipInfoAttribute>();
|
||||
AddEquipInfoAttributes(from, attrs);
|
||||
|
||||
int number;
|
||||
|
|
@ -931,6 +936,30 @@ namespace Server.Items
|
|||
from.NetState.SendDisplayEquipmentInfo(Serial, number, _crafter, false, attrs);
|
||||
}
|
||||
|
||||
public void OnSingleClickPreUOTD(Mobile from)
|
||||
{
|
||||
var name = Name;
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
var articleAnName = (TileData.ItemTable[ItemID].Flags & TileFlag.ArticleAn) != 0;
|
||||
name = $"{(articleAnName ? "an" : "a")} {Localization.GetText(LabelNumber).ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
if (Crafter == null)
|
||||
{
|
||||
LabelTo(from, Quality == ClothingQuality.Exceptional ? $"{name} of exceptional quality" : name);
|
||||
return;
|
||||
}
|
||||
|
||||
LabelTo(
|
||||
from,
|
||||
Quality == ClothingQuality.Exceptional
|
||||
? $"{name} crafted with exceptional quality by {Crafter}"
|
||||
: $"{name} crafted by {Crafter}"
|
||||
);
|
||||
}
|
||||
|
||||
public virtual void AddEquipInfoAttributes(Mobile from, List<EquipInfoAttribute> attrs)
|
||||
{
|
||||
if (DisplayLootType)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@ public abstract partial class FillableContainer : LockableContainer
|
|||
}
|
||||
}
|
||||
|
||||
public FillableContainer(int itemID) : base(itemID) => Movable = false;
|
||||
public FillableContainer(int itemID) : base(itemID)
|
||||
{
|
||||
Movable = false;
|
||||
_contentType = FillableContentType.None;
|
||||
}
|
||||
|
||||
public virtual int MinRespawnMinutes => 60;
|
||||
public virtual int MaxRespawnMinutes => 90;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Collections;
|
||||
using Server.Engines.Plants;
|
||||
|
|
@ -711,10 +713,9 @@ public abstract partial class BaseBeverage : Item, IHasQuantity
|
|||
_quantity = reader.ReadInt();
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
{
|
||||
CheckHeaveTimer(m);
|
||||
}
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void OnLogin(PlayerMobile pm) => CheckHeaveTimer(pm);
|
||||
|
||||
public static void CheckHeaveTimer(Mobile from)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public partial class BaseQuiver : Container, ICraftable, IAosItem
|
|||
private string _crafter;
|
||||
|
||||
[SerializableFieldSaveFlag(4)]
|
||||
private bool ShouldSerializeCrafter() => _crafter != null;
|
||||
private bool ShouldSerializeCrafter() => !string.IsNullOrEmpty(_crafter);
|
||||
|
||||
[InvalidateProperties]
|
||||
[SerializableField(5)]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
|
|
@ -168,6 +169,12 @@ public abstract partial class BaseWand : BaseBashing
|
|||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
if (!Core.UOTD)
|
||||
{
|
||||
OnSingleClickPreUOTD(from);
|
||||
return;
|
||||
}
|
||||
|
||||
var attrs = new List<EquipInfoAttribute>();
|
||||
|
||||
if (DisplayLootType)
|
||||
|
|
@ -230,6 +237,45 @@ public abstract partial class BaseWand : BaseBashing
|
|||
from.NetState.SendDisplayEquipmentInfo(Serial, number, Crafter, false, attrs);
|
||||
}
|
||||
|
||||
public void OnSingleClickPreUOTD(Mobile from)
|
||||
{
|
||||
var isMagicItem = _charges > 0;
|
||||
var name = Name;
|
||||
if (name == null)
|
||||
{
|
||||
var articleAnName = (TileData.ItemTable[ItemID].Flags & TileFlag.ArticleAn) != 0;
|
||||
name = $"{(articleAnName ? "an" : "a")} {Localization.GetText(LabelNumber).ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
if (isMagicItem && !Identified)
|
||||
{
|
||||
LabelTo(from, $"an unidentified {name}");
|
||||
return;
|
||||
}
|
||||
|
||||
LabelTo(from, isMagicItem ? $"{name} of {WandEffectText}" : name);
|
||||
}
|
||||
|
||||
private string WandEffectText
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _wandEffect switch
|
||||
{
|
||||
WandEffect.Clumsiness => "clumsiness",
|
||||
WandEffect.Identification => "identification",
|
||||
WandEffect.Healing => "healing",
|
||||
WandEffect.Feeblemindedness => "feeblemindedness",
|
||||
WandEffect.Weakness => "weakness",
|
||||
WandEffect.MagicArrow => "magic arrow",
|
||||
WandEffect.Harming => "harming",
|
||||
WandEffect.Fireball => "fireball",
|
||||
WandEffect.GreaterHealing => "greater healing",
|
||||
WandEffect.Lightning => "lightning",
|
||||
WandEffect.ManaDraining => "mana draining",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public void Cast(Spell spell)
|
||||
{
|
||||
var m = Movable;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using Server.Spells.Necromancy;
|
|||
using Server.Spells.Ninjitsu;
|
||||
using Server.Spells.Sixth;
|
||||
using Server.Spells.Spellweaving;
|
||||
using Server.Text;
|
||||
|
||||
namespace Server.Items;
|
||||
|
||||
|
|
@ -27,7 +28,8 @@ public interface ISlayer
|
|||
}
|
||||
|
||||
[SerializationGenerator(10, false)]
|
||||
public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability, IAosItem
|
||||
public abstract partial class BaseWeapon
|
||||
: Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability, IAosItem, IIdentifiable
|
||||
{
|
||||
private static bool _enableInstaHit;
|
||||
|
||||
|
|
@ -104,7 +106,7 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
|
||||
[SerializableFieldSaveFlag(9)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool ShouldSerializeCrafter() => string.IsNullOrEmpty(_crafter);
|
||||
private bool ShouldSerializeCrafter() => !string.IsNullOrEmpty(_crafter);
|
||||
|
||||
[InvalidateProperties]
|
||||
[SerializableField(10)]
|
||||
|
|
@ -673,6 +675,7 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
}
|
||||
|
||||
PlayerConstructed = true;
|
||||
Identified = true;
|
||||
|
||||
var resourceType = typeRes ?? craftItem.Resources[0].ItemType;
|
||||
|
||||
|
|
@ -728,21 +731,18 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
{
|
||||
case CraftResource.DullCopper:
|
||||
{
|
||||
Identified = true;
|
||||
DurabilityLevel = WeaponDurabilityLevel.Durable;
|
||||
AccuracyLevel = WeaponAccuracyLevel.Accurate;
|
||||
break;
|
||||
}
|
||||
case CraftResource.ShadowIron:
|
||||
{
|
||||
Identified = true;
|
||||
DurabilityLevel = WeaponDurabilityLevel.Durable;
|
||||
DamageLevel = WeaponDamageLevel.Ruin;
|
||||
break;
|
||||
}
|
||||
case CraftResource.Copper:
|
||||
{
|
||||
Identified = true;
|
||||
DurabilityLevel = WeaponDurabilityLevel.Fortified;
|
||||
DamageLevel = WeaponDamageLevel.Ruin;
|
||||
AccuracyLevel = WeaponAccuracyLevel.Surpassingly;
|
||||
|
|
@ -750,7 +750,6 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
}
|
||||
case CraftResource.Bronze:
|
||||
{
|
||||
Identified = true;
|
||||
DurabilityLevel = WeaponDurabilityLevel.Fortified;
|
||||
DamageLevel = WeaponDamageLevel.Might;
|
||||
AccuracyLevel = WeaponAccuracyLevel.Surpassingly;
|
||||
|
|
@ -758,7 +757,6 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
}
|
||||
case CraftResource.Gold:
|
||||
{
|
||||
Identified = true;
|
||||
DurabilityLevel = WeaponDurabilityLevel.Indestructible;
|
||||
DamageLevel = WeaponDamageLevel.Force;
|
||||
AccuracyLevel = WeaponAccuracyLevel.Eminently;
|
||||
|
|
@ -766,7 +764,6 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
}
|
||||
case CraftResource.Agapite:
|
||||
{
|
||||
Identified = true;
|
||||
DurabilityLevel = WeaponDurabilityLevel.Indestructible;
|
||||
DamageLevel = WeaponDamageLevel.Power;
|
||||
AccuracyLevel = WeaponAccuracyLevel.Eminently;
|
||||
|
|
@ -774,7 +771,6 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
}
|
||||
case CraftResource.Verite:
|
||||
{
|
||||
Identified = true;
|
||||
DurabilityLevel = WeaponDurabilityLevel.Indestructible;
|
||||
DamageLevel = WeaponDamageLevel.Power;
|
||||
AccuracyLevel = WeaponAccuracyLevel.Exceedingly;
|
||||
|
|
@ -782,7 +778,6 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
}
|
||||
case CraftResource.Valorite:
|
||||
{
|
||||
Identified = true;
|
||||
DurabilityLevel = WeaponDurabilityLevel.Indestructible;
|
||||
DamageLevel = WeaponDamageLevel.Vanq;
|
||||
AccuracyLevel = WeaponAccuracyLevel.Supremely;
|
||||
|
|
@ -3332,6 +3327,12 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
if (!Core.UOTD)
|
||||
{
|
||||
OnSingleClickPreUOTD(from);
|
||||
return;
|
||||
}
|
||||
|
||||
var attrs = new List<EquipInfoAttribute>();
|
||||
|
||||
if (DisplayLootType)
|
||||
|
|
@ -3423,6 +3424,130 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
|
|||
from.NetState.SendDisplayEquipmentInfo(Serial, number, _crafter, false, attrs);
|
||||
}
|
||||
|
||||
public virtual void OnSingleClickPreUOTD(Mobile from)
|
||||
{
|
||||
var isMagicItem = _durabilityLevel > WeaponDurabilityLevel.Regular ||
|
||||
_accuracyLevel > WeaponAccuracyLevel.Regular ||
|
||||
_damageLevel > WeaponDamageLevel.Regular ||
|
||||
_slayer != SlayerName.None;
|
||||
|
||||
if (isMagicItem && !_identified)
|
||||
{
|
||||
LabelTo(from, $"an unidentified {Name ?? Localization.GetText(LabelNumber).ToLowerInvariant()}");
|
||||
return;
|
||||
}
|
||||
|
||||
var name = Name;
|
||||
var articleAnName = (TileData.ItemTable[ItemID].Flags & TileFlag.ArticleAn) != 0;
|
||||
|
||||
if (isMagicItem)
|
||||
{
|
||||
var builder = ValueStringBuilder.Create(128);
|
||||
|
||||
var durabilityText = DurabilityText(out var articleAnDurability);
|
||||
if (durabilityText != null)
|
||||
{
|
||||
builder.AppendSpaceWithArticle(durabilityText, articleAnDurability);
|
||||
}
|
||||
|
||||
var accuracyText = AccuracyText(out var articleAnAccuracy);
|
||||
if (accuracyText != null)
|
||||
{
|
||||
builder.AppendSpaceWithArticle(accuracyText, articleAnAccuracy);
|
||||
}
|
||||
|
||||
var slayerEntry = SlayerGroup.GetEntryByName(_slayer);
|
||||
if (slayerEntry != null)
|
||||
{
|
||||
builder.AppendSpaceWithArticle(slayerEntry.SlayerText(out var articleAnSlayer), articleAnSlayer);
|
||||
}
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
builder.AppendSpaceWithArticle(Localization.GetText(LabelNumber).ToLowerInvariant(), articleAnName);
|
||||
}
|
||||
else if (builder.Length != 0)
|
||||
{
|
||||
builder.Append($" {name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(name);
|
||||
}
|
||||
|
||||
var weaponDamageText = WeaponDamageText;
|
||||
if (weaponDamageText != null)
|
||||
{
|
||||
builder.Append($" of {weaponDamageText}");
|
||||
}
|
||||
|
||||
// TODO: Spells (of Ghoul's Touch)
|
||||
|
||||
LabelTo(from, builder.ToString());
|
||||
builder.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
name ??= $"{(articleAnName ? "an" : "a")} {Localization.GetText(LabelNumber).ToLowerInvariant()}";
|
||||
|
||||
if (Crafter == null)
|
||||
{
|
||||
LabelTo(from, Quality == WeaponQuality.Exceptional ? $"{name} of exceptional quality" : name);
|
||||
return;
|
||||
}
|
||||
|
||||
LabelTo(
|
||||
from,
|
||||
Quality == WeaponQuality.Exceptional
|
||||
? $"{name} crafted with exceptional quality by {Crafter}"
|
||||
: $"{name} crafted by {Crafter}"
|
||||
);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private string DurabilityText(out bool articleAn)
|
||||
{
|
||||
articleAn = _durabilityLevel is WeaponDurabilityLevel.Indestructible;
|
||||
return _durabilityLevel switch
|
||||
{
|
||||
WeaponDurabilityLevel.Durable => "durable",
|
||||
WeaponDurabilityLevel.Substantial => "substantial",
|
||||
WeaponDurabilityLevel.Massive => "massive",
|
||||
WeaponDurabilityLevel.Fortified => "fortified",
|
||||
WeaponDurabilityLevel.Indestructible => "indestructible",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private string AccuracyText(out bool articleAn)
|
||||
{
|
||||
articleAn = _accuracyLevel is WeaponAccuracyLevel.Accurate or WeaponAccuracyLevel.Eminently;
|
||||
return _accuracyLevel switch
|
||||
{
|
||||
WeaponAccuracyLevel.Accurate => "accurate",
|
||||
WeaponAccuracyLevel.Surpassingly => "surpassingly accurate",
|
||||
WeaponAccuracyLevel.Eminently => "eminently accurate",
|
||||
WeaponAccuracyLevel.Exceedingly => "exceedingly accurate",
|
||||
WeaponAccuracyLevel.Supremely => "supremely accurate",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private string WeaponDamageText
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _damageLevel switch
|
||||
{
|
||||
WeaponDamageLevel.Ruin => "ruin",
|
||||
WeaponDamageLevel.Might => "might",
|
||||
WeaponDamageLevel.Force => "force",
|
||||
WeaponDamageLevel.Power => "power",
|
||||
WeaponDamageLevel.Vanq => "vanquishing",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public virtual int GetHitAttackSound(Mobile attacker, Mobile defender)
|
||||
{
|
||||
var sound = attacker.GetAttackSound();
|
||||
|
|
|
|||
|
|
@ -98,5 +98,10 @@ namespace Server.Items
|
|||
Effects.PlaySound(endLoc, map, Utility.Random(0x11B, 4));
|
||||
Effects.SendLocationEffect(endLoc, map, 0x373A + 0x10 * Utility.Random(4), 16, 10, hue, renderMode);
|
||||
}
|
||||
|
||||
public override void OnSingleClickPreUOTD(Mobile from)
|
||||
{
|
||||
LabelTo(from, Name ?? Localization.GetText(LabelNumber).ToLowerInvariant());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,20 @@ namespace Server.Items
|
|||
}
|
||||
}
|
||||
|
||||
public string SlayerText(out bool articleAn)
|
||||
{
|
||||
if (Name == SlayerName.None)
|
||||
{
|
||||
articleAn = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
articleAn = Name is SlayerName.OrcSlaying or SlayerName.OgreTrashing or SlayerName.Exorcism or SlayerName.Ophidian
|
||||
or SlayerName.ArachnidDoom or SlayerName.ElementalBan or SlayerName.ElementalHealth or SlayerName.EarthShatter;
|
||||
|
||||
return Localization.GetText(Title)?.ToLowerInvariant();
|
||||
}
|
||||
|
||||
public bool Slays(Mobile m)
|
||||
{
|
||||
var t = m.GetType();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
|
|
@ -108,17 +109,15 @@ namespace Server
|
|||
Enabled = ServerConfiguration.GetOrUpdateSetting("buffIcons.enable", Core.ML);
|
||||
}
|
||||
|
||||
public static void ResendBuffsOnClientVersionReceived(NetState ns, ClientVersion cv)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (!Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ns.Mobile is PlayerMobile pm)
|
||||
{
|
||||
Timer.StartTimer(pm.ResendBuffs);
|
||||
}
|
||||
pm.ResendBuffs();
|
||||
}
|
||||
|
||||
public static void AddBuff(Mobile m, BuffInfo b)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
|
|
@ -55,10 +57,8 @@ namespace Server
|
|||
}
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
{
|
||||
m.CheckLightLevels(true);
|
||||
}
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm) => pm.CheckLightLevels(true);
|
||||
|
||||
public static int ComputeLevelFor(Mobile from)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Misc
|
||||
{
|
||||
public static class LoginStats
|
||||
{
|
||||
public static void OnLogin(Mobile m)
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
var userCount = NetState.Instances.Count;
|
||||
var itemCount = World.Items.Count;
|
||||
var mobileCount = World.Mobiles.Count;
|
||||
|
||||
m.SendMessage(
|
||||
$"Welcome, {m.Name}! There {(userCount == 1 ? "is" : "are")} currently {userCount} user{(userCount == 1 ? "" : "s")} " +
|
||||
pm.SendMessage(
|
||||
$"Welcome, {pm.Name}! There {(userCount == 1 ? "is" : "are")} currently {userCount} user{(userCount == 1 ? "" : "s")} " +
|
||||
$"online, with {itemCount} item{(itemCount == 1 ? "" : "s")} and {mobileCount} mobile{(mobileCount == 1 ? "" : "s")} in the world."
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Prompts;
|
||||
|
||||
|
|
@ -125,14 +127,15 @@ public partial class ShardPoller : Item
|
|||
Options[^1] = option;
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (_activePollers.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1.0), () => EventSink_Login_Callback(m));
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1.0), () => EventSink_Login_Callback(pm));
|
||||
}
|
||||
|
||||
private static void EventSink_Login_Callback(Mobile from)
|
||||
|
|
|
|||
|
|
@ -82,17 +82,19 @@ public static class StaminaSystem
|
|||
RemoveEntry(m as IHasSteps);
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
bool exists;
|
||||
if (EnableMountStamina)
|
||||
{
|
||||
// Start idle for mount
|
||||
ref var stepsTaken = ref GetStepsTaken(m.Mount, out var exists);
|
||||
ref var stepsTaken = ref GetStepsTaken(pm.Mount, out exists);
|
||||
if (exists)
|
||||
{
|
||||
if (stepsTaken.Steps <= 0 || Core.Now >= stepsTaken.IdleStartTime + ResetDuration)
|
||||
{
|
||||
_stepsTaken.Remove(m.Mount);
|
||||
_stepsTaken.Remove(pm.Mount);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -100,16 +102,13 @@ public static class StaminaSystem
|
|||
}
|
||||
}
|
||||
|
||||
_resetHash.Remove(m.Mount);
|
||||
_resetHash.Remove(pm.Mount);
|
||||
}
|
||||
|
||||
if (m is PlayerMobile pm)
|
||||
ref var regenStepsTaken = ref RegenSteps(pm, out exists);
|
||||
if (exists)
|
||||
{
|
||||
ref var stepsTaken = ref RegenSteps(pm, out var exists);
|
||||
if (exists)
|
||||
{
|
||||
stepsTaken.IdleStartTime = Core.Now;
|
||||
}
|
||||
regenStepsTaken.IdleStartTime = Core.Now;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1220,6 +1220,10 @@ namespace Server.Mobiles
|
|||
}
|
||||
}
|
||||
|
||||
[GeneratedEvent(nameof(PlayerLoginEvent))]
|
||||
public static partial void PlayerLoginEvent(PlayerMobile pm);
|
||||
|
||||
[OnEvent(nameof(PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile from)
|
||||
{
|
||||
if (AccountHandler.LockdownLevel > AccessLevel.Player)
|
||||
|
|
@ -4474,20 +4478,39 @@ namespace Server.Mobiles
|
|||
|
||||
public void SendAddBuffPacket(BuffInfo buffInfo)
|
||||
{
|
||||
if (buffInfo == null)
|
||||
if (buffInfo == null || NetState?.BuffIcon != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Synchronize the buff icon as close to _on the second_ as we can.
|
||||
var msecs = buffInfo.TimeLength.Milliseconds;
|
||||
if (msecs >= 8)
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.FromMilliseconds(msecs), () =>
|
||||
{
|
||||
// They are still online, we still have the buff icon in the table, and it is the same buff icon
|
||||
if (NetState != null && m_BuffTable?.GetValueOrDefault(buffInfo.ID) == buffInfo)
|
||||
{
|
||||
SendAddBuffPacket(buffInfo, (long)buffInfo.TimeLength.TotalMilliseconds - msecs);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
SendAddBuffPacket(buffInfo, (long)buffInfo.TimeLength.TotalMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendAddBuffPacket(BuffInfo buffInfo, long ticks)
|
||||
{
|
||||
NetState.SendAddBuffPacket(
|
||||
Serial,
|
||||
buffInfo.ID,
|
||||
buffInfo.TitleCliloc,
|
||||
buffInfo.SecondaryCliloc,
|
||||
buffInfo.Args,
|
||||
buffInfo.TimeStart == 0
|
||||
? 0
|
||||
: Math.Max(buffInfo.TimeStart + (long)buffInfo.TimeLength.TotalMilliseconds - Core.TickCount, 0)
|
||||
ticks
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -4512,29 +4535,9 @@ namespace Server.Mobiles
|
|||
RemoveBuff(b); // Check & subsequently remove the old one.
|
||||
|
||||
m_BuffTable ??= new Dictionary<BuffIcon, BuffInfo>();
|
||||
|
||||
m_BuffTable.Add(b.ID, b);
|
||||
|
||||
if (NetState?.BuffIcon == true)
|
||||
{
|
||||
// Synchronize the buff icon as close to _on the second_ as we can.
|
||||
var msecs = b.TimeLength.Milliseconds;
|
||||
if (msecs >= 8)
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.FromMilliseconds(msecs), (buffInfo, pm) =>
|
||||
{
|
||||
// They are still online, we still have the buff icon in the table, and it is the same buff icon
|
||||
if (pm.NetState != null && pm.m_BuffTable?.GetValueOrDefault(buffInfo.ID) == buffInfo)
|
||||
{
|
||||
pm.SendAddBuffPacket(buffInfo);
|
||||
}
|
||||
}, b, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendAddBuffPacket(b);
|
||||
}
|
||||
}
|
||||
SendAddBuffPacket(b);
|
||||
}
|
||||
|
||||
public void RemoveBuff(BuffInfo b)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Misc
|
||||
{
|
||||
public static class Strandedness
|
||||
|
|
@ -112,7 +115,8 @@ namespace Server.Misc
|
|||
return false;
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile from)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile from)
|
||||
{
|
||||
if (!IsStranded(from))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,23 +17,9 @@ using System;
|
|||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Server.Accounting;
|
||||
using Server.Assistants;
|
||||
using Server.Commands;
|
||||
using Server.Engines.CharacterCreation;
|
||||
using Server.Engines.ConPVP;
|
||||
using Server.Engines.Doom;
|
||||
using Server.Engines.PartySystem;
|
||||
using Server.Engines.Plants;
|
||||
using Server.Engines.PlayerMurderSystem;
|
||||
using Server.Engines.VeteranRewards;
|
||||
using Server.Factions;
|
||||
using Server.Items;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
using Server.Regions;
|
||||
using Server.Spells.Ninjitsu;
|
||||
using Server.Spells.Spellweaving;
|
||||
|
||||
namespace Server.Network;
|
||||
|
||||
|
|
@ -314,34 +300,10 @@ public static class IncomingAccountPackets
|
|||
|
||||
state.SendPlayMusic(m.Region.Music);
|
||||
|
||||
StaminaSystem.OnLogin(m);
|
||||
DuelContext.OnLogin(m);
|
||||
LightCycle.OnLogin(m);
|
||||
LoginStats.OnLogin(m);
|
||||
AnimalForm.OnLogin(m);
|
||||
BaseBeverage.OnLogin(m);
|
||||
AntiMacroSystem.OnLogin(m);
|
||||
Strandedness.OnLogin(m);
|
||||
ShardPoller.OnLogin(m);
|
||||
ReaperFormSpell.OnLogin(m);
|
||||
Party.OnLogin(m);
|
||||
PlantSystem.OnLogin(m);
|
||||
LampRoomRegion.OnLogin(m);
|
||||
HouseRegion.OnLogin(m);
|
||||
Faction.OnLogin(m);
|
||||
PlayerMurderSystem.OnLogin(m);
|
||||
AssistantHandler.OnLogin(m);
|
||||
VisibilityList.OnLogin(m);
|
||||
|
||||
if (m is PlayerMobile pm)
|
||||
{
|
||||
PlayerMobile.OnLogin(pm);
|
||||
PlayerMobile.PlayerLoginEvent(pm);
|
||||
}
|
||||
Account.OnLogin(m);
|
||||
GiftGiving.OnLogin(m);
|
||||
PreventInaccess.OnLogin(m);
|
||||
TwistedWealdDesertRegion.OnLogin(m);
|
||||
RewardSystem.OnLogin(m);
|
||||
}
|
||||
|
||||
private static int GenerateAuthID(this NetState state)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
|
@ -29,13 +30,14 @@ public class HouseRegion : BaseRegion
|
|||
{
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
var house = BaseHouse.FindHouseAt(m);
|
||||
var house = BaseHouse.FindHouseAt(pm);
|
||||
|
||||
if (house?.Public == false && !house.IsFriend(m))
|
||||
if (house?.Public == false && !house.IsFriend(pm))
|
||||
{
|
||||
m.Location = house.BanLocation;
|
||||
pm.Location = house.BanLocation;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Ninjitsu;
|
||||
|
|
@ -41,11 +43,12 @@ public class TwistedWealdDesertRegion : MondainRegion
|
|||
}
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (m.Region.IsPartOf<TwistedWealdDesertRegion>() && m.AccessLevel == AccessLevel.Player)
|
||||
if (pm.AccessLevel == AccessLevel.Player && pm.Region.IsPartOf<TwistedWealdDesertRegion>())
|
||||
{
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
pm.NetState.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json.Serialization;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Collections;
|
||||
using Server.Json;
|
||||
using Server.Mobiles;
|
||||
|
|
@ -138,10 +139,11 @@ public static class AntiMacroSystem
|
|||
}
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
// Stop the clear out timer
|
||||
if (_logoutCleanup?.Remove(m, out var timer) == true)
|
||||
if (_logoutCleanup?.Remove(pm, out var timer) == true)
|
||||
{
|
||||
timer.Stop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,62 +2,62 @@ using System;
|
|||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
public interface IIdentifiable
|
||||
{
|
||||
public static class ItemIdentification
|
||||
bool Identified { get; set; }
|
||||
}
|
||||
|
||||
public static class ItemIdentification
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
public static void Initialize()
|
||||
SkillInfo.Table[(int)SkillName.ItemID].Callback = OnUse;
|
||||
}
|
||||
|
||||
public static TimeSpan OnUse(Mobile from)
|
||||
{
|
||||
from.SendLocalizedMessage(500343); // What do you wish to appraise and identify?
|
||||
from.Target = new InternalTarget();
|
||||
|
||||
return TimeSpan.FromSeconds(1.0);
|
||||
}
|
||||
|
||||
[PlayerVendorTarget]
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
public InternalTarget() : base(8, false, TargetFlags.None) => AllowNonlocal = true;
|
||||
|
||||
protected override void OnTarget(Mobile from, object o)
|
||||
{
|
||||
SkillInfo.Table[(int)SkillName.ItemID].Callback = OnUse;
|
||||
}
|
||||
|
||||
public static TimeSpan OnUse(Mobile from)
|
||||
{
|
||||
from.SendLocalizedMessage(500343); // What do you wish to appraise and identify?
|
||||
from.Target = new InternalTarget();
|
||||
|
||||
return TimeSpan.FromSeconds(1.0);
|
||||
}
|
||||
|
||||
[PlayerVendorTarget]
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
public InternalTarget() : base(8, false, TargetFlags.None) => AllowNonlocal = true;
|
||||
|
||||
protected override void OnTarget(Mobile from, object o)
|
||||
if (o is Mobile mobile)
|
||||
{
|
||||
if (o is Item item)
|
||||
{
|
||||
if (from.CheckTargetSkill(SkillName.ItemID, item, 0, 100))
|
||||
{
|
||||
if (item is BaseWeapon weapon)
|
||||
{
|
||||
weapon.Identified = true;
|
||||
}
|
||||
else if (item is BaseArmor armor)
|
||||
{
|
||||
armor.Identified = true;
|
||||
}
|
||||
mobile.OnSingleClick(from);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Core.AOS)
|
||||
{
|
||||
item.OnSingleClick(from);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(500353); // You are not certain...
|
||||
}
|
||||
}
|
||||
else if (o is Mobile mobile)
|
||||
bool identified = false;
|
||||
|
||||
if (o is Item item)
|
||||
{
|
||||
if (item is IIdentifiable identifiable && from.CheckTargetSkill(SkillName.ItemID, item, 0, 100))
|
||||
{
|
||||
mobile.OnSingleClick(from);
|
||||
identifiable.Identified = true;
|
||||
identified = true;
|
||||
}
|
||||
else
|
||||
|
||||
if (!Core.AOS)
|
||||
{
|
||||
from.SendLocalizedMessage(500353); // You are not certain...
|
||||
item.OnSingleClick(from);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!identified)
|
||||
{
|
||||
from.SendLocalizedMessage(500353); // You are not certain...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Accounting;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Misc
|
||||
{
|
||||
|
|
@ -19,9 +21,10 @@ namespace Server.Misc
|
|||
m_Givers.Add(giver);
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (m.Account is not Account acct)
|
||||
if (pm.Account is not Account acct)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -47,7 +50,7 @@ namespace Server.Misc
|
|||
continue; // already got one
|
||||
}
|
||||
|
||||
giver.DelayGiveGift(TimeSpan.FromSeconds(5.0), m);
|
||||
giver.DelayGiveGift(TimeSpan.FromSeconds(5.0), pm);
|
||||
}
|
||||
|
||||
acct.LastLogin = now;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Misc
|
||||
{
|
||||
|
|
@ -34,7 +36,8 @@ namespace Server.Misc
|
|||
m_MoveHistory = new Dictionary<Mobile, LocationInfo>();
|
||||
}
|
||||
|
||||
public static void OnLogin(Mobile from)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile from)
|
||||
{
|
||||
if (!Enabled)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -64,11 +64,12 @@ public class AnimalForm : NinjaSpell
|
|||
new(typeof(Reptalon), 1075202, 11669, 0, 1075222, 90.0, 0x114, 0, 0, false, false)
|
||||
};
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
if (GetContext(m)?.SpeedBoost == true)
|
||||
if (GetContext(pm)?.SpeedBoost == true)
|
||||
{
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Mount);
|
||||
pm.NetState.SendSpeedControl(SpeedControlSetting.Mount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using ModernUO.CodeGeneratedEvents;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Spells.Spellweaving
|
||||
|
|
@ -27,13 +29,14 @@ namespace Server.Spells.Spellweaving
|
|||
public virtual int SwingSpeedBonus => 10 + FocusLevel;
|
||||
public virtual int SpellDamageBonus => 10 + FocusLevel;
|
||||
|
||||
public static void OnLogin(Mobile m)
|
||||
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
||||
public static void OnLogin(PlayerMobile pm)
|
||||
{
|
||||
var context = TransformationSpellHelper.GetContext(m);
|
||||
var context = TransformationSpellHelper.GetContext(pm);
|
||||
|
||||
if (context?.Type == typeof(ReaperFormSpell))
|
||||
{
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
pm.NetState.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue