v0.0.1-Alpha (#42)

This commit is contained in:
Kamron Batman 2019-08-02 18:16:11 -07:00 • committed by GitHub
parent d30f93c454
commit a36796c2c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3552 changed files with 2476 additions and 15223 deletions

View file

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using Server.Mobiles;
namespace Server.Items
{
public class AcidSlime : Item
{
private DateTime m_Created;
private bool m_Drying;
private TimeSpan m_Duration;
private int m_MaxDamage;
private int m_MinDamage;
private Timer m_Timer;
[Constructible]
public AcidSlime() : this(TimeSpan.FromSeconds(10.0), 5, 10)
{
}
[Constructible]
public AcidSlime(TimeSpan duration, int minDamage, int maxDamage)
: base(0x122A)
{
Hue = 0x3F;
Movable = false;
m_MinDamage = minDamage;
m_MaxDamage = maxDamage;
m_Created = DateTime.UtcNow;
m_Duration = duration;
m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1), OnTick);
}
public AcidSlime(Serial serial) : base(serial)
{
}
public override string DefaultName => "slime";
public override void OnAfterDelete()
{
m_Timer?.Stop();
}
private void OnTick()
{
DateTime now = DateTime.UtcNow;
TimeSpan age = now - m_Created;
if (age > m_Duration)
{
Delete();
}
else
{
if (!m_Drying && age > m_Duration - age)
{
m_Drying = true;
ItemID = 0x122B;
}
List<Mobile> toDamage = new List<Mobile>();
foreach (Mobile m in GetMobilesInRange(0))
if (m.Alive && !m.IsDeadBondedPet && (!(m is BaseCreature bc) || bc.Controlled || bc.Summoned))
toDamage.Add(m);
for (int i = 0; i < toDamage.Count; i++)
Damage(toDamage[i]);
}
}
public override bool OnMoveOver(Mobile m)
{
Damage(m);
return true;
}
public void Damage(Mobile m)
{
int damage = Utility.RandomMinMax(m_MinDamage, m_MaxDamage);
if (Core.AOS)
AOS.Damage(m, damage, 0, 0, 0, 100, 0);
else
m.Damage(damage);
}
public override void Serialize(GenericWriter writer)
{
}
public override void Deserialize(GenericReader reader)
{
}
}
}

View file

@ -0,0 +1,211 @@
using System.Collections.Generic;
using Server.Targeting;
namespace Server.Items
{
public class ArcaneGem : Item
{
public const int DefaultArcaneHue = 2117;
[Constructible]
public ArcaneGem() : base(0x1EA7)
{
Stackable = Core.ML;
Weight = 1.0;
}
public ArcaneGem(Serial serial) : base(serial)
{
}
public override string DefaultName => "arcane gem";
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)
{
int v = (int)(m.Skills.Tailoring.Value / 5);
if (v < 16)
return 16;
if (v > 24)
return 24;
return v;
}
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;
}
if (obj is IArcaneEquip eq && eq is Item item)
{
BaseClothing clothing = item as BaseClothing;
BaseArmor armor = item as BaseArmor;
BaseWeapon weapon = item as BaseWeapon;
CraftResource 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;
}
int 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)
{
bool 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;
}
else if (armor != null)
{
armor.Quality = ArmorQuality.Regular;
armor.Crafter = from;
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
{
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)
{
List<Item> items = from.Items;
int avail = 0;
for (int i = 0; i < items.Count; ++i)
{
Item obj = items[i];
if (obj is IArcaneEquip eq && eq.IsArcane)
avail += eq.CurArcaneCharges;
}
if (avail < amount)
return false;
for (int i = 0; i < items.Count; ++i)
{
Item 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;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,247 @@
using System;
using System.Globalization;
using Server.Accounting;
using Server.Engines.Quests;
using Server.Engines.Quests.Haven;
using Server.Engines.Quests.Necro;
using Server.Mobiles;
using Server.Network;
using CashBankCheckObjective = Server.Engines.Quests.Necro.CashBankCheckObjective;
namespace Server.Items
{
public class BankCheck : Item
{
private int m_Worth;
public BankCheck(Serial serial) : base(serial)
{
}
[Constructible]
public BankCheck(int worth) : base(0x14F0)
{
Weight = 1.0;
Hue = 0x34;
LootType = LootType.Blessed;
m_Worth = worth;
}
[CommandProperty(AccessLevel.GameMaster)]
public int Worth
{
get => m_Worth;
set
{
m_Worth = value;
InvalidateProperties();
}
}
public override bool DisplayLootType => Core.AOS;
public override int LabelNumber => 1041361; // A bank check
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_Worth);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
LootType = LootType.Blessed;
int version = reader.ReadInt();
switch (version)
{
case 0:
{
m_Worth = reader.ReadInt();
break;
}
}
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
string worth;
if (Core.ML)
worth = m_Worth.ToString("N0", CultureInfo.GetCultureInfo("en-US"));
else
worth = m_Worth.ToString();
list.Add(1060738, worth); // value: ~1_val~
}
public override void OnAdded(IEntity parent)
{
base.OnAdded(parent);
if (!AccountGold.Enabled) return;
Mobile owner = null;
SecureTradeInfo tradeInfo = null;
Container 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 == null || !owner.Account.DepositGold(Worth)) return;
if (tradeInfo != null)
{
if (owner.NetState?.NewSecureTrading == false)
{
int plat = Math.DivRem(Worth, AccountGold.CurrencyThreshold, out int gold);
tradeInfo.Plat += plat;
tradeInfo.Gold += gold;
}
tradeInfo.VirtualCheck?.UpdateTrade(tradeInfo.Mobile);
}
owner.SendLocalizedMessage(1042763, Worth.ToString("#,0"));
Delete();
((Container)parent).UpdateTotals();
}
public override void OnSingleClick(Mobile from)
{
from.Send(
new MessageLocalizedAffix(
Serial,
ItemID,
MessageType.Label,
0x3B2,
3,
1041361,
"",
AffixType.Append,
string.Concat(" ", m_Worth.ToString()),
"")); // A bank check:
}
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.
Container box = AccountGold.Enabled ? from.Backpack : from.FindBankNoCreate();
if (box == null || !IsChildOf(box))
{
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;
}
Delete();
int deposited = 0;
int toAdd = m_Worth;
if (AccountGold.Enabled && from.Account != null && from.Account.DepositGold(toAdd))
{
deposited = toAdd;
toAdd = 0;
}
if (toAdd > 0)
{
Gold gold;
while (toAdd > 60000)
{
gold = new Gold(60000);
if (box.TryDropItem(from, gold, false))
{
toAdd -= 60000;
deposited += 60000;
}
else
{
gold.Delete();
from.AddToBackpack(new BankCheck(toAdd));
toAdd = 0;
break;
}
}
if (toAdd > 0)
{
gold = new Gold(toAdd);
if (box.TryDropItem(from, gold, false))
{
deposited += toAdd;
}
else
{
gold.Delete();
from.AddToBackpack(new BankCheck(toAdd));
}
}
}
// Gold was deposited in your account:
from.SendLocalizedMessage(1042672, true, deposited.ToString("#,0"));
if (from is PlayerMobile pm)
{
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<CashBankCheckObjective>();
if (obj?.Completed == false) obj.Complete();
}
if (qs is UzeraanTurmoilQuest)
{
QuestObjective obj = qs.FindObjective(typeof(Engines.Quests.Haven.CashBankCheckObjective));
if (obj?.Completed == false) obj.Complete();
}
}
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class GlobOfMonstreousInterredGrizzle : Item
{
[Constructible]
public GlobOfMonstreousInterredGrizzle() : base(0x2F3)
{
}
public GlobOfMonstreousInterredGrizzle(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072117; // Glob of Monsterous Interred Grizzle
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class GrizzledSkullCollection : Item
{
[Constructible]
public GrizzledSkullCollection() : base(0x21FC)
{
}
public GrizzledSkullCollection(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072116; // Grizzled Skull collection
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class MonsterousInterredGrizzleMaggots : Item
{
[Constructible]
public MonsterousInterredGrizzleMaggots() : base(0x2633)
{
}
public MonsterousInterredGrizzleMaggots(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1075090; // Monsterous Interred Grizzle Maggots
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class ResolvesBridle : Item
{
[Constructible]
public ResolvesBridle() : base(0x1374)
{
}
public ResolvesBridle(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074761; // Resolve's Bridle
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class TombstoneOfTheDamned : Item
{
[Constructible]
public TombstoneOfTheDamned() : base(Utility.RandomMinMax(0xED7, 0xEDE))
{
}
public TombstoneOfTheDamned(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072123; // Tombstone of the Damned
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class Beeswax : Item
{
[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(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class AbscessTail : Item
{
[Constructible]
public AbscessTail() : base(0x1A9D)
{
LootType = LootType.Blessed;
Hue = 0x51D; // TODO check
}
public AbscessTail(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074231; // Abscess' Tail
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class CoilsFang : Item
{
[Constructible]
public CoilsFang() : base(0x10E8)
{
LootType = LootType.Blessed;
Hue = 0x487;
}
public CoilsFang(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074229; // Coil's Fang
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class EternallyCorruptTree : Item
{
[Constructible]
public EternallyCorruptTree() : base(0x20FA)
{
Hue = Utility.RandomMinMax(0x899, 0x8B0);
}
public EternallyCorruptTree(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072093; // Eternally Corrupt Tree
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class HydraScale : Item
{
[Constructible]
public HydraScale() : base(0x26B4)
{
LootType = LootType.Blessed;
Hue = 0xC2; // TODO check
}
public HydraScale(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074760; // A hydra scale.
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,47 @@
namespace Server.Items
{
public class MelisandesFermentedWine : GreaterExplosionPotion
{
[Constructible]
public MelisandesFermentedWine()
{
Stackable = false;
ItemID = 0x99B;
Hue = Utility.RandomList(0xB, 0xF, 0x48D); // TODO update
}
public MelisandesFermentedWine(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072114; // Melisande's Fermented Wine
public override void Drink(Mobile from)
{
if (MondainsLegacy.CheckML(from))
base.Drink(from);
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
list.Add(1074502); // It looks explosive.
list.Add(1075085); // Requirement: Mondain's Legacy
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,95 @@
using Server.Gumps;
namespace Server.Items
{
public class MelisandesHairDye : Item
{
[Constructible]
public MelisandesHairDye() : base(0xEFF)
{
Hue = Utility.RandomMinMax(0x47E, 0x499);
}
public MelisandesHairDye(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041088; // Hair Dye
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
{
if (MondainsLegacy.CheckML(from))
from.SendGump(new ConfirmGump(this));
}
else
{
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
}
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
list.Add(1075085); // Requirement: Mondain's Legacy
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
private class ConfirmGump : BaseConfirmGump
{
private Item m_Item;
public ConfirmGump(Item item)
{
m_Item = item;
}
public override int TitleNumber => 1074395; // <div align=right>Use Permanent Hair Dye</div>
public override int LabelNumber =>
1074396; // This special hair dye is made of a unique mixture of leaves, permanently changing one's hair color until another dye is used.
public override void Confirm(Mobile from)
{
if (m_Item?.Deleted == false && m_Item.IsChildOf(from.Backpack))
{
if (from.HairItemID != 0)
{
from.HairHue = m_Item.Hue;
from.PlaySound(0x240);
from.SendLocalizedMessage(502622); // You dye your hair.
m_Item.Delete();
}
else
{
from.SendLocalizedMessage(502623); // You have no hair to dye and you cannot use this.
}
}
else
{
from.SendLocalizedMessage(1073461); // You don't have enough dye.
}
}
public override void Refuse(Mobile from)
{
from.SendLocalizedMessage(502620); // You decide not to dye your hair.
}
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class SalivasFeather : Item
{
[Constructible]
public SalivasFeather() : base(0x1020)
{
LootType = LootType.Blessed;
Hue = 0x5C;
}
public SalivasFeather(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074234; // Saliva's Feather
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class SamplesOfCorruptedWater : Item
{
[Constructible]
public SamplesOfCorruptedWater() : base(0xEFE)
{
LootType = LootType.Blessed;
}
public SamplesOfCorruptedWater(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074999; // samples of corrupted water
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class TaintedSeeds : Item
{
[Constructible]
public TaintedSeeds() : base(0xDFA)
{
LootType = LootType.Blessed;
Hue = 0x48; // TODO check
}
public TaintedSeeds(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074233; // Tainted Seeds
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class ThorvaldsMedallion : Item
{
[Constructible]
public ThorvaldsMedallion() : base(0x2AAA)
{
LootType = LootType.Blessed;
Hue = 0x47F; // TODO check
}
public ThorvaldsMedallion(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074232; // Thorvald's Medallion
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class ThrashersTail : Item
{
[Constructible]
public ThrashersTail() : base(0x1A9D)
{
LootType = LootType.Blessed;
Hue = 0x455;
}
public ThrashersTail(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074230; // Thrasher's Tail
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,105 @@
using Server.Network;
namespace Server.Items
{
public class Blocker : Item
{
[Constructible]
public Blocker() : base(0x21A4)
{
Movable = false;
}
public Blocker(Serial serial) : base(serial)
{
}
public override int LabelNumber => 503057; // Impassable!
protected override Packet GetWorldPacketFor(NetState state)
{
Mobile mob = state.Mobile;
if (mob?.AccessLevel >= AccessLevel.GameMaster)
return new GMItemPacket(this);
return base.GetWorldPacketFor(state);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public sealed class GMItemPacket : Packet
{
public GMItemPacket(Item item) : base(0x1A)
{
EnsureCapacity(20);
// 14 base length
// +2 - Amount
// +2 - Hue
// +1 - Flags
uint serial = item.Serial.Value;
int itemID = 0x1183;
int amount = item.Amount;
Point3D loc = item.Location;
int x = loc.X;
int y = loc.Y;
int hue = item.Hue;
int flags = item.GetPacketFlags();
int direction = (int)item.Direction;
if (amount != 0)
serial |= 0x80000000;
else
serial &= 0x7FFFFFFF;
m_Stream.Write(serial);
m_Stream.Write((short)(itemID & 0x7FFF));
if (amount != 0)
m_Stream.Write((short)amount);
x &= 0x7FFF;
if (direction != 0)
x |= 0x8000;
m_Stream.Write((short)x);
y &= 0x3FFF;
if (hue != 0)
y |= 0x8000;
if (flags != 0)
y |= 0x4000;
m_Stream.Write((short)y);
if (direction != 0)
m_Stream.Write((byte)direction);
m_Stream.Write((sbyte)loc.Z);
if (hue != 0)
m_Stream.Write((ushort)hue);
if (flags != 0)
m_Stream.Write((byte)flags);
}
}
}
}

View file

@ -0,0 +1,56 @@
using System;
namespace Server.Items
{
public class Blood : Item
{
[Constructible]
public Blood() : this(Utility.RandomList(0x1645, 0x122A, 0x122B, 0x122C, 0x122D, 0x122E, 0x122F))
{
}
[Constructible]
public Blood(int itemID) : base(itemID)
{
Movable = false;
new InternalTimer(this).Start();
}
public Blood(Serial serial) : base(serial)
{
new InternalTimer(this).Start();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
private class InternalTimer : Timer
{
private Item m_Blood;
public InternalTimer(Item blood) : base(TimeSpan.FromSeconds(5.0))
{
Priority = TimerPriority.OneSecond;
m_Blood = blood;
}
protected override void OnTick()
{
m_Blood.Delete();
}
}
}
}

View file

@ -0,0 +1,212 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Spells.Ninjitsu;
using Server.Targeting;
namespace Server.Items
{
public class Bola : Item
{
[Constructible]
public Bola(int amount = 1) : base(0x26AC)
{
Weight = 4.0;
Stackable = true;
Amount = amount;
}
public Bola(Serial serial) : base(serial)
{
}
public override void OnDoubleClick(Mobile from)
{
if (!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
}
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...*
from.NonlocalOverheadMessage(MessageType.Emote, 0x3B2, 1049633,
from.Name); // ~1_NAME~ begins to menacingly swing a bola...
}
}
private static void FinishThrow(Mobile from, Mobile to)
{
if (Core.AOS)
new Bola().MoveToWorld(to.Location, to.Map);
if (to is ChaosDragoon || to is ChaosDragoonElite)
from.SendLocalizedMessage(1042047); // You fail to knock the rider from its mount.
IMount mt = to.Mount;
if (mt != null && !(to is ChaosDragoon || to is 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.DelayCall(TimeSpan.FromSeconds(2.0), () => from.EndAction<Bola>());
}
private static bool HasFreeHands(Mobile from)
{
Item one = from.FindItemOnLayer(Layer.OneHanded);
Item two = from.FindItemOnLayer(Layer.TwoHanded);
if (Core.SE)
{
Container 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(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public class BolaTarget : Target
{
private 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.DelayCall(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.
}
}
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class BolaBall : Item
{
[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(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,615 @@
using System;
using System.Collections.Generic;
using Server.Network;
using Server.Targeting;
namespace Server.Items
{
[Flippable(0x1E5E, 0x1E5F)]
public class BulletinBoard : BaseBulletinBoard
{
[Constructible]
public BulletinBoard() : base(0x1E5E)
{
}
public BulletinBoard(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public abstract class BaseBulletinBoard : Item
{
// Threads will be removed six hours after the last post was made
private static TimeSpan ThreadDeletionTime = TimeSpan.FromHours(6.0);
// A player may only create a thread once every two minutes
private static TimeSpan ThreadCreateTime = TimeSpan.FromMinutes(2.0);
// A player may only reply once every thirty seconds
private static TimeSpan ThreadReplyTime = TimeSpan.FromSeconds(30.0);
public BaseBulletinBoard(int itemID) : base(itemID)
{
BoardName = "bulletin board";
Movable = false;
}
public BaseBulletinBoard(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public string BoardName{ get; set; }
public static bool CheckTime(DateTime time, TimeSpan range)
{
return time + range < DateTime.UtcNow;
}
public static string FormatTS(TimeSpan ts)
{
int totalSeconds = (int)ts.TotalSeconds;
int seconds = totalSeconds % 60;
int minutes = totalSeconds / 60;
if (minutes != 0 && seconds != 0)
return $"{minutes} minute{(minutes == 1 ? "" : "s")} and {seconds} second{(seconds == 1 ? "" : "s")}";
if (minutes != 0)
return $"{minutes} minute{(minutes == 1 ? "" : "s")}";
return $"{seconds} second{(seconds == 1 ? "" : "s")}";
}
public virtual void Cleanup()
{
List<Item> items = Items;
for (int i = items.Count - 1; i >= 0; --i)
{
if (i >= items.Count)
continue;
if (!(items[i] is BulletinMessage msg))
continue;
if (msg.Thread == null && CheckTime(msg.LastPostTime, ThreadDeletionTime))
{
msg.Delete();
RecurseDelete(msg); // A root-level thread has expired
}
}
}
private void RecurseDelete(BulletinMessage msg)
{
List<Item> found = new List<Item>();
List<Item> items = Items;
for (int i = items.Count - 1; i >= 0; --i)
{
if (i >= items.Count)
continue;
if (!(items[i] is BulletinMessage check))
continue;
if (check.Thread == msg)
{
check.Delete();
found.Add(check);
}
}
for (int i = 0; i < found.Count; ++i)
RecurseDelete((BulletinMessage)found[i]);
}
public virtual bool GetLastPostTime(Mobile poster, bool onlyCheckRoot, ref DateTime lastPostTime)
{
List<Item> items = Items;
bool wasSet = false;
for (int i = 0; i < items.Count; ++i)
{
if (!(items[i] is BulletinMessage msg) || msg.Poster != poster)
continue;
if (onlyCheckRoot && msg.Thread != null)
continue;
if (msg.Time > lastPostTime)
{
wasSet = true;
lastPostTime = msg.Time;
}
}
return wasSet;
}
public override void OnDoubleClick(Mobile from)
{
if (CheckRange(from))
{
Cleanup();
NetState state = from.NetState;
state.Send(new BBDisplayBoard(this));
if (state.ContainerGridLines)
state.Send(new ContainerContent6017(from, this));
else
state.Send(new ContainerContent(from, this));
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
}
}
public virtual bool CheckRange(Mobile from)
{
if (from.AccessLevel >= AccessLevel.GameMaster)
return true;
return from.Map == Map && from.InRange(GetWorldLocation(), 2);
}
public void PostMessage(Mobile from, BulletinMessage thread, string subject, string[] lines)
{
if (thread != null)
thread.LastPostTime = DateTime.UtcNow;
AddItem(new BulletinMessage(from, thread, subject, lines));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(BoardName);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
BoardName = reader.ReadString();
break;
}
}
}
public static void Initialize()
{
PacketHandlers.Register(0x71, 0, true, BBClientRequest);
}
public static void BBClientRequest(NetState state, PacketReader pvSrc)
{
Mobile from = state.Mobile;
int packetID = pvSrc.ReadByte();
if (!(World.FindItem(pvSrc.ReadUInt32()) is BaseBulletinBoard board) || !board.CheckRange(from))
return;
switch (packetID)
{
case 3:
BBRequestContent(from, board, pvSrc);
break;
case 4:
BBRequestHeader(from, board, pvSrc);
break;
case 5:
BBPostMessage(from, board, pvSrc);
break;
case 6:
BBRemoveMessage(from, board, pvSrc);
break;
}
}
public static void BBRequestContent(Mobile from, BaseBulletinBoard board, PacketReader pvSrc)
{
if (!(World.FindItem(pvSrc.ReadUInt32()) is BulletinMessage msg) || msg.Parent != board)
return;
from.Send(new BBMessageContent(board, msg));
}
public static void BBRequestHeader(Mobile from, BaseBulletinBoard board, PacketReader pvSrc)
{
if (!(World.FindItem(pvSrc.ReadUInt32()) is BulletinMessage msg) || msg.Parent != board)
return;
from.Send(new BBMessageHeader(board, msg));
}
public static void BBPostMessage(Mobile from, BaseBulletinBoard board, PacketReader pvSrc)
{
BulletinMessage thread = World.FindItem(pvSrc.ReadUInt32()) as BulletinMessage;
if (thread != null && thread.Parent != board)
thread = null;
int breakout = 0;
while (thread?.Thread != null && breakout++ < 10)
thread = thread.Thread;
DateTime lastPostTime = DateTime.MinValue;
if (board.GetLastPostTime(from, thread == null, ref lastPostTime))
if (!CheckTime(lastPostTime, thread == null ? ThreadCreateTime : ThreadReplyTime))
{
if (thread == null)
from.SendMessage("You must wait {0} before creating a new thread.", FormatTS(ThreadCreateTime));
else
from.SendMessage("You must wait {0} before replying to another thread.", FormatTS(ThreadReplyTime));
return;
}
string subject = pvSrc.ReadUTF8StringSafe(pvSrc.ReadByte());
if (subject.Length == 0)
return;
string[] lines = new string[pvSrc.ReadByte()];
if (lines.Length == 0)
return;
for (int i = 0; i < lines.Length; ++i)
lines[i] = pvSrc.ReadUTF8StringSafe(pvSrc.ReadByte());
board.PostMessage(from, thread, subject, lines);
}
public static void BBRemoveMessage(Mobile from, BaseBulletinBoard board, PacketReader pvSrc)
{
if (!(World.FindItem(pvSrc.ReadUInt32()) is BulletinMessage msg) || msg.Parent != board)
return;
if (from.AccessLevel < AccessLevel.GameMaster && msg.Poster != from)
return;
msg.Delete();
}
}
public struct BulletinEquip
{
public int itemID;
public int hue;
public BulletinEquip(int itemID, int hue)
{
this.itemID = itemID;
this.hue = hue;
}
}
public class BulletinMessage : Item
{
public BulletinMessage(Mobile poster, BulletinMessage thread, string subject, string[] lines) : base(0xEB0)
{
Movable = false;
Poster = poster;
Subject = subject;
Time = DateTime.UtcNow;
LastPostTime = Time;
Thread = thread;
PostedName = Poster.Name;
PostedBody = Poster.Body;
PostedHue = Poster.Hue;
Lines = lines;
List<BulletinEquip> list = new List<BulletinEquip>();
for (int i = 0; i < poster.Items.Count; ++i)
{
Item item = poster.Items[i];
if (item.Layer >= Layer.OneHanded && item.Layer <= Layer.Mount)
list.Add(new BulletinEquip(item.ItemID, item.Hue));
}
PostedEquip = list.ToArray();
}
public BulletinMessage(Serial serial) : base(serial)
{
}
public Mobile Poster{ get; private set; }
public BulletinMessage Thread{ get; private set; }
public string Subject{ get; private set; }
public DateTime Time{ get; private set; }
public DateTime LastPostTime{ get; set; }
public string PostedName{ get; private set; }
public int PostedBody{ get; private set; }
public int PostedHue{ get; private set; }
public BulletinEquip[] PostedEquip{ get; private set; }
public string[] Lines{ get; private set; }
public string GetTimeAsString()
{
return Time.ToString("MMM dd, yyyy");
}
public override bool CheckTarget(Mobile from, Target targ, object targeted)
{
return false;
}
public override bool IsAccessibleTo(Mobile check)
{
return false;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
writer.Write(Poster);
writer.Write(Subject);
writer.Write(Time);
writer.Write(LastPostTime);
writer.Write(Thread != null);
writer.Write(Thread);
writer.Write(PostedName);
writer.Write(PostedBody);
writer.Write(PostedHue);
writer.Write(PostedEquip.Length);
for (int i = 0; i < PostedEquip.Length; ++i)
{
writer.Write(PostedEquip[i].itemID);
writer.Write(PostedEquip[i].hue);
}
writer.Write(Lines.Length);
for (int i = 0; i < Lines.Length; ++i)
writer.Write(Lines[i]);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 1:
case 0:
{
Poster = reader.ReadMobile();
Subject = reader.ReadString();
Time = reader.ReadDateTime();
LastPostTime = reader.ReadDateTime();
bool hasThread = reader.ReadBool();
Thread = reader.ReadItem() as BulletinMessage;
PostedName = reader.ReadString();
PostedBody = reader.ReadInt();
PostedHue = reader.ReadInt();
PostedEquip = new BulletinEquip[reader.ReadInt()];
for (int i = 0; i < PostedEquip.Length; ++i)
{
PostedEquip[i].itemID = reader.ReadInt();
PostedEquip[i].hue = reader.ReadInt();
}
Lines = new string[reader.ReadInt()];
for (int i = 0; i < Lines.Length; ++i)
Lines[i] = reader.ReadString();
if (hasThread && Thread == null)
Delete();
if (version == 0)
ValidationQueue<BulletinMessage>.Add(this);
break;
}
}
}
public void Validate()
{
if ((Parent as BulletinBoard)?.Items.Contains(this) == false)
Delete();
}
}
public class BBDisplayBoard : Packet
{
public BBDisplayBoard(BaseBulletinBoard board) : base(0x71)
{
EnsureCapacity(38);
byte[] buffer = Utility.UTF8.GetBytes(board.BoardName ?? "");
m_Stream.Write((byte)0x00); // PacketID
m_Stream.Write(board.Serial); // Bulletin board serial
// Bulletin board name
if (buffer.Length >= 29)
{
m_Stream.Write(buffer, 0, 29);
m_Stream.Write((byte)0);
}
else
{
m_Stream.Write(buffer, 0, buffer.Length);
m_Stream.Fill(30 - buffer.Length);
}
}
}
public class BBMessageHeader : Packet
{
public BBMessageHeader(BaseBulletinBoard board, BulletinMessage msg) : base(0x71)
{
string poster = SafeString(msg.PostedName);
string subject = SafeString(msg.Subject);
string time = SafeString(msg.GetTimeAsString());
EnsureCapacity(22 + poster.Length + subject.Length + time.Length);
m_Stream.Write((byte)0x01); // PacketID
m_Stream.Write(board.Serial); // Bulletin board serial
m_Stream.Write(msg.Serial); // Message serial
BulletinMessage thread = msg.Thread;
if (thread == null)
m_Stream.Write(0); // Thread serial--root
else
m_Stream.Write(thread.Serial); // Thread serial--parent
WriteString(poster);
WriteString(subject);
WriteString(time);
}
public void WriteString(string v)
{
byte[] buffer = Utility.UTF8.GetBytes(v);
int len = buffer.Length + 1;
if (len > 255)
len = 255;
m_Stream.Write((byte)len);
m_Stream.Write(buffer, 0, len - 1);
m_Stream.Write((byte)0);
}
public string SafeString(string v)
{
return v ?? string.Empty;
}
}
public class BBMessageContent : Packet
{
public BBMessageContent(BaseBulletinBoard board, BulletinMessage msg) : base(0x71)
{
string poster = SafeString(msg.PostedName);
string subject = SafeString(msg.Subject);
string time = SafeString(msg.GetTimeAsString());
EnsureCapacity(22 + poster.Length + subject.Length + time.Length);
m_Stream.Write((byte)0x02); // PacketID
m_Stream.Write(board.Serial); // Bulletin board serial
m_Stream.Write(msg.Serial); // Message serial
WriteString(poster);
WriteString(subject);
WriteString(time);
m_Stream.Write((short)msg.PostedBody);
m_Stream.Write((short)msg.PostedHue);
int len = msg.PostedEquip.Length;
if (len > 255)
len = 255;
m_Stream.Write((byte)len);
for (int i = 0; i < len; ++i)
{
BulletinEquip eq = msg.PostedEquip[i];
m_Stream.Write((short)eq.itemID);
m_Stream.Write((short)eq.hue);
}
len = msg.Lines.Length;
if (len > 255)
len = 255;
m_Stream.Write((byte)len);
for (int i = 0; i < len; ++i)
WriteString(msg.Lines[i], true);
}
public void WriteString(string v)
{
WriteString(v, false);
}
public void WriteString(string v, bool padding)
{
byte[] buffer = Utility.UTF8.GetBytes(v);
int tail = padding ? 2 : 1;
int len = buffer.Length + tail;
if (len > 255)
len = 255;
m_Stream.Write((byte)len);
m_Stream.Write(buffer, 0, len - tail);
if (padding)
m_Stream.Write((short)0); // padding compensates for a client bug
else
m_Stream.Write((byte)0);
}
public string SafeString(string v)
{
if (v == null)
return string.Empty;
return v;
}
}
}

View file

@ -0,0 +1,129 @@
using Server.Mobiles;
namespace Server.Items
{
public class ClockworkAssembly : Item
{
[Constructible]
public ClockworkAssembly() : base(0x1EA8)
{
Weight = 5.0;
Hue = 1102;
}
public ClockworkAssembly(Serial serial) : base(serial)
{
}
public override string DefaultName => "clockwork assembly";
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
return;
}
double 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;
}
if (from.Followers + 4 > from.FollowersMax)
{
from.SendLocalizedMessage(1049607); // You have too many followers to control that creature.
return;
}
double scalar;
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;
Container pack = from.Backpack;
if (pack == null)
return;
int res = pack.ConsumeTotal(
new[]
{
typeof(PowerCrystal),
typeof(IronIngot),
typeof(BronzeIngot),
typeof(Gears)
},
new[]
{
1,
50,
50,
5
});
switch (res)
{
case 0:
{
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:
{
Golem g = new Golem(true, scalar);
if (g.SetControlMaster(from))
{
Delete();
g.MoveToWorld(from.Location, from.Map);
from.PlaySound(0x241);
}
break;
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,450 @@
using System;
using System.Collections.Generic;
using Server.Network;
using Server.Targeting;
namespace Server.Items
{
public class CrystalRechargeInfo
{
public static readonly CrystalRechargeInfo[] Table =
{
new CrystalRechargeInfo(typeof(Citrine), 500),
new CrystalRechargeInfo(typeof(Amber), 500),
new CrystalRechargeInfo(typeof(Tourmaline), 750),
new CrystalRechargeInfo(typeof(Emerald), 1000),
new CrystalRechargeInfo(typeof(Sapphire), 1000),
new CrystalRechargeInfo(typeof(Amethyst), 1000),
new CrystalRechargeInfo(typeof(StarSapphire), 1250),
new CrystalRechargeInfo(typeof(Diamond), 2000)
};
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 (CrystalRechargeInfo info in Table)
if (info.Type == type)
return info;
return null;
}
}
public class BroadcastCrystal : Item
{
public static readonly int MaxCharges = 2000;
private int m_Charges;
[Constructible]
public BroadcastCrystal(int charges = 2000) : base(0x1ED0)
{
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(ObjectPropertyList list)
{
base.GetProperties(list);
list.Add(Active ? 1060742 : 1060743); // active / inactive
list.Add(1060745); // broadcast
list.Add(1060741, Charges.ToString()); // charges: ~1_val~
if (Receivers.Count > 0)
list.Add(1060746, Receivers.Count.ToString()); // 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 Mobile))
return;
if (e.Type == MessageType.Emote)
return;
Mobile from = e.Mobile;
string speech = e.Speech;
foreach (ReceiverCrystal 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(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(m_Charges);
writer.WriteItemList(Receivers);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
m_Charges = reader.ReadEncodedInt();
Receivers = reader.ReadStrongItemList<ReceiverCrystal>();
}
private class InternalTarget : Target
{
private 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 (ReceiverCrystal 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))
{
CrystalRechargeInfo 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.
}
}
}
}
public class ReceiverCrystal : Item
{
private BroadcastCrystal m_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();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public BroadcastCrystal Sender
{
get => m_Sender;
set
{
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(ObjectPropertyList 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;
string 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);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.WriteItem(m_Sender);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
m_Sender = reader.ReadItem<BroadcastCrystal>();
}
private class InternalTarget : Target
{
private 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))
{
CrystalRechargeInfo 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.
}
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
using System;
namespace Server
{
[AttributeUsage(AttributeTargets.Class)]
public class CorpseNameAttribute : Attribute
{
public CorpseNameAttribute(string name)
{
Name = name;
}
public string Name{ get; }
}
}

View file

@ -0,0 +1,111 @@
using System;
namespace Server.Items
{
public class DecayedCorpse : Container
{
private static TimeSpan m_DefaultDecayTime = TimeSpan.FromMinutes(7.0);
private DateTime m_DecayTime;
private Timer m_DecayTimer;
public DecayedCorpse(string name) : base(Utility.Random(0xECA, 9))
{
Movable = false;
Name = name;
BeginDecay(m_DefaultDecayTime);
}
public DecayedCorpse(Serial serial) : base(serial)
{
}
// Do not display (x items, y stones)
public override bool DisplaysContent => false;
public void BeginDecay(TimeSpan delay)
{
m_DecayTimer?.Stop();
m_DecayTime = DateTime.UtcNow + delay;
m_DecayTimer = new InternalTimer(this, delay);
m_DecayTimer.Start();
}
public override void OnAfterDelete()
{
m_DecayTimer?.Stop();
m_DecayTimer = null;
}
// Do not display (x items, y stones)
public override bool CheckContentDisplay(Mobile from)
{
return false;
}
public override void AddNameProperty(ObjectPropertyList list)
{
list.Add(1046414, Name); // the remains of ~1_NAME~
}
public override void OnSingleClick(Mobile from)
{
LabelTo(from, 1046414, Name); // the remains of ~1_NAME~
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
writer.Write(m_DecayTimer != null);
if (m_DecayTimer != null)
writer.WriteDeltaTime(m_DecayTime);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
BeginDecay(m_DefaultDecayTime);
break;
}
case 1:
{
if (reader.ReadBool())
BeginDecay(reader.ReadDeltaTime() - DateTime.UtcNow);
break;
}
}
}
private class InternalTimer : Timer
{
private DecayedCorpse m_Corpse;
public InternalTimer(DecayedCorpse c, TimeSpan delay) : base(delay)
{
m_Corpse = c;
Priority = TimerPriority.FiveSeconds;
}
protected override void OnTick()
{
m_Corpse.Delete();
}
}
}
}

View file

@ -0,0 +1,198 @@
using System.Collections.Generic;
using System.IO;
using Server.Items;
namespace Server.Network
{
public sealed class CorpseEquip : Packet
{
public CorpseEquip(Mobile beholder, Corpse beheld) : base(0x89)
{
List<Item> list = beheld.EquipItems;
int count = list.Count;
if (beheld.Hair != null && beheld.Hair.ItemID > 0)
count++;
if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0)
count++;
EnsureCapacity(8 + count * 5);
m_Stream.Write(beheld.Serial);
for (int i = 0; i < list.Count; ++i)
{
Item item = list[i];
if (!item.Deleted && beholder.CanSee(item) && item.Parent == beheld)
{
m_Stream.Write((byte)(item.Layer + 1));
m_Stream.Write(item.Serial);
}
}
if (beheld.Hair != null && beheld.Hair.ItemID > 0)
{
m_Stream.Write((byte)(Layer.Hair + 1));
m_Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2);
}
if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0)
{
m_Stream.Write((byte)(Layer.FacialHair + 1));
m_Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2);
}
m_Stream.Write((byte)Layer.Invalid);
}
}
public sealed class CorpseContent : Packet
{
public CorpseContent(Mobile beholder, Corpse beheld)
: base(0x3C)
{
List<Item> items = beheld.EquipItems;
int count = items.Count;
if (beheld.Hair != null && beheld.Hair.ItemID > 0)
count++;
if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0)
count++;
EnsureCapacity(5 + count * 19);
long pos = m_Stream.Position;
int written = 0;
m_Stream.Write((ushort)0);
for (int i = 0; i < items.Count; ++i)
{
Item child = items[i];
if (!child.Deleted && child.Parent == beheld && beholder.CanSee(child))
{
m_Stream.Write(child.Serial);
m_Stream.Write((ushort)child.ItemID);
m_Stream.Write((byte)0); // signed, itemID offset
m_Stream.Write((ushort)child.Amount);
m_Stream.Write((short)child.X);
m_Stream.Write((short)child.Y);
m_Stream.Write(beheld.Serial);
m_Stream.Write((ushort)child.Hue);
++written;
}
}
if (beheld.Hair != null && beheld.Hair.ItemID > 0)
{
m_Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2);
m_Stream.Write((ushort)beheld.Hair.ItemID);
m_Stream.Write((byte)0); // signed, itemID offset
m_Stream.Write((ushort)1);
m_Stream.Write((short)0);
m_Stream.Write((short)0);
m_Stream.Write(beheld.Serial);
m_Stream.Write((ushort)beheld.Hair.Hue);
++written;
}
if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0)
{
m_Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2);
m_Stream.Write((ushort)beheld.FacialHair.ItemID);
m_Stream.Write((byte)0); // signed, itemID offset
m_Stream.Write((ushort)1);
m_Stream.Write((short)0);
m_Stream.Write((short)0);
m_Stream.Write(beheld.Serial);
m_Stream.Write((ushort)beheld.FacialHair.Hue);
++written;
}
m_Stream.Seek(pos, SeekOrigin.Begin);
m_Stream.Write((ushort)written);
}
}
public sealed class CorpseContent6017 : Packet
{
public CorpseContent6017(Mobile beholder, Corpse beheld)
: base(0x3C)
{
List<Item> items = beheld.EquipItems;
int count = items.Count;
if (beheld.Hair != null && beheld.Hair.ItemID > 0)
count++;
if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0)
count++;
EnsureCapacity(5 + count * 20);
long pos = m_Stream.Position;
int written = 0;
m_Stream.Write((ushort)0);
for (int i = 0; i < items.Count; ++i)
{
Item child = items[i];
if (!child.Deleted && child.Parent == beheld && beholder.CanSee(child))
{
m_Stream.Write(child.Serial);
m_Stream.Write((ushort)child.ItemID);
m_Stream.Write((byte)0); // signed, itemID offset
m_Stream.Write((ushort)child.Amount);
m_Stream.Write((short)child.X);
m_Stream.Write((short)child.Y);
m_Stream.Write((byte)0); // Grid Location?
m_Stream.Write(beheld.Serial);
m_Stream.Write((ushort)child.Hue);
++written;
}
}
if (beheld.Hair != null && beheld.Hair.ItemID > 0)
{
m_Stream.Write(HairInfo.FakeSerial(beheld.Owner) - 2);
m_Stream.Write((ushort)beheld.Hair.ItemID);
m_Stream.Write((byte)0); // signed, itemID offset
m_Stream.Write((ushort)1);
m_Stream.Write((short)0);
m_Stream.Write((short)0);
m_Stream.Write((byte)0); // Grid Location?
m_Stream.Write(beheld.Serial);
m_Stream.Write((ushort)beheld.Hair.Hue);
++written;
}
if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0)
{
m_Stream.Write(FacialHairInfo.FakeSerial(beheld.Owner) - 2);
m_Stream.Write((ushort)beheld.FacialHair.ItemID);
m_Stream.Write((byte)0); // signed, itemID offset
m_Stream.Write((ushort)1);
m_Stream.Write((short)0);
m_Stream.Write((short)0);
m_Stream.Write((byte)0); // Grid Location?
m_Stream.Write(beheld.Serial);
m_Stream.Write((ushort)beheld.FacialHair.Hue);
++written;
}
m_Stream.Seek(pos, SeekOrigin.Begin);
m_Stream.Write((ushort)written);
}
}
}

View file

@ -0,0 +1,233 @@
using System;
using Server.Mobiles;
using Server.Network;
namespace Server.Items
{
public class DeceitBrazier : Item
{
private Timer m_Timer;
[Constructible]
public DeceitBrazier() : base(0xE31)
{
Movable = false;
Light = LightType.Circle225;
NextSpawn = DateTime.UtcNow;
NextSpawnDelay = TimeSpan.FromMinutes(15.0);
SpawnRange = 5;
}
public DeceitBrazier(Serial serial) : base(serial)
{
}
public static Type[] Creatures{ get; } =
{
#region Animals
typeof(FireSteed), //Set the tents up people!
#endregion
#region Undead
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),
#endregion
#region Demons
typeof(Balron), typeof(Daemon), typeof(Imp), typeof(GreaterMongbat),
typeof(Mongbat), typeof(IceFiend), typeof(Gargoyle), typeof(StoneGargoyle),
typeof(FireGargoyle), typeof(HordeMinion),
#endregion
#region Gazers
typeof(Gazer), typeof(ElderGazer), typeof(GazerLarva),
#endregion
#region Uncategorized
typeof(Harpy), typeof(StoneHarpy), typeof(HeadlessOne), typeof(HellHound),
typeof(HellCat), typeof(Phoenix), typeof(LavaLizard), typeof(SandVortex),
typeof(ShadowWisp), typeof(SwampTentacle), typeof(PredatorHellCat), typeof(Wisp),
#endregion
#region Arachnid
typeof(GiantSpider), typeof(DreadSpider), typeof(FrostSpider), typeof(Scorpion),
#endregion
#region Repond
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),
#endregion
#region Reptilian
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),
#endregion
#region Elementals
typeof(EarthElemental), typeof(PoisonElemental), typeof(FireElemental), typeof(SnowElemental),
typeof(IceElemental), typeof(AcidElemental), typeof(WaterElemental), typeof(Efreet),
typeof(AirElemental), typeof(Golem),
#endregion
#region Random Critters
typeof(SewerRat), typeof(GiantRat), typeof(DireWolf), typeof(TimberWolf),
typeof(Cougar), typeof(Alligator)
#endregion
};
[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(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(SpawnRange);
writer.Write(NextSpawnDelay);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version >= 0)
{
SpawnRange = reader.ReadInt();
NextSpawnDelay = reader.ReadTimeSpan();
}
NextSpawn = DateTime.UtcNow;
}
public virtual void HeedWarning()
{
PublicOverheadMessage(MessageType.Regular, 0x3B2,
500761); // Heed this warning well, and use this brazier at your own peril.
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (NextSpawn < DateTime.UtcNow) // means we haven't spawned anything if the next spawn is below
if (Utility.InRange(m.Location, Location, 1) && !Utility.InRange(oldLocation, Location, 1) && m.Player &&
!(m.AccessLevel > AccessLevel.Player || m.Hidden))
if (m_Timer == null || !m_Timer.Running)
m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(2), HeedWarning);
base.OnMovement(m, oldLocation);
}
public Point3D GetSpawnPosition()
{
Map map = Map;
if (map == null)
return Location;
// Try 10 times to find a Spawnable location.
for (int i = 0; i < 10; i++)
{
int x = Location.X + (Utility.Random(SpawnRange * 2 + 1) - SpawnRange);
int y = Location.Y + (Utility.Random(SpawnRange * 2 + 1) - SpawnRange);
int 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)
{
Effects.SendLocationParticles(EffectItem.Create(loc, map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052);
Effects.PlaySound(loc, map, 0x225);
}
public override void OnDoubleClick(Mobile from)
{
if (Utility.InRange(from.Location, Location, 2))
try
{
if (NextSpawn < DateTime.UtcNow)
{
Map map = Map;
BaseCreature bc =
(BaseCreature)Activator.CreateInstance(Creatures[Utility.Random(Creatures.Length)]);
Point3D spawnLoc = GetSpawnPosition();
DoEffect(spawnLoc, map);
Timer.DelayCall(TimeSpan.FromSeconds(1), delegate
{
bc.Home = Location;
bc.RangeHome = SpawnRange;
bc.FightMode = FightMode.Closest;
bc.MoveToWorld(spawnLoc, map);
DoEffect(spawnLoc, map);
bc.ForceReacquire();
});
NextSpawn = DateTime.UtcNow + NextSpawnDelay;
}
else
{
PublicOverheadMessage(MessageType.Regular, 0x3B2,
500760); // The brazier fizzes and pops, but nothing seems to happen.
}
}
catch
{
// ignored
}
else
from.SendLocalizedMessage(500446); // That is too far away.
}
}
}

View file

@ -0,0 +1,340 @@
using System;
namespace Server.Items
{
public enum ECEffectType
{
None,
Moving,
Location,
Target,
Lightning
}
public enum EffectTriggerType
{
None,
Sequenced,
DoubleClick,
InRange
}
public class EffectController : Item
{
private IEntity m_Source;
private IEntity m_Target;
[Constructible]
public EffectController() : base(0x1B72)
{
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) m_Source = null;
}
}
[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) m_Target = null;
}
}
[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(GenericWriter 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);
}
private IEntity ReadEntity(GenericReader reader)
{
return World.FindEntity(reader.ReadUInt());
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
EffectDelay = reader.ReadTimeSpan();
TriggerDelay = reader.ReadTimeSpan();
SoundDelay = reader.ReadTimeSpan();
m_Source = ReadEntity(reader);
m_Target = ReadEntity(reader);
Sequence = reader.ReadItem() as 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;
}
}
}
public void PlaySound(IEntity trigger)
{
IEntity ent = null;
if (PlaySoundAtTrigger)
ent = trigger;
if (ent == null)
ent = 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 mobile && mobile.Hidden && mobile.AccessLevel > AccessLevel.Player)
return;
if (SoundID > 0)
Timer.DelayCall(SoundDelay, PlaySound, trigger);
if (Sequence != null)
Timer.DelayCall(TriggerDelay, Sequence.DoEffect, trigger);
if (EffectType != ECEffectType.None)
Timer.DelayCall(EffectDelay, InternalDoEffect, trigger);
}
public void InternalDoEffect(IEntity trigger)
{
IEntity from = m_Source, to = m_Target;
if (from == null)
from = trigger;
if (to == null)
to = trigger;
switch (EffectType)
{
case ECEffectType.Lightning:
{
Effects.SendBoltEffect(from, false, EffectHue);
break;
}
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;
}
}
}
}
}

View file

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
namespace Server.Items
{
public class EffectItem : Item
{
private static List<EffectItem> m_Free = new List<EffectItem>(); // List of available EffectItems
public static readonly TimeSpan DefaultDuration = TimeSpan.FromSeconds(5.0);
private EffectItem() : base(1) // nodraw
{
Movable = false;
}
public EffectItem(Serial serial) : base(serial)
{
}
public override bool Decays => true;
public static EffectItem Create(Point3D p, Map map, TimeSpan duration)
{
EffectItem item = null;
for (int i = m_Free.Count - 1; item == null && i >= 0; --i) // We reuse new entries first so decay works better
{
EffectItem 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;
}
public void BeginFree(TimeSpan duration)
{
new FreeTimer(this, duration).Start();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Delete();
}
private class FreeTimer : Timer
{
private EffectItem m_Item;
public FreeTimer(EffectItem item, TimeSpan delay) : base(delay)
{
m_Item = item;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
m_Item.Internalize();
m_Free.Add(m_Item);
}
}
}
}

View file

@ -0,0 +1,29 @@
namespace Server.Items
{
public class ExecutionersCap : Item
{
[Constructible]
public ExecutionersCap() : base(0xF83)
{
Weight = 1.0;
}
public ExecutionersCap(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,286 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Network;
using Server.Spells;
using Server.Targeting;
namespace Server.Items
{
public class Firebomb : Item
{
private Mobile m_LitBy;
private int m_Ticks;
private Timer m_Timer;
private List<Mobile> m_Users;
[Constructible]
public Firebomb(int itemID = 0x99B) : base(itemID)
{
//Name = "a firebomb";
Weight = 2.0;
Hue = 1260;
}
public Firebomb(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
public override void OnDoubleClick(Mobile from)
{
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 != null && from.Spell.IsCasting))
{
// to prevent exploiting for pvp
from.SendLocalizedMessage(1075857); // You cannot use that while paralyzed.
return;
}
if (m_Timer == null)
{
m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnFirebombTimerTick);
m_LitBy = from;
from.SendLocalizedMessage(1060582); // You light the firebomb. Throw it now!
}
else
{
from.SendLocalizedMessage(1060581); // You've already lit it! Better throw it now!
}
if (m_Users == null)
m_Users = new List<Mobile>();
if (!m_Users.Contains(from))
m_Users.Add(from);
from.Target = new ThrowTarget(this);
}
private void OnFirebombTimerTick()
{
if (Deleted)
{
m_Timer.Stop();
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 (Mobile 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)
{
IPooledEnumerable<Mobile> eable = Map.GetMobilesInRange(Location, 1);
List<Mobile> toDamage = eable.ToList();
eable.Free();
for (int i = 0; i < toDamage.Count; ++i)
{
Mobile victim = toDamage[i];
if (m_LitBy == null || SpellHelper.ValidIndirectTarget(m_LitBy, victim) &&
m_LitBy.CanBeHarmful(victim, false))
{
m_LitBy?.DoHarmful(victim);
AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
}
}
new FirebombField(m_LitBy, toDamage).MoveToWorld(Location, Map);
}
m_Timer.Stop();
Delete();
break;
}
}
}
private void OnFirebombTarget(Mobile from, object obj)
{
if (Deleted || Map == Map.Internal || !IsChildOf(from.Backpack))
return;
if (!(obj is IPoint3D p))
return;
SpellHelper.GetSurfaceTop(ref p);
from.RevealingAction();
IEntity to = p as IEntity ?? new Entity(Serial.Zero, new Point3D(p), Map);
Effects.SendMovingEffect(from, to, ItemID, 7, 0, false, false, Hue);
Timer.DelayCall(TimeSpan.FromSeconds(1.0), () => FirebombReposition_OnTick(p, Map));
Internalize();
}
private void FirebombReposition_OnTick(IPoint3D p, Map map)
{
if (Deleted)
return;
MoveToWorld(new Point3D(p), map);
}
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);
}
}
}
public class FirebombField : Item
{
private List<Mobile> m_Burning;
private DateTime m_Expire;
private Mobile m_LitBy;
private Timer m_Timer;
public FirebombField(Mobile litBy, List<Mobile> toDamage) : base(0x376A)
{
Movable = false;
m_LitBy = litBy;
m_Expire = DateTime.UtcNow + TimeSpan.FromSeconds(10);
m_Burning = toDamage;
m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), OnFirebombFieldTimerTick);
}
public FirebombField(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
// Don't serialize these...
}
public override void Deserialize(GenericReader reader)
{
}
public override bool OnMoveOver(Mobile m)
{
if (ItemID == 0x398C && m_LitBy == null ||
SpellHelper.ValidIndirectTarget(m_LitBy, m) && m_LitBy.CanBeHarmful(m, false))
{
m_LitBy?.DoHarmful(m);
AOS.Damage(m, m_LitBy, 2, 0, 100, 0, 0, 0);
m.PlaySound(0x208);
if (!m_Burning.Contains(m))
m_Burning.Add(m);
}
return true;
}
private void OnFirebombFieldTimerTick()
{
if (Deleted)
{
m_Timer.Stop();
return;
}
if (ItemID == 0x376A)
{
ItemID = 0x398C;
return;
}
for (int i = 0; i < m_Burning.Count;)
{
Mobile victim = m_Burning[i];
if (victim.Location == Location && victim.Map == Map &&
(m_LitBy == null || SpellHelper.ValidIndirectTarget(m_LitBy, victim) &&
m_LitBy.CanBeHarmful(victim, false)))
{
m_LitBy?.DoHarmful(victim);
AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0);
++i;
}
else
{
m_Burning.RemoveAt(i);
}
}
if (DateTime.UtcNow >= m_Expire)
{
m_Timer.Stop();
Delete();
}
}
}
}

View file

@ -0,0 +1,117 @@
using System;
using System.Reflection;
using Server.Multis;
namespace Server.Items
{
[AttributeUsage(AttributeTargets.Class)]
public class FlippableAddonAttribute : Attribute
{
private static string m_MethodName = "Flip";
private static Type[] m_Params =
{
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
{
MethodInfo flipMethod = addon.GetType().GetMethod(m_MethodName, m_Params);
if (flipMethod != null)
{
int index = 0;
for (int 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;
AddonFitResult 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[2] { 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 (AddonComponent c in addon.Components)
{
c.Addon = null;
c.Delete();
}
addon.Components.Clear();
}
else if (item is BaseAddonContainer addonContainer)
{
foreach (AddonContainerComponent c in addonContainer.Components)
{
c.Addon = null;
c.Delete();
}
addonContainer.Components.Clear();
}
}
}
}

View file

@ -0,0 +1,95 @@
using System;
using Server.Commands;
using Server.Targeting;
namespace Server.Items
{
public class FlipCommandHandlers
{
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;
Type type = item.GetType();
FlippableAttribute[] AttributeArray =
(FlippableAttribute[])type.GetCustomAttributes(typeof(FlippableAttribute), false);
if (AttributeArray.Length == 0) return;
FlippableAttribute fa = AttributeArray[0];
fa.Flip(item);
}
}
}
}
[AttributeUsage(AttributeTargets.Class)]
public class DynamicFlipingAttribute : 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, new object[0]);
}
catch
{
// ignored
}
}
else
{
int index = 0;
for (int 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

View file

@ -0,0 +1,122 @@
using System;
using Server.Accounting;
namespace Server.Items
{
public class Gold : Item
{
[Constructible]
public Gold(int amountFrom, int amountTo) : this(Utility.RandomMinMax(amountFrom, amountTo))
{
}
[Constructible]
public Gold(int amount = 1) : base(0xEED)
{
Stackable = true;
Amount = amount;
}
public Gold(Serial serial) : base(serial)
{
}
public override double DefaultWeight => Core.ML ? 0.02 / 3 : 0.02;
public override int GetDropSound()
{
if (Amount <= 1)
return 0x2E4;
if (Amount <= 5)
return 0x2E5;
return 0x2E6;
}
protected override void OnAmountChange(int oldValue)
{
int newValue = Amount;
UpdateTotal(this, TotalType.Gold, newValue - oldValue);
}
public override void OnAdded(IEntity parent)
{
base.OnAdded(parent);
if (!AccountGold.Enabled) return;
Mobile owner = null;
SecureTradeInfo tradeInfo = null;
Container 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 == null || !owner.Account.DepositGold(Amount)) return;
if (tradeInfo != null)
{
if (owner.NetState?.NewSecureTrading == false)
{
int plat = Math.DivRem(Amount, AccountGold.CurrencyThreshold, out int gold);
tradeInfo.Plat += plat;
tradeInfo.Gold += gold;
}
tradeInfo.VirtualCheck?.UpdateTrade(tradeInfo.Mobile);
}
owner.SendLocalizedMessage(1042763, Amount.ToString("#,0"));
Delete();
((Container)parent).UpdateTotals();
}
public override int GetTotal(TotalType type)
{
int baseTotal = base.GetTotal(type);
if (type == TotalType.Gold)
baseTotal += Amount;
return baseTotal;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,115 @@
using System;
using Server.Network;
using Server.Spells;
namespace Server.Items
{
public class Guillotine : Item
{
private DateTime m_NextUse;
[Constructible]
public Guillotine()
: base(4656)
{
Movable = false;
}
public Guillotine(Serial serial)
: base(serial)
{
}
public override void OnDoubleClick(Mobile from)
{
if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this))
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
}
else if (Visible && (ItemID == 4656 || ItemID == 4702) && DateTime.UtcNow >= m_NextUse)
{
Point3D p = GetWorldLocation();
if (1 > Utility.Random(Math.Max(Math.Abs(from.X - p.X), Math.Abs(from.Y - p.Y))))
{
Effects.PlaySound(from.Location, from.Map, from.GetHurtSound());
from.PublicOverheadMessage(MessageType.Regular, from.SpeechHue, true, "Ouch!");
SpellHelper.Damage(TimeSpan.FromSeconds(0.5), from, Utility.Dice(2, 10, 5));
}
Effects.PlaySound(GetWorldLocation(), Map, 0x387);
Timer.DelayCall(TimeSpan.FromSeconds(0.25), Down1);
Timer.DelayCall(TimeSpan.FromSeconds(0.50), Down2);
Timer.DelayCall(TimeSpan.FromSeconds(5.00), BackUp);
m_NextUse = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
}
}
private void Down1()
{
ItemID = ItemID == 4656 ? 4678 : 4712;
}
private void Down2()
{
ItemID = ItemID == 4678 ? 4679 : 4713;
Point3D p = GetWorldLocation();
Map f = Map;
if (f == null)
return;
new Blood(4650).MoveToWorld(p, f);
for (int i = 0; i < 4; ++i)
{
int x = p.X - 2 + Utility.Random(5);
int y = p.Y - 2 + Utility.Random(5);
int z = p.Z;
if (!f.CanFit(x, y, z, 1, false, false))
{
z = f.GetAverageZ(x, y);
if (!f.CanFit(x, y, z, 1, false, false))
continue;
}
Point3D loc = f.GetRandomNearbyLocation(p, 2, -2, 4, 1);
new Blood().MoveToWorld(loc, f);
}
}
private void BackUp()
{
if (ItemID == 4678 || ItemID == 4679)
ItemID = 4656;
else if (ItemID == 4712 || ItemID == 4713)
ItemID = 4702;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((byte)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadByte();
if (ItemID == 4678 || ItemID == 4679)
ItemID = 4656;
else if (ItemID == 4712 || ItemID == 4713)
ItemID = 4702;
}
}
}

View file

@ -0,0 +1,169 @@
using Server.Gumps;
using Server.Network;
namespace Server.Items
{
public class HairDye : Item
{
[Constructible]
public HairDye() : base(0xEFF)
{
Weight = 1.0;
}
public HairDye(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041060; // Hair Dye
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public override void OnDoubleClick(Mobile from)
{
if (from.InRange(GetWorldLocation(), 1))
{
from.CloseGump<HairDyeGump>();
from.SendGump(new HairDyeGump(this));
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 906, 1019045); // I can't reach that.
}
}
}
public class HairDyeGump : Gump
{
private static HairDyeEntry[] m_Entries =
{
new HairDyeEntry("*****", 1602, 26),
new HairDyeEntry("*****", 1628, 27),
new HairDyeEntry("*****", 1502, 32),
new HairDyeEntry("*****", 1302, 32),
new HairDyeEntry("*****", 1402, 32),
new HairDyeEntry("*****", 1202, 24),
new HairDyeEntry("*****", 2402, 29),
new HairDyeEntry("*****", 2213, 6),
new HairDyeEntry("*****", 1102, 8),
new HairDyeEntry("*****", 1110, 8),
new HairDyeEntry("*****", 1118, 16),
new HairDyeEntry("*****", 1134, 16)
};
private HairDye m_HairDye;
public HairDyeGump(HairDye dye) : base(50, 50)
{
m_HairDye = dye;
AddPage(0);
AddBackground(100, 10, 350, 355, 2600);
AddBackground(120, 54, 110, 270, 5100);
AddHtmlLocalized(70, 25, 400, 35, 1011013); // <center>Hair Color Selection Menu</center>
AddButton(149, 328, 4005, 4007, 1);
AddHtmlLocalized(185, 329, 250, 35, 1011014); // Dye my hair this color!
for (int i = 0; i < m_Entries.Length; ++i)
{
AddLabel(130, 59 + i * 22, m_Entries[i].HueStart - 1, m_Entries[i].Name);
AddButton(207, 60 + i * 22, 5224, 5224, 0, GumpButtonType.Page, i + 1);
}
for (int i = 0; i < m_Entries.Length; ++i)
{
HairDyeEntry e = m_Entries[i];
AddPage(i + 1);
for (int j = 0; j < e.HueCount; ++j)
{
AddLabel(278 + j / 16 * 80, 52 + j % 16 * 17, e.HueStart + j - 1, "*****");
AddRadio(260 + j / 16 * 80, 52 + j % 16 * 17, 210, 211, false, i * 100 + j);
}
}
}
public override void OnResponse(NetState from, RelayInfo info)
{
if (m_HairDye.Deleted)
return;
Mobile m = from.Mobile;
int[] switches = info.Switches;
if (!m_HairDye.IsChildOf(m.Backpack))
{
m.SendLocalizedMessage(1042010); //You must have the objectin your backpack to use it.
return;
}
if (info.ButtonID != 0 && switches.Length > 0)
{
if (m.HairItemID == 0 && m.FacialHairItemID == 0)
{
m.SendLocalizedMessage(502623); // You have no hair to dye and cannot use this
}
else
{
// To prevent this from being exploited, the hue is abstracted into an internal list
int entryIndex = switches[0] / 100;
int hueOffset = switches[0] % 100;
if (entryIndex >= 0 && entryIndex < m_Entries.Length)
{
HairDyeEntry e = m_Entries[entryIndex];
if (hueOffset >= 0 && hueOffset < e.HueCount)
{
int hue = e.HueStart + hueOffset;
m.HairHue = hue;
m.FacialHairHue = hue;
m.SendLocalizedMessage(501199); // You dye your hair
m_HairDye.Delete();
m.PlaySound(0x4E);
}
}
}
}
else
{
m.SendLocalizedMessage(501200); // You decide not to dye your hair
}
}
private class HairDyeEntry
{
public HairDyeEntry(string name, int hueStart, int hueCount)
{
Name = name;
HueStart = hueStart;
HueCount = hueCount;
}
public string Name{ get; }
public int HueStart{ get; }
public int HueCount{ get; }
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class HoveringWisp : Item
{
[Constructible]
public HoveringWisp() : base(0x2100)
{
}
public HoveringWisp(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072881; // hovering wisp
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,21 @@
namespace Server.Items
{
internal interface IDurability
{
bool CanFortify{ get; }
int InitMinHits{ get; }
int InitMaxHits{ get; }
int HitPoints{ get; set; }
int MaxHitPoints{ get; set; }
void ScaleDurability();
void UnscaleDurability();
}
internal interface IWearableDurability : IDurability
{
int OnHit(BaseWeapon weapon, int damageTaken);
}
}

View file

@ -0,0 +1,336 @@
using Server.Gumps;
using Server.Multis;
using Server.Network;
using Server.Targeting;
namespace Server.Items
{
public enum DecorateCommand
{
None,
Turn,
Up,
Down
}
public class InteriorDecorator : Item
{
private DecorateCommand m_Command;
[Constructible]
public InteriorDecorator() : base(0xFC1)
{
Weight = 1.0;
LootType = LootType.Blessed;
}
public InteriorDecorator(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public DecorateCommand Command
{
get => m_Command;
set
{
m_Command = value;
InvalidateProperties();
}
}
public override int LabelNumber => 1041280; // an interior decorator
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
if (m_Command != DecorateCommand.None)
list.Add(1018322 + (int)m_Command); // Turn/Up/Down
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public override void OnDoubleClick(Mobile from)
{
if (!CheckUse(this, from))
return;
if (!from.HasGump<InternalGump>())
from.SendGump(new InternalGump(this));
if (m_Command != DecorateCommand.None)
from.Target = new InternalTarget(this);
}
public static bool InHouse(Mobile from)
{
BaseHouse house = BaseHouse.FindHouseAt(from);
return house?.IsCoOwner(from) == true;
}
public static bool CheckUse(InteriorDecorator tool, Mobile from)
{
/*if ( tool.Deleted || !tool.IsChildOf( from.Backpack ) )
from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it.
else*/
if (!InHouse(from))
from.SendLocalizedMessage(502092); // You must be in your house to do this.
else
return true;
return false;
}
private class InternalGump : Gump
{
private InteriorDecorator m_Decorator;
public InternalGump(InteriorDecorator decorator) : base(150, 50)
{
m_Decorator = decorator;
AddBackground(0, 0, 200, 200, 2600);
AddButton(50, 45, decorator.Command == DecorateCommand.Turn ? 2154 : 2152, 2154, 1);
AddHtmlLocalized(90, 50, 70, 40, 1018323); // Turn
AddButton(50, 95, decorator.Command == DecorateCommand.Up ? 2154 : 2152, 2154, 2);
AddHtmlLocalized(90, 100, 70, 40, 1018324); // Up
AddButton(50, 145, decorator.Command == DecorateCommand.Down ? 2154 : 2152, 2154, 3);
AddHtmlLocalized(90, 150, 70, 40, 1018325); // Down
}
public override void OnResponse(NetState sender, RelayInfo info)
{
DecorateCommand command = DecorateCommand.None;
switch (info.ButtonID)
{
case 1:
command = DecorateCommand.Turn;
break;
case 2:
command = DecorateCommand.Up;
break;
case 3:
command = DecorateCommand.Down;
break;
}
if (command != DecorateCommand.None)
{
m_Decorator.Command = command;
sender.Mobile.SendGump(new InternalGump(m_Decorator));
sender.Mobile.Target = new InternalTarget(m_Decorator);
}
else
{
Target.Cancel(sender.Mobile);
}
}
}
private class InternalTarget : Target
{
private InteriorDecorator m_Decorator;
public InternalTarget(InteriorDecorator decorator) : base(-1, false, TargetFlags.None)
{
CheckLOS = false;
m_Decorator = decorator;
}
protected override void OnTargetNotAccessible(Mobile from, object targeted)
{
OnTarget(from, targeted);
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is Item item && CheckUse(m_Decorator, from))
{
BaseHouse house = BaseHouse.FindHouseAt(from);
bool isDecorableComponent = false;
object addon = null;
int count = 0;
if (item is AddonComponent component)
{
count = component.Addon.Components.Count;
addon = component.Addon;
}
else if (item is AddonContainerComponent containerComponent)
{
count = containerComponent.Addon.Components.Count;
addon = containerComponent.Addon;
}
else if (item is BaseAddonContainer container)
{
count = container.Components.Count;
addon = container;
}
if (addon != null)
{
if (count == 1 && Core.SE)
isDecorableComponent = true;
if (m_Decorator.Command == DecorateCommand.Turn)
{
FlippableAddonAttribute[] attributes =
(FlippableAddonAttribute[])addon.GetType()
.GetCustomAttributes(typeof(FlippableAddonAttribute), false);
if (attributes.Length > 0)
isDecorableComponent = true;
}
}
if (house == null || !house.IsCoOwner(from))
{
from.SendLocalizedMessage(502092); // You must be in your house to do this.
}
else if (item.Parent != null || !house.IsInside(item))
{
from.SendLocalizedMessage(1042270); // That is not in your house.
}
else if (!house.HasLockedDownItem(item) && !house.HasSecureItem(item) && !isDecorableComponent)
{
if (item is AddonComponent && m_Decorator.Command == DecorateCommand.Up)
from.SendLocalizedMessage(1042274); // You cannot raise it up any higher.
else if (item is AddonComponent && m_Decorator.Command == DecorateCommand.Down)
from.SendLocalizedMessage(1042275); // You cannot lower it down any further.
else
from.SendLocalizedMessage(1042271); // That is not locked down.
}
else if (item is VendorRentalContract)
{
from.SendLocalizedMessage(1062491); // You cannot use the house decorator on that object.
}
else if (item.TotalWeight + item.PileWeight > 100)
{
from.SendLocalizedMessage(1042272); // That is too heavy.
}
else
{
switch (m_Decorator.Command)
{
case DecorateCommand.Up:
Up(item, from);
break;
case DecorateCommand.Down:
Down(item, from);
break;
case DecorateCommand.Turn:
Turn(item, from);
break;
}
}
}
from.Target = new InternalTarget(m_Decorator);
}
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
{
if (cancelType == TargetCancelType.Canceled)
from.CloseGump<InternalGump>();
}
private static void Turn(Item item, Mobile from)
{
object addon = null;
if (item is AddonComponent component)
addon = component.Addon;
else if (item is AddonContainerComponent containerComponent)
addon = containerComponent.Addon;
else if (item is BaseAddonContainer container)
addon = container;
if (addon != null)
{
FlippableAddonAttribute[] aAttributes =
(FlippableAddonAttribute[])addon.GetType()
.GetCustomAttributes(typeof(FlippableAddonAttribute), false);
if (aAttributes.Length > 0)
{
aAttributes[0].Flip(from, (Item)addon);
return;
}
}
FlippableAttribute[] attributes =
(FlippableAttribute[])item.GetType().GetCustomAttributes(typeof(FlippableAttribute), false);
if (attributes.Length > 0)
attributes[0].Flip(item);
else
from.SendLocalizedMessage(1042273); // You cannot turn that.
}
private static void Up(Item item, Mobile from)
{
int floorZ = GetFloorZ(item);
if (floorZ > int.MinValue && item.Z < floorZ + 15) // Confirmed : no height checks here
item.Location = new Point3D(item.Location, item.Z + 1);
else
from.SendLocalizedMessage(1042274); // You cannot raise it up any higher.
}
private static void Down(Item item, Mobile from)
{
int floorZ = GetFloorZ(item);
if (floorZ > int.MinValue && item.Z > GetFloorZ(item))
item.Location = new Point3D(item.Location, item.Z - 1);
else
from.SendLocalizedMessage(1042275); // You cannot lower it down any further.
}
private static int GetFloorZ(Item item)
{
Map map = item.Map;
if (map == null)
return int.MinValue;
StaticTile[] tiles = map.Tiles.GetStaticTiles(item.X, item.Y, true);
int z = int.MinValue;
for (int i = 0; i < tiles.Length; ++i)
{
StaticTile tile = tiles[i];
ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
int top = tile.Z; // Confirmed : no height checks here
if (id.Surface && !id.Impassable && top > z && top <= item.Z)
z = top;
}
return z;
}
}
}
}

View file

@ -0,0 +1,391 @@
using Server.Network;
using Server.Prompts;
using Server.Targeting;
namespace Server.Items
{
public enum KeyType
{
Copper = 0x100E,
Gold = 0x100F,
Iron = 0x1010,
Rusty = 0x1013
}
public interface ILockable
{
bool Locked{ get; set; }
uint KeyValue{ get; set; }
}
public class Key : Item
{
private string m_Description;
private uint m_KeyVal;
[Constructible]
public Key(uint val = 0) : this(KeyType.Iron, val)
{
}
public Key(KeyType type, uint val = 0, Item link = null) : base((int)type)
{
Weight = 1.0;
MaxRange = 3;
m_KeyVal = val;
Link = link;
}
public Key(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public string Description
{
get => m_Description;
set
{
m_Description = value;
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int MaxRange{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public uint KeyValue
{
get => m_KeyVal;
set
{
m_KeyVal = value;
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Item Link{ get; set; }
public static uint RandomValue()
{
return (uint)(0xFFFFFFFE * Utility.RandomDouble()) + 1;
}
public static void RemoveKeys(Mobile m, uint keyValue)
{
if (keyValue == 0)
return;
RemoveKeys(m.Backpack, keyValue);
RemoveKeys(m.BankBox, keyValue);
}
public static void RemoveKeys(Container cont, uint keyValue)
{
if (cont == null || keyValue == 0)
return;
Item[] items = cont.FindItemsByType(new[] { typeof(Key), typeof(KeyRing) });
foreach (Item item in items)
if (item is Key key)
{
if (key.KeyValue == keyValue)
key.Delete();
}
else
{
KeyRing keyRing = (KeyRing)item;
keyRing.RemoveKeys(keyValue);
}
}
public static bool ContainsKey(Container cont, uint keyValue)
{
if (cont == null)
return false;
Item[] items = cont.FindItemsByType(new[] { typeof(Key), typeof(KeyRing) });
foreach (Item item in items)
if (item is Key key)
{
if (key.KeyValue == keyValue)
return true;
}
else
{
KeyRing keyRing = (KeyRing)item;
if (keyRing.ContainsKey(keyValue))
return true;
}
return false;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(2); // version
writer.Write(MaxRange);
writer.Write(Link);
writer.Write(m_Description);
writer.Write(m_KeyVal);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 2:
{
MaxRange = reader.ReadInt();
goto case 1;
}
case 1:
{
Link = reader.ReadItem();
goto case 0;
}
case 0:
{
if (version < 2 || MaxRange == 0)
MaxRange = 3;
m_Description = reader.ReadString();
m_KeyVal = reader.ReadUInt();
break;
}
}
}
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(501661); // That key is unreachable.
return;
}
Target t;
int number;
if (m_KeyVal != 0)
{
number = 501662; // What shall I use this key on?
t = new UnlockTarget(this);
}
else
{
number = 501663; // This key is a key blank. Which key would you like to make a copy of?
t = new CopyTarget(this);
}
from.SendLocalizedMessage(number);
from.Target = t;
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
string desc;
if (m_KeyVal == 0)
desc = "(blank)";
else if ((desc = m_Description) == null || (desc = desc.Trim()).Length <= 0)
desc = null;
if (desc != null)
list.Add(desc);
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
string desc;
if (m_KeyVal == 0)
desc = "(blank)";
else if ((desc = m_Description) == null || (desc = desc.Trim()).Length <= 0)
desc = "";
if (desc.Length > 0)
from.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", "", desc));
}
public bool UseOn(Mobile from, ILockable o)
{
if (o.KeyValue == KeyValue)
{
if (o is BaseDoor door && !door.UseLocks())
return false;
o.Locked = !o.Locked;
if (o is LockableContainer cont1)
if (cont1.LockLevel == -255)
cont1.LockLevel = cont1.RequiredSkill - 10;
if (o is Item item)
{
if (o.Locked)
item.SendLocalizedMessageTo(from, 1048000); // You lock it.
else
item.SendLocalizedMessageTo(from, 1048001); // You unlock it.
if (item is LockableContainer cont && cont.TrapType != TrapType.None && cont.TrapOnLockpick)
{
if (o.Locked)
cont.SendLocalizedMessageTo(from, 501673); // You re-enable the trap.
else
cont.SendLocalizedMessageTo(from,
501672); // You disable the trap temporarily. Lock it again to re-enable it.
}
}
return true;
}
return false;
}
private class RenamePrompt : Prompt
{
private Key m_Key;
public RenamePrompt(Key key)
{
m_Key = key;
}
public override void OnResponse(Mobile from, string text)
{
if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(501661); // That key is unreachable.
return;
}
m_Key.Description = Utility.FixHtml(text);
}
}
private class UnlockTarget : Target
{
private Key m_Key;
public UnlockTarget(Key key) : base(key.MaxRange, false, TargetFlags.None)
{
m_Key = key;
CheckLOS = false;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(501661); // That key is unreachable.
return;
}
int number;
if (targeted == m_Key)
{
number = 501665; // Enter a description for this key.
from.Prompt = new RenamePrompt(m_Key);
}
else if (targeted is ILockable lockable)
{
if (m_Key.UseOn(from, lockable))
number = -1;
else
number = 501668; // This key doesn't seem to unlock that.
}
else
{
number = 501666; // You can't unlock that!
}
if (number != -1) from.SendLocalizedMessage(number);
}
}
private class CopyTarget : Target
{
private Key m_Key;
public CopyTarget(Key key) : base(3, false, TargetFlags.None)
{
m_Key = key;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(501661); // That key is unreachable.
return;
}
int number;
if (targeted is Key k)
{
if (k.m_KeyVal == 0)
{
number = 501675; // This key is also blank.
}
else if (from.CheckTargetSkill(SkillName.Tinkering, k, 0, 75.0))
{
number = 501676; // You make a copy of the key.
m_Key.Description = k.Description;
m_Key.KeyValue = k.KeyValue;
m_Key.Link = k.Link;
m_Key.MaxRange = k.MaxRange;
}
else if (Utility.RandomDouble() <= 0.1) // 10% chance to destroy the key
{
from.SendLocalizedMessage(501677); // You fail to make a copy of the key.
number = 501678; // The key was destroyed in the attempt.
m_Key.Delete();
}
else
{
number = 501677; // You fail to make a copy of the key.
}
}
else
{
number = 501688; // Not a key.
}
from.SendLocalizedMessage(number);
}
}
}
}

View file

@ -0,0 +1,188 @@
using System.Collections.Generic;
using Server.Targeting;
namespace Server.Items
{
public class KeyRing : Item
{
public static readonly int MaxKeys = 20;
[Constructible]
public KeyRing() : base(0x1011)
{
Weight = 1.0; // They seem to have no weight on OSI ?!
Keys = new List<Key>();
}
public KeyRing(Serial serial) : base(serial)
{
}
public List<Key> Keys{ get; private set; }
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (!IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it.
return false;
}
if (!(dropped is Key key) || key.KeyValue == 0)
{
from.SendLocalizedMessage(501689); // Only non-blank keys can be put on a keyring.
return false;
}
if (Keys.Count >= MaxKeys)
{
from.SendLocalizedMessage(1008138); // This keyring is full.
return false;
}
Add(key);
from.SendLocalizedMessage(501691); // You put the key on the keyring.
return true;
}
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it.
return;
}
from.SendLocalizedMessage(501680); // What do you want to unlock?
from.Target = new InternalTarget(this);
}
public override void OnDelete()
{
base.OnDelete();
foreach (Key key in Keys) key.Delete();
Keys.Clear();
}
public void Add(Key key)
{
key.Internalize();
Keys.Add(key);
UpdateItemID();
}
public void Open(Mobile from)
{
if (!(Parent is Container cont))
return;
for (int i = Keys.Count - 1; i >= 0; i--)
{
Key key = Keys[i];
if (!key.Deleted && !cont.TryDropItem(from, key, true))
break;
Keys.RemoveAt(i);
}
UpdateItemID();
}
public void RemoveKeys(uint keyValue)
{
for (int i = Keys.Count - 1; i >= 0; i--)
{
Key key = Keys[i];
if (key.KeyValue == keyValue)
{
key.Delete();
Keys.RemoveAt(i);
}
}
UpdateItemID();
}
public bool ContainsKey(uint keyValue)
{
foreach (Key key in Keys)
if (key.KeyValue == keyValue)
return true;
return false;
}
private void UpdateItemID()
{
if (Keys.Count < 1)
ItemID = 0x1011;
else if (Keys.Count < 3)
ItemID = 0x1769;
else if (Keys.Count < 5)
ItemID = 0x176A;
else
ItemID = 0x176B;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.WriteItemList(Keys);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
Keys = reader.ReadStrongItemList<Key>();
}
private class InternalTarget : Target
{
private KeyRing m_KeyRing;
public InternalTarget(KeyRing keyRing) : base(-1, false, TargetFlags.None)
{
m_KeyRing = keyRing;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (m_KeyRing.Deleted || !m_KeyRing.IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it.
return;
}
if (m_KeyRing == targeted)
{
m_KeyRing.Open(from);
from.SendLocalizedMessage(501685); // You open the keyring.
}
else if (targeted is ILockable o)
{
foreach (Key key in m_KeyRing.Keys)
if (key.UseOn(from, o))
return;
from.SendLocalizedMessage(1008140); // You do not have a key for that.
}
else
{
from.SendLocalizedMessage(501666); // You can't unlock that!
}
}
}
}
}

View file

@ -0,0 +1,113 @@
using Server.Network;
namespace Server.Items
{
public class LOSBlocker : Item
{
[Constructible]
public LOSBlocker() : base(0x21A2)
{
Movable = false;
}
public LOSBlocker(Serial serial) : base(serial)
{
}
public override string DefaultName => "no line of sight";
public static void Initialize()
{
TileData.ItemTable[0x21A2].Flags = TileFlag.Wall | TileFlag.NoShoot;
TileData.ItemTable[0x21A2].Height = 20;
}
protected override Packet GetWorldPacketFor(NetState state)
{
Mobile mob = state.Mobile;
if (mob?.AccessLevel >= AccessLevel.GameMaster) return new GMItemPacket(this);
return base.GetWorldPacketFor(state);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version < 1 && ItemID == 0x2199)
ItemID = 0x21A2;
}
public sealed class GMItemPacket : Packet
{
public GMItemPacket(Item item) : base(0x1A)
{
EnsureCapacity(20);
// 14 base length
// +2 - Amount
// +2 - Hue
// +1 - Flags
uint serial = item.Serial.Value;
int itemID = 0x36FF;
int amount = item.Amount;
Point3D loc = item.Location;
int x = loc.X;
int y = loc.Y;
int hue = item.Hue;
int flags = item.GetPacketFlags();
int direction = (int)item.Direction;
if (amount != 0)
serial |= 0x80000000;
else
serial &= 0x7FFFFFFF;
m_Stream.Write(serial);
m_Stream.Write((short)(itemID & 0x7FFF));
if (amount != 0)
m_Stream.Write((short)amount);
x &= 0x7FFF;
if (direction != 0)
x |= 0x8000;
m_Stream.Write((short)x);
y &= 0x3FFF;
if (hue != 0)
y |= 0x8000;
if (flags != 0)
y |= 0x4000;
m_Stream.Write((short)y);
if (direction != 0)
m_Stream.Write((byte)direction);
m_Stream.Write((sbyte)loc.Z);
if (hue != 0)
m_Stream.Write((ushort)hue);
if (flags != 0)
m_Stream.Write((byte)flags);
}
}
}
}

View file

@ -0,0 +1,36 @@
namespace Server.Items
{
public class MinotaurArtifact : Item
{
[Constructible]
public MinotaurArtifact() : base(Utility.RandomList(0xB46, 0xB48, 0x9ED))
{
if (ItemID == 0x9ED)
Weight = 30;
LootType = LootType.Blessed;
Hue = 0x100;
}
public MinotaurArtifact(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074826; // Minotaur Artifact
public override double DefaultWeight => 5.0;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,205 @@
using System;
using Server.Factions;
using Server.Mobiles;
using Server.Network;
namespace Server.Items
{
public enum MoonstoneType
{
Felucca,
Trammel
}
public class Moonstone : Item
{
private MoonstoneType m_Type;
[Constructible]
public Moonstone(MoonstoneType type) : base(0xF8B)
{
Weight = 1.0;
m_Type = type;
}
public Moonstone(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public MoonstoneType Type
{
get => m_Type;
set
{
m_Type = value;
InvalidateProperties();
}
}
public override int LabelNumber => 1041490 + (int)m_Type;
public override void OnSingleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
{
Hue = Utility.RandomBirdHue();
ProcessDelta();
from.SendLocalizedMessage(1005398); // The stone's substance shifts as you examine it.
}
base.OnSingleClick(from);
}
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 if (from.Mounted)
{
from.SendLocalizedMessage(1005399); // You can not bury a stone while you sit on a mount.
}
else if (!from.Body.IsHuman)
{
from.SendLocalizedMessage(1005400); // You can not bury a stone in this form.
}
else if (Sigil.ExistsOn(from))
{
from.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil.
}
else if (from.Map == GetTargetMap() || from.Map != Map.Trammel && from.Map != Map.Felucca)
{
from.SendLocalizedMessage(1005401); // You cannot bury the stone here.
}
else if (from is PlayerMobile mobile && mobile.Young)
{
mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young.
}
else if (from.Kills >= 5)
{
from.SendLocalizedMessage(
1005402); // The magic of the stone cannot be evoked by someone with blood on their hands.
}
else if (from.Criminal)
{
from.SendLocalizedMessage(1005403); // The magic of the stone cannot be evoked by the lawless.
}
else if (!Region.Find(from.Location, from.Map).IsDefault ||
!Region.Find(from.Location, GetTargetMap()).IsDefault)
{
from.SendLocalizedMessage(1005401); // You cannot bury the stone here.
}
else if (!GetTargetMap().CanFit(from.Location, 16))
{
from.SendLocalizedMessage(1005408); // Something is blocking the facet gate exit.
}
else
{
Movable = false;
MoveToWorld(from.Location, from.Map);
from.Animate(32, 5, 1, true, false, 0);
new SettleTimer(this, from.Location, from.Map, GetTargetMap(), from).Start();
}
}
public Map GetTargetMap()
{
return m_Type == MoonstoneType.Felucca ? Map.Felucca : Map.Trammel;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write((int)m_Type);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
m_Type = (MoonstoneType)reader.ReadInt();
break;
}
}
}
private class SettleTimer : Timer
{
private Mobile m_Caster;
private int m_Count;
private Point3D m_Location;
private Map m_Map, m_TargetMap;
private Item m_Stone;
public SettleTimer(Item stone, Point3D loc, Map map, Map targetMap, Mobile caster) : base(
TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0))
{
m_Stone = stone;
m_Location = loc;
m_Map = map;
m_TargetMap = targetMap;
m_Caster = caster;
}
protected override void OnTick()
{
++m_Count;
if (m_Count == 1)
{
m_Stone.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1005414); // The stone settles into the ground.
}
else if (m_Count >= 10)
{
m_Stone.Location = new Point3D(m_Stone.X, m_Stone.Y, m_Stone.Z - 1);
if (m_Count == 16)
{
if (!Region.Find(m_Location, m_Map).IsDefault || !Region.Find(m_Location, m_TargetMap).IsDefault)
{
m_Stone.Movable = true;
m_Caster.AddToBackpack(m_Stone);
Stop();
return;
}
if (!m_TargetMap.CanFit(m_Location, 16))
{
m_Stone.Movable = true;
m_Caster.AddToBackpack(m_Stone);
Stop();
return;
}
int hue = m_Stone.Hue;
if (hue == 0)
hue = Utility.RandomBirdHue();
new MoonstoneGate(m_Location, m_TargetMap, m_Map, m_Caster, hue);
new MoonstoneGate(m_Location, m_Map, m_TargetMap, m_Caster, hue);
m_Stone.Delete();
Stop();
}
}
}
}
}
}

View file

@ -0,0 +1,83 @@
using System;
using Server.Engines.PartySystem;
namespace Server.Items
{
public class MoonstoneGate : Moongate
{
private Mobile m_Caster;
public MoonstoneGate(Point3D loc, Map map, Map targetMap, Mobile caster, int hue) : base(loc, targetMap)
{
MoveToWorld(loc, map);
Dispellable = false;
Hue = hue;
m_Caster = caster;
new InternalTimer(this).Start();
Effects.PlaySound(loc, map, 0x20E);
}
public MoonstoneGate(Serial serial) : base(serial)
{
}
public override void CheckGate(Mobile m, int range)
{
if (m.Kills >= 5)
return;
Party casterParty = Party.Get(m_Caster);
Party userParty = Party.Get(m);
if (m == m_Caster || casterParty != null && userParty == casterParty)
base.CheckGate(m, range);
}
public override void UseGate(Mobile m)
{
if (m.Kills >= 5)
return;
Party casterParty = Party.Get(m_Caster);
Party userParty = Party.Get(m);
if (m == m_Caster || casterParty != null && userParty == casterParty)
base.UseGate(m);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Delete();
}
private class InternalTimer : Timer
{
private Item m_Item;
public InternalTimer(Item item) : base(TimeSpan.FromSeconds(30.0))
{
m_Item = item;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
m_Item.Delete();
}
}
}
}

View file

@ -0,0 +1,132 @@
using System;
using System.Linq;
namespace Server.Items
{
public class MorphItem : Item
{
private int m_InRange;
private int m_OutRange;
[Constructible]
public MorphItem(int inactiveItemID, int activeItemID, int range) : this(inactiveItemID, activeItemID, range, range)
{
}
[Constructible]
public MorphItem(int inactiveItemID, int activeItemID, int inRange, int outRange) : base(inactiveItemID)
{
Movable = false;
InactiveItemID = inactiveItemID;
ActiveItemID = activeItemID;
InRange = inRange;
OutRange = outRange;
}
public MorphItem(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public int InactiveItemID{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int ActiveItemID{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int InRange
{
get => m_InRange;
set
{
if (value > 18) value = 18;
m_InRange = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int OutRange
{
get => m_OutRange;
set
{
if (value > 18) value = 18;
m_OutRange = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int CurrentRange => ItemID == InactiveItemID ? InRange : OutRange;
public override bool HandlesOnMovement => true;
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (Utility.InRange(m.Location, Location, CurrentRange) || Utility.InRange(oldLocation, Location, CurrentRange))
Refresh();
}
public override void OnMapChange()
{
if (!Deleted)
Refresh();
}
public override void OnLocationChange(Point3D oldLoc)
{
if (!Deleted)
Refresh();
}
public void Refresh()
{
bool found = GetMobilesInRange(CurrentRange).Any(mob => !mob.Hidden || mob.AccessLevel <= AccessLevel.Player);
ItemID = found ? ActiveItemID : InactiveItemID;
Visible = ItemID != 0x1;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
writer.Write(m_OutRange);
writer.Write(InactiveItemID);
writer.Write(ActiveItemID);
writer.Write(m_InRange);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 1:
{
m_OutRange = reader.ReadInt();
goto case 0;
}
case 0:
{
InactiveItemID = reader.ReadInt();
ActiveItemID = reader.ReadInt();
m_InRange = reader.ReadInt();
if (version < 1)
m_OutRange = m_InRange;
break;
}
}
Timer.DelayCall(TimeSpan.Zero, Refresh);
}
}
}

View file

@ -0,0 +1,151 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Items
{
public class OilCloth : Item, IScissorable, IDyable
{
[Constructible]
public OilCloth() : base(0x175D)
{
Hue = 2001;
}
public OilCloth(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041498; // oil cloth
public override double DefaultWeight => 1.0;
public bool Dye(Mobile from, DyeTub sender)
{
if (Deleted)
return false;
Hue = sender.DyedHue;
return true;
}
public bool Scissor(Mobile from, Scissors scissors)
{
if (Deleted || !from.CanSee(this))
return false;
base.ScissorHelper(from, new Bandage(), 1);
return true;
}
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
{
from.BeginTarget(-1, false, TargetFlags.None, OnTarget);
from.SendLocalizedMessage(1005424); // Select the weapon or armor you wish to use the cloth on.
}
else
{
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
}
}
public void OnTarget(Mobile from, object obj)
{
// TODO: Need details on how oil cloths should get consumed here
if (!IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
}
else if (obj is Item item && item.RootParent != from)
{
from.SendLocalizedMessage(1005425); // You may only wipe down items you are holding or carrying.
}
else if (obj is BaseWeapon weapon)
{
if (weapon.Poison == null || weapon.PoisonCharges <= 0)
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2,
1005422); // Hmmmm... this does not need to be cleaned.
}
else
{
if (weapon.PoisonCharges < 2)
weapon.PoisonCharges = 0;
else
weapon.PoisonCharges -= 2;
if (weapon.PoisonCharges > 0)
from.SendLocalizedMessage(1005423); // You have removed some of the caustic substance, but not all.
else
from.SendLocalizedMessage(1010497); // You have cleaned the item.
}
}
else if (obj == from && obj is PlayerMobile pm)
{
if (pm.BodyMod == 183 || pm.BodyMod == 184)
{
pm.SavagePaintExpiration = TimeSpan.Zero;
pm.BodyMod = 0;
pm.HueMod = -1;
from.SendLocalizedMessage(1040006); // You wipe away all of your body paint.
Consume();
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2,
1005422); // Hmmmm... this does not need to be cleaned.
}
}
#region Firebomb
else if (obj is BaseBeverage beverage)
{
if (beverage.Content == BeverageType.Liquor)
{
Firebomb bomb = new Firebomb(beverage.ItemID);
bomb.Name = beverage.Name;
beverage.ReplaceWith(bomb);
from.SendLocalizedMessage(1060580); // You prepare a firebomb.
Consume();
}
}
else if (obj is Firebomb)
{
from.SendLocalizedMessage(1060579); // That is already a firebomb!
}
#endregion
else
{
from.SendLocalizedMessage(1005426); // The cloth will not work on that.
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,245 @@
namespace Server.Items
{
public class OrigamiPaper : Item
{
[Constructible]
public OrigamiPaper() : base(0x2830)
{
}
public OrigamiPaper(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030288; // origami paper
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
{
Delete();
Item i = null;
switch (Utility.Random(from.BAC >= 5 ? 6 : 5))
{
case 0:
i = new OrigamiButterfly();
break;
case 1:
i = new OrigamiSwan();
break;
case 2:
i = new OrigamiFrog();
break;
case 3:
i = new OrigamiShape();
break;
case 4:
i = new OrigamiSongbird();
break;
case 5:
i = new OrigamiFish();
break;
}
if (i != null)
from.AddToBackpack(i);
from.SendLocalizedMessage(1070822); // You fold the paper into an interesting shape.
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class OrigamiButterfly : Item
{
[Constructible]
public OrigamiButterfly() : base(0x2838)
{
LootType = LootType.Blessed;
}
public OrigamiButterfly(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030296; // a delicate origami butterfly
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class OrigamiSwan : Item
{
[Constructible]
public OrigamiSwan() : base(0x2839)
{
LootType = LootType.Blessed;
}
public OrigamiSwan(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030297; // a delicate origami swan
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class OrigamiFrog : Item
{
[Constructible]
public OrigamiFrog() : base(0x283A)
{
LootType = LootType.Blessed;
}
public OrigamiFrog(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030298; // a delicate origami frog
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class OrigamiShape : Item
{
[Constructible]
public OrigamiShape() : base(0x283B)
{
LootType = LootType.Blessed;
}
public OrigamiShape(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030299; // an intricate geometric origami shape
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class OrigamiSongbird : Item
{
[Constructible]
public OrigamiSongbird() : base(0x283C)
{
LootType = LootType.Blessed;
}
public OrigamiSongbird(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030300; // a delicate origami songbird
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class OrigamiFish : Item
{
[Constructible]
public OrigamiFish() : base(0x283D)
{
LootType = LootType.Blessed;
}
public OrigamiFish(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030301; // a delicate origami fish
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class GrobusFur : Item
{
[Constructible]
public GrobusFur() : base(0x11F4)
{
LootType = LootType.Blessed;
Hue = 0x455;
}
public GrobusFur(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074676; // Grobu's Fur
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class PrimitiveFetish : Item
{
[Constructible]
public PrimitiveFetish() : base(0x23F)
{
LootType = LootType.Blessed;
Hue = 0x244;
}
public PrimitiveFetish(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074675; // Primitive Fetish
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class AcidProofRope : Item
{
[Constructible]
public AcidProofRope() : base(0x20D)
{
Hue = 0x3D1; // TODO check
}
public AcidProofRope(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074886; // Acid Proof Rope
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class ParoxysmusCorrodedStein : Item
{
[Constructible]
public ParoxysmusCorrodedStein() : base(0x9D6)
{
}
public ParoxysmusCorrodedStein(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072083; // Paroxysmus' Corroded Stein
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class ParoxysmusDinner : Item
{
[Constructible]
public ParoxysmusDinner() : base(0x1E95)
{
}
public ParoxysmusDinner(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072086; // Paroxysmus' Dinner
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class StringOfPartsOfParoxysmusVictims : Item
{
[Constructible]
public StringOfPartsOfParoxysmusVictims() : base(0xFD2)
{
}
public StringOfPartsOfParoxysmusVictims(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072082; // String of Parts of Paroxysmus' Victims
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class SweatOfParoxysmus : Item
{
[Constructible]
public SweatOfParoxysmus() : base(0xF01)
{
}
public SweatOfParoxysmus(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072081; // Sweat of Paroxysmus
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,600 @@
using System;
using System.Collections.Generic;
using Server.Gumps;
using Server.Multis;
using Server.Prompts;
using Server.Mobiles;
using Server.Network;
using Server.ContextMenus;
namespace Server.Items
{
public class PlayerBBSouth : BasePlayerBB
{
public override int LabelNumber => 1062421; // bulletin board (south)
[Constructible]
public PlayerBBSouth() : base( 0x2311 )
{
Weight = 15.0;
}
public PlayerBBSouth( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( 0 ); // version
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
}
public class PlayerBBEast : BasePlayerBB
{
public override int LabelNumber => 1062420; // bulletin board (east)
[Constructible]
public PlayerBBEast() : base( 0x2312 )
{
Weight = 15.0;
}
public PlayerBBEast( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( 0 ); // version
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
}
public abstract class BasePlayerBB : Item, ISecurable
{
public List<PlayerBBMessage> Messages { get; private set; }
public PlayerBBMessage Greeting { get; set; }
[CommandProperty( AccessLevel.GameMaster )]
public string Title { get; set; }
[CommandProperty( AccessLevel.GameMaster )]
public SecureLevel Level { get; set; }
public BasePlayerBB( int itemID ) : base( itemID )
{
Messages = new List<PlayerBBMessage>();
Level = SecureLevel.Anyone;
}
public BasePlayerBB( Serial serial ) : base( serial )
{
}
public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
{
base.GetContextMenuEntries( from, list );
SetSecureLevelEntry.AddTo( from, this, list );
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( 1 );
writer.Write( (int) Level );
writer.Write( Title );
if ( Greeting != null )
{
writer.Write( true );
Greeting.Serialize( writer );
}
else
{
writer.Write( false );
}
writer.WriteEncodedInt( Messages.Count );
for ( int i = 0; i < Messages.Count; ++i )
Messages[i].Serialize( writer );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 1:
{
Level = (SecureLevel)reader.ReadInt();
goto case 0;
}
case 0:
{
if ( version < 1 )
Level = SecureLevel.Anyone;
Title = reader.ReadString();
if ( reader.ReadBool() )
Greeting = new PlayerBBMessage( reader );
int count = reader.ReadEncodedInt();
Messages = new List<PlayerBBMessage>( count );
for ( int i = 0; i < count; ++i )
Messages.Add( new PlayerBBMessage( reader ) );
break;
}
}
}
public static bool CheckAccess( BaseHouse house, Mobile from )
{
if ( house.Public || !house.IsAosRules )
return !house.IsBanned( from );
return house.HasAccess( from );
}
public override void OnDoubleClick( Mobile from )
{
BaseHouse house = BaseHouse.FindHouseAt( this );
if ( house == null || !house.HasLockedDownItem( this ) )
from.SendLocalizedMessage( 1062396 ); // This bulletin board must be locked down in a house to be usable.
else if ( !from.InRange( GetWorldLocation(), 2 ) || !from.InLOS( this ) )
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
else if ( CheckAccess( house, from ) )
from.SendGump( new PlayerBBGump( from, house, this, 0 ) );
}
public class PostPrompt : Prompt
{
private int m_Page;
private BaseHouse m_House;
private BasePlayerBB m_Board;
private bool m_Greeting;
public PostPrompt( int page, BaseHouse house, BasePlayerBB board, bool greeting )
{
m_Page = page;
m_House = house;
m_Board = board;
m_Greeting = greeting;
}
public override void OnCancel( Mobile from )
{
OnResponse( from, "" );
}
public override void OnResponse( Mobile from, string text )
{
int page = m_Page;
BaseHouse house = m_House;
BasePlayerBB board = m_Board;
if ( house == null || !house.HasLockedDownItem( board ) )
{
from.SendLocalizedMessage( 1062396 ); // This bulletin board must be locked down in a house to be usable.
return;
}
if ( !from.InRange( board.GetWorldLocation(), 2 ) || !from.InLOS( board ) )
{
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
return;
}
if ( !CheckAccess( house, from ) )
{
from.SendLocalizedMessage( 1062398 ); // You are not allowed to post to this bulletin board.
return;
}
if ( m_Greeting && !house.IsOwner( from ) )
{
return;
}
text = text.Trim();
if ( text.Length > 255 )
text = text.Substring( 0, 255 );
if ( text.Length > 0 )
{
PlayerBBMessage message = new PlayerBBMessage( DateTime.UtcNow, from, text );
if ( m_Greeting )
{
board.Greeting = message;
}
else
{
board.Messages.Add( message );
if ( board.Messages.Count > 50 )
{
board.Messages.RemoveAt( 0 );
if ( page > 0 )
--page;
}
}
}
from.SendGump( new PlayerBBGump( from, house, board, page ) );
}
}
public class SetTitlePrompt : Prompt
{
private int m_Page;
private BaseHouse m_House;
private BasePlayerBB m_Board;
public SetTitlePrompt( int page, BaseHouse house, BasePlayerBB board )
{
m_Page = page;
m_House = house;
m_Board = board;
}
public override void OnCancel( Mobile from )
{
OnResponse( from, "" );
}
public override void OnResponse( Mobile from, string text )
{
int page = m_Page;
BaseHouse house = m_House;
BasePlayerBB board = m_Board;
if ( house == null || !house.HasLockedDownItem( board ) )
{
from.SendLocalizedMessage( 1062396 ); // This bulletin board must be locked down in a house to be usable.
return;
}
if ( !from.InRange( board.GetWorldLocation(), 2 ) || !from.InLOS( board ) )
{
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
return;
}
if ( !CheckAccess( house, from ) )
{
from.SendLocalizedMessage( 1062398 ); // You are not allowed to post to this bulletin board.
return;
}
text = text.Trim();
if ( text.Length > 255 )
text = text.Substring( 0, 255 );
if ( text.Length > 0 )
board.Title = text;
from.SendGump( new PlayerBBGump( from, house, board, page ) );
}
}
}
public class PlayerBBMessage
{
[CommandProperty( AccessLevel.GameMaster )]
public DateTime Time { get; set; }
[CommandProperty( AccessLevel.GameMaster )]
public Mobile Poster { get; set; }
[CommandProperty( AccessLevel.GameMaster )]
public string Message { get; set; }
public PlayerBBMessage( DateTime time, Mobile poster, string message )
{
Time = time;
Poster = poster;
Message = message;
}
public PlayerBBMessage( GenericReader reader )
{
int version = reader.ReadEncodedInt();
switch ( version )
{
case 0:
{
Time = reader.ReadDateTime();
Poster = reader.ReadMobile();
Message = reader.ReadString();
break;
}
}
}
public void Serialize( GenericWriter writer )
{
writer.WriteEncodedInt( 0 ); // version
writer.Write( Time );
writer.Write( Poster );
writer.Write( Message );
}
}
public class PlayerBBGump : Gump
{
private int m_Page;
private Mobile m_From;
private BaseHouse m_House;
private BasePlayerBB m_Board;
private const int LabelColor = 0x7FFF;
private const int LabelHue = 1153;
public override void OnResponse( NetState sender, RelayInfo info )
{
int page = m_Page;
Mobile from = m_From;
BaseHouse house = m_House;
BasePlayerBB board = m_Board;
if ( house == null || !house.HasLockedDownItem( board ) )
{
from.SendLocalizedMessage( 1062396 ); // This bulletin board must be locked down in a house to be usable.
return;
}
if ( !from.InRange( board.GetWorldLocation(), 2 ) || !from.InLOS( board ) )
{
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
return;
}
if ( !BasePlayerBB.CheckAccess( house, from ) )
{
from.SendLocalizedMessage( 1062398 ); // You are not allowed to post to this bulletin board.
return;
}
switch ( info.ButtonID )
{
case 1: // Post message
{
from.Prompt = new BasePlayerBB.PostPrompt( page, house, board, false );
from.SendLocalizedMessage( 1062397 ); // Please enter your message:
break;
}
case 2: // Set title
{
if ( house.IsOwner( from ) )
{
from.Prompt = new BasePlayerBB.SetTitlePrompt( page, house, board );
from.SendLocalizedMessage( 1062402 ); // Enter new title:
}
break;
}
case 3: // Post greeting
{
if ( house.IsOwner( from ) )
{
from.Prompt = new BasePlayerBB.PostPrompt( page, house, board, true );
from.SendLocalizedMessage( 1062404 ); // Enter new greeting (this will always be the first post):
}
break;
}
case 4: // Scroll up
{
if ( page == 0 )
page = board.Messages.Count;
else
page -= 1;
from.SendGump( new PlayerBBGump( from, house, board, page ) );
break;
}
case 5: // Scroll down
{
page += 1;
page %= board.Messages.Count + 1;
from.SendGump( new PlayerBBGump( from, house, board, page ) );
break;
}
case 6: // Banish poster
{
if ( house.IsOwner( from ) )
{
if ( page >= 1 && page <= board.Messages.Count )
{
PlayerBBMessage message = board.Messages[page - 1];
Mobile poster = message.Poster;
if ( poster == null )
{
from.SendGump( new PlayerBBGump( from, house, board, page ) );
return;
}
if ( poster.AccessLevel > AccessLevel.Player && from.AccessLevel <= poster.AccessLevel )
{
from.SendLocalizedMessage( 501354 ); // Uh oh...a bigger boot may be required.
}
else if ( house.IsFriend( poster ) )
{
from.SendLocalizedMessage( 1060750 ); // That person is a friend, co-owner, or owner of this house, and therefore cannot be banished!
}
else if ( poster is PlayerVendor )
{
from.SendLocalizedMessage( 501351 ); // You cannot eject a vendor.
}
else if ( house.Bans.Count >= BaseHouse.MaxBans )
{
from.SendLocalizedMessage( 501355 ); // The ban limit for this house has been reached!
}
else if ( house.IsBanned( poster ) )
{
from.SendLocalizedMessage( 501356 ); // This person is already banned!
}
else if ( poster is BaseCreature creature && creature.NoHouseRestrictions )
{
from.SendLocalizedMessage( 1062040 ); // You cannot ban that.
}
else
{
if ( !house.Bans.Contains( poster ) )
house.Bans.Add( poster );
from.SendLocalizedMessage( 1062417 ); // That person has been banned from this house.
if ( house.IsInside( poster ) && !BasePlayerBB.CheckAccess( house, poster ) )
poster.MoveToWorld( house.BanLocation, house.Map );
}
}
from.SendGump( new PlayerBBGump( from, house, board, page ) );
}
break;
}
case 7: // Delete message
{
if ( house.IsOwner( from ) )
{
if ( page >= 1 && page <= board.Messages.Count )
board.Messages.RemoveAt( page - 1 );
from.SendGump( new PlayerBBGump( from, house, board, 0 ) );
}
break;
}
case 8: // Post props
{
if ( from.AccessLevel >= AccessLevel.GameMaster )
{
PlayerBBMessage message = board.Greeting;
if ( page >= 1 && page <= board.Messages.Count )
message = board.Messages[page - 1];
from.SendGump( new PlayerBBGump( from, house, board, page ) );
from.SendGump( new PropertiesGump( from, message ) );
}
break;
}
}
}
public PlayerBBGump( Mobile from, BaseHouse house, BasePlayerBB board, int page ) : base( 50, 10 )
{
from.CloseGump<PlayerBBGump>();
m_Page = page;
m_From = from;
m_House = house;
m_Board = board;
AddPage( 0 );
AddImage( 30, 30, 5400 );
AddButton( 393, 145, 2084, 2084, 4); // Scroll up
AddButton( 390, 371, 2085, 2085, 5); // Scroll down
AddButton( 32, 183, 5412, 5413, 1); // Post message
if ( house.IsOwner( from ) )
{
AddButton( 63, 90, 5601, 5605, 2);
AddHtmlLocalized( 81, 89, 230, 20, 1062400, LabelColor ); // Set title
AddButton( 63, 109, 5601, 5605, 3);
AddHtmlLocalized( 81, 108, 230, 20, 1062401, LabelColor ); // Post greeting
}
string title = board.Title;
if ( title != null )
AddHtml( 183, 68, 180, 23, title );
AddHtmlLocalized( 385, 89, 60, 20, 1062409, LabelColor ); // Post
AddLabel( 440, 89, LabelHue, page.ToString() );
AddLabel( 455, 89, LabelHue, "/" );
AddLabel( 470, 89, LabelHue, board.Messages.Count.ToString() );
PlayerBBMessage message = board.Greeting;
if ( page >= 1 && page <= board.Messages.Count )
message = board.Messages[page - 1];
AddImageTiled( 150, 220, 240, 1, 2700 ); // Separator
AddHtmlLocalized( 150, 180, 100, 20, 1062405, 16715 ); // Posted On:
AddHtmlLocalized( 150, 200, 100, 20, 1062406, 16715 ); // Posted By:
if ( message != null )
{
AddHtml( 255, 180, 150, 20, message.Time.ToString( "yyyy-MM-dd HH:mm:ss" ) );
Mobile poster = message.Poster;
string name = poster?.Name;
if ( name == null || (name = name.Trim()).Length == 0 )
name = "Someone";
AddHtml( 255, 200, 150, 20, name );
AddHtml( 150, 240, 250, 100, message.Message ?? "" );
if ( message != board.Greeting && house.IsOwner( from ) )
{
AddButton( 130, 395, 1209, 1210, 6);
AddHtmlLocalized( 150, 393, 150, 20, 1062410, LabelColor ); // Banish Poster
AddButton( 310, 395, 1209, 1210, 7);
AddHtmlLocalized( 330, 393, 150, 20, 1062411, LabelColor ); // Delete Message
}
if ( from.AccessLevel >= AccessLevel.GameMaster )
AddButton( 135, 242, 1209, 1210, 8); // Post props
}
}
}
}

View file

@ -0,0 +1,105 @@
using Server.Mobiles;
using Server.Multis;
namespace Server.Items
{
public class ContractOfEmployment : Item
{
[Constructible]
public ContractOfEmployment() : base(0x14F0)
{
Weight = 1.0;
//LootType = LootType.Blessed;
}
public ContractOfEmployment(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041243; // a contract of employment
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
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 if (from.AccessLevel >= AccessLevel.GameMaster)
{
from.SendLocalizedMessage(503248); // Your godly powers allow you to place this vendor whereever you wish.
Mobile v = new PlayerVendor(from, BaseHouse.FindHouseAt(from));
v.Direction = from.Direction & Direction.Mask;
v.MoveToWorld(from.Location, from.Map);
v.SayTo(from, 503246); // Ah! it feels good to be working again.
Delete();
}
else
{
BaseHouse house = BaseHouse.FindHouseAt(from);
if (house == null)
{
from.SendLocalizedMessage(503240); // Vendors can only be placed in houses.
}
else if (!BaseHouse.NewVendorSystem && !house.IsFriend(from))
{
from.SendLocalizedMessage(
503242); // You must ask the owner of this building to name you a friend of the household in order to place a vendor here.
}
else if (BaseHouse.NewVendorSystem && !house.IsOwner(from))
{
from.SendLocalizedMessage(
1062423); // Only the house owner can directly place vendors. Please ask the house owner to offer you a vendor contract so that you may place a vendor in this house.
}
else if (!house.Public || !house.CanPlaceNewVendor())
{
from.SendLocalizedMessage(
503241); // You cannot place this vendor or barkeep. Make sure the house is public and has sufficient storage available.
}
else
{
BaseHouse.IsThereVendor(from.Location, from.Map, out bool vendor, out bool contract);
if (vendor)
{
from.SendLocalizedMessage(1062677); // You cannot place a vendor or barkeep at this location.
}
else if (contract)
{
from.SendLocalizedMessage(
1062678); // You cannot place a vendor or barkeep on top of a rental contract!
}
else
{
Mobile v = new PlayerVendor(from, house);
v.Direction = from.Direction & Direction.Mask;
v.MoveToWorld(from.Location, from.Map);
v.SayTo(from, 503246); // Ah! it feels good to be working again.
Delete();
}
}
}
}
}
}

View file

@ -0,0 +1,95 @@
using System;
using Server.Mobiles;
using System.Collections.Generic;
namespace Server.Items
{
public class PoolOfAcid : Item
{
private TimeSpan m_Duration;
private int m_MinDamage;
private int m_MaxDamage;
private DateTime m_Created;
private bool m_Drying;
private Timer m_Timer;
[Constructible]
public PoolOfAcid() : this( TimeSpan.FromSeconds( 10.0 ), 2, 5 )
{
}
public override string DefaultName => "a pool of acid";
[Constructible]
public PoolOfAcid( TimeSpan duration, int minDamage, int maxDamage )
: base( 0x122A )
{
Hue = 0x3F;
Movable = false;
m_MinDamage = minDamage;
m_MaxDamage = maxDamage;
m_Created = DateTime.UtcNow;
m_Duration = duration;
m_Timer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromSeconds( 1 ), OnTick );
}
public override void OnAfterDelete()
{
m_Timer?.Stop();
}
private void OnTick()
{
DateTime now = DateTime.UtcNow;
TimeSpan age = now - m_Created;
if ( age > m_Duration ) {
Delete();
} else {
if ( !m_Drying && age > (m_Duration - age) )
{
m_Drying = true;
ItemID = 0x122B;
}
List<Mobile> toDamage = new List<Mobile>();
foreach( Mobile m in GetMobilesInRange( 0 ) )
{
if ( m.Alive && !m.IsDeadBondedPet && (!(m is BaseCreature bc) || bc.Controlled || bc.Summoned) )
{
toDamage.Add( m );
}
}
for ( int i = 0; i < toDamage.Count; i++ )
Damage( toDamage[i] );
}
}
public override bool OnMoveOver( Mobile m )
{
Damage( m );
return true;
}
public void Damage ( Mobile m )
{
m.Damage( Utility.RandomMinMax( m_MinDamage, m_MaxDamage ) );
}
public PoolOfAcid( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
//Don't serialize these
}
public override void Deserialize( GenericReader reader )
{
}
}
}

View file

@ -0,0 +1,41 @@
using Server.Network;
namespace Server.Items
{
public class PowerCrystal : Item
{
[Constructible]
public PowerCrystal() : base(0x1F1C)
{
Weight = 1.0;
}
public PowerCrystal(Serial serial) : base(serial)
{
}
public override string DefaultName => "power crystal";
public override void OnDoubleClick(Mobile from)
{
if (!from.InRange(GetWorldLocation(), 3))
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
else
from.SendAsciiMessage("This looks like part of a larger contraption.");
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,549 @@
using System;
using System.Collections.Generic;
using Server.Gumps;
using Server.Network;
namespace Server.Items
{
public class PowerGenerator : BaseAddon
{
[Constructible]
public PowerGenerator() : this(Utility.RandomMinMax(3, 6))
{
}
[Constructible]
public PowerGenerator(int sideLength)
{
AddGeneratorComponent(0x4FA1, 0, 0, 0);
AddGeneratorComponent(0x76, -1, 0, 0);
AddGeneratorComponent(0x75, 0, -1, 0);
AddGeneratorComponent(0x37F4, 0, 0, 13);
AddComponent(new ControlPanel(sideLength), 1, 0, -2);
}
public PowerGenerator(Serial serial) : base(serial)
{
}
public override bool ShareHue => false;
private void AddGeneratorComponent(int itemID, int x, int y, int z)
{
AddonComponent component = new AddonComponent(itemID);
component.Name = "a power generator";
component.Hue = 0x451;
AddComponent(component, x, y, z);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class ControlPanel : AddonComponent
{
private static readonly TimeSpan m_UseTimeout = TimeSpan.FromMinutes(2.0);
private HashSet<Mobile> m_DamageTable = new HashSet<Mobile>();
private DateTime m_LastUse;
private int m_SideLength;
private Mobile m_User;
public ControlPanel(int sideLength) : base(0xBDC)
{
Hue = 0x835;
SideLength = sideLength;
}
public ControlPanel(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public int SideLength
{
get => m_SideLength;
set
{
if (value < 3)
value = 3;
else if (value > 6)
value = 6;
if (m_SideLength != value)
{
m_SideLength = value;
InitPath();
}
}
}
public Node[] Path{ get; private set; }
public override string DefaultName => "a control panel";
public void InitPath()
{
// Depth-First Search algorithm
int totalNodes = SideLength * SideLength;
Node[] stack = new Node[totalNodes];
Node current = stack[0] = new Node(0, 0);
int stackSize = 1;
bool[,] visited = new bool[SideLength, SideLength];
visited[0, 0] = true;
while (true)
{
PathDirection[] choices = new PathDirection[4];
int count = 0;
if (current.X > 0 && !visited[current.X - 1, current.Y])
choices[count++] = PathDirection.Left;
if (current.Y > 0 && !visited[current.X, current.Y - 1])
choices[count++] = PathDirection.Up;
if (current.X < SideLength - 1 && !visited[current.X + 1, current.Y])
choices[count++] = PathDirection.Right;
if (current.Y < SideLength - 1 && !visited[current.X, current.Y + 1])
choices[count++] = PathDirection.Down;
if (count > 0)
{
PathDirection dir = choices[Utility.Random(count)];
switch (dir)
{
case PathDirection.Left:
current = new Node(current.X - 1, current.Y);
break;
case PathDirection.Up:
current = new Node(current.X, current.Y - 1);
break;
case PathDirection.Right:
current = new Node(current.X + 1, current.Y);
break;
default:
current = new Node(current.X, current.Y + 1);
break;
}
stack[stackSize++] = current;
if (current.X == SideLength - 1 && current.Y == SideLength - 1)
break;
visited[current.X, current.Y] = true;
}
else
{
current = stack[--stackSize - 1];
}
}
Path = new Node[stackSize];
for (int i = 0; i < stackSize; i++) Path[i] = stack[i];
if (m_User != null)
{
m_User.CloseGump<GameGump>();
m_User = null;
}
}
public override void OnDoubleClick(Mobile from)
{
if (!from.InRange(this, 3))
{
from.SendLocalizedMessage(500446); // That is too far away.
return;
}
if (m_User != null)
{
if (m_User == from)
return;
if (m_User.Deleted || m_User.Map != Map || !m_User.InRange(this, 3)
|| m_User.NetState == null || DateTime.UtcNow - m_LastUse >= m_UseTimeout)
{
m_User.CloseGump<GameGump>();
}
else
{
from.SendMessage("Someone is currently using the control panel.");
return;
}
}
m_User = from;
m_LastUse = DateTime.UtcNow;
from.SendGump(new GameGump(this, from, 0, false));
}
public void DoDamage(Mobile to)
{
to.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "", "",
"The generator shoots an arc of electricity at you!"));
to.BoltEffect(0);
to.LocalOverheadMessage(MessageType.Regular, 0xC9, true, "* Your body convulses from electric shock *");
to.NonlocalOverheadMessage(MessageType.Regular, 0xC9, true, $"* {to.Name} spasms from electric shock *");
AOS.Damage(to, to, 60, 0, 0, 0, 0, 100);
if (!to.Alive)
return;
if (!m_DamageTable.Contains(to))
{
to.Frozen = true;
DamageTimer timer = new DamageTimer(this, to);
m_DamageTable.Add(to);
timer.Start();
}
}
public void Solve(Mobile from)
{
Effects.PlaySound(Location, Map, 0x211);
Effects.PlaySound(Location, Map, 0x1F3);
Effects.SendLocationEffect(Location, Map, 0x36B0, 4, 4);
Effects.SendLocationEffect(new Point3D(X - 1, Y - 1, Z + 2), Map, 0x36B0, 4, 4);
Effects.SendLocationEffect(new Point3D(X - 2, Y - 1, Z + 2), Map, 0x36B0, 4, 4);
from.SendMessage("You scrounge some gems from the wreckage.");
for (int i = 0; i < SideLength; i++) from.AddToBackpack(new ArcaneGem());
from.AddToBackpack(new Diamond(SideLength));
Item ore = new ShadowIronOre(9);
ore.MoveToWorld(new Point3D(X - 1, Y, Z + 2), Map);
ore = new ShadowIronOre(14);
ore.MoveToWorld(new Point3D(X - 2, Y - 1, Z + 2), Map);
Delete();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(m_SideLength);
writer.WriteEncodedInt(Path.Length);
for (int i = 0; i < Path.Length; i++)
{
Node cur = Path[i];
writer.WriteEncodedInt(cur.X);
writer.WriteEncodedInt(cur.Y);
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
m_SideLength = reader.ReadEncodedInt();
Path = new Node[reader.ReadEncodedInt()];
for (int i = 0; i < Path.Length; i++) Path[i] = new Node(reader.ReadEncodedInt(), reader.ReadEncodedInt());
}
public struct Node
{
public int X{ get; set; }
public int Y{ get; set; }
public Node(int x, int y)
{
X = x;
Y = y;
}
}
private enum PathDirection
{
Left,
Up,
Right,
Down
}
private class GameGump : Gump
{
private Mobile m_From;
private ControlPanel m_Panel;
private int m_Step;
public GameGump(ControlPanel panel, Mobile from, int step, bool hint) : base(5, 30)
{
m_Panel = panel;
m_From = from;
m_Step = step;
int sideLength = panel.SideLength;
AddBackground(50, 0, 530, 410, 0xA28);
AddImage(0, 0, 0x28C8);
AddImage(547, 0, 0x28C9);
AddBackground(95, 20, 442, 90, 0xA28);
AddHtml(229, 35, 300, 45, "GENERATOR CONTROL PANEL");
AddHtml(223, 60, 300, 70, "Use the Directional Controls to");
AddHtml(253, 75, 300, 85, "Close the Grid Circuit");
AddImage(140, 40, 0x28D3);
AddImage(420, 40, 0x28D3);
AddBackground(365, 120, 178, 210, 0x1400);
AddImage(365, 115, 0x28D4);
AddImage(365, 288, 0x28D4);
AddImage(414, 189, 0x589);
AddImage(435, 210, 0xA52);
AddButton(408, 222, 0x29EA, 0x29EC, 1); // Left
AddButton(448, 185, 0x29CC, 0x29CE, 2); // Up
AddButton(473, 222, 0x29D6, 0x29D8, 3); // Right
AddButton(448, 243, 0x29E0, 0x29E2, 4); // Down
AddBackground(90, 115, 30 + 40 * sideLength, 30 + 40 * sideLength, 0xA28);
AddBackground(100, 125, 10 + 40 * sideLength, 10 + 40 * sideLength, 0x1400);
for (int i = 0; i < sideLength; i++)
for (int j = 0; j < sideLength - 1; j++)
AddImage(120 + 40 * i, 162 + 40 * j, 0x13F9);
for (int i = 0; i < sideLength - 1; i++)
for (int j = 0; j < sideLength; j++)
AddImage(138 + 40 * i, 147 + 40 * j, 0x13FD);
Node[] path = panel.Path;
NodeHue[,] hues = new NodeHue[sideLength, sideLength];
for (int i = 0; i <= step; i++)
{
Node n = path[i];
hues[n.X, n.Y] = NodeHue.Blue;
}
Node lastNode = path[path.Length - 1];
hues[lastNode.X, lastNode.Y] = NodeHue.Red;
for (int i = 0; i < sideLength; i++)
for (int j = 0; j < sideLength; j++)
AddNode(110 + 40 * i, 135 + 40 * j, hues[i, j]);
Node curNode = path[step];
AddImage(118 + 40 * curNode.X, 143 + 40 * curNode.Y, 0x13A8);
if (hint)
{
Node nextNode = path[step + 1];
AddImage(119 + 40 * nextNode.X, 143 + 40 * nextNode.Y, 0x939);
}
if (from.Skills.Lockpicking.Value >= 65.0)
{
AddButton(365, 350, 0xFA6, 0xFA7, 5);
AddHtml(405, 345, 140, 40, "Attempt to Decipher the Circuit Path");
}
}
private void AddNode(int x, int y, NodeHue hue)
{
int id;
switch (hue)
{
case NodeHue.Gray:
id = 0x25F8;
break;
case NodeHue.Blue:
id = 0x868;
break;
default:
id = 0x9A8;
break;
}
AddImage(x, y, id);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (m_Panel.Deleted || info.ButtonID == 0 || !m_From.CheckAlive())
{
m_Panel.m_User = null;
return;
}
if (m_From.Map != m_Panel.Map || !m_From.InRange(m_Panel, 3))
{
m_From.SendLocalizedMessage(500446); // That is too far away.
m_Panel.m_User = null;
return;
}
Node nextNode = m_Panel.Path[m_Step + 1];
if (info.ButtonID == 5) // Attempt to Decipher
{
double lockpicking = m_From.Skills.Lockpicking.Value;
if (lockpicking < 65.0)
return;
m_From.PlaySound(0x241);
if (40.0 + Utility.RandomDouble() * 80.0 < lockpicking)
{
m_From.SendGump(new GameGump(m_Panel, m_From, m_Step, true));
m_Panel.m_LastUse = DateTime.UtcNow;
}
else
{
m_Panel.DoDamage(m_From);
m_Panel.m_User = null;
}
}
else
{
Node curNode = m_Panel.Path[m_Step];
int newX, newY;
switch (info.ButtonID)
{
case 1: // Left
newX = curNode.X - 1;
newY = curNode.Y;
break;
case 2: // Up
newX = curNode.X;
newY = curNode.Y - 1;
break;
case 3: // Right
newX = curNode.X + 1;
newY = curNode.Y;
break;
case 4: // Down
newX = curNode.X;
newY = curNode.Y + 1;
break;
default:
return;
}
if (nextNode.X == newX && nextNode.Y == newY)
{
if (m_Step + 1 == m_Panel.Path.Length - 1)
{
m_Panel.Solve(m_From);
m_Panel.m_User = null;
}
else
{
m_From.PlaySound(0x1F4);
m_From.SendGump(new GameGump(m_Panel, m_From, m_Step + 1, false));
m_Panel.m_LastUse = DateTime.UtcNow;
}
}
else
{
m_Panel.DoDamage(m_From);
m_Panel.m_User = null;
}
}
}
private enum NodeHue
{
Gray,
Blue,
Red
}
}
private class DamageTimer : Timer
{
private ControlPanel m_Panel;
private int m_Step;
private Mobile m_To;
public DamageTimer(ControlPanel panel, Mobile to) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
{
m_Panel = panel;
m_To = to;
m_Step = 0;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if (m_Panel.Deleted || m_To.Deleted || !m_To.Alive)
{
End();
return;
}
m_To.PlaySound(0x28);
m_To.LocalOverheadMessage(MessageType.Regular, 0xC9, true, "* Your body convulses from electric shock *");
m_To.NonlocalOverheadMessage(MessageType.Regular, 0xC9, true,
$"* {m_To.Name} spasms from electric shock *");
AOS.Damage(m_To, m_To, 20, 0, 0, 0, 0, 100);
if (++m_Step >= 3 || !m_To.Alive) End();
}
private void End()
{
m_Panel.m_DamageTable.Remove(m_To);
m_To.Frozen = false;
Stop();
}
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class CrystallineFragments : Item
{
[Constructible]
public CrystallineFragments() : base(0x223B)
{
LootType = LootType.Blessed;
Hue = 0x47E;
}
public CrystallineFragments(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1073160; // Crystalline Fragments
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class IcyHeart : Item
{
[Constructible]
public IcyHeart() : base(0x24B)
{
}
public IcyHeart(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1073162; // Icy Heart
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,29 @@
namespace Server.Items
{
public class LuckyDagger : Item
{
[Constructible]
public LuckyDagger() : base(0xF52)
{
Hue = 0x8A5;
}
public LuckyDagger(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class ProtectorsEssence : Item
{
[Constructible]
public ProtectorsEssence() : base(0x23F)
{
}
public ProtectorsEssence(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1073159; // Protector's Essence
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,39 @@
namespace Server.Items
{
public class ShimmeringCrystals : Item
{
private static readonly int[] m_ItemIDs =
{
0x2206, 0x2207, 0x2208, 0x2209, 0x220A, 0x220B, 0x220C, 0x220D, 0x220E,
0x2210, 0x2211, 0x2212, 0x2213, 0x2214, 0x2215, 0x2216, 0x2217, 0x2218,
0x221A, 0x221B, 0x221C, 0x221D, 0x221E, 0x221F, 0x2220, 0x2221, 0x2222,
0x2224, 0x2225, 0x2226, 0x2227, 0x2228, 0x2229, 0x222A, 0x222B, 0x222C
};
[Constructible]
public ShimmeringCrystals() : base(Utility.RandomList(m_ItemIDs))
{
}
public ShimmeringCrystals(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1075095; // Shimmering Crystals
public override bool ForceShowProperties => true;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,156 @@
using Server.Gumps;
using Server.Network;
namespace Server.Items
{
public abstract class PromotionalToken : Item
{
public abstract Item CreateItemFor( Mobile from );
public abstract TextDefinition ItemName{ get; }
public abstract TextDefinition ItemReceiveMessage { get; }
public abstract TextDefinition ItemGumpName { get; }
public PromotionalToken() : base( 0x2AAA )
{
LootType = LootType.Blessed;
Light = LightType.Circle300;
Weight = 5.0;
}
public PromotionalToken( Serial serial ) : base( serial )
{
}
public override void GetProperties( ObjectPropertyList list )
{
base.GetProperties( list );
list.Add( 1070998, ItemName.ToString() ); // Use this to redeem<br>your ~1_PROMO~
}
public override void OnDoubleClick( Mobile from )
{
if ( !IsChildOf( from.Backpack ) )
{
from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used.
}
else
{
from.CloseGump<PromotionalTokenGump>();
from.SendGump( new PromotionalTokenGump( this ) );
}
}
public override void OnRemoved(IEntity parent)
{
Mobile m = null;
if ( parent is Item item )
m = item.RootParent as Mobile;
else if ( parent is Mobile mobile )
m = mobile;
m?.CloseGump<PromotionalTokenGump>();
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( 0 );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
public override int LabelNumber => 1070997; // A promotional token
private class PromotionalTokenGump : Gump
{
private PromotionalToken m_Token;
public PromotionalTokenGump( PromotionalToken token ) : base( 10, 10 )
{
m_Token = token;
AddPage( 0 );
AddBackground( 0, 0, 240, 135, 0x2422 );
AddHtmlLocalized( 15, 15, 210, 75, 1070972, 0x0, true ); // Click "OKAY" to redeem the following promotional item:
TextDefinition.AddHtmlText( this, 15, 60, 210, 75, m_Token.ItemGumpName, false, false );
AddButton( 160, 95, 0xF7, 0xF8, 1); //Okay
AddButton( 90, 95, 0xF2, 0xF1, 0); //Cancel
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( info.ButtonID != 1 )
return;
Mobile from = sender.Mobile;
if ( !m_Token.IsChildOf( from.Backpack ) )
{
from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used.
}
else
{
Item i = m_Token.CreateItemFor( from );
if ( i != null )
{
from.BankBox.AddItem( i );
TextDefinition.SendMessageTo( from, m_Token.ItemReceiveMessage );
m_Token.Delete();
}
}
}
}
}
public class SoulstoneFragmentToken : PromotionalToken
{
public override Item CreateItemFor( Mobile from )
{
if ( from?.Account != null )
return new SoulstoneFragment( from.Account.ToString() );
return null;
}
public override TextDefinition ItemGumpName => 1070999;// <center>Soulstone Fragment</center>
public override TextDefinition ItemName => 1071000;//soulstone fragment
public override TextDefinition ItemReceiveMessage => 1070976; // A soulstone fragment has been created in your bank box.
[Constructible]
public SoulstoneFragmentToken()
{
}
public SoulstoneFragmentToken( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( 0 );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,421 @@
using System;
using System.Collections.Generic;
using Server.Commands;
using Server.Factions;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
using Server.Spells;
namespace Server.Items
{
public class PublicMoongate : Item
{
[Constructible]
public PublicMoongate() : base(0xF6C)
{
Movable = false;
Light = LightType.Circle300;
}
public PublicMoongate(Serial serial) : base(serial)
{
}
public override bool ForceShowProperties => ObjectPropertyList.Enabled;
public override bool HandlesOnMovement => true;
public override void OnDoubleClick(Mobile from)
{
if (!from.Player)
return;
if (from.InRange(GetWorldLocation(), 1))
UseGate(from);
else
from.SendLocalizedMessage(500446); // That is too far away.
}
public override bool OnMoveOver(Mobile m)
{
// Changed so criminals are not blocked by it.
if (m.Player)
UseGate(m);
return true;
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (m is PlayerMobile)
if (!Utility.InRange(m.Location, Location, 1) && Utility.InRange(oldLocation, Location, 1))
m.CloseGump<MoongateGump>();
}
public bool UseGate(Mobile m)
{
if (m.Criminal)
{
m.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily.
return false;
}
if (SpellHelper.CheckCombat(m))
{
m.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle??
return false;
}
if (m.Spell != null)
{
m.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
return false;
}
m.CloseGump<MoongateGump>();
m.SendGump(new MoongateGump(m, this));
if (!m.Hidden || m.AccessLevel == AccessLevel.Player)
Effects.PlaySound(m.Location, m.Map, 0x20E);
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public static void Initialize()
{
CommandSystem.Register("MoonGen", AccessLevel.Administrator, MoonGen_OnCommand);
}
[Usage("MoonGen")]
[Description("Generates public moongates. Removes all old moongates.")]
public static void MoonGen_OnCommand(CommandEventArgs e)
{
DeleteAll();
int count = 0;
count += MoonGen(PMList.Trammel);
count += MoonGen(PMList.Felucca);
count += MoonGen(PMList.Ilshenar);
count += MoonGen(PMList.Malas);
count += MoonGen(PMList.Tokuno);
World.Broadcast(0x35, true, "{0} moongates generated.", count);
}
private static void DeleteAll()
{
List<Item> list = new List<Item>();
foreach (Item item in World.Items.Values)
if (item is PublicMoongate)
list.Add(item);
foreach (Item item in list)
item.Delete();
if (list.Count > 0)
World.Broadcast(0x35, true, "{0} moongates removed.", list.Count);
}
private static int MoonGen(PMList list)
{
foreach (PMEntry entry in list.Entries)
{
Item item = new PublicMoongate();
item.MoveToWorld(entry.Location, list.Map);
if (entry.Number == 1060642) // Umbra
item.Hue = 0x497;
}
return list.Entries.Length;
}
}
public class PMEntry
{
public PMEntry(Point3D loc, int number)
{
Location = loc;
Number = number;
}
public Point3D Location{ get; }
public int Number{ get; }
}
public class PMList
{
public static readonly PMList Trammel =
new PMList(1012000, 1012012, Map.Trammel, new[]
{
new PMEntry(new Point3D(4467, 1283, 5), 1012003), // Moonglow
new PMEntry(new Point3D(1336, 1997, 5), 1012004), // Britain
new PMEntry(new Point3D(1499, 3771, 5), 1012005), // Jhelom
new PMEntry(new Point3D(771, 752, 5), 1012006), // Yew
new PMEntry(new Point3D(2701, 692, 5), 1012007), // Minoc
new PMEntry(new Point3D(1828, 2948, -20), 1012008), // Trinsic
new PMEntry(new Point3D(643, 2067, 5), 1012009), // Skara Brae
/* Dynamic Z for Magincia to support both old and new maps. */
new PMEntry(new Point3D(3563, 2139, Map.Trammel.GetAverageZ(3563, 2139)), 1012010), // (New) Magincia
new PMEntry(new Point3D(3450, 2677, 25), 1078098) // New Haven
});
public static readonly PMList Felucca =
new PMList(1012001, 1012013, Map.Felucca, new[]
{
new PMEntry(new Point3D(4467, 1283, 5), 1012003), // Moonglow
new PMEntry(new Point3D(1336, 1997, 5), 1012004), // Britain
new PMEntry(new Point3D(1499, 3771, 5), 1012005), // Jhelom
new PMEntry(new Point3D(771, 752, 5), 1012006), // Yew
new PMEntry(new Point3D(2701, 692, 5), 1012007), // Minoc
new PMEntry(new Point3D(1828, 2948, -20), 1012008), // Trinsic
new PMEntry(new Point3D(643, 2067, 5), 1012009), // Skara Brae
/* Dynamic Z for Magincia to support both old and new maps. */
new PMEntry(new Point3D(3563, 2139, Map.Felucca.GetAverageZ(3563, 2139)), 1012010), // (New) Magincia
new PMEntry(new Point3D(2711, 2234, 0), 1019001) // Buccaneer's Den
});
public static readonly PMList Ilshenar =
new PMList(1012002, 1012014, Map.Ilshenar, new[]
{
new PMEntry(new Point3D(1215, 467, -13), 1012015), // Compassion
new PMEntry(new Point3D(722, 1366, -60), 1012016), // Honesty
new PMEntry(new Point3D(744, 724, -28), 1012017), // Honor
new PMEntry(new Point3D(281, 1016, 0), 1012018), // Humility
new PMEntry(new Point3D(987, 1011, -32), 1012019), // Justice
new PMEntry(new Point3D(1174, 1286, -30), 1012020), // Sacrifice
new PMEntry(new Point3D(1532, 1340, -3), 1012021), // Spirituality
new PMEntry(new Point3D(528, 216, -45), 1012022), // Valor
new PMEntry(new Point3D(1721, 218, 96), 1019000) // Chaos
});
public static readonly PMList Malas =
new PMList(1060643, 1062039, Map.Malas, new[]
{
new PMEntry(new Point3D(1015, 527, -65), 1060641), // Luna
new PMEntry(new Point3D(1997, 1386, -85), 1060642) // Umbra
});
public static readonly PMList Tokuno =
new PMList(1063258, 1063415, Map.Tokuno, new[]
{
new PMEntry(new Point3D(1169, 998, 41), 1063412), // Isamu-Jima
new PMEntry(new Point3D(802, 1204, 25), 1063413), // Makoto-Jima
new PMEntry(new Point3D(270, 628, 15), 1063414) // Homare-Jima
});
public static readonly PMList[] UORLists = { Trammel, Felucca };
public static readonly PMList[] UORListsYoung = { Trammel };
public static readonly PMList[] LBRLists = { Trammel, Felucca, Ilshenar };
public static readonly PMList[] LBRListsYoung = { Trammel, Ilshenar };
public static readonly PMList[] AOSLists = { Trammel, Felucca, Ilshenar, Malas };
public static readonly PMList[] AOSListsYoung = { Trammel, Ilshenar, Malas };
public static readonly PMList[] SELists = { Trammel, Felucca, Ilshenar, Malas, Tokuno };
public static readonly PMList[] SEListsYoung = { Trammel, Ilshenar, Malas, Tokuno };
public static readonly PMList[] RedLists = { Felucca };
public static readonly PMList[] SigilLists = { Felucca };
public PMList(int number, int selNumber, Map map, PMEntry[] entries)
{
Number = number;
SelNumber = selNumber;
Map = map;
Entries = entries;
}
public int Number{ get; }
public int SelNumber{ get; }
public Map Map{ get; }
public PMEntry[] Entries{ get; }
}
public class MoongateGump : Gump
{
private PMList[] m_Lists;
private Mobile m_Mobile;
private Item m_Moongate;
public MoongateGump(Mobile mobile, Item moongate) : base(100, 100)
{
m_Mobile = mobile;
m_Moongate = moongate;
PMList[] checkLists;
if (mobile.Player)
{
if (Sigil.ExistsOn(mobile))
{
checkLists = PMList.SigilLists;
}
else if (mobile.Kills >= 5)
{
checkLists = PMList.RedLists;
}
else
{
ClientFlags flags = mobile.NetState?.Flags ?? ClientFlags.None;
bool young = mobile is PlayerMobile playerMobile && playerMobile.Young;
if (Core.SE && (flags & ClientFlags.Tokuno) != 0)
checkLists = young ? PMList.SEListsYoung : PMList.SELists;
else if (Core.AOS && (flags & ClientFlags.Malas) != 0)
checkLists = young ? PMList.AOSListsYoung : PMList.AOSLists;
else if ((flags & ClientFlags.Ilshenar) != 0)
checkLists = young ? PMList.LBRListsYoung : PMList.LBRLists;
else
checkLists = young ? PMList.UORListsYoung : PMList.UORLists;
}
}
else
{
checkLists = PMList.SELists;
}
m_Lists = new PMList[checkLists.Length];
for (int i = 0; i < m_Lists.Length; ++i)
m_Lists[i] = checkLists[i];
for (int i = 0; i < m_Lists.Length; ++i)
if (m_Lists[i].Map == mobile.Map)
{
PMList temp = m_Lists[i];
m_Lists[i] = m_Lists[0];
m_Lists[0] = temp;
break;
}
AddPage(0);
AddBackground(0, 0, 380, 280, 5054);
AddButton(10, 210, 4005, 4007, 1);
AddHtmlLocalized(45, 210, 140, 25, 1011036); // OKAY
AddButton(10, 235, 4005, 4007, 0);
AddHtmlLocalized(45, 235, 140, 25, 1011012); // CANCEL
AddHtmlLocalized(5, 5, 200, 20, 1012011); // Pick your destination:
for (int i = 0; i < checkLists.Length; ++i)
{
AddButton(10, 35 + i * 25, 2117, 2118, 0, GumpButtonType.Page, Array.IndexOf(m_Lists, checkLists[i]) + 1);
AddHtmlLocalized(30, 35 + i * 25, 150, 20, checkLists[i].Number);
}
for (int i = 0; i < m_Lists.Length; ++i)
RenderPage(i, Array.IndexOf(checkLists, m_Lists[i]));
}
private void RenderPage(int index, int offset)
{
PMList list = m_Lists[index];
AddPage(index + 1);
AddButton(10, 35 + offset * 25, 2117, 2118, 0, GumpButtonType.Page, index + 1);
AddHtmlLocalized(30, 35 + offset * 25, 150, 20, list.SelNumber);
PMEntry[] entries = list.Entries;
for (int i = 0; i < entries.Length; ++i)
{
AddRadio(200, 35 + i * 25, 210, 211, false, index * 100 + i);
AddHtmlLocalized(225, 35 + i * 25, 150, 20, entries[i].Number);
}
}
public override void OnResponse(NetState state, RelayInfo info)
{
if (info.ButtonID == 0) // Cancel
return;
if (m_Mobile.Deleted || m_Moongate.Deleted || m_Mobile.Map == null)
return;
int[] switches = info.Switches;
if (switches.Length == 0)
return;
int switchID = switches[0];
int listIndex = switchID / 100;
int listEntry = switchID % 100;
if (listIndex < 0 || listIndex >= m_Lists.Length)
return;
PMList list = m_Lists[listIndex];
if (listEntry < 0 || listEntry >= list.Entries.Length)
return;
PMEntry entry = list.Entries[listEntry];
if (!m_Mobile.InRange(m_Moongate.GetWorldLocation(), 1) || m_Mobile.Map != m_Moongate.Map)
{
m_Mobile.SendLocalizedMessage(1019002); // You are too far away to use the gate.
}
else if (m_Mobile.Player && m_Mobile.Kills >= 5 && list.Map != Map.Felucca)
{
m_Mobile.SendLocalizedMessage(1019004); // You are not allowed to travel there.
}
else if (Sigil.ExistsOn(m_Mobile) && list.Map != Faction.Facet)
{
m_Mobile.SendLocalizedMessage(1019004); // You are not allowed to travel there.
}
else if (m_Mobile.Criminal)
{
m_Mobile.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily.
}
else if (SpellHelper.CheckCombat(m_Mobile))
{
m_Mobile.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle??
}
else if (m_Mobile.Spell != null)
{
m_Mobile.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
}
else if (m_Mobile.Map == list.Map && m_Mobile.InRange(entry.Location, 1))
{
m_Mobile.SendLocalizedMessage(1019003); // You are already there.
}
else
{
BaseCreature.TeleportPets(m_Mobile, entry.Location, list.Map);
m_Mobile.Combatant = null;
m_Mobile.Warmode = false;
m_Mobile.Hidden = true;
m_Mobile.MoveToWorld(entry.Location, list.Map);
Effects.PlaySound(entry.Location, list.Map, 0x1FE);
}
}
}
}

View file

@ -0,0 +1,662 @@
namespace Server.Items
{
public class Rope : Item
{
[Constructible]
public Rope(int amount = 1) : base(0x14F8)
{
Stackable = true;
Weight = 1.0;
Amount = amount;
}
public Rope(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class IronWire : Item
{
[Constructible]
public IronWire(int amount = 1) : base(0x1876)
{
Stackable = true;
Weight = 5.0;
Amount = amount;
}
public IronWire(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version < 1 && Weight == 2.0)
Weight = 5.0;
}
}
public class SilverWire : Item
{
[Constructible]
public SilverWire(int amount = 1) : base(0x1877)
{
Stackable = true;
Weight = 5.0;
Amount = amount;
}
public SilverWire(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version < 1 && Weight == 2.0)
Weight = 5.0;
}
}
public class GoldWire : Item
{
[Constructible]
public GoldWire(int amount = 1) : base(0x1878)
{
Stackable = true;
Weight = 5.0;
Amount = amount;
}
public GoldWire(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version < 1 && Weight == 2.0)
Weight = 5.0;
}
}
public class CopperWire : Item
{
[Constructible]
public CopperWire(int amount = 1) : base(0x1879)
{
Stackable = true;
Weight = 5.0;
Amount = amount;
}
public CopperWire(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version < 1 && Weight == 2.0)
Weight = 5.0;
}
}
public class WhiteDriedFlowers : Item
{
[Constructible]
public WhiteDriedFlowers(int amount = 1) : base(0xC3C)
{
Stackable = true;
Weight = 1.0;
Amount = amount;
}
public WhiteDriedFlowers(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class GreenDriedFlowers : Item
{
[Constructible]
public GreenDriedFlowers(int amount = 1) : base(0xC3E)
{
Stackable = true;
Weight = 1.0;
Amount = amount;
}
public GreenDriedFlowers(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class DriedOnions : Item
{
[Constructible]
public DriedOnions(int amount = 1) : base(0xC40)
{
Stackable = true;
Weight = 1.0;
Amount = amount;
}
public DriedOnions(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class DriedHerbs : Item
{
[Constructible]
public DriedHerbs(int amount = 1) : base(0xC42)
{
Stackable = true;
Weight = 1.0;
Amount = amount;
}
public DriedHerbs(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class HorseShoes : Item
{
[Constructible]
public HorseShoes() : base(0xFB6)
{
Weight = 3.0;
}
public HorseShoes(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class ForgedMetal : Item
{
[Constructible]
public ForgedMetal() : base(0xFB8)
{
Weight = 5.0;
}
public ForgedMetal(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class Whip : Item
{
[Constructible]
public Whip() : base(0x166E)
{
Weight = 1.0;
}
public Whip(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class PaintsAndBrush : Item
{
[Constructible]
public PaintsAndBrush() : base(0xFC1)
{
Weight = 1.0;
}
public PaintsAndBrush(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class PenAndInk : Item
{
[Constructible]
public PenAndInk() : base(0xFBF)
{
Weight = 1.0;
}
public PenAndInk(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class ChiselsNorth : Item
{
[Constructible]
public ChiselsNorth() : base(0x1026)
{
Weight = 1.0;
}
public ChiselsNorth(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class ChiselsWest : Item
{
[Constructible]
public ChiselsWest() : base(0x1027)
{
Weight = 1.0;
}
public ChiselsWest(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class DirtyPan : Item
{
[Constructible]
public DirtyPan() : base(0x9E8)
{
Weight = 1.0;
}
public DirtyPan(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class DirtySmallRoundPot : Item
{
[Constructible]
public DirtySmallRoundPot() : base(0x9E7)
{
Weight = 1.0;
}
public DirtySmallRoundPot(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class DirtyPot : Item
{
[Constructible]
public DirtyPot() : base(0x9E6)
{
Weight = 1.0;
}
public DirtyPot(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class DirtyRoundPot : Item
{
[Constructible]
public DirtyRoundPot() : base(0x9DF)
{
Weight = 1.0;
}
public DirtyRoundPot(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class DirtyFrypan : Item
{
[Constructible]
public DirtyFrypan() : base(0x9DE)
{
Weight = 1.0;
}
public DirtyFrypan(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class DirtySmallPot : Item
{
[Constructible]
public DirtySmallPot() : base(0x9DD)
{
Weight = 1.0;
}
public DirtySmallPot(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class DirtyKettle : Item
{
[Constructible]
public DirtyKettle() : base(0x9DC)
{
Weight = 1.0;
}
public DirtyKettle(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,87 @@
using Server.Targeting;
namespace Server.Items
{
public class Scales : Item
{
[Constructible]
public Scales() : base(0x1852)
{
Weight = 4.0;
}
public Scales(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public override void OnDoubleClick(Mobile from)
{
from.SendLocalizedMessage(502431); // What would you like to weigh?
from.Target = new InternalTarget(this);
}
private class InternalTarget : Target
{
private Scales m_Item;
public InternalTarget(Scales item) : base(1, false, TargetFlags.None)
{
m_Item = item;
}
protected override void OnTarget(Mobile from, object targeted)
{
string message;
if (targeted == m_Item)
{
message = "It cannot weight itself.";
}
else if (targeted is Item item)
{
IEntity root = item.RootParent;
if (root != null && root != from || item.Parent == from)
{
message = "You decide that item's current location is too awkward to get an accurate result.";
}
else if (item.Movable)
{
message = item.Amount > 1 ? "You place one item on the scale. " : "You place that item on the scale. ";
double weight = item.Weight;
if (weight <= 0.0)
message += "It is lighter than a feather.";
else
message += $"It weighs {weight} stones.";
}
else
{
message = "You cannot weigh that object.";
}
}
else
{
message = "You cannot weigh that object.";
}
from.SendMessage(message);
}
}
}
}

View file

@ -0,0 +1,103 @@
using Server.Multis;
namespace Server.Items
{
public class SerpentPillar : Item
{
[Constructible]
public SerpentPillar() : this(null, new Rectangle2D(), false)
{
}
public SerpentPillar(string word, Rectangle2D destination, bool active = true) : base(0x233F)
{
Movable = false;
Active = active;
Word = word;
Destination = destination;
}
public SerpentPillar(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public bool Active{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public string Word{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public Rectangle2D Destination{ get; set; }
public override bool HandlesOnSpeech => true;
public override void OnSpeech(SpeechEventArgs e)
{
Mobile from = e.Mobile;
if (!e.Handled && from.InRange(this, 10) && e.Speech.ToLower() == Word)
{
BaseBoat boat = BaseBoat.FindBoatAt(from, from.Map);
if (boat == null)
return;
if (!Active)
{
boat.TillerMan
?.Say(502507); // Ar, Legend has it that these pillars are inactive! No man knows how it might be undone!
return;
}
Map map = from.Map;
for (int i = 0; i < 5; i++) // Try 5 times
{
int x = Utility.Random(Destination.X, Destination.Width);
int y = Utility.Random(Destination.Y, Destination.Height);
int z = map.GetAverageZ(x, y);
Point3D dest = new Point3D(x, y, z);
if (boat.CanFit(dest, map, boat.ItemID))
{
int xOffset = x - boat.X;
int yOffset = y - boat.Y;
int zOffset = z - boat.Z;
boat.Teleport(xOffset, yOffset, zOffset);
return;
}
}
boat.TillerMan?.Say(502508); // Ar, I refuse to take that matey through here!
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.Write(Active);
writer.Write(Word);
writer.Write(Destination);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
Active = reader.ReadBool();
Word = reader.ReadString();
Destination = reader.ReadRect2D();
}
}
}

View file

@ -0,0 +1,162 @@
using Server.Gumps;
using Server.Network;
namespace Server.Items
{
public class SpecialBeardDye : Item
{
[Constructible]
public SpecialBeardDye() : base(0xE26)
{
Weight = 1.0;
LootType = LootType.Newbied;
}
public SpecialBeardDye(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041087; // Special Beard Dye
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public override void OnDoubleClick(Mobile from)
{
if (from.InRange(GetWorldLocation(), 1))
{
from.CloseGump<SpecialBeardDyeGump>();
from.SendGump(new SpecialBeardDyeGump(this));
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 906, 1019045); // I can't reach that.
}
}
}
public class SpecialBeardDyeGump : Gump
{
private static SpecialBeardDyeEntry[] m_Entries =
{
new SpecialBeardDyeEntry("*****", 12, 10),
new SpecialBeardDyeEntry("*****", 32, 5),
new SpecialBeardDyeEntry("*****", 38, 8),
new SpecialBeardDyeEntry("*****", 54, 3),
new SpecialBeardDyeEntry("*****", 62, 10),
new SpecialBeardDyeEntry("*****", 81, 2),
new SpecialBeardDyeEntry("*****", 89, 2),
new SpecialBeardDyeEntry("*****", 1153, 2)
};
private SpecialBeardDye m_SpecialBeardDye;
public SpecialBeardDyeGump(SpecialBeardDye dye) : base(0, 0)
{
m_SpecialBeardDye = dye;
AddPage(0);
AddBackground(150, 60, 350, 358, 2600);
AddBackground(170, 104, 110, 270, 5100);
AddHtmlLocalized(230, 75, 200, 20, 1011013); // Hair Color Selection Menu
AddHtmlLocalized(235, 380, 300, 20, 1013007); // Dye my beard this color!
AddButton(200, 380, 0xFA5, 0xFA7, 1); // DYE HAIR
for (int i = 0; i < m_Entries.Length; ++i)
{
AddLabel(180, 109 + i * 22, m_Entries[i].HueStart - 1, m_Entries[i].Name);
AddButton(257, 110 + i * 22, 5224, 5224, 0, GumpButtonType.Page, i + 1);
}
for (int i = 0; i < m_Entries.Length; ++i)
{
SpecialBeardDyeEntry e = m_Entries[i];
AddPage(i + 1);
for (int j = 0; j < e.HueCount; ++j)
{
AddLabel(328 + j / 16 * 80, 102 + j % 16 * 17, e.HueStart + j - 1, "*****");
AddRadio(310 + j / 16 * 80, 102 + j % 16 * 17, 210, 211, false, i * 100 + j);
}
}
}
public override void OnResponse(NetState from, RelayInfo info)
{
if (m_SpecialBeardDye.Deleted)
return;
Mobile m = from.Mobile;
int[] switches = info.Switches;
if (!m_SpecialBeardDye.IsChildOf(m.Backpack))
{
m.SendLocalizedMessage(1042010); //You must have the objectin your backpack to use it.
return;
}
if (info.ButtonID != 0 && switches.Length > 0)
{
if (m.FacialHairItemID == 0)
{
m.SendLocalizedMessage(502623); // You have no hair to dye and cannot use this
}
else
{
// To prevent this from being exploited, the hue is abstracted into an internal list
int entryIndex = switches[0] / 100;
int hueOffset = switches[0] % 100;
if (entryIndex >= 0 && entryIndex < m_Entries.Length)
{
SpecialBeardDyeEntry e = m_Entries[entryIndex];
if (hueOffset >= 0 && hueOffset < e.HueCount)
{
int hue = e.HueStart + hueOffset;
m.FacialHairHue = hue;
m.SendLocalizedMessage(501199); // You dye your hair
m_SpecialBeardDye.Delete();
m.PlaySound(0x4E);
}
}
}
}
else
{
m.SendLocalizedMessage(501200); // You decide not to dye your hair
}
}
private class SpecialBeardDyeEntry
{
public SpecialBeardDyeEntry(string name, int hueStart, int hueCount)
{
Name = name;
HueStart = hueStart;
HueCount = hueCount;
}
public string Name{ get; }
public int HueStart{ get; }
public int HueCount{ get; }
}
}
}

View file

@ -0,0 +1,163 @@
using Server.Gumps;
using Server.Network;
namespace Server.Items
{
public class SpecialHairDye : Item
{
[Constructible]
public SpecialHairDye() : base(0xE26)
{
Weight = 1.0;
LootType = LootType.Newbied;
}
public SpecialHairDye(Serial serial) : base(serial)
{
}
public override string DefaultName => "Special Hair Dye";
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public override void OnDoubleClick(Mobile from)
{
if (from.InRange(GetWorldLocation(), 1))
{
from.CloseGump<SpecialHairDyeGump>();
from.SendGump(new SpecialHairDyeGump(this));
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 906, 1019045); // I can't reach that.
}
}
}
public class SpecialHairDyeGump : Gump
{
private static SpecialHairDyeEntry[] m_Entries =
{
new SpecialHairDyeEntry("*****", 12, 10),
new SpecialHairDyeEntry("*****", 32, 5),
new SpecialHairDyeEntry("*****", 38, 8),
new SpecialHairDyeEntry("*****", 54, 3),
new SpecialHairDyeEntry("*****", 62, 10),
new SpecialHairDyeEntry("*****", 81, 2),
new SpecialHairDyeEntry("*****", 89, 2),
new SpecialHairDyeEntry("*****", 1153, 2)
};
private SpecialHairDye m_SpecialHairDye;
public SpecialHairDyeGump(SpecialHairDye dye) : base(0, 0)
{
m_SpecialHairDye = dye;
AddPage(0);
AddBackground(150, 60, 350, 358, 2600);
AddBackground(170, 104, 110, 270, 5100);
AddHtmlLocalized(230, 75, 200, 20, 1011013); // Hair Color Selection Menu
AddHtmlLocalized(235, 380, 300, 20, 1011014); // Dye my hair this color!
AddButton(200, 380, 0xFA5, 0xFA7, 1); // DYE HAIR
for (int i = 0; i < m_Entries.Length; ++i)
{
AddLabel(180, 109 + i * 22, m_Entries[i].HueStart - 1, m_Entries[i].Name);
AddButton(257, 110 + i * 22, 5224, 5224, 0, GumpButtonType.Page, i + 1);
}
for (int i = 0; i < m_Entries.Length; ++i)
{
SpecialHairDyeEntry e = m_Entries[i];
AddPage(i + 1);
for (int j = 0; j < e.HueCount; ++j)
{
AddLabel(328 + j / 16 * 80, 102 + j % 16 * 17, e.HueStart + j - 1, "*****");
AddRadio(310 + j / 16 * 80, 102 + j % 16 * 17, 210, 211, false, i * 100 + j);
}
}
}
public override void OnResponse(NetState from, RelayInfo info)
{
if (m_SpecialHairDye.Deleted)
return;
Mobile m = from.Mobile;
int[] switches = info.Switches;
if (!m_SpecialHairDye.IsChildOf(m.Backpack))
{
m.SendLocalizedMessage(1042010); //You must have the objectin your backpack to use it.
return;
}
if (info.ButtonID != 0 && switches.Length > 0)
{
if (m.HairItemID == 0)
{
m.SendLocalizedMessage(502623); // You have no hair to dye and cannot use this
}
else
{
// To prevent this from being exploited, the hue is abstracted into an internal list
int entryIndex = switches[0] / 100;
int hueOffset = switches[0] % 100;
if (entryIndex >= 0 && entryIndex < m_Entries.Length)
{
SpecialHairDyeEntry e = m_Entries[entryIndex];
if (hueOffset >= 0 && hueOffset < e.HueCount)
{
m_SpecialHairDye.Delete();
int hue = e.HueStart + hueOffset;
m.HairHue = hue;
m.SendLocalizedMessage(501199); // You dye your hair
m.PlaySound(0x4E);
}
}
}
}
else
{
m.SendLocalizedMessage(501200); // You decide not to dye your hair
}
}
private class SpecialHairDyeEntry
{
public SpecialHairDyeEntry(string name, int hueStart, int hueCount)
{
Name = name;
HueStart = hueStart;
HueCount = hueCount;
}
public string Name{ get; }
public int HueStart{ get; }
public int HueCount{ get; }
}
}
}

View file

@ -0,0 +1,99 @@
namespace Server.Items
{
public class Static : Item
{
public Static() : base(0x80)
{
Movable = false;
}
[Constructible]
public Static(int itemID) : base(itemID)
{
Movable = false;
}
[Constructible]
public Static(int itemID, int count) : this(Utility.Random(itemID, count))
{
}
public Static(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version == 0 && Weight == 0)
Weight = -1;
}
}
public class LocalizedStatic : Static
{
private int m_LabelNumber;
[Constructible]
public LocalizedStatic(int itemID) : this(itemID, itemID < 0x4000 ? 1020000 + itemID : 1078872 + itemID)
{
}
[Constructible]
public LocalizedStatic(int itemID, int labelNumber) : base(itemID)
{
m_LabelNumber = labelNumber;
}
public LocalizedStatic(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public int Number
{
get => m_LabelNumber;
set
{
m_LabelNumber = value;
InvalidateProperties();
}
}
public override int LabelNumber => m_LabelNumber;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((byte)0); // version
writer.WriteEncodedInt(m_LabelNumber);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadByte();
switch (version)
{
case 0:
{
m_LabelNumber = reader.ReadEncodedInt();
break;
}
}
}
}
}

View file

@ -0,0 +1,32 @@
namespace Server.Items
{
public class SwarmOfFlies : Item
{
[Constructible]
public SwarmOfFlies() : base(0x91B)
{
Hue = 1;
Movable = false;
}
public SwarmOfFlies(Serial serial) : base(serial)
{
}
public override string DefaultName => "a swarm of flies";
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class DragonFlameSectBadge : Item
{
[Constructible]
public DragonFlameSectBadge() : base(0x23E)
{
LootType = LootType.Blessed;
}
public DragonFlameSectBadge(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1073141; // A Dragon Flame Sect Badge
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class OrdersFromMinax : Item
{
[Constructible]
public OrdersFromMinax() : base(0x2279)
{
LootType = LootType.Blessed;
}
public OrdersFromMinax(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1074639; // Orders from Minax
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class SerpentFangSectBadge : Item
{
[Constructible]
public SerpentFangSectBadge() : base(0x23C)
{
LootType = LootType.Blessed;
}
public SerpentFangSectBadge(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1073139; // A Serpent Fang Sect Badge
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class TigerClawSectBadge : Item
{
[Constructible]
public TigerClawSectBadge() : base(0x23D)
{
LootType = LootType.Blessed;
}
public TigerClawSectBadge(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1073140; // A Tiger Claw Sect Badge
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class TravestysCollectionOfShells : Item
{
[Constructible]
public TravestysCollectionOfShells() : base(0xFD3)
{
}
public TravestysCollectionOfShells(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072090; // Travesty's Collection of Shells
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class TravestysFineTeakwoodTray : Item
{
[Constructible]
public TravestysFineTeakwoodTray() : base(Utility.Random(0x991, 2))
{
}
public TravestysFineTeakwoodTray(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1075094; // Travesty's Fine Teakwood Tray
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Items
{
public class TravestysSushiPreparations : Item
{
[Constructible]
public TravestysSushiPreparations() : base(Utility.Random(0x1E15, 2))
{
}
public TravestysSushiPreparations(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1075093; // Travesty's Sushi Preparations
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using Server.Multis;
using Server.Network;
namespace Server.Items
{
public class TrashBarrel : Container, IChopable
{
private Timer m_Timer;
[Constructible]
public TrashBarrel() : base(0xE77)
{
Hue = 0x3B2;
Movable = false;
}
public TrashBarrel(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041064; // a trash barrel
public override int DefaultMaxWeight => 0; // A value of 0 signals unlimited weight
public override bool IsDecoContainer => false;
public void OnChop(Mobile from)
{
BaseHouse house = BaseHouse.FindHouseAt(from);
if (house?.IsCoOwner(from) == true)
{
Effects.PlaySound(Location, Map, 0x3B3);
from.SendLocalizedMessage(500461); // You destroy the item.
Destroy();
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (Items.Count > 0)
{
m_Timer = new EmptyTimer(this);
m_Timer.Start();
}
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (!base.OnDragDrop(from, dropped))
return false;
if (TotalItems >= 50)
{
Empty(501478); // The trash is full! Emptying!
}
else
{
SendLocalizedMessageTo(from, 1010442); // The item will be deleted in three minutes
if (m_Timer != null)
m_Timer.Stop();
else
m_Timer = new EmptyTimer(this);
m_Timer.Start();
}
return true;
}
public override bool OnDragDropInto(Mobile from, Item item, Point3D p)
{
if (!base.OnDragDropInto(from, item, p))
return false;
if (TotalItems >= 50)
{
Empty(501478); // The trash is full! Emptying!
}
else
{
SendLocalizedMessageTo(from, 1010442); // The item will be deleted in three minutes
if (m_Timer != null)
m_Timer.Stop();
else
m_Timer = new EmptyTimer(this);
m_Timer.Start();
}
return true;
}
public void Empty(int message)
{
List<Item> items = Items;
if (items.Count > 0)
{
PublicOverheadMessage(MessageType.Regular, 0x3B2, message, "");
for (int i = items.Count - 1; i >= 0; --i)
{
if (i >= items.Count)
continue;
items[i].Delete();
}
}
m_Timer?.Stop();
m_Timer = null;
}
private class EmptyTimer : Timer
{
private TrashBarrel m_Barrel;
public EmptyTimer(TrashBarrel barrel) : base(TimeSpan.FromMinutes(3.0))
{
m_Barrel = barrel;
Priority = TimerPriority.FiveSeconds;
}
protected override void OnTick()
{
m_Barrel.Empty(501479); // Emptying the trashcan!
}
}
}
}

View file

@ -0,0 +1,58 @@
using Server.Network;
namespace Server.Items
{
[Flippable(0xE41, 0xE40)]
public class TrashChest : Container
{
[Constructible]
public TrashChest() : base(0xE41)
{
Movable = false;
}
public TrashChest(Serial serial) : base(serial)
{
}
public override int DefaultMaxWeight => 0; // A value of 0 signals unlimited weight
public override bool IsDecoContainer => false;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (!base.OnDragDrop(from, dropped))
return false;
PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(1042891, 8));
dropped.Delete();
return true;
}
public override bool OnDragDropInto(Mobile from, Item item, Point3D p)
{
if (!base.OnDragDropInto(from, item, p))
return false;
PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(1042891, 8));
item.Delete();
return true;
}
}
}

View file

@ -0,0 +1,38 @@
namespace Server.Items
{
public class TribalBerry : Item
{
[Constructible]
public TribalBerry(int amount = 1) : base(0x9D0)
{
Weight = 1.0;
Stackable = true;
Amount = amount;
Hue = 6;
}
public TribalBerry(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1040001; // tribal berry
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (Hue == 4)
Hue = 6;
}
}
}

View file

@ -0,0 +1,89 @@
using System;
using Server.Factions;
using Server.Mobiles;
using Server.Spells;
using Server.Spells.Fifth;
using Server.Spells.Ninjitsu;
using Server.Spells.Seventh;
namespace Server.Items
{
public class TribalPaint : Item
{
[Constructible]
public TribalPaint() : base(0x9EC)
{
Hue = 2101;
Weight = 2.0;
Stackable = Core.ML;
}
public TribalPaint(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1040000; // savage kin paint
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
{
if (Sigil.ExistsOn(from))
{
from.SendLocalizedMessage(1010465); // You cannot disguise yourself while holding a sigil.
}
else if (!from.CanBeginAction<IncognitoSpell>())
{
from.SendLocalizedMessage(501698); // You cannot disguise yourself while incognitoed.
}
else if (!from.CanBeginAction<PolymorphSpell>())
{
from.SendLocalizedMessage(501699); // You cannot disguise yourself while polymorphed.
}
else if (TransformationSpellHelper.UnderTransformation(from))
{
from.SendLocalizedMessage(501699); // You cannot disguise yourself while polymorphed.
}
else if (AnimalForm.UnderTransformation(from))
{
from.SendLocalizedMessage(1061634); // You cannot disguise yourself while in that form.
}
else if (from.IsBodyMod || from.FindItemOnLayer(Layer.Helm) is OrcishKinMask)
{
from.SendLocalizedMessage(501605); // You are already disguised.
}
else
{
from.BodyMod = from.Female ? 184 : 183;
from.HueMod = 0;
if (from is PlayerMobile mobile)
mobile.SavagePaintExpiration = TimeSpan.FromDays(7.0);
from.SendLocalizedMessage(
1042537); // You now bear the markings of the savage tribe. Your body paint will last about a week or you can remove it with an oil cloth.
Consume();
}
}
else
{
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
[Flippable(0x315C, 0x315D)]
public class HornOfTheDreadhorn : Item
{
[Constructible]
public HornOfTheDreadhorn() : base(0x315C)
{
}
public HornOfTheDreadhorn(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072089; // Horn of the Dread
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
[Flippable(0x3156, 0x3157)]
public class MangledHeadOfDreadhorn : Item
{
[Constructible]
public MangledHeadOfDreadhorn() : base(0x3156)
{
}
public MangledHeadOfDreadhorn(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1072088; // The Mangled Head of Dread Horn
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class TaintedMushroom : Item
{
[Constructible]
public TaintedMushroom() : base(Utility.RandomMinMax(0x222E, 0x2231))
{
}
public TaintedMushroom(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1075088; // Dread Horn Tainted Mushroom
public override bool ForceShowProperties => true;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,137 @@
using System;
using Server.Mobiles;
namespace Server.Items
{
public class UnholyBone : Item, ICarvable
{
private SpawnTimer m_Timer;
[Constructible]
public UnholyBone() : base(0xF7E)
{
Movable = false;
Hue = 0x497;
m_Timer = new SpawnTimer(this);
m_Timer.Start();
}
public UnholyBone(Serial serial) : base(serial)
{
}
public override string DefaultName => "unholy bone";
public void Carve(Mobile from, Item item)
{
Effects.PlaySound(GetWorldLocation(), Map, 0x48F);
Effects.SendLocationEffect(GetWorldLocation(), Map, 0x3728, 10, 10, 0, 0);
if (0.3 > Utility.RandomDouble())
{
if (ItemID == 0xF7E)
from.SendMessage("You destroy the bone.");
else
from.SendMessage("You destroy the bone pile.");
Gold gold = new Gold(25, 100);
gold.MoveToWorld(GetWorldLocation(), Map);
Delete();
m_Timer.Stop();
}
else
{
if (ItemID == 0xF7E)
from.SendMessage("You damage the bone.");
else
from.SendMessage("You damage the bone pile.");
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Timer = new SpawnTimer(this);
m_Timer.Start();
}
private class SpawnTimer : Timer
{
private Item m_Item;
public SpawnTimer(Item item) : base(TimeSpan.FromSeconds(Utility.RandomMinMax(5, 10)))
{
Priority = TimerPriority.FiftyMS;
m_Item = item;
}
protected override void OnTick()
{
if (m_Item.Deleted)
return;
Mobile spawn;
switch (Utility.Random(12))
{
default:
case 0:
spawn = new Skeleton();
break;
case 1:
spawn = new Zombie();
break;
case 2:
spawn = new Wraith();
break;
case 3:
spawn = new Spectre();
break;
case 4:
spawn = new Ghoul();
break;
case 5:
spawn = new Mummy();
break;
case 6:
spawn = new Bogle();
break;
case 7:
spawn = new RottingCorpse();
break;
case 8:
spawn = new BoneKnight();
break;
case 9:
spawn = new SkeletalKnight();
break;
case 10:
spawn = new Lich();
break;
case 11:
spawn = new LichLord();
break;
}
spawn.MoveToWorld(m_Item.Location, m_Item.Map);
m_Item.Delete();
}
}
}
}

View file

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using Server.Network;
namespace Server.Items
{
public class WarningItem : Item
{
private bool m_Broadcasting;
private DateTime m_LastBroadcast;
private int m_Range;
[Constructible]
public WarningItem(int itemID, int range, int warning) : base(itemID)
{
if (range > 18)
range = 18;
Movable = false;
WarningNumber = warning;
m_Range = range;
}
[Constructible]
public WarningItem(int itemID, int range, string warning) : base(itemID)
{
if (range > 18)
range = 18;
Movable = false;
WarningString = warning;
m_Range = range;
}
public WarningItem(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public string WarningString{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int WarningNumber{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int Range
{
get => m_Range;
set
{
if (value > 18) value = 18;
m_Range = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan ResetDelay{ get; set; }
public virtual bool OnlyToTriggerer => false;
public virtual int NeighborRange => 5;
public override bool HandlesOnMovement => true;
public virtual void SendMessage(Mobile triggerer, bool onlyToTriggerer, string messageString, int messageNumber)
{
if (onlyToTriggerer)
{
if (messageString != null)
triggerer.SendMessage(messageString);
else
triggerer.SendLocalizedMessage(messageNumber);
}
else
{
if (messageString != null)
PublicOverheadMessage(MessageType.Regular, 0x3B2, false, messageString);
else
PublicOverheadMessage(MessageType.Regular, 0x3B2, messageNumber);
}
}
public virtual void Broadcast(Mobile triggerer)
{
if (m_Broadcasting || DateTime.UtcNow < m_LastBroadcast + ResetDelay)
return;
m_LastBroadcast = DateTime.UtcNow;
m_Broadcasting = true;
SendMessage(triggerer, OnlyToTriggerer, WarningString, WarningNumber);
if (NeighborRange >= 0)
{
List<WarningItem> list = new List<WarningItem>();
foreach (Item item in GetItemsInRange(NeighborRange))
if (item != this && item is WarningItem warningItem)
list.Add(warningItem);
for (int i = 0; i < list.Count; i++)
list[i].Broadcast(triggerer);
}
Timer.DelayCall(TimeSpan.Zero, InternalCallback);
}
private void InternalCallback()
{
m_Broadcasting = false;
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (m.Player && Utility.InRange(m.Location, Location, m_Range) &&
!Utility.InRange(oldLocation, Location, m_Range))
Broadcast(m);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
writer.Write(WarningString);
writer.Write(WarningNumber);
writer.Write(m_Range);
writer.Write(ResetDelay);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
WarningString = reader.ReadString();
WarningNumber = reader.ReadInt();
m_Range = reader.ReadInt();
ResetDelay = reader.ReadTimeSpan();
break;
}
}
}
}
public class HintItem : WarningItem
{
[Constructible]
public HintItem(int itemID, int range, int warning, int hint) : base(itemID, range, warning)
{
HintNumber = hint;
}
[Constructible]
public HintItem(int itemID, int range, string warning, string hint) : base(itemID, range, warning)
{
HintString = hint;
}
public HintItem(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public string HintString{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int HintNumber{ get; set; }
public override bool OnlyToTriggerer => true;
public override void OnDoubleClick(Mobile from)
{
SendMessage(from, true, HintString, HintNumber);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
writer.Write(HintString);
writer.Write(HintNumber);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
HintString = reader.ReadString();
HintNumber = reader.ReadInt();
break;
}
}
}
}
}

View file

@ -0,0 +1,146 @@
using Server.Commands;
using Server.Targeting;
namespace Server.Items
{
[Flippable(0x1f14, 0x1f15, 0x1f16, 0x1f17)]
public class WayPoint : Item
{
private WayPoint m_Next;
[Constructible]
public WayPoint(WayPoint prev = null) : base(0x1f14)
{
Hue = 0x498;
Visible = false;
//this.Movable = false;
if (prev != null)
prev.NextPoint = this;
}
public WayPoint(Serial serial) : base(serial)
{
}
public override string DefaultName => "AI Way Point";
[CommandProperty(AccessLevel.GameMaster)]
public WayPoint NextPoint
{
get => m_Next;
set
{
if (m_Next != this)
m_Next = value;
}
}
public static void Initialize()
{
CommandSystem.Register("WayPointSeq", AccessLevel.GameMaster, WayPointSeq_OnCommand);
}
public static void WayPointSeq_OnCommand(CommandEventArgs arg)
{
arg.Mobile.SendMessage("Target the position of the first way point.");
arg.Mobile.Target = new WayPointSeqTarget(null);
}
public override void OnDoubleClick(Mobile from)
{
if (from.AccessLevel >= AccessLevel.GameMaster)
{
from.SendMessage("Target the next way point in the sequence.");
from.Target = new NextPointTarget(this);
}
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
if (m_Next == null)
LabelTo(from, "(Unlinked)");
else
LabelTo(from, "(Linked: {0})", m_Next.Location);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
m_Next = reader.ReadItem() as WayPoint;
break;
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
writer.Write(m_Next);
}
}
public class NextPointTarget : Target
{
private WayPoint m_Point;
public NextPointTarget(WayPoint pt) : base(-1, false, TargetFlags.None)
{
m_Point = pt;
}
protected override void OnTarget(Mobile from, object target)
{
if (target is WayPoint point && m_Point != null)
m_Point.NextPoint = point;
else
from.SendMessage("Target a way point.");
}
}
public class WayPointSeqTarget : Target
{
private WayPoint m_Last;
public WayPointSeqTarget(WayPoint last) : base(-1, true, TargetFlags.None)
{
m_Last = last;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is WayPoint wayPoint)
{
if (m_Last != null)
m_Last.NextPoint = wayPoint;
}
else if (targeted is IPoint3D d)
{
Point3D p = new Point3D(d);
WayPoint point = new WayPoint(m_Last);
point.MoveToWorld(p, from.Map);
from.Target = new WayPointSeqTarget(point);
from.SendMessage(
"Target the position of the next way point in the sequence, or target a way point link the newest way point to.");
}
else
{
from.SendMessage("Target a position, or another way point.");
}
}
}
}

View file

@ -0,0 +1,183 @@
using Server.Gumps;
using Server.Multis;
using Server.Network;
namespace Server.Items
{
public abstract class BaseWindChimes : Item
{
private bool m_TurnedOn;
public BaseWindChimes(int itemID) : base(itemID)
{
}
public BaseWindChimes(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public bool TurnedOn
{
get => m_TurnedOn;
set
{
m_TurnedOn = value;
InvalidateProperties();
}
}
public static int[] Sounds{ get; } = { 0x505, 0x506, 0x507 };
public override bool HandlesOnMovement => m_TurnedOn && IsLockedDown;
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (m_TurnedOn && IsLockedDown && (!m.Hidden || m.AccessLevel == AccessLevel.Player) &&
Utility.InRange(m.Location, Location, 2) && !Utility.InRange(oldLocation, Location, 2))
Effects.PlaySound(Location, Map, Sounds[Utility.Random(Sounds.Length)]);
base.OnMovement(m, oldLocation);
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
if (m_TurnedOn)
list.Add(502695); // turned on
else
list.Add(502696); // turned off
}
public bool IsOwner(Mobile mob)
{
return BaseHouse.FindHouseAt(this)?.IsOwner(mob) == true;
}
public override void OnDoubleClick(Mobile from)
{
if (IsOwner(from))
{
from.SendGump(new OnOffGump(this));
}
else
{
from.SendLocalizedMessage(502691); // You must be the owner to use this.
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_TurnedOn);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
m_TurnedOn = reader.ReadBool();
break;
}
}
}
private class OnOffGump : Gump
{
private BaseWindChimes m_Chimes;
public OnOffGump(BaseWindChimes chimes) : base(150, 200)
{
m_Chimes = chimes;
AddBackground(0, 0, 300, 150, 0xA28);
AddHtmlLocalized(45, 20, 300, 35, chimes.TurnedOn ? 1011035 : 1011034); // [De]Activate this item
AddButton(40, 53, 0xFA5, 0xFA7, 1);
AddHtmlLocalized(80, 55, 65, 35, 1011036); // OKAY
AddButton(150, 53, 0xFA5, 0xFA7, 0);
AddHtmlLocalized(190, 55, 100, 35, 1011012); // CANCEL
}
public override void OnResponse(NetState sender, RelayInfo info)
{
Mobile from = sender.Mobile;
if (info.ButtonID == 1)
{
bool newValue = !m_Chimes.TurnedOn;
m_Chimes.TurnedOn = newValue;
if (newValue && !m_Chimes.IsLockedDown)
from.SendLocalizedMessage(502693); // Remember, this only works when locked down.
}
else
{
from.SendLocalizedMessage(502694); // Cancelled action.
}
}
}
}
public class WindChimes : BaseWindChimes
{
[Constructible]
public WindChimes() : base(0x2832)
{
}
public WindChimes(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030290;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class FancyWindChimes : BaseWindChimes
{
[Constructible]
public FancyWindChimes() : base(0x2833)
{
}
public FancyWindChimes(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1030291;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}