Fixes more potion throwing edge cases (#1852)

This commit is contained in:
Kamron Batman 2024-07-03 18:04:03 -07:00 • committed by GitHub
parent cbaa349a87
commit ac3e4fcc97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 78 additions and 43 deletions

View file

@ -15,12 +15,11 @@ public partial class Firebomb : Item
private Point3D _thrownFromLocation; private Point3D _thrownFromLocation;
private int _ticks; private int _ticks;
private TimerExecutionToken _timerToken; private TimerExecutionToken _timerToken;
private List<Mobile> _users; private HashSet<Mobile> _users;
[Constructible] [Constructible]
public Firebomb(int itemID = 0x99B) : base(itemID) public Firebomb(int itemID = 0x99B) : base(itemID)
{ {
// Name = "a firebomb";
Weight = 2.0; Weight = 2.0;
Hue = 1260; Hue = 1260;
} }
@ -51,12 +50,8 @@ public partial class Firebomb : Item
from.SendLocalizedMessage(1060582); // You light the firebomb. Throw it now! from.SendLocalizedMessage(1060582); // You light the firebomb. Throw it now!
} }
_users ??= new List<Mobile>(); _users ??= [];
_users.Add(from);
if (!_users.Contains(from))
{
_users.Add(from);
}
from.Target = new ThrowTarget(this); from.Target = new ThrowTarget(this);
} }
@ -101,18 +96,23 @@ public partial class Firebomb : Item
{ {
HeldBy?.DropHolding(); HeldBy?.DropHolding();
if (_users != null) if (_users is { Count: > 0 })
{ {
foreach (var m in _users) using var usersQueue = PooledRefQueue<Mobile>.Create();
foreach (var user in _users)
{ {
if (m.Target is ThrowTarget targ && targ.Bomb == this) if ((user.Target as ThrowTarget)?.Bomb == this)
{ {
Target.Cancel(m); usersQueue.Enqueue(user);
} }
} }
_users.Clear(); _users.Clear();
_users = null;
while (usersQueue.Count > 0)
{
Target.Cancel(usersQueue.Dequeue());
}
} }
if (RootParent is Mobile parent) if (RootParent is Mobile parent)
@ -201,5 +201,7 @@ public partial class Firebomb : Item
public Firebomb Bomb { get; } public Firebomb Bomb { get; }
protected override void OnTarget(Mobile from, object targeted) => Bomb.OnFirebombTarget(from, targeted); protected override void OnTarget(Mobile from, object targeted) => Bomb.OnFirebombTarget(from, targeted);
protected override void OnTargetFinish(Mobile from) => Bomb._users.Remove(from);
} }
} }

View file

@ -57,6 +57,8 @@ public abstract partial class BasePotion : Item, ICraftable, ICommodity
public virtual bool RequireFreeHand => true; public virtual bool RequireFreeHand => true;
public virtual bool IsThrowablePotion => false;
int ICommodity.DescriptionNumber => LabelNumber; int ICommodity.DescriptionNumber => LabelNumber;
bool ICommodity.IsDeedable => Core.ML; bool ICommodity.IsDeedable => Core.ML;
@ -144,9 +146,11 @@ public abstract partial class BasePotion : Item, ICraftable, ICommodity
return; return;
} }
if (this is BaseExplosionPotion && Amount > 1) var pot = this;
if (IsThrowablePotion && Amount > 1)
{ {
var pot = GetType().CreateInstance<BaseExplosionPotion>(); pot = GetType().CreateInstance<BasePotion>();
Amount--; Amount--;
@ -158,13 +162,9 @@ public abstract partial class BasePotion : Item, ICraftable, ICommodity
{ {
pot.MoveToWorld(from.Location, from.Map); pot.MoveToWorld(from.Location, from.Map);
} }
}
pot.Drink(from); pot.Drink(from);
}
else
{
Drink(from);
}
} }
private void Deserialize(IGenericReader reader, int version) private void Deserialize(IGenericReader reader, int version)

View file

@ -10,8 +10,8 @@ namespace Server.Items;
[SerializationGenerator(0, false)] [SerializationGenerator(0, false)]
public abstract partial class BaseConflagrationPotion : BasePotion public abstract partial class BaseConflagrationPotion : BasePotion
{ {
private static readonly Dictionary<Mobile, TimerExecutionToken> m_Delay = new(); private static readonly Dictionary<Mobile, TimerExecutionToken> _delay = [];
private readonly List<Mobile> m_Users = new(); private HashSet<Mobile> _users;
public BaseConflagrationPotion(PotionEffect effect) : base(0xF06, effect) => Hue = 0x489; public BaseConflagrationPotion(PotionEffect effect) : base(0xF06, effect) => Hue = 0x489;
@ -20,6 +20,8 @@ public abstract partial class BaseConflagrationPotion : BasePotion
public override bool RequireFreeHand => false; public override bool RequireFreeHand => false;
public override bool IsThrowablePotion => true;
public override void Drink(Mobile from) public override void Drink(Mobile from)
{ {
if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true)) if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true))
@ -37,17 +39,15 @@ public abstract partial class BaseConflagrationPotion : BasePotion
return; return;
} }
if (from.Target is ThrowTarget targ && targ.Potion == this) if ((from.Target as ThrowTarget)?.Potion == this)
{ {
return; return;
} }
from.RevealingAction(); from.RevealingAction();
if (!m_Users.Contains(from)) _users ??= [];
{ _users.Add(from);
m_Users.Add(from);
}
from.Target = new ThrowTarget(this); from.Target = new ThrowTarget(this);
} }
@ -62,11 +62,22 @@ public abstract partial class BaseConflagrationPotion : BasePotion
Consume(); Consume();
// Check if any other players are using this potion // Check if any other players are using this potion
for (var i = 0; i < m_Users.Count; i++) if (_users is { Count: > 0 })
{ {
if (m_Users[i].Target is ThrowTarget targ && targ.Potion == this) using var usersQueue = PooledRefQueue<Mobile>.Create();
foreach (var user in _users)
{ {
Target.Cancel(from); if ((user.Target as ThrowTarget)?.Potion == this)
{
usersQueue.Enqueue(user);
}
}
_users.Clear();
while (usersQueue.Count > 0)
{
Target.Cancel(usersQueue.Dequeue());
} }
} }
@ -89,16 +100,16 @@ public abstract partial class BaseConflagrationPotion : BasePotion
public static void AddDelay(Mobile m) public static void AddDelay(Mobile m)
{ {
m_Delay.TryGetValue(m, out var timer); _delay.TryGetValue(m, out var timer);
timer.Cancel(); timer.Cancel();
Timer.StartTimer(TimeSpan.FromSeconds(30), () => EndDelay(m), out timer); Timer.StartTimer(TimeSpan.FromSeconds(30), () => EndDelay(m), out timer);
m_Delay[m] = timer; _delay[m] = timer;
} }
public static int GetDelay(Mobile m) public static int GetDelay(Mobile m)
{ {
if (m_Delay.TryGetValue(m, out var timer) && timer.Next > Core.Now) if (_delay.TryGetValue(m, out var timer) && timer.Next > Core.Now)
{ {
return (int)Math.Round((timer.Next - Core.Now).TotalSeconds); return (int)Math.Round((timer.Next - Core.Now).TotalSeconds);
} }
@ -108,7 +119,7 @@ public abstract partial class BaseConflagrationPotion : BasePotion
public static void EndDelay(Mobile m) public static void EndDelay(Mobile m)
{ {
if (m_Delay.Remove(m, out var timer)) if (_delay.Remove(m, out var timer))
{ {
timer.Cancel(); timer.Cancel();
} }
@ -155,6 +166,8 @@ public abstract partial class BaseConflagrationPotion : BasePotion
Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, Potion.Hue); Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, Potion.Hue);
Timer.StartTimer(TimeSpan.FromSeconds(1.5), () => Potion.Explode(from, loc, map)); Timer.StartTimer(TimeSpan.FromSeconds(1.5), () => Potion.Explode(from, loc, map));
} }
protected override void OnTargetFinish(Mobile from) => Potion._users.Remove(from);
} }
[SerializationGenerator(0, false)] [SerializationGenerator(0, false)]

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ModernUO.Serialization; using ModernUO.Serialization;
using Server.Collections;
using Server.Misc; using Server.Misc;
using Server.Mobiles; using Server.Mobiles;
using Server.Spells; using Server.Spells;
@ -20,6 +21,8 @@ public abstract partial class BaseConfusionBlastPotion : BasePotion
public override bool RequireFreeHand => false; public override bool RequireFreeHand => false;
public override bool IsThrowablePotion => true;
public override void Drink(Mobile from) public override void Drink(Mobile from)
{ {
if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true)) if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true))
@ -37,14 +40,14 @@ public abstract partial class BaseConfusionBlastPotion : BasePotion
return; return;
} }
if (from.Target is ThrowTarget targ && targ.Potion == this) if ((from.Target as ThrowTarget)?.Potion == this)
{ {
return; return;
} }
from.RevealingAction(); from.RevealingAction();
_users ??= new HashSet<Mobile>(); _users ??= [];
_users.Add(from); _users.Add(from);
from.Target = new ThrowTarget(this); from.Target = new ThrowTarget(this);
@ -59,18 +62,23 @@ public abstract partial class BaseConfusionBlastPotion : BasePotion
Consume(); Consume();
if (_users != null) if (_users is { Count: > 0 })
{ {
// Check if any other players are using this potion using var usersQueue = PooledRefQueue<Mobile>.Create();
foreach (var user in _users) foreach (var user in _users)
{ {
if ((user.Target as ThrowTarget)?.Potion == this) if ((user.Target as ThrowTarget)?.Potion == this)
{ {
Target.Cancel(from); usersQueue.Enqueue(user);
} }
} }
_users.Clear(); _users.Clear();
while (usersQueue.Count > 0)
{
Target.Cancel(usersQueue.Dequeue());
}
} }
// Effects // Effects
@ -170,5 +178,7 @@ public abstract partial class BaseConfusionBlastPotion : BasePotion
Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, Potion.Hue); Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, Potion.Hue);
Timer.StartTimer(TimeSpan.FromSeconds(1.0), () => Potion.Explode(from, loc, map)); Timer.StartTimer(TimeSpan.FromSeconds(1.0), () => Potion.Explode(from, loc, map));
} }
protected override void OnTargetFinish(Mobile from) => Potion._users.Remove(from);
} }
} }

View file

@ -27,6 +27,8 @@ public abstract partial class BaseExplosionPotion : BasePotion
public override bool RequireFreeHand => false; public override bool RequireFreeHand => false;
public override bool IsThrowablePotion => true;
private HashSet<Mobile> _users; private HashSet<Mobile> _users;
public virtual IEntity FindParent(Mobile from) public virtual IEntity FindParent(Mobile from)
@ -67,7 +69,7 @@ public abstract partial class BaseExplosionPotion : BasePotion
from.RevealingAction(); from.RevealingAction();
_users ??= new HashSet<Mobile>(); _users ??= [];
_users.Add(from); _users.Add(from);
from.Target = new ThrowTarget(this); from.Target = new ThrowTarget(this);
@ -115,17 +117,23 @@ public abstract partial class BaseExplosionPotion : BasePotion
Consume(); Consume();
if (_users != null) if (_users is { Count: > 0 })
{ {
using var usersQueue = PooledRefQueue<Mobile>.Create();
foreach (var user in _users) foreach (var user in _users)
{ {
if ((user.Target as ThrowTarget)?.Potion == this) if ((user.Target as ThrowTarget)?.Potion == this)
{ {
Target.Cancel(user); usersQueue.Enqueue(user);
} }
} }
_users.Clear(); _users.Clear();
while (usersQueue.Count > 0)
{
Target.Cancel(usersQueue.Dequeue());
}
} }
if (map == null) if (map == null)
@ -259,6 +267,8 @@ public abstract partial class BaseExplosionPotion : BasePotion
Timer.StartTimer(delay, () => Potion.Reposition_OnTick(from, loc, map)); Timer.StartTimer(delay, () => Potion.Reposition_OnTick(from, loc, map));
} }
protected override void OnTargetFinish(Mobile from) => Potion._users.Remove(from);
} }
private class DetonateTimer : Timer private class DetonateTimer : Timer