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:
2026-06-08 11:09:25 -07:00
parent 510c12a980
commit 43f355c06b
28 changed files with 709 additions and 6 deletions
@@ -40,6 +40,12 @@ namespace ProjectM.Authoring
Category = def.Category,
Tier = def.Tier,
StackMax = def.StackMax,
EquipSlot = def.EquipSlot,
GrantedAbilityId = def.GrantedAbilityId,
Mod0 = ModAt(def, 0),
Mod1 = ModAt(def, 1),
Mod2 = ModAt(def, 2),
Mod3 = ModAt(def, 3),
Name = def.DisplayName,
};
}
@@ -48,6 +54,16 @@ namespace ProjectM.Authoring
builder.Dispose();
AddBlobAsset(ref blob, out _);
AddComponent(entity, new ItemDatabase { Value = blob });
static ItemModSpec ModAt(ItemDefinition def, int i)
{
if (def.Mods != null && i < def.Mods.Count)
{
var m = def.Mods[i];
return new ItemModSpec { Target = m.Target, Op = m.Op, Value = m.Value };
}
return new ItemModSpec { Target = 255 };
}
}
}
}