UNPKG

@opendnd/genetica

Version:

This is a tool for using a simplified genetics system to generate inheritable traits for DnD characters.

128 lines (106 loc) 4.11 kB
const xlsx = require('node-xlsx'); const fs = require('fs'); const path = require('path'); const rootDir = path.join(__dirname, '..'); const libDir = path.join(rootDir, 'lib'); const scriptsDir = path.join(rootDir, 'scripts'); const defaults = require(path.join(libDir, 'defaults')); const searchWorksheets = ['general', 'eye-color', 'hair-general', 'hair-color', 'skin-general', 'skin-color', 'eye-shape', 'face-shape', 'face-nose', 'hair-facial', 'face-mouth', 'eye-brows', 'skin-aging', 'sex']; // Parse a file const race = process.argv[2] || 'Dragonborn'; const template = defaults.DNA[race]; const Xdice = template.sex.x.replace('d', ''); const Ydice = template.sex.y.replace('d', ''); const worksheets = xlsx.parse(path.join(scriptsDir, `${race}.xlsx`)); // generate genes let genes = {}; // generate all possible rolls for some dice const generatePossibleRolls = (diceA, diceB, gender) => { diceA = parseInt(diceA, 10); diceB = parseInt(diceB, 10); let rolls = []; // do dice A let a = 1; while (a <= diceA) { // do dice B let b = 1; while (b <= diceB) { if ((a === 1) && (b === 1)) break; // skip 1=1 as it makes 1 dominant impossible if (gender === 'female') { rolls.push(`X${a}=X${b}`); } else if (gender === 'male') { rolls.push(`X${a}=Y${b}`); } else { rolls.push(`${a}=${b}`); } b += 1; } a += 1; } return rolls; } // go through each worksheet worksheets.forEach((ws) => { let legendName = ws.name; if ((legendName === 'sex-male') || (legendName === 'sex-female')) legendName = 'sex'; if (searchWorksheets.includes(legendName)) { const DNA = defaults.DNA[race]; const chromosome = DNA.legend[legendName]; const data = ws.data.slice(5, ws.data.length); const dice = ws.data[1][1]; const templateDice = DNA.chromosomes[chromosome].replace('d', ''); if (dice === undefined) throw new Error('Dice not defined!'); // check dice if (legendName !== 'sex') { if (parseInt(dice, 10) !== parseInt(templateDice, 10)) throw new Error(`Dice is not defined to the correct amount for ${ws.name} it should be ${templateDice}!`); } if (ws.name === 'sex-male') { if (parseInt(dice, 10) !== parseInt(Ydice)) throw new Error(`Dice is not defined properly for sex-male it should be ${Ydice}!`); } if (ws.name === 'sex-female') { if (parseInt(dice, 10) !== parseInt(Xdice)) throw new Error(`Dice is not defined properly for sex-female it should be ${Xdice}!`); } // generate rolls let femaleRolls = generatePossibleRolls(Xdice, Xdice, 'female'); let maleRolls = generatePossibleRolls(Xdice, Ydice, 'male'); let rolls = generatePossibleRolls(dice, dice); // iterate on the data data.forEach((row) => { const trait = row[0]; const dominance = row[1]; const type = row[2]; if (trait === undefined) return; if (dominance === undefined) return; if (type === undefined) return; let gene = `C${chromosome}:`; // rare if (dominance < 1) { // handle rare differently for female, male and standard if (ws.name === 'sex-female') { const randomRoll = femaleRolls.sample(); gene += randomRoll; femaleRolls.splice(rolls.indexOf(randomRoll), 1); // remove from rolls } else if (ws.name === 'sex-male') { const randomRoll = maleRolls.sample(); gene += randomRoll; maleRolls.splice(rolls.indexOf(randomRoll), 1); // remove from rolls } else { const randomRoll = rolls.sample(); gene += randomRoll; rolls.splice(rolls.indexOf(randomRoll), 1); // remove from rolls } // common } else { // prepend the sex if (ws.name === 'sex-female') gene += 'XX'; if (ws.name === 'sex-male') gene += 'Y'; gene += dominance; } // common genes[`${legendName}:${gene}`] = trait; }); } else { throw new Error('Unknown worksheet found!'); } }); console.log(JSON.stringify(genes));