bcdice 3.6.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -0
  3. data/i18n/Arianrhod/ja_jp.yml +3 -0
  4. data/i18n/Emoklore/ja_jp.yml +7 -0
  5. data/i18n/FutariSousa/ja_jp.yml +431 -0
  6. data/i18n/LogHorizon/ja_jp.yml +1 -1
  7. data/i18n/SwordWorld/ja_jp.yml +1 -0
  8. data/i18n/SwordWorld/zh_hans.yml +7 -0
  9. data/i18n/SwordWorld2_0/zh_hans.yml +37 -0
  10. data/i18n/SwordWorld2_5/ja_jp.yml +1 -1
  11. data/i18n/SwordWorld2_5/zh_hans.yml +57 -0
  12. data/lib/bcdice/arithmetic/parser.rb +1 -1
  13. data/lib/bcdice/command/parser.rb +1 -1
  14. data/lib/bcdice/common_command/add_dice/parser.rb +106 -74
  15. data/lib/bcdice/common_command/add_dice.rb +1 -1
  16. data/lib/bcdice/common_command/barabara_dice/parser.rb +1 -1
  17. data/lib/bcdice/common_command/calc/parser.rb +1 -1
  18. data/lib/bcdice/common_command/d66_dice.rb +1 -1
  19. data/lib/bcdice/common_command/reroll_dice/parser.rb +1 -1
  20. data/lib/bcdice/common_command/tally_dice/parser.rb +1 -1
  21. data/lib/bcdice/common_command/upper_dice/parser.rb +1 -1
  22. data/lib/bcdice/game_system/AngelGear.rb +1 -1
  23. data/lib/bcdice/game_system/AnimaAnimus.rb +1 -1
  24. data/lib/bcdice/game_system/Arianrhod.rb +4 -4
  25. data/lib/bcdice/game_system/AssaultEngine.rb +3 -3
  26. data/lib/bcdice/game_system/Ayabito.rb +170 -4
  27. data/lib/bcdice/game_system/BeastBindTrinity.rb +1 -1
  28. data/lib/bcdice/game_system/BeginningIdol.rb +4 -2
  29. data/lib/bcdice/game_system/BeginningIdol2022.rb +184 -0
  30. data/lib/bcdice/game_system/BladeOfArcana.rb +3 -3
  31. data/lib/bcdice/game_system/Bloodorium.rb +68 -0
  32. data/lib/bcdice/game_system/ConvictorDrive.rb +117 -0
  33. data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb +1 -1
  34. data/lib/bcdice/game_system/Cthulhu7th_Korean.rb +1 -1
  35. data/lib/bcdice/game_system/CyberpunkRed.rb +2 -6
  36. data/lib/bcdice/game_system/DeadlineHeroes.rb +1 -1
  37. data/lib/bcdice/game_system/DungeonsAndDragons5.rb +196 -0
  38. data/lib/bcdice/game_system/EmbryoMachine.rb +4 -4
  39. data/lib/bcdice/game_system/Emoklore.rb +8 -8
  40. data/lib/bcdice/game_system/FutariSousa.rb +31 -5
  41. data/lib/bcdice/game_system/GURPS.rb +1 -1
  42. data/lib/bcdice/game_system/GehennaAn.rb +2 -2
  43. data/lib/bcdice/game_system/GhostLive.rb +144 -0
  44. data/lib/bcdice/game_system/GoblinSlayer.rb +30 -8
  45. data/lib/bcdice/game_system/HunterTheReckoning5th.rb +152 -0
  46. data/lib/bcdice/game_system/IfIfIf.rb +648 -0
  47. data/lib/bcdice/game_system/Kutulu.rb +95 -0
  48. data/lib/bcdice/game_system/LostRoyal.rb +1 -1
  49. data/lib/bcdice/game_system/NobunagasBlackCastle.rb +237 -0
  50. data/lib/bcdice/game_system/OracleEngine.rb +1 -1
  51. data/lib/bcdice/game_system/Raisondetre.rb +1 -1
  52. data/lib/bcdice/game_system/RokumonSekai2.rb +1 -1
  53. data/lib/bcdice/game_system/SajinsenkiAGuS.rb +154 -0
  54. data/lib/bcdice/game_system/Sengensyou.rb +59 -0
  55. data/lib/bcdice/game_system/ShinkuuGakuen.rb +1 -1
  56. data/lib/bcdice/game_system/ShinobiGami.rb +14 -1
  57. data/lib/bcdice/game_system/SkynautsBouken.rb +93 -2
  58. data/lib/bcdice/game_system/StellarLife.rb +1 -1
  59. data/lib/bcdice/game_system/StrangerOfSwordCity.rb +1 -1
  60. data/lib/bcdice/game_system/SwordWorld.rb +2 -2
  61. data/lib/bcdice/game_system/SwordWorld2_0_SimplifiedChinese.rb +84 -0
  62. data/lib/bcdice/game_system/SwordWorld2_5_SimplifiedChinese.rb +95 -0
  63. data/lib/bcdice/game_system/SwordWorld_SimplifiedChinese.rb +29 -0
  64. data/lib/bcdice/game_system/TherapieSein.rb +2 -2
  65. data/lib/bcdice/game_system/Torg.rb +1 -1
  66. data/lib/bcdice/game_system/TorgEternity.rb +54 -18
  67. data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +26 -12
  68. data/lib/bcdice/game_system/VisionConnect.rb +135 -0
  69. data/lib/bcdice/game_system/Warhammer4.rb +4 -0
  70. data/lib/bcdice/game_system/WorldOfDarkness.rb +54 -50
  71. data/lib/bcdice/game_system/cthulhu7th/full_auto.rb +1 -1
  72. data/lib/bcdice/game_system/filled_with/tresure_tables.rb +1 -1
  73. data/lib/bcdice/game_system/satasupe/tables.rb +1 -1
  74. data/lib/bcdice/game_system/sword_world/rating_parser.rb +1 -1
  75. data/lib/bcdice/game_system.rb +15 -0
  76. data/lib/bcdice/version.rb +1 -1
  77. metadata +26 -6
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class Kutulu < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'Kutulu'
8
+
9
+ # ゲームシステム名
10
+ NAME = 'Kutulu'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'くとうるう'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGETEXT
17
+ ■判定 nKU n: ダイス数
18
+
19
+ 例)3KU: ダイスを3個振って、その結果を表示(ギリギリでの成功も表示)
20
+
21
+ ■対抗判定 nKR n: ダイス数
22
+
23
+ 例)2KR: ダイスを2個振って、その結果を表示。対抗判定用の3桁の数字も出力。(大きい方が勝利)
24
+ INFO_MESSAGETEXT
25
+
26
+ register_prefix('\dK[UR]')
27
+
28
+ def initialize(command)
29
+ super(command)
30
+
31
+ @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
32
+ end
33
+
34
+ def eval_game_system_specific_command(command)
35
+ resolute_action(command) || resolute_competition(command)
36
+ end
37
+
38
+ private
39
+
40
+ # アクティヴ能力の判定
41
+ # @param [String] command
42
+ # @return [Result]
43
+ def resolute_action(command)
44
+ m = /(\d)KU/.match(command)
45
+ return nil unless m
46
+
47
+ num_dices = m[1].to_i
48
+
49
+ dices = @randomizer.roll_barabara(num_dices, 6).sort
50
+ dice_text = dices.join(",")
51
+
52
+ output = "(#{num_dices}KU) > #{dice_text}"
53
+
54
+ success_num = dices.count { |val| val >= 4 }
55
+ counts_4 = dices.count(4)
56
+ if success_num > 0
57
+ output += " > 成功数#{success_num}"
58
+ if success_num == 1 && counts_4 == 1
59
+ output += " > *ギリギリでの成功"
60
+ end
61
+ return Result.success(output)
62
+ else
63
+ output += " > 失敗"
64
+ return Result.failure(output)
65
+ end
66
+ end
67
+
68
+ # 対抗判定用出力
69
+ # @param [String] command
70
+ # @return [Result]
71
+ def resolute_competition(command)
72
+ m = /(\d)KR/.match(command)
73
+ return nil unless m
74
+
75
+ num_dices = m[1].to_i
76
+
77
+ dices = @randomizer.roll_barabara(num_dices, 6).sort
78
+ dice_text = dices.join(",")
79
+
80
+ counts_6 = dices.count(6)
81
+ counts_5 = dices.count(5)
82
+ success_num = dices.count { |val| val >= 4 }
83
+ com_text = format("(%d%d%d)", success_num, counts_6, counts_5)
84
+
85
+ output = "(#{num_dices}KR) > #{dice_text} > #{com_text}"
86
+
87
+ if success_num > 0
88
+ return Result.success(output)
89
+ else
90
+ return Result.failure(output)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -64,7 +64,7 @@ module BCDice
64
64
  def check_lostroyal(checking_table)
65
65
  keys = []
66
66
 
67
- (0...3).each do |_i|
67
+ 3.times do |_i|
68
68
  key = @randomizer.roll_once(6)
69
69
  keys << key
70
70
  end
@@ -0,0 +1,237 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bcdice/dice_table/table'
4
+
5
+ module BCDice
6
+ module GameSystem
7
+ class NobunagasBlackCastle < Base
8
+ # ゲームシステムの識別子
9
+ ID = 'NobunagasBlackCastle'
10
+
11
+ # ゲームシステム名
12
+ NAME = '信長の黒い城'
13
+
14
+ # ゲームシステム名の読みがな
15
+ SORT_KEY = 'のふなかのくろいしろ'
16
+
17
+ # ダイスボットの使い方
18
+ HELP_MESSAGE = <<~INFO_MESSAGETEXT
19
+ ■判定 sDRt s: 能力値 t:目標値
20
+
21
+ 例)+3DR12: 能力値+3、DR12で1d20を振って、その結果を表示(クリティカル・ファンブルも表示)
22
+
23
+ ■イニシアティヴ INS
24
+
25
+ 例)INS: 1d6を振って、イニシアティヴの結果を表示(PC先行を成功として表示)
26
+
27
+ ■NPC能力値作成 NPCST
28
+
29
+ 例)NPCST: 3d6を4回振って、各能力値とHPを表示
30
+
31
+
32
+ ■各種表
33
+
34
+ ・遭遇反応表(ERT)
35
+ ・武器表(SWT)/その他の奇妙な武器表(OSWT)
36
+ ・鎧表(ART)
37
+
38
+ INFO_MESSAGETEXT
39
+
40
+ def initialize(command)
41
+ super(command)
42
+
43
+ @sort_add_dice = true
44
+ @d66_sort_type = D66SortType::NO_SORT
45
+ end
46
+
47
+ def eval_game_system_specific_command(command)
48
+ resolute_action(command) || resolute_initiative(command) || roll_tables(command, TABLES) || make_npc_status(command)
49
+ end
50
+
51
+ private
52
+
53
+ def result_dr(total, dice_total, target)
54
+ if dice_total <= 1
55
+ Result.fumble("ファンブル")
56
+ elsif dice_total >= 20
57
+ Result.critical("クリティカル")
58
+ elsif total >= target
59
+ Result.success("成功")
60
+ else
61
+ Result.failure("失敗")
62
+ end
63
+ end
64
+
65
+ # DR判定
66
+ # @param [String] command
67
+ # @return [Result]
68
+ def resolute_action(command)
69
+ m = /^([+-]?\d*)DR(\d+)$/.match(command)
70
+ return nil unless m
71
+
72
+ num_status = m[1].to_i
73
+ num_target = m[2].to_i
74
+
75
+ total = @randomizer.roll_once(20)
76
+ total_status = total.to_s + with_symbol(num_status)
77
+ result = result_dr(total + num_status, total, num_target)
78
+
79
+ sequence = [
80
+ "(#{command})",
81
+ total_status,
82
+ total + num_status,
83
+ result.text,
84
+ ]
85
+
86
+ result.text = sequence.join(" > ")
87
+ return result
88
+ end
89
+
90
+ def with_symbol(number)
91
+ if number == 0
92
+ return "+0"
93
+ elsif number > 0
94
+ return "+#{number}"
95
+ else
96
+ return number.to_s
97
+ end
98
+ end
99
+
100
+ # イニシアティヴ判定
101
+ # @param [String] command
102
+ # @return [Result]
103
+ def resolute_initiative(command)
104
+ unless command == "INS"
105
+ return nil
106
+ end
107
+
108
+ total = @randomizer.roll_once(6)
109
+ result =
110
+ if total >= 4
111
+ Result.success("PC先行")
112
+ else
113
+ Result.failure("敵先行")
114
+ end
115
+
116
+ result.text = "(#{command}) > #{total} > #{result.text}"
117
+ return result
118
+ end
119
+
120
+ # NPC能力値作成
121
+ # @param [String] command
122
+ # @return [String]
123
+ def make_npc_status(command)
124
+ unless command == "NPCST"
125
+ return nil
126
+ end
127
+
128
+ pre = @randomizer.roll_sum(3, 6)
129
+ agi = @randomizer.roll_sum(3, 6)
130
+ str = @randomizer.roll_sum(3, 6)
131
+ tgh = @randomizer.roll_sum(3, 6)
132
+ hpd = @randomizer.roll_once(8)
133
+ hp = hpd + calc_status(tgh)
134
+ hp = 1 if hp < 1
135
+
136
+ text = [
137
+ "心#{with_symbol(calc_status(pre))}(#{pre})",
138
+ "技#{with_symbol(calc_status(agi))}(#{agi})",
139
+ "体#{with_symbol(calc_status(str))}(#{str})",
140
+ "耐久#{with_symbol(calc_status(tgh))}(#{tgh})",
141
+ "HP#{hp}(#{hpd})",
142
+ ].join(", ")
143
+
144
+ return "(#{command}) > #{text}"
145
+ end
146
+
147
+ def calc_status(st)
148
+ if st <= 4
149
+ return -3
150
+ elsif st <= 6
151
+ return -2
152
+ elsif st <= 8
153
+ return -1
154
+ elsif st <= 12
155
+ return 0
156
+ elsif st <= 14
157
+ return 1
158
+ elsif st <= 16
159
+ return 2
160
+ elsif st <= 20
161
+ return 3
162
+ end
163
+ end
164
+
165
+ # 各種表
166
+
167
+ TABLES = {
168
+ 'OSWT' => DiceTable::Table.new(
169
+ 'その他の奇妙な武器表',
170
+ '1D10',
171
+ [
172
+ '六尺棒(D4)',
173
+ '手槍(D4)',
174
+ '弓矢(D6)',
175
+ '鉄扇(D4)',
176
+ '大鉞(D8)',
177
+ '吹き矢(D2)+感染',
178
+ '鞭(D3)',
179
+ '熊手(D4)',
180
+ '石つぶて(D3)',
181
+ '丸太(D4)',
182
+ ]
183
+ ),
184
+ 'SWT' => DiceTable::Table.new(
185
+ '武器表',
186
+ '1D12',
187
+ [
188
+ '尖らせた骨の杭(D3)',
189
+ '竹槍(D4)',
190
+ '百姓から奪った鍬(D4)',
191
+ '脇差し(D4)',
192
+ '手裏剣 D6本(D4)',
193
+ '刀(D6)',
194
+ '鎖鎌(D6)',
195
+ '太刀(D8)',
196
+ '種子島銃(2D6) 弾丸(心+5)発',
197
+ '大槍(D8)',
198
+ '爆裂弾(D4) 心+3発',
199
+ '斬馬刀(D10)',
200
+ ]
201
+ ),
202
+ 'ART' => DiceTable::Table.new(
203
+ '鎧表',
204
+ '1D6',
205
+ [
206
+ '防具は、何もない',
207
+ '防具は、何もない',
208
+ '部分鎧(腹巻き) -D2ダメージ',
209
+ 'お貸し具足 -D3ダメージ',
210
+ '武者鎧 -D4ダメージ',
211
+ '大鎧 -D6ダメージ',
212
+ ]
213
+ ),
214
+ # 無理に高度なことをしなくても、表は展開して実装しても動く
215
+ 'ERT' => DiceTable::Table.new(
216
+ '遭遇反応表',
217
+ '2D6',
218
+ [
219
+ 'お前ら、殺す!',
220
+ 'お前ら、殺す!',
221
+ '憎悪の視線で睨んでくる。すきを見せれば、攻撃してくる。',
222
+ '憎悪の視線で睨んでくる。すきを見せれば、攻撃してくる。',
223
+ '憎悪の視線で睨んでくる。すきを見せれば、攻撃してくる。',
224
+ '警戒はしているが、特に、戦闘は望んでいない。怒らせなければ、自分たちの目的に沿って動く。',
225
+ '警戒はしているが、特に、戦闘は望んでいない。怒らせなければ、自分たちの目的に沿って動く。',
226
+ '中立。何かを与えたり、取引の材料を提示したりできれば、交渉できそうだ。',
227
+ '中立。何かを与えたり、取引の材料を提示したりできれば、交渉できそうだ。',
228
+ '好意的に会話できそうだ。向こうも取引したがっている。',
229
+ '好意的に会話できそうだ。向こうも取引したがっている。',
230
+ ]
231
+ ),
232
+ }.freeze
233
+
234
+ register_prefix('[+-]?\d*DR[\d]+', 'INS', 'NPCST', TABLES.keys)
235
+ end
236
+ end
237
+ end
@@ -46,7 +46,7 @@ MESSAGETEXT
46
46
  case command
47
47
  when /\d+CL.*/i
48
48
  clutch_roll(command)
49
- when /\d+D6.*\$[+\-]?\d.*/
49
+ when /\d+D6.*\$[+-]?\d.*/
50
50
  damage_roll(command)
51
51
  when /\d+R6/
52
52
  r_roll(command)
@@ -52,7 +52,7 @@ module BCDice
52
52
 
53
53
  return checkRoll(diceCount, choiceCount, target)
54
54
 
55
- elsif command =~ /(-)?(\d+)?DD([1-9])?([+\-]\d+)?$/i
55
+ elsif command =~ /(-)?(\d+)?DD([1-9])?([+-]\d+)?$/i
56
56
  diceCount = (Regexp.last_match(2) || 1).to_i
57
57
  diceCount *= -1 unless Regexp.last_match(1).nil?
58
58
  armor = (Regexp.last_match(3) || 0).to_i
@@ -31,7 +31,7 @@ module BCDice
31
31
  end
32
32
 
33
33
  def replace_text(string)
34
- string = string.gsub(/(\d+)RS([+\-][+\-\d]+)<=(\d+)/i) { "3R6#{Regexp.last_match(2)}<=#{Regexp.last_match(3)}[#{Regexp.last_match(1)}]" }
34
+ string = string.gsub(/(\d+)RS([+-][+\-\d]+)<=(\d+)/i) { "3R6#{Regexp.last_match(2)}<=#{Regexp.last_match(3)}[#{Regexp.last_match(1)}]" }
35
35
  string = string.gsub(/(\d+)RS<=(\d+)/i) { "3R6<=#{Regexp.last_match(2)}[#{Regexp.last_match(1)}]" }
36
36
 
37
37
  return string
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class SajinsenkiAGuS < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'SajinsenkiAGuS'
8
+
9
+ # ゲームシステム名
10
+ NAME = '砂塵戦機アーガス'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'さしんせんきああかす'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
+ ・一般判定Lv(チャンス出目0→判定0) nAG+x
18
+    nは習得レベル、Lv0の場合nの省略可能。xは判定値修正(数式による修正可)、省略した場合はレベル修正0
19
+    例)AG:習得レベル0の一般技能、1AG+1:習得レベル1・判定値修正+1の技能、AG+2-1:習得レベル0・判定値修正2-1の技能、(1-1)AG:習得レベル1・レベル修正-1の技能
20
+
21
+ ・適正距離での命中判定(チャンス出目0→判定0、HR算出)OM+y@z
22
+    yは命中補正値(数式可)、zはクリティカル値。クリティカル値省略時は0
23
+    HRの算出時には、HRが大きくなる場合に出目0を10に読み替えます。
24
+    例)OM+18-6@2:命中補正値+18-6でクリティカル値2、適正距離の判定
25
+
26
+ ・非適正距離での命中判定(チャンス出目0→判定0、HR算出)NM+y@z
27
+    yは命中補正値(数式可)、zはクリティカル値。クリティカル値省略時は0
28
+    HRの算出時には、HRが大きくなる場合に出目0を10に読み替えます。
29
+    例)NM+4-3:命中補正値+4-3で非適正距離の判定
30
+
31
+ ・クリティカル表 CR
32
+
33
+ ※通常の1D10などの10面ダイスにおいて出目10の読み替えはしません。コマンドのみです。
34
+
35
+ INFO_MESSAGE_TEXT
36
+ register_prefix('-?\d*AG', 'OM', 'NM', 'CR')
37
+
38
+ def eval_game_system_specific_command(command)
39
+ roll_ippan(command) || roll_hit_check(command) || roll_tables(command, TABLES)
40
+ end
41
+
42
+ private
43
+
44
+ def roll_ippan(command)
45
+ m = /^(-?\d+)?AG((?:[-+]\d+)*)$/.match(command)
46
+ return nil unless m
47
+
48
+ level = m[1].to_i
49
+ x = Arithmetic.eval(m[2], @round_type) || 0
50
+ target = level <= 0 ? 7 + x : 10 + level + x
51
+
52
+ dice_list = @randomizer.roll_barabara(2, 10).map { |d| d == 10 ? 0 : d }
53
+ total = dice_list.sum
54
+
55
+ return Result.new.tap do |result|
56
+ result.condition = total <= target
57
+
58
+ sequence = [
59
+ "(2D10<=#{target})",
60
+ "#{total}[#{dice_list.join(',')}]",
61
+ ("チャンス" if dice_list.include?(0)),
62
+ result.success? ? "成功" : "失敗"
63
+ ].compact
64
+
65
+ result.text = sequence.join(" > ")
66
+ end
67
+ end
68
+
69
+ # 命中判定&HR算出
70
+ def roll_hit_check(command)
71
+ parser = Command::Parser.new("OM", "NM", round_type: @round_type).enable_critical
72
+ parsed = parser.parse(command)
73
+ return nil unless parsed
74
+
75
+ if parsed.command == "OM"
76
+ return roll_om(parsed)
77
+ elsif parsed.command == "NM"
78
+ return roll_nm(parsed)
79
+ end
80
+ end
81
+
82
+ def roll_om(parsed)
83
+ target = parsed.modify_number
84
+ critical = parsed.critical || 0
85
+
86
+ dice_list = @randomizer.roll_barabara(2, 10).map { |v| v == 10 ? 0 : v }.sort.reverse
87
+
88
+ total = dice_list.sum()
89
+ criticals = dice_list.count { |v| v <= critical }
90
+ hr = calc_hr(target, dice_list)
91
+
92
+ return Result.new.tap do |r|
93
+ r.condition = total <= target
94
+ r.critical = criticals >= 1
95
+ r.text = [
96
+ "(2D10<=#{target})",
97
+ "#{total}[#{dice_list.join(',')}]",
98
+ ("チャンス" if dice_list.include?(0)),
99
+ r.success? ? "成功(HR=#{hr}、クリティカル#{criticals})" : "失敗",
100
+ ].compact.join(" > ")
101
+ end
102
+ end
103
+
104
+ def roll_nm(parsed)
105
+ target = parsed.modify_number
106
+ critical = parsed.critical || 0
107
+
108
+ dice_list = @randomizer.roll_barabara(3, 10).map { |v| v == 10 ? 0 : v }.sort.reverse
109
+
110
+ chosen_dice_list = dice_list.take(2)
111
+ total = chosen_dice_list.sum()
112
+ criticals = chosen_dice_list.count { |v| v <= critical }
113
+ hr = calc_hr(target, chosen_dice_list)
114
+
115
+ return Result.new.tap do |r|
116
+ r.condition = total <= target
117
+ r.critical = criticals >= 1
118
+ r.text = [
119
+ "(3D10<=#{target})",
120
+ "#{total}[#{dice_list[0]},#{dice_list[1]}&#{dice_list[2]}]",
121
+ ("チャンス" if chosen_dice_list.include?(0)),
122
+ r.success? ? "成功(HR=#{hr}、クリティカル#{criticals})" : "失敗",
123
+ ].compact.join(" > ")
124
+ end
125
+ end
126
+
127
+ def calc_hr(target, chosen_dice_list)
128
+ total = chosen_dice_list.sum()
129
+ a = (target - total).abs
130
+ b = (target - total - chosen_dice_list.count(0) * 10).abs
131
+ return [a, b].max
132
+ end
133
+
134
+ TABLES = {
135
+ "CR" => DiceTable::Table.new(
136
+ "クリティカル表",
137
+ "1D10",
138
+ [
139
+ "1:「小破」ダメージ+[5]。耐久値-[1]",
140
+ "2:「小破」ダメージ+[5]。耐久値-[1]",
141
+ "3:「小破」ダメージ+[5]。耐久値-[1]",
142
+ "4:「小破」ダメージ+[5]。耐久値-[1]",
143
+ "5:「兵装」損壊を受けるごとに[1D10]を振り、出目に応じた部位の兵装とオプションが《脱落》",
144
+ "6:「上体」攻撃系能力[白兵/ 火器/ 索敵]は各[- 損壊Lv]",
145
+ "7:「脚部」行動系・防御系能力[Iv 値(イニシア値)/ 最大MP/ 回避]は各[- 損壊Lv]",
146
+ "8:「搭乗者」搭乗者の〈最大HP〉および〈HP〉は[-(4 ×損壊Lv)]",
147
+ "9:「搭乗者」搭乗者の〈最大HP〉および〈HP〉は[-(4 ×損壊Lv)]",
148
+ "0:「小破」ダメージ+[5]。耐久値-[1]",
149
+ ]
150
+ )
151
+ }.freeze
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class Sengensyou < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'Sengensyou'
8
+
9
+ # ゲームシステム名
10
+ NAME = '千幻抄'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'せんけんしよう'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
+ ・SGS 命中判定・回避判定
18
+ INFO_MESSAGE_TEXT
19
+
20
+ register_prefix('SGS')
21
+
22
+ def eval_game_system_specific_command(command)
23
+ # 命中判定・回避判定
24
+ parser = Command::Parser.new('SGS', round_type: @round_type).restrict_cmp_op_to(nil)
25
+ command = parser.parse(command)
26
+
27
+ unless command
28
+ return nil
29
+ end
30
+
31
+ dice_list = @randomizer.roll_barabara(3, 6)
32
+ dice_total = dice_list.sum()
33
+ is_critical = dice_total >= 16
34
+ is_fumble = dice_total <= 5
35
+ additional_text =
36
+ if is_critical
37
+ "クリティカル"
38
+ elsif is_fumble
39
+ "ファンブル"
40
+ end
41
+ modify_text = "#{dice_total}#{Format.modifier(command.modify_number)}" if command.modify_number != 0
42
+ sequence = [
43
+ "(3D6#{Format.modifier(command.modify_number)})",
44
+ "#{dice_total}[#{dice_list.join(',')}]",
45
+ modify_text,
46
+ (dice_total + command.modify_number).to_s,
47
+ additional_text,
48
+ ].compact
49
+
50
+ result = Result.new.tap do |r|
51
+ r.text = sequence.join(" > ")
52
+ r.critical = is_critical
53
+ r.fumble = is_fumble
54
+ end
55
+ return result
56
+ end
57
+ end
58
+ end
59
+ end
@@ -39,7 +39,7 @@ module BCDice
39
39
  )
40
40
 
41
41
  def eval_game_system_specific_command(command)
42
- m = /^([A-Z]+)([+\-]?\d+)?(?:>=(\d+))?$/i.match(command)
42
+ m = /^([A-Z]+)([+-]?\d+)?(?:>=(\d+))?$/i.match(command)
43
43
  unless m
44
44
  return nil
45
45
  end
@@ -41,6 +41,7 @@ module BCDice
41
41
    /夏の終わりシーン表 NTST/培養プラントシーン表  PLST
42
42
    ・忍秘伝  中忍試験シーン表 HC/滅びの塔シーン表 HT/影の街でシーン表 HK
43
43
    /夜行列車シーン表 HY/病院シーン表 HO/龍動シーン表 HR/密室シーン表 HM/催眠シーン表 HS
44
+  ・ファンブル表(旧文庫版) OFT
44
45
  ・D66ダイスあり
45
46
  INFO_MESSAGE_TEXT
46
47
 
@@ -584,6 +585,18 @@ module BCDice
584
585
  'FT' => DiceTable::Table.new(
585
586
  'ファンブル表',
586
587
  '1D6',
588
+ [
589
+ '何か調子がおかしい。そのサイクルの間、すべての行為判定にマイナス1の修正がつく。',
590
+ 'しまった! 好きな忍具を1つ失ってしまう。',
591
+ '情報が漏れる! あなた以外のキャラクターは、あなたの持っている【秘密】か【居所】の中から、好きなものをそれぞれ一つ知ることができる。',
592
+ '油断した! 術の制御に失敗し、好きな【生命力】を1点失う。',
593
+ '敵の陰謀か? 罠にかかり、ランダムに選んだ変調一つを受ける。変調は、変調表で決定すること。',
594
+ 'ふう。危ないところだった。特に何も起こらない。',
595
+ ]
596
+ ),
597
+ 'OFT' => DiceTable::Table.new(
598
+ 'ファンブル表(旧文庫版)',
599
+ '1D6',
587
600
  [
588
601
  '何か調子がおかしい。そのサイクルの間、すべての行為判定にマイナス1の修正がつく。',
589
602
  'しまった! 好きな忍具を1つ失ってしまう。',
@@ -634,7 +647,7 @@ module BCDice
634
647
  '1D6',
635
648
  [
636
649
  '故障:すべての忍具が使用不能になる。この効果は累積しない。各サイクルの終了時に、《絡繰術》で行為判定を行い、成功するとこの変調は無効化される。',
637
- 'マヒ:修得している特技の中からランダムに一つを選び、その特技が使用不能になる。この効果は、修得している特技の数だけ累積する。各サイクルの終了時に、《身体操術l》で行為判定を行い、成功するとこの変調はすべて無効化される。',
650
+ 'マヒ:修得している特技の中からランダムに一つを選び、その特技が使用不能になる。この効果は、修得している特技の数だけ累積する。各サイクルの終了時に、《身体操術》で行為判定を行い、成功するとこの変調はすべて無効化される。',
638
651
  '重傷:命中判定、情報判定、感情判定を行うたびに、接近戦ダメージを1点受ける。この効果は累積しない。各サイクルの終了時に、《生存術》で行為判定を行い、成功するとこの変調は無効化される。',
639
652
  '行方不明:メインフェイズ中、自分以外がシーンプレイヤーのシーンに登場することができなくなる。この効果は累積しない。各サイクルの終了時に、《経済力》で行為判定を行い、成功するとこの変調は無効化される。',
640
653
  '忘却:修得している【感情】の中からランダムに一つを選び、その【感情】を持っていないものとして扱う。この効果は、修得している【感情】の数だけ累積する。各サイクルの終了時に、《記憶術》で行為判定を行い、成功するとこの変調はすべて無効化される。',