fix: Fixes splitting potions before error (#1862)
### Summary Most potions have various checks, such as a cooldown. This fixes an edge case where potions get split from their stack before erroring.
This commit is contained in:
parent
e6bfc45228
commit
38731d98b6
12 changed files with 169 additions and 99 deletions
|
|
@ -22,13 +22,7 @@ public partial class MelisandesFermentedWine : GreaterExplosionPotion
|
|||
|
||||
public override int LabelNumber => 1072114; // Melisande's Fermented Wine
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
if (MondainsLegacy.CheckML(from))
|
||||
{
|
||||
base.Drink(from);
|
||||
}
|
||||
}
|
||||
public override bool CanDrink(Mobile from) => MondainsLegacy.CheckML(from) && base.CanDrink(from);
|
||||
|
||||
public override void GetProperties(IPropertyList list)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,25 +14,27 @@ public abstract partial class BaseAgilityPotion : BasePotion
|
|||
public abstract int DexOffset { get; }
|
||||
public abstract TimeSpan Duration { get; }
|
||||
|
||||
public bool DoAgility(Mobile from)
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
// TODO: Verify scaled; is it offset, duration, or both?
|
||||
if (SpellHelper.AddStatOffset(from, StatType.Dex, Scale(from, DexOffset), Duration))
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
from.FixedEffect(0x375A, 10, 15);
|
||||
from.PlaySound(0x1E7);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage(502173); // You are already under a similar effect.
|
||||
return false;
|
||||
// TODO: Verify scaled; is it offset, duration, or both?
|
||||
if (!SpellHelper.AddStatOffset(from, StatType.Dex, Scale(from, DexOffset), Duration))
|
||||
{
|
||||
from.SendLocalizedMessage(502173); // You are already under a similar effect.
|
||||
return false;
|
||||
}
|
||||
|
||||
from.FixedEffect(0x375A, 10, 15);
|
||||
from.PlaySound(0x1E7);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
if (DoAgility(from))
|
||||
{
|
||||
PlayDrinkEffect(from);
|
||||
}
|
||||
PlayDrinkEffect(from);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,23 +129,11 @@ public abstract partial class BasePotion : Item, ICraftable, ICommodity
|
|||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!Movable)
|
||||
if (!CanDrink(from))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!from.InRange(GetWorldLocation(), 1))
|
||||
{
|
||||
from.SendLocalizedMessage(502138); // That is too far away for you to use
|
||||
return;
|
||||
}
|
||||
|
||||
if (RequireFreeHand && !HasFreeHand(from))
|
||||
{
|
||||
from.SendLocalizedMessage(502172); // You must have a free hand to drink a potion.
|
||||
return;
|
||||
}
|
||||
|
||||
var pot = this;
|
||||
|
||||
if (IsThrowablePotion && Amount > 1)
|
||||
|
|
@ -172,12 +160,33 @@ public abstract partial class BasePotion : Item, ICraftable, ICommodity
|
|||
_potionEffect = (PotionEffect)reader.ReadInt();
|
||||
}
|
||||
|
||||
public virtual bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!Movable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.InRange(GetWorldLocation(), 1))
|
||||
{
|
||||
from.SendLocalizedMessage(502138); // That is too far away for you to use
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RequireFreeHand && !HasFreeHand(from))
|
||||
{
|
||||
from.SendLocalizedMessage(502172); // You must have a free hand to drink a potion.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void Drink(Mobile from);
|
||||
|
||||
public void PlayDrinkEffect(Mobile m)
|
||||
{
|
||||
m.RevealingAction();
|
||||
|
||||
m.PlaySound(0x2D6);
|
||||
|
||||
if (!DuelContext.IsFreeConsume(m))
|
||||
|
|
|
|||
|
|
@ -22,12 +22,17 @@ public abstract partial class BaseConflagrationPotion : BasePotion
|
|||
|
||||
public override bool IsThrowablePotion => true;
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true))
|
||||
{
|
||||
from.SendLocalizedMessage(1062725); // You can not use that potion while paralyzed.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
var delay = GetDelay(from);
|
||||
|
|
@ -36,14 +41,14 @@ public abstract partial class BaseConflagrationPotion : BasePotion
|
|||
{
|
||||
// You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~
|
||||
from.SendLocalizedMessage(1072529, $"{delay}\t{(delay > 1 ? "seconds." : "second.")}");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((from.Target as ThrowTarget)?.Potion == this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return (from.Target as ThrowTarget)?.Potion != this;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
from.RevealingAction();
|
||||
|
||||
_users ??= [];
|
||||
|
|
|
|||
|
|
@ -23,12 +23,17 @@ public abstract partial class BaseConfusionBlastPotion : BasePotion
|
|||
|
||||
public override bool IsThrowablePotion => true;
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true))
|
||||
{
|
||||
from.SendLocalizedMessage(1062725); // You can not use that potion while paralyzed.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
var delay = GetDelay(from);
|
||||
|
|
@ -37,14 +42,14 @@ public abstract partial class BaseConfusionBlastPotion : BasePotion
|
|||
{
|
||||
// You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~
|
||||
from.SendLocalizedMessage(1072529, $"{delay}\t{(delay > 1 ? "seconds." : "second.")}");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((from.Target as ThrowTarget)?.Potion == this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return (from.Target as ThrowTarget)?.Potion != this;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
from.RevealingAction();
|
||||
|
||||
_users ??= [];
|
||||
|
|
|
|||
|
|
@ -56,24 +56,35 @@ public abstract partial class BaseCurePotion : BasePotion
|
|||
}
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TransformationSpellHelper.UnderTransformation(from, typeof(VampiricEmbraceSpell)))
|
||||
{
|
||||
from.SendLocalizedMessage(1061652); // The garlic in the potion would surely kill you.
|
||||
return false;
|
||||
}
|
||||
else if (from.Poisoned)
|
||||
{
|
||||
DoCure(from);
|
||||
|
||||
PlayDrinkEffect(from);
|
||||
|
||||
from.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist);
|
||||
from.PlaySound(0x1E0);
|
||||
}
|
||||
else
|
||||
if (!from.Poisoned)
|
||||
{
|
||||
from.SendLocalizedMessage(1042000); // You are not poisoned.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
DoCure(from);
|
||||
|
||||
PlayDrinkEffect(from);
|
||||
|
||||
from.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist);
|
||||
from.PlaySound(0x1E0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,22 +51,26 @@ public abstract partial class BaseExplosionPotion : BasePotion
|
|||
return this;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true))
|
||||
{
|
||||
from.SendLocalizedMessage(1062725); // You can not use a purple potion while paralyzed.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
var targ = from.Target as ThrowTarget;
|
||||
return (from.Target as ThrowTarget)?.Potion != this;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
Stackable = false; // Scavenged explosion potions won't stack with those ones in backpack, and still will explode.
|
||||
|
||||
if (targ?.Potion == this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
from.RevealingAction();
|
||||
|
||||
_users ??= [];
|
||||
|
|
|
|||
|
|
@ -22,29 +22,39 @@ public abstract partial class BaseHealPotion : BasePotion
|
|||
from.Heal(Utility.RandomMinMax(min, max));
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from.Hits >= from.HitsMax)
|
||||
{
|
||||
// You decide against drinking this potion, as you are already at full health.
|
||||
from.SendLocalizedMessage(1049547);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from.Poisoned || MortalStrike.IsWounded(from))
|
||||
{
|
||||
// You can not heal yourself in your current state.
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x22, 1005000);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.BeginAction<BaseHealPotion>())
|
||||
{
|
||||
// You must wait 10 seconds before using another healing potion.
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x22, 500235);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
DoHeal(from);
|
||||
|
||||
PlayDrinkEffect(from);
|
||||
|
|
|
|||
|
|
@ -7,29 +7,39 @@ namespace Server.Items;
|
|||
[SerializationGenerator(0, false)]
|
||||
public partial class InvisibilityPotion : BasePotion
|
||||
{
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> m_Table = new();
|
||||
private static readonly Dictionary<Mobile, TimerExecutionToken> _table = new();
|
||||
|
||||
[Constructible]
|
||||
public InvisibilityPotion() : base(0xF0A, PotionEffect.Invisibility) => Hue = 0x48D;
|
||||
|
||||
public override int LabelNumber => 1072941; // Potion of Invisibility
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from.Hidden)
|
||||
{
|
||||
from.SendLocalizedMessage(1073185); // You are already unseen.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasTimer(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1073186); // An invisibility potion is already taking effect on your person.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(2), () => Hide(from), out var timerToken);
|
||||
m_Table[from] = timerToken;
|
||||
_table[from] = timerToken;
|
||||
PlayDrinkEffect(from);
|
||||
}
|
||||
|
||||
|
|
@ -61,11 +71,11 @@ public partial class InvisibilityPotion : BasePotion
|
|||
RemoveTimer(m);
|
||||
}
|
||||
|
||||
public static bool HasTimer(Mobile m) => m_Table.ContainsKey(m);
|
||||
public static bool HasTimer(Mobile m) => _table.ContainsKey(m);
|
||||
|
||||
public static void RemoveTimer(Mobile m, bool interrupted = false)
|
||||
{
|
||||
if (m_Table.Remove(m, out var timer))
|
||||
if (_table.Remove(m, out var timer))
|
||||
{
|
||||
if (interrupted)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,21 +10,30 @@ public partial class NightSightPotion : BasePotion
|
|||
{
|
||||
}
|
||||
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!from.BeginAction<LightCycle>())
|
||||
{
|
||||
from.SendMessage("You already have night sight.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
if (from.BeginAction<LightCycle>())
|
||||
{
|
||||
new LightCycle.NightSightTimer(from).Start();
|
||||
from.LightLevel = LightCycle.DungeonLevel / 2;
|
||||
new LightCycle.NightSightTimer(from).Start();
|
||||
from.LightLevel = LightCycle.DungeonLevel / 2;
|
||||
|
||||
from.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist);
|
||||
from.PlaySound(0x1E3);
|
||||
from.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist);
|
||||
from.PlaySound(0x1E3);
|
||||
|
||||
PlayDrinkEffect(from);
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("You already have nightsight.");
|
||||
}
|
||||
PlayDrinkEffect(from);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,17 +11,26 @@ public abstract partial class BaseRefreshPotion : BasePotion
|
|||
|
||||
public abstract double Refresh { get; }
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
public override bool CanDrink(Mobile from)
|
||||
{
|
||||
if (from.Stam < from.StamMax)
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
from.Stam += Scale(from, (int)(Refresh * from.StamMax));
|
||||
|
||||
PlayDrinkEffect(from);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
if (from.Stam >= from.StamMax)
|
||||
{
|
||||
from.SendMessage("You decide against drinking this potion, as you are already at full stamina.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
from.Stam += Scale(from, (int)(Refresh * from.StamMax));
|
||||
|
||||
PlayDrinkEffect(from);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,13 @@ public abstract partial class BaseStrengthPotion : BasePotion
|
|||
public abstract int StrOffset { get; }
|
||||
public abstract TimeSpan Duration { get; }
|
||||
|
||||
public bool DoStrength(Mobile from)
|
||||
public bool CanDrink(Mobile from)
|
||||
{
|
||||
if (!base.CanDrink(from))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Verify scaled; is it offset, duration, or both?
|
||||
if (SpellHelper.AddStatOffset(from, StatType.Str, Scale(from, StrOffset), Duration))
|
||||
{
|
||||
|
|
@ -30,9 +35,6 @@ public abstract partial class BaseStrengthPotion : BasePotion
|
|||
|
||||
public override void Drink(Mobile from)
|
||||
{
|
||||
if (DoStrength(from))
|
||||
{
|
||||
PlayDrinkEffect(from);
|
||||
}
|
||||
PlayDrinkEffect(from);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue