fix: Codegens gifts. Unifies staff names. Thank you to the community! (#1766)

### Summary
* Adds contributors/sponsors to the "staff" list for holiday items.
* Unifies all of the staff lists
* Moves 2004 winter gifts to the appropriate folder
* Codegens the gift items

## Thank you!
Thank you to the RunUO/ServUO community, Owyn, Jaedan, the Outlands community, and the ModernUO contributors/community. Without all of you, this would not be possible! ❤️
This commit is contained in:
Kamron Batman 2024-05-08 20:44:00 -07:00 • committed by GitHub
parent 8efa90b3ce
commit 8fd04ac5aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 822 additions and 1017 deletions

View file

@ -0,0 +1,28 @@
using ModernUO.Serialization;
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class DecorativeTopiary : Item
{
[Constructible]
public DecorativeTopiary() : base(0x2378)
{
Weight = 1.0;
LootType = LootType.Blessed;
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
LabelTo(from, 1070880); // Winter 2004
}
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1070880); // Winter 2004
}
}

View file

@ -0,0 +1,28 @@
using ModernUO.Serialization;
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class FestiveCactus : Item
{
[Constructible]
public FestiveCactus() : base(0x2376)
{
Weight = 1.0;
LootType = LootType.Blessed;
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
LabelTo(from, 1070880); // Winter 2004
}
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1070880); // Winter 2004
}
}

View file

@ -0,0 +1,42 @@
using ModernUO.Serialization;
using Server.Misc;
namespace Server.Items;
[Flippable(0x236E, 0x2371)]
[SerializationGenerator(0, false)]
public partial class LightOfTheWinterSolstice : Item
{
[InternString]
[InvalidateProperties]
[SerializableField(0)]
[SerializedCommandProperty(AccessLevel.GameMaster)]
private string _dipper;
[Constructible]
public LightOfTheWinterSolstice(string dipper = null) : base(0x236E)
{
_dipper = dipper?.Intern() ?? StaffInfo.GetRandomStaff();
Weight = 1.0;
LootType = LootType.Blessed;
Light = LightType.Circle300;
Hue = Utility.RandomDyedHue();
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
LabelTo(from, 1070881, _dipper); // Hand Dipped by ~1_name~
LabelTo(from, 1070880); // Winter 2004
}
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1070881, _dipper); // Hand Dipped by ~1_name~
list.Add(1070880); // Winter 2004
}
}

View file

@ -0,0 +1,322 @@
using ModernUO.Serialization;
using Server.Gumps;
using Server.Multis;
using Server.Network;
using Server.Targeting;
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class MistletoeAddon : Item, IDyable, IAddon
{
[Constructible]
public MistletoeAddon() : this(Utility.RandomDyedHue())
{
}
[Constructible]
public MistletoeAddon(int hue) : base(0x2375)
{
Hue = hue;
Movable = false;
}
public bool CouldFit(IPoint3D p, Map map)
{
if (!map.CanFit(p.X, p.Y, p.Z, ItemData.Height))
{
return false;
}
if (ItemID == 0x2375)
{
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 MistletoeDeed(Hue);
public virtual bool Dye(Mobile from, DyeTub sender)
{
if (Deleted)
{
return false;
}
var house = BaseHouse.FindHouseAt(this);
if (house?.IsCoOwner(from) == true)
{
if (from.InRange(GetWorldLocation(), 1))
{
Hue = sender.DyedHue;
return true;
}
from.SendLocalizedMessage(500295); // You are too far away to do that.
return false;
}
return false;
}
[AfterDeserialization(false)]
private void AfterDeserialization()
{
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)
{
return;
}
if (from.InRange(GetWorldLocation(), 3))
{
from.CloseGump<MistletoeAddonGump>();
from.SendGump(new MistletoeAddonGump(from, this));
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
}
}
private class MistletoeAddonGump : Gump
{
private readonly MistletoeAddon _addon;
private readonly Mobile _from;
public MistletoeAddonGump(Mobile from, MistletoeAddon addon) : base(150, 50)
{
_from = from;
_addon = addon;
AddPage(0);
AddBackground(0, 0, 220, 170, 0x13BE);
AddBackground(10, 10, 200, 150, 0xBB8);
AddHtmlLocalized(20, 30, 180, 60, 1062839); // Do you wish to re-deed this decoration?
AddHtmlLocalized(55, 100, 160, 25, 1011011); // CONTINUE
AddButton(20, 100, 0xFA5, 0xFA7, 1);
AddHtmlLocalized(55, 125, 160, 25, 1011012); // CANCEL
AddButton(20, 125, 0xFA5, 0xFA7, 0);
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (_addon.Deleted || info.ButtonID != 1)
{
return;
}
if (_from.InRange(_addon.GetWorldLocation(), 3))
{
_from.AddToBackpack(_addon.Deed);
_addon.Delete();
}
else
{
_from.SendLocalizedMessage(500295); // You are too far away to do that.
}
}
}
}
[Flippable(0x14F0, 0x14EF)]
[SerializationGenerator(0, false)]
public partial class MistletoeDeed : Item
{
[Constructible]
public MistletoeDeed(int hue = 0) : base(0x14F0)
{
Hue = hue;
Weight = 1.0;
LootType = LootType.Blessed;
}
public override int LabelNumber => 1070882; // Mistletoe Deed
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
LabelTo(from, 1070880); // Winter 2004
}
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1070880); // Winter 2004
}
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;
}
var house = BaseHouse.FindHouseAt(from);
if (house?.IsCoOwner(from) == true)
{
from.SendLocalizedMessage(1062838); // Where would you like to place this decoration?
from.BeginTarget(-1, true, TargetFlags.None, Placement_OnTarget);
}
else
{
from.SendLocalizedMessage(502092); // You must be in your house to do this.
}
}
public void Placement_OnTarget(Mobile from, object targeted)
{
if (targeted is not IPoint3D p)
{
return;
}
var loc = new Point3D(p);
var house = BaseHouse.FindHouseAt(loc, from.Map, 16);
if (house?.IsCoOwner(from) != true)
{
from.SendLocalizedMessage(1042036); // That location is not in your house.
return;
}
var northWall = BaseAddon.IsWall(loc.X, loc.Y - 1, loc.Z, from.Map);
var westWall = BaseAddon.IsWall(loc.X - 1, loc.Y, loc.Z, from.Map);
if (northWall && westWall)
{
from.SendGump(new MistletoeDeedGump(from, loc, this));
}
else
{
PlaceAddon(from, loc, northWall, westWall);
}
}
private void PlaceAddon(Mobile from, Point3D loc, bool northWall, bool westWall)
{
if (Deleted)
{
return;
}
var house = BaseHouse.FindHouseAt(loc, from.Map, 16);
if (house?.IsCoOwner(from) != true)
{
from.SendLocalizedMessage(1042036); // That location is not in your house.
return;
}
var itemID = 0;
if (northWall)
{
itemID = 0x2374;
}
else if (westWall)
{
itemID = 0x2375;
}
else
{
from.SendLocalizedMessage(1070883); // The mistletoe must be placed next to a wall.
}
if (itemID > 0)
{
Item addon = new MistletoeAddon(Hue);
addon.ItemID = itemID;
addon.MoveToWorld(loc, from.Map);
house.Addons.Add(addon);
Delete();
}
}
private class MistletoeDeedGump : Gump
{
private readonly MistletoeDeed _deed;
private readonly Mobile _from;
private readonly Point3D _loc;
public MistletoeDeedGump(Mobile from, Point3D loc, MistletoeDeed deed) : base(150, 50)
{
_from = from;
_loc = loc;
_deed = deed;
AddBackground(0, 0, 300, 150, 0xA28);
AddPage(0);
AddItem(90, 30, 0x2375);
AddItem(180, 30, 0x2374);
AddButton(50, 35, 0x868, 0x869, 1);
AddButton(145, 35, 0x868, 0x869, 2);
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (_deed.Deleted)
{
return;
}
switch (info.ButtonID)
{
case 1:
{
_deed.PlaceAddon(_from, _loc, false, true);
break;
}
case 2:
{
_deed.PlaceAddon(_from, _loc, true, false);
break;
}
}
}
}
}

View file

@ -0,0 +1,50 @@
using ModernUO.Serialization;
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class PileOfGlacialSnow : Item
{
[Constructible]
public PileOfGlacialSnow() : base(0x913)
{
Hue = 0x480;
Weight = 1.0;
LootType = LootType.Blessed;
}
public override int LabelNumber => 1070874; // a Pile of Glacial Snow
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
LabelTo(from, 1070880); // Winter 2004
}
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1070880); // Winter 2004
}
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1042010); // You must have the object in your backpack to use it.
}
else if (from.Mounted)
{
from.SendLocalizedMessage(1010097); // You cannot use this while mounted.
}
else if (from.CanBeginAction<SnowPile>())
{
from.SendLocalizedMessage(1005575); // You carefully pack the snow into a ball...
from.Target = new SnowTarget();
}
else
{
from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying.
}
}
}

View file

@ -0,0 +1,38 @@
using ModernUO.Serialization;
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class SnowPile : Item
{
[Constructible]
public SnowPile() : base(0x913)
{
Hue = 0x481;
Weight = 1.0;
LootType = LootType.Blessed;
}
public override int LabelNumber => 1005578; // a pile of snow
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1042010); // You must have the object in your backpack to use it.
}
else if (from.Mounted)
{
from.SendLocalizedMessage(1010097); // You cannot use this while mounted.
}
else if (from.CanBeginAction<SnowPile>())
{
from.SendLocalizedMessage(1005575); // You carefully pack the snow into a ball...
from.Target = new SnowTarget();
}
else
{
from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying.
}
}
}

View file

@ -0,0 +1,62 @@
using System;
using Server.Engines.ConPVP;
using Server.Targeting;
namespace Server.Items;
public class SnowTarget : Target
{
private static readonly Type[] _snowPileTypes = [typeof(SnowPile), typeof(PileOfGlacialSnow)];
public SnowTarget() : base(10, false, TargetFlags.None)
{
}
protected override void OnTarget(Mobile from, object target)
{
if (target == from)
{
from.SendLocalizedMessage(1005576); // You can't throw this at yourself.
return;
}
if (target is not Mobile targ)
{
// You can only throw a snowball at something that can throw one back.
from.SendLocalizedMessage(1005577);
return;
}
var pack = targ.Backpack;
if (from.Region.IsPartOf<SafeZone>() || targ.Region.IsPartOf<SafeZone>())
{
from.SendMessage("You may not throw snow here.");
return;
}
if (pack?.FindItemByType(_snowPileTypes) == null)
{
// You can only throw a snowball at something that can throw one back.
from.SendLocalizedMessage(1005577);
return;
}
if (!from.BeginAction<SnowPile>())
{
from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying.
return;
}
Timer.StartTimer(TimeSpan.FromSeconds(5.0), from.EndAction<SnowPile>);
from.PlaySound(0x145);
from.Animate(9, 1, 1, true, false, 0);
targ.SendLocalizedMessage(1010572); // You have just been hit by a snowball!
from.SendLocalizedMessage(1010573); // You throw the snowball and hit the target!
Effects.SendMovingEffect(from, targ, 0x36E4, 7, 0, false, true, 0x47F);
}
}

View file

@ -0,0 +1,28 @@
using ModernUO.Serialization;
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class SnowyTree : Item
{
[Constructible]
public SnowyTree() : base(0x2377)
{
Weight = 1.0;
LootType = LootType.Blessed;
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
LabelTo(from, 1070880); // Winter 2004
}
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1070880); // Winter 2004
}
}

View file

@ -0,0 +1,53 @@
using System;
using Server.Items;
namespace Server.Misc;
public class WinterGiftGiver2004 : GiftGiver
{
public override DateTime Start => new(2004, 12, 24);
public override DateTime Finish => new(2005, 1, 1);
public static void Initialize()
{
GiftGiving.Register(new WinterGiftGiver2004());
}
public override void GiveGift(Mobile mob)
{
var box = new GiftBox();
box.DropItem(new MistletoeDeed());
box.DropItem(new PileOfGlacialSnow());
box.DropItem(new LightOfTheWinterSolstice());
var random = Utility.Random(100);
if (random < 60)
{
box.DropItem(new DecorativeTopiary());
}
else if (random < 84)
{
box.DropItem(new FestiveCactus());
}
else
{
box.DropItem(new SnowyTree());
}
switch (GiveGift(mob, box))
{
case GiftResult.Backpack:
{
mob.SendMessage(0x482, "Happy Holidays from the team! Gift items have been placed in your backpack.");
break;
}
case GiftResult.BankBox:
{
mob.SendMessage(0x482, "Happy Holidays from the team! Gift items have been placed in your bank box.");
break;
}
}
}
}

View file

@ -1,90 +1,64 @@
using ModernUO.Serialization;
using Server.Misc;
using Server.Mobiles;
namespace Server.Items
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class HalloweenPumpkin : Item
{
[SerializationGenerator(1, false)]
public partial class HalloweenPumpkin : Item
[InternString]
[SerializableField(0)]
private string _staffer;
[Constructible]
public HalloweenPumpkin()
{
private static readonly string[] m_Staff =
Weight = Utility.RandomMinMax(3, 20);
ItemID = Utility.RandomDouble() < 0.02
? Utility.RandomList(0x4694, 0x4698)
: Utility.RandomList(0xc6a, 0xc6b, 0xc6c);
}
public override string DefaultName => _staffer != null ? $"{_staffer}'s Jack-O-Lantern" : "A Jack-O-Lantern";
public override void OnDoubleClick(Mobile from)
{
if (!from.InRange(GetWorldLocation(), 2))
{
"Owyn",
"Luthius",
"Kamron",
"Jaedan",
"Vorspire"
return;
}
var douse = ItemID is 0x4695 or 0x4691;
ItemID = ItemID switch
{
0x4694 => 0x4691,
0x4691 => 0x4694,
0x4698 => 0x4695,
0x4695 => 0x4698,
_ => ItemID
};
[Constructible]
public HalloweenPumpkin()
{
Weight = Utility.RandomMinMax(3, 20);
ItemID = Utility.RandomDouble() < 0.02
? Utility.RandomList(0x4694, 0x4698)
: Utility.RandomList(0xc6a, 0xc6b, 0xc6c);
}
from.SendLocalizedMessage(douse ? 1113988 : 1113987); // You extinguish/light the Jack-O-Lantern
Effects.PlaySound(GetWorldLocation(), Map, douse ? 0x3be : 0x47);
}
public override void OnDoubleClick(Mobile from)
public override bool OnDragLift(Mobile from)
{
if (Name == null && ItemID is 0x4694 or 0x4691 or 0x4698 or 0x4695)
{
if (!from.InRange(GetWorldLocation(), 2))
if (Utility.RandomBool())
{
return;
new PumpkinHead().MoveToWorld(GetWorldLocation(), Map);
Delete();
return false;
}
var douse = false;
switch (ItemID)
{
case 0x4694:
ItemID = 0x4691;
break;
case 0x4691:
ItemID = 0x4694;
douse = true;
break;
case 0x4698:
ItemID = 0x4695;
break;
case 0x4695:
ItemID = 0x4698;
douse = true;
break;
default: return;
}
from.SendLocalizedMessage(douse ? 1113988 : 1113987); // You extinguish/light the Jack-O-Lantern
Effects.PlaySound(GetWorldLocation(), Map, douse ? 0x3be : 0x47);
_staffer = StaffInfo.GetRandomStaff();
}
private void AssignRandomName()
{
Name = $"{m_Staff.RandomElement()}'s Jack-O-Lantern";
}
public override bool OnDragLift(Mobile from)
{
if (Name == null && ItemID is 0x4694 or 0x4691 or 0x4698 or 0x4695)
{
if (Utility.RandomBool())
{
new PumpkinHead().MoveToWorld(GetWorldLocation(), Map);
Delete();
return false;
}
AssignRandomName();
}
return true;
}
private void Deserialize(IGenericReader reader, int version)
{
if (version == 0 && Name == null && ItemID == 0x4698)
{
AssignRandomName();
}
}
return true;
}
}

View file

@ -1,33 +1,24 @@
using ModernUO.Serialization;
using Server.Misc;
namespace Server.Items.Holiday
namespace Server.Items.Holiday;
[SerializationGenerator(0, false)]
[TypeAlias("Server.Items.ClownMask", "Server.Items.DaemonMask", "Server.Items.PlagueMask")]
public partial class BasePaintedMask : Item
{
[SerializationGenerator(0, false)]
[TypeAlias("Server.Items.ClownMask", "Server.Items.DaemonMask", "Server.Items.PlagueMask")]
public partial class BasePaintedMask : Item
[InternString]
[SerializableField(0, setter: "private")]
private string _staffer;
public BasePaintedMask(int itemid) : this(StaffInfo.GetRandomStaff(), itemid)
{
private static readonly string[] Staffers =
{
"Owyn",
"Luthius",
"Kamron",
"Jaedan",
"Vorspire"
};
[InternString]
[SerializableField(0, setter: "private")]
private string _staffer;
public BasePaintedMask(int itemid) : this(Staffers.RandomElement(), itemid)
{
}
public BasePaintedMask(string staffer, int itemid) : base(itemid + Utility.Random(2)) =>
_staffer = staffer.Intern();
public override string DefaultName => _staffer != null ? $"{MaskName} hand painted by {_staffer}" : MaskName;
public virtual string MaskName => "A Mask";
}
public BasePaintedMask(string staffer, int itemid) : base(itemid + Utility.Random(2)) =>
_staffer = staffer.Intern();
public override string DefaultName => _staffer != null ? $"{MaskName} hand painted by {_staffer}" : MaskName;
public virtual string MaskName => "A Mask";
}