Skip to content

Commit a25386f

Browse files
committed
Add character mini-icons to Workshop refinement cards to show access at a glance. Includes bUnit tests and refactoring of UIComponentTests to avoid monolith limit.
1 parent bf1063c commit a25386f

6 files changed

Lines changed: 134 additions & 67 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@using Mythril.Data
2+
3+
<span class="material-icons character-mini-icon"
4+
style="color: @Character.Color; font-size: 14px; cursor: default;"
5+
title="@Character.Name"
6+
data-testid="character-mini-icon-@Character.Name.ToLower()">
7+
@Character.Icon
8+
</span>
9+
10+
@code {
11+
[Parameter] public Character Character { get; set; }
12+
}

Mythril.Blazor/Components/RefinementCard.razor

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,17 @@
1919
<span class="arrow text-muted mx-1">→</span>
2020
<span class="output fw-bold small">@Refinement.Recipe.OutputQuantity @Refinement.Recipe.OutputItem.Name</span>
2121
</div>
22-
<div class="duration x-small-text">
23-
<span>@(ResourceManager.IsTestMode ? "2s" : "15s")</span>
24-
<span class="text-info ms-2">⚡ @Refinement.PrimaryStat</span>
22+
<div class="duration x-small-text d-flex align-items-center justify-content-between">
23+
<div>
24+
<span>@(ResourceManager.IsTestMode ? "2s" : "15s")</span>
25+
<span class="text-info ms-2">⚡ @Refinement.PrimaryStat</span>
26+
</div>
27+
<div class="character-access d-flex gap-1">
28+
@foreach (var character in charactersWithAccess)
29+
{
30+
<CharacterMiniIcon @key="character.Name" Character="character" />
31+
}
32+
</div>
2533
</div>
2634
</div>
2735
</div>
@@ -33,6 +41,8 @@
3341
private bool canAfford => ResourceManager.Inventory.Has(Refinement.InputItem, Refinement.Recipe.InputQuantity);
3442
private bool isStarred => ResourceManager.StarredRecipes.Contains(Refinement.Name);
3543

44+
private IEnumerable<Character> charactersWithAccess => ResourceManager.Characters.Where(c => ResourceManager.HasAbility(c, Refinement.Ability));
45+
3646
private void ToggleStar()
3747
{
3848
ResourceManager.ToggleRecipeStar(Refinement.Name);

Mythril.Tests/UIComponentTests.cs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -154,27 +154,6 @@ public void CadencePanel_NoCadences_RendersWarning()
154154
Assert.Contains("No Cadences discovered", noCadences.TextContent);
155155
}
156156

157-
[TestMethod]
158-
public void RefinementCard_RendersCorrectly()
159-
{
160-
// Arrange
161-
var ability = new CadenceAbility("Refine Fire", "Desc");
162-
var input = new Item("Basic Gem", "Desc", ItemType.Material);
163-
var output = new Item("Fire I", "Desc", ItemType.Spell);
164-
var recipe = new Recipe(1, output, 5);
165-
var refinement = new RefinementData(ability, input, recipe);
166-
167-
// Act
168-
var cut = RenderComponent<RefinementCard>(parameters => parameters
169-
.Add(p => p.Refinement, refinement)
170-
);
171-
172-
// Assert
173-
var text = cut.Find(".refinement-info").TextContent;
174-
Assert.Contains("1 Basic Gem", text);
175-
Assert.Contains("5 Fire I", text);
176-
}
177-
178157
[TestMethod]
179158
public void ItemIcon_RendersSpellWithFallback()
180159
{
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using Bunit;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Mythril.Blazor.Components;
4+
using Mythril.Data;
5+
6+
namespace Mythril.Tests;
7+
8+
[TestClass]
9+
public class WorkshopComponentTests : BunitTestBase
10+
{
11+
[TestMethod]
12+
public void CharacterMiniIcon_RendersCorrectly()
13+
{
14+
// Arrange
15+
var character = new Character("Protagonist");
16+
17+
// Act
18+
var cut = RenderComponent<CharacterMiniIcon>(parameters => parameters
19+
.Add(p => p.Character, character)
20+
);
21+
22+
// Assert
23+
var icon = cut.Find("[data-testid='character-mini-icon-protagonist']");
24+
Assert.AreEqual("person", icon.TextContent.Trim());
25+
Assert.Contains("#ff4444", icon.GetAttribute("style"));
26+
}
27+
28+
[TestMethod]
29+
public void RefinementCard_RendersCorrectly()
30+
{
31+
// Arrange
32+
// Use an ability that already exists in SandboxContent for Recruit
33+
var ability = ContentHost.GetContent<CadenceAbilities>().All.First(a => a.Name == SandboxContent.RefineScrap);
34+
var input = ContentHost.GetContent<Items>().All.First(i => i.Name == SandboxContent.Scrap);
35+
var output = ContentHost.GetContent<Items>().All.First(i => i.Name == SandboxContent.Gold);
36+
var recipe = new Recipe(5, output, 10);
37+
var refinement = new RefinementData(ability, input, recipe);
38+
39+
var resourceManager = Services.GetRequiredService<ResourceManager>();
40+
var character = resourceManager.Characters[0]; // Protagonist
41+
42+
// Ensure Recruit is unlocked so we can find it in UnlockedCadences
43+
var recruit = ContentHost.GetContent<Cadences>().All.First(c => c.Name == SandboxContent.Recruit);
44+
resourceManager.UnlockCadence(recruit);
45+
46+
resourceManager.UnlockAbility(SandboxContent.Recruit, SandboxContent.RefineScrap);
47+
resourceManager.JunctionManager.AssignCadence(recruit, character, resourceManager.UnlockedAbilities);
48+
49+
// Act - Render AFTER setup
50+
var cut = RenderComponent<RefinementCard>(parameters => parameters
51+
.Add(p => p.Refinement, refinement)
52+
);
53+
54+
cut.Render();
55+
56+
// Assert
57+
var text = cut.Find(".refinement-info").TextContent;
58+
Assert.Contains("5 Scrap", text);
59+
Assert.Contains("10 Gold", text);
60+
61+
// Should see character mini icon
62+
var miniIcon = cut.Find("[data-testid^='character-mini-icon-']");
63+
Assert.IsNotNull(miniIcon);
64+
65+
var iconHtml = cut.Find(".character-access").InnerHtml;
66+
Assert.Contains("person", iconHtml); // Protagonist icon
67+
}
68+
}

docs/Playtest_Feedback.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
- Rework lightning. Currently it's only unlockable very late in the game and the magic itself is vastly outclassed by other options by that point, making it a chain of orphaned content. => Fire and Ice shards both being part of this chain and also pointless.
1010
- Review and rework the entire stats system related to task performance. Right now, it's relatively random what requires vitality or speed, etc. I need to map things out and make larger design choices with intention. Just map for now.
1111

12-
- **j-str on Apprentice needs a second requirement. !!!major error. Secondary requirements aren't being heard!!!**
13-
1412
- Magic Pocket needs to be a benefit just to that character and more cadences need to have a magic pocket I and II unlock (enough so everyone could have it). Review. If we're leaving it as a global unlock, it needs to be properly illustrated in the UI as such.
1513

1614
- Consider junctioning magic on multiple characters/stats. FF8 would limit a single magic to a single stat and each character had their own magic inventory. Review and plan.

simulation_report.md

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Game Content Health Report
2-
Generated: 2026-04-28 11:59:39
2+
Generated: 2026-04-28 12:43:09
33

44
## 💀 Reachability Analysis
55
Total Quests Completed: 31
@@ -11,68 +11,68 @@ Routed Completion Time: 87.8m
1111

1212
## ⚖️ Economic Sustainability
1313
### Sustainable Recurring Activities
14+
- Chop Wood
15+
- Power the Forge
16+
- Refine Mixology:Herb->Potion
1417
- Gather Moonberries
15-
- Deep Sea Scavenge
16-
- Study Ancient Texts
17-
- Hunt Spiders
18+
- Refine Lightning:Ice Shard->Lightning I
19+
- Refine Ice:Moonberry->Ice I
20+
- Refine Ice:Mana Leaf->Ice I
1821
- Refine Scrap:Web->Gold
19-
- Power the Forge
22+
- Refine Fire:Basic Gem->Fire I
23+
- Archive Sifting
24+
- Alchemy I:Basic Gem->Gold
25+
- Scavenge Scrap
2026
- Hunt Slimes
27+
- Refine Lightning:Fire Shard->Lightning I
2128
- Refine Fire:Iron Ore->Fire I
22-
- Hunt Goblins
23-
- Refine Haste:Lost Parchment->Haste I
24-
- Hunt Sand-Sharks
25-
- Refine Ice:Moonberry->Ice I
26-
- Refine Ice:Mana Leaf->Ice I
27-
- Chop Wood
29+
- Tutorial Section
30+
- Harvest Sea-Life
2831
- Refine Earth:Crystal Shards->Earth I
29-
- Alchemy I:Basic Gem->Gold
32+
- Hunt Sand-Sharks
3033
- Mine Iron Ore
34+
- Shatter the Crystals
3135
- Refine Water:Blue Coral->Water I
36+
- Hunt Goblins
37+
- Study Ancient Texts
38+
- High Altitude Survey
39+
- Hunt Bats
40+
- Hunt Spiders
41+
- Deep Sea Scavenge
42+
- Refine Haste:Lost Parchment->Haste I
3243
- Refine Wood:Log->Herb
33-
- Refine Lightning:Fire Shard->Lightning I
34-
- Refine Fire:Basic Gem->Fire I
35-
- Refine Mixology:Herb->Potion
3644
- Refine Life:Ancient Bark->Cure I
37-
- Refine Lightning:Ice Shard->Lightning I
38-
- Harvest Sea-Life
39-
- Hunt Bats
40-
- Archive Sifting
41-
- High Altitude Survey
42-
- Tutorial Section
43-
- Shatter the Crystals
44-
- Scavenge Scrap
4545

4646
### ⚠️ Unsustainable Activities (Reachable but starving)
47-
- Alchemy II:Potion->Gold
48-
- Alchemy II:Sun-baked Scale->Gold
4947
- Refine Life:Solar Essence->Cure I
48+
- Alchemy II:Sun-baked Scale->Gold
49+
- Alchemy II:Potion->Gold
5050
- Refine Scrap:Slime->Gold
5151

5252
### Net Resource Rates (per second)
53-
- **Fire I**: 54.0445/s
54-
- **Mana Leaf**: 5.3223/s
55-
- **Leather**: 26.2781/s
56-
- **Moonberry**: 21.2893/s
57-
- **Ice Shard**: 30.0487/s
58-
- **Cure I**: 24.9436/s
59-
- **Potion**: 4.9887/s
60-
- **Crystal Shards**: 7.4831/s
6153
- **Log**: 4.9887/s
62-
- **Water I**: 105.1123/s
54+
- **Ice I**: 49.8873/s
6355
- **Sun-baked Scale**: 0.8315/s
6456
- **Slime**: 4.1573/s
57+
- **Earth I**: 24.9436/s
58+
- **Mana Leaf**: 5.3223/s
59+
- **Herb**: 19.9549/s
60+
- **Ice Shard**: 30.0487/s
6561
- **Lost Parchment**: 3.3258/s
66-
- **Iron Ore**: 11.1049/s
62+
- **Leather**: 26.2781/s
63+
- **Crystal Shards**: 7.4831/s
64+
- **Moonberry**: 21.2893/s
65+
- **Gold**: 6896.7448/s
66+
- **Water I**: 105.1123/s
6767
- **Haste I**: 24.9436/s
68-
- **Herb**: 19.9549/s
69-
- **Earth I**: 24.9436/s
70-
- **Basic Gem**: 5.5225/s
71-
- **Mythril Spark**: 0.4157/s
68+
- **Iron Ore**: 11.1049/s
69+
- **Cure I**: 24.9436/s
7270
- **Fire Shard**: 31.2959/s
73-
- **Ice I**: 49.8873/s
71+
- **Fire I**: 54.0445/s
7472
- **Lightning I**: 49.8873/s
75-
- **Gold**: 6896.7448/s
73+
- **Mythril Spark**: 0.4157/s
74+
- **Basic Gem**: 5.5225/s
75+
- **Potion**: 4.9887/s
7676

7777
## 🔄 Feedback Loops
7878
✅ No unbounded growth loops detected (approximation).

0 commit comments

Comments
 (0)