feat: discipline UI improvements - stat labels, prerequisites, mana type tab
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m23s

- Add player-friendly label field to statBonus in DisciplineDefinition
- Show prerequisite requirements on locked discipline cards
- Disable activate button for locked disciplines
- Restructure elemental attunement into dedicated 'Mana Types' tab
- Add checkDisciplinePrerequisites utility function
- Update store to enforce prerequisite checking on activation
- Split discipline-prerequisites tests into separate file
This commit is contained in:
2026-05-25 15:20:02 +02:00
parent 2c58186a67
commit 635b3b3f70
21 changed files with 313 additions and 82 deletions
+1 -22
View File
@@ -12,7 +12,7 @@ export const baseDisciplines: DisciplineDefinition[] = [
manaType: 'raw',
baseCost: 5,
description: 'Learn to harness raw mana more efficiently.',
statBonus: { stat: 'maxManaBonus', baseValue: 10 },
statBonus: { stat: 'maxManaBonus', baseValue: 10, label: 'Max Mana' },
difficultyFactor: 100,
scalingFactor: 50,
drainBase: 1,
@@ -33,25 +33,4 @@ export const baseDisciplines: DisciplineDefinition[] = [
},
],
},
{
id: 'elemental-attunement',
name: 'Elemental Attunement',
attunement: DisciplinesAttunementType.BASE,
manaType: 'fire',
baseCost: 10,
description: 'Begin focusing raw mana into fire.',
statBonus: { stat: 'elementCap_fire', baseValue: 5 },
difficultyFactor: 150,
scalingFactor: 75,
drainBase: 2,
perks: [
{
id: 'elem-attunement-1',
type: 'once',
threshold: 200,
value: 0,
description: '+10 Fire Capacity',
},
],
},
];
@@ -14,7 +14,7 @@ export const elementalRegenAdvancedDisciplines: DisciplineDefinition[] = [
manaType: 'metal',
baseCost: 12,
description: 'Attune your metal mana to regenerate passively over time.',
statBonus: { stat: 'regen_metal', baseValue: 0.35 },
statBonus: { stat: 'regen_metal', baseValue: 0.35, label: 'Metal Regen/tick' },
difficultyFactor: 160,
scalingFactor: 80,
drainBase: 2,
@@ -43,7 +43,7 @@ export const elementalRegenAdvancedDisciplines: DisciplineDefinition[] = [
manaType: 'sand',
baseCost: 12,
description: 'Attune your sand mana to regenerate passively over time.',
statBonus: { stat: 'regen_sand', baseValue: 0.35 },
statBonus: { stat: 'regen_sand', baseValue: 0.35, label: 'Sand Regen/tick' },
difficultyFactor: 160,
scalingFactor: 80,
drainBase: 2,
@@ -72,7 +72,7 @@ export const elementalRegenAdvancedDisciplines: DisciplineDefinition[] = [
manaType: 'lightning',
baseCost: 12,
description: 'Attune your lightning mana to regenerate passively over time.',
statBonus: { stat: 'regen_lightning', baseValue: 0.35 },
statBonus: { stat: 'regen_lightning', baseValue: 0.35, label: 'Lightning Regen/tick' },
difficultyFactor: 160,
scalingFactor: 80,
drainBase: 2,
@@ -102,7 +102,7 @@ export const elementalRegenAdvancedDisciplines: DisciplineDefinition[] = [
manaType: 'crystal',
baseCost: 18,
description: 'Attune your crystal mana to regenerate passively over time.',
statBonus: { stat: 'regen_crystal', baseValue: 0.25 },
statBonus: { stat: 'regen_crystal', baseValue: 0.25, label: 'Crystal Regen/tick' },
difficultyFactor: 220,
scalingFactor: 110,
drainBase: 3,
@@ -131,7 +131,7 @@ export const elementalRegenAdvancedDisciplines: DisciplineDefinition[] = [
manaType: 'stellar',
baseCost: 18,
description: 'Attune your stellar mana to regenerate passively over time.',
statBonus: { stat: 'regen_stellar', baseValue: 0.25 },
statBonus: { stat: 'regen_stellar', baseValue: 0.25, label: 'Stellar Regen/tick' },
difficultyFactor: 220,
scalingFactor: 110,
drainBase: 3,
@@ -160,7 +160,7 @@ export const elementalRegenAdvancedDisciplines: DisciplineDefinition[] = [
manaType: 'void',
baseCost: 18,
description: 'Attune your void mana to regenerate passively over time.',
statBonus: { stat: 'regen_void', baseValue: 0.25 },
statBonus: { stat: 'regen_void', baseValue: 0.25, label: 'Void Regen/tick' },
difficultyFactor: 220,
scalingFactor: 110,
drainBase: 3,
@@ -19,7 +19,7 @@ function makeBaseRegen(id: string, name: string, manaType: string, cost: number)
manaType: manaType as DisciplineDefinition['manaType'],
baseCost: cost,
description: `Attune your ${name.toLowerCase()} mana to regenerate passively over time.`,
statBonus: { stat: `regen_${shortId}` as DisciplineDefinition['statBonus']['stat'], baseValue: BASE_REGEN },
statBonus: { stat: `regen_${shortId}` as DisciplineDefinition['statBonus']['stat'], baseValue: BASE_REGEN, label: `${name} Regen/tick` },
difficultyFactor: BASE_DIFF,
scalingFactor: BASE_SCALE,
drainBase: BASE_DRAIN,
@@ -61,7 +61,7 @@ export const elementalRegenDisciplines: DisciplineDefinition[] = [
manaType: 'transference',
baseCost: 6,
description: 'Attune your transference mana to regenerate passively over time.',
statBonus: { stat: 'regen_transference', baseValue: 0.4 },
statBonus: { stat: 'regen_transference', baseValue: 0.4, label: 'Transference Regen/tick' },
difficultyFactor: 100,
scalingFactor: 50,
drainBase: 1,
@@ -0,0 +1,54 @@
// ─── Elemental Attunement Disciplines ──────────────────────────────────────────
// One discipline per base mana type that increases that element's capacity.
// All are BASE attunement so they are available to every role once the element is unlocked.
import { DisciplinesAttunementType } from '../../types/disciplines';
import type { DisciplineDefinition } from '../../types/disciplines';
interface ElementalAttunementConfig {
id: string;
name: string;
manaType: DisciplineDefinition['manaType'];
cost: number;
baseValue: number;
difficultyFactor: number;
scalingFactor: number;
drainBase: number;
}
const ELEMENTAL_ATTUNEMENTS: ElementalAttunementConfig[] = [
{ id: 'attune-fire', name: 'Fire', manaType: 'fire', cost: 10, baseValue: 5, difficultyFactor: 150, scalingFactor: 75, drainBase: 2 },
{ id: 'attune-water', name: 'Water', manaType: 'water', cost: 10, baseValue: 5, difficultyFactor: 150, scalingFactor: 75, drainBase: 2 },
{ id: 'attune-air', name: 'Air', manaType: 'air', cost: 10, baseValue: 5, difficultyFactor: 150, scalingFactor: 75, drainBase: 2 },
{ id: 'attune-earth', name: 'Earth', manaType: 'earth', cost: 10, baseValue: 5, difficultyFactor: 150, scalingFactor: 75, drainBase: 2 },
{ id: 'attune-light', name: 'Light', manaType: 'light', cost: 10, baseValue: 5, difficultyFactor: 150, scalingFactor: 75, drainBase: 2 },
{ id: 'attune-dark', name: 'Dark', manaType: 'dark', cost: 10, baseValue: 5, difficultyFactor: 150, scalingFactor: 75, drainBase: 2 },
{ id: 'attune-death', name: 'Death', manaType: 'death', cost: 12, baseValue: 4, difficultyFactor: 180, scalingFactor: 90, drainBase: 3 },
];
function makeElementalAttunement(cfg: ElementalAttunementConfig): DisciplineDefinition {
return {
id: cfg.id,
name: `${cfg.name} Attunement`,
attunement: DisciplinesAttunementType.BASE,
manaType: cfg.manaType,
baseCost: cfg.cost,
description: `Begin focusing raw mana into ${cfg.name.toLowerCase()}.`,
statBonus: { stat: `elementCap_${cfg.manaType}`, baseValue: cfg.baseValue, label: `${cfg.name} Mana Capacity` },
difficultyFactor: cfg.difficultyFactor,
scalingFactor: cfg.scalingFactor,
drainBase: cfg.drainBase,
perks: [
{
id: `${cfg.id}-1`,
type: 'once',
threshold: 200,
value: 0,
description: `+10 ${cfg.name} Capacity`,
},
],
};
}
export const elementalAttunementDisciplines: DisciplineDefinition[] =
ELEMENTAL_ATTUNEMENTS.map(makeElementalAttunement);
@@ -12,7 +12,7 @@ export const enchanterSpecialDisciplines: DisciplineDefinition[] = [
manaType: 'death',
baseCost: 22,
description: 'Learn to enchant equipment with unique and powerful effects.',
statBonus: { stat: 'enchantPower', baseValue: 5 },
statBonus: { stat: 'enchantPower', baseValue: 5, label: 'Enchantment Power' },
difficultyFactor: 220,
scalingFactor: 130,
drainBase: 4,
@@ -12,7 +12,7 @@ export const enchanterSpellDisciplines: DisciplineDefinition[] = [
manaType: 'air',
baseCost: 18,
description: 'Learn to enchant casters with basic spell effects.',
statBonus: { stat: 'enchantPower', baseValue: 4 },
statBonus: { stat: 'enchantPower', baseValue: 4, label: 'Enchantment Power' },
difficultyFactor: 160,
scalingFactor: 100,
drainBase: 3,
@@ -90,7 +90,7 @@ export const enchanterSpellDisciplines: DisciplineDefinition[] = [
manaType: 'earth',
baseCost: 25,
description: 'Learn to enchant casters with intermediate and compound spell effects.',
statBonus: { stat: 'enchantPower', baseValue: 6 },
statBonus: { stat: 'enchantPower', baseValue: 6, label: 'Enchantment Power' },
difficultyFactor: 250,
scalingFactor: 150,
drainBase: 5,
@@ -153,7 +153,7 @@ export const enchanterSpellDisciplines: DisciplineDefinition[] = [
manaType: 'dark',
baseCost: 35,
description: 'Learn to enchant casters with master and exotic spell effects.',
statBonus: { stat: 'enchantPower', baseValue: 10 },
statBonus: { stat: 'enchantPower', baseValue: 10, label: 'Enchantment Power' },
difficultyFactor: 350,
scalingFactor: 200,
drainBase: 7,
@@ -12,7 +12,7 @@ export const enchanterUtilityDisciplines: DisciplineDefinition[] = [
manaType: 'light',
baseCost: 8,
description: 'Learn to enchant equipment with utility effects.',
statBonus: { stat: 'studySpeed', baseValue: 0.05 },
statBonus: { stat: 'studySpeed', baseValue: 0.05, label: 'Study Speed' },
difficultyFactor: 80,
scalingFactor: 60,
drainBase: 2,
@@ -50,7 +50,7 @@ export const enchanterUtilityDisciplines: DisciplineDefinition[] = [
manaType: 'water',
baseCost: 15,
description: 'Learn to enchant equipment with mana-boosting effects.',
statBonus: { stat: 'maxMana', baseValue: 10 },
statBonus: { stat: 'maxMana', baseValue: 10, label: 'Max Mana' },
difficultyFactor: 150,
scalingFactor: 100,
drainBase: 3,
+4 -4
View File
@@ -12,7 +12,7 @@ export const enchanterDisciplines: DisciplineDefinition[] = [
manaType: 'transference',
baseCost: 8,
description: 'Improve your ability to apply enchantments to equipment.',
statBonus: { stat: 'enchantPower', baseValue: 8 },
statBonus: { stat: 'enchantPower', baseValue: 8, label: 'Enchantment Power' },
difficultyFactor: 120,
scalingFactor: 60,
drainBase: 3,
@@ -40,7 +40,7 @@ export const enchanterDisciplines: DisciplineDefinition[] = [
manaType: 'lightning',
baseCost: 12,
description: 'Use lightning to transfer mana to equipment.',
statBonus: { stat: 'clickManaMultiplier', baseValue: 0.3 },
statBonus: { stat: 'clickManaMultiplier', baseValue: 0.3, label: 'Click Mana Multiplier' },
difficultyFactor: 180,
scalingFactor: 90,
drainBase: 5,
@@ -61,7 +61,7 @@ export const enchanterDisciplines: DisciplineDefinition[] = [
manaType: 'fire',
baseCost: 10,
description: 'Learn to enchant weapons with basic elemental effects.',
statBonus: { stat: 'enchantPower', baseValue: 3 },
statBonus: { stat: 'enchantPower', baseValue: 3, label: 'Enchantment Power' },
difficultyFactor: 100,
scalingFactor: 80,
drainBase: 2,
@@ -99,7 +99,7 @@ export const enchanterDisciplines: DisciplineDefinition[] = [
manaType: 'dark',
baseCost: 20,
description: 'Learn to enchant weapons with exotic and combat effects.',
statBonus: { stat: 'enchantPower', baseValue: 5 },
statBonus: { stat: 'enchantPower', baseValue: 5, label: 'Enchantment Power' },
difficultyFactor: 200,
scalingFactor: 120,
drainBase: 4,
+2 -2
View File
@@ -12,7 +12,7 @@ export const fabricatorDisciplines: DisciplineDefinition[] = [
manaType: 'earth',
baseCost: 10,
description: 'Improve your ability to craft and maintain golems.',
statBonus: { stat: 'golemCapacity', baseValue: 2 },
statBonus: { stat: 'golemCapacity', baseValue: 2, label: 'Golem Capacity' },
difficultyFactor: 150,
scalingFactor: 80,
drainBase: 4,
@@ -40,7 +40,7 @@ export const fabricatorDisciplines: DisciplineDefinition[] = [
manaType: 'sand',
baseCost: 12,
description: 'Reduce material costs for crafting.',
statBonus: { stat: 'craftingCostReduction', baseValue: 15 },
statBonus: { stat: 'craftingCostReduction', baseValue: 15, label: 'Crafting Cost Reduction' },
difficultyFactor: 180,
scalingFactor: 90,
drainBase: 6,
+3
View File
@@ -2,6 +2,7 @@
// Aggregates all discipline definitions into a single ALL_DISCIPLINES array
import { baseDisciplines } from './base';
import { elementalAttunementDisciplines } from './elemental';
import { elementalRegenDisciplines } from './elemental-regen';
import { elementalRegenAdvancedDisciplines } from './elemental-regen-advanced';
import { enchanterDisciplines } from './enchanter';
@@ -14,6 +15,7 @@ import type { DisciplineDefinition } from '../../types/disciplines';
export const ALL_DISCIPLINES: DisciplineDefinition[] = [
...baseDisciplines,
...elementalAttunementDisciplines,
...elementalRegenDisciplines,
...elementalRegenAdvancedDisciplines,
...enchanterDisciplines,
@@ -25,6 +27,7 @@ export const ALL_DISCIPLINES: DisciplineDefinition[] = [
];
export { baseDisciplines } from './base';
export { elementalAttunementDisciplines } from './elemental';
export { elementalRegenDisciplines } from './elemental-regen';
export { elementalRegenAdvancedDisciplines } from './elemental-regen-advanced';
export { enchanterDisciplines } from './enchanter';
+2 -2
View File
@@ -12,7 +12,7 @@ export const invokerDisciplines: DisciplineDefinition[] = [
manaType: 'light',
baseCost: 10,
description: 'Improve spell power and effectiveness.',
statBonus: { stat: 'baseDamageBonus', baseValue: 6 },
statBonus: { stat: 'baseDamageBonus', baseValue: 6, label: 'Base Damage' },
difficultyFactor: 130,
scalingFactor: 65,
drainBase: 3,
@@ -40,7 +40,7 @@ export const invokerDisciplines: DisciplineDefinition[] = [
manaType: 'void',
baseCost: 15,
description: 'Master the exotic void mana for devastating effects.',
statBonus: { stat: 'baseDamageMultiplier', baseValue: 0.15 },
statBonus: { stat: 'baseDamageMultiplier', baseValue: 0.15, label: 'Base Damage Multiplier' },
difficultyFactor: 200,
scalingFactor: 100,
drainBase: 7,