diff --git a/lib/bcdice/game_system.rb b/lib/bcdice/game_system.rb index 7bfaa1c16..e3f111c88 100644 --- a/lib/bcdice/game_system.rb +++ b/lib/bcdice/game_system.rb @@ -180,6 +180,7 @@ require "bcdice/game_system/MorkBorg" require "bcdice/game_system/Nechronica" require "bcdice/game_system/Nechronica_Korean" +require "bcdice/game_system/NegikureNegimaki" require "bcdice/game_system/NeonUnderRealm" require "bcdice/game_system/NervWhitePaper" require "bcdice/game_system/NeverCloud" diff --git a/lib/bcdice/game_system/NegikureNegimaki.rb b/lib/bcdice/game_system/NegikureNegimaki.rb new file mode 100644 index 000000000..685c8895d --- /dev/null +++ b/lib/bcdice/game_system/NegikureNegimaki.rb @@ -0,0 +1,139 @@ +# frozen_string_literal: true + +module BCDice + module GameSystem + class NegikureNegimaki < Base + # ゲームシステムの識別子 + ID = "NegikureNegimaki" + + # ゲームシステム名 + NAME = "ネジクレネジマキ" + + # ゲームシステム名の読みがな + SORT_KEY = "ねしくれねしまき" + + # ダイスボットの使い方 + HELP_MESSAGE = <<~INFO_MESSAGE_TEXT + ■ 行為判定 + nNNx#y: n個のD6を振り、x以上の出目の個数を成功レベルとして判定する + n: ダイス数(省略時1) + x: 難易度(省略時4) + y: 要求成功レベル(省略時1、0は1として扱う) + + ■ 戦闘判定(アタック判定) + nNAx#y: n個のD6を振り、x以上を成功とする。y以上の成功は直撃ダメージになる + n: ダイス数(省略時1) + x: 難易度(省略時4) + y: クリティカル値(省略時6、0は1として扱う) + 通常ダメージ = 成功レベル - 直撃ダメージ + 直撃ダメージ = 成功した出目のうち y 以上の個数 + ガッツ減少 = 出目 1 の個数 + + ■ ストライクの判定 + nNS: n個のD6を振り、出目 1 の個数だけガッツ減少を算出する + n: ダイス数(省略時1) + ガッツ減少が 0 なら成功、1 以上なら失敗 + INFO_MESSAGE_TEXT + + register_prefix('\d*NN\d*(#\d+)?', '\d*NA\d*(#\d+)?', '\d*NS') + + def eval_game_system_specific_command(command) + return eval_action_command(command) || eval_attack_command(command) || eval_guts_command(command) + end + + private + + def eval_action_command(command) + m = /\A(\d+)?NN(\d+)?(?:#(\d+))?\z/i.match(command) + return nil unless m + + dice_count = m[1]&.to_i || 1 + difficulty = m[2]&.to_i || 4 + required_level = [m[3]&.to_i || 1, 1].max + + return nil if dice_count.zero? + + command_text = "(#{dice_count}NN#{difficulty}##{required_level})" + + dice_list = @randomizer.roll_barabara(dice_count, 6) + success_level = dice_list.count { |value| value >= difficulty } + detail_text = "[#{dice_list.join(',')}]" + + return build_result(command_text, detail_text, success_level, required_level) + end + + def eval_attack_command(command) + m = /\A(\d+)?NA(\d+)?(?:#(\d+))?\z/i.match(command) + return nil unless m + + dice_count = m[1]&.to_i || 1 + difficulty = m[2]&.to_i || 4 + critical_value = [m[3]&.to_i || 6, 1].max + + return nil if dice_count.zero? + + command_text = "(#{dice_count}NA#{difficulty}##{critical_value})" + + dice_list = @randomizer.roll_barabara(dice_count, 6) + success_level = dice_list.count { |value| value >= difficulty } + direct_damage = dice_list.count { |value| value >= difficulty && value >= critical_value } + guts_loss = dice_list.count(1) + detail_text = "[#{dice_list.join(',')}]" + + return build_attack_result(command_text, detail_text, success_level, direct_damage, guts_loss) + end + + def eval_guts_command(command) + m = /\A(\d+)?NS\z/i.match(command) + return nil unless m + + dice_count = m[1]&.to_i || 1 + return nil if dice_count.zero? + + command_text = "(#{dice_count}NS)" + dice_list = @randomizer.roll_barabara(dice_count, 6) + guts_loss = dice_list.count(1) + detail_text = "[#{dice_list.join(',')}]" + + return build_guts_result(command_text, detail_text, guts_loss) + end + + def build_result(command_text, detail_text, success_level, required_level) + success = success_level >= required_level + judge_text = success ? "成功" : "失敗" + text = "#{command_text} > #{detail_text} > 成功レベル#{success_level}/要求#{required_level} > #{judge_text}" + + if success + return Result.success(text) + end + + return Result.failure(text) + end + + def build_attack_result(command_text, detail_text, success_level, direct_damage, guts_loss) + normal_damage = [success_level - direct_damage, 0].max + success = success_level.positive? + damage_text = "通常ダメージ#{normal_damage}/直撃ダメージ#{direct_damage}" + damage_text += "/ガッツ減少#{guts_loss}" if guts_loss.positive? + text = "#{command_text} > #{detail_text} > 成功レベル#{success_level} > #{damage_text}" + + if success + return Result.success(text) + end + + return Result.failure(text) + end + + def build_guts_result(command_text, detail_text, guts_loss) + success = guts_loss.zero? + text = "#{command_text} > #{detail_text} > ガッツ減少#{guts_loss}" + + if success + return Result.success(text) + end + + return Result.failure(text) + end + end + end +end diff --git a/test/data/NegikureNegimaki.toml b/test/data/NegikureNegimaki.toml new file mode 100644 index 000000000..a0753755e --- /dev/null +++ b/test/data/NegikureNegimaki.toml @@ -0,0 +1,254 @@ +[[ test ]] +game_system = "NegikureNegimaki" +input = "3NN4" +output = "(3NN4#1) > [6,3,1] > 成功レベル1/要求1 > 成功" +success = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 3 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "4NN5#3" +output = "(4NN5#3) > [6,5,2,1] > 成功レベル2/要求3 > 失敗" +failure = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 5 }, + { sides = 6, value = 2 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "NN4" +output = "(1NN4#1) > [4] > 成功レベル1/要求1 > 成功" +success = true +rands = [ + { sides = 6, value = 4 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "3NN" +output = "(3NN4#1) > [3,2,5] > 成功レベル1/要求1 > 成功" +success = true +rands = [ + { sides = 6, value = 3 }, + { sides = 6, value = 2 }, + { sides = 6, value = 5 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "NN" +output = "(1NN4#1) > [2] > 成功レベル0/要求1 > 失敗" +failure = true +rands = [ + { sides = 6, value = 2 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2NN6" +output = "(2NN6#1) > [6,1] > 成功レベル1/要求1 > 成功" +success = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2NN5#0" +output = "(2NN5#1) > [4,6] > 成功レベル1/要求1 > 成功" +success = true +rands = [ + { sides = 6, value = 4 }, + { sides = 6, value = 6 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2NN1#2" +output = "(2NN1#2) > [2,2] > 成功レベル2/要求2 > 成功" +success = true +rands = [ + { sides = 6, value = 2 }, + { sides = 6, value = 2 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "3NN7#1" +output = "(3NN7#1) > [6,5,1] > 成功レベル0/要求1 > 失敗" +failure = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 5 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "0NN4" +output = "" +rands = [] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2nn4#2" +output = "(2NN4#2) > [4,4] > 成功レベル2/要求2 > 成功" +success = true +rands = [ + { sides = 6, value = 4 }, + { sides = 6, value = 4 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "3NA4" +output = "(3NA4#6) > [6,4,1] > 成功レベル2 > 通常ダメージ1/直撃ダメージ1/ガッツ減少1" +success = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 4 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "4NA4#5" +output = "(4NA4#5) > [5,4,3,6] > 成功レベル3 > 通常ダメージ1/直撃ダメージ2" +success = true +rands = [ + { sides = 6, value = 5 }, + { sides = 6, value = 4 }, + { sides = 6, value = 3 }, + { sides = 6, value = 6 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "NA4#6" +output = "(1NA4#6) > [6] > 成功レベル1 > 通常ダメージ0/直撃ダメージ1" +success = true +rands = [ + { sides = 6, value = 6 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2NA#5" +output = "(2NA4#5) > [5,2] > 成功レベル1 > 通常ダメージ0/直撃ダメージ1" +success = true +rands = [ + { sides = 6, value = 5 }, + { sides = 6, value = 2 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "NA" +output = "(1NA4#6) > [3] > 成功レベル0 > 通常ダメージ0/直撃ダメージ0" +failure = true +rands = [ + { sides = 6, value = 3 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2NA4#0" +output = "(2NA4#1) > [4,1] > 成功レベル1 > 通常ダメージ0/直撃ダメージ1/ガッツ減少1" +success = true +rands = [ + { sides = 6, value = 4 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2NA1#6" +output = "(2NA1#6) > [6,1] > 成功レベル2 > 通常ダメージ1/直撃ダメージ1/ガッツ減少1" +success = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "3NA7#6" +output = "(3NA7#6) > [6,6,1] > 成功レベル0 > 通常ダメージ0/直撃ダメージ0/ガッツ減少1" +failure = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 6 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "4NA4#6" +output = "(4NA4#6) > [1,1,4,6] > 成功レベル2 > 通常ダメージ1/直撃ダメージ1/ガッツ減少2" +success = true +rands = [ + { sides = 6, value = 1 }, + { sides = 6, value = 1 }, + { sides = 6, value = 4 }, + { sides = 6, value = 6 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "0NA4" +output = "" +rands = [] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2na4#5" +output = "(2NA4#5) > [6,4] > 成功レベル2 > 通常ダメージ1/直撃ダメージ1" +success = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 4 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "3NS" +output = "(3NS) > [1,4,1] > ガッツ減少2" +failure = true +rands = [ + { sides = 6, value = 1 }, + { sides = 6, value = 4 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "NS" +output = "(1NS) > [4] > ガッツ減少0" +success = true +rands = [ + { sides = 6, value = 4 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "0NS" +output = "" +rands = [] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2ns" +output = "(2NS) > [1,6] > ガッツ減少1" +failure = true +rands = [ + { sides = 6, value = 1 }, + { sides = 6, value = 6 }, +]