From 551a0b44827090126a0db8868d8664779df6d56a Mon Sep 17 00:00:00 2001 From: mrrlll Date: Fri, 6 Mar 2026 00:40:54 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=E3=83=8D=E3=82=B8=E3=82=AF=E3=83=AC?= =?UTF-8?q?=E3=83=8D=E3=82=B8=E3=83=9E=E3=82=AD=E3=81=AE=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bcdice/game_system.rb | 1 + lib/bcdice/game_system/NegikureNegimaki.rb | 104 +++++++++++ test/data/NegikureNegimaki.toml | 206 +++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 lib/bcdice/game_system/NegikureNegimaki.rb create mode 100644 test/data/NegikureNegimaki.toml 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..4a9f98dca --- /dev/null +++ b/lib/bcdice/game_system/NegikureNegimaki.rb @@ -0,0 +1,104 @@ +# 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 以上の個数 + INFO_MESSAGE_TEXT + + register_prefix('\d*NN\d*(#\d+)?', '\d*NA\d*(#\d+)?') + + def eval_game_system_specific_command(command) + return eval_action_command(command) || eval_attack_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 } + detail_text = "[#{dice_list.join(',')}]" + + return build_attack_result(command_text, detail_text, success_level, direct_damage) + 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) + normal_damage = [success_level - direct_damage, 0].max + success = success_level.positive? + text = "#{command_text} > #{detail_text} > 成功レベル#{success_level} > 通常ダメージ#{normal_damage}/直撃ダメージ#{direct_damage}" + + 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..28c350b13 --- /dev/null +++ b/test/data/NegikureNegimaki.toml @@ -0,0 +1,206 @@ +[[ 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" +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" +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" +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" +failure = true +rands = [ + { sides = 6, value = 6 }, + { sides = 6, value = 6 }, + { sides = 6, value = 1 }, +] + +[[ 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 }, +] From 17b477f3ad71730058ead24f8030ddd9251fef10 Mon Sep 17 00:00:00 2001 From: mrrlll Date: Sat, 7 Mar 2026 14:39:43 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E6=88=A6=E9=97=98=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E3=81=AB=E3=82=AC=E3=83=83=E3=83=84=E6=B8=9B=E5=B0=91=E3=81=AE?= =?UTF-8?q?=E7=AE=97=E5=87=BA=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bcdice/game_system/NegikureNegimaki.rb | 10 +++++++--- test/data/NegikureNegimaki.toml | 20 ++++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/bcdice/game_system/NegikureNegimaki.rb b/lib/bcdice/game_system/NegikureNegimaki.rb index 4a9f98dca..ea5720132 100644 --- a/lib/bcdice/game_system/NegikureNegimaki.rb +++ b/lib/bcdice/game_system/NegikureNegimaki.rb @@ -27,6 +27,7 @@ class NegikureNegimaki < Base y: クリティカル値(省略時6、0は1として扱う) 通常ダメージ = 成功レベル - 直撃ダメージ 直撃ダメージ = 成功した出目のうち y 以上の個数 + ガッツ減少 = 出目 1 の個数 INFO_MESSAGE_TEXT register_prefix('\d*NN\d*(#\d+)?', '\d*NA\d*(#\d+)?') @@ -71,9 +72,10 @@ def eval_attack_command(command) 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) + return build_attack_result(command_text, detail_text, success_level, direct_damage, guts_loss) end def build_result(command_text, detail_text, success_level, required_level) @@ -88,10 +90,12 @@ def build_result(command_text, detail_text, success_level, required_level) return Result.failure(text) end - def build_attack_result(command_text, detail_text, success_level, direct_damage) + 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? - text = "#{command_text} > #{detail_text} > 成功レベル#{success_level} > 通常ダメージ#{normal_damage}/直撃ダメージ#{direct_damage}" + 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) diff --git a/test/data/NegikureNegimaki.toml b/test/data/NegikureNegimaki.toml index 28c350b13..2ca951496 100644 --- a/test/data/NegikureNegimaki.toml +++ b/test/data/NegikureNegimaki.toml @@ -110,7 +110,7 @@ rands = [ [[ test ]] game_system = "NegikureNegimaki" input = "3NA4" -output = "(3NA4#6) > [6,4,1] > 成功レベル2 > 通常ダメージ1/直撃ダメージ1" +output = "(3NA4#6) > [6,4,1] > 成功レベル2 > 通常ダメージ1/直撃ダメージ1/ガッツ減少1" success = true rands = [ { sides = 6, value = 6 }, @@ -161,7 +161,7 @@ rands = [ [[ test ]] game_system = "NegikureNegimaki" input = "2NA4#0" -output = "(2NA4#1) > [4,1] > 成功レベル1 > 通常ダメージ0/直撃ダメージ1" +output = "(2NA4#1) > [4,1] > 成功レベル1 > 通常ダメージ0/直撃ダメージ1/ガッツ減少1" success = true rands = [ { sides = 6, value = 4 }, @@ -171,7 +171,7 @@ rands = [ [[ test ]] game_system = "NegikureNegimaki" input = "2NA1#6" -output = "(2NA1#6) > [6,1] > 成功レベル2 > 通常ダメージ1/直撃ダメージ1" +output = "(2NA1#6) > [6,1] > 成功レベル2 > 通常ダメージ1/直撃ダメージ1/ガッツ減少1" success = true rands = [ { sides = 6, value = 6 }, @@ -181,7 +181,7 @@ rands = [ [[ test ]] game_system = "NegikureNegimaki" input = "3NA7#6" -output = "(3NA7#6) > [6,6,1] > 成功レベル0 > 通常ダメージ0/直撃ダメージ0" +output = "(3NA7#6) > [6,6,1] > 成功レベル0 > 通常ダメージ0/直撃ダメージ0/ガッツ減少1" failure = true rands = [ { sides = 6, value = 6 }, @@ -189,6 +189,18 @@ rands = [ { 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" From bfafc2093de1c151a70885b6f67685b022926b94 Mon Sep 17 00:00:00 2001 From: mrrlll Date: Thu, 12 Mar 2026 12:05:45 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=E3=80=8C=E3=82=B9=E3=83=88=E3=83=A9?= =?UTF-8?q?=E3=82=A4=E3=82=AF=E3=80=8D=E7=94=A8=E3=81=AE=E3=82=B3=E3=83=9E?= =?UTF-8?q?=E3=83=B3=E3=83=89=E3=82=92=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bcdice/game_system/NegikureNegimaki.rb | 23 +++++++++++++-- test/data/NegikureNegimaki.toml | 33 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/lib/bcdice/game_system/NegikureNegimaki.rb b/lib/bcdice/game_system/NegikureNegimaki.rb index ea5720132..fb9641f55 100644 --- a/lib/bcdice/game_system/NegikureNegimaki.rb +++ b/lib/bcdice/game_system/NegikureNegimaki.rb @@ -28,12 +28,16 @@ class NegikureNegimaki < Base 通常ダメージ = 成功レベル - 直撃ダメージ 直撃ダメージ = 成功した出目のうち y 以上の個数 ガッツ減少 = 出目 1 の個数 + + ■ ストライクの判定 + nNS: n個のD6を振り、出目 1 の個数だけガッツ減少を算出する + n: ダイス数(省略時1) INFO_MESSAGE_TEXT - register_prefix('\d*NN\d*(#\d+)?', '\d*NA\d*(#\d+)?') + 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) + return eval_action_command(command) || eval_attack_command(command) || eval_guts_command(command) end private @@ -78,6 +82,21 @@ def eval_attack_command(command) 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 Result.new("#{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 ? "成功" : "失敗" diff --git a/test/data/NegikureNegimaki.toml b/test/data/NegikureNegimaki.toml index 2ca951496..3d54b3372 100644 --- a/test/data/NegikureNegimaki.toml +++ b/test/data/NegikureNegimaki.toml @@ -216,3 +216,36 @@ rands = [ { sides = 6, value = 6 }, { sides = 6, value = 4 }, ] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "3NS" +output = "(3NS) > [1,4,1] > ガッツ減少2" +rands = [ + { sides = 6, value = 1 }, + { sides = 6, value = 4 }, + { sides = 6, value = 1 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "NS" +output = "(1NS) > [4] > ガッツ減少0" +rands = [ + { sides = 6, value = 4 }, +] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "0NS" +output = "" +rands = [] + +[[ test ]] +game_system = "NegikureNegimaki" +input = "2ns" +output = "(2NS) > [1,6] > ガッツ減少1" +rands = [ + { sides = 6, value = 1 }, + { sides = 6, value = 6 }, +] From 356a29b2aef4ae985897788569088cb9aee930cb Mon Sep 17 00:00:00 2001 From: mrrlll Date: Thu, 12 Mar 2026 18:00:48 +0900 Subject: [PATCH 4/4] =?UTF-8?q?NS=E3=81=AE=E5=88=A4=E5=AE=9A=E3=82=92?= =?UTF-8?q?=E3=82=AC=E3=83=83=E3=83=84=E6=B8=9B=E5=B0=91=E3=81=8C=E3=81=82?= =?UTF-8?q?=E3=81=A3=E3=81=9F=E3=81=8B=E3=81=A9=E3=81=86=E3=81=8B=E3=81=A7?= =?UTF-8?q?=E6=88=90=E5=90=A6=E5=88=86=E3=81=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bcdice/game_system/NegikureNegimaki.rb | 14 +++++++++++++- test/data/NegikureNegimaki.toml | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/bcdice/game_system/NegikureNegimaki.rb b/lib/bcdice/game_system/NegikureNegimaki.rb index fb9641f55..685c8895d 100644 --- a/lib/bcdice/game_system/NegikureNegimaki.rb +++ b/lib/bcdice/game_system/NegikureNegimaki.rb @@ -32,6 +32,7 @@ class NegikureNegimaki < Base ■ ストライクの判定 nNS: n個のD6を振り、出目 1 の個数だけガッツ減少を算出する n: ダイス数(省略時1) + ガッツ減少が 0 なら成功、1 以上なら失敗 INFO_MESSAGE_TEXT register_prefix('\d*NN\d*(#\d+)?', '\d*NA\d*(#\d+)?', '\d*NS') @@ -94,7 +95,7 @@ def eval_guts_command(command) guts_loss = dice_list.count(1) detail_text = "[#{dice_list.join(',')}]" - return Result.new("#{command_text} > #{detail_text} > ガッツ減少#{guts_loss}") + return build_guts_result(command_text, detail_text, guts_loss) end def build_result(command_text, detail_text, success_level, required_level) @@ -122,6 +123,17 @@ def build_attack_result(command_text, detail_text, success_level, direct_damage, 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 index 3d54b3372..a0753755e 100644 --- a/test/data/NegikureNegimaki.toml +++ b/test/data/NegikureNegimaki.toml @@ -221,6 +221,7 @@ rands = [ game_system = "NegikureNegimaki" input = "3NS" output = "(3NS) > [1,4,1] > ガッツ減少2" +failure = true rands = [ { sides = 6, value = 1 }, { sides = 6, value = 4 }, @@ -231,6 +232,7 @@ rands = [ game_system = "NegikureNegimaki" input = "NS" output = "(1NS) > [4] > ガッツ減少0" +success = true rands = [ { sides = 6, value = 4 }, ] @@ -245,6 +247,7 @@ rands = [] game_system = "NegikureNegimaki" input = "2ns" output = "(2NS) > [1,6] > ガッツ減少1" +failure = true rands = [ { sides = 6, value = 1 }, { sides = 6, value = 6 },