[feature: fabricator-discipline] Add discipline for unlocking fabricator recipes #206

Closed
opened 2026-05-29 13:58:54 +02:00 by Anexim · 3 comments
Owner

FEATURE: Fabricator recipes should be gated behind a discipline, similar to how enchantment effects are gated behind enchanter disciplines.

Current State

Fabricator recipes in src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx are shown to the player purely based on mana type filter — ALL recipes for a given mana type are visible immediately once that mana type is unlocked. There is no progression gating.

Desired Behavior

Add a new discipline (or disciplines) that gates fabricator recipes behind XP thresholds, following the exact same pattern used by enchanter disciplines for enchantment effect unlocks.

Reference Pattern: Enchanter Discipline Unlocks

The existing infrastructure works as follows:

  1. Discipline perks define unlocksEffects: string[] — e.g. in data/disciplines/enchanter.ts line 70-96, the study-basic-weapon-enchantments discipline unlocks ['sword_fire', 'sword_frost', 'sword_lightning'] at thresholds 50/100/150.

  2. Tick processing collects unlocksstores/discipline-slice.ts ~line 192-220: during processTick(), newly unlocked perks with unlocksEffects are collected into newUnlockedEffects[].

  3. GameStore passes unlocks to CraftingStorestores/gameStore.ts ~line 270-274: calls useCraftingStore.getState().unlockEffects(disciplineResult.unlockedEffects).

  4. UI filters by unlock statuscrafting/EnchantmentDesigner/utils.ts line 12-25: getAvailableEffects() filters to only effects where unlockedEffects.includes(effect.id).

Implementation Plan

Option A (simplest): Reuse the unlocksEffects field on discipline perks to also hold fabricator recipe IDs. The unlock pipeline already works — just add recipe IDs to the array and filter recipes in FabricatorSubTab.tsx using the same unlockedEffects check.

Option B (cleaner): Add a new unlocksRecipes?: string[] field to DisciplinePerk (in types/disciplines.ts line 26) and mirror the unlock pipeline: collect during tick processing, pass to a new unlockRecipes() action on the crafting store, filter in the UI.

Files to Modify

  • src/lib/game/types/disciplines.ts — Add unlocksRecipes?: string[] to DisciplinePerk (if going with Option B)
  • src/lib/game/data/disciplines/fabricator.ts — Add new discipline(s) with recipe-unlocking perks
  • src/lib/game/data/disciplines/index.ts — Re-export new discipline(s)
  • src/lib/game/stores/discipline-slice.ts — Collect unlocksRecipes during tick (Option B only)
  • src/lib/game/stores/gameStore.ts — Pass recipe unlocks to crafting store (Option B only)
  • src/lib/game/stores/craftingStore.ts — Add unlockRecipes() action (Option B only)
  • src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx — Filter recipes by unlock status

Priority

MEDIUM — Affects game balance and progression pacing.

**FEATURE: Fabricator recipes should be gated behind a discipline, similar to how enchantment effects are gated behind enchanter disciplines.** ### Current State Fabricator recipes in `src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx` are shown to the player purely based on mana type filter — ALL recipes for a given mana type are visible immediately once that mana type is unlocked. There is no progression gating. ### Desired Behavior Add a new discipline (or disciplines) that gates fabricator recipes behind XP thresholds, following the exact same pattern used by enchanter disciplines for enchantment effect unlocks. ### Reference Pattern: Enchanter Discipline Unlocks The existing infrastructure works as follows: 1. **Discipline perks define `unlocksEffects: string[]`** — e.g. in `data/disciplines/enchanter.ts` line 70-96, the `study-basic-weapon-enchantments` discipline unlocks `['sword_fire', 'sword_frost', 'sword_lightning']` at thresholds 50/100/150. 2. **Tick processing collects unlocks** — `stores/discipline-slice.ts` ~line 192-220: during `processTick()`, newly unlocked perks with `unlocksEffects` are collected into `newUnlockedEffects[]`. 3. **GameStore passes unlocks to CraftingStore** — `stores/gameStore.ts` ~line 270-274: calls `useCraftingStore.getState().unlockEffects(disciplineResult.unlockedEffects)`. 4. **UI filters by unlock status** — `crafting/EnchantmentDesigner/utils.ts` line 12-25: `getAvailableEffects()` filters to only effects where `unlockedEffects.includes(effect.id)`. ### Implementation Plan **Option A (simplest):** Reuse the `unlocksEffects` field on discipline perks to also hold fabricator recipe IDs. The unlock pipeline already works — just add recipe IDs to the array and filter recipes in `FabricatorSubTab.tsx` using the same `unlockedEffects` check. **Option B (cleaner):** Add a new `unlocksRecipes?: string[]` field to `DisciplinePerk` (in `types/disciplines.ts` line 26) and mirror the unlock pipeline: collect during tick processing, pass to a new `unlockRecipes()` action on the crafting store, filter in the UI. ### Files to Modify - `src/lib/game/types/disciplines.ts` — Add `unlocksRecipes?: string[]` to `DisciplinePerk` (if going with Option B) - `src/lib/game/data/disciplines/fabricator.ts` — Add new discipline(s) with recipe-unlocking perks - `src/lib/game/data/disciplines/index.ts` — Re-export new discipline(s) - `src/lib/game/stores/discipline-slice.ts` — Collect `unlocksRecipes` during tick (Option B only) - `src/lib/game/stores/gameStore.ts` — Pass recipe unlocks to crafting store (Option B only) - `src/lib/game/stores/craftingStore.ts` — Add `unlockRecipes()` action (Option B only) - `src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx` — Filter recipes by unlock status ### Priority MEDIUM — Affects game balance and progression pacing.
Anexim added the ai:todo label 2026-05-29 13:58:54 +02:00
n8n-gitea was assigned by Anexim 2026-05-29 13:58:54 +02:00
Author
Owner

Starting work on fabricator discipline for unlocking recipes.

Starting work on fabricator discipline for unlocking recipes.
Author
Owner

Implementation Complete

Implemented Option B (cleaner approach with separate unlocksRecipes field on discipline perks).

Changes Made (10 files, +216/-8)

  1. src/lib/game/types/disciplines.ts — Added unlocksRecipes?: string[] to DisciplinePerk interface
  2. src/lib/game/data/disciplines/fabricator.ts — Added 3 new disciplines:
    • study-fabricator-recipes — Unlocks elemental recipes (earth/metal/sand/crystal) at thresholds 50/100/150/200
    • study-wizard-branch — Unlocks wizard equipment recipes (oak/arcanist/battlestaff/arcanist set/void catalyst/pendant) at thresholds 50-300, requires study-fabricator-recipes
    • study-physical-branch — Unlocks physical combat recipes (crystal/arcanist/void blade/battle set) at thresholds 50-300, requires study-fabricator-recipes
  3. src/lib/game/stores/discipline-slice.ts — Collects unlocksRecipes during processTick() alongside unlocksEffects, returns unlockedRecipes in result
  4. src/lib/game/stores/gameStore.ts — Passes disciplineResult.unlockedRecipes to craftingStore.unlockRecipes() with log messages
  5. src/lib/game/stores/craftingStore.types.ts — Added unlockedRecipes: string[] to state and unlockRecipes() to actions
  6. src/lib/game/stores/craftingStore.ts — Implemented unlockRecipes() action, added to persistence
  7. src/lib/game/stores/crafting-initial-state.ts — Added unlockedRecipes: [] to default state
  8. src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx — Filters recipes by unlockedRecipes.includes(r.id) so only unlocked recipes are visible

Verification

  • All 896 tests pass (44 test files)
  • All pre-commit checks pass (file sizes, no circular deps)
  • No new TypeScript errors introduced
## Implementation Complete ✅ Implemented Option B (cleaner approach with separate `unlocksRecipes` field on discipline perks). ### Changes Made (10 files, +216/-8) 1. **`src/lib/game/types/disciplines.ts`** — Added `unlocksRecipes?: string[]` to `DisciplinePerk` interface 2. **`src/lib/game/data/disciplines/fabricator.ts`** — Added 3 new disciplines: - `study-fabricator-recipes` — Unlocks elemental recipes (earth/metal/sand/crystal) at thresholds 50/100/150/200 - `study-wizard-branch` — Unlocks wizard equipment recipes (oak/arcanist/battlestaff/arcanist set/void catalyst/pendant) at thresholds 50-300, requires `study-fabricator-recipes` - `study-physical-branch` — Unlocks physical combat recipes (crystal/arcanist/void blade/battle set) at thresholds 50-300, requires `study-fabricator-recipes` 3. **`src/lib/game/stores/discipline-slice.ts`** — Collects `unlocksRecipes` during `processTick()` alongside `unlocksEffects`, returns `unlockedRecipes` in result 4. **`src/lib/game/stores/gameStore.ts`** — Passes `disciplineResult.unlockedRecipes` to `craftingStore.unlockRecipes()` with log messages 5. **`src/lib/game/stores/craftingStore.types.ts`** — Added `unlockedRecipes: string[]` to state and `unlockRecipes()` to actions 6. **`src/lib/game/stores/craftingStore.ts`** — Implemented `unlockRecipes()` action, added to persistence 7. **`src/lib/game/stores/crafting-initial-state.ts`** — Added `unlockedRecipes: []` to default state 8. **`src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx`** — Filters recipes by `unlockedRecipes.includes(r.id)` so only unlocked recipes are visible ### Verification - All 896 tests pass (44 test files) - All pre-commit checks pass (file sizes, no circular deps) - No new TypeScript errors introduced
Author
Owner

Implementation complete. All tests passing, committed and pushed.

Implementation complete. All tests passing, committed and pushed.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Anexim/Mana-Loop#206