Equipment: weapon-granted abilities + gear mods (DR-027 Phase 1)
Equipment slots reusing the AbilityRef/StatModifier machinery: EquipmentSlot [GhostField] buffer (index=slot), server-only event-driven EquipSystem (RPC). Weapon -> AbilityRef.Id swaps the attack (prefab + base stats, prediction-correct); gear -> StatModifiers tagged a reserved per-slot EquipSourceId, stripped target-agnostically via RemoveBySourceId. Item mods are INLINE on ItemDefBlob (a nested BlobArray reads empty under the by-value TryGetItem copy). Atomic equip-over swap (no item loss); DefaultAbility restores the unarmed ability on weapon-unequip. Client keys + build-safe hooks; HUD equipment panel + click-to-equip. 4 catalog weapon/gear items wired + re-baked. Play-validated host+client: weapon equip swaps AbilityRef on both worlds, gear folds into EffectiveCharacterStats, unequip reverses + restores DefaultAbility, all replicated to the owner. See DR-027. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,20 @@ namespace ProjectM.Simulation
|
||||
/// is baked NOW because the project's progression axis is gear tiers, so Phase 2/3 tier gating is a
|
||||
/// content-only edit.
|
||||
/// </summary>
|
||||
/// <summary>One stat-modifier grant on an equippable item, stored INLINE (NOT a nested BlobArray: a nested
|
||||
/// BlobArray is a relative-offset pointer that corrupts the moment <see cref="ItemDatabaseBlob.TryGetItem"/>
|
||||
/// returns the containing <see cref="ItemDefBlob"/> BY VALUE — the same copy hazard the class note warns about).
|
||||
/// Target 255 = unused.</summary>
|
||||
public struct ItemModSpec
|
||||
{
|
||||
/// <summary><see cref="StatTarget"/> as a byte; 255 = unused slot.</summary>
|
||||
public byte Target;
|
||||
/// <summary><see cref="ModOp"/> as a byte.</summary>
|
||||
public byte Op;
|
||||
/// <summary>Magnitude (flat amount or fractional percent).</summary>
|
||||
public float Value;
|
||||
}
|
||||
|
||||
public struct ItemDefBlob
|
||||
{
|
||||
/// <summary>Stable item id (ushort; 1-3 reserved for the existing resources, keep stable for saves).</summary>
|
||||
@@ -33,8 +47,32 @@ namespace ProjectM.Simulation
|
||||
/// <summary>Max units that stack in a single inventory slot (1 for non-stacking equipment).</summary>
|
||||
public int StackMax;
|
||||
|
||||
/// <summary>Equip slot (see <see cref="EquipSlotId"/>); 255 = not equippable.</summary>
|
||||
public byte EquipSlot;
|
||||
|
||||
/// <summary>AbilityId granted when equipped in the Weapon slot (0 = none); the equip handler writes it into AbilityRef.Id.</summary>
|
||||
public byte GrantedAbilityId;
|
||||
|
||||
/// <summary>Up to <see cref="MaxMods"/> INLINE stat-mod grants applied while equipped (Target 255 = unused). Inline, not a nested BlobArray.</summary>
|
||||
public ItemModSpec Mod0, Mod1, Mod2, Mod3;
|
||||
|
||||
/// <summary>Designer-facing display name (shown in the HUD inventory panel).</summary>
|
||||
public FixedString64Bytes Name;
|
||||
|
||||
/// <summary>Number of inline mod slots.</summary>
|
||||
public const int MaxMods = 4;
|
||||
|
||||
/// <summary>Indexed access to the inline mod slots (returns a copy — safe, ItemModSpec holds no BlobArray).</summary>
|
||||
public ItemModSpec GetMod(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return Mod0;
|
||||
case 1: return Mod1;
|
||||
case 2: return Mod2;
|
||||
default: return Mod3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user