fix: Codegens more misc items (#1214)
This commit is contained in:
parent
505865e3ed
commit
212ce8bc24
81 changed files with 2641 additions and 3498 deletions
|
|
@ -100,10 +100,12 @@ namespace Server.Commands
|
|||
return;
|
||||
}
|
||||
|
||||
var item = new EffectController();
|
||||
item.SoundID = sound;
|
||||
item.TriggerType = EffectTriggerType.InRange;
|
||||
item.TriggerRange = range;
|
||||
var item = new EffectController
|
||||
{
|
||||
SoundId = sound,
|
||||
TriggerType = EffectTriggerType.InRange,
|
||||
TriggerRange = range
|
||||
};
|
||||
|
||||
item.MoveToWorld(new Point3D(x, y, z), Map.Felucca);
|
||||
m_Count++;
|
||||
|
|
|
|||
|
|
@ -1,232 +1,206 @@
|
|||
using System;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class ArcaneGem : Item
|
||||
{
|
||||
public class ArcaneGem : Item
|
||||
public const int DefaultArcaneHue = 2117;
|
||||
|
||||
[Constructible]
|
||||
public ArcaneGem() : base(0x1EA7)
|
||||
{
|
||||
public const int DefaultArcaneHue = 2117;
|
||||
Stackable = Core.ML;
|
||||
Weight = 1.0;
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public ArcaneGem() : base(0x1EA7)
|
||||
public override string DefaultName => "arcane gem";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
Stackable = Core.ML;
|
||||
Weight = 1.0;
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
}
|
||||
else
|
||||
{
|
||||
from.BeginTarget(2, false, TargetFlags.None, OnTarget);
|
||||
from.SendMessage("What do you wish to use the gem on?");
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetChargesFor(Mobile m) => Math.Clamp((int)(m.Skills.Tailoring.Value / 5), 16, 24);
|
||||
|
||||
public void OnTarget(Mobile from, object obj)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
return;
|
||||
}
|
||||
|
||||
public ArcaneGem(Serial serial) : base(serial)
|
||||
if (obj is IArcaneEquip eq and Item item)
|
||||
{
|
||||
}
|
||||
var clothing = item as BaseClothing;
|
||||
var armor = item as BaseArmor;
|
||||
var weapon = item as BaseWeapon;
|
||||
|
||||
public override string DefaultName => "arcane gem";
|
||||
var resource = clothing?.Resource ?? armor?.Resource ?? weapon?.Resource ?? CraftResource.None;
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
}
|
||||
else
|
||||
{
|
||||
from.BeginTarget(2, false, TargetFlags.None, OnTarget);
|
||||
from.SendMessage("What do you wish to use the gem on?");
|
||||
}
|
||||
}
|
||||
|
||||
public int GetChargesFor(Mobile m)
|
||||
{
|
||||
var v = (int)(m.Skills.Tailoring.Value / 5);
|
||||
|
||||
return v switch
|
||||
{
|
||||
< 16 => 16,
|
||||
> 24 => 24,
|
||||
_ => v
|
||||
};
|
||||
}
|
||||
|
||||
public void OnTarget(Mobile from, object obj)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
if (!item.IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is IArcaneEquip eq && eq is Item item)
|
||||
{
|
||||
var clothing = item as BaseClothing;
|
||||
var armor = item as BaseArmor;
|
||||
var weapon = item as BaseWeapon;
|
||||
|
||||
var resource = clothing?.Resource ?? armor?.Resource ?? weapon?.Resource ?? CraftResource.None;
|
||||
|
||||
if (!item.IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.LootType == LootType.Blessed)
|
||||
{
|
||||
from.SendMessage(
|
||||
"You can only use this on exceptionally crafted robes, thigh boots, cloaks, or leather gloves."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resource != CraftResource.None && resource != CraftResource.RegularLeather)
|
||||
{
|
||||
from.SendLocalizedMessage(1049690); // Arcane gems can not be used on that type of leather.
|
||||
return;
|
||||
}
|
||||
|
||||
var charges = GetChargesFor(from);
|
||||
|
||||
if (eq.IsArcane)
|
||||
{
|
||||
if (eq.CurArcaneCharges >= eq.MaxArcaneCharges)
|
||||
{
|
||||
from.SendMessage("That item is already fully charged.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (eq.CurArcaneCharges <= 0)
|
||||
{
|
||||
item.Hue = DefaultArcaneHue;
|
||||
}
|
||||
|
||||
if (eq.CurArcaneCharges + charges > eq.MaxArcaneCharges)
|
||||
{
|
||||
eq.CurArcaneCharges = eq.MaxArcaneCharges;
|
||||
}
|
||||
else
|
||||
{
|
||||
eq.CurArcaneCharges += charges;
|
||||
}
|
||||
|
||||
from.SendMessage("You recharge the item.");
|
||||
if (Amount <= 1)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
Amount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (from.Skills.Tailoring.Value >= 80.0)
|
||||
{
|
||||
var isExceptional = clothing?.Quality == ClothingQuality.Exceptional ||
|
||||
armor?.Quality == ArmorQuality.Exceptional ||
|
||||
weapon?.Quality == WeaponQuality.Exceptional;
|
||||
|
||||
if (isExceptional)
|
||||
{
|
||||
if (clothing != null)
|
||||
{
|
||||
clothing.Quality = ClothingQuality.Regular;
|
||||
clothing.Crafter = from.RawName;
|
||||
}
|
||||
else if (armor != null)
|
||||
{
|
||||
armor.Quality = ArmorQuality.Regular;
|
||||
armor.Crafter = from.RawName;
|
||||
armor.PhysicalBonus =
|
||||
armor.FireBonus =
|
||||
armor.ColdBonus =
|
||||
armor.PoisonBonus = armor.EnergyBonus = 0; // Is there a method to remove bonuses?
|
||||
}
|
||||
else
|
||||
{
|
||||
weapon.Quality = WeaponQuality.Regular;
|
||||
weapon.Crafter = from;
|
||||
}
|
||||
|
||||
eq.CurArcaneCharges = eq.MaxArcaneCharges = charges;
|
||||
|
||||
item.Hue = DefaultArcaneHue;
|
||||
|
||||
from.SendMessage("You enhance the item with your gem.");
|
||||
if (Amount <= 1)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
Amount--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("Only exceptional items can be enhanced with the gem.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("You do not have enough skill in tailoring to enhance the item.");
|
||||
}
|
||||
}
|
||||
else
|
||||
if (item.LootType == LootType.Blessed)
|
||||
{
|
||||
from.SendMessage(
|
||||
"You can only use this on exceptionally crafted robes, thigh boots, cloaks, or leather gloves."
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ConsumeCharges(Mobile from, int amount)
|
||||
{
|
||||
var items = from.Items;
|
||||
var avail = 0;
|
||||
|
||||
for (var i = 0; i < items.Count; ++i)
|
||||
if (resource != CraftResource.None && resource != CraftResource.RegularLeather)
|
||||
{
|
||||
var obj = items[i];
|
||||
from.SendLocalizedMessage(1049690); // Arcane gems can not be used on that type of leather.
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is IArcaneEquip eq && eq.IsArcane)
|
||||
var charges = GetChargesFor(from);
|
||||
|
||||
if (eq.IsArcane)
|
||||
{
|
||||
if (eq.CurArcaneCharges >= eq.MaxArcaneCharges)
|
||||
{
|
||||
avail += eq.CurArcaneCharges;
|
||||
from.SendMessage("That item is already fully charged.");
|
||||
}
|
||||
}
|
||||
|
||||
if (avail < amount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < items.Count; ++i)
|
||||
{
|
||||
var obj = items[i];
|
||||
|
||||
if (obj is IArcaneEquip eq && eq.IsArcane)
|
||||
else
|
||||
{
|
||||
if (eq.CurArcaneCharges > amount)
|
||||
if (eq.CurArcaneCharges <= 0)
|
||||
{
|
||||
eq.CurArcaneCharges -= amount;
|
||||
break;
|
||||
item.Hue = DefaultArcaneHue;
|
||||
}
|
||||
|
||||
amount -= eq.CurArcaneCharges;
|
||||
eq.CurArcaneCharges = 0;
|
||||
if (eq.CurArcaneCharges + charges > eq.MaxArcaneCharges)
|
||||
{
|
||||
eq.CurArcaneCharges = eq.MaxArcaneCharges;
|
||||
}
|
||||
else
|
||||
{
|
||||
eq.CurArcaneCharges += charges;
|
||||
}
|
||||
|
||||
from.SendMessage("You recharge the item.");
|
||||
if (Amount <= 1)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
Amount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (from.Skills.Tailoring.Value >= 80.0)
|
||||
{
|
||||
var isExceptional = clothing?.Quality == ClothingQuality.Exceptional ||
|
||||
armor?.Quality == ArmorQuality.Exceptional ||
|
||||
weapon?.Quality == WeaponQuality.Exceptional;
|
||||
|
||||
return true;
|
||||
if (isExceptional)
|
||||
{
|
||||
if (clothing != null)
|
||||
{
|
||||
clothing.Quality = ClothingQuality.Regular;
|
||||
clothing.Crafter = from.RawName;
|
||||
}
|
||||
else if (armor != null)
|
||||
{
|
||||
armor.Quality = ArmorQuality.Regular;
|
||||
armor.Crafter = from.RawName;
|
||||
armor.PhysicalBonus =
|
||||
armor.FireBonus =
|
||||
armor.ColdBonus =
|
||||
armor.PoisonBonus = armor.EnergyBonus = 0; // Is there a method to remove bonuses?
|
||||
}
|
||||
else
|
||||
{
|
||||
weapon.Quality = WeaponQuality.Regular;
|
||||
weapon.Crafter = from;
|
||||
}
|
||||
|
||||
eq.CurArcaneCharges = eq.MaxArcaneCharges = charges;
|
||||
|
||||
item.Hue = DefaultArcaneHue;
|
||||
|
||||
from.SendMessage("You enhance the item with your gem.");
|
||||
if (Amount <= 1)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
Amount--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("Only exceptional items can be enhanced with the gem.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("You do not have enough skill in tailoring to enhance the item.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
else
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
from.SendMessage(
|
||||
"You can only use this on exceptionally crafted robes, thigh boots, cloaks, or leather gloves."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ConsumeCharges(Mobile from, int amount)
|
||||
{
|
||||
var items = from.Items;
|
||||
var avail = 0;
|
||||
|
||||
for (var i = 0; i < items.Count; ++i)
|
||||
{
|
||||
var obj = items[i];
|
||||
|
||||
if (obj is IArcaneEquip eq && eq.IsArcane)
|
||||
{
|
||||
avail += eq.CurArcaneCharges;
|
||||
}
|
||||
}
|
||||
|
||||
if (avail < amount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < items.Count; ++i)
|
||||
{
|
||||
var obj = items[i];
|
||||
|
||||
if (obj is IArcaneEquip eq && eq.IsArcane)
|
||||
{
|
||||
if (eq.CurArcaneCharges > amount)
|
||||
{
|
||||
eq.CurArcaneCharges -= amount;
|
||||
break;
|
||||
}
|
||||
|
||||
amount -= eq.CurArcaneCharges;
|
||||
eq.CurArcaneCharges = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Accounting;
|
||||
using Server.Engines.Quests;
|
||||
using Server.Engines.Quests.Haven;
|
||||
|
|
@ -7,234 +8,196 @@ using Server.Mobiles;
|
|||
using Server.Network;
|
||||
using CashBankCheckObjective = Server.Engines.Quests.Necro.CashBankCheckObjective;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class BankCheck : Item
|
||||
{
|
||||
public class BankCheck : Item
|
||||
[InvalidateProperties]
|
||||
[SerializableField(0)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _worth;
|
||||
|
||||
[Constructible]
|
||||
public BankCheck(int worth) : base(0x14F0)
|
||||
{
|
||||
private int m_Worth;
|
||||
Weight = 1.0;
|
||||
Hue = 0x34;
|
||||
LootType = LootType.Blessed;
|
||||
|
||||
public BankCheck(Serial serial) : base(serial)
|
||||
_worth = worth;
|
||||
}
|
||||
|
||||
public override bool DisplayLootType => Core.AOS;
|
||||
|
||||
public override int LabelNumber => 1041361; // A bank check
|
||||
|
||||
public override void GetProperties(IPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
if (Core.ML)
|
||||
{
|
||||
list.Add(1060738, $"{_worth:N0}"); // value: ~1_val~
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(1060738, _worth); // value: ~1_val~
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAdded(IEntity parent)
|
||||
{
|
||||
base.OnAdded(parent);
|
||||
|
||||
if (!AccountGold.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public BankCheck(int worth) : base(0x14F0)
|
||||
{
|
||||
Weight = 1.0;
|
||||
Hue = 0x34;
|
||||
LootType = LootType.Blessed;
|
||||
Mobile owner = null;
|
||||
SecureTradeInfo tradeInfo = null;
|
||||
|
||||
m_Worth = worth;
|
||||
var root = parent as Container;
|
||||
|
||||
while (root?.Parent is Container container)
|
||||
{
|
||||
root = container;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Worth
|
||||
parent = root ?? parent;
|
||||
|
||||
if (parent is SecureTradeContainer trade && AccountGold.ConvertOnTrade)
|
||||
{
|
||||
get => m_Worth;
|
||||
set
|
||||
if (trade.Trade.From.Container == trade)
|
||||
{
|
||||
m_Worth = value;
|
||||
InvalidateProperties();
|
||||
tradeInfo = trade.Trade.From;
|
||||
owner = tradeInfo.Mobile;
|
||||
}
|
||||
else if (trade.Trade.To.Container == trade)
|
||||
{
|
||||
tradeInfo = trade.Trade.To;
|
||||
owner = tradeInfo.Mobile;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool DisplayLootType => Core.AOS;
|
||||
|
||||
public override int LabelNumber => 1041361; // A bank check
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
else if (parent is BankBox box && AccountGold.ConvertOnBank)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Worth);
|
||||
owner = box.Owner;
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
if (owner?.Account?.DepositGold(_worth) != true)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
LootType = LootType.Blessed;
|
||||
return;
|
||||
}
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
if (tradeInfo != null)
|
||||
{
|
||||
if (owner.NetState?.NewSecureTrading == false)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Worth = reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
var plat = Math.DivRem(_worth, AccountGold.CurrencyThreshold, out var gold);
|
||||
|
||||
tradeInfo.Plat += plat;
|
||||
tradeInfo.Gold += gold;
|
||||
}
|
||||
|
||||
tradeInfo.VirtualCheck?.UpdateTrade(tradeInfo.Mobile);
|
||||
}
|
||||
|
||||
public override void GetProperties(IPropertyList list)
|
||||
owner.SendLocalizedMessage(1042763, $"{_worth:N0}");
|
||||
|
||||
Delete();
|
||||
|
||||
((Container)parent).UpdateTotals();
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
from.NetState.SendMessageLocalizedAffix(
|
||||
Serial,
|
||||
ItemID,
|
||||
MessageType.Label,
|
||||
0x3B2,
|
||||
3,
|
||||
1041361, // A bank check:
|
||||
"",
|
||||
AffixType.Append,
|
||||
$" {_worth}"
|
||||
);
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
// This probably isn't OSI accurate, but we can't just make the quests redundant.
|
||||
// Double-clicking the BankCheck in your pack will now credit your account.
|
||||
var box = AccountGold.Enabled ? from.Backpack : from.FindBankNoCreate();
|
||||
|
||||
if (box == null || !IsChildOf(box))
|
||||
{
|
||||
base.GetProperties(list);
|
||||
if (Core.ML)
|
||||
from.SendLocalizedMessage(AccountGold.Enabled ? 1080058 : 1047026);
|
||||
// This must be in your backpack to use it. : That must be in your bank box to use it.
|
||||
return;
|
||||
}
|
||||
|
||||
var deposited = 0;
|
||||
var toAdd = _worth;
|
||||
|
||||
if (AccountGold.Enabled && from.Account?.DepositGold(toAdd) == true)
|
||||
{
|
||||
deposited = toAdd;
|
||||
}
|
||||
|
||||
while (toAdd > 0)
|
||||
{
|
||||
var amount = Math.Min(toAdd, 60000);
|
||||
|
||||
var gold = new Gold(amount);
|
||||
|
||||
if (box.TryDropItem(from, gold, false))
|
||||
{
|
||||
list.Add(1060738, $"{m_Worth:N0}"); // value: ~1_val~
|
||||
toAdd -= amount;
|
||||
deposited += amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(1060738, m_Worth); // value: ~1_val~
|
||||
gold.Delete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAdded(IEntity parent)
|
||||
if (deposited >= _worth)
|
||||
{
|
||||
base.OnAdded(parent);
|
||||
|
||||
if (!AccountGold.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mobile owner = null;
|
||||
SecureTradeInfo tradeInfo = null;
|
||||
|
||||
var root = parent as Container;
|
||||
|
||||
while (root?.Parent is Container container)
|
||||
{
|
||||
root = container;
|
||||
}
|
||||
|
||||
parent = root ?? parent;
|
||||
|
||||
if (parent is SecureTradeContainer trade && AccountGold.ConvertOnTrade)
|
||||
{
|
||||
if (trade.Trade.From.Container == trade)
|
||||
{
|
||||
tradeInfo = trade.Trade.From;
|
||||
owner = tradeInfo.Mobile;
|
||||
}
|
||||
else if (trade.Trade.To.Container == trade)
|
||||
{
|
||||
tradeInfo = trade.Trade.To;
|
||||
owner = tradeInfo.Mobile;
|
||||
}
|
||||
}
|
||||
else if (parent is BankBox box && AccountGold.ConvertOnBank)
|
||||
{
|
||||
owner = box.Owner;
|
||||
}
|
||||
|
||||
if (owner?.Account?.DepositGold(Worth) != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (tradeInfo != null)
|
||||
{
|
||||
if (owner.NetState?.NewSecureTrading == false)
|
||||
{
|
||||
var plat = Math.DivRem(Worth, AccountGold.CurrencyThreshold, out var gold);
|
||||
|
||||
tradeInfo.Plat += plat;
|
||||
tradeInfo.Gold += gold;
|
||||
}
|
||||
|
||||
tradeInfo.VirtualCheck?.UpdateTrade(tradeInfo.Mobile);
|
||||
}
|
||||
|
||||
owner.SendLocalizedMessage(1042763, $"{m_Worth:N0}");
|
||||
|
||||
Delete();
|
||||
|
||||
((Container)parent).UpdateTotals();
|
||||
}
|
||||
else
|
||||
{
|
||||
Worth -= deposited;
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
if (deposited > 0)
|
||||
{
|
||||
from.NetState.SendMessageLocalizedAffix(
|
||||
Serial,
|
||||
ItemID,
|
||||
MessageType.Label,
|
||||
0x3B2,
|
||||
3,
|
||||
1041361, // A bank check:
|
||||
"",
|
||||
AffixType.Append,
|
||||
$" {m_Worth}"
|
||||
);
|
||||
}
|
||||
// Gold was deposited in your account:
|
||||
from.SendLocalizedMessage(1042672, true, $"{deposited:N0}");
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
// This probably isn't OSI accurate, but we can't just make the quests redundant.
|
||||
// Double-clicking the BankCheck in your pack will now credit your account.
|
||||
var box = AccountGold.Enabled ? from.Backpack : from.FindBankNoCreate();
|
||||
|
||||
if (box == null || !IsChildOf(box))
|
||||
if (from is PlayerMobile pm)
|
||||
{
|
||||
from.SendLocalizedMessage(AccountGold.Enabled ? 1080058 : 1047026);
|
||||
// This must be in your backpack to use it. : That must be in your bank box to use it.
|
||||
return;
|
||||
}
|
||||
var qs = pm.Quest;
|
||||
|
||||
var deposited = 0;
|
||||
var toAdd = m_Worth;
|
||||
|
||||
if (AccountGold.Enabled && from.Account?.DepositGold(toAdd) == true)
|
||||
{
|
||||
deposited = toAdd;
|
||||
}
|
||||
|
||||
while (toAdd > 0)
|
||||
{
|
||||
var amount = Math.Min(toAdd, 60000);
|
||||
|
||||
var gold = new Gold(amount);
|
||||
|
||||
if (box.TryDropItem(from, gold, false))
|
||||
if (qs is DarkTidesQuest)
|
||||
{
|
||||
toAdd -= amount;
|
||||
deposited += amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
gold.Delete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
QuestObjective obj = qs.FindObjective<CashBankCheckObjective>();
|
||||
|
||||
if (deposited >= m_Worth)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
Worth -= deposited;
|
||||
}
|
||||
|
||||
if (deposited > 0)
|
||||
{
|
||||
// Gold was deposited in your account:
|
||||
from.SendLocalizedMessage(1042672, true, $"{deposited:N0}");
|
||||
|
||||
if (from is PlayerMobile pm)
|
||||
{
|
||||
var qs = pm.Quest;
|
||||
|
||||
if (qs is DarkTidesQuest)
|
||||
if (obj?.Completed == false)
|
||||
{
|
||||
QuestObjective obj = qs.FindObjective<CashBankCheckObjective>();
|
||||
|
||||
if (obj?.Completed == false)
|
||||
{
|
||||
obj.Complete();
|
||||
}
|
||||
obj.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
if (qs is UzeraanTurmoilQuest)
|
||||
if (qs is UzeraanTurmoilQuest)
|
||||
{
|
||||
var obj = qs.FindObjective(typeof(Engines.Quests.Haven.CashBankCheckObjective));
|
||||
|
||||
if (obj?.Completed == false)
|
||||
{
|
||||
var obj = qs.FindObjective(typeof(Engines.Quests.Haven.CashBankCheckObjective));
|
||||
|
||||
if (obj?.Completed == false)
|
||||
{
|
||||
obj.Complete();
|
||||
}
|
||||
obj.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,15 @@
|
|||
namespace Server.Items
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class Beeswax : Item
|
||||
{
|
||||
public class Beeswax : Item
|
||||
[Constructible]
|
||||
public Beeswax(int amount = 1) : base(0x1422)
|
||||
{
|
||||
[Constructible]
|
||||
public Beeswax(int amount = 1) : base(0x1422)
|
||||
{
|
||||
Weight = 1.0;
|
||||
Stackable = true;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public Beeswax(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
Weight = 1.0;
|
||||
Stackable = true;
|
||||
Amount = amount;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,67 +1,50 @@
|
|||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class Blocker : Item
|
||||
{
|
||||
public class Blocker : Item
|
||||
private const ushort GMItemId = 0x1183;
|
||||
|
||||
[Constructible]
|
||||
public Blocker() : base(0x21A4) => Movable = false;
|
||||
|
||||
public override int LabelNumber => 503057; // Impassable!
|
||||
|
||||
public override void SendWorldPacketTo(NetState ns, ReadOnlySpan<byte> world = default)
|
||||
{
|
||||
private const ushort GMItemId = 0x1183;
|
||||
|
||||
[Constructible]
|
||||
public Blocker() : base(0x21A4) => Movable = false;
|
||||
|
||||
public Blocker(Serial serial) : base(serial)
|
||||
var mob = ns.Mobile;
|
||||
if (AccessLevel.GameMaster >= mob?.AccessLevel)
|
||||
{
|
||||
base.SendWorldPacketTo(ns, world);
|
||||
return;
|
||||
}
|
||||
|
||||
public override int LabelNumber => 503057; // Impassable!
|
||||
SendGMItem(ns);
|
||||
}
|
||||
|
||||
public override void SendWorldPacketTo(NetState ns, ReadOnlySpan<byte> world = default)
|
||||
private void SendGMItem(NetState ns)
|
||||
{
|
||||
// GM Packet
|
||||
Span<byte> buffer = stackalloc byte[OutgoingEntityPackets.MaxWorldEntityPacketLength].InitializePacket();
|
||||
|
||||
int length;
|
||||
|
||||
if (ns.StygianAbyss)
|
||||
{
|
||||
var mob = ns.Mobile;
|
||||
if (AccessLevel.GameMaster >= mob?.AccessLevel)
|
||||
{
|
||||
base.SendWorldPacketTo(ns, world);
|
||||
return;
|
||||
}
|
||||
|
||||
SendGMItem(ns);
|
||||
length = OutgoingEntityPackets.CreateWorldEntity(buffer, this, ns.HighSeas);
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer[8..10], GMItemId);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = OutgoingItemPackets.CreateWorldItem(buffer, this);
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer[7..9], GMItemId);
|
||||
}
|
||||
|
||||
private void SendGMItem(NetState ns)
|
||||
{
|
||||
// GM Packet
|
||||
Span<byte> buffer = stackalloc byte[OutgoingEntityPackets.MaxWorldEntityPacketLength].InitializePacket();
|
||||
|
||||
int length;
|
||||
|
||||
if (ns.StygianAbyss)
|
||||
{
|
||||
length = OutgoingEntityPackets.CreateWorldEntity(buffer, this, ns.HighSeas);
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer[8..10], GMItemId);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = OutgoingItemPackets.CreateWorldItem(buffer, this);
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer[7..9], GMItemId);
|
||||
}
|
||||
|
||||
ns.Send(buffer[..length]);
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
ns.Send(buffer[..length]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +1,26 @@
|
|||
using System;
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class Blood : Item
|
||||
{
|
||||
public class Blood : Item
|
||||
[Constructible]
|
||||
public Blood() : this(Utility.RandomList(0x1645, 0x122A, 0x122B, 0x122C, 0x122D, 0x122E, 0x122F))
|
||||
{
|
||||
[Constructible]
|
||||
public Blood() : this(Utility.RandomList(0x1645, 0x122A, 0x122B, 0x122C, 0x122D, 0x122E, 0x122F))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public Blood(int itemID) : base(itemID)
|
||||
{
|
||||
Movable = false;
|
||||
[Constructible]
|
||||
public Blood(int itemID) : base(itemID)
|
||||
{
|
||||
Movable = false;
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(5), Delete);
|
||||
}
|
||||
|
||||
new InternalTimer(this).Start();
|
||||
}
|
||||
|
||||
public Blood(Serial serial) : base(serial)
|
||||
{
|
||||
new InternalTimer(this).Start();
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly Item m_Blood;
|
||||
|
||||
public InternalTimer(Item blood) : base(TimeSpan.FromSeconds(5.0))
|
||||
{
|
||||
|
||||
m_Blood = blood;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Blood.Delete();
|
||||
}
|
||||
}
|
||||
[AfterDeserialization]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(5), Delete);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,170 @@
|
|||
using System;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Spells.Ninjitsu;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class Bola : Item
|
||||
{
|
||||
public class Bola : Item
|
||||
[Constructible]
|
||||
public Bola(int amount = 1) : base(0x26AC)
|
||||
{
|
||||
[Constructible]
|
||||
public Bola(int amount = 1) : base(0x26AC)
|
||||
Weight = 4.0;
|
||||
Stackable = true;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
Weight = 4.0;
|
||||
Stackable = true;
|
||||
Amount = amount;
|
||||
from.SendLocalizedMessage(1040019); // The bola must be in your pack to use it.
|
||||
}
|
||||
else if (!from.CanBeginAction<Bola>())
|
||||
{
|
||||
from.SendLocalizedMessage(1049624); // You have to wait a few moments before you can use another bola!
|
||||
}
|
||||
else if (from.Target is BolaTarget)
|
||||
{
|
||||
from.SendLocalizedMessage(1049631); // This bola is already being used.
|
||||
}
|
||||
else if (!HasFreeHands(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1040015); // Your hands must be free to use this
|
||||
}
|
||||
else if (from.Mounted)
|
||||
{
|
||||
from.SendLocalizedMessage(1040016); // You cannot use this while riding a mount
|
||||
}
|
||||
else if (AnimalForm.UnderTransformation(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1070902); // You can't use this while in an animal form!
|
||||
}
|
||||
else
|
||||
{
|
||||
EtherealMount.StopMounting(from);
|
||||
|
||||
from.Target = new BolaTarget(this);
|
||||
from.LocalOverheadMessage(MessageType.Emote, 0x3B2, 1049632); // * You begin to swing the bola...*
|
||||
// ~1_NAME~ begins to menacingly swing a bola...
|
||||
from.NonlocalOverheadMessage(MessageType.Emote, 0x3B2, 1049633, from.Name);
|
||||
}
|
||||
}
|
||||
|
||||
private static void FinishThrow(Mobile from, Mobile to)
|
||||
{
|
||||
if (Core.AOS)
|
||||
{
|
||||
new Bola().MoveToWorld(to.Location, to.Map);
|
||||
}
|
||||
|
||||
public Bola(Serial serial) : base(serial)
|
||||
if (to is ChaosDragoon or ChaosDragoonElite)
|
||||
{
|
||||
from.SendLocalizedMessage(1042047); // You fail to knock the rider from its mount.
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
var mt = to.Mount;
|
||||
if (mt != null && !(to is ChaosDragoon or ChaosDragoonElite))
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
mt.Rider = null;
|
||||
}
|
||||
|
||||
if (to is PlayerMobile mobile)
|
||||
{
|
||||
if (AnimalForm.UnderTransformation(mobile))
|
||||
{
|
||||
mobile.SendLocalizedMessage(1114066, from.Name); // ~1_NAME~ knocked you out of animal form!
|
||||
}
|
||||
else if (mobile.Mounted)
|
||||
{
|
||||
mobile.SendLocalizedMessage(1040023); // You have been knocked off of your mount!
|
||||
}
|
||||
|
||||
mobile.SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(Core.ML ? 10 : 3), true);
|
||||
}
|
||||
|
||||
/* only failsafe, attacker should already be dismounted */
|
||||
if (Core.AOS)
|
||||
{
|
||||
(from as PlayerMobile)?.SetMountBlock(
|
||||
BlockMountType.BolaRecovery,
|
||||
TimeSpan.FromSeconds(Core.ML ? 10 : 3),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
to.Damage(1);
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(2.0), from.EndAction<Bola>);
|
||||
}
|
||||
|
||||
private static bool HasFreeHands(Mobile from)
|
||||
{
|
||||
var one = from.FindItemOnLayer(Layer.OneHanded);
|
||||
var two = from.FindItemOnLayer(Layer.TwoHanded);
|
||||
|
||||
if (Core.SE)
|
||||
{
|
||||
var pack = from.Backpack;
|
||||
|
||||
if (pack != null)
|
||||
{
|
||||
if (one?.Movable == true)
|
||||
{
|
||||
pack.DropItem(one);
|
||||
one = null;
|
||||
}
|
||||
|
||||
if (two?.Movable == true)
|
||||
{
|
||||
pack.DropItem(two);
|
||||
two = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Core.AOS)
|
||||
{
|
||||
if (one?.Movable == true)
|
||||
{
|
||||
from.AddToBackpack(one);
|
||||
one = null;
|
||||
}
|
||||
|
||||
if (two?.Movable == true)
|
||||
{
|
||||
from.AddToBackpack(two);
|
||||
two = null;
|
||||
}
|
||||
}
|
||||
|
||||
return one == null && two == null;
|
||||
}
|
||||
|
||||
public class BolaTarget : Target
|
||||
{
|
||||
private readonly Bola m_Bola;
|
||||
|
||||
public BolaTarget(Bola bola) : base(8, false, TargetFlags.Harmful) => m_Bola = bola;
|
||||
|
||||
protected override void OnTarget(Mobile from, object obj)
|
||||
{
|
||||
if (m_Bola.Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is not Mobile to)
|
||||
{
|
||||
from.SendLocalizedMessage(1049629); // You cannot throw a bola at that.
|
||||
}
|
||||
else if (!m_Bola.IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1040019); // The bola must be in your pack to use it.
|
||||
}
|
||||
else if (!from.CanBeginAction<Bola>())
|
||||
{
|
||||
from.SendLocalizedMessage(1049624); // You have to wait a few moments before you can use another bola!
|
||||
}
|
||||
else if (from.Target is BolaTarget)
|
||||
{
|
||||
from.SendLocalizedMessage(1049631); // This bola is already being used.
|
||||
}
|
||||
else if (!HasFreeHands(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1040015); // Your hands must be free to use this
|
||||
|
|
@ -46,186 +177,31 @@ namespace Server.Items
|
|||
{
|
||||
from.SendLocalizedMessage(1070902); // You can't use this while in an animal form!
|
||||
}
|
||||
else
|
||||
else if (!to.Mounted && !AnimalForm.UnderTransformation(to))
|
||||
{
|
||||
from.SendLocalizedMessage(1049628); // You have no reason to throw a bola at that.
|
||||
}
|
||||
else if (!from.CanBeHarmful(to))
|
||||
{
|
||||
}
|
||||
else if (from.BeginAction<Bola>())
|
||||
{
|
||||
EtherealMount.StopMounting(from);
|
||||
|
||||
from.Target = new BolaTarget(this);
|
||||
from.LocalOverheadMessage(MessageType.Emote, 0x3B2, 1049632); // * You begin to swing the bola...*
|
||||
from.NonlocalOverheadMessage(
|
||||
MessageType.Emote,
|
||||
0x3B2,
|
||||
1049633,
|
||||
from.Name
|
||||
); // ~1_NAME~ begins to menacingly swing a bola...
|
||||
from.DoHarmful(to);
|
||||
|
||||
m_Bola.Consume();
|
||||
|
||||
from.Direction = from.GetDirectionTo(to);
|
||||
from.Animate(11, 5, 1, true, false, 0);
|
||||
from.MovingEffect(to, 0x26AC, 10, 0, false, false);
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(0.5), () => FinishThrow(from, to));
|
||||
}
|
||||
}
|
||||
|
||||
private static void FinishThrow(Mobile from, Mobile to)
|
||||
{
|
||||
if (Core.AOS)
|
||||
else
|
||||
{
|
||||
new Bola().MoveToWorld(to.Location, to.Map);
|
||||
}
|
||||
|
||||
if (to is ChaosDragoon or ChaosDragoonElite)
|
||||
{
|
||||
from.SendLocalizedMessage(1042047); // You fail to knock the rider from its mount.
|
||||
}
|
||||
|
||||
var mt = to.Mount;
|
||||
if (mt != null && !(to is ChaosDragoon or ChaosDragoonElite))
|
||||
{
|
||||
mt.Rider = null;
|
||||
}
|
||||
|
||||
if (to is PlayerMobile mobile)
|
||||
{
|
||||
if (AnimalForm.UnderTransformation(mobile))
|
||||
{
|
||||
mobile.SendLocalizedMessage(1114066, from.Name); // ~1_NAME~ knocked you out of animal form!
|
||||
}
|
||||
else if (mobile.Mounted)
|
||||
{
|
||||
mobile.SendLocalizedMessage(1040023); // You have been knocked off of your mount!
|
||||
}
|
||||
|
||||
mobile.SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(Core.ML ? 10 : 3), true);
|
||||
}
|
||||
|
||||
if (Core.AOS) /* only failsafe, attacker should already be dismounted */
|
||||
{
|
||||
(from as PlayerMobile)?.SetMountBlock(
|
||||
BlockMountType.BolaRecovery,
|
||||
TimeSpan.FromSeconds(Core.ML ? 10 : 3),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
to.Damage(1);
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(2.0), from.EndAction<Bola>);
|
||||
}
|
||||
|
||||
private static bool HasFreeHands(Mobile from)
|
||||
{
|
||||
var one = from.FindItemOnLayer(Layer.OneHanded);
|
||||
var two = from.FindItemOnLayer(Layer.TwoHanded);
|
||||
|
||||
if (Core.SE)
|
||||
{
|
||||
var pack = from.Backpack;
|
||||
|
||||
if (pack != null)
|
||||
{
|
||||
if (one?.Movable == true)
|
||||
{
|
||||
pack.DropItem(one);
|
||||
one = null;
|
||||
}
|
||||
|
||||
if (two?.Movable == true)
|
||||
{
|
||||
pack.DropItem(two);
|
||||
two = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Core.AOS)
|
||||
{
|
||||
if (one?.Movable == true)
|
||||
{
|
||||
from.AddToBackpack(one);
|
||||
one = null;
|
||||
}
|
||||
|
||||
if (two?.Movable == true)
|
||||
{
|
||||
from.AddToBackpack(two);
|
||||
two = null;
|
||||
}
|
||||
}
|
||||
|
||||
return one == null && two == null;
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
|
||||
public class BolaTarget : Target
|
||||
{
|
||||
private readonly Bola m_Bola;
|
||||
|
||||
public BolaTarget(Bola bola) : base(8, false, TargetFlags.Harmful) => m_Bola = bola;
|
||||
|
||||
protected override void OnTarget(Mobile from, object obj)
|
||||
{
|
||||
if (m_Bola.Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is Mobile to)
|
||||
{
|
||||
if (!m_Bola.IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1040019); // The bola must be in your pack to use it.
|
||||
}
|
||||
else if (!HasFreeHands(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1040015); // Your hands must be free to use this
|
||||
}
|
||||
else if (from.Mounted)
|
||||
{
|
||||
from.SendLocalizedMessage(1040016); // You cannot use this while riding a mount
|
||||
}
|
||||
else if (AnimalForm.UnderTransformation(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1070902); // You can't use this while in an animal form!
|
||||
}
|
||||
else if (!to.Mounted && !AnimalForm.UnderTransformation(to))
|
||||
{
|
||||
from.SendLocalizedMessage(1049628); // You have no reason to throw a bola at that.
|
||||
}
|
||||
else if (!from.CanBeHarmful(to))
|
||||
{
|
||||
}
|
||||
else if (from.BeginAction<Bola>())
|
||||
{
|
||||
EtherealMount.StopMounting(from);
|
||||
|
||||
from.DoHarmful(to);
|
||||
|
||||
m_Bola.Consume();
|
||||
|
||||
from.Direction = from.GetDirectionTo(to);
|
||||
from.Animate(11, 5, 1, true, false, 0);
|
||||
from.MovingEffect(to, 0x26AC, 10, 0, false, false);
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(0.5), () => FinishThrow(from, to));
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(
|
||||
1049624
|
||||
); // You have to wait a few moments before you can use another bola!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1049629); // You cannot throw a bola at that.
|
||||
}
|
||||
// You have to wait a few moments before you can use another bola!
|
||||
from.SendLocalizedMessage(1049624);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,16 @@
|
|||
namespace Server.Items
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class BolaBall : Item
|
||||
{
|
||||
public class BolaBall : Item
|
||||
[Constructible]
|
||||
public BolaBall(int amount = 1) : base(0xE73)
|
||||
{
|
||||
[Constructible]
|
||||
public BolaBall(int amount = 1) : base(0xE73)
|
||||
{
|
||||
Weight = 4.0;
|
||||
Stackable = true;
|
||||
Amount = amount;
|
||||
Hue = 0x8AC;
|
||||
}
|
||||
|
||||
public BolaBall(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
Weight = 4.0;
|
||||
Stackable = true;
|
||||
Amount = amount;
|
||||
Hue = 0x8AC;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,142 +1,125 @@
|
|||
using ModernUO.Serialization;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class ClockworkAssembly : Item
|
||||
{
|
||||
public class ClockworkAssembly : Item
|
||||
[Constructible]
|
||||
public ClockworkAssembly() : base(0x1EA8)
|
||||
{
|
||||
[Constructible]
|
||||
public ClockworkAssembly() : base(0x1EA8)
|
||||
Weight = 5.0;
|
||||
Hue = 1102;
|
||||
}
|
||||
|
||||
public override string DefaultName => "clockwork assembly";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
Weight = 5.0;
|
||||
Hue = 1102;
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
return;
|
||||
}
|
||||
|
||||
public ClockworkAssembly(Serial serial) : base(serial)
|
||||
var tinkerSkill = from.Skills.Tinkering.Value;
|
||||
|
||||
if (tinkerSkill < 60.0)
|
||||
{
|
||||
from.SendMessage("You must have at least 60.0 skill in tinkering to construct a golem.");
|
||||
return;
|
||||
}
|
||||
|
||||
public override string DefaultName => "clockwork assembly";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
if (from.Followers + 4 > from.FollowersMax)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
return;
|
||||
}
|
||||
from.SendLocalizedMessage(1049607); // You have too many followers to control that creature.
|
||||
return;
|
||||
}
|
||||
|
||||
var tinkerSkill = from.Skills.Tinkering.Value;
|
||||
double scalar;
|
||||
|
||||
if (tinkerSkill < 60.0)
|
||||
{
|
||||
from.SendMessage("You must have at least 60.0 skill in tinkering to construct a golem.");
|
||||
return;
|
||||
}
|
||||
if (tinkerSkill >= 100.0)
|
||||
{
|
||||
scalar = 1.0;
|
||||
}
|
||||
else if (tinkerSkill >= 90.0)
|
||||
{
|
||||
scalar = 0.9;
|
||||
}
|
||||
else if (tinkerSkill >= 80.0)
|
||||
{
|
||||
scalar = 0.8;
|
||||
}
|
||||
else if (tinkerSkill >= 70.0)
|
||||
{
|
||||
scalar = 0.7;
|
||||
}
|
||||
else
|
||||
{
|
||||
scalar = 0.6;
|
||||
}
|
||||
|
||||
if (from.Followers + 4 > from.FollowersMax)
|
||||
{
|
||||
from.SendLocalizedMessage(1049607); // You have too many followers to control that creature.
|
||||
return;
|
||||
}
|
||||
var pack = from.Backpack;
|
||||
|
||||
double scalar;
|
||||
if (pack == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (tinkerSkill >= 100.0)
|
||||
var res = pack.ConsumeTotal(
|
||||
new[]
|
||||
{
|
||||
scalar = 1.0;
|
||||
}
|
||||
else if (tinkerSkill >= 90.0)
|
||||
typeof(PowerCrystal),
|
||||
typeof(IronIngot),
|
||||
typeof(BronzeIngot),
|
||||
typeof(Gears)
|
||||
},
|
||||
new[]
|
||||
{
|
||||
scalar = 0.9;
|
||||
}
|
||||
else if (tinkerSkill >= 80.0)
|
||||
{
|
||||
scalar = 0.8;
|
||||
}
|
||||
else if (tinkerSkill >= 70.0)
|
||||
{
|
||||
scalar = 0.7;
|
||||
}
|
||||
else
|
||||
{
|
||||
scalar = 0.6;
|
||||
1,
|
||||
50,
|
||||
50,
|
||||
5
|
||||
}
|
||||
);
|
||||
|
||||
var pack = from.Backpack;
|
||||
|
||||
if (pack == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var res = pack.ConsumeTotal(
|
||||
new[]
|
||||
switch (res)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
typeof(PowerCrystal),
|
||||
typeof(IronIngot),
|
||||
typeof(BronzeIngot),
|
||||
typeof(Gears)
|
||||
},
|
||||
new[]
|
||||
{
|
||||
1,
|
||||
50,
|
||||
50,
|
||||
5
|
||||
from.SendMessage("You must have a power crystal to construct the golem.");
|
||||
break;
|
||||
}
|
||||
);
|
||||
case 1:
|
||||
{
|
||||
from.SendMessage("You must have 50 iron ingots to construct the golem.");
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
from.SendMessage("You must have 50 bronze ingots to construct the golem.");
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
from.SendMessage("You must have 5 gears to construct the golem.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
var g = new Golem(true, scalar);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case 0:
|
||||
if (g.SetControlMaster(from))
|
||||
{
|
||||
from.SendMessage("You must have a power crystal to construct the golem.");
|
||||
break;
|
||||
Delete();
|
||||
|
||||
g.MoveToWorld(from.Location, from.Map);
|
||||
from.PlaySound(0x241);
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
from.SendMessage("You must have 50 iron ingots to construct the golem.");
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
from.SendMessage("You must have 50 bronze ingots to construct the golem.");
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
from.SendMessage("You must have 5 gears to construct the golem.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
var g = new Golem(true, scalar);
|
||||
|
||||
if (g.SetControlMaster(from))
|
||||
{
|
||||
Delete();
|
||||
|
||||
g.MoveToWorld(from.Location, from.Map);
|
||||
from.PlaySound(0x241);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,471 +1,426 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
public class CrystalRechargeInfo
|
||||
{
|
||||
public class CrystalRechargeInfo
|
||||
private static CrystalRechargeInfo[] _table =
|
||||
{
|
||||
public static readonly CrystalRechargeInfo[] Table =
|
||||
{
|
||||
new(typeof(Citrine), 500),
|
||||
new(typeof(Amber), 500),
|
||||
new(typeof(Tourmaline), 750),
|
||||
new(typeof(Emerald), 1000),
|
||||
new(typeof(Sapphire), 1000),
|
||||
new(typeof(Amethyst), 1000),
|
||||
new(typeof(StarSapphire), 1250),
|
||||
new(typeof(Diamond), 2000)
|
||||
};
|
||||
new(typeof(Citrine), 500),
|
||||
new(typeof(Amber), 500),
|
||||
new(typeof(Tourmaline), 750),
|
||||
new(typeof(Emerald), 1000),
|
||||
new(typeof(Sapphire), 1000),
|
||||
new(typeof(Amethyst), 1000),
|
||||
new(typeof(StarSapphire), 1250),
|
||||
new(typeof(Diamond), 2000)
|
||||
};
|
||||
|
||||
private CrystalRechargeInfo(Type type, int amount)
|
||||
private CrystalRechargeInfo(Type type, int amount)
|
||||
{
|
||||
Type = type;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public Type Type { get; }
|
||||
|
||||
public int Amount { get; }
|
||||
|
||||
public static CrystalRechargeInfo Get(Type type)
|
||||
{
|
||||
foreach (var info in _table)
|
||||
{
|
||||
Type = type;
|
||||
Amount = amount;
|
||||
if (info.Type == type)
|
||||
{
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
public Type Type { get; }
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int Amount { get; }
|
||||
[SerializationGenerator(1)]
|
||||
public partial class BroadcastCrystal : Item
|
||||
{
|
||||
public const int MaxCharges = 2000;
|
||||
|
||||
public static CrystalRechargeInfo Get(Type type)
|
||||
[InvalidateProperties]
|
||||
[SerializableField(0)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _charges;
|
||||
|
||||
[InvalidateProperties]
|
||||
[SerializableField(1, getter: "private", setter: "private")]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private List<ReceiverCrystal> _receivers;
|
||||
|
||||
[Constructible]
|
||||
public BroadcastCrystal(int charges = 2000) : base(0x1ED0)
|
||||
{
|
||||
Light = LightType.Circle150;
|
||||
_charges = charges;
|
||||
_receivers = new List<ReceiverCrystal>();
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1060740; // communication crystal
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool Active
|
||||
{
|
||||
get => ItemID == 0x1ECD;
|
||||
set
|
||||
{
|
||||
foreach (var info in Table)
|
||||
{
|
||||
if (info.Type == type)
|
||||
{
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
ItemID = value ? 0x1ECD : 0x1ED0;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public class BroadcastCrystal : Item
|
||||
public override bool HandlesOnSpeech => true;
|
||||
|
||||
public override void GetProperties(IPropertyList list)
|
||||
{
|
||||
public static readonly int MaxCharges = 2000;
|
||||
base.GetProperties(list);
|
||||
|
||||
private int m_Charges;
|
||||
list.Add(Active ? 1060742 : 1060743); // active / inactive
|
||||
list.Add(1060745); // broadcast
|
||||
list.Add(1060741, Charges); // charges: ~1_val~
|
||||
|
||||
[Constructible]
|
||||
public BroadcastCrystal(int charges = 2000) : base(0x1ED0)
|
||||
if (_receivers.Count > 0)
|
||||
{
|
||||
Light = LightType.Circle150;
|
||||
|
||||
m_Charges = charges;
|
||||
|
||||
Receivers = new List<ReceiverCrystal>();
|
||||
}
|
||||
|
||||
public BroadcastCrystal(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1060740; // communication crystal
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool Active
|
||||
{
|
||||
get => ItemID == 0x1ECD;
|
||||
set
|
||||
{
|
||||
ItemID = value ? 0x1ECD : 0x1ED0;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Charges
|
||||
{
|
||||
get => m_Charges;
|
||||
set
|
||||
{
|
||||
m_Charges = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public List<ReceiverCrystal> Receivers { get; private set; }
|
||||
|
||||
public override bool HandlesOnSpeech => true;
|
||||
|
||||
public override void GetProperties(IPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
list.Add(Active ? 1060742 : 1060743); // active / inactive
|
||||
list.Add(1060745); // broadcast
|
||||
list.Add(1060741, Charges); // charges: ~1_val~
|
||||
|
||||
if (Receivers.Count > 0)
|
||||
{
|
||||
list.Add(1060746, Receivers.Count); // links: ~1_val~
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
base.OnSingleClick(from);
|
||||
|
||||
LabelTo(from, Active ? 1060742 : 1060743); // active / inactive
|
||||
LabelTo(from, 1060745); // broadcast
|
||||
LabelTo(from, 1060741, Charges.ToString()); // charges: ~1_val~
|
||||
|
||||
if (Receivers.Count > 0)
|
||||
{
|
||||
LabelTo(from, 1060746, Receivers.Count.ToString()); // links: ~1_val~
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSpeech(SpeechEventArgs e)
|
||||
{
|
||||
if (!Active || Receivers.Count == 0 || RootParent != null && RootParent is not Mobile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Type == MessageType.Emote)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var from = e.Mobile;
|
||||
var speech = e.Speech;
|
||||
|
||||
foreach (var receiver in new List<ReceiverCrystal>(Receivers))
|
||||
{
|
||||
if (receiver.Deleted)
|
||||
{
|
||||
Receivers.Remove(receiver);
|
||||
}
|
||||
else if (Charges > 0)
|
||||
{
|
||||
receiver.TransmitMessage(from, speech);
|
||||
Charges--;
|
||||
}
|
||||
else
|
||||
{
|
||||
Active = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
return;
|
||||
}
|
||||
|
||||
from.Target = new InternalTarget(this);
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.WriteEncodedInt(m_Charges);
|
||||
writer.Write(Receivers);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadEncodedInt();
|
||||
|
||||
m_Charges = reader.ReadEncodedInt();
|
||||
Receivers = reader.ReadEntityList<ReceiverCrystal>();
|
||||
}
|
||||
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
private readonly BroadcastCrystal m_Crystal;
|
||||
|
||||
public InternalTarget(BroadcastCrystal crystal) : base(2, false, TargetFlags.None) => m_Crystal = crystal;
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (!m_Crystal.IsAccessibleTo(from))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (from.Map != m_Crystal.Map || !from.InRange(m_Crystal.GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
return;
|
||||
}
|
||||
|
||||
if (targeted == m_Crystal)
|
||||
{
|
||||
if (m_Crystal.Active)
|
||||
{
|
||||
m_Crystal.Active = false;
|
||||
from.SendLocalizedMessage(500672); // You turn the crystal off.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Crystal.Charges > 0)
|
||||
{
|
||||
m_Crystal.Active = true;
|
||||
from.SendLocalizedMessage(500673); // You turn the crystal on.
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(500676); // This crystal is out of charges.
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targeted is ReceiverCrystal receiver)
|
||||
{
|
||||
if (m_Crystal.Receivers.Count >= 10)
|
||||
{
|
||||
from.SendLocalizedMessage(1010042); // This broadcast crystal is already linked to 10 receivers.
|
||||
}
|
||||
else if (receiver.Sender == m_Crystal)
|
||||
{
|
||||
from.SendLocalizedMessage(500674); // This crystal is already linked with that crystal.
|
||||
}
|
||||
else if (receiver.Sender != null)
|
||||
{
|
||||
from.SendLocalizedMessage(
|
||||
1010043
|
||||
); // That receiver crystal is already linked to another broadcast crystal.
|
||||
}
|
||||
else
|
||||
{
|
||||
receiver.Sender = m_Crystal;
|
||||
from.SendLocalizedMessage(500675); // That crystal has been linked to this crystal.
|
||||
}
|
||||
}
|
||||
else if (targeted == from)
|
||||
{
|
||||
foreach (var rc in new List<ReceiverCrystal>(m_Crystal.Receivers))
|
||||
{
|
||||
rc.Sender = null;
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage(1010046); // You unlink the broadcast crystal from all of its receivers.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targeted is Item targItem && targItem.VerifyMove(from))
|
||||
{
|
||||
var info = CrystalRechargeInfo.Get(targItem.GetType());
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
if (m_Crystal.Charges >= MaxCharges)
|
||||
{
|
||||
from.SendLocalizedMessage(500678); // This crystal is already fully charged.
|
||||
}
|
||||
else
|
||||
{
|
||||
targItem.Consume();
|
||||
|
||||
if (m_Crystal.Charges + info.Amount >= MaxCharges)
|
||||
{
|
||||
m_Crystal.Charges = MaxCharges;
|
||||
from.SendLocalizedMessage(500679); // You completely recharge the crystal.
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Crystal.Charges += info.Amount;
|
||||
from.SendLocalizedMessage(500680); // You recharge the crystal.
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage(500681); // You cannot use this crystal on that.
|
||||
}
|
||||
}
|
||||
list.Add(1060746, _receivers.Count); // links: ~1_val~
|
||||
}
|
||||
}
|
||||
|
||||
public class ReceiverCrystal : Item
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
private BroadcastCrystal m_Sender;
|
||||
base.OnSingleClick(from);
|
||||
|
||||
[Constructible]
|
||||
public ReceiverCrystal() : base(0x1ED0) => Light = LightType.Circle150;
|
||||
LabelTo(from, Active ? 1060742 : 1060743); // active / inactive
|
||||
LabelTo(from, 1060745); // broadcast
|
||||
LabelTo(from, 1060741, Charges.ToString()); // charges: ~1_val~
|
||||
|
||||
public ReceiverCrystal(Serial serial) : base(serial)
|
||||
if (_receivers.Count > 0)
|
||||
{
|
||||
LabelTo(from, 1060746, _receivers.Count.ToString()); // links: ~1_val~
|
||||
}
|
||||
}
|
||||
|
||||
private void Deserialize(IGenericReader reader, int version)
|
||||
{
|
||||
_charges = reader.ReadEncodedInt();
|
||||
_receivers = reader.ReadEntityList<ReceiverCrystal>();
|
||||
}
|
||||
|
||||
public override void OnSpeech(SpeechEventArgs e)
|
||||
{
|
||||
if (!Active || Receivers.Count == 0 || RootParent != null && RootParent is not Mobile || e.Type == MessageType.Emote)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1060740; // communication crystal
|
||||
var from = e.Mobile;
|
||||
var speech = e.Speech;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool Active
|
||||
foreach (var receiver in new List<ReceiverCrystal>(Receivers))
|
||||
{
|
||||
get => ItemID == 0x1ED1;
|
||||
set
|
||||
if (receiver.Deleted)
|
||||
{
|
||||
ItemID = value ? 0x1ED1 : 0x1ED0;
|
||||
InvalidateProperties();
|
||||
RemoveReceiver(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public BroadcastCrystal Sender
|
||||
{
|
||||
get => m_Sender;
|
||||
set
|
||||
else if (Charges > 0)
|
||||
{
|
||||
if (m_Sender != null)
|
||||
{
|
||||
m_Sender.Receivers.Remove(this);
|
||||
m_Sender.InvalidateProperties();
|
||||
}
|
||||
|
||||
m_Sender = value;
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
value.Receivers.Add(this);
|
||||
value.InvalidateProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetProperties(IPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
list.Add(Active ? 1060742 : 1060743); // active / inactive
|
||||
list.Add(1060744); // receiver
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
base.OnSingleClick(from);
|
||||
|
||||
LabelTo(from, Active ? 1060742 : 1060743); // active / inactive
|
||||
LabelTo(from, 1060744); // receiver
|
||||
}
|
||||
|
||||
public void TransmitMessage(Mobile from, string message)
|
||||
{
|
||||
if (!Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var text = $"{from.Name} says {message}";
|
||||
|
||||
if (RootParent is Mobile mobile)
|
||||
{
|
||||
mobile.SendMessage(0x2B2, $"Crystal: {text}");
|
||||
}
|
||||
else if (RootParent is Item item)
|
||||
{
|
||||
item.PublicOverheadMessage(MessageType.Regular, 0x2B2, false, $"Crystal: {text}");
|
||||
receiver.TransmitMessage(from, speech);
|
||||
Charges--;
|
||||
}
|
||||
else
|
||||
{
|
||||
PublicOverheadMessage(MessageType.Regular, 0x2B2, false, text);
|
||||
Active = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
public void AddReceiver(ReceiverCrystal receiver)
|
||||
{
|
||||
this.Add(Receivers, receiver);
|
||||
InvalidateProperties();
|
||||
}
|
||||
|
||||
public void RemoveReceiver(ReceiverCrystal receiver)
|
||||
{
|
||||
this.Remove(Receivers, receiver);
|
||||
InvalidateProperties();
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
return;
|
||||
}
|
||||
|
||||
from.Target = new InternalTarget(this);
|
||||
}
|
||||
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
private readonly BroadcastCrystal m_Crystal;
|
||||
|
||||
public InternalTarget(BroadcastCrystal crystal) : base(2, false, TargetFlags.None) => m_Crystal = crystal;
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (!m_Crystal.IsAccessibleTo(from))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (from.Map != m_Crystal.Map || !from.InRange(m_Crystal.GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
return;
|
||||
}
|
||||
|
||||
from.Target = new InternalTarget(this);
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.Write(m_Sender);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadEncodedInt();
|
||||
|
||||
m_Sender = reader.ReadEntity<BroadcastCrystal>();
|
||||
}
|
||||
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
private readonly ReceiverCrystal m_Crystal;
|
||||
|
||||
public InternalTarget(ReceiverCrystal crystal) : base(-1, false, TargetFlags.None) => m_Crystal = crystal;
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
if (targeted == m_Crystal)
|
||||
{
|
||||
if (!m_Crystal.IsAccessibleTo(from))
|
||||
if (m_Crystal.Active)
|
||||
{
|
||||
return;
|
||||
m_Crystal.Active = false;
|
||||
from.SendLocalizedMessage(500672); // You turn the crystal off.
|
||||
}
|
||||
|
||||
if (from.Map != m_Crystal.Map || !from.InRange(m_Crystal.GetWorldLocation(), 2))
|
||||
else
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
return;
|
||||
}
|
||||
|
||||
if (targeted == m_Crystal)
|
||||
{
|
||||
if (m_Crystal.Active)
|
||||
{
|
||||
m_Crystal.Active = false;
|
||||
from.SendLocalizedMessage(500672); // You turn the crystal off.
|
||||
}
|
||||
else
|
||||
if (m_Crystal.Charges > 0)
|
||||
{
|
||||
m_Crystal.Active = true;
|
||||
from.SendLocalizedMessage(500673); // You turn the crystal on.
|
||||
}
|
||||
}
|
||||
else if (targeted == from)
|
||||
{
|
||||
if (m_Crystal.Sender != null)
|
||||
{
|
||||
m_Crystal.Sender = null;
|
||||
from.SendLocalizedMessage(1010044); // You unlink the receiver crystal.
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1010045); // That receiver crystal is not linked.
|
||||
from.SendLocalizedMessage(500676); // This crystal is out of charges.
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targeted is ReceiverCrystal receiver)
|
||||
{
|
||||
if (m_Crystal.Receivers.Count >= 10)
|
||||
{
|
||||
from.SendLocalizedMessage(1010042); // This broadcast crystal is already linked to 10 receivers.
|
||||
}
|
||||
else if (receiver.Sender == m_Crystal)
|
||||
{
|
||||
from.SendLocalizedMessage(500674); // This crystal is already linked with that crystal.
|
||||
}
|
||||
else if (receiver.Sender != null)
|
||||
{
|
||||
// That receiver crystal is already linked to another broadcast crystal.
|
||||
from.SendLocalizedMessage(1010043);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targeted is Item targItem && targItem.VerifyMove(from))
|
||||
receiver.Sender = m_Crystal;
|
||||
from.SendLocalizedMessage(500675); // That crystal has been linked to this crystal.
|
||||
}
|
||||
}
|
||||
else if (targeted == from)
|
||||
{
|
||||
foreach (var rc in new List<ReceiverCrystal>(m_Crystal.Receivers))
|
||||
{
|
||||
rc.Sender = null;
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage(1010046); // You unlink the broadcast crystal from all of its receivers.
|
||||
}
|
||||
else if (targeted is not Item targItem || !targItem.VerifyMove(from))
|
||||
{
|
||||
from.SendLocalizedMessage(500681); // You cannot use this crystal on that.
|
||||
}
|
||||
else
|
||||
{
|
||||
var info = CrystalRechargeInfo.Get(targItem.GetType());
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
from.SendLocalizedMessage(500681); // You cannot use this crystal on that.
|
||||
}
|
||||
else if (m_Crystal.Charges >= MaxCharges)
|
||||
{
|
||||
from.SendLocalizedMessage(500678); // This crystal is already fully charged.
|
||||
}
|
||||
else
|
||||
{
|
||||
targItem.Consume();
|
||||
|
||||
if (m_Crystal.Charges + info.Amount >= MaxCharges)
|
||||
{
|
||||
var info = CrystalRechargeInfo.Get(targItem.GetType());
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
from.SendLocalizedMessage(500677); // This crystal cannot be recharged.
|
||||
return;
|
||||
}
|
||||
m_Crystal.Charges = MaxCharges;
|
||||
from.SendLocalizedMessage(500679); // You completely recharge the crystal.
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Crystal.Charges += info.Amount;
|
||||
from.SendLocalizedMessage(500680); // You recharge the crystal.
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage(1010045); // That receiver crystal is not linked.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializationGenerator(0)]
|
||||
public partial class ReceiverCrystal : Item
|
||||
{
|
||||
private BroadcastCrystal _sender;
|
||||
|
||||
[Constructible]
|
||||
public ReceiverCrystal() : base(0x1ED0) => Light = LightType.Circle150;
|
||||
|
||||
public ReceiverCrystal(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1060740; // communication crystal
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool Active
|
||||
{
|
||||
get => ItemID == 0x1ED1;
|
||||
set
|
||||
{
|
||||
ItemID = value ? 0x1ED1 : 0x1ED0;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[SerializableProperty(0, useField: nameof(_sender))]
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public BroadcastCrystal Sender
|
||||
{
|
||||
get => _sender;
|
||||
set
|
||||
{
|
||||
_sender?.RemoveReceiver(this);
|
||||
_sender = value;
|
||||
value?.AddReceiver(this);
|
||||
this.MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetProperties(IPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
list.Add(Active ? 1060742 : 1060743); // active / inactive
|
||||
list.Add(1060744); // receiver
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
base.OnSingleClick(from);
|
||||
|
||||
LabelTo(from, Active ? 1060742 : 1060743); // active / inactive
|
||||
LabelTo(from, 1060744); // receiver
|
||||
}
|
||||
|
||||
public void TransmitMessage(Mobile from, string message)
|
||||
{
|
||||
if (!Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var text = $"{from.Name} says {message}";
|
||||
|
||||
if (RootParent is Mobile mobile)
|
||||
{
|
||||
mobile.SendMessage(0x2B2, $"Crystal: {text}");
|
||||
}
|
||||
else if (RootParent is Item item)
|
||||
{
|
||||
item.PublicOverheadMessage(MessageType.Regular, 0x2B2, false, $"Crystal: {text}");
|
||||
}
|
||||
else
|
||||
{
|
||||
PublicOverheadMessage(MessageType.Regular, 0x2B2, false, text);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
return;
|
||||
}
|
||||
|
||||
from.Target = new InternalTarget(this);
|
||||
}
|
||||
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
private readonly ReceiverCrystal m_Crystal;
|
||||
|
||||
public InternalTarget(ReceiverCrystal crystal) : base(-1, false, TargetFlags.None) => m_Crystal = crystal;
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (!m_Crystal.IsAccessibleTo(from))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (from.Map != m_Crystal.Map || !from.InRange(m_Crystal.GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
return;
|
||||
}
|
||||
|
||||
if (targeted == m_Crystal)
|
||||
{
|
||||
if (m_Crystal.Active)
|
||||
{
|
||||
m_Crystal.Active = false;
|
||||
from.SendLocalizedMessage(500672); // You turn the crystal off.
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Crystal.Active = true;
|
||||
from.SendLocalizedMessage(500673); // You turn the crystal on.
|
||||
}
|
||||
}
|
||||
else if (targeted == from)
|
||||
{
|
||||
if (m_Crystal.Sender != null)
|
||||
{
|
||||
m_Crystal.Sender = null;
|
||||
from.SendLocalizedMessage(1010044); // You unlink the receiver crystal.
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1010045); // That receiver crystal is not linked.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targeted is Item targItem && targItem.VerifyMove(from))
|
||||
{
|
||||
var info = CrystalRechargeInfo.Get(targItem.GetType());
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
from.SendLocalizedMessage(500677); // This crystal cannot be recharged.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage(1010045); // That receiver crystal is not linked.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1221,10 +1221,7 @@ namespace Server.Items
|
|||
{
|
||||
private readonly Corpse m_Corpse;
|
||||
|
||||
public InternalTimer(Corpse c, TimeSpan delay) : base(delay)
|
||||
{
|
||||
m_Corpse = c;
|
||||
}
|
||||
public InternalTimer(Corpse c, TimeSpan delay) : base(delay) => m_Corpse = c;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,10 +97,7 @@ namespace Server.Items
|
|||
{
|
||||
private readonly DecayedCorpse m_Corpse;
|
||||
|
||||
public InternalTimer(DecayedCorpse c, TimeSpan delay) : base(delay)
|
||||
{
|
||||
m_Corpse = c;
|
||||
}
|
||||
public InternalTimer(DecayedCorpse c, TimeSpan delay) : base(delay) => m_Corpse = c;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,206 +1,179 @@
|
|||
using System;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Utilities;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class DeceitBrazier : Item
|
||||
{
|
||||
public class DeceitBrazier : Item
|
||||
private TimerExecutionToken _timerToken;
|
||||
|
||||
[SerializableField(0)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _spawnRange;
|
||||
|
||||
[SerializableField(1)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private TimeSpan _nextSpawnDelay;
|
||||
|
||||
[Constructible]
|
||||
public DeceitBrazier() : base(0xE31)
|
||||
{
|
||||
private TimerExecutionToken _timerToken;
|
||||
Movable = false;
|
||||
Light = LightType.Circle225;
|
||||
NextSpawn = Core.Now;
|
||||
NextSpawnDelay = TimeSpan.FromMinutes(15.0);
|
||||
SpawnRange = 5;
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public DeceitBrazier() : base(0xE31)
|
||||
private static Type[] _creatures { get; } =
|
||||
{
|
||||
typeof(FireSteed), // Set the tents up people!
|
||||
|
||||
typeof(Skeleton), typeof(SkeletalKnight), typeof(SkeletalMage), typeof(Mummy),
|
||||
typeof(BoneKnight), typeof(Lich), typeof(LichLord), typeof(BoneMagi),
|
||||
typeof(Wraith), typeof(Shade), typeof(Spectre), typeof(Zombie),
|
||||
typeof(RottingCorpse), typeof(Ghoul), typeof(Balron), typeof(Daemon), typeof(Imp), typeof(GreaterMongbat),
|
||||
typeof(Mongbat), typeof(IceFiend), typeof(Gargoyle), typeof(StoneGargoyle),
|
||||
typeof(FireGargoyle), typeof(HordeMinion), typeof(Gazer), typeof(ElderGazer), typeof(GazerLarva), typeof(Harpy),
|
||||
typeof(StoneHarpy), typeof(HeadlessOne), typeof(HellHound),
|
||||
typeof(HellCat), typeof(Phoenix), typeof(LavaLizard), typeof(SandVortex),
|
||||
typeof(ShadowWisp), typeof(SwampTentacle), typeof(PredatorHellCat), typeof(Wisp), typeof(GiantSpider),
|
||||
typeof(DreadSpider), typeof(FrostSpider), typeof(Scorpion), typeof(ArcticOgreLord), typeof(Cyclops),
|
||||
typeof(Ettin), typeof(EvilMage),
|
||||
typeof(FrostTroll), typeof(Ogre), typeof(OgreLord), typeof(Orc),
|
||||
typeof(OrcishLord), typeof(OrcishMage), typeof(OrcBrute), typeof(Ratman),
|
||||
typeof(RatmanMage), typeof(OrcCaptain), typeof(Troll), typeof(Titan),
|
||||
typeof(EvilMageLord), typeof(OrcBomber), typeof(RatmanArcher), typeof(Dragon), typeof(Drake), typeof(Snake),
|
||||
typeof(GreaterDragon),
|
||||
typeof(IceSerpent), typeof(GiantSerpent), typeof(IceSnake), typeof(LavaSerpent),
|
||||
typeof(Lizardman), typeof(Wyvern), typeof(WhiteWyrm),
|
||||
typeof(ShadowWyrm), typeof(SilverSerpent), typeof(LavaSnake), typeof(EarthElemental), typeof(PoisonElemental),
|
||||
typeof(FireElemental), typeof(SnowElemental),
|
||||
typeof(IceElemental), typeof(AcidElemental), typeof(WaterElemental), typeof(Efreet),
|
||||
typeof(AirElemental), typeof(Golem), typeof(SewerRat), typeof(GiantRat), typeof(DireWolf), typeof(TimberWolf),
|
||||
typeof(Cougar), typeof(Alligator)
|
||||
};
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime NextSpawn { get; private set; }
|
||||
|
||||
public override int LabelNumber => 1023633; // Brazier
|
||||
|
||||
public override bool HandlesOnMovement => true;
|
||||
|
||||
[AfterDeserialization]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
NextSpawn = Core.Now;
|
||||
}
|
||||
|
||||
public virtual void HeedWarning()
|
||||
{
|
||||
// Heed this warning well, and use this brazier at your own peril.
|
||||
PublicOverheadMessage(MessageType.Regular, 0x3B2, 500761);
|
||||
|
||||
_timerToken.Cancel();
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
// means we haven't spawned anything if the next spawn is below
|
||||
if (NextSpawn < Core.Now &&
|
||||
Utility.InRange(m.Location, Location, 1) &&
|
||||
!Utility.InRange(oldLocation, Location, 1) &&
|
||||
m.Player && !(m.AccessLevel > AccessLevel.Player || m.Hidden) && !_timerToken.Running)
|
||||
{
|
||||
Movable = false;
|
||||
Light = LightType.Circle225;
|
||||
NextSpawn = Core.Now;
|
||||
NextSpawnDelay = TimeSpan.FromMinutes(15.0);
|
||||
SpawnRange = 5;
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(2), HeedWarning, out _timerToken);
|
||||
}
|
||||
|
||||
public DeceitBrazier(Serial serial) : base(serial)
|
||||
base.OnMovement(m, oldLocation);
|
||||
}
|
||||
|
||||
public Point3D GetSpawnPosition()
|
||||
{
|
||||
var map = Map;
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
}
|
||||
|
||||
public static Type[] Creatures { get; } =
|
||||
{
|
||||
typeof(FireSteed), // Set the tents up people!
|
||||
|
||||
typeof(Skeleton), typeof(SkeletalKnight), typeof(SkeletalMage), typeof(Mummy),
|
||||
typeof(BoneKnight), typeof(Lich), typeof(LichLord), typeof(BoneMagi),
|
||||
typeof(Wraith), typeof(Shade), typeof(Spectre), typeof(Zombie),
|
||||
typeof(RottingCorpse), typeof(Ghoul), typeof(Balron), typeof(Daemon), typeof(Imp), typeof(GreaterMongbat),
|
||||
typeof(Mongbat), typeof(IceFiend), typeof(Gargoyle), typeof(StoneGargoyle),
|
||||
typeof(FireGargoyle), typeof(HordeMinion), typeof(Gazer), typeof(ElderGazer), typeof(GazerLarva), typeof(Harpy),
|
||||
typeof(StoneHarpy), typeof(HeadlessOne), typeof(HellHound),
|
||||
typeof(HellCat), typeof(Phoenix), typeof(LavaLizard), typeof(SandVortex),
|
||||
typeof(ShadowWisp), typeof(SwampTentacle), typeof(PredatorHellCat), typeof(Wisp), typeof(GiantSpider),
|
||||
typeof(DreadSpider), typeof(FrostSpider), typeof(Scorpion), typeof(ArcticOgreLord), typeof(Cyclops),
|
||||
typeof(Ettin), typeof(EvilMage),
|
||||
typeof(FrostTroll), typeof(Ogre), typeof(OgreLord), typeof(Orc),
|
||||
typeof(OrcishLord), typeof(OrcishMage), typeof(OrcBrute), typeof(Ratman),
|
||||
typeof(RatmanMage), typeof(OrcCaptain), typeof(Troll), typeof(Titan),
|
||||
typeof(EvilMageLord), typeof(OrcBomber), typeof(RatmanArcher), typeof(Dragon), typeof(Drake), typeof(Snake),
|
||||
typeof(GreaterDragon),
|
||||
typeof(IceSerpent), typeof(GiantSerpent), typeof(IceSnake), typeof(LavaSerpent),
|
||||
typeof(Lizardman), typeof(Wyvern), typeof(WhiteWyrm),
|
||||
typeof(ShadowWyrm), typeof(SilverSerpent), typeof(LavaSnake), typeof(EarthElemental), typeof(PoisonElemental),
|
||||
typeof(FireElemental), typeof(SnowElemental),
|
||||
typeof(IceElemental), typeof(AcidElemental), typeof(WaterElemental), typeof(Efreet),
|
||||
typeof(AirElemental), typeof(Golem), typeof(SewerRat), typeof(GiantRat), typeof(DireWolf), typeof(TimberWolf),
|
||||
typeof(Cougar), typeof(Alligator)
|
||||
};
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime NextSpawn { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int SpawnRange { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan NextSpawnDelay { get; set; }
|
||||
|
||||
public override int LabelNumber => 1023633; // Brazier
|
||||
|
||||
public override bool HandlesOnMovement => true;
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(SpawnRange);
|
||||
writer.Write(NextSpawnDelay);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
if (version >= 0)
|
||||
{
|
||||
SpawnRange = reader.ReadInt();
|
||||
NextSpawnDelay = reader.ReadTimeSpan();
|
||||
}
|
||||
|
||||
NextSpawn = Core.Now;
|
||||
}
|
||||
|
||||
public virtual void HeedWarning()
|
||||
{
|
||||
PublicOverheadMessage(
|
||||
MessageType.Regular,
|
||||
0x3B2,
|
||||
500761 // Heed this warning well, and use this brazier at your own peril.
|
||||
);
|
||||
|
||||
_timerToken.Cancel();
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
// means we haven't spawned anything if the next spawn is below
|
||||
if (NextSpawn < Core.Now &&
|
||||
Utility.InRange(m.Location, Location, 1) &&
|
||||
!Utility.InRange(oldLocation, Location, 1) &&
|
||||
m.Player && !(m.AccessLevel > AccessLevel.Player || m.Hidden) && !_timerToken.Running)
|
||||
{
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(2), HeedWarning, out _timerToken);
|
||||
}
|
||||
|
||||
base.OnMovement(m, oldLocation);
|
||||
}
|
||||
|
||||
public Point3D GetSpawnPosition()
|
||||
{
|
||||
var map = Map;
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
return Location;
|
||||
}
|
||||
|
||||
// Try 10 times to find a Spawnable location.
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var x = Location.X + (Utility.Random(SpawnRange * 2 + 1) - SpawnRange);
|
||||
var y = Location.Y + (Utility.Random(SpawnRange * 2 + 1) - SpawnRange);
|
||||
var z = Map.GetAverageZ(x, y);
|
||||
|
||||
if (Map.CanSpawnMobile(new Point2D(x, y), Z))
|
||||
{
|
||||
return new Point3D(x, y, Z);
|
||||
}
|
||||
|
||||
if (Map.CanSpawnMobile(new Point2D(x, y), z))
|
||||
{
|
||||
return new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
return Location;
|
||||
}
|
||||
|
||||
public virtual void DoEffect(Point3D loc, Map map)
|
||||
// Try 10 times to find a Spawnable location.
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
Effects.SendLocationParticles(EffectItem.Create(loc, map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052);
|
||||
Effects.PlaySound(loc, map, 0x225);
|
||||
}
|
||||
var x = Location.X + (Utility.Random(SpawnRange * 2 + 1) - SpawnRange);
|
||||
var y = Location.Y + (Utility.Random(SpawnRange * 2 + 1) - SpawnRange);
|
||||
var z = Map.GetAverageZ(x, y);
|
||||
|
||||
private void SummonCreatureToWorld(BaseCreature bc, Point3D spawnLoc, Map map)
|
||||
{
|
||||
bc.Home = Location;
|
||||
bc.RangeHome = SpawnRange;
|
||||
bc.FightMode = FightMode.Closest;
|
||||
|
||||
bc.MoveToWorld(spawnLoc, map);
|
||||
|
||||
DoEffect(spawnLoc, map);
|
||||
|
||||
bc.ForceReacquire();
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (Utility.InRange(from.Location, Location, 2))
|
||||
if (Map.CanSpawnMobile(new Point2D(x, y), Z))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (NextSpawn < Core.Now)
|
||||
{
|
||||
var map = Map;
|
||||
var bc = Creatures.RandomElement().CreateInstance<BaseCreature>();
|
||||
return new Point3D(x, y, Z);
|
||||
}
|
||||
|
||||
var spawnLoc = GetSpawnPosition();
|
||||
if (Map.CanSpawnMobile(new Point2D(x, y), z))
|
||||
{
|
||||
return new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
DoEffect(spawnLoc, map);
|
||||
return Location;
|
||||
}
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1), () => SummonCreatureToWorld(bc, spawnLoc, map));
|
||||
public virtual void DoEffect(Point3D loc, Map map)
|
||||
{
|
||||
Effects.SendLocationParticles(EffectItem.Create(loc, map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052);
|
||||
Effects.PlaySound(loc, map, 0x225);
|
||||
}
|
||||
|
||||
NextSpawn = Core.Now + NextSpawnDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
PublicOverheadMessage(
|
||||
MessageType.Regular,
|
||||
0x3B2,
|
||||
500760
|
||||
); // The brazier fizzes and pops, but nothing seems to happen.
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
private void SummonCreatureToWorld(BaseCreature bc, Point3D spawnLoc, Map map)
|
||||
{
|
||||
bc.Home = Location;
|
||||
bc.RangeHome = SpawnRange;
|
||||
bc.FightMode = FightMode.Closest;
|
||||
|
||||
bc.MoveToWorld(spawnLoc, map);
|
||||
|
||||
DoEffect(spawnLoc, map);
|
||||
|
||||
bc.ForceReacquire();
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!Utility.InRange(from.Location, Location, 2))
|
||||
{
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (NextSpawn < Core.Now)
|
||||
{
|
||||
var map = Map;
|
||||
var bc = _creatures.RandomElement().CreateInstance<BaseCreature>();
|
||||
|
||||
var spawnLoc = GetSpawnPosition();
|
||||
|
||||
DoEffect(spawnLoc, map);
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1), () => SummonCreatureToWorld(bc, spawnLoc, map));
|
||||
|
||||
NextSpawn = Core.Now + NextSpawnDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
// The brazier fizzes and pops, but nothing seems to happen.
|
||||
PublicOverheadMessage(MessageType.Regular, 0x3B2, 500760);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,382 +1,315 @@
|
|||
using System;
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
public enum ECEffectType
|
||||
{
|
||||
public enum ECEffectType
|
||||
None,
|
||||
Moving,
|
||||
Location,
|
||||
Target,
|
||||
Lightning
|
||||
}
|
||||
|
||||
public enum EffectTriggerType
|
||||
{
|
||||
None,
|
||||
Sequenced,
|
||||
DoubleClick,
|
||||
InRange
|
||||
}
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class EffectController : Item
|
||||
{
|
||||
[SerializableField(0)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private TimeSpan _effectDelay;
|
||||
|
||||
[SerializableField(1)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private TimeSpan _triggerDelay;
|
||||
|
||||
[SerializableField(2)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private TimeSpan _soundDelay;
|
||||
|
||||
[SerializableField(3)]
|
||||
private IEntity _source;
|
||||
|
||||
[SerializableField(4)]
|
||||
private IEntity _target;
|
||||
|
||||
[SerializableField(5)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private EffectController _sequence;
|
||||
|
||||
[SerializableField(6)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private bool _fixedDirection;
|
||||
|
||||
[SerializableField(7)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private bool _explodes;
|
||||
|
||||
[SerializableField(8)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private bool _playSoundAtTrigger;
|
||||
|
||||
[SerializableField(9)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private ECEffectType _effectType;
|
||||
|
||||
[SerializableField(10)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private EffectLayer _effectLayer;
|
||||
|
||||
[SerializableField(11)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private EffectTriggerType _triggerType;
|
||||
|
||||
[SerializableField(12)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _effectItemId;
|
||||
|
||||
[SerializableField(13)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _effectHue;
|
||||
|
||||
[SerializableField(14)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _renderMode;
|
||||
|
||||
[SerializableField(15)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _speed;
|
||||
|
||||
[SerializableField(16)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _duration;
|
||||
|
||||
[SerializableField(17)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _particleEffect;
|
||||
|
||||
[SerializableField(18)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _explodeParticleEffect;
|
||||
|
||||
[SerializableField(19)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _explodeSound;
|
||||
|
||||
[SerializableField(20)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _unknown;
|
||||
|
||||
[SerializableField(21)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _soundId;
|
||||
|
||||
[SerializableField(22)]
|
||||
[SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")]
|
||||
private int _triggerRange;
|
||||
|
||||
[Constructible]
|
||||
public EffectController() : base(0x1B72)
|
||||
{
|
||||
None,
|
||||
Moving,
|
||||
Location,
|
||||
Target,
|
||||
Lightning
|
||||
Movable = false;
|
||||
Visible = false;
|
||||
TriggerType = EffectTriggerType.Sequenced;
|
||||
EffectLayer = (EffectLayer)255;
|
||||
}
|
||||
|
||||
public enum EffectTriggerType
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Item SourceItem
|
||||
{
|
||||
None,
|
||||
Sequenced,
|
||||
DoubleClick,
|
||||
InRange
|
||||
get => _source as Item;
|
||||
set => _source = value;
|
||||
}
|
||||
|
||||
public class EffectController : Item
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile SourceMobile
|
||||
{
|
||||
private IEntity m_Source;
|
||||
private IEntity m_Target;
|
||||
get => _source as Mobile;
|
||||
set => _source = value;
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public EffectController() : base(0x1B72)
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool SourceNull
|
||||
{
|
||||
get => _source == null;
|
||||
set
|
||||
{
|
||||
Movable = false;
|
||||
Visible = false;
|
||||
TriggerType = EffectTriggerType.Sequenced;
|
||||
EffectLayer = (EffectLayer)255;
|
||||
}
|
||||
|
||||
public EffectController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ECEffectType EffectType { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public EffectTriggerType TriggerType { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public EffectLayer EffectLayer { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan EffectDelay { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan TriggerDelay { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan SoundDelay { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Item SourceItem
|
||||
{
|
||||
get => m_Source as Item;
|
||||
set => m_Source = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile SourceMobile
|
||||
{
|
||||
get => m_Source as Mobile;
|
||||
set => m_Source = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool SourceNull
|
||||
{
|
||||
get => m_Source == null;
|
||||
set
|
||||
if (value)
|
||||
{
|
||||
if (value)
|
||||
_source = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Item TargetItem
|
||||
{
|
||||
get => _target as Item;
|
||||
set => _target = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile TargetMobile
|
||||
{
|
||||
get => _target as Mobile;
|
||||
set => _target = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool TargetNull
|
||||
{
|
||||
get => _target == null;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
_target = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string DefaultName => "Effect Controller";
|
||||
|
||||
public override bool HandlesOnMovement => _triggerType == EffectTriggerType.InRange;
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (_triggerType == EffectTriggerType.DoubleClick)
|
||||
{
|
||||
DoEffect(from);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
if (m.Location == oldLocation || _triggerType != EffectTriggerType.InRange)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var worldLocation = GetWorldLocation();
|
||||
|
||||
if (Utility.InRange(worldLocation, m.Location, _triggerRange) &&
|
||||
!Utility.InRange(worldLocation, oldLocation, _triggerRange))
|
||||
{
|
||||
DoEffect(m);
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaySound(IEntity trigger)
|
||||
{
|
||||
var ent = PlaySoundAtTrigger ? trigger : this;
|
||||
|
||||
Effects.PlaySound((ent as Item)?.GetWorldLocation() ?? ent.Location, ent.Map, _soundId);
|
||||
}
|
||||
|
||||
public void DoEffect(IEntity trigger)
|
||||
{
|
||||
if (Deleted || TriggerType == EffectTriggerType.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (trigger is Mobile { Hidden: true, AccessLevel: > AccessLevel.Player })
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_soundId > 0)
|
||||
{
|
||||
Timer.StartTimer(SoundDelay, () => PlaySound(trigger));
|
||||
}
|
||||
|
||||
if (Sequence != null)
|
||||
{
|
||||
Timer.StartTimer(TriggerDelay, () => Sequence.DoEffect(trigger));
|
||||
}
|
||||
|
||||
if (EffectType != ECEffectType.None)
|
||||
{
|
||||
Timer.StartTimer(EffectDelay, () => InternalDoEffect(trigger));
|
||||
}
|
||||
}
|
||||
|
||||
public void InternalDoEffect(IEntity trigger)
|
||||
{
|
||||
var from = _source ?? trigger;
|
||||
var to = _target ?? trigger;
|
||||
|
||||
switch (EffectType)
|
||||
{
|
||||
case ECEffectType.Lightning:
|
||||
{
|
||||
m_Source = null;
|
||||
Effects.SendBoltEffect(from, false, EffectHue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Item TargetItem
|
||||
{
|
||||
get => m_Target as Item;
|
||||
set => m_Target = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile TargetMobile
|
||||
{
|
||||
get => m_Target as Mobile;
|
||||
set => m_Target = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool TargetNull
|
||||
{
|
||||
get => m_Target == null;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
case ECEffectType.Location:
|
||||
{
|
||||
m_Target = null;
|
||||
Effects.SendLocationParticles(
|
||||
EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration),
|
||||
_effectItemId,
|
||||
_speed,
|
||||
_duration,
|
||||
_effectHue,
|
||||
_renderMode,
|
||||
_particleEffect,
|
||||
_unknown
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public EffectController Sequence { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
private bool FixedDirection { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
private bool Explodes { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
private bool PlaySoundAtTrigger { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int EffectItemID { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int EffectHue { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int RenderMode { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Speed { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Duration { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ParticleEffect { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ExplodeParticleEffect { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ExplodeSound { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Unknown { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int SoundID { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int TriggerRange { get; set; }
|
||||
|
||||
public override string DefaultName => "Effect Controller";
|
||||
|
||||
public override bool HandlesOnMovement => TriggerType == EffectTriggerType.InRange;
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (TriggerType == EffectTriggerType.DoubleClick)
|
||||
{
|
||||
DoEffect(from);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
if (m.Location != oldLocation && TriggerType == EffectTriggerType.InRange &&
|
||||
Utility.InRange(GetWorldLocation(), m.Location, TriggerRange) &&
|
||||
!Utility.InRange(GetWorldLocation(), oldLocation, TriggerRange))
|
||||
{
|
||||
DoEffect(m);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(EffectDelay);
|
||||
writer.Write(TriggerDelay);
|
||||
writer.Write(SoundDelay);
|
||||
|
||||
if (m_Source is Item srcItem)
|
||||
{
|
||||
writer.Write(srcItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(m_Source as Mobile);
|
||||
}
|
||||
|
||||
if (m_Target is Item targItem)
|
||||
{
|
||||
writer.Write(targItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(m_Target as Mobile);
|
||||
}
|
||||
|
||||
writer.Write(Sequence);
|
||||
|
||||
writer.Write(FixedDirection);
|
||||
writer.Write(Explodes);
|
||||
writer.Write(PlaySoundAtTrigger);
|
||||
|
||||
writer.WriteEncodedInt((int)EffectType);
|
||||
writer.WriteEncodedInt((int)EffectLayer);
|
||||
writer.WriteEncodedInt((int)TriggerType);
|
||||
|
||||
writer.WriteEncodedInt(EffectItemID);
|
||||
writer.WriteEncodedInt(EffectHue);
|
||||
writer.WriteEncodedInt(RenderMode);
|
||||
writer.WriteEncodedInt(Speed);
|
||||
writer.WriteEncodedInt(Duration);
|
||||
writer.WriteEncodedInt(ParticleEffect);
|
||||
writer.WriteEncodedInt(ExplodeParticleEffect);
|
||||
writer.WriteEncodedInt(ExplodeSound);
|
||||
writer.WriteEncodedInt(Unknown);
|
||||
writer.WriteEncodedInt(SoundID);
|
||||
writer.WriteEncodedInt(TriggerRange);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
case ECEffectType.Moving:
|
||||
{
|
||||
if (from == this)
|
||||
{
|
||||
EffectDelay = reader.ReadTimeSpan();
|
||||
TriggerDelay = reader.ReadTimeSpan();
|
||||
SoundDelay = reader.ReadTimeSpan();
|
||||
|
||||
m_Source = reader.ReadEntity<IEntity>();
|
||||
m_Target = reader.ReadEntity<IEntity>();
|
||||
Sequence = reader.ReadEntity<EffectController>();
|
||||
|
||||
FixedDirection = reader.ReadBool();
|
||||
Explodes = reader.ReadBool();
|
||||
PlaySoundAtTrigger = reader.ReadBool();
|
||||
|
||||
EffectType = (ECEffectType)reader.ReadEncodedInt();
|
||||
EffectLayer = (EffectLayer)reader.ReadEncodedInt();
|
||||
TriggerType = (EffectTriggerType)reader.ReadEncodedInt();
|
||||
|
||||
EffectItemID = reader.ReadEncodedInt();
|
||||
EffectHue = reader.ReadEncodedInt();
|
||||
RenderMode = reader.ReadEncodedInt();
|
||||
Speed = reader.ReadEncodedInt();
|
||||
Duration = reader.ReadEncodedInt();
|
||||
ParticleEffect = reader.ReadEncodedInt();
|
||||
ExplodeParticleEffect = reader.ReadEncodedInt();
|
||||
ExplodeSound = reader.ReadEncodedInt();
|
||||
Unknown = reader.ReadEncodedInt();
|
||||
SoundID = reader.ReadEncodedInt();
|
||||
TriggerRange = reader.ReadEncodedInt();
|
||||
|
||||
break;
|
||||
from = EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaySound(IEntity trigger)
|
||||
{
|
||||
var ent = PlaySoundAtTrigger ? trigger : this;
|
||||
|
||||
Effects.PlaySound((ent as Item)?.GetWorldLocation() ?? ent.Location, ent.Map, SoundID);
|
||||
}
|
||||
|
||||
public void DoEffect(IEntity trigger)
|
||||
{
|
||||
if (Deleted || TriggerType == EffectTriggerType.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (trigger is Mobile { Hidden: true } mobile && mobile.AccessLevel > AccessLevel.Player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SoundID > 0)
|
||||
{
|
||||
Timer.StartTimer(SoundDelay, () => PlaySound(trigger));
|
||||
}
|
||||
|
||||
if (Sequence != null)
|
||||
{
|
||||
Timer.StartTimer(TriggerDelay, () => Sequence.DoEffect(trigger));
|
||||
}
|
||||
|
||||
if (EffectType != ECEffectType.None)
|
||||
{
|
||||
Timer.StartTimer(EffectDelay, () => InternalDoEffect(trigger));
|
||||
}
|
||||
}
|
||||
|
||||
public void InternalDoEffect(IEntity trigger)
|
||||
{
|
||||
var from = m_Source ?? trigger;
|
||||
var to = m_Target ?? trigger;
|
||||
|
||||
switch (EffectType)
|
||||
{
|
||||
case ECEffectType.Lightning:
|
||||
if (to == this)
|
||||
{
|
||||
Effects.SendBoltEffect(from, false, EffectHue);
|
||||
break;
|
||||
to = EffectItem.Create(to.Location, to.Map, EffectItem.DefaultDuration);
|
||||
}
|
||||
case ECEffectType.Location:
|
||||
{
|
||||
Effects.SendLocationParticles(
|
||||
EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration),
|
||||
EffectItemID,
|
||||
Speed,
|
||||
Duration,
|
||||
EffectHue,
|
||||
RenderMode,
|
||||
ParticleEffect,
|
||||
Unknown
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ECEffectType.Moving:
|
||||
{
|
||||
if (from == this)
|
||||
{
|
||||
from = EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration);
|
||||
}
|
||||
|
||||
if (to == this)
|
||||
{
|
||||
to = EffectItem.Create(to.Location, to.Map, EffectItem.DefaultDuration);
|
||||
}
|
||||
|
||||
Effects.SendMovingParticles(
|
||||
from,
|
||||
to,
|
||||
EffectItemID,
|
||||
Speed,
|
||||
Duration,
|
||||
FixedDirection,
|
||||
Explodes,
|
||||
EffectHue,
|
||||
RenderMode,
|
||||
ParticleEffect,
|
||||
ExplodeParticleEffect,
|
||||
ExplodeSound,
|
||||
EffectLayer,
|
||||
Unknown
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ECEffectType.Target:
|
||||
{
|
||||
Effects.SendTargetParticles(
|
||||
from,
|
||||
EffectItemID,
|
||||
Speed,
|
||||
Duration,
|
||||
EffectHue,
|
||||
RenderMode,
|
||||
ParticleEffect,
|
||||
EffectLayer,
|
||||
Unknown
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Effects.SendMovingParticles(
|
||||
from,
|
||||
to,
|
||||
_effectItemId,
|
||||
_speed,
|
||||
_duration,
|
||||
_fixedDirection,
|
||||
_explodes,
|
||||
_effectHue,
|
||||
_renderMode,
|
||||
_particleEffect,
|
||||
_explodeParticleEffect,
|
||||
_explodeSound,
|
||||
_effectLayer,
|
||||
_unknown
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ECEffectType.Target:
|
||||
{
|
||||
Effects.SendTargetParticles(
|
||||
from,
|
||||
_effectItemId,
|
||||
_speed,
|
||||
_duration,
|
||||
_effectHue,
|
||||
_renderMode,
|
||||
_particleEffect,
|
||||
_effectLayer,
|
||||
_unknown
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,91 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class EffectItem : Item
|
||||
{
|
||||
public class EffectItem : Item
|
||||
private static Queue<EffectItem> _free = new(); // List of available EffectItems
|
||||
|
||||
public static readonly TimeSpan DefaultDuration = TimeSpan.FromSeconds(5.0);
|
||||
|
||||
private EffectItem() : base(1) => Movable = false;
|
||||
|
||||
public override bool Decays => true;
|
||||
|
||||
public static EffectItem Create(Point3D p, Map map, TimeSpan duration)
|
||||
{
|
||||
private static readonly List<EffectItem> m_Free = new(); // List of available EffectItems
|
||||
EffectItem item = null;
|
||||
|
||||
public static readonly TimeSpan DefaultDuration = TimeSpan.FromSeconds(5.0);
|
||||
|
||||
private EffectItem() : base(1) // nodraw
|
||||
=>
|
||||
Movable = false;
|
||||
|
||||
public EffectItem(Serial serial) : base(serial)
|
||||
while (_free.Count > 0)
|
||||
{
|
||||
var free = _free.Dequeue();
|
||||
if (!free.Deleted && free.Map == Map.Internal)
|
||||
{
|
||||
item = free;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Decays => true;
|
||||
|
||||
public static EffectItem Create(Point3D p, Map map, TimeSpan duration)
|
||||
if (item == null)
|
||||
{
|
||||
EffectItem item = null;
|
||||
|
||||
for (var i = m_Free.Count - 1; item == null && i >= 0; --i) // We reuse new entries first so decay works better
|
||||
{
|
||||
var free = m_Free[i];
|
||||
|
||||
m_Free.RemoveAt(i);
|
||||
|
||||
if (!free.Deleted && free.Map == Map.Internal)
|
||||
{
|
||||
item = free;
|
||||
}
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
item = new EffectItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
item.ItemID = 1;
|
||||
}
|
||||
|
||||
item.MoveToWorld(p, map);
|
||||
item.BeginFree(duration);
|
||||
|
||||
return item;
|
||||
item = new EffectItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
item.ItemID = 1;
|
||||
}
|
||||
|
||||
public void BeginFree(TimeSpan duration)
|
||||
item.MoveToWorld(p, map);
|
||||
item.BeginFree(duration);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public void BeginFree(TimeSpan duration) => new FreeTimer(this, duration).Start();
|
||||
|
||||
[AfterDeserialization(false)]
|
||||
private void AfterDeserialization()
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
|
||||
private class FreeTimer : Timer
|
||||
{
|
||||
private EffectItem _item;
|
||||
|
||||
public FreeTimer(EffectItem item, TimeSpan delay) : base(delay) => _item = item;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
new FreeTimer(this, duration).Start();
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
Delete();
|
||||
}
|
||||
|
||||
private class FreeTimer : Timer
|
||||
{
|
||||
private readonly EffectItem m_Item;
|
||||
|
||||
public FreeTimer(EffectItem item, TimeSpan delay) : base(delay)
|
||||
{
|
||||
m_Item = item;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Item.Internalize();
|
||||
|
||||
m_Free.Add(m_Item);
|
||||
}
|
||||
_item.Internalize();
|
||||
_free.Enqueue(_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,10 @@
|
|||
namespace Server.Items
|
||||
using ModernUO.Serialization;
|
||||
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class ExecutionersCap : Item
|
||||
{
|
||||
public class ExecutionersCap : Item
|
||||
{
|
||||
[Constructible]
|
||||
public ExecutionersCap() : base(0xF83) => Weight = 1.0;
|
||||
|
||||
public ExecutionersCap(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
[Constructible]
|
||||
public ExecutionersCap() : base(0xF83) => Weight = 1.0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,228 +1,208 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Collections;
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Fourth;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[SerializationGenerator(0, false)]
|
||||
public partial class Firebomb : Item
|
||||
{
|
||||
public class Firebomb : Item
|
||||
private Mobile m_LitBy;
|
||||
private Point3D _thrownFromLocation;
|
||||
private int _ticks;
|
||||
private TimerExecutionToken _timerToken;
|
||||
private List<Mobile> _users;
|
||||
|
||||
[Constructible]
|
||||
public Firebomb(int itemID = 0x99B) : base(itemID)
|
||||
{
|
||||
private Mobile m_LitBy;
|
||||
private Point3D _thrownFromLocation;
|
||||
private int m_Ticks;
|
||||
private TimerExecutionToken _timerToken;
|
||||
private List<Mobile> m_Users;
|
||||
// Name = "a firebomb";
|
||||
Weight = 2.0;
|
||||
Hue = 1260;
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public Firebomb(int itemID = 0x99B) : base(itemID)
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
// Name = "a firebomb";
|
||||
Weight = 2.0;
|
||||
Hue = 1260;
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
return;
|
||||
}
|
||||
|
||||
public Firebomb(Serial serial) : base(serial)
|
||||
if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true))
|
||||
{
|
||||
// to prevent exploiting for pvp
|
||||
from.SendLocalizedMessage(1075857); // You cannot use that while paralyzed.
|
||||
return;
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
if (_timerToken.Running)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
from.SendLocalizedMessage(1060581); // You've already lit it! Better throw it now!
|
||||
}
|
||||
else
|
||||
{
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnFirebombTimerTick, out _timerToken);
|
||||
m_LitBy = from;
|
||||
from.SendLocalizedMessage(1060582); // You light the firebomb. Throw it now!
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
_users ??= new List<Mobile>();
|
||||
|
||||
var version = reader.ReadEncodedInt();
|
||||
if (!_users.Contains(from))
|
||||
{
|
||||
_users.Add(from);
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
from.Target = new ThrowTarget(this);
|
||||
}
|
||||
|
||||
private void OnFirebombTimerTick()
|
||||
{
|
||||
if (Deleted)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
||||
return;
|
||||
}
|
||||
|
||||
if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true))
|
||||
{
|
||||
// to prevent exploiting for pvp
|
||||
from.SendLocalizedMessage(1075857); // You cannot use that while paralyzed.
|
||||
return;
|
||||
}
|
||||
|
||||
if (_timerToken.Running)
|
||||
{
|
||||
from.SendLocalizedMessage(1060581); // You've already lit it! Better throw it now!
|
||||
}
|
||||
else
|
||||
{
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnFirebombTimerTick, out _timerToken);
|
||||
m_LitBy = from;
|
||||
from.SendLocalizedMessage(1060582); // You light the firebomb. Throw it now!
|
||||
}
|
||||
|
||||
m_Users ??= new List<Mobile>();
|
||||
|
||||
if (!m_Users.Contains(from))
|
||||
{
|
||||
m_Users.Add(from);
|
||||
}
|
||||
|
||||
from.Target = new ThrowTarget(this);
|
||||
_timerToken.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
private void OnFirebombTimerTick()
|
||||
if (Map == Map.Internal && HeldBy == null)
|
||||
{
|
||||
if (Deleted)
|
||||
{
|
||||
_timerToken.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Map == Map.Internal && HeldBy == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_Ticks)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
++m_Ticks;
|
||||
|
||||
if (HeldBy != null)
|
||||
{
|
||||
HeldBy.PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString());
|
||||
}
|
||||
else if (RootParent == null)
|
||||
{
|
||||
PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString());
|
||||
}
|
||||
else if (RootParent is Mobile mobile)
|
||||
{
|
||||
mobile.PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
HeldBy?.DropHolding();
|
||||
|
||||
if (m_Users != null)
|
||||
{
|
||||
foreach (var m in m_Users)
|
||||
{
|
||||
if (m.Target is ThrowTarget targ && targ.Bomb == this)
|
||||
{
|
||||
Target.Cancel(m);
|
||||
}
|
||||
}
|
||||
|
||||
m_Users.Clear();
|
||||
m_Users = null;
|
||||
}
|
||||
|
||||
if (RootParent is Mobile parent)
|
||||
{
|
||||
parent.SendLocalizedMessage(1060583); // The firebomb explodes in your hand!
|
||||
AOS.Damage(parent, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
|
||||
}
|
||||
else if (RootParent == null)
|
||||
{
|
||||
var eable = Map.GetMobilesInRange(Location, 1);
|
||||
using var targets = PooledRefQueue<Mobile>.Create();
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (m_LitBy == null || SpellHelper.ValidIndirectTarget(m_LitBy, m) &&
|
||||
m_LitBy.CanBeHarmful(m, false))
|
||||
{
|
||||
targets.Enqueue(m);
|
||||
}
|
||||
}
|
||||
eable.Free();
|
||||
|
||||
while (targets.Count > 0)
|
||||
{
|
||||
var victim = targets.Dequeue();
|
||||
m_LitBy?.DoHarmful(victim);
|
||||
AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
|
||||
}
|
||||
|
||||
var loc = _thrownFromLocation;
|
||||
var eastToWest = SpellHelper.GetEastToWest(loc, Location);
|
||||
Effects.PlaySound(loc, Map, 0x20C);
|
||||
var itemID = eastToWest ? 0x398C : 0x3996;
|
||||
|
||||
for (var i = -2; i <= 2; ++i)
|
||||
{
|
||||
var targetLoc = new Point3D(eastToWest ? loc.X + i : loc.X, eastToWest ? loc.Y : loc.Y + i, loc.Z);
|
||||
new FireFieldSpell.FireFieldItem(itemID, targetLoc, m_LitBy, Map, TimeSpan.FromSeconds(9), i);
|
||||
}
|
||||
}
|
||||
|
||||
_timerToken.Cancel();
|
||||
Delete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private void OnFirebombTarget(Mobile from, object obj)
|
||||
switch (_ticks)
|
||||
{
|
||||
if (Deleted || Map == Map.Internal || !IsChildOf(from.Backpack))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is not IPoint3D p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SpellHelper.GetSurfaceTop(ref p);
|
||||
_thrownFromLocation = new Point3D(p);
|
||||
var map = Map;
|
||||
|
||||
from.RevealingAction();
|
||||
|
||||
var to = p as IEntity ?? new Entity(Serial.Zero, _thrownFromLocation, map);
|
||||
|
||||
Effects.SendMovingEffect(from, to, ItemID, 7, 0, false, false, Hue);
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1.0),
|
||||
() =>
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
if (Deleted)
|
||||
++_ticks;
|
||||
|
||||
if (HeldBy != null)
|
||||
{
|
||||
return;
|
||||
HeldBy.PublicOverheadMessage(MessageType.Regular, 957, false, _ticks.ToString());
|
||||
}
|
||||
else if (RootParent == null)
|
||||
{
|
||||
PublicOverheadMessage(MessageType.Regular, 957, false, _ticks.ToString());
|
||||
}
|
||||
else if (RootParent is Mobile mobile)
|
||||
{
|
||||
mobile.PublicOverheadMessage(MessageType.Regular, 957, false, _ticks.ToString());
|
||||
}
|
||||
|
||||
MoveToWorld(_thrownFromLocation, map);
|
||||
break;
|
||||
}
|
||||
);
|
||||
Internalize();
|
||||
}
|
||||
default:
|
||||
{
|
||||
HeldBy?.DropHolding();
|
||||
|
||||
private class ThrowTarget : Target
|
||||
{
|
||||
public ThrowTarget(Firebomb bomb) : base(12, true, TargetFlags.None) => Bomb = bomb;
|
||||
if (_users != null)
|
||||
{
|
||||
foreach (var m in _users)
|
||||
{
|
||||
if (m.Target is ThrowTarget targ && targ.Bomb == this)
|
||||
{
|
||||
Target.Cancel(m);
|
||||
}
|
||||
}
|
||||
|
||||
public Firebomb Bomb { get; }
|
||||
_users.Clear();
|
||||
_users = null;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
Bomb.OnFirebombTarget(from, targeted);
|
||||
}
|
||||
if (RootParent is Mobile parent)
|
||||
{
|
||||
parent.SendLocalizedMessage(1060583); // The firebomb explodes in your hand!
|
||||
AOS.Damage(parent, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
|
||||
}
|
||||
else if (RootParent == null)
|
||||
{
|
||||
var eable = Map.GetMobilesInRange(Location, 1);
|
||||
using var targets = PooledRefQueue<Mobile>.Create();
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (m_LitBy == null || SpellHelper.ValidIndirectTarget(m_LitBy, m) &&
|
||||
m_LitBy.CanBeHarmful(m, false))
|
||||
{
|
||||
targets.Enqueue(m);
|
||||
}
|
||||
}
|
||||
eable.Free();
|
||||
|
||||
while (targets.Count > 0)
|
||||
{
|
||||
var victim = targets.Dequeue();
|
||||
m_LitBy?.DoHarmful(victim);
|
||||
AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
|
||||
}
|
||||
|
||||
var loc = _thrownFromLocation;
|
||||
var eastToWest = SpellHelper.GetEastToWest(loc, Location);
|
||||
Effects.PlaySound(loc, Map, 0x20C);
|
||||
var itemID = eastToWest ? 0x398C : 0x3996;
|
||||
|
||||
for (var i = -2; i <= 2; ++i)
|
||||
{
|
||||
var targetLoc = new Point3D(eastToWest ? loc.X + i : loc.X, eastToWest ? loc.Y : loc.Y + i, loc.Z);
|
||||
new FireFieldSpell.FireFieldItem(itemID, targetLoc, m_LitBy, Map, TimeSpan.FromSeconds(9), i);
|
||||
}
|
||||
}
|
||||
|
||||
_timerToken.Cancel();
|
||||
Delete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFirebombTarget(Mobile from, object obj)
|
||||
{
|
||||
if (Deleted || Map == Map.Internal || !IsChildOf(from.Backpack))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj is not IPoint3D p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SpellHelper.GetSurfaceTop(ref p);
|
||||
_thrownFromLocation = new Point3D(p);
|
||||
var map = Map;
|
||||
|
||||
from.RevealingAction();
|
||||
|
||||
var to = p as IEntity ?? new Entity(Serial.Zero, _thrownFromLocation, map);
|
||||
|
||||
Effects.SendMovingEffect(from, to, ItemID, 7, 0, false, false, Hue);
|
||||
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(1.0),
|
||||
() =>
|
||||
{
|
||||
if (Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MoveToWorld(_thrownFromLocation, map);
|
||||
}
|
||||
);
|
||||
Internalize();
|
||||
}
|
||||
|
||||
private class ThrowTarget : Target
|
||||
{
|
||||
public ThrowTarget(Firebomb bomb) : base(12, true, TargetFlags.None) => Bomb = bomb;
|
||||
|
||||
public Firebomb Bomb { get; }
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted) => Bomb.OnFirebombTarget(from, targeted);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,137 +1,140 @@
|
|||
using System;
|
||||
using Server.Multis;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class FlippableAddonAttribute : Attribute
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class FlippableAddonAttribute : Attribute
|
||||
private static readonly string m_MethodName = "Flip";
|
||||
|
||||
private static readonly Type[] m_Params =
|
||||
{
|
||||
private static readonly string m_MethodName = "Flip";
|
||||
typeof(Mobile), typeof(Direction)
|
||||
};
|
||||
|
||||
private static readonly Type[] m_Params =
|
||||
public FlippableAddonAttribute(params Direction[] directions) => Directions = directions;
|
||||
|
||||
public Direction[] Directions { get; }
|
||||
|
||||
public virtual void Flip(Mobile from, Item addon)
|
||||
{
|
||||
if (!(Directions?.Length > 1))
|
||||
{
|
||||
typeof(Mobile), typeof(Direction)
|
||||
};
|
||||
|
||||
public FlippableAddonAttribute(params Direction[] directions) => Directions = directions;
|
||||
|
||||
public Direction[] Directions { get; }
|
||||
|
||||
public virtual void Flip(Mobile from, Item addon)
|
||||
{
|
||||
if (Directions?.Length > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
var flipMethod = addon.GetType().GetMethod(m_MethodName, m_Params);
|
||||
|
||||
if (flipMethod != null)
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
for (var i = 0; i < Directions.Length; i++)
|
||||
{
|
||||
if (addon.Direction == Directions[i])
|
||||
{
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= Directions.Length)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
ClearComponents(addon);
|
||||
|
||||
flipMethod.Invoke(addon, new object[] { from, Directions[index] });
|
||||
|
||||
BaseHouse house = null;
|
||||
var result = AddonFitResult.Valid;
|
||||
|
||||
addon.Map = Map.Internal;
|
||||
|
||||
if (addon is BaseAddon baseAddon)
|
||||
{
|
||||
result = baseAddon.CouldFit(baseAddon.Location, from.Map, from, ref house);
|
||||
}
|
||||
else if (addon is BaseAddonContainer container)
|
||||
{
|
||||
result = container.CouldFit(container.Location, from.Map, from, ref house);
|
||||
}
|
||||
|
||||
addon.Map = from.Map;
|
||||
|
||||
if (result != AddonFitResult.Valid)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
index = Directions.Length - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
index -= 1;
|
||||
}
|
||||
|
||||
ClearComponents(addon);
|
||||
|
||||
flipMethod.Invoke(addon, new object[] { from, Directions[index] });
|
||||
|
||||
if (result == AddonFitResult.Blocked)
|
||||
{
|
||||
from.SendLocalizedMessage(500269); // You cannot build that there.
|
||||
}
|
||||
else if (result == AddonFitResult.NotInHouse)
|
||||
{
|
||||
from.SendLocalizedMessage(500274); // You can only place this in a house that you own!
|
||||
}
|
||||
else if (result == AddonFitResult.DoorsNotClosed)
|
||||
{
|
||||
from.SendMessage("You must close all house doors before placing this.");
|
||||
}
|
||||
else if (result == AddonFitResult.DoorTooClose)
|
||||
{
|
||||
from.SendLocalizedMessage(500271); // You cannot build near the door.
|
||||
}
|
||||
else if (result == AddonFitResult.NoWall)
|
||||
{
|
||||
from.SendLocalizedMessage(500268); // This object needs to be mounted on something.
|
||||
}
|
||||
}
|
||||
|
||||
addon.Direction = Directions[index];
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private void ClearComponents(Item item)
|
||||
try
|
||||
{
|
||||
if (item is BaseAddon addon)
|
||||
var flipMethod = addon.GetType().GetMethod(m_MethodName, m_Params);
|
||||
|
||||
if (flipMethod == null)
|
||||
{
|
||||
foreach (var c in addon.Components)
|
||||
return;
|
||||
}
|
||||
|
||||
var index = 0;
|
||||
|
||||
for (var i = 0; i < Directions.Length; i++)
|
||||
{
|
||||
if (addon.Direction == Directions[i])
|
||||
{
|
||||
c.Addon = null;
|
||||
c.Delete();
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= Directions.Length)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
ClearComponents(addon);
|
||||
|
||||
flipMethod.Invoke(addon, new object[] { from, Directions[index] });
|
||||
|
||||
BaseHouse house = null;
|
||||
var result = AddonFitResult.Valid;
|
||||
|
||||
addon.Map = Map.Internal;
|
||||
|
||||
if (addon is BaseAddon baseAddon)
|
||||
{
|
||||
result = baseAddon.CouldFit(baseAddon.Location, from.Map, from, ref house);
|
||||
}
|
||||
else if (addon is BaseAddonContainer container)
|
||||
{
|
||||
result = container.CouldFit(container.Location, from.Map, from, ref house);
|
||||
}
|
||||
|
||||
addon.Map = from.Map;
|
||||
|
||||
if (result != AddonFitResult.Valid)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
index = Directions.Length - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
index -= 1;
|
||||
}
|
||||
|
||||
addon.Clear(addon.Components);
|
||||
}
|
||||
else if (item is BaseAddonContainer addonContainer)
|
||||
{
|
||||
foreach (var c in addonContainer.Components)
|
||||
{
|
||||
c.Addon = null;
|
||||
c.Delete();
|
||||
}
|
||||
ClearComponents(addon);
|
||||
|
||||
addonContainer.Clear(addonContainer.Components);
|
||||
flipMethod.Invoke(addon, new object[] { from, Directions[index] });
|
||||
|
||||
if (result == AddonFitResult.Blocked)
|
||||
{
|
||||
from.SendLocalizedMessage(500269); // You cannot build that there.
|
||||
}
|
||||
else if (result == AddonFitResult.NotInHouse)
|
||||
{
|
||||
from.SendLocalizedMessage(500274); // You can only place this in a house that you own!
|
||||
}
|
||||
else if (result == AddonFitResult.DoorsNotClosed)
|
||||
{
|
||||
from.SendMessage("You must close all house doors before placing this.");
|
||||
}
|
||||
else if (result == AddonFitResult.DoorTooClose)
|
||||
{
|
||||
from.SendLocalizedMessage(500271); // You cannot build near the door.
|
||||
}
|
||||
else if (result == AddonFitResult.NoWall)
|
||||
{
|
||||
from.SendLocalizedMessage(500268); // This object needs to be mounted on something.
|
||||
}
|
||||
}
|
||||
|
||||
addon.Direction = Directions[index];
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearComponents(Item item)
|
||||
{
|
||||
if (item is BaseAddon addon)
|
||||
{
|
||||
foreach (var c in addon.Components)
|
||||
{
|
||||
c.Addon = null;
|
||||
c.Delete();
|
||||
}
|
||||
|
||||
addon.Clear(addon.Components);
|
||||
}
|
||||
else if (item is BaseAddonContainer addonContainer)
|
||||
{
|
||||
foreach (var c in addonContainer.Components)
|
||||
{
|
||||
c.Addon = null;
|
||||
c.Delete();
|
||||
}
|
||||
|
||||
addonContainer.Clear(addonContainer.Components);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,99 +1,93 @@
|
|||
using System;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Items
|
||||
namespace Server.Items;
|
||||
|
||||
public static class FlipCommandHandlers
|
||||
{
|
||||
public static class FlipCommandHandlers
|
||||
public static void Initialize()
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("Flip", AccessLevel.GameMaster, Flip_OnCommand);
|
||||
}
|
||||
|
||||
[Usage("Flip"), Description("Turns an item.")]
|
||||
public static void Flip_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
e.Mobile.Target = new FlipTarget();
|
||||
}
|
||||
|
||||
private class FlipTarget : Target
|
||||
{
|
||||
public FlipTarget()
|
||||
: base(-1, false, TargetFlags.None)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (targeted is Item item)
|
||||
{
|
||||
if (item.Movable == false && from.AccessLevel == AccessLevel.Player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var type = item.GetType();
|
||||
|
||||
var AttributeArray =
|
||||
(FlippableAttribute[])type.GetCustomAttributes(typeof(FlippableAttribute), false);
|
||||
|
||||
if (AttributeArray.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var fa = AttributeArray[0];
|
||||
|
||||
fa.Flip(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandSystem.Register("Flip", AccessLevel.GameMaster, Flip_OnCommand);
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class DynamicFlippingAttribute : Attribute
|
||||
[Usage("Flip"), Description("Turns an item.")]
|
||||
public static void Flip_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
e.Mobile.Target = new FlipTarget();
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class FlippableAttribute : Attribute
|
||||
private class FlipTarget : Target
|
||||
{
|
||||
public FlippableAttribute(params int[] itemIDs) => ItemIDs = itemIDs;
|
||||
|
||||
public int[] ItemIDs { get; }
|
||||
|
||||
public virtual void Flip(Item item)
|
||||
public FlipTarget() : base(-1, false, TargetFlags.None)
|
||||
{
|
||||
if (ItemIDs == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
item.GetType().GetMethod("Flip", Type.EmptyTypes)?.Invoke(item, Array.Empty<object>());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = 0;
|
||||
for (var i = 0; i < ItemIDs.Length; i++)
|
||||
{
|
||||
if (item.ItemID == ItemIDs[i])
|
||||
{
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index > ItemIDs.Length - 1)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
item.ItemID = ItemIDs[index];
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (targeted is not Item item || item.Movable == false && from.AccessLevel == AccessLevel.Player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var type = item.GetType();
|
||||
|
||||
var array = (FlippableAttribute[])type.GetCustomAttributes(typeof(FlippableAttribute), false);
|
||||
|
||||
if (array.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var fa = array[0];
|
||||
|
||||
fa.Flip(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class DynamicFlippingAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class FlippableAttribute : Attribute
|
||||
{
|
||||
public FlippableAttribute(params int[] itemIDs) => ItemIDs = itemIDs;
|
||||
|
||||
public int[] ItemIDs { get; }
|
||||
|
||||
public virtual void Flip(Item item)
|
||||
{
|
||||
if (ItemIDs == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
item.GetType().GetMethod("Flip", Type.EmptyTypes)?.Invoke(item, Array.Empty<object>());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = 0;
|
||||
for (var i = 0; i < ItemIDs.Length; i++)
|
||||
{
|
||||
if (item.ItemID == ItemIDs[i])
|
||||
{
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > ItemIDs.Length - 1)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
item.ItemID = ItemIDs[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -76,10 +76,7 @@ namespace Server.Items
|
|||
{
|
||||
private readonly Item m_Item;
|
||||
|
||||
public InternalTimer(Item item) : base(TimeSpan.FromSeconds(30.0))
|
||||
{
|
||||
m_Item = item;
|
||||
}
|
||||
public InternalTimer(Item item) : base(TimeSpan.FromSeconds(30.0)) => m_Item = item;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -145,10 +145,7 @@ namespace Server.Items
|
|||
{
|
||||
private readonly TrashBarrel m_Barrel;
|
||||
|
||||
public EmptyTimer(TrashBarrel barrel) : base(TimeSpan.FromMinutes(3.0))
|
||||
{
|
||||
m_Barrel = barrel;
|
||||
}
|
||||
public EmptyTimer(TrashBarrel barrel) : base(TimeSpan.FromMinutes(3.0)) => m_Barrel = barrel;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -81,11 +81,7 @@ namespace Server.Items
|
|||
{
|
||||
private readonly Item m_Item;
|
||||
|
||||
public SpawnTimer(Item item) : base(TimeSpan.FromSeconds(Utility.RandomMinMax(5, 10)))
|
||||
{
|
||||
|
||||
m_Item = item;
|
||||
}
|
||||
public SpawnTimer(Item item) : base(TimeSpan.FromSeconds(Utility.RandomMinMax(5, 10))) => m_Item = item;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.AniLargeVioletFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.AniRedRibbedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.AniSmallBlueFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.ArcaneGem"
|
||||
}
|
||||
14
Projects/UOContent/Migrations/Server.Items.BankCheck.v0.json
Normal file
14
Projects/UOContent/Migrations/Server.Items.BankCheck.v0.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.BankCheck",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Worth",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.Beeswax"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.Blocker"
|
||||
}
|
||||
4
Projects/UOContent/Migrations/Server.Items.Blood.v0.json
Normal file
4
Projects/UOContent/Migrations/Server.Items.Blood.v0.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.Blood"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.BlueBeaker"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.BlueCurvedFlask"
|
||||
}
|
||||
4
Projects/UOContent/Migrations/Server.Items.Bola.v0.json
Normal file
4
Projects/UOContent/Migrations/Server.Items.Bola.v0.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.Bola"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.BolaBall"
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"version": 1,
|
||||
"type": "Server.Items.BroadcastCrystal",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Charges",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Receivers",
|
||||
"type": "System.Collections.Generic.List\u003CServer.Items.ReceiverCrystal\u003E",
|
||||
"rule": "ListMigrationRule",
|
||||
"ruleArguments": [
|
||||
"",
|
||||
"Server.Items.ReceiverCrystal",
|
||||
"SerializableInterfaceMigrationRule"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.ClockworkAssembly"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.CurvedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.DeceitBrazier",
|
||||
"properties": [
|
||||
{
|
||||
"name": "SpawnRange",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NextSpawnDelay",
|
||||
"type": "System.TimeSpan",
|
||||
"rule": "PrimitiveTypeMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.EffectController",
|
||||
"properties": [
|
||||
{
|
||||
"name": "EffectDelay",
|
||||
"type": "System.TimeSpan",
|
||||
"rule": "PrimitiveTypeMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "TriggerDelay",
|
||||
"type": "System.TimeSpan",
|
||||
"rule": "PrimitiveTypeMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "SoundDelay",
|
||||
"type": "System.TimeSpan",
|
||||
"rule": "PrimitiveTypeMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Source",
|
||||
"type": "Server.IEntity",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Target",
|
||||
"type": "Server.IEntity",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "Sequence",
|
||||
"type": "Server.Items.EffectController",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "FixedDirection",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Explodes",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PlaySoundAtTrigger",
|
||||
"type": "bool",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "EffectType",
|
||||
"type": "Server.Items.ECEffectType",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "EffectLayer",
|
||||
"type": "Server.EffectLayer",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "TriggerType",
|
||||
"type": "Server.Items.EffectTriggerType",
|
||||
"rule": "EnumMigrationRule"
|
||||
},
|
||||
{
|
||||
"name": "EffectItemId",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "EffectHue",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "RenderMode",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Speed",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Duration",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ParticleEffect",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ExplodeParticleEffect",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ExplodeSound",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Unknown",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SoundId",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TriggerRange",
|
||||
"type": "int",
|
||||
"rule": "PrimitiveTypeMigrationRule",
|
||||
"ruleArguments": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.EffectItem"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.EmptyCurvedFlaskE"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.EmptyCurvedFlaskW"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.EmptyRibbedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.EmptyVial"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.EmptyVialsWRack"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.ExecutionersCap"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.Firebomb"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.FullVialsWRack"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.GreenBeaker"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.GreenBottle"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.GreenCurvedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.Hourglass"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.HourglassAni"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.LargeEmptyFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.LargeFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.LargeVioletFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.LargeYellowFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.LongFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.LtBlueCurvedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.MediumFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.ReceiverCrystal",
|
||||
"properties": [
|
||||
{
|
||||
"name": "Sender",
|
||||
"type": "Server.Items.BroadcastCrystal",
|
||||
"rule": "SerializableInterfaceMigrationRule"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.RedBeaker"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.RedBottle"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.RedCurvedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.RedRibbedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallBlueBottle"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallBlueFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallBrownBottle"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallEmptyFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallGreenBottle"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallGreenBottle2"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallRedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallVioletBottle"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SmallYellowFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.SpinningHourglass"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.TinyRedBottle"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.TinyYellowBottle"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.VioletRibbedFlask"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"version": 0,
|
||||
"type": "Server.Items.YellowBeaker"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue