## Summary Migrates 16 player-facing legacy `Gump` subclasses in the Veteran Rewards system to `DynamicGump` or `StaticGump<T>`, renames every nested `InternalGump`/`ConfirmGump` to system-prefixed names, and updates external callers to use new static `DisplayTo` entry points. ### Reward chain (Engines/Veteran Rewards) | Gump | Base type | Reasoning | |---|---|---| | `RewardNoticeGump` | `StaticGump<T>` | Fixed layout | | `RewardChoiceGump` | `DynamicGump` | Layout shape varies (per-player categories, entries, pages) | | `RewardConfirmGump` | `DynamicGump` | `entry.Name` is a dynamic cliloc per reward (cliloc rule) | | `RewardOptionGump` | `DynamicGump` | Title cliloc and per-option clilocs are dynamic (cliloc rule) | | `RewardDemolitionGump` | `DynamicGump` | `question` cliloc is dynamic per caller (cliloc rule) | ### Statue (Engines/Veteran Rewards/Character Statue Maker) | Gump | Base type | Reasoning | |---|---|---| | `CharacterStatueGump` | `DynamicGump` | Pose/Direction/Material labels are dynamic clilocs (cliloc rule) | | `CharacterPlinthGump` | `DynamicGump` | `statue.Name`, sculpted-on date, and statue-type cliloc are dynamic (cliloc rule) | ### Decorations (Items/Special/Veteran Rewards) — every `InternalGump` renamed | Original | New name | Base type | Reasoning | |---|---|---|---| | `Banner.InternalGump` | `BannerGump` | `StaticGump<T>` | Fully fixed item-id picker over `Start..End` range | | `Brazier.InternalGump` | `BrazierGump` | `StaticGump<T>` | Fixed two-item picker | | `Cannon.InternalGump` | `CannonGump` | `DynamicGump` | `keg.Validate()` value passed as `~1_CHARGES~` arg (cliloc-arg rule) | | `DecorativeShield.InternalGump` | `DecorativeShieldGump` | `StaticGump<T>` | Fixed item picker over a constant range | | `DecorativeShield.FacingGump` | `DecorativeShieldFacingGump` | `DynamicGump` | Item ids depend on instance state | | `HangingSkeleton.InternalGump` | `HangingSkeletonGump` | `StaticGump<T>` | Fixed item picker (5 hard-coded ids) | | `PottedCactus.InternalGump` | `PottedCactusGump` | `StaticGump<T>` | Fixed 6-item picker | | `StoneAnkh.InternalGump` | `StoneAnkhGump` | `StaticGump<T>` | Fixed two-direction picker | | `WallBanner.InternalGump` | `WallBannerGump` | `StaticGump<T>` | Fixed 30-banner picker across 5 pages | | `WeaponEngravingTool.InternalGump` | `WeaponEngravingToolGump` | `StaticGump<T>` | Fixed text-entry dialog | | `WeaponEngravingTool.ConfirmGump` | `WeaponEngravingToolConfirmGump` | `DynamicGump` | Layout branches on `guildmaster != null` | ### External callers updated `RewardSystem`, `CharacterStatue`, `FireFliesDeed`, `FlamingHead`, `Banner`, `DecorativeShield`, `HangingSkeleton`, `StoneAnkh` (RewardDemolitionGump callers); `AnkhOfSacrifice`, `Cannon`, `MiningCart`, `MinotaurStatue`, `TreeStump` (RewardOptionGump callers); `TinkerGuildmaster` (engraver confirm gump). The pre-existing `FacingGump` inside `Banner.cs` (already `DynamicGump`) was left as-is — it is private, nested inside `InternalTarget`, and never referenced outside.
213 lines
6 KiB
C#
213 lines
6 KiB
C#
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using ModernUO.Serialization;
|
|
using Server.Engines.VeteranRewards;
|
|
using Server.Gumps;
|
|
using Server.Multis;
|
|
|
|
namespace Server.Items;
|
|
|
|
[SerializationGenerator(1)]
|
|
public partial class TreeStump : BaseAddon, IRewardItem
|
|
{
|
|
[InvalidateProperties]
|
|
[SerializableField(0)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private bool _isRewardItem;
|
|
|
|
[InvalidateProperties]
|
|
[SerializableField(1)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private int _logs;
|
|
|
|
[SerializableField(2)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
|
private DateTime _lastChecked;
|
|
|
|
[Constructible]
|
|
public TreeStump(int itemID)
|
|
{
|
|
AddComponent(new AddonComponent(itemID), 0, 0, 0);
|
|
_lastChecked = Core.Now;
|
|
}
|
|
|
|
public override BaseAddonDeed Deed =>
|
|
new TreeStumpDeed
|
|
{
|
|
IsRewardItem = _isRewardItem,
|
|
Logs = _logs
|
|
};
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private void UpdateLogs()
|
|
{
|
|
var now = Core.Now;
|
|
var daysSince = (now - _lastChecked).Days;
|
|
_logs = Math.Min(100, _logs + daysSince * 10);
|
|
_lastChecked = now;
|
|
}
|
|
|
|
public override void OnComponentUsed(AddonComponent c, Mobile from)
|
|
{
|
|
var house = BaseHouse.FindHouseAt(this);
|
|
|
|
/*
|
|
* Unique problems have unique solutions. OSI does not have a problem with 1000s of mining carts
|
|
* due to the fact that they have only a miniscule fraction of the number of 10 year vets that a
|
|
* typical RunUO shard will have (RunUO's scaled down account aging system makes this a unique problem),
|
|
* and the "freeness" of free accounts. We also dont have mitigating factors like inactive (unpaid)
|
|
* accounts not gaining veteran time.
|
|
*
|
|
* The lack of high end vets and vet rewards on OSI has made testing the *exact* ranging/stacking
|
|
* behavior of these things all but impossible, so either way its just an estimation.
|
|
*
|
|
* If youd like your shard's carts/stumps to work the way they did before, simply replace the check
|
|
* below with this line of code:
|
|
*
|
|
* if (!from.InRange(GetWorldLocation(), 2)
|
|
*
|
|
* However, I am sure these checks are more accurate to OSI than the former version was.
|
|
*
|
|
*/
|
|
|
|
if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this) || !(from.Z - Z > -3 && from.Z - Z < 3))
|
|
{
|
|
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
|
return;
|
|
}
|
|
|
|
if (house?.HasSecureAccess(from, SecureLevel.Friends) != true)
|
|
{
|
|
from.SendLocalizedMessage(1061637); // You are not allowed to access this.
|
|
return;
|
|
}
|
|
|
|
UpdateLogs();
|
|
|
|
if (_logs <= 0)
|
|
{
|
|
from.SendLocalizedMessage(1094720); // There are no more logs available.
|
|
return;
|
|
}
|
|
|
|
var logs = Utility.Random(7) switch
|
|
{
|
|
0 => new Log(),
|
|
1 => new AshLog(),
|
|
2 => new OakLog(),
|
|
3 => new YewLog(),
|
|
4 => new HeartwoodLog(),
|
|
5 => new BloodwoodLog(),
|
|
_ => new FrostwoodLog()
|
|
};
|
|
|
|
var amount = Math.Min(10, _logs);
|
|
logs.Amount = amount;
|
|
|
|
if (!from.PlaceInBackpack(logs))
|
|
{
|
|
logs.Delete();
|
|
from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again.
|
|
}
|
|
else
|
|
{
|
|
_logs -= amount;
|
|
PublicOverheadMessage(MessageType.Regular, 0, 1094719, _logs.ToString()); // Logs: ~1_COUNT~
|
|
}
|
|
}
|
|
|
|
private void Deserialize(IGenericReader reader, int version)
|
|
{
|
|
_isRewardItem = reader.ReadBool();
|
|
_logs = reader.ReadInt();
|
|
|
|
var next = reader.ReadDateTime();
|
|
|
|
if (next < Core.Now)
|
|
{
|
|
next = Core.Now;
|
|
}
|
|
|
|
_lastChecked = next - TimeSpan.FromDays(1);
|
|
}
|
|
}
|
|
|
|
[SerializationGenerator(0)]
|
|
public partial class TreeStumpDeed : BaseAddonDeed, IRewardItem, IRewardOption
|
|
{
|
|
[InvalidateProperties]
|
|
[SerializableField(0)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private bool _isRewardItem;
|
|
|
|
[InvalidateProperties]
|
|
[SerializableField(1)]
|
|
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
|
private int _logs;
|
|
|
|
private int _itemID;
|
|
|
|
[Constructible]
|
|
public TreeStumpDeed() => LootType = LootType.Blessed;
|
|
|
|
public override int LabelNumber => 1080406; // a deed for a tree stump decoration
|
|
|
|
public override BaseAddon Addon =>
|
|
new TreeStump(_itemID)
|
|
{
|
|
IsRewardItem = _isRewardItem,
|
|
Logs = _logs
|
|
};
|
|
|
|
public void GetOptions(RewardOptionList list)
|
|
{
|
|
list.Add(1, 1080403); // Tree Stump with Axe West
|
|
list.Add(2, 1080404); // Tree Stump with Axe North
|
|
list.Add(3, 1080401); // Tree Stump East
|
|
list.Add(4, 1080402); // Tree Stump South
|
|
}
|
|
|
|
public void OnOptionSelected(Mobile from, int option)
|
|
{
|
|
_itemID = option switch
|
|
{
|
|
1 => 0xE56,
|
|
2 => 0xE58,
|
|
3 => 0xE57,
|
|
4 => 0xE59,
|
|
_ => _itemID
|
|
};
|
|
|
|
if (!Deleted)
|
|
{
|
|
base.OnDoubleClick(from);
|
|
}
|
|
}
|
|
|
|
public override void GetProperties(IPropertyList list)
|
|
{
|
|
base.GetProperties(list);
|
|
|
|
if (_isRewardItem)
|
|
{
|
|
list.Add(1076223); // 7th Year Veteran Reward
|
|
}
|
|
}
|
|
|
|
public override void OnDoubleClick(Mobile from)
|
|
{
|
|
if (_isRewardItem && !RewardSystem.CheckIsUsableBy(from, this))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsChildOf(from.Backpack))
|
|
{
|
|
RewardOptionGump.DisplayTo(from, this);
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used.
|
|
}
|
|
}
|
|
}
|