czuger/dd-next-encounters

View on GitHub
lib/encounters/lairs.rb

Summary

Maintainability
A
1 hr
Test Coverage
require_relative '../data/lairs_data'
require_relative 'encounters'
require_relative '../data/xp_difficulty_table'

class Lairs
  include LairsData
  include XpDifficultyTable
  AVAILABLE_ENCOUNTER_LEVEL = REVERSED_XP_DIFFICULTY_TABLE.keys

  MIN_PARTY_LEVEL_MUL = 0.4

  attr_reader :lair_type

  # encounter_level : :easy, :medium, :hard, :deadly
  def initialize( encounter_level, hero_levels, lair_type = nil)

    @encounters = Encounters.new
    @encounter_level = encounter_level
    @hero_levels = hero_levels
    check_params

    @party_xp_level = hero_levels.map{ |hl| XP_DIFFICULTY_TABLE[hl][@encounter_level] }.reduce(&:+)

    @lair_type = lair_type ? lair_type : get_available_lairs.sample
  end

  def encounter
    encounter_id = get_available_encounters.sample
    @encounters.by_id encounter_id
  end

  def to_hash
    { encounter_level: @encounter_level, hero_levels: @hero_levels, lair_type: @lair_type }
  end

  def self.from_hash( hash )
    hash = hash.map { |k, v| [k.to_sym, v] }.to_h
    Lairs.new( hash[ :encounter_level ].to_sym, hash[ :hero_levels ], hash[ :lair_type ].to_sym )
  end

  private

  def get_available_lairs
    LAIRS_DATA[:by_xp_lair].select{ |k, _| k >= @party_xp_level*MIN_PARTY_LEVEL_MUL && k <= @party_xp_level }.values.flatten.uniq
  end

  def get_available_encounters
    LAIRS_DATA[:lairs][@lair_type][:by_encounters_xp].select{ |k, _| k >= @party_xp_level*MIN_PARTY_LEVEL_MUL && k <= @party_xp_level }.values.flatten.uniq
  end

  def check_params
    raise 'Empty party is not valid. Please provide at least one hero' if @hero_levels.empty?

    raise "Bad encounter level : #{@encounter_level.inspect}. Available encounter level : #{AVAILABLE_ENCOUNTER_LEVEL.inspect}" unless AVAILABLE_ENCOUNTER_LEVEL.include?( @encounter_level )
    raise 'Party too weak. Minimum 3 members' if @hero_levels.count < 3

    @hero_levels.each do |level|
      raise "Hero level should be an integer currently : #{level.class.to_s}" unless level.class == Integer
      raise "Bad hero level : #{level}. Should be between 1 .. 20" if level < 1 || level > 20
    end
  end

end