class Natural20::CharacterBuilder

Constants

ALL_LANGUAGES

Attributes

battle[R]
prompt[R]
session[R]

Public Class Methods

new(prompt, session, battle) click to toggle source
# File lib/natural_20/cli/character_builder.rb, line 13
def initialize(prompt, session, battle)
  @prompt = prompt
  @session = session
  @battle = battle
end

Public Instance Methods

build_character() click to toggle source
# File lib/natural_20/cli/character_builder.rb, line 19
def build_character
  @values = {
    hit_die: 'inherit',
    classes: {},
    ability: {},
    skills: [],
    level: 1,
    token: ['X'],
    tools: []
  }
  loop do
    ability_method = :random

    @values[:name] = prompt.ask(t('builder.enter_name'), default: @values[:name]) do |q|
      q.required true
      q.modify :capitalize
    end

    @values[:token] = [prompt.ask(t('builder.token'), default: @values[:name][0])]
    @values[:color] = prompt.select(t('builder.token_color')) do |q|
      %i[
        red light_red
        green light_green
        yellow light_yellow
        blue light_blue
        magenta light_magenta
        cyan light_cyan
        white light_white
      ].each do |color|
        q.choice @values[:token].first.colorize(color), color
      end
    end

    description = prompt.multiline(t('builder.description')) do |q|
      q.default t('builder.default_description')
    end

    @values[:description] = description.is_a?(Array) ? description.join("\n") : description

    races = session.load_races
    @values[:race] = prompt.select(t('builder.select_race')) do |q|
      races.each do |race, details|
        q.choice details[:label] || race.humanize, race
      end
    end

    race_detail = races[@values[:race]]
    if race_detail[:subrace]
      @values[:subrace] = prompt.select(t('builder.select_subrace')) do |q|
        race_detail[:subrace].each do |subrace, detail|
          q.choice detail[:label] || t("builder.races.#{subrace}"), subrace
        end
      end
    end
    subrace_detail = race_detail.dig(:subrace, @values[:subrace]&.to_sym)

    known_languages = race_detail.fetch(:languages, []) + (subrace_detail&.fetch(:languages, []) || [])
    language_choice = race_detail.fetch(:language_choice, 0) + (subrace_detail&.fetch(:language_choice, 0) || 0)
    if language_choice.positive?
      language_selector(ALL_LANGUAGES - known_languages, min: language_choice, max: language_choice)
    end

    race_bonus = race_detail[:attribute_bonus] || {}
    subrace_bonus = subrace_detail&.fetch(:attribute_bonus, {}) || {}

    attribute_bonuses = race_bonus.merge!(subrace_bonus)

    k = prompt.select(t('builder.class')) do |q|
      session.load_classes.each do |klass, details|
        q.choice details[:label] || klass.humanize, klass.to_sym
      end
    end

    @values[:classes][k.to_sym] = 1
    @class_properties = session.load_class(k)

    if race_detail[:tool_proficiencies_choice]
      num_tools_choices = race_detail[:tool_proficiencies_choice]
      @values[:tools] = prompt.multi_select(t('builder.select_tools_proficiency'), min: num_tools_choices, max: num_tools_choices) do |q|
        race_detail[:tool_proficiencies].each do |prof|
          q.choice t("builder.tools.#{prof}"), prof
        end
      end
    end

    ability_method = prompt.select(t('builder.ability_score_method')) do |q|
      q.choice t('builder.ability_score.random'), :random
      q.choice t('builder.ability_score.fixed'), :fixed
      # q.choice t('builder.ability_score.point_buy'), :point_buy
    end

    ability_scores = if ability_method == :random
                       6.times.map do |index|
                         r = 4.times.map do |_x|
                           die_roll = Natural20::DieRoll.roll('1d6', battle: battle,
                                                                     description: t('dice_roll.ability_score', roll_num: index + 1))
                           die_roll.result
                         end.sort.reverse
                         puts "#{index + 1}. #{r.join(',')}"

                         r.take(3).sum
                       end.sort.reverse
                     elsif ability_method == :fixed
                       [15, 14, 13, 12, 10, 8]
                     end

    puts t('builder.assign_ability_scores', scores: ability_scores.join(','))

    chosen_score = []

    Natural20::Entity::ATTRIBUTE_TYPES_ABBV.each do |type|
      bonus = attribute_bonuses[type.to_sym] || 0
      ability_choice_str = t("builder.#{type}")
      ability_choice_str += " (+#{bonus})" if bonus.positive?
      score_index = prompt.select(ability_choice_str) do |q|
        ability_scores.each_with_index do |score, index|
          next if chosen_score.include?(index)

          q.choice score, index
        end
      end

      chosen_score << score_index
      @values[:ability][type.to_sym] = ability_scores[score_index] + bonus
    end

    class_skills_selector

    send(:"#{k}_builder", @values)

    @values.merge!(@class_values)
    @pc = Natural20::PlayerCharacter.new(session, @values)
    character_sheet(@pc)
    break if prompt.yes?(t('builder.review'))
  end

  session.save_character(@values[:name], @values)

  @pc
end

Protected Instance Methods

class_skills_selector() click to toggle source
# File lib/natural_20/cli/character_builder.rb, line 187
def class_skills_selector
  class_skills = @class_properties[:available_skills]
  num_choices = @class_properties[:available_skills_choices]
  @values[:skills] += prompt.multi_select(t("builder.#{@values[:classes].keys.first}.select_skill"),
                                          min: num_choices, max: num_choices, per_page: 20) do |q|
    class_skills.each do |skill|
      q.choice t("builder.skill.#{skill}"), skill
    end
  end
end
language_selector(languages = ALL_LANGUAGES, min: 1, max: 1) click to toggle source
# File lib/natural_20/cli/character_builder.rb, line 179
def language_selector(languages = ALL_LANGUAGES, min: 1, max: 1)
  @values[:languages] = prompt.multi_select(t('builder.select_languages'), min: min, max: max, per_page: 20) do |q|
    languages.each do |lang|
      q.choice t("language.#{lang}"), lang
    end
  end
end
modifier_table(value) click to toggle source
# File lib/natural_20/cli/character_builder.rb, line 198
def modifier_table(value)
  mod_table = [[1, 1, -5],
               [2, 3, -4],
               [4, 5, -3],
               [6, 7, -2],
               [8, 9, -1],
               [10, 11, 0],
               [12, 13, 1],
               [14, 15, 2],
               [16, 17, 3],
               [18, 19, 4],
               [20, 21, 5],
               [22, 23, 6],
               [24, 25, 7],
               [26, 27, 8],
               [28, 29, 9],
               [30, 30, 10]]

  mod_table.each do |row|
    low, high, mod = row
    return mod if value.between?(low, high)
  end
end