Source: commands/charOptions/abilityScores.js

'use strict';

const rl = require('../../readline');
const charDB = require('../../../data/db.json');
const chalk = require('chalk');

const invalid = require('./invalid.js');

/**
 * Prompts the user to choose between the default ability scores or rolling random scores using regular D&D rules.
 * Also calls the assign function with the correct array of scores.
 */
async function abilityScores() {
  return new Promise( async (resolve, reject) => {

    console.log(chalk.hex('#4298eb')('\nWe will now assign attribute scores...'));
    let defaultScores = [15, 14, 13, 12, 10, 8];

    let scoresArr = [roll4d6(), roll4d6(), roll4d6(), roll4d6(), roll4d6(), roll4d6()];

    // disclaimer about how randomly generated scores are created
    let generateRandomScoresStr = chalk.yellow('\nEach randomly generated score is created by "rolling" 4 d6, and adding the sum of the highest 3 rolls\n');

    let whichScores = await rl.ask(
      chalk.hex('#4298eb')('\nWould you like to use the default scores (15, 14, 13, 12, 10, 8)\nOr generate 6 random scores?\n') + generateRandomScoresStr,
      ['Default','Generate Random']
    );

    // input validation
    while(whichScores !== '1' && whichScores !== '2') {
      whichScores = rl.ask(chalk.red('That is not a valid option. Please try again.\n') + '- ');
    }

    let ability_scores;

    if (whichScores === '1') {
      ability_scores = await assign(defaultScores);
    } else {
      ability_scores = await assign(scoresArr);
    }


    resolve(ability_scores);
  })
}

/**
 * Ties ability score values to the newly created character object.
 * 
 * @param {*} scores - These are the aggregate scores determined through a series of prompts given to the user.
 */
async function assign(scores) {
  return new Promise( async (resolve, reject) => {
    let attrArr = ['STR', 'DEX', 'CON', 'INT', 'WIS', 'CHA'];

    let ability_scores = {
      str: '-',
      dex: '-',
      con: '-',
      int: '-',
      wis: '-',
      cha: '-',
    };

    console.log(`Here are your scores:`);
    scores.forEach(score => {
      console.log(score);
    });

    while(attrArr[0]) {
      let attrChoice = await rl.ask(
        chalk.hex('#4298eb')('\nWhich attribute would you like to assign?\n'),
        attrArr
      );

      while(invalid(attrChoice, attrArr)) {
        attrChoice = await rl.ask(chalk.red('\nThat attribute does not exist. Please try again.\n') + '- ');
      }

      let attr = attrArr[attrChoice - 1];

      let scoreChoice = await rl.ask(
        chalk.hex('#4298eb')('\nPlease select from the following scores:\n'),
        scores
      );

      while(invalid(scoreChoice, scores)) {
        scoreChoice = await rl.ask(chalk.red('\nInvalid select. Please try again.\n') + '- ');
      }

      let score = scores[scoreChoice - 1];

      ability_scores[attr.toLowerCase()] = score;

      attrArr.splice(attrChoice - 1, 1);
      scores.splice(scoreChoice - 1, 1);

      let scoreStr = '';
      console.log('\nCurrent scores:\n');
      let scoresToPrint = Object.entries(ability_scores);
      scoresToPrint.forEach((arr, index) => {
        scoreStr += `${arr[0].toUpperCase()}: ${arr[1]}`;
        if (index !== scoresToPrint.length - 1) scoreStr += ' | ';
      });
      console.log(scoreStr);
    }

    resolve(ability_scores);
  });
}

/**
 * Rolls 4 'd6' and returns the sum of the highest 3 rolls. This is the typical process used for creating ability scores in D&D.
 */
function roll4d6() {
  let arr = [];
  arr.push(Math.floor(Math.random() * 6) + 1);
  arr.push(Math.floor(Math.random() * 6) + 1);
  arr.push(Math.floor(Math.random() * 6) + 1);
  arr.push(Math.floor(Math.random() * 6) + 1);

  arr.sort((a, b) => {
    return b - a;
  });

  return arr[0] + arr[1] + arr[2];
}

module.exports = abilityScores;