fix: Moves ContextMenu out of core, streamlines code, fixes bugs (#1873)

## Summary
- Removes allocation of a `List<ContextMenuEntry>` every time a context menu is created.
- Moves packet/context menu creation logic out of the core
- Fixes tame entry

## BREAKING CHANGE
> [!Important]
> **Developer Note**
> ```cs
> public virtual void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
> ```
> and similar functions changed to
> ```cs
> public virtual void GetContextMenuEntries(Mobile from, ref PooledRefList<ContextMenuEntry> list)
> ```
This commit is contained in:
Kamron Batman 2024-07-20 21:33:23 -07:00 • committed by GitHub
parent bb24b330e1
commit f58117a877
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
88 changed files with 1206 additions and 1483 deletions

View file

@ -160,40 +160,44 @@ public abstract class BaseAI
return name != null && speech.InsensitiveStartsWith(name);
}
public virtual void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
public virtual void GetContextMenuEntries(Mobile from, ref PooledRefList<ContextMenuEntry> list)
{
if (from.Alive && m_Mobile.Controlled && from.InRange(m_Mobile, 14))
if (!from.Alive || !m_Mobile.Controlled || !from.InRange(m_Mobile, 14))
{
if (from == m_Mobile.ControlMaster)
return;
}
var isDeadPet = m_Mobile.IsDeadPet;
if (from == m_Mobile.ControlMaster)
{
list.Add(new InternalEntry(6107, 14, OrderType.Guard, !isDeadPet)); // Command: Guard
list.Add(new InternalEntry(6108, 14, OrderType.Follow, true)); // Command: Follow
if (m_Mobile.CanDrop)
{
list.Add(new InternalEntry(from, 6107, 14, m_Mobile, this, OrderType.Guard)); // Command: Guard
list.Add(new InternalEntry(from, 6108, 14, m_Mobile, this, OrderType.Follow)); // Command: Follow
if (m_Mobile.CanDrop)
{
list.Add(new InternalEntry(from, 6109, 14, m_Mobile, this, OrderType.Drop)); // Command: Drop
}
list.Add(new InternalEntry(from, 6111, 14, m_Mobile, this, OrderType.Attack)); // Command: Kill
list.Add(new InternalEntry(from, 6112, 14, m_Mobile, this, OrderType.Stop)); // Command: Stop
list.Add(new InternalEntry(from, 6114, 14, m_Mobile, this, OrderType.Stay)); // Command: Stay
if (!m_Mobile.Summoned && m_Mobile is not GrizzledMare)
{
list.Add(new InternalEntry(from, 6110, 14, m_Mobile, this, OrderType.Friend)); // Add Friend
list.Add(new InternalEntry(from, 6099, 14, m_Mobile, this, OrderType.Unfriend)); // Remove Friend
list.Add(new InternalEntry(from, 6113, 14, m_Mobile, this, OrderType.Transfer)); // Transfer
}
list.Add(new InternalEntry(from, 6118, 14, m_Mobile, this, OrderType.Release)); // Release
list.Add(new InternalEntry(6109, 14, OrderType.Drop, !isDeadPet)); // Command: Drop
}
else if (m_Mobile.IsPetFriend(from))
list.Add(new InternalEntry(6111, 14, OrderType.Attack, !isDeadPet)); // Command: Kill
list.Add(new InternalEntry(6112, 14, OrderType.Stop, true)); // Command: Stop
list.Add(new InternalEntry(6114, 14, OrderType.Stay, true)); // Command: Stay
if (!m_Mobile.Summoned && m_Mobile is not GrizzledMare)
{
list.Add(new InternalEntry(from, 6108, 14, m_Mobile, this, OrderType.Follow)); // Command: Follow
list.Add(new InternalEntry(from, 6112, 14, m_Mobile, this, OrderType.Stop)); // Command: Stop
list.Add(new InternalEntry(from, 6114, 14, m_Mobile, this, OrderType.Stay)); // Command: Stay
list.Add(new InternalEntry(6110, 14, OrderType.Friend, true)); // Add Friend
list.Add(new InternalEntry(6099, 14, OrderType.Unfriend, true)); // Remove Friend
list.Add(new InternalEntry(6113, 14, OrderType.Transfer, !isDeadPet)); // Transfer
}
list.Add(new InternalEntry(6118, 14, OrderType.Release, true)); // Release
}
else if (m_Mobile.IsPetFriend(from))
{
list.Add(new InternalEntry(6108, 14, OrderType.Follow, true)); // Command: Follow
list.Add(new InternalEntry(6112, 14, OrderType.Stop, !isDeadPet)); // Command: Stop
list.Add(new InternalEntry(6114, 14, OrderType.Stay, true)); // Command: Stay
}
}
@ -2910,51 +2914,41 @@ public abstract class BaseAI
private class InternalEntry : ContextMenuEntry
{
private readonly BaseAI m_AI;
private readonly Mobile m_From;
private readonly BaseCreature m_Mobile;
private readonly OrderType m_Order;
private readonly OrderType _order;
public InternalEntry(Mobile from, int number, int range, BaseCreature mobile, BaseAI ai, OrderType order)
: base(number, range)
public InternalEntry(int number, int range, OrderType order, bool enabled) : base(number, range)
{
m_From = from;
m_Mobile = mobile;
m_AI = ai;
m_Order = order;
if (mobile.IsDeadPet && order is OrderType.Guard or OrderType.Attack or OrderType.Transfer or OrderType.Drop)
{
Enabled = false;
}
_order = order;
Enabled = enabled;
}
public override void OnClick()
public override void OnClick(Mobile from, IEntity target)
{
if (m_Mobile.Deleted || !m_Mobile.Controlled || !m_From.CheckAlive())
if (!from.CheckAlive() || target is not BaseCreature { Deleted: not true, Controlled: true } bc)
{
return;
}
if (m_Mobile.IsDeadPet && m_Order is OrderType.Guard or OrderType.Attack or OrderType.Transfer or OrderType.Drop)
// Just in case
if (bc.IsDeadPet && _order is OrderType.Guard or OrderType.Attack or OrderType.Transfer or OrderType.Drop)
{
return;
}
var isOwner = m_From == m_Mobile.ControlMaster;
var isFriend = !isOwner && m_Mobile.IsPetFriend(m_From);
var isOwner = from == bc.ControlMaster;
var isFriend = !isOwner && bc.IsPetFriend(from);
if (!isOwner && !isFriend)
{
return;
}
if (isFriend && m_Order != OrderType.Follow && m_Order != OrderType.Stay && m_Order != OrderType.Stop)
if (isFriend && _order != OrderType.Follow && _order != OrderType.Stay && _order != OrderType.Stop)
{
return;
}
switch (m_Order)
switch (_order)
{
case OrderType.Follow:
case OrderType.Attack:
@ -2962,37 +2956,37 @@ public abstract class BaseAI
case OrderType.Friend:
case OrderType.Unfriend:
{
if (m_Order == OrderType.Transfer && m_From.HasTrade)
if (_order == OrderType.Transfer && from.HasTrade)
{
m_From.SendLocalizedMessage(1010507); // You cannot transfer a pet with a trade pending
from.SendLocalizedMessage(1010507); // You cannot transfer a pet with a trade pending
}
else if (m_Order == OrderType.Friend && m_From.HasTrade)
else if (_order == OrderType.Friend && from.HasTrade)
{
m_From.SendLocalizedMessage(1070947); // You cannot friend a pet with a trade pending
from.SendLocalizedMessage(1070947); // You cannot friend a pet with a trade pending
}
else
{
m_AI.BeginPickTarget(m_From, m_Order);
bc.AIObject.BeginPickTarget(from, _order);
}
break;
}
case OrderType.Release:
{
if (m_Mobile.Summoned)
if (bc.Summoned)
{
goto default;
}
m_From.SendGump(new ConfirmReleaseGump(m_From, m_Mobile));
from.SendGump(new ConfirmReleaseGump(from, bc));
break;
}
default:
{
if (m_Mobile.CheckControlChance(m_From))
if (bc.CheckControlChance(from))
{
m_Mobile.ControlOrder = m_Order;
bc.ControlOrder = _order;
}
break;