bcdice 3.11.0 → 3.13.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -0
  3. data/i18n/FutariSousa/ko_kr.yml +1625 -529
  4. data/i18n/Insane/ko_kr.yml +393 -258
  5. data/i18n/NinjaSlayer2/ja_jp.yml +34 -0
  6. data/lib/bcdice/arithmetic/parser.rb +4 -2
  7. data/lib/bcdice/base.rb +1 -1
  8. data/lib/bcdice/command/parser.rb +4 -2
  9. data/lib/bcdice/common_command/add_dice/parser.rb +4 -2
  10. data/lib/bcdice/common_command/barabara_dice/parser.rb +4 -2
  11. data/lib/bcdice/common_command/calc/parser.rb +4 -2
  12. data/lib/bcdice/common_command/reroll_dice/parser.rb +4 -2
  13. data/lib/bcdice/common_command/tally_dice/parser.rb +4 -2
  14. data/lib/bcdice/common_command/upper_dice/parser.rb +4 -2
  15. data/lib/bcdice/game_system/Airgetlamh.rb +1 -1
  16. data/lib/bcdice/game_system/Alsetto.rb +2 -2
  17. data/lib/bcdice/game_system/AniMalus.rb +221 -0
  18. data/lib/bcdice/game_system/ArknightsFan.rb +182 -0
  19. data/lib/bcdice/game_system/Avandner.rb +1 -1
  20. data/lib/bcdice/game_system/BBN.rb +1 -1
  21. data/lib/bcdice/game_system/BadLife.rb +3 -3
  22. data/lib/bcdice/game_system/BarnaKronika.rb +1 -1
  23. data/lib/bcdice/game_system/Chill3.rb +6 -6
  24. data/lib/bcdice/game_system/DarkSouls.rb +1 -1
  25. data/lib/bcdice/game_system/Elric.rb +1 -1
  26. data/lib/bcdice/game_system/Emoklore.rb +4 -6
  27. data/lib/bcdice/game_system/FullFace.rb +92 -0
  28. data/lib/bcdice/game_system/FutariSousa_Korean.rb +44 -19
  29. data/lib/bcdice/game_system/HunterTheReckoning5th.rb +10 -3
  30. data/lib/bcdice/game_system/InfiniteFantasia.rb +4 -1
  31. data/lib/bcdice/game_system/Insane_Korean.rb +11 -11
  32. data/lib/bcdice/game_system/Irisbane.rb +1 -1
  33. data/lib/bcdice/game_system/KamitsubakiCityUnderConstructionNarrative.rb +251 -0
  34. data/lib/bcdice/game_system/KillDeathBusiness.rb +1 -1
  35. data/lib/bcdice/game_system/KyokoShinshoku.rb +158 -0
  36. data/lib/bcdice/game_system/Liminal.rb +136 -0
  37. data/lib/bcdice/game_system/MetalHead.rb +1 -1
  38. data/lib/bcdice/game_system/MetalHeadExtream.rb +1 -1
  39. data/lib/bcdice/game_system/NRR.rb +122 -0
  40. data/lib/bcdice/game_system/NSSQ.rb +1 -1
  41. data/lib/bcdice/game_system/NightWizard.rb +1 -1
  42. data/lib/bcdice/game_system/NightWizard3rd.rb +15 -2
  43. data/lib/bcdice/game_system/NinjaSlayer.rb +3 -1
  44. data/lib/bcdice/game_system/NinjaSlayer2.rb +299 -0
  45. data/lib/bcdice/game_system/OneWayHeroics.rb +1 -1
  46. data/lib/bcdice/game_system/PastFutureParadox.rb +1238 -0
  47. data/lib/bcdice/game_system/Postman.rb +3 -3
  48. data/lib/bcdice/game_system/RecordOfSteam.rb +1 -1
  49. data/lib/bcdice/game_system/RuneQuestRoleplayingInGlorantha.rb +10 -7
  50. data/lib/bcdice/game_system/Ryutama.rb +4 -4
  51. data/lib/bcdice/game_system/SajinsenkiAGuS.rb +5 -1
  52. data/lib/bcdice/game_system/SajinsenkiAGuS2E.rb +285 -0
  53. data/lib/bcdice/game_system/Siren.rb +97 -0
  54. data/lib/bcdice/game_system/Skynauts.rb +1 -1
  55. data/lib/bcdice/game_system/SkynautsBouken.rb +1 -1
  56. data/lib/bcdice/game_system/Strave.rb +1 -1
  57. data/lib/bcdice/game_system/SwordWorld.rb +16 -0
  58. data/lib/bcdice/game_system/SwordWorld2_5.rb +8 -1
  59. data/lib/bcdice/game_system/TherapieSein.rb +1 -1
  60. data/lib/bcdice/game_system/TrinitySeven.rb +1 -1
  61. data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +21 -9
  62. data/lib/bcdice/game_system/WerewolfTheApocalypse5th.rb +179 -0
  63. data/lib/bcdice/game_system/cthulhu7th/full_auto.rb +1 -1
  64. data/lib/bcdice/game_system/sword_world/rating_options.rb +3 -0
  65. data/lib/bcdice/game_system/sword_world/rating_parsed.rb +9 -0
  66. data/lib/bcdice/game_system/sword_world/rating_parser.rb +177 -130
  67. data/lib/bcdice/game_system/sword_world/transcendent_test.rb +1 -1
  68. data/lib/bcdice/game_system.rb +12 -0
  69. data/lib/bcdice/loader.rb +1 -1
  70. data/lib/bcdice/version.rb +1 -1
  71. metadata +32 -5
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class KamitsubakiCityUnderConstructionNarrative < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'KamitsubakiCityUnderConstructionNarrative'
8
+
9
+ # ゲームシステム名
10
+ NAME = '神椿市建設中。NARRATIVE'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'かみつはきしけんせつちゆうならていふ'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
+ ・可組(KA)
18
+  KA6 行動判定
19
+  KA8 技能ロール
20
+  KA10 特技ロール
21
+  KA12 Aロール
22
+
23
+ ・裏組(RI)
24
+  RI6 行動判定
25
+  RI8 技能ロール
26
+  RI10 特技ロール
27
+  RI12 Aロール
28
+
29
+ ・羽組(HA)
30
+  HA6 行動判定
31
+  HA8 技能ロール
32
+  HA10 特技ロール
33
+  HA12 Aロール
34
+
35
+ ・星組(SE)
36
+  SE6 行動判定
37
+  SE8 技能ロール
38
+  SE10 特技ロール
39
+  SE12 Aロール
40
+
41
+ ・狐組(CO)
42
+  CO6 行動判定
43
+  CO8 技能ロール
44
+  CO10 特技ロール
45
+  CO12 Aロール
46
+
47
+ ・GM用
48
+  GM6 (成否判定なし)
49
+  GM8 技能ロール
50
+  GM10 特技ロール
51
+  Q12 Qロール
52
+
53
+ ・存在証明 EXI<=x
54
+  存在証明の判定を行う
55
+  x: 存在値
56
+ INFO_MESSAGE_TEXT
57
+
58
+ def eval_game_system_specific_command(command)
59
+ roll_kumi(command) || roll_existence(command)
60
+ end
61
+
62
+ private
63
+
64
+ def roll_kumi(command)
65
+ table = TABLES[command]
66
+ unless table
67
+ return nil
68
+ end
69
+
70
+ return table.roll(@randomizer)
71
+ end
72
+
73
+ class KumiDice
74
+ def initialize(items)
75
+ @items = items.freeze
76
+ end
77
+
78
+ CRITICAL = "M"
79
+ FUMBLE = "Q"
80
+
81
+ def roll(randomizer)
82
+ dice = randomizer.roll_once(@items.length)
83
+ chosen = @items[dice - 1]
84
+
85
+ fumble = chosen == FUMBLE
86
+ critical = chosen == CRITICAL
87
+
88
+ result_tail =
89
+ if fumble
90
+ "ファンブル"
91
+ elsif critical
92
+ "マジック"
93
+ elsif !chosen.empty?
94
+ "成功"
95
+ else
96
+ "失敗"
97
+ end
98
+
99
+ Result.new.tap do |r|
100
+ r.critical = critical
101
+ r.fumble = fumble
102
+ r.condition = !chosen.empty? && !r.fumble?
103
+ r.text = [
104
+ "(D#{@items.length})",
105
+ dice,
106
+ chosen.empty? ? nil : chosen,
107
+ result_tail
108
+ ].compact.join(" > ")
109
+ end
110
+ end
111
+ end
112
+
113
+ class KumiD6
114
+ def initialize(success_symbol)
115
+ @success_symbol = success_symbol
116
+ end
117
+
118
+ TABLE = ["裏", "羽", "星", "狐", "可", "Q"].freeze
119
+
120
+ def roll(randomizer)
121
+ dice = randomizer.roll_once(6)
122
+ chosen = TABLE[dice - 1]
123
+
124
+ Result.new.tap do |r|
125
+ unless @success_symbol.nil?
126
+ r.fumble = chosen == "Q"
127
+ r.condition = chosen == @success_symbol
128
+ end
129
+
130
+ result_tail =
131
+ if r.fumble?
132
+ "ファンブル"
133
+ elsif r.success?
134
+ "成功"
135
+ elsif r.failure?
136
+ "失敗"
137
+ end
138
+
139
+ r.text = [
140
+ "(D6)",
141
+ dice,
142
+ chosen,
143
+ result_tail
144
+ ].compact.join(" > ")
145
+ end
146
+ end
147
+ end
148
+
149
+ class QDice
150
+ def initialize(items)
151
+ @items = items.freeze
152
+ end
153
+
154
+ CRITICAL = "M"
155
+
156
+ def roll(randomizer)
157
+ dice = randomizer.roll_once(@items.length)
158
+ chosen = @items[dice - 1]
159
+
160
+ critical = chosen == CRITICAL
161
+
162
+ result_tail =
163
+ if critical
164
+ "マジック"
165
+ elsif !chosen.empty?
166
+ "成功"
167
+ else
168
+ "失敗"
169
+ end
170
+
171
+ Result.new.tap do |r|
172
+ r.critical = critical
173
+ r.condition = !chosen.empty?
174
+ r.text = [
175
+ "(D#{@items.length})",
176
+ dice.to_s,
177
+ chosen.empty? ? nil : chosen,
178
+ result_tail,
179
+ ].compact.join(" > ")
180
+ end
181
+ end
182
+ end
183
+
184
+ def roll_existence(command)
185
+ m = /^EXI<=(\d+)$/.match(command)
186
+ unless m
187
+ return nil
188
+ end
189
+
190
+ target = m[1].to_i
191
+ dice = @randomizer.roll_once(20)
192
+ Result.new.tap do |r|
193
+ r.critical = dice == 1
194
+ r.fumble = dice == 20
195
+ r.condition = (dice <= target && !r.fumble?) || r.critical?
196
+
197
+ result_tail =
198
+ if r.critical?
199
+ "M > マジック"
200
+ elsif r.fumble?
201
+ "Q > ファンブル"
202
+ elsif r.success?
203
+ "成功"
204
+ else
205
+ "失敗"
206
+ end
207
+
208
+ r.text = [
209
+ "(D20<=#{target})",
210
+ dice,
211
+ result_tail
212
+ ].join(" > ")
213
+ end
214
+ end
215
+
216
+ TABLES = {
217
+ "KA6" => KumiD6.new("可"),
218
+ "KA8" => KumiDice.new(["Q", "", "", "", "可", "可", "可", "M"]),
219
+ "KA10" => KumiDice.new(["Q", "", "", "可", "可", "可", "可", "可", "M", "M"]),
220
+ "KA12" => KumiDice.new(["Q", "", "", "可", "可", "可", "可", "可", "可", "可", "M", "M"]),
221
+
222
+ "RI6" => KumiD6.new("裏"),
223
+ "RI8" => KumiDice.new(["Q", "", "", "", "裏", "裏", "裏", "M"]),
224
+ "RI10" => KumiDice.new(["Q", "", "", "裏", "裏", "裏", "裏", "裏", "M", "M"]),
225
+ "RI12" => KumiDice.new(["M", "M", "裏", "裏", "裏", "裏", "裏", "裏", "裏", "", "", "Q"]),
226
+
227
+ "HA6" => KumiD6.new("羽"),
228
+ "HA8" => KumiDice.new(["Q", "", "", "", "羽", "羽", "羽", "M"]),
229
+ "HA10" => KumiDice.new(["Q", "", "", "羽", "羽", "羽", "羽", "羽", "M", "M"]),
230
+ "HA12" => KumiDice.new(["Q", "Q", "羽", "羽", "羽", "", "", "", "M", "M", "M", "M"]),
231
+
232
+ "SE6" => KumiD6.new("星"),
233
+ "SE8" => KumiDice.new(["Q", "", "", "", "星", "星", "星", "M"]),
234
+ "SE10" => KumiDice.new(["Q", "", "", "星", "星", "星", "星", "星", "M", "M"]),
235
+ "SE12" => KumiDice.new(["星", "", "星", "星", "M", "Q", "M", "星", "星", "星", "", "星"]),
236
+
237
+ "CO6" => KumiD6.new("狐"),
238
+ "CO8" => KumiDice.new(["Q", "", "", "", "狐", "狐", "狐", "M"]),
239
+ "CO10" => KumiDice.new(["Q", "", "", "狐", "狐", "狐", "狐", "狐", "M", "M"]),
240
+ "CO12" => KumiDice.new(["Q", "", "", "狐狐狐", "狐狐", "狐", "狐狐狐", "狐狐", "狐", "狐", "M", "M"]),
241
+
242
+ "GM6" => KumiD6.new(nil),
243
+ "GM8" => KumiDice.new(["Q", "", "", "", "W", "W", "W", "M"]),
244
+ "GM10" => KumiDice.new(["Q", "", "", "W", "W", "W", "W", "W", "M", "M"]),
245
+ "Q12" => QDice.new(["", "", "", "Q", "Q", "Q", "Q", "Q", "Q", "Q", "M", "M"])
246
+ }.freeze
247
+
248
+ register_prefix("EXI", TABLES.keys)
249
+ end
250
+ end
251
+ end
@@ -101,7 +101,7 @@ module BCDice
101
101
  target = 5
102
102
  end
103
103
 
104
- if fumble < 2
104
+ if fumble < 2
105
105
  fumble = 2
106
106
  elsif fumble > 11
107
107
  result += "【#{command}】 > #{translate('KillDeathBusiness.JD.warning.over_fumble')}\n"
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class KyokoShinshoku < Base
6
+ # ゲームシステムの識別子
7
+ ID = "KyokoShinshoku"
8
+
9
+ # ゲームシステム名
10
+ NAME = "虚構侵蝕TRPG"
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = "きよこうしんしよくTRPG"
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~MESSAGETEXT
17
+ ・判定
18
+  ダイスを指定数ダイスロールして、最も高い出目を出力します。難易度を指定すると成否を判定します。
19
+ KS(x,y)
20
+ x:ダイスサイズ。1=D4(能力値1、2以上の出目が出ていたとしても最大1)/2=D4(能力値2、3以上の出目が出ていたとしても最大2)/3=D4(能力値3、出目4が出ていたとしても最大3)/4=D4/6=D6/8=D8/10=D10/12=D12/20=D20
21
+ y:ダイス数(省略:1)
22
+
23
+ KS(x,y)>=z
24
+ x:ダイスサイズ。1=D4(能力値1、2以上の出目が出ていたとしても最大1)/2=D4(能力値2、3以上の出目が出ていたとしても最大2)/3=D4(能力値3、出目4が出ていたとしても最大3)/4=D4/6=D6/8=D8/10=D10/12=D12/20=D20
25
+ y:ダイス数(省略:1)
26
+ z:難易度
27
+
28
+ ・観測ロール
29
+  [現実乖離]の段階に応じたダイスを指定数ダイスロールして、最も高い出目を出力します。
30
+ KR(x)
31
+ x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
32
+
33
+ KR(x,y) 観測ロール(リアリティラインあり)
34
+ x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
35
+ y=[リアリティライン]のレベル(3=1個/2=2個/1=3個)
36
+
37
+ ・虚構の収束の侵蝕度減少ロール
38
+  [現実乖離]の段階に応じたダイスを指定数ダイスロールして、その合計を出力します。
39
+ KRS(x,y)
40
+ x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
41
+ y=ダイスの個数
42
+ MESSAGETEXT
43
+
44
+ register_prefix('KS', 'KR', 'KRS')
45
+
46
+ def eval_game_system_specific_command(command)
47
+ roll_check(command) || roll_kansoku(command) || roll_shusoku(command)
48
+ end
49
+
50
+ private
51
+
52
+ DICE_SIZE_TO_SIDES = {
53
+ 1 => 4,
54
+ 2 => 4,
55
+ 3 => 4,
56
+ 4 => 4,
57
+ 6 => 6,
58
+ 8 => 8,
59
+ 10 => 10,
60
+ 12 => 12,
61
+ 20 => 20,
62
+ }.freeze
63
+
64
+ def roll_check(command)
65
+ m = /^KS(?:\((\d+),([-+\d]+)?\)|(\d+))(?:>=([-+\d]+))?$/.match(command)
66
+ return nil unless m
67
+
68
+ dice_size = m[1]&.to_i || m[3].to_i
69
+ times = m[2] ? Arithmetic.eval(m[2], @round_type) : 1
70
+ target = m[4] && Arithmetic.eval(m[4], @round_type)
71
+
72
+ sides = DICE_SIZE_TO_SIDES[dice_size]
73
+
74
+ return nil if sides.nil? || times.nil?
75
+
76
+ dice_list = @randomizer.roll_barabara(times, sides).sort
77
+ value = dice_list.max.clamp(1, dice_size)
78
+
79
+ result =
80
+ if value == 1
81
+ Result.fumble("ファンブル")
82
+ elsif target && value < target
83
+ Result.failure("失敗")
84
+ elsif target && value == sides
85
+ Result.critical("クリティカル")
86
+ elsif target && value >= target
87
+ Result.success("成功")
88
+ else
89
+ Result.new()
90
+ end
91
+
92
+ result.text = [
93
+ target ? "(KS(#{dice_size},#{times})>=#{target})" : "(KS(#{dice_size},#{times}))",
94
+ ("#{value}[#{dice_list.join(',')}]" if times > 1),
95
+ value,
96
+ result.text,
97
+ ].compact.join(" > ")
98
+
99
+ return result
100
+ end
101
+
102
+ GENJITU_KAIRI_TO_SIDES = [4, 6, 8, 10, 12, 20].freeze
103
+ REALITY_LINE_TO_TIMES = {
104
+ 3 => 1,
105
+ 2 => 2,
106
+ 1 => 3,
107
+ }.freeze
108
+
109
+ def roll_kansoku(command)
110
+ m = /^KR(?:(\d+)|\((\d),(\d)\))$/.match(command)
111
+ return nil unless m
112
+
113
+ dice_size = m[1]&.to_i || m[2].to_i
114
+ reality_line = m[3]&.to_i
115
+
116
+ if reality_line && (reality_line > 3 || reality_line < 1)
117
+ return nil
118
+ end
119
+
120
+ sides = GENJITU_KAIRI_TO_SIDES[dice_size - 1]
121
+ times = REALITY_LINE_TO_TIMES[reality_line] || 1
122
+
123
+ return nil unless sides
124
+
125
+ dice_list = @randomizer.roll_barabara(times, sides).sort
126
+ value = dice_list.max
127
+
128
+ cmd = reality_line ? "KR(#{dice_size},#{reality_line})" : "KR(#{dice_size})"
129
+
130
+ if times == 1
131
+ "(#{cmd}) > #{value}"
132
+ else
133
+ "(#{cmd}) > #{value}[#{dice_list.join(',')}] > #{value}"
134
+ end
135
+ end
136
+
137
+ def roll_shusoku(command)
138
+ m = /^KRS(?:\((\d),([-+\d]+)\))$/.match(command)
139
+ return nil unless m
140
+
141
+ dice_size = m[1].to_i
142
+ times = m[2] && Arithmetic.eval(m[2], @round_type)
143
+
144
+ sides = GENJITU_KAIRI_TO_SIDES[dice_size - 1]
145
+ return nil if sides.nil? || times.nil?
146
+
147
+ dice_list = @randomizer.roll_barabara(times, sides)
148
+ value = dice_list.sum
149
+
150
+ if times == 1
151
+ "(KRS(#{dice_size},#{times})) > #{value}"
152
+ else
153
+ "(KRS(#{dice_size},#{times})) > #{value}[#{dice_list.join(',')}] > #{value}"
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class Liminal < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'Liminal'
8
+
9
+ # ゲームシステム名
10
+ NAME = 'リミナル'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'りみなる'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGETEXT
17
+ ■技能判定 LMx+b>=t+m x:技能レベル b:ボーナス t:難易度 m:敵の技能レベル(対抗判定)
18
+
19
+ 例)LM2>=8: 技能レベル2,難易度8で技能判定し、その結果を表示。(クリティカル成功も表示)
20
+ LM3+2>=9:技能レベル3,ボーナス+2,難易度9で技能判定し、その結果を表示。( 〃 )
21
+ LM0>=8: 技能なし,難易度8で技能判定する。(難易度+2は自動的に足されます)
22
+
23
+ ■イニシアティヴ判定 LIx+b>=t+m x:認識力レベル b:ボーナス t:難易度 m:敵の認識力レベル
24
+ 例)LI2>=8+2: 認識力レベル2,難易度8,敵認識力レベル2で技能判定し、その結果を表示。
25
+ LI0>=8+2: 認識力なし,難易度8,敵認識力レベル2で技能判定する。(難易度加算なし)
26
+ INFO_MESSAGETEXT
27
+
28
+ register_prefix("LI", "LM")
29
+
30
+ def eval_game_system_specific_command(command)
31
+ resolute_action(command) || resolute_initiative(command)
32
+ end
33
+
34
+ private
35
+
36
+ # 技能判定
37
+ # @param [String] command
38
+ # @return [Result]
39
+ def resolute_action(command)
40
+ parser = Command::Parser.new("LM", round_type: @round_type)
41
+ .has_suffix_number
42
+ .restrict_cmp_op_to(:>=)
43
+ parsed = parser.parse(command)
44
+ return nil unless parsed
45
+
46
+ skill_level = parsed.suffix_number
47
+ bonus = parsed.modify_number
48
+ difficulty = parsed.target_number
49
+
50
+ dice = @randomizer.roll_barabara(2, 6)
51
+ dice_total = dice.sum
52
+ total = dice_total + skill_level + bonus
53
+ difficulty += 2 if skill_level == 0
54
+
55
+ return Result.new.tap do |result|
56
+ result.condition = (total >= difficulty)
57
+ result.critical = (total >= difficulty + 5)
58
+ if dice_total == 2
59
+ result.fumble = true
60
+ result.critical = false
61
+ result.condition = false
62
+ end
63
+
64
+ sequence = [
65
+ "(LM#{skill_level}#{with_symbol(bonus)}>=#{difficulty})",
66
+ "#{dice_total}[#{dice.join(',')}]#{with_symbol(skill_level + bonus)}",
67
+ total.to_s,
68
+ if result.fumble?
69
+ "1ゾロ"
70
+ elsif result.critical?
71
+ "クリティカル"
72
+ else
73
+ result.success? ? "成功" : "失敗"
74
+ end
75
+ ].compact
76
+
77
+ result.text = sequence.join(" > ")
78
+ end
79
+ end
80
+
81
+ def with_symbol(number)
82
+ if number == 0
83
+ return "+0"
84
+ elsif number > 0
85
+ return "+#{number}"
86
+ else
87
+ return number.to_s
88
+ end
89
+ end
90
+
91
+ # イニシアティヴ判定
92
+ # @param [String] command
93
+ # @return [Result]
94
+ def resolute_initiative(command)
95
+ parser = Command::Parser.new("LI", round_type: @round_type)
96
+ .has_suffix_number
97
+ .restrict_cmp_op_to(:>=)
98
+ parsed = parser.parse(command)
99
+ return nil unless parsed
100
+
101
+ skill_level = parsed.suffix_number
102
+ bonus = parsed.modify_number
103
+ difficulty = parsed.target_number
104
+
105
+ dice = @randomizer.roll_barabara(2, 6)
106
+ dice_total = dice.sum
107
+ total = dice_total + skill_level + bonus
108
+
109
+ return Result.new.tap do |result|
110
+ result.condition = (total >= difficulty)
111
+ result.critical = (total >= difficulty + 5)
112
+ if dice_total == 2
113
+ result.fumble = true
114
+ result.critical = false
115
+ result.condition = false
116
+ end
117
+
118
+ sequence = [
119
+ "(LI#{skill_level}#{with_symbol(bonus)}>=#{difficulty})",
120
+ "#{dice_total}[#{dice.join(',')}]#{with_symbol(skill_level + bonus)}",
121
+ total.to_s,
122
+ if result.fumble?
123
+ "1ゾロ"
124
+ elsif result.critical?
125
+ "クリティカル"
126
+ else
127
+ result.success? ? "成功" : "失敗"
128
+ end
129
+ ].compact
130
+
131
+ result.text = sequence.join(" > ")
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -151,7 +151,7 @@ module BCDice
151
151
  'D' => [{'LW' => 2}, {'MW' => 26}, {'HW' => 46}, {'MO' => 76}, {'K' => 96}],
152
152
  'E' => [{'LW' => 2}, {'MW' => 26}, {'HW' => 39}, {'MO' => 54}, {'K' => 76}],
153
153
  'F' => [{'LW' => 2}, {'MW' => 16}, {'HW' => 39}, {'MO' => 54}, {'K' => 66}],
154
- 'G' => [{'LW' => 2}, {'MW' => 6}, {'HW' => 16}, {'MO' => 26}, {'K' => 39}],
154
+ 'G' => [{'LW' => 2}, {'MW' => 6}, {'HW' => 16}, {'MO' => 26}, {'K' => 39}],
155
155
  'M' => [{'0' => 2}, {'1' => 22}, {'2' => 42}, {'3' => 62}, {'4' => 82}, {'5' => 92}, {'6' => 102}, {'8' => 112}],
156
156
  }
157
157
 
@@ -68,7 +68,7 @@ module BCDice
68
68
  type = m[1]
69
69
  target = m[2].to_i
70
70
  modify = get_value(1, m[3])
71
- paramText = (m[5] || '')
71
+ paramText = m[5] || ''
72
72
  isMuse = !m[8].nil? # パンドラ《ミューズ》
73
73
 
74
74
  accidentValue = 96
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class NRR < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'NRR'
8
+
9
+ # ゲームシステム名
10
+ NAME = 'nRR'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'えぬああるあある'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGETEXT
17
+ ▪️判定
18
+ ・ノーマルダイス NR8
19
+ ・有利ダイス NR10
20
+ ・不利ダイス NR6
21
+ ・Exダイス NR12
22
+
23
+ ダイスの個数を指定しての判定ができます。
24
+ 例:有利ダイス2個で判定 2NR10
25
+
26
+ ▪️判定結果とシンボル
27
+ ⭕:成功
28
+ ❌:失敗
29
+ ✨:クリティカル(大成功)
30
+ 💀:ファンブル(大失敗)
31
+ 🌈:ミラクル(奇跡)
32
+ INFO_MESSAGETEXT
33
+
34
+ register_prefix('\d*NR(6|8|10|12)')
35
+
36
+ def initialize(command)
37
+ super(command)
38
+
39
+ @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
40
+ end
41
+
42
+ def eval_game_system_specific_command(command)
43
+ roll_nr(command)
44
+ end
45
+
46
+ private
47
+
48
+ def roll_nr(command)
49
+ m = /^(\d+)?NR(6|8|10|12)$/.match(command)
50
+ return nil unless m
51
+
52
+ times = m[1]&.to_i || 1
53
+ table = case m[2]
54
+ when "6"
55
+ DISADVANTAGE
56
+ when "8"
57
+ NORMAL
58
+ when "10"
59
+ ADVANTAGE
60
+ else
61
+ EXTRA
62
+ end
63
+
64
+ values = @randomizer.roll_barabara(times, table.size)
65
+ result = Result.new
66
+ text =
67
+ if times == 1
68
+ level = table[values[0] - 1]
69
+ result.condition = SUCCESSES.include?(level)
70
+ result.fumble = level == :fumble
71
+ result.critical = CRITICALS.include?(level)
72
+
73
+ "#{ICON[level]} #{RESULT_LABEL[level]}"
74
+ else
75
+ levels = values.map { |v| table[v - 1] }
76
+ values_count = levels
77
+ .group_by(&:itself)
78
+ .transform_values(&:length)
79
+
80
+ values_count_strs = LEVELS.map do |l|
81
+ count = values_count.fetch(l, 0)
82
+ next nil if count == 0
83
+
84
+ "#{ICON[l]} #{count}"
85
+ end
86
+
87
+ values_count_strs.compact.join(", ")
88
+ end
89
+
90
+ times_str = times == 1 ? nil : times
91
+ result.text = "(#{times_str}NR#{m[2]}) > #{values.join(',')} > #{text}"
92
+
93
+ result
94
+ end
95
+
96
+ LEVELS = [:fumble, :failure, :success, :critical, :miracle].freeze
97
+ SUCCESSES = [:success, :critical, :miracle].freeze
98
+ CRITICALS = [:critical, :miracle].freeze
99
+
100
+ DISADVANTAGE = [:fumble, :fumble, :failure, :failure, :success, :success].freeze
101
+ NORMAL = [:fumble, :failure, :failure, :failure, :success, :success, :success, :critical].freeze
102
+ ADVANTAGE = [:fumble, :failure, :failure, :success, :success, :success, :success, :success, :critical, :critical].freeze
103
+ EXTRA = [:fumble, :fumble, :fumble, :failure, :success, :success, :critical, :critical, :critical, :critical, :miracle, :miracle].freeze
104
+
105
+ ICON = {
106
+ fumble: "💀",
107
+ failure: "❌",
108
+ success: "⭕️",
109
+ critical: "✨",
110
+ miracle: "🌈",
111
+ }.freeze
112
+
113
+ RESULT_LABEL = {
114
+ fumble: "ファンブル(大失敗)",
115
+ failure: "失敗",
116
+ success: "成功",
117
+ critical: "クリティカル(大成功)",
118
+ miracle: "ミラクル(奇跡)",
119
+ }.freeze
120
+ end
121
+ end
122
+ end