Refactor large files into modular components
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m9s

- Refactored page.tsx (613→252 lines) with GameOverScreen and LeftPanel extracted
- Refactored StatsTab.tsx (584→92 lines) with section components
- Refactored SkillsTab.tsx (434→54 lines) with sub-components
- Created modular structure for GameContext, LootInventory, and other components
- All extracted components organized into feature directories
This commit is contained in:
Refactoring Agent
2026-05-02 17:35:03 +02:00
parent c9ae2576f4
commit d2d28887b1
194 changed files with 16862 additions and 15729 deletions
+30
View File
@@ -0,0 +1,30 @@
// ─── Base Golem Definitions ───────────────────────────────────
import type { GolemDef } from './types';
import { elemCost } from './types';
export const BASE_GOLEMS: Record<string, GolemDef> = {
// ─── BASE GOLEMS ─────────────────────────────────────────────────────
// Earth Golem - Basic, available with Fabricator attunement
earthGolem: {
id: 'earthGolem',
name: 'Earth Golem',
description: 'A sturdy construct of stone and soil. Slow but powerful.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 10)],
maintenanceCost: [elemCost('earth', 0.5)],
damage: 8,
attackSpeed: 1.5,
hp: 50,
armorPierce: 0.15,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'attunement_level',
attunement: 'fabricator',
level: 2,
},
tier: 1,
},
};
@@ -0,0 +1,71 @@
// ─── Elemental Variant Golems ───────────────────────────────────
import type { GolemDef } from './types';
import { elemCost } from './types';
export const ELEMENTAL_GOLEMS: Record<string, GolemDef> = {
// ─── ELEMENTAL VARIANT GOLEMS ────────────────────────────────────────
// Steel Golem - Metal mana variant
steelGolem: {
id: 'steelGolem',
name: 'Steel Golem',
description: 'Forged from metal, this golem has high armor piercing.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 8), elemCost('earth', 5)],
maintenanceCost: [elemCost('metal', 0.6), elemCost('earth', 0.2)],
damage: 12,
attackSpeed: 1.2,
hp: 60,
armorPierce: 0.35,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'metal',
},
tier: 2,
},
// Crystal Golem - Crystal mana variant
crystalGolem: {
id: 'crystalGolem',
name: 'Crystal Golem',
description: 'A prismatic construct that deals high damage with precision.',
baseManaType: 'crystal',
summonCost: [elemCost('crystal', 6), elemCost('earth', 3)],
maintenanceCost: [elemCost('crystal', 0.4), elemCost('earth', 0.2)],
damage: 18,
attackSpeed: 1.0,
hp: 40,
armorPierce: 0.25,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'crystal',
},
tier: 3,
},
// Sand Golem - Sand mana variant
sandGolem: {
id: 'sandGolem',
name: 'Sand Golem',
description: 'A shifting construct of sand particles. Hits multiple enemies.',
baseManaType: 'sand',
summonCost: [elemCost('sand', 8), elemCost('earth', 3)],
maintenanceCost: [elemCost('sand', 0.5), elemCost('earth', 0.2)],
damage: 6,
attackSpeed: 2.0,
hp: 35,
armorPierce: 0.1,
isAoe: true,
aoeTargets: 2,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'sand',
},
tier: 2,
},
};
+139
View File
@@ -0,0 +1,139 @@
// ─── Advanced Hybrid Golems ────────────────────────────────────
// Require Enchanter 5 + Fabricator 5
import type { GolemDef } from './types';
import { elemCost } from './types';
export const HYBRID_GOLEMS: Record<string, GolemDef> = {
// Lava Golem - Fire + Earth fusion
lavaGolem: {
id: 'lavaGolem',
name: 'Lava Golem',
description: 'Molten earth and fire combined. Burns enemies over time.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 10), elemCost('fire', 8)],
maintenanceCost: [elemCost('earth', 0.4), elemCost('fire', 0.5)],
damage: 15,
attackSpeed: 1.0,
hp: 70,
armorPierce: 0.2,
isAoe: true,
aoeTargets: 2,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Galvanic Golem - Metal + Lightning fusion
galvanicGolem: {
id: 'galvanicGolem',
name: 'Galvanic Golem',
description: 'A conductive metal construct charged with lightning. Extremely fast attacks.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 8), elemCost('lightning', 6)],
maintenanceCost: [elemCost('metal', 0.3), elemCost('lightning', 0.6)],
damage: 10,
attackSpeed: 3.5,
hp: 45,
armorPierce: 0.45,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Obsidian Golem - Dark + Earth fusion
obsidianGolem: {
id: 'obsidianGolem',
name: 'Obsidian Golem',
description: 'Volcanic glass animated by shadow. Devastating single-target damage.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 12), elemCost('dark', 6)],
maintenanceCost: [elemCost('earth', 0.3), elemCost('dark', 0.4)],
damage: 25,
attackSpeed: 0.8,
hp: 55,
armorPierce: 0.5,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
// Prism Golem - Light + Crystal fusion
prismGolem: {
id: 'prismGolem',
name: 'Prism Golem',
description: 'A radiant crystal construct. Channels light into piercing beams.',
baseManaType: 'crystal',
summonCost: [elemCost('crystal', 10), elemCost('light', 6)],
maintenanceCost: [elemCost('crystal', 0.4), elemCost('light', 0.4)],
damage: 20,
attackSpeed: 1.5,
hp: 50,
armorPierce: 0.35,
isAoe: true,
aoeTargets: 3,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
// Quicksilver Golem - Water + Metal fusion
quicksilverGolem: {
id: 'quicksilverGolem',
name: 'Quicksilver Golem',
description: 'Liquid metal that flows around defenses. Fast and hard to dodge.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 6), elemCost('water', 6)],
maintenanceCost: [elemCost('metal', 0.3), elemCost('water', 0.3)],
damage: 8,
attackSpeed: 4.0,
hp: 40,
armorPierce: 0.3,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Voidstone Golem - Void + Earth fusion (ultimate)
voidstoneGolem: {
id: 'voidstoneGolem',
name: 'Voidstone Golem',
description: 'Earth infused with void energy. The ultimate golem construct.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 15), elemCost('void', 8)],
maintenanceCost: [elemCost('earth', 0.3), elemCost('void', 0.6)],
damage: 40,
attackSpeed: 0.6,
hp: 100,
armorPierce: 0.6,
isAoe: true,
aoeTargets: 3,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
};
+23
View File
@@ -0,0 +1,23 @@
// ─── Golem Definitions Index ─────────────────────────────────
// Re-exports from all golem modules
// Re-export types
export type { GolemDef, GolemManaCost } from './types';
// Re-export data
export { GOLEMS_DEF } from './data';
// Re-export utility functions
export {
getGolemSlots,
isGolemUnlocked,
getUnlockedGolems,
getGolemDamage,
getGolemAttackSpeed,
getGolemFloorDuration,
getGolemMaintenanceMultiplier,
canAffordGolemSummon,
deductGolemSummonCost,
canAffordGolemMaintenance,
deductGolemMaintenance,
} from './utils';
+42
View File
@@ -0,0 +1,42 @@
// ─── Golem Types ─────────────────────────────────────────────────
import type { SpellCost } from '../types';
// Golem mana cost helper
export function elemCost(element: string, amount: number): SpellCost {
return { type: 'element', element, amount };
}
export function rawCost(amount: number): SpellCost {
return { type: 'raw', amount };
}
export interface GolemManaCost {
type: 'raw' | 'element';
element?: string;
amount: number;
}
export interface GolemDef {
id: string;
name: string;
description: string;
baseManaType: string; // The primary mana type this golem uses
summonCost: GolemManaCost[]; // Cost to summon (can be multiple types)
maintenanceCost: GolemManaCost[]; // Cost per hour to maintain
damage: number; // Base damage per attack
attackSpeed: number; // Attacks per hour
hp: number; // Golem HP (for display, they don't take damage)
armorPierce: number; // Armor piercing (0-1)
isAoe: boolean; // Whether golem attacks are AOE
aoeTargets: number; // Number of targets for AOE
unlockCondition: {
type: 'attunement_level' | 'mana_unlocked' | 'dual_attunement';
attunement?: string;
level?: number;
manaType?: string;
attunements?: string[];
levels?: number[];
};
tier: number; // Power tier (1-4)
}
+204
View File
@@ -0,0 +1,204 @@
// ─── Golem Helper Functions ─────────────────────────
import type { GolemDef, GolemManaCost } from './types';
import { GOLEMS_DEF } from './index';
// Get golem slots based on Fabricator attunement level
// Level 2 = 1, Level 4 = 2, Level 6 = 3, Level 8 = 4, Level 10 = 5
export function getGolemSlots(fabricatorLevel: number): number {
if (fabricatorLevel < 2) return 0;
return Math.floor(fabricatorLevel / 2);
}
// Check if a golem is unlocked based on player state
export function isGolemUnlocked(
golemId: string,
attunements: Record<string, { active: boolean; level: number }>,
unlockedElements: string[]
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
const condition = golem.unlockCondition;
switch (condition.type) {
case 'attunement_level':
const attState = attunements[condition.attunement || ''];
return attState?.active && (attState.level || 1) >= (condition.level || 1);
case 'mana_unlocked':
return unlockedElements.includes(condition.manaType || '');
case 'dual_attunement':
if (!condition.attunements || !condition.levels) return false;
return condition.attunements.every((attId, idx) => {
const att = attunements[attId];
return att?.active && (att.level || 1) >= condition.levels![idx];
});
default:
return false;
}
}
// Get all unlocked golems for a player
export function getUnlockedGolems(
attunements: Record<string, { active: boolean; level: number }>,
unlockedElements: string[]
): GolemDef[] {
return Object.values(GOLEMS_DEF).filter(golem =>
isGolemUnlocked(golem.id, attunements, unlockedElements)
) as GolemDef[];
}
// Calculate golem damage with skill bonuses
export function getGolemDamage(
golemId: string,
skills: Record<string, number>
): number {
const golem = GOLEMS_DEF[golemId];
if (!golem) return 0;
let damage = golem.damage;
// Golem Mastery skill bonus
const masteryBonus = 1 + (skills.golemMastery || 0) * 0.1;
damage *= masteryBonus;
return damage;
}
// Calculate golem attack speed with skill bonuses
export function getGolemAttackSpeed(
golemId: string,
skills: Record<string, number>
): number {
const golem = GOLEMS_DEF[golemId];
if (!golem) return 0;
let speed = golem.attackSpeed;
// Golem Efficiency skill bonus
const efficiencyBonus = 1 + (skills.golemEfficiency || 0) * 0.05;
speed *= efficiencyBonus;
return speed;
}
// Get floors golems can last (base 1, +1 per Golem Longevity skill level)
export function getGolemFloorDuration(skills: Record<string, number>): number {
return 1 + (skills.golemLongevity || 0);
}
// Get maintenance cost multiplier (Golem Siphon reduces by 10% per level)
export function getGolemMaintenanceMultiplier(skills: Record<string, number>): number {
return 1 - (skills.golemSiphon || 0) * 0.1;
}
// Check if player can afford golem summon cost
export function canAffordGolemSummon(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
for (const cost of golem.summonCost) {
if (cost.type === 'raw') {
if (rawMana < cost.amount) return false;
} else if (cost.element) {
const elem = elements[cost.element];
if (!elem || !elem.unlocked || elem.current < cost.amount) return false;
}
}
return true;
}
// Deduct golem summon cost from mana pools
export function deductGolemSummonCost(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>
): { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> } {
const golem = GOLEMS_DEF[golemId];
if (!golem) return { rawMana, elements };
let newRawMana = rawMana;
let newElements = { ...elements };
for (const cost of golem.summonCost) {
if (cost.type === 'raw') {
newRawMana -= cost.amount;
} else if (cost.element && newElements[cost.element]) {
newElements = {
...newElements,
[cost.element]: {
...newElements[cost.element],
current: newElements[cost.element].current - cost.amount,
},
};
}
}
return { rawMana: newRawMana, elements: newElements };
}
// Check if player can afford golem maintenance for one tick
export function canAffordGolemMaintenance(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
skills: Record<string, number>
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
const maintenanceMult = getGolemMaintenanceMultiplier(skills);
for (const cost of golem.maintenanceCost) {
const adjustedAmount = cost.amount * maintenanceMult;
if (cost.type === 'raw') {
if (rawMana < adjustedAmount) return false;
} else if (cost.element) {
const elem = elements[cost.element];
if (!elem || !elem.unlocked || elem.current < adjustedAmount) return false;
}
}
return true;
}
// Deduct golem maintenance cost for one tick
export function deductGolemMaintenance(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
skills: Record<string, number>
): { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> } {
const golem = GOLEMS_DEF[golemId];
if (!golem) return { rawMana, elements };
const maintenanceMult = getGolemMaintenanceMultiplier(skills);
let newRawMana = rawMana;
let newElements = { ...elements };
for (const cost of golem.maintenanceCost) {
const adjustedAmount = cost.amount * maintenanceMult;
if (cost.type === 'raw') {
newRawMana -= adjustedAmount;
} else if (cost.element && newElements[cost.element]) {
newElements = {
...newElements,
[cost.element]: {
...newElements[cost.element],
current: newElements[cost.element].current - adjustedAmount,
},
};
}
}
return { rawMana: newRawMana, elements: newElements };
}