bcdice/BCDice

View on GitHub
lib/bcdice/game_system/one_way_heroics/random_event_table.rb

Summary

Maintainability
A
20 mins
Test Coverage
B
87%
# frozen_string_literal: true

module BCDice
  module GameSystem
    class OneWayHeroics < Base
      class RandomEventTable
        def initialize(name, type, items)
          @name = name
          @items = items.freeze

          m = /(\d+)D(\d+)/i.match(type)
          unless m
            raise ArgumentError, "Unexpected table type: #{type}"
          end

          @times = m[1].to_i
          @sides = m[2].to_i
        end

        def roll_with_day(day, randomizer)
          value = randomizer.roll_sum(@times, @sides)
          index = value - 1

          chosen = @items[index]
          chosen =
            if chosen.respond_to?(:roll)
              chosen.roll(randomizer)
            elsif chosen.respond_to?(:roll_with_day)
              chosen.roll_with_day(day, randomizer)
            else
              chosen
            end

          return "#{@name}(#{value}) > #{chosen}"
        end
      end

      class BranchByDay
        def initialize(text, less_than_equal, greater)
          @text = text
          @greater = greater
          @less_than_equal = less_than_equal
        end

        def roll_with_day(day, randomizer)
          value = randomizer.roll_once(6)
          chosen = choice(value, day)

          chosen =
            if chosen.respond_to?(:roll_with_day)
              "#{chosen.key}#{day} > #{chosen.roll_with_day(day, randomizer)}"
            elsif chosen.ascii_only?
              [chosen, TABLES[chosen].roll(randomizer)].join(" > ")
            else
              chosen
            end

          result = <<~RESULT.chomp
            #{@text} >
             1D6 > #{value} > #{branch_result(value, day)} >
             #{chosen}
          RESULT
          return result
        end

        def choice(value, day)
          raise NotImplementedError
        end

        def branch_result(value, day)
          raise NotImplementedError
        end
      end

      class BranchByElapsedDays < BranchByDay
        def choice(value, day)
          value > day ? @greater : @less_than_equal
        end

        def branch_result(value, day)
          if value > day
            "日数[#{day}]を超えている"
          else
            "日数[#{day}]以下"
          end
        end
      end

      class BranchByDayParity < BranchByDay
        def choice(value, _)
          value.odd? ? @greater : @less_than_equal
        end

        def branch_result(value, _)
          if value.odd?
            "奇数"
          else
            "偶数"
          end
        end
      end

      class MoveToTableWithDay
        def initialize(text, table)
          @text = text
          @table = table
        end

        def roll_with_day(day, randomizer)
          <<~RESULT.chomp
            #{@text} >
             #{@table.key}#{day} > #{@table.roll_with_day(day, randomizer)}
          RESULT
        end
      end

      RANDOM_EVENT_TABLE = RandomEventTable.new(
        "ランダムイベント表",
        "1D6",
        [
          BranchByElapsedDays.new(
            "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら「施設表」へ移動。【日数】を超えていれば「ダンジョン表」(153ページ)へ移動。",
            "FCLT",
            DUNGEON_TABLE
          ),
          BranchByElapsedDays.new(
            "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら「世界の旅表」(157ページ)へ移動。【日数】を超えていれば「野外遭遇表(OUTENC)」(155ページ)へ移動。",
            "「世界の旅表」(157ページ)へ。",
            "OUTENC"
          ),
          MoveToTable.new("「施設表」へ移動。", "FCLT"),
          "「世界の旅表」(157ページ)へ移動。",
          MoveToTable.new("「野外遭遇表」(155ページ)へ移動。", "OUTENC"),
          MoveToTableWithDay.new("「ダンジョン表」(152ページ)へ移動。", DUNGEON_TABLE),
        ]
      )

      RANDOM_EVENT_TABLE_PLUS = RandomEventTable.new(
        "ランダムイベント表プラス",
        "1D6",
        [
          BranchByElapsedDays.new(
            "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら施設表プラス(022ページ)へ移動。【経過日数】を超えていればダンジョン表プラス(025ページ)へ移動",
            "FCLTP",
            DUNGEON_TABLE_PLUS
          ),
          BranchByElapsedDays.new(
            "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら世界の旅表(基本157ページ)へ移動。【経過日数】を超えていれば野外遭遇表(基本155ページ)へ移動",
            "「世界の旅表」(157ページ)へ。",
            "OUTENC"
          ),
          BranchByElapsedDays.new(
            "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら世界の旅表2(028ページ)へ移動。【経過日数】を超えていれば野外遭遇表プラス(025ページ)へ移動",
            "世界の旅表2(028ページ)へ。",
            "OUTENCP"
          ),
          BranchByDayParity.new(
            "さらに1D6を振る。奇数なら世界の旅表(基本157ページ)へ移動。偶数なら世界の旅表2(028ページ)へ移動",
            "世界の旅表(基本157ページ)へ。",
            "世界の旅表2(028ページ)へ。"
          ),
          MoveToTable.new("施設表プラスへ移動(022ページ)", "FCLTP"),
          MoveToTableWithDay.new("ダンジョン表プラスへ移動(025ページ)", DUNGEON_TABLE_PLUS)
        ]
      )
    end
  end
end