feat(D.5.2): ItemInstance.Effects + ItemRepository.UpdateIntProperty
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
52306d9268
commit
77f64d7925
3 changed files with 62 additions and 1 deletions
|
|
@ -136,6 +136,13 @@ public sealed class ItemInstance
|
||||||
public uint IconId { get; set; } // 0x06xxxxxx
|
public uint IconId { get; set; } // 0x06xxxxxx
|
||||||
public uint IconUnderlayId{ get; set; } // "magic" underlay
|
public uint IconUnderlayId{ get; set; } // "magic" underlay
|
||||||
public uint IconOverlayId { get; set; } // "enchanted" overlay
|
public uint IconOverlayId { get; set; } // "enchanted" overlay
|
||||||
|
/// <summary>
|
||||||
|
/// UiEffects bitfield (retail PublicWeenieDesc._effects, acclient.h:37183).
|
||||||
|
/// Drives the icon's effect-overlay recolor (Magical=0x1 … Nether=0x1000).
|
||||||
|
/// CreateObject-only (weenieFlags 0x80) + live PublicUpdatePropertyInt(0x02CE);
|
||||||
|
/// appraise never carries it. 0 = no effect.
|
||||||
|
/// </summary>
|
||||||
|
public uint Effects { get; set; }
|
||||||
public int StackSize { get; set; } = 1;
|
public int StackSize { get; set; } = 1;
|
||||||
public int StackSizeMax { get; set; } = 1;
|
public int StackSizeMax { get; set; } = 1;
|
||||||
public int Burden { get; set; } // per-stack total
|
public int Burden { get; set; } // per-stack total
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ public sealed class ItemRepository
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnrichItem(uint objectId, uint iconId, string name, ItemType type,
|
public bool EnrichItem(uint objectId, uint iconId, string name, ItemType type,
|
||||||
uint iconOverlayId = 0, uint iconUnderlayId = 0)
|
uint iconOverlayId = 0, uint iconUnderlayId = 0, uint effects = 0)
|
||||||
{
|
{
|
||||||
if (!_items.TryGetValue(objectId, out var item)) return false;
|
if (!_items.TryGetValue(objectId, out var item)) return false;
|
||||||
if (iconId != 0) item.IconId = iconId;
|
if (iconId != 0) item.IconId = iconId;
|
||||||
|
|
@ -160,6 +160,9 @@ public sealed class ItemRepository
|
||||||
if (type != default) item.Type = type;
|
if (type != default) item.Type = type;
|
||||||
if (iconOverlayId != 0) item.IconOverlayId = iconOverlayId;
|
if (iconOverlayId != 0) item.IconOverlayId = iconOverlayId;
|
||||||
if (iconUnderlayId != 0) item.IconUnderlayId = iconUnderlayId;
|
if (iconUnderlayId != 0) item.IconUnderlayId = iconUnderlayId;
|
||||||
|
// D.5.2: 0 is a meaningful "no effect" state (e.g. a caster out of mana),
|
||||||
|
// so assign unconditionally — re-composition reflects the CURRENT state.
|
||||||
|
item.Effects = effects;
|
||||||
ItemPropertiesUpdated?.Invoke(item);
|
ItemPropertiesUpdated?.Invoke(item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -184,6 +187,25 @@ public sealed class ItemRepository
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>PropertyInt.UiEffects (ACE enum value 18) — the icon effect bitfield.</summary>
|
||||||
|
public const uint UiEffectsPropertyId = 18u;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply a single PropertyInt update (from PublicUpdatePropertyInt 0x02CE) to an
|
||||||
|
/// item: store it in the bundle and, for known typed ints, mirror to the typed
|
||||||
|
/// field. Today: UiEffects (18) → <see cref="ItemInstance.Effects"/>. Fires
|
||||||
|
/// ItemPropertiesUpdated so bound widgets re-composite. Extensible hook for future
|
||||||
|
/// typed PropertyInts (StackSize, Structure, …). False if the item is unknown.
|
||||||
|
/// </summary>
|
||||||
|
public bool UpdateIntProperty(uint itemId, uint propertyId, int value)
|
||||||
|
{
|
||||||
|
if (!_items.TryGetValue(itemId, out var item)) return false;
|
||||||
|
item.Properties.Ints[propertyId] = value;
|
||||||
|
if (propertyId == UiEffectsPropertyId) item.Effects = (uint)value;
|
||||||
|
ItemPropertiesUpdated?.Invoke(item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flush the repository — typically called on logoff or teleport
|
/// Flush the repository — typically called on logoff or teleport
|
||||||
/// that drops the session's item state.
|
/// that drops the session's item state.
|
||||||
|
|
|
||||||
|
|
@ -139,4 +139,36 @@ public sealed class ItemRepositoryTests
|
||||||
var repo = new ItemRepository();
|
var repo = new ItemRepository();
|
||||||
Assert.False(repo.EnrichItem(0x9999u, 0x06001234u, "x", ItemType.Misc));
|
Assert.False(repo.EnrichItem(0x9999u, 0x06001234u, "x", ItemType.Misc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EnrichItem_carriesEffects()
|
||||||
|
{
|
||||||
|
var repo = new ItemRepository();
|
||||||
|
repo.AddOrUpdate(new ItemInstance { ObjectId = 0x500000AAu });
|
||||||
|
bool ok = repo.EnrichItem(0x500000AAu, iconId: 0x06001234u, name: "Wand",
|
||||||
|
type: ItemType.Caster, iconOverlayId: 0, iconUnderlayId: 0, effects: 0x1u);
|
||||||
|
Assert.True(ok);
|
||||||
|
Assert.Equal(0x1u, repo.GetItem(0x500000AAu)!.Effects);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void UpdateIntProperty_uiEffects_setsEffectsAndFires()
|
||||||
|
{
|
||||||
|
var repo = new ItemRepository();
|
||||||
|
repo.AddOrUpdate(new ItemInstance { ObjectId = 0x500000ABu });
|
||||||
|
ItemInstance? fired = null;
|
||||||
|
repo.ItemPropertiesUpdated += i => fired = i;
|
||||||
|
bool ok = repo.UpdateIntProperty(0x500000ABu, 18u, value: 0x9); // 18 = UiEffects
|
||||||
|
Assert.True(ok);
|
||||||
|
Assert.Equal(0x9u, repo.GetItem(0x500000ABu)!.Effects);
|
||||||
|
Assert.Equal(0x9, repo.GetItem(0x500000ABu)!.Properties.Ints[18u]);
|
||||||
|
Assert.NotNull(fired);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void UpdateIntProperty_unknownItem_returnsFalse()
|
||||||
|
{
|
||||||
|
var repo = new ItemRepository();
|
||||||
|
Assert.False(repo.UpdateIntProperty(0xDEADBEEFu, 18u, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue