ModernUO/Projects/UOContent/Items/Skill Items/Magical/Potions/BasePotion.cs
Kamron Batman 38731d98b6
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.
2024-07-06 16:39:47 -07:00

244 lines
5.5 KiB
C#

using System;
using ModernUO.Serialization;
using Server.Engines.ConPVP;
using Server.Engines.Craft;
namespace Server.Items;
public enum PotionEffect
{
Nightsight,
CureLesser,
Cure,
CureGreater,
Agility,
AgilityGreater,
Strength,
StrengthGreater,
PoisonLesser,
Poison,
PoisonGreater,
PoisonDeadly,
Refresh,
RefreshTotal,
HealLesser,
Heal,
HealGreater,
ExplosionLesser,
Explosion,
ExplosionGreater,
Conflagration,
ConflagrationGreater,
MaskOfDeath, // Mask of Death is not available in OSI but does exist in cliloc files
MaskOfDeathGreater, // included in enumeration for compatibility if later enabled by OSI
ConfusionBlast,
ConfusionBlastGreater,
Invisibility,
Parasitic,
Darkglow
}
[SerializationGenerator(2, false)]
public abstract partial class BasePotion : Item, ICraftable, ICommodity
{
[InvalidateProperties]
[SerializableField(0)]
private PotionEffect _potionEffect;
public BasePotion(int itemID, PotionEffect effect) : base(itemID)
{
_potionEffect = effect;
Stackable = Core.ML;
Weight = 1.0;
}
public override int LabelNumber => 1041314 + (int)_potionEffect;
public virtual bool RequireFreeHand => true;
public virtual bool IsThrowablePotion => false;
int ICommodity.DescriptionNumber => LabelNumber;
bool ICommodity.IsDeedable => Core.ML;
public int OnCraft(
int quality,
bool makersMark,
Mobile from,
CraftSystem craftSystem,
Type typeRes,
BaseTool tool,
CraftItem craftItem,
int resHue
)
{
if (craftSystem is DefAlchemy)
{
var pack = from.Backpack;
if (pack != null)
{
if ((int)PotionEffect >= (int)PotionEffect.Invisibility)
{
return 1;
}
foreach (var keg in pack.EnumerateItemsByType<PotionKeg>())
{
if (keg.Held is <= 0 or >= 100)
{
continue;
}
if (keg.Type != PotionEffect)
{
continue;
}
++keg.Held;
Consume();
from.AddToBackpack(new Bottle());
return -1; // signal placed in keg
}
}
}
return 1;
}
public static bool HasFreeHand(Mobile m)
{
var handOne = m.FindItemOnLayer(Layer.OneHanded);
var handTwo = m.FindItemOnLayer(Layer.TwoHanded);
if (handTwo is BaseWeapon)
{
handOne = handTwo;
}
if (handTwo is BaseRanged ranged && ranged.Balanced)
{
return true;
}
return handOne == null || handTwo == null;
}
public override void OnDoubleClick(Mobile from)
{
if (!CanDrink(from))
{
return;
}
var pot = this;
if (IsThrowablePotion && Amount > 1)
{
pot = GetType().CreateInstance<BasePotion>();
Amount--;
if (from.Backpack?.Deleted == false)
{
from.Backpack.DropItem(pot);
}
else
{
pot.MoveToWorld(from.Location, from.Map);
}
}
pot.Drink(from);
}
private void Deserialize(IGenericReader reader, int version)
{
_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))
{
Consume();
m.AddToBackpack(new Bottle());
}
if (m.Body.IsHuman && !m.Mounted)
{
m.Animate(34, 5, 1, true, false, 0);
}
}
public static int EnhancePotions(Mobile m)
{
var EP = AosAttributes.GetValue(m, AosAttribute.EnhancePotions);
var skillBonus = (int)(m.Skills.Alchemy.Value * 10 / 33);
if (Core.ML && EP > 50 && m.AccessLevel <= AccessLevel.Player)
{
EP = 50;
}
return EP + skillBonus;
}
public static TimeSpan Scale(Mobile m, TimeSpan v)
{
if (!Core.AOS)
{
return v;
}
return v * (1.0 + 0.01 * EnhancePotions(m));
}
public static double Scale(Mobile m, double v)
{
if (!Core.AOS)
{
return v;
}
var scalar = 1.0 + 0.01 * EnhancePotions(m);
return v * scalar;
}
public static int Scale(Mobile m, int v) => !Core.AOS ? v : AOS.Scale(v, 100 + EnhancePotions(m));
public override bool StackWith(Mobile from, Item dropped, bool playSound) =>
dropped is BasePotion potion && potion._potionEffect == _potionEffect &&
base.StackWith(from, potion, playSound);
}