#!/usr/bin/env node 'use strict'; const fs = require('fs'); const path = require('path'); const { DUNGEONS } = require('./src/data/dungeons'); const themeColors = { stone: { body: '#696969', eye: '#FFD700', accent: '#A9A9A9' }, forest: { body: '#228B22', eye: '#90EE90', accent: '#006400' }, desert: { body: '#DAA520', eye: '#8B4513', accent: '#FFD700' }, mountain: { body: '#4682B4', eye: '#E0E0E0', accent: '#87CEEB' }, underground: { body: '#4B0082', eye: '#DA70D6', accent: '#9400D3' }, ocean: { body: '#006994', eye: '#00CED1', accent: '#4682B4' }, sky: { body: '#FFD700', eye: '#FFFACD', accent: '#FF8C00' }, shadow: { body: '#1A0A2A', eye: '#9400D3', accent: '#4B0082' }, final: { body: '#8B0000', eye: '#FFD700', accent: '#FF4500' }, }; const templateAssignments = { 0: 'gleeok', 11: 'gleeok', 22: 'gleeok', 33: 'gleeok', 44: 'gleeok', 55: 'gleeok', 66: 'gleeok', 77: 'gleeok', 88: 'gleeok', 99: 'gleeok', 1: 'darknut', 10: 'darknut', 21: 'darknut', 32: 'darknut', 43: 'darknut', 54: 'darknut', 65: 'darknut', 76: 'darknut', 87: 'darknut', 98: 'darknut', 2: 'wizzrobe', 12: 'wizzrobe', 23: 'wizzrobe', 34: 'wizzrobe', 45: 'wizzrobe', 56: 'wizzrobe', 67: 'wizzrobe', 78: 'wizzrobe', 89: 'wizzrobe', 97: 'wizzrobe', 3: 'moldorm', 13: 'moldorm', 24: 'moldorm', 35: 'moldorm', 46: 'moldorm', 57: 'moldorm', 68: 'moldorm', 79: 'moldorm', 90: 'moldorm', 96: 'moldorm', 4: 'genie', 14: 'genie', 25: 'genie', 36: 'genie', 47: 'genie', 58: 'genie', 69: 'genie', 80: 'genie', 91: 'genie', 95: 'genie', 5: 'liklike', 15: 'liklike', 26: 'liklike', 37: 'liklike', 48: 'liklike', 59: 'liklike', 70: 'liklike', 81: 'liklike', 92: 'liklike', 94: 'liklike', 6: 'aquamentus', 16: 'aquamentus', 27: 'aquamentus', 38: 'aquamentus', 49: 'aquamentus', 60: 'aquamentus', 71: 'aquamentus', 82: 'aquamentus', 93: 'aquamentus', 7: 'manhandla', 17: 'manhandla', 28: 'manhandla', 39: 'manhandla', 50: 'manhandla', 61: 'manhandla', 72: 'manhandla', 83: 'manhandla', 8: 'gleeok_variant', 18: 'gleeok_variant', 29: 'gleeok_variant', 40: 'gleeok_variant', 51: 'gleeok_variant', 62: 'gleeok_variant', 73: 'gleeok_variant', 84: 'gleeok_variant', 9: 'agahnim', 19: 'agahnim', 30: 'agahnim', 41: 'agahnim', 52: 'agahnim', 63: 'agahnim', 74: 'agahnim', 85: 'agahnim', // Fill remaining gaps not covered by the mod-11 pattern 20: 'genie', 31: 'liklike', 42: 'moldorm', 53: 'wizzrobe', 64: 'darknut', 75: 'gleeok', 86: 'moldorm', }; // Verify all 100 indices covered for (let i = 0; i < 100; i++) { if (!templateAssignments[i]) { console.error('ERROR: No template for index ' + i); process.exit(1); } } const nameTemplates = { gleeok: { stone: 'Stone Gleeok', forest: 'Verdant Gleeok', desert: 'Sand Gleeok', mountain: 'Frost Gleeok', underground: 'Shadow Gleeok', ocean: 'Tidal Gleeok', sky: 'Storm Gleeok', shadow: 'Dark Gleeok', final: 'Infernal Gleeok', }, darknut: { stone: 'Stone Darknut', forest: 'Green Darknut', desert: 'Sand Darknut', mountain: 'Iron Darknut', underground: 'Deep Darknut', ocean: 'Abyssal Darknut', sky: 'Sky Darknut', shadow: 'Shadow Darknut', final: 'Demon Darknut', }, wizzrobe: { stone: 'Stone Wizzrobe', forest: 'Thorn Wizzrobe', desert: 'Mirage Wizzrobe', mountain: 'Frost Wizzrobe', underground: 'Crystal Wizzrobe', ocean: 'Tide Wizzrobe', sky: 'Storm Wizzrobe', shadow: 'Void Wizzrobe', final: 'Dark Wizzrobe', }, moldorm: { stone: 'Stone Moldorm', forest: 'Root Moldorm', desert: 'Dune Moldorm', mountain: 'Frost Moldorm', underground: 'Deep Moldorm', ocean: 'Abyssal Moldorm', sky: 'Cloud Moldorm', shadow: 'Shadow Moldorm', final: 'Abyssal Moldorm', }, genie: { stone: 'Stone Genie', forest: 'Moss Genie', desert: 'Sand Genie', mountain: 'Ice Genie', underground: 'Crystal Genie', ocean: 'Tidal Genie', sky: 'Sky Genie', shadow: 'Dark Genie', final: 'Demon Genie', }, liklike: { stone: 'Stone Like Like', forest: 'Moss Like Like', desert: 'Dune Like Like', mountain: 'Frost Like Like', underground: 'Deep Like Like', ocean: 'Abyssal Like Like', sky: 'Cloud Like Like', shadow: 'Shadow Like Like', final: 'Abyssal Like Like', }, aquamentus: { stone: 'Stone Aquamentus', forest: 'Verdant Aquamentus', desert: 'Sand Aquamentus', mountain: 'Frost Aquamentus', underground: 'Crystal Aquamentus', ocean: 'Tidal Aquamentus', sky: 'Storm Aquamentus', shadow: 'Dark Aquamentus', final: 'Infernal Aquamentus', }, manhandla: { stone: 'Stone Manhandla', forest: 'Verdant Manhandla', desert: 'Dune Manhandla', mountain: 'Frost Manhandla', underground: 'Crystal Manhandla', ocean: 'Abyssal Manhandla', sky: 'Storm Manhandla', shadow: 'Dark Manhandla', final: 'Infernal Manhandla', }, gleeok_variant: { stone: 'Stone Ice Gleeok', forest: 'Forest Ice Gleeok', desert: 'Desert Ice Gleeok', mountain: 'Glacier Gleeok', underground: 'Shadow Ice Gleeok', ocean: 'Abyssal Water Gleeok', sky: 'Sky Ice Gleeok', shadow: 'Dark Ice Gleeok', final: 'Infernal Ice Gleeok', }, agahnim: { stone: 'Stone Agahnim', forest: 'Verdant Agahnim', desert: 'Sand Agahnim', mountain: 'Frost Agahnim', underground: 'Crystal Agahnim', ocean: 'Tidal Agahnim', sky: 'Storm Agahnim', shadow: 'Void Agahnim', final: 'Dark Agahnim', }, }; function getStatsByDifficulty(diff) { if (diff <= 2) return { hp: 20 + (diff - 1) * 10, damage: 3 + (diff - 1), defense: diff - 1 }; if (diff <= 4) return { hp: 40 + (diff - 3) * 20, damage: 4 + (diff - 3), defense: Math.min(diff - 2, 2) }; if (diff <= 6) return { hp: 80 + (diff - 5) * 35, damage: 5 + (diff - 5), defense: Math.min(diff - 4, 3) }; if (diff <= 8) return { hp: 150 + (diff - 7) * 50, damage: 6 + (diff - 7) * 2, defense: Math.min(diff - 5, 4) }; return { hp: 250 + (diff - 9) * 250, damage: 8 + (diff - 9) * 7, defense: Math.min(diff - 6, 5) }; } function generatePhases(template, diff, baseDamage) { const phases = []; const scaledDmg = Math.round(baseDamage * 1.3); switch (template) { case 'gleeok': phases.push({ hpThreshold: 100, attacks: [ { type: 'aoe', damage: scaledDmg, cooldown: 2000, count: 2, spreadAngle: 360, projectileSpeed: 2 }, { type: 'melee', damage: baseDamage, cooldown: 1500, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); if (diff >= 4) { phases.push({ hpThreshold: 60, attacks: [ { type: 'aoe', damage: scaledDmg + 1, cooldown: 1800, count: 3, spreadAngle: 360, projectileSpeed: 2.5 }, { type: 'melee', damage: baseDamage + 1, cooldown: 1200, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); } if (diff >= 7) { phases.push({ hpThreshold: 30, attacks: [ { type: 'aoe', damage: scaledDmg + 2, cooldown: 1200, count: 4, spreadAngle: 360, projectileSpeed: 3 }, { type: 'melee', damage: baseDamage + 2, cooldown: 1000, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); } break; case 'gleeok_variant': phases.push({ hpThreshold: 100, attacks: [ { type: 'aoe', damage: scaledDmg, cooldown: 2200, count: 2, spreadAngle: 360, projectileSpeed: 1.5 }, { type: 'melee', damage: baseDamage, cooldown: 1800, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); if (diff >= 4) { phases.push({ hpThreshold: 60, attacks: [ { type: 'aoe', damage: scaledDmg + 1, cooldown: 2000, count: 3, spreadAngle: 360, projectileSpeed: 2 }, { type: 'melee', damage: baseDamage + 1, cooldown: 1500, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); } if (diff >= 7) { phases.push({ hpThreshold: 30, attacks: [ { type: 'aoe', damage: scaledDmg + 2, cooldown: 1400, count: 4, spreadAngle: 360, projectileSpeed: 2.5 }, { type: 'melee', damage: baseDamage + 2, cooldown: 1100, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); } break; case 'darknut': phases.push({ hpThreshold: 100, attacks: [ { type: 'melee', damage: baseDamage, cooldown: 1000, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); phases.push({ hpThreshold: 50, attacks: [ { type: 'melee', damage: scaledDmg, cooldown: 800, count: 1, spreadAngle: 0, projectileSpeed: 0 }, { type: 'melee', damage: scaledDmg, cooldown: 1500, count: 3, spreadAngle: 120, projectileSpeed: 0 }, ], }); if (diff >= 6) { phases.push({ hpThreshold: 25, attacks: [ { type: 'melee', damage: scaledDmg + 2, cooldown: 600, count: 1, spreadAngle: 0, projectileSpeed: 0 }, { type: 'aoe', damage: baseDamage, cooldown: 2000, count: 4, spreadAngle: 180, projectileSpeed: 0 }, ], }); } break; case 'wizzrobe': phases.push({ hpThreshold: 100, attacks: [ { type: 'projectile', damage: scaledDmg, cooldown: 1500, count: 2, spreadAngle: 60, projectileSpeed: 3 }, ], }); if (diff >= 3) { phases.push({ hpThreshold: 40, attacks: [ { type: 'projectile', damage: scaledDmg + 1, cooldown: 1200, count: 3, spreadAngle: 90, projectileSpeed: 3.5 }, { type: 'summon', damage: 0, cooldown: 4000, count: 2, spreadAngle: 0, projectileSpeed: 0, enemyType: diff < 6 ? 'keese' : 'stalfos' }, ], }); } break; case 'moldorm': phases.push({ hpThreshold: 100, attacks: [ { type: 'melee', damage: baseDamage, cooldown: 2000, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); phases.push({ hpThreshold: 30, attacks: [ { type: 'aoe', damage: scaledDmg, cooldown: 3000, count: 1, spreadAngle: 360, projectileSpeed: 0 }, { type: 'melee', damage: scaledDmg, cooldown: 800, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); break; case 'genie': phases.push({ hpThreshold: 100, attacks: [ { type: 'projectile', damage: scaledDmg, cooldown: 1500, count: 1, spreadAngle: 0, projectileSpeed: 2.5 }, ], }); if (diff >= 3) { phases.push({ hpThreshold: 50, attacks: [ { type: 'projectile', damage: scaledDmg, cooldown: 1200, count: 2, spreadAngle: 90, projectileSpeed: 2.5 }, ], }); } if (diff >= 6) { phases.push({ hpThreshold: 20, attacks: [ { type: 'aoe', damage: scaledDmg + 1, cooldown: 1000, count: 3, spreadAngle: 120, projectileSpeed: 3 }, { type: 'projectile', damage: scaledDmg, cooldown: 800, count: 2, spreadAngle: 45, projectileSpeed: 3.5 }, ], }); } break; case 'liklike': phases.push({ hpThreshold: 100, attacks: [ { type: 'melee', damage: baseDamage, cooldown: 2000, count: 1, spreadAngle: 0, projectileSpeed: 0 }, ], }); if (diff >= 3) { phases.push({ hpThreshold: 40, attacks: [ { type: 'melee', damage: scaledDmg, cooldown: 1500, count: 1, spreadAngle: 0, projectileSpeed: 0 }, { type: 'summon', damage: 0, cooldown: 5000, count: 2, spreadAngle: 0, projectileSpeed: 0, enemyType: 'slime' }, ], }); } break; case 'aquamentus': phases.push({ hpThreshold: 100, attacks: [ { type: 'projectile', damage: scaledDmg, cooldown: 2000, count: 1, spreadAngle: 0, projectileSpeed: 2 }, ], }); phases.push({ hpThreshold: 50, attacks: [ { type: 'aoe', damage: scaledDmg, cooldown: 1800, count: 3, spreadAngle: 120, projectileSpeed: 2.5 }, ], }); if (diff >= 6) { phases.push({ hpThreshold: 20, attacks: [ { type: 'aoe', damage: scaledDmg + 2, cooldown: 1200, count: 3, spreadAngle: 180, projectileSpeed: 3 }, ], }); } break; case 'manhandla': phases.push({ hpThreshold: 100, attacks: [ { type: 'melee', damage: baseDamage, cooldown: 1200, count: 4, spreadAngle: 360, projectileSpeed: 0 }, ], }); if (diff >= 3) { phases.push({ hpThreshold: 30, attacks: [ { type: 'aoe', damage: scaledDmg, cooldown: 2000, count: 4, spreadAngle: 360, projectileSpeed: 2 }, { type: 'melee', damage: scaledDmg, cooldown: 800, count: 4, spreadAngle: 360, projectileSpeed: 0 }, ], }); } break; case 'agahnim': phases.push({ hpThreshold: 100, attacks: [ { type: 'projectile', damage: scaledDmg, cooldown: 1500, count: 3, spreadAngle: 90, projectileSpeed: 2.5 }, ], }); phases.push({ hpThreshold: 60, attacks: [ { type: 'melee', damage: scaledDmg, cooldown: 1000, count: 1, spreadAngle: 0, projectileSpeed: 0 }, { type: 'projectile', damage: scaledDmg, cooldown: 1200, count: 3, spreadAngle: 90, projectileSpeed: 2.5 }, ], }); phases.push({ hpThreshold: 30, attacks: [ { type: 'projectile', damage: scaledDmg, cooldown: 1500, count: 3, spreadAngle: 90, projectileSpeed: 2.5 }, ], }); phases.push({ hpThreshold: 10, attacks: [ { type: 'melee', damage: scaledDmg + 2, cooldown: 800, count: 1, spreadAngle: 0, projectileSpeed: 0 }, { type: 'aoe', damage: scaledDmg, cooldown: 1500, count: 4, spreadAngle: 180, projectileSpeed: 3 }, ], }); break; } return phases; } function generateDrops(template, diff) { const drops = [{ item: 'heart_piece', weight: 100 }]; if (diff >= 2) drops.push({ item: 'healing_potion', weight: 30 }); if (diff >= 4) drops.push({ item: 'super_potion', weight: 15 }); if (diff >= 6) drops.push({ item: 'magic_potion', weight: 10 }); if (diff >= 8) drops.push({ item: 'heart_piece', weight: 20 }); switch (template) { case 'gleeok': case 'gleeok_variant': if (diff >= 5) drops.push({ item: 'fire_rod', weight: 5 }); if (diff >= 8) drops.push({ item: 'master_sword', weight: 3 }); break; case 'darknut': if (diff >= 3) drops.push({ item: 'hammer', weight: 8 }); if (diff >= 7) drops.push({ item: 'magic_sword', weight: 3 }); break; case 'wizzrobe': if (diff >= 4) drops.push({ item: 'ice_rod', weight: 5 }); if (diff >= 7) drops.push({ item: 'magic_potion', weight: 15 }); break; case 'agahnim': if (diff >= 6) drops.push({ item: 'magic_sword', weight: 5 }); break; case 'aquamentus': if (diff >= 5) drops.push({ item: 'fire_rod', weight: 5 }); break; case 'manhandla': if (diff >= 4) drops.push({ item: 'boomerang', weight: 5 }); break; case 'moldorm': if (diff >= 6) drops.push({ item: 'hookshot', weight: 3 }); break; case 'genie': if (diff >= 5) drops.push({ item: 'magic_crystal', weight: 10 }); break; case 'liklike': if (diff >= 3) drops.push({ item: 'super_potion', weight: 20 }); break; } return drops; } function generateBosses() { const bosses = []; const descriptions = { gleeok: 'A multi-headed dragon whose fiery breath devastates all.', darknut: 'A heavily-armored knight wielding a massive sword.', wizzrobe: 'A teleporting mage who commands destructive magic.', moldorm: 'A giant segmented worm that charges relentlessly.', genie: 'A lamp spirit that unleashes devastating elemental blasts.', liklike: 'A voracious worm that steals hearts and shields.', aquamentus: 'A dragon that breathes flames at everything in sight.', manhandla: 'A spinning plant monster with razor-sharp limbs.', gleeok_variant: 'A spectral dragon wielding ice and shadow.', agahnim: 'A dark mage protected by impenetrable barriers.', }; for (let i = 0; i < 100; i++) { const dungeon = DUNGEONS[i]; const template = templateAssignments[i]; const theme = dungeon.theme; const diff = dungeon.difficulty; const stats = getStatsByDifficulty(diff); const colors = themeColors[theme]; let hp = stats.hp; let damage = stats.damage; let defense = stats.defense; let speed = 0; let behavior = 'chase'; let drawFunction = 'drawGeneric'; switch (template) { case 'gleeok': case 'gleeok_variant': hp = Math.round(hp * 1.3); speed = 1.5; behavior = 'charge'; drawFunction = 'drawGleeok'; break; case 'darknut': defense = Math.min(defense + 1, 5); speed = 1.2; behavior = 'chase'; drawFunction = 'drawDarknut'; break; case 'wizzrobe': damage = Math.round(damage * 0.8); defense = Math.max(defense - 1, 0); speed = 0; behavior = 'teleport'; drawFunction = 'drawWizzrobe'; break; case 'moldorm': hp = Math.round(hp * 0.7); speed = 2.0; behavior = 'charge'; break; case 'genie': hp = Math.round(hp * 1.1); speed = 0; behavior = 'stationary'; break; case 'liklike': hp = Math.round(hp * 0.8); speed = 1.0; behavior = 'chase'; break; case 'aquamentus': hp = Math.round(hp * 1.2); speed = 0; behavior = 'stationary'; drawFunction = 'drawGleeok'; break; case 'manhandla': speed = 1.8; behavior = 'charge'; break; case 'agahnim': damage = Math.round(damage * 1.2); defense = Math.min(defense + 1, 5); speed = 0; behavior = 'stationary'; drawFunction = 'drawWizzrobe'; break; } const name = nameTemplates[template] ? nameTemplates[template][theme] : (theme + ' ' + template); const phases = generatePhases(template, diff, damage); const drops = generateDrops(template, diff); bosses.push({ id: i, name, hp, damage, defense, speed, colors, behavior, drawFunction, phases, drops, description: descriptions[template], }); } return bosses; } const bosses = generateBosses(); let output = "'use strict';\n\nconst BOSS_TYPES = [\n"; for (const boss of bosses) { output += ' { id: ' + boss.id + ', '; output += "name: '" + boss.name + "', "; output += 'hp: ' + boss.hp + ', '; output += 'damage: ' + boss.damage + ', '; output += 'defense: ' + boss.defense + ', '; output += 'speed: ' + boss.speed + ', '; output += 'colors: { body: "' + boss.colors.body + '", eye: "' + boss.colors.eye + '", accent: "' + boss.colors.accent + '" }, '; output += 'behavior: "' + boss.behavior + '", '; output += 'drawFunction: "' + boss.drawFunction + '", '; output += 'description: "' + boss.description + '", '; output += 'phases: ['; for (let p = 0; p < boss.phases.length; p++) { const phase = boss.phases[p]; output += '{ hpThreshold: ' + phase.hpThreshold + ', attacks: ['; for (let a = 0; a < phase.attacks.length; a++) { const attack = phase.attacks[a]; output += '{ type: "' + attack.type + '", damage: ' + attack.damage + ', cooldown: ' + attack.cooldown + ', count: ' + attack.count + ', spreadAngle: ' + attack.spreadAngle + ', projectileSpeed: ' + attack.projectileSpeed; if (attack.enemyType) output += ', enemyType: "' + attack.enemyType + '"'; output += '}'; if (a < phase.attacks.length - 1) output += ', '; } output += ']}'; if (p < boss.phases.length - 1) output += ', '; } output += '], '; output += 'drops: ['; for (let d = 0; d < boss.drops.length; d++) { const drop = boss.drops[d]; output += '{ item: "' + drop.item + '", weight: ' + drop.weight + ' }'; if (d < boss.drops.length - 1) output += ', '; } output += ']'; output += ' },\n'; } output += '];\n\n'; output += 'function getBossType(id) {\n'; output += ' return BOSS_TYPES.find(b => b.id === id);\n'; output += '}\n\n'; output += 'module.exports = { BOSS_TYPES, getBossType };\n'; fs.writeFileSync(path.join(__dirname, 'src/data/bosses.js'), output); console.log('Generated ' + bosses.length + ' bosses successfully.'); const { BOSS_TYPES } = require('./src/data/bosses'); console.log('Verification: ' + BOSS_TYPES.length + ' bosses loaded.');