bcdice/BCDice

View on GitHub
lib/bcdice/game_system/ChaosFlare.rb

Summary

Maintainability
B
5 hrs
Test Coverage
A
92%
# frozen_string_literal: true

module BCDice
  module GameSystem
    class ChaosFlare < Base
      # ゲームシステムの識別子
      ID = 'ChaosFlare'
      # ゲームシステム名
      NAME = 'カオスフレア'

      # ゲームシステム名の読みがな
      SORT_KEY = 'かおすふれあ'

      # ダイスボットの使い方
      HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
        判定
        CF
          書式: [ダイスの数]CF[修正値][@クリティカル値][#ファンブル値][>=目標値]
            CF以外は全て省略可能
          例:
          - CF 2D6,クリティカル値12,ファンブル値2で判定
          - CF+10@10 修正値+10,クリティカル値10で判定
          - CF+10#3 修正値+10,ファンブル値3で判定
          - CF+10>=10 目標値を指定した場合、差分値も出力する
          - 3CF+10@10#3>=10 3D6での判定
          - CF@9#3+8>=10

        2D6
          ファンブル値2で判定する。クリティカルの判定は行われない。
          目標値が設定された場合、差分値を出力する。
          - 2D6+4>=10

        各種表
          FT: 因縁表
          FTx: 数値を指定すると因果表の値を出力する
          - FT -> 11から66の間でランダム決定
          - FT23 -> 23の項目を出力
          - FT0
          - FT7
      INFO_MESSAGE_TEXT

      register_prefix('\d*CF', 'FT')

      # ゲーム別成功度判定(2D6)。以前の処理をそのまま残しています。
      def result_2d6(total, dice_total, _dice_list, cmp_op, target)
        return nil unless cmp_op == :>=

        sequence = []
        result = Result.new

        if dice_total <= 2
          total -= 20
          sequence.push("ファンブル(-20)")
          result.fumble = true
        end

        if target != '?'
          if total >= target
            sequence.push("成功")
            result.success = true
          else
            sequence.push("失敗")
            result.failure = true
          end

          if total - target != 0
            sequence.push("差分値#{total - target}")
          end
        end

        return Result.nothing if sequence.empty?

        result.text = sequence.join(" > ")
        return result
      end

      def eval_game_system_specific_command(command)
        if command.start_with? "FT"
          roll_fate_table(command)
        else
          cf_roll(command)
        end
      end

      private

      # 因縁表
      def roll_fate_table(command)
        m = /^FT(\d+)?/.match(command)
        if m[1]
          num = m[1].to_i
          if [0, 7].include?(num)
            return "因果表(#{num}) > #{FATE_TABLE[num][0]}"
          end

          dice1 = num / 10
          dice2 = num % 10
          if !(1..6).include?(dice1) || !(1..6).include?(dice2)
            return nil
          end
        else
          dice1 = @randomizer.roll_once(6)
          dice2 = @randomizer.roll_once(6)
        end

        index1 = dice1
        index2 = (dice2 / 2) - 1
        return "因果表(#{dice1}#{dice2}) > #{FATE_TABLE[index1][index2]}"
      end

      # カオスフレア専用コマンド
      # @param command [String]
      # @return [String, nil]
      def cf_roll(command)
        parser = Command::Parser.new(/\d*CF/, round_type: round_type)
                                .enable_critical
                                .enable_fumble

        @cmd = parser.parse(command)
        unless @cmd
          return nil
        end

        times = @cmd.command == "CF" ? 2 : @cmd.command.to_i
        critical = @cmd.critical || 12
        fumble = @cmd.fumble || 2
        @cmd.dollar = nil

        if times < 0 || ![:>=, nil].include?(@cmd.cmp_op)
          return nil
        end

        dice_list = @randomizer.roll_barabara(times, 6)
        dice_total = dice_list.sum()
        dice_list_text = dice_list.join(",")

        is_critical = dice_total >= critical
        is_fumble = dice_total <= fumble

        total =
          if is_critical
            30
          elsif is_fumble
            -20
          else
            dice_total
          end

        total += @cmd.modify_number

        sequence = [
          "(#{@cmd.to_s(:after_modify_number)})",
          "#{dice_total}[#{dice_list_text}]",
          total.to_s,
          ("0" if total < 0),
          ("クリティカル" if is_critical),
          ("ファンブル" if is_fumble),
          ("差分値 #{difference(total)}" if @cmd.target_number),
        ].compact

        return sequence.join(" > ")
      end

      # @param total [Integer] 合計値
      # @return [Integer] 差分値
      def difference(total)
        if total < 0
          -@cmd.target_number
        else
          total - @cmd.target_number
        end
      end

      # 表を振るのに使う定数的なやつ。
      FATE_TABLE = [
        ["腐れ縁"],
        ["純愛", "親近感", "庇護"],
        ["信頼", "感服", "共感"],
        ["友情", "尊敬", "慕情"],
        ["好敵手", "期待", "借り"],
        ["興味", "憎悪", "悲しみ"],
        ["恐怖", "執着", "利用"],
        ["任意"]
      ].freeze
    end
  end
end