Improve auto-opening box UX with clear messaging

- Auto-opened boxes now show "Box of Boxes opens automatically!" instead
  of the full opening sequence, making the cascade clear to the player
- Items that are immediately auto-consumed (auto-opening boxes) are
  hidden from loot reveal to reduce noise
- BoxOpenedEvent now carries IsAutoOpen flag set by BoxEngine
This commit is contained in:
Samuel Bouchet 2026-03-10 20:34:35 +01:00
parent c580e1cf2e
commit 77c70593ee
3 changed files with 20 additions and 7 deletions

View file

@ -237,18 +237,31 @@ public static class Program
private static async Task RenderEvents(List<GameEvent> events)
{
// Collect IDs of items that are auto-consumed (auto-opening boxes)
// so we don't show "You received" for items the player never actually gets
var autoConsumedIds = events.OfType<ItemConsumedEvent>().Select(e => e.InstanceId).ToHashSet();
foreach (var evt in events)
{
switch (evt)
{
case BoxOpenedEvent boxEvt:
var boxDef = _registry.GetBox(boxEvt.BoxId);
_renderer.ShowBoxOpening(
_loc.Get(boxDef?.NameKey ?? boxEvt.BoxId),
boxDef?.Rarity.ToString() ?? "Common");
var boxName = _loc.Get(boxDef?.NameKey ?? boxEvt.BoxId);
if (boxEvt.IsAutoOpen)
{
_renderer.ShowMessage(_loc.Get("box.auto_open", boxName));
}
else
{
_renderer.ShowBoxOpening(boxName, boxDef?.Rarity.ToString() ?? "Common");
}
break;
case ItemReceivedEvent itemEvt:
// Skip loot reveal for auto-consumed items (auto-opening boxes)
if (autoConsumedIds.Contains(itemEvt.Item.Id))
break;
_state.AddItem(itemEvt.Item);
var itemDef = _registry.GetItem(itemEvt.Item.DefinitionId);
var itemBoxDef = itemDef is null ? _registry.GetBox(itemEvt.Item.DefinitionId) : null;

View file

@ -17,7 +17,7 @@ public class BoxEngine(ContentRegistry registry)
/// Opens a box, evaluating its loot table against the current game state and returning
/// all resulting events (items received, nested box opens, etc.).
/// </summary>
public List<GameEvent> Open(string boxDefId, GameState state, Random rng)
public List<GameEvent> Open(string boxDefId, GameState state, Random rng, bool isAutoOpen = false)
{
var events = new List<GameEvent>();
var boxDef = registry.GetBox(boxDefId);
@ -47,7 +47,7 @@ public class BoxEngine(ContentRegistry registry)
}
}
events.Add(new BoxOpenedEvent(boxDefId, droppedItemDefIds));
events.Add(new BoxOpenedEvent(boxDefId, droppedItemDefIds, isAutoOpen));
// Create item instances for each dropped item
foreach (var itemDefId in droppedItemDefIds)
@ -62,7 +62,7 @@ public class BoxEngine(ContentRegistry registry)
{
state.RemoveItem(instance.Id);
events.Add(new ItemConsumedEvent(instance.Id));
events.AddRange(Open(itemDefId, state, rng));
events.AddRange(Open(itemDefId, state, rng, isAutoOpen: true));
}
}

View file

@ -14,7 +14,7 @@ public abstract record GameEvent
/// <summary>
/// A box was opened, producing dropped items.
/// </summary>
public sealed record BoxOpenedEvent(string BoxId, List<string> DroppedItemDefIds) : GameEvent;
public sealed record BoxOpenedEvent(string BoxId, List<string> DroppedItemDefIds, bool IsAutoOpen = false) : GameEvent;
/// <summary>
/// An item was received and added to inventory.