Stop meta box drops when all unlocks obtained, add next-step hints
- BoxEngine: treat meta box chain items as "already obtained" when the entire meta unlock sequence is complete, preventing useless box_meta_mastery drops that only contain more boxes. - Add progression hints under completion tracker showing lore fragment count, adventure completion count, and a teaser for the final adventure.
This commit is contained in:
parent
a8d2903b94
commit
d079faa2e6
6 changed files with 42 additions and 0 deletions
|
|
@ -43,6 +43,9 @@
|
||||||
"loot.category": "Category",
|
"loot.category": "Category",
|
||||||
"ui.feature_unlocked": "NEW FEATURE UNLOCKED: {0}",
|
"ui.feature_unlocked": "NEW FEATURE UNLOCKED: {0}",
|
||||||
"ui.completion": "Completion: {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.what_do": "What do you do?",
|
||||||
"prompt.invalid_choice": "Please enter a number between 1 and {0}.",
|
"prompt.invalid_choice": "Please enter a number between 1 and {0}.",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@
|
||||||
"loot.category": "Catégorie",
|
"loot.category": "Catégorie",
|
||||||
"ui.feature_unlocked": "NOUVELLE FONCTIONNALITÉ : {0}",
|
"ui.feature_unlocked": "NOUVELLE FONCTIONNALITÉ : {0}",
|
||||||
"ui.completion": "Complétion : {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.what_do": "Que fais-tu ?",
|
||||||
"prompt.invalid_choice": "Entre un nombre entre 1 et {0}.",
|
"prompt.invalid_choice": "Entre un nombre entre 1 et {0}.",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1013,6 +1013,27 @@ public static class Program
|
||||||
+ _state.VisibleStats.Count;
|
+ _state.VisibleStats.Count;
|
||||||
|
|
||||||
_renderContext.CompletionPercent = total > 0 ? (int)(unlocked * 100.0 / total) : 0;
|
_renderContext.CompletionPercent = total > 0 ? (int)(unlocked * 100.0 / total) : 0;
|
||||||
|
|
||||||
|
// Build next-step hints
|
||||||
|
var hints = new List<string>();
|
||||||
|
|
||||||
|
// 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
|
private static string GetUIFeatureLocKey(UIFeature feature) => feature switch
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ public sealed class RenderContext
|
||||||
/// <summary>Completion percentage (0-100), updated before each render call.</summary>
|
/// <summary>Completion percentage (0-100), updated before each render call.</summary>
|
||||||
public int CompletionPercent { get; set; }
|
public int CompletionPercent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Short hints about what to do next, displayed under completion tracker.</summary>
|
||||||
|
public List<string> NextHints { get; set; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds a <see cref="RenderContext"/> that mirrors the features already unlocked in a
|
/// Builds a <see cref="RenderContext"/> that mirrors the features already unlocked in a
|
||||||
/// <see cref="GameState"/>.
|
/// <see cref="GameState"/>.
|
||||||
|
|
|
||||||
|
|
@ -497,7 +497,11 @@ public sealed class SpectreRenderer : IRenderer
|
||||||
rightItems.Add(CraftingPanel.Render(state, _registry, _loc));
|
rightItems.Add(CraftingPanel.Render(state, _registry, _loc));
|
||||||
|
|
||||||
if (context.HasCompletionTracker)
|
if (context.HasCompletionTracker)
|
||||||
|
{
|
||||||
rightItems.Add(new Markup($"[bold cyan]{Markup.Escape(_loc.Get("ui.completion", context.CompletionPercent))}[/]"));
|
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
|
IRenderable rightPanel = rightItems.Count > 0
|
||||||
? new Rows(rightItems)
|
? new Rows(rightItems)
|
||||||
|
|
@ -545,6 +549,10 @@ public sealed class SpectreRenderer : IRenderer
|
||||||
AnsiConsole.Write(CraftingPanel.Render(state, _registry, _loc));
|
AnsiConsole.Write(CraftingPanel.Render(state, _registry, _loc));
|
||||||
|
|
||||||
if (context.HasCompletionTracker)
|
if (context.HasCompletionTracker)
|
||||||
|
{
|
||||||
AnsiConsole.Write(new Rule($"[bold cyan]{Markup.Escape(_loc.Get("ui.completion", context.CompletionPercent))}[/]").RuleStyle("cyan"));
|
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)}[/]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,10 @@ public class BoxEngine(ContentRegistry registry)
|
||||||
if (itemDef.MetaUnlock.HasValue && state.UnlockedUIFeatures.Contains(itemDef.MetaUnlock.Value))
|
if (itemDef.MetaUnlock.HasValue && state.UnlockedUIFeatures.Contains(itemDef.MetaUnlock.Value))
|
||||||
return true;
|
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)
|
// Resource visibility already unlocked (only Meta items, not consumables)
|
||||||
if (itemDef.ResourceType.HasValue && itemDef.Category == ItemCategory.Meta
|
if (itemDef.ResourceType.HasValue && itemDef.Category == ItemCategory.Meta
|
||||||
&& state.VisibleResources.Contains(itemDef.ResourceType.Value))
|
&& state.VisibleResources.Contains(itemDef.ResourceType.Value))
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue