diff --git a/content/strings/en.json b/content/strings/en.json index 2d9f796..57dc3b7 100644 --- a/content/strings/en.json +++ b/content/strings/en.json @@ -43,6 +43,9 @@ "loot.category": "Category", "ui.feature_unlocked": "NEW FEATURE UNLOCKED: {0}", "ui.completion": "Completion: {0}%", + "hint.lore": "Lore Fragments: {0}/{1}", + "hint.adventures": "Adventures completed: {0}/{1}", + "hint.destiny": "Complete all adventures to unlock the final adventure…", "prompt.what_do": "What do you do?", "prompt.invalid_choice": "Please enter a number between 1 and {0}.", diff --git a/content/strings/fr.json b/content/strings/fr.json index 45dd915..9f202dc 100644 --- a/content/strings/fr.json +++ b/content/strings/fr.json @@ -43,6 +43,9 @@ "loot.category": "Catégorie", "ui.feature_unlocked": "NOUVELLE FONCTIONNALITÉ : {0}", "ui.completion": "Complétion : {0}%", + "hint.lore": "Fragments de Lore : {0}/{1}", + "hint.adventures": "Aventures terminées : {0}/{1}", + "hint.destiny": "Termine toutes les aventures pour débloquer l'aventure finale…", "prompt.what_do": "Que fais-tu ?", "prompt.invalid_choice": "Entre un nombre entre 1 et {0}.", diff --git a/src/OpenTheBox/Program.cs b/src/OpenTheBox/Program.cs index 9b48577..e8d4772 100644 --- a/src/OpenTheBox/Program.cs +++ b/src/OpenTheBox/Program.cs @@ -1013,6 +1013,27 @@ public static class Program + _state.VisibleStats.Count; _renderContext.CompletionPercent = total > 0 ? (int)(unlocked * 100.0 / total) : 0; + + // Build next-step hints + var hints = new List(); + + // Lore fragments + var totalLore = _registry.Items.Values.Count(i => i.Category == ItemCategory.LoreFragment); + var ownedLore = _state.Inventory.Count(i => + _registry.GetItem(i.DefinitionId)?.Category == ItemCategory.LoreFragment); + if (ownedLore < totalLore) + hints.Add(_loc.Get("hint.lore", ownedLore, totalLore)); + + // Adventures completed + var completedAdv = _state.CompletedAdventures.Count; + if (completedAdv < totalAdventures) + hints.Add(_loc.Get("hint.adventures", completedAdv, totalAdventures)); + + // Destiny adventure not yet unlocked — show condition + if (!_state.UnlockedAdventures.Contains(AdventureTheme.Destiny)) + hints.Add(_loc.Get("hint.destiny")); + + _renderContext.NextHints = hints; } private static string GetUIFeatureLocKey(UIFeature feature) => feature switch diff --git a/src/OpenTheBox/Rendering/RenderContext.cs b/src/OpenTheBox/Rendering/RenderContext.cs index 6fb3946..9bb8969 100644 --- a/src/OpenTheBox/Rendering/RenderContext.cs +++ b/src/OpenTheBox/Rendering/RenderContext.cs @@ -40,6 +40,9 @@ public sealed class RenderContext /// Completion percentage (0-100), updated before each render call. public int CompletionPercent { get; set; } + /// Short hints about what to do next, displayed under completion tracker. + public List NextHints { get; set; } = []; + /// /// Builds a that mirrors the features already unlocked in a /// . diff --git a/src/OpenTheBox/Rendering/SpectreRenderer.cs b/src/OpenTheBox/Rendering/SpectreRenderer.cs index 335bffa..ad61970 100644 --- a/src/OpenTheBox/Rendering/SpectreRenderer.cs +++ b/src/OpenTheBox/Rendering/SpectreRenderer.cs @@ -497,7 +497,11 @@ public sealed class SpectreRenderer : IRenderer rightItems.Add(CraftingPanel.Render(state, _registry, _loc)); if (context.HasCompletionTracker) + { rightItems.Add(new Markup($"[bold cyan]{Markup.Escape(_loc.Get("ui.completion", context.CompletionPercent))}[/]")); + foreach (var hint in context.NextHints) + rightItems.Add(new Markup($" [dim]{Markup.Escape(hint)}[/]")); + } IRenderable rightPanel = rightItems.Count > 0 ? new Rows(rightItems) @@ -545,6 +549,10 @@ public sealed class SpectreRenderer : IRenderer AnsiConsole.Write(CraftingPanel.Render(state, _registry, _loc)); if (context.HasCompletionTracker) + { AnsiConsole.Write(new Rule($"[bold cyan]{Markup.Escape(_loc.Get("ui.completion", context.CompletionPercent))}[/]").RuleStyle("cyan")); + foreach (var hint in context.NextHints) + AnsiConsole.MarkupLine($" [dim]{Markup.Escape(hint)}[/]"); + } } } diff --git a/src/OpenTheBox/Simulation/BoxEngine.cs b/src/OpenTheBox/Simulation/BoxEngine.cs index 0420583..8390879 100644 --- a/src/OpenTheBox/Simulation/BoxEngine.cs +++ b/src/OpenTheBox/Simulation/BoxEngine.cs @@ -221,6 +221,10 @@ public class BoxEngine(ContentRegistry registry) if (itemDef.MetaUnlock.HasValue && state.UnlockedUIFeatures.Contains(itemDef.MetaUnlock.Value)) return true; + // Meta box chain: treat as obtained when the entire chain is exhausted + if (Array.IndexOf(MetaBoxChain, itemDefId) >= 0 && MetaEngine.GetNextMetaItemId(state, registry) is null) + return true; + // Resource visibility already unlocked (only Meta items, not consumables) if (itemDef.ResourceType.HasValue && itemDef.Category == ItemCategory.Meta && state.VisibleResources.Contains(itemDef.ResourceType.Value))