## Changes
- [X] Adds OPL convenience methods
- `opl.Add(cliloc, value)` and `opl.Add(value)` - value as an integer or string works just like `opl.Add(cliloc, $"{value}")`
- `opl.AddLocalized(cliloc, clilocValue)` - works the same as `opl.Add(cliloc, $"#{clilocValue}");`
- [X] Simplifies basic `list.Add()` situations
- [X] Changes cliloc as an argument so it works with custom IPropertyList implementations (HTML)
- [X] Fixes plants so they support the old localization and new (changed in 7.0.12.0+)
- [X] Exposes more methods to override for Item to make creating custom OPL possible.
## Important Notes
* Using a ternary as an argument, like this `opl.Add(number, showType ? $"{type}\t{value}" : $"{value}");` _will not use the correct string interpolation_. This means if you use a custom PropertyList (for HTML or some other purpose), the property list won't be localized properly.
* All localization values must be interpolated, even if they are literal strings, or integers. Example: `opl.Add(number, $"{"Charges"}\t{m_Charges}");` is correct. Using the following: `$"Charges\t{m_Charges}"` will not work for custom PropertyList implementations!
560 lines
16 KiB
C#
560 lines
16 KiB
C#
using System;
|
|
using Server.Mobiles;
|
|
using Server.Multis;
|
|
using Server.Targeting;
|
|
|
|
namespace Server.Items
|
|
{
|
|
[Flippable(0x1EBA, 0x1EBB)]
|
|
public class TaxidermyKit : Item
|
|
{
|
|
private static readonly TrophyInfo[] m_Table =
|
|
{
|
|
new(typeof(BrownBear), 0x1E60, 1041093, 1041107),
|
|
new(typeof(GreatHart), 0x1E61, 1041095, 1041109),
|
|
new(typeof(BigFish), 0x1E62, 1041096, 1041110),
|
|
new(typeof(Gorilla), 0x1E63, 1041091, 1041105),
|
|
new(typeof(Orc), 0x1E64, 1041090, 1041104),
|
|
new(typeof(PolarBear), 0x1E65, 1041094, 1041108),
|
|
new(typeof(Troll), 0x1E66, 1041092, 1041106)
|
|
};
|
|
|
|
[Constructible]
|
|
public TaxidermyKit() : base(0x1EBA) => Weight = 1.0;
|
|
|
|
public TaxidermyKit(Serial serial) : base(serial)
|
|
{
|
|
}
|
|
|
|
public override int LabelNumber => 1041279; // a taxidermy kit
|
|
|
|
public override void Serialize(IGenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
|
|
writer.Write(0); // version
|
|
}
|
|
|
|
public override void Deserialize(IGenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
|
|
var version = reader.ReadInt();
|
|
}
|
|
|
|
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.Skills.Carpentry.Base < 90.0)
|
|
{
|
|
from.SendLocalizedMessage(1042594); // You do not understand how to use this.
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(1042595); // Target the corpse to make a trophy out of.
|
|
from.Target = new CorpseTarget(this);
|
|
}
|
|
}
|
|
|
|
public class TrophyInfo
|
|
{
|
|
public TrophyInfo(Type type, int id, int deedNum, int addonNum)
|
|
{
|
|
CreatureType = type;
|
|
NorthID = id;
|
|
DeedNumber = deedNum;
|
|
AddonNumber = addonNum;
|
|
}
|
|
|
|
public Type CreatureType { get; }
|
|
|
|
public int NorthID { get; }
|
|
|
|
public int DeedNumber { get; }
|
|
|
|
public int AddonNumber { get; }
|
|
}
|
|
|
|
private class CorpseTarget : Target
|
|
{
|
|
private readonly TaxidermyKit m_Kit;
|
|
|
|
public CorpseTarget(TaxidermyKit kit) : base(3, false, TargetFlags.None) => m_Kit = kit;
|
|
|
|
protected override void OnTarget(Mobile from, object targeted)
|
|
{
|
|
if (m_Kit.Deleted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var corpse = targeted as Corpse;
|
|
|
|
if (!(corpse != null || targeted is BigFish))
|
|
{
|
|
from.SendLocalizedMessage(1042600); // That is not a corpse!
|
|
}
|
|
else if (corpse?.VisitedByTaxidermist == true)
|
|
{
|
|
from.SendLocalizedMessage(1042596); // That corpse seems to have been visited by a taxidermist already.
|
|
}
|
|
else if (!m_Kit.IsChildOf(from.Backpack))
|
|
{
|
|
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
|
}
|
|
else if (from.Skills.Carpentry.Base < 90.0)
|
|
{
|
|
from.SendLocalizedMessage(1042603); // You would not understand how to use the kit.
|
|
}
|
|
else
|
|
{
|
|
var obj = corpse?.Owner ?? targeted;
|
|
|
|
foreach (var t in m_Table)
|
|
{
|
|
if (t.CreatureType != obj.GetType())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var pack = from.Backpack;
|
|
|
|
if (pack?.ConsumeTotal(typeof(Board), 10) == true)
|
|
{
|
|
from.SendLocalizedMessage(
|
|
1042278
|
|
); // You review the corpse and find it worthy of a trophy.
|
|
from.SendLocalizedMessage(1042602); // You use your kit up making the trophy.
|
|
|
|
Mobile hunter = null;
|
|
var weight = 0;
|
|
|
|
if (targeted is BigFish fish)
|
|
{
|
|
hunter = fish.Fisher;
|
|
weight = (int)fish.Weight;
|
|
|
|
fish.Consume();
|
|
}
|
|
|
|
from.AddToBackpack(new TrophyDeed(t, hunter, weight));
|
|
|
|
if (corpse != null)
|
|
{
|
|
corpse.VisitedByTaxidermist = true;
|
|
}
|
|
|
|
m_Kit.Delete();
|
|
return;
|
|
}
|
|
|
|
from.SendLocalizedMessage(1042598); // You do not have enough boards.
|
|
return;
|
|
}
|
|
|
|
from.SendLocalizedMessage(1042599); // That does not look like something you want hanging on a wall.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class TrophyAddon : Item, IAddon
|
|
{
|
|
private int m_AddonNumber;
|
|
private int m_AnimalWeight;
|
|
|
|
private Mobile m_Hunter;
|
|
|
|
public TrophyAddon(
|
|
Mobile from, int itemID, int westID, int northID, int deedNumber,
|
|
int addonNumber, Mobile hunter = null, int animalWeight = 0
|
|
) : base(itemID)
|
|
{
|
|
WestID = westID;
|
|
NorthID = northID;
|
|
DeedNumber = deedNumber;
|
|
m_AddonNumber = addonNumber;
|
|
|
|
m_Hunter = hunter;
|
|
m_AnimalWeight = animalWeight;
|
|
|
|
Movable = false;
|
|
|
|
MoveToWorld(from.Location, from.Map);
|
|
}
|
|
|
|
public TrophyAddon(Serial serial) : base(serial)
|
|
{
|
|
}
|
|
|
|
public override bool ForceShowProperties => ObjectPropertyList.Enabled;
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int WestID { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int NorthID { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int DeedNumber { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int AddonNumber
|
|
{
|
|
get => m_AddonNumber;
|
|
set
|
|
{
|
|
m_AddonNumber = value;
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public Mobile Hunter
|
|
{
|
|
get => m_Hunter;
|
|
set
|
|
{
|
|
m_Hunter = value;
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int AnimalWeight
|
|
{
|
|
get => m_AnimalWeight;
|
|
set
|
|
{
|
|
m_AnimalWeight = value;
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
public override int LabelNumber => m_AddonNumber;
|
|
|
|
public bool CouldFit(IPoint3D p, Map map)
|
|
{
|
|
if (!map.CanFit(p.X, p.Y, p.Z, ItemData.Height))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (ItemID == NorthID)
|
|
{
|
|
return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // North wall
|
|
}
|
|
|
|
return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // West wall
|
|
}
|
|
|
|
public Item Deed => new TrophyDeed(WestID, NorthID, DeedNumber, m_AddonNumber, m_Hunter, m_AnimalWeight);
|
|
|
|
public override void GetProperties(IPropertyList list)
|
|
{
|
|
base.GetProperties(list);
|
|
|
|
if (m_AnimalWeight >= 20)
|
|
{
|
|
if (m_Hunter != null)
|
|
{
|
|
list.Add(1070857, m_Hunter.Name); // Caught by ~1_fisherman~
|
|
}
|
|
|
|
list.Add(1070858, m_AnimalWeight); // ~1_weight~ stones
|
|
}
|
|
}
|
|
|
|
public override void Serialize(IGenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
|
|
writer.Write(1); // version
|
|
|
|
writer.Write(m_Hunter);
|
|
writer.Write(m_AnimalWeight);
|
|
|
|
writer.Write(WestID);
|
|
writer.Write(NorthID);
|
|
writer.Write(DeedNumber);
|
|
writer.Write(m_AddonNumber);
|
|
}
|
|
|
|
public override void Deserialize(IGenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
|
|
var version = reader.ReadInt();
|
|
|
|
switch (version)
|
|
{
|
|
case 1:
|
|
{
|
|
m_Hunter = reader.ReadEntity<Mobile>();
|
|
m_AnimalWeight = reader.ReadInt();
|
|
goto case 0;
|
|
}
|
|
case 0:
|
|
{
|
|
WestID = reader.ReadInt();
|
|
NorthID = reader.ReadInt();
|
|
DeedNumber = reader.ReadInt();
|
|
m_AddonNumber = reader.ReadInt();
|
|
break;
|
|
}
|
|
}
|
|
|
|
Timer.StartTimer(FixMovingCrate);
|
|
}
|
|
|
|
private void FixMovingCrate()
|
|
{
|
|
if (Deleted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Movable || IsLockedDown)
|
|
{
|
|
var deed = Deed;
|
|
|
|
if (Parent is Item item)
|
|
{
|
|
item.AddItem(deed);
|
|
deed.Location = Location;
|
|
}
|
|
else
|
|
{
|
|
deed.MoveToWorld(Location, Map);
|
|
}
|
|
|
|
Delete();
|
|
}
|
|
}
|
|
|
|
public override void OnDoubleClick(Mobile from)
|
|
{
|
|
var house = BaseHouse.FindHouseAt(this);
|
|
|
|
if (house?.IsCoOwner(from) == true)
|
|
{
|
|
if (from.InRange(GetWorldLocation(), 1))
|
|
{
|
|
from.AddToBackpack(Deed);
|
|
Delete();
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(500295); // You are too far away to do that.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Flippable(0x14F0, 0x14EF)]
|
|
public class TrophyDeed : Item
|
|
{
|
|
private int m_AnimalWeight;
|
|
private int m_DeedNumber;
|
|
|
|
private Mobile m_Hunter;
|
|
|
|
public TrophyDeed(
|
|
int westID, int northID, int deedNumber, int addonNumber,
|
|
Mobile hunter = null, int animalWeight = 0
|
|
) : base(0x14F0)
|
|
{
|
|
WestID = westID;
|
|
NorthID = northID;
|
|
m_DeedNumber = deedNumber;
|
|
AddonNumber = addonNumber;
|
|
m_Hunter = hunter;
|
|
m_AnimalWeight = animalWeight;
|
|
}
|
|
|
|
public TrophyDeed(TaxidermyKit.TrophyInfo info, Mobile hunter, int animalWeight)
|
|
: this(info.NorthID + 7, info.NorthID, info.DeedNumber, info.AddonNumber, hunter, animalWeight)
|
|
{
|
|
}
|
|
|
|
public TrophyDeed(Serial serial) : base(serial)
|
|
{
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int WestID { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int NorthID { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int DeedNumber
|
|
{
|
|
get => m_DeedNumber;
|
|
set
|
|
{
|
|
m_DeedNumber = value;
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int AddonNumber { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public Mobile Hunter
|
|
{
|
|
get => m_Hunter;
|
|
set
|
|
{
|
|
m_Hunter = value;
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int AnimalWeight
|
|
{
|
|
get => m_AnimalWeight;
|
|
set
|
|
{
|
|
m_AnimalWeight = value;
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
public override int LabelNumber => m_DeedNumber;
|
|
|
|
public override void GetProperties(IPropertyList list)
|
|
{
|
|
base.GetProperties(list);
|
|
|
|
if (m_AnimalWeight >= 20)
|
|
{
|
|
if (m_Hunter != null)
|
|
{
|
|
list.Add(1070857, m_Hunter.Name); // Caught by ~1_fisherman~
|
|
}
|
|
|
|
list.Add(1070858, m_AnimalWeight); // ~1_weight~ stones
|
|
}
|
|
}
|
|
|
|
public override void Serialize(IGenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
|
|
writer.Write(1); // version
|
|
|
|
writer.Write(m_Hunter);
|
|
writer.Write(m_AnimalWeight);
|
|
|
|
writer.Write(WestID);
|
|
writer.Write(NorthID);
|
|
writer.Write(m_DeedNumber);
|
|
writer.Write(AddonNumber);
|
|
}
|
|
|
|
public override void Deserialize(IGenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
|
|
var version = reader.ReadInt();
|
|
|
|
switch (version)
|
|
{
|
|
case 1:
|
|
{
|
|
m_Hunter = reader.ReadEntity<Mobile>();
|
|
m_AnimalWeight = reader.ReadInt();
|
|
goto case 0;
|
|
}
|
|
case 0:
|
|
{
|
|
WestID = reader.ReadInt();
|
|
NorthID = reader.ReadInt();
|
|
m_DeedNumber = reader.ReadInt();
|
|
AddonNumber = reader.ReadInt();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void OnDoubleClick(Mobile from)
|
|
{
|
|
if (IsChildOf(from.Backpack))
|
|
{
|
|
var house = BaseHouse.FindHouseAt(from);
|
|
|
|
if (house?.IsCoOwner(from) == true)
|
|
{
|
|
var northWall = BaseAddon.IsWall(from.X, from.Y - 1, from.Z, from.Map);
|
|
var westWall = BaseAddon.IsWall(from.X - 1, from.Y, from.Z, from.Map);
|
|
|
|
if (northWall && westWall)
|
|
{
|
|
switch (from.Direction & Direction.Mask)
|
|
{
|
|
case Direction.North:
|
|
case Direction.South:
|
|
westWall = false;
|
|
break;
|
|
|
|
case Direction.East:
|
|
case Direction.West:
|
|
northWall = false;
|
|
break;
|
|
|
|
default:
|
|
from.SendMessage("Turn to face the wall on which to hang this trophy.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
var itemID = 0;
|
|
|
|
if (northWall)
|
|
{
|
|
itemID = NorthID;
|
|
}
|
|
else if (westWall)
|
|
{
|
|
itemID = WestID;
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(1042626); // The trophy must be placed next to a wall.
|
|
}
|
|
|
|
if (itemID > 0)
|
|
{
|
|
house.Addons.Add(
|
|
new TrophyAddon(
|
|
from,
|
|
itemID,
|
|
WestID,
|
|
NorthID,
|
|
m_DeedNumber,
|
|
AddonNumber,
|
|
m_Hunter,
|
|
m_AnimalWeight
|
|
)
|
|
);
|
|
Delete();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(502092); // You must be in your house to do this.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
|
|
}
|
|
}
|
|
}
|
|
}
|