bcdice 3.13.0 → 3.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/i18n/Arianrhod/ko_kr.yml +3 -0
  4. data/i18n/Cthulhu/en_us.yml +11 -0
  5. data/i18n/CyberpunkRed/ja_jp.yml +389 -0
  6. data/i18n/FinalFantasyXIV/en_us.yml +4 -0
  7. data/i18n/FinalFantasyXIV/ja_jp.yml +4 -0
  8. data/i18n/FutariSousa/ja_jp.yml +158 -1
  9. data/i18n/KizunaBullet/ja_jp.yml +653 -0
  10. data/i18n/MonotoneMuseum/ja_jp.yml +246 -14
  11. data/i18n/SkynautsBouken/ja_jp.yml +114 -0
  12. data/i18n/TensaiGunshiNiNaro/ja_jp.yml +126 -0
  13. data/i18n/UnsungDuet/ja_jp.yml +62 -0
  14. data/i18n/UnsungDuet/ko_kr.yml +62 -0
  15. data/i18n/en_us.yml +5 -0
  16. data/lib/bcdice/dice_table/range_table.rb +24 -0
  17. data/lib/bcdice/game_system/Agnostos.rb +248 -0
  18. data/lib/bcdice/game_system/AniMalus.rb +99 -59
  19. data/lib/bcdice/game_system/Arianrhod_Korean.rb +30 -0
  20. data/lib/bcdice/game_system/BlackJacket.rb +244 -0
  21. data/lib/bcdice/game_system/ConvictorDrive.rb +5 -4
  22. data/lib/bcdice/game_system/Cthulhu_English.rb +59 -0
  23. data/lib/bcdice/game_system/CyberpunkRed.rb +14 -4
  24. data/lib/bcdice/game_system/DivineCharger.rb +841 -0
  25. data/lib/bcdice/game_system/FinalFantasyXIV.rb +115 -0
  26. data/lib/bcdice/game_system/FinalFantasyXIV_English.rb +39 -0
  27. data/lib/bcdice/game_system/FullFace.rb +39 -10
  28. data/lib/bcdice/game_system/FutariSousa.rb +88 -8
  29. data/lib/bcdice/game_system/Insane_Korean.rb +1 -1
  30. data/lib/bcdice/game_system/InvisibleLiar.rb +79 -0
  31. data/lib/bcdice/game_system/KizunaBullet.rb +240 -0
  32. data/lib/bcdice/game_system/KyokoShinshoku.rb +51 -8
  33. data/lib/bcdice/game_system/MonotoneMuseum.rb +14 -1
  34. data/lib/bcdice/game_system/NRR.rb +2 -2
  35. data/lib/bcdice/game_system/ShuumatsuBargainWars.rb +203 -0
  36. data/lib/bcdice/game_system/SkynautsBouken.rb +45 -130
  37. data/lib/bcdice/game_system/SwordWorld.rb +1 -1
  38. data/lib/bcdice/game_system/TensaiGunshiNiNaro.rb +228 -0
  39. data/lib/bcdice/game_system/TheOneRing2nd.rb +406 -0
  40. data/lib/bcdice/game_system/TheUnofficialHollowKnightRPG.rb +185 -0
  41. data/lib/bcdice/game_system/TrailOfCthulhu.rb +139 -0
  42. data/lib/bcdice/game_system/UnsungDuet.rb +17 -75
  43. data/lib/bcdice/game_system/UnsungDuet_Korean.rb +41 -0
  44. data/lib/bcdice/game_system/Utakaze.rb +55 -2
  45. data/lib/bcdice/game_system/Warhammer4.rb +124 -3
  46. data/lib/bcdice/game_system/Yotabana.rb +62 -0
  47. data/lib/bcdice/game_system/cyberpunk_red/tables.rb +111 -473
  48. data/lib/bcdice/game_system/kizuna_bullet/tables.rb +171 -0
  49. data/lib/bcdice/game_system.rb +16 -0
  50. data/lib/bcdice/version.rb +1 -1
  51. metadata +30 -2
@@ -0,0 +1,406 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class TheOneRing2nd < Base
6
+ # ゲームシステムの識別子
7
+ ID = "TheOneRing2nd"
8
+
9
+ # ゲームシステム名
10
+ NAME = "一つの指輪:指輪物語TRPG2版"
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = "ひとつのゆひわゆひわものかたりTRPG2"
14
+
15
+ HELP_MESSAGE = <<~TEXT
16
+ ・判定コマンド(nRG[x][@y][Az][f[0|1]][i[0|1]][w[0|1]][m[0|1]])
17
+ 判定用に難易度nを指定して判定ダイスを振る。技量ダイスx、痛打判定値y、修正値zを指定可能。
18
+ 技量ダイス、痛打判定値、修正値は0、または未指定(0と同じ)にできる。
19
+ 痛打判定値の0、未指定は痛打判定を行わない。
20
+ 修正値は判定合計値に加算され、「ガンダルフ・ルーン」や「サウロンの目」はその影響を受けない。
21
+ 例1: 13RG (難易度13 技量ダイス0個)
22
+ 例2: 13RG3 (難易度13 技量ダイス3個)
23
+ 例3: 13RG3@10A1 (難易度13 技量ダイス3個、痛打判定10、結果に1を加算)
24
+
25
+ ・表用コマンド(FD[x][f[0|1]][i[0|1]])
26
+ 表用に判定ダイスを振る。修正値xが指定可能。修正値は0、あるいは未指定(0と同じ)にできる。
27
+ 「ガンダルフ・ルーン」や「サウロンの目」は修正値の影響を受けず、値が10を越えることもない。
28
+ 例1: FD (1d12で判定)
29
+ 例2: FD1 (1d12で判定し、ダイス目に+1修正)
30
+
31
+ ・コマンドオプション
32
+ オプションは、判定コマンドなら4個まで、表用コマンドなら2個まで、順不同で指定可能(重複可)。
33
+ f: 有利(favoured)オプション。不利と同時指定時は相殺。選択された値に◎。
34
+ i: 不利(ill-favoured)オプション。有利と同時指定時は相殺。選択された値に◎。
35
+ 例1: 13RG3f (難易度13 技量ダイス3個、有利)
36
+ 例2: FD1f (1修正、有利)
37
+ 例3: 13RG3if (難易度13 技量ダイス3個、不利、有利)
38
+ ※有利/不利は相殺。
39
+
40
+ 判定コマンドでは更に下記のオプションを同じ条件で指定可能。
41
+ w: 疲労(weary)状態オプション。
42
+ m: 絶望(miserable)状態オプション。
43
+ 例1: 13RG3wf (難易度13 技量ダイス3個、疲労状態、有利)
44
+ 例2: 13RG3fiwm (難易度13 技量ダイス3個、有利、不利、疲労状態、絶望状態)
45
+ ※有利/不利は相殺。最大オプション数である4つを指定。
46
+
47
+ ・オプションスイッチ
48
+ 指定したオプションのon/offを1/0で指定可能。1はon、0はoffを表す。
49
+ 複数の同じオプションへのスイッチ指定は、最後のスイッチが有効となる。
50
+ 例1: 13RG3if0 (難易度13 技量ダイス3個、不利はon、有利はoff)
51
+ ※ 有利指定がoffのため、相殺されず不利となる。
52
+ 例2: 13RG3f1f0 (難易度13 技量ダイス3個、有利は最終的にoff)
53
+ TEXT
54
+
55
+ register_prefix('\d+RG', 'FD')
56
+
57
+ SAURONS_EYE_NUMBER = 11 # サウロンの目
58
+ GANDALF_RUNE_NUMBER = 12 # ガンダルフ・ルーン
59
+
60
+ CHOICE_DIE_MARK = '◎' # 有利/不利の状態で選択されたダイスにつけるマーク
61
+
62
+ # 有利/不利状態のenum
63
+ module FavouredState
64
+ NORMAL = -98 # 通常状態
65
+ FAVOURED = -99 # 有利状態
66
+ ILLFAVOURED = -100 # 不利状態
67
+ end
68
+
69
+ def eval_game_system_specific_command(command)
70
+ case command
71
+ when /^\d+RG/i
72
+ return rg_command_exec(command)
73
+ when /^FD/i
74
+ return fd_command_exec(command)
75
+ end
76
+ return "Error" # 到達しないはずだが、念のため
77
+ end
78
+
79
+ private
80
+
81
+ # ================ RG/FGコマンド共有メソッド等 ================#
82
+
83
+ # オプションデータクラス
84
+ class OptionData
85
+ attr_reader :favoured_state, :weary, :miserable
86
+
87
+ def initialize(favoured_state_value: FavouredState::NORMAL, weary_condition: false, miserable_condition: false)
88
+ @favoured_state = favoured_state_value
89
+ @weary = weary_condition
90
+ @miserable = miserable_condition
91
+ end
92
+ end
93
+
94
+ # 指定された修正値文字列を取得
95
+ def get_adjust_number_text(adjust_number)
96
+ adjust_number_text = ""
97
+
98
+ if adjust_number > 0
99
+ adjust_number_text = "+#{adjust_number}"
100
+ elsif adjust_number < 0
101
+ adjust_number_text = adjust_number.to_s
102
+ end
103
+
104
+ return adjust_number_text
105
+ end
106
+
107
+ # 指定された状態文字列を取得
108
+ def get_condition_text(opts)
109
+ if opts.favoured_state == FavouredState::NORMAL && !opts.weary && !opts.miserable
110
+ return ""
111
+ end
112
+
113
+ condition_text = "\n状態:"
114
+ if opts.favoured_state == FavouredState::FAVOURED
115
+ condition_text = "#{condition_text}有利 "
116
+ elsif opts.favoured_state == FavouredState::ILLFAVOURED
117
+ condition_text = "#{condition_text}不利 "
118
+ end
119
+ if opts.weary
120
+ condition_text = "#{condition_text}疲労 "
121
+ end
122
+ if opts.miserable
123
+ condition_text = "#{condition_text}絶望 "
124
+ end
125
+
126
+ return condition_text.rstrip
127
+ end
128
+
129
+ # 指定された状態文字列を取得
130
+ def get_options(opt_params)
131
+ favoured_state_value = FavouredState::NORMAL
132
+ miserable_condition = false
133
+ weary_condition = false
134
+
135
+ opt_params.each do |x|
136
+ case x[/[WFIM]/]
137
+ when "W"
138
+ weary_condition = on_option_switch?(x)
139
+ when "F"
140
+ favoured_state_value = get_favoured_state(on_option_switch?(x), favoured_state_value, FavouredState::FAVOURED)
141
+ when "I"
142
+ favoured_state_value = get_favoured_state(on_option_switch?(x), favoured_state_value, FavouredState::ILLFAVOURED)
143
+ when "M"
144
+ miserable_condition = on_option_switch?(x)
145
+ end
146
+ end
147
+
148
+ return OptionData.new(favoured_state_value: favoured_state_value, weary_condition: weary_condition, miserable_condition: miserable_condition)
149
+ end
150
+
151
+ # オプションから有利/不利状態指定を取得
152
+ def get_favoured_state(option_switch, before_favoured_state_value, tagert_state_type)
153
+ if option_switch
154
+ if before_favoured_state_value == tagert_state_type || before_favoured_state_value == FavouredState::NORMAL
155
+ return tagert_state_type
156
+ end
157
+
158
+ return FavouredState::NORMAL
159
+ else
160
+ if before_favoured_state_value == tagert_state_type
161
+ return FavouredState::NORMAL
162
+ end
163
+ end
164
+ return before_favoured_state_value
165
+ end
166
+
167
+ # オプションのON/OFFを取得
168
+ def on_option_switch?(opt_value)
169
+ if opt_value.length == 1 || opt_value[1..opt_value.length].to_i > 0
170
+ return true
171
+ end
172
+
173
+ return false
174
+ end
175
+
176
+ # 技量ダイスロールを行う
177
+ def make_successdice_roll(success_dice_count, weary_condition)
178
+ dice_list = @randomizer.roll_barabara(success_dice_count, 6)
179
+ success_count = dice_list.count(6)
180
+ if weary_condition
181
+ success_total_number = dice_list.reject { |i| i <= 3 }.sum
182
+ else
183
+ success_total_number = dice_list.sum
184
+ end
185
+ return dice_list.to_s, success_total_number, success_count
186
+ end
187
+
188
+ # 判定ダイスロールを行う
189
+ def make_featdice_roll(favoured_state_value)
190
+ feat_dice_count = favoured_state_value == FavouredState::NORMAL ? 1 : 2
191
+ dice_list = @randomizer.roll_barabara(feat_dice_count, 12)
192
+
193
+ choice_die_number = die_choice(dice_list, favoured_state_value)
194
+ if feat_dice_count > 1
195
+
196
+ choice_index = dice_list.find_index(choice_die_number)
197
+
198
+ first_die = "#{CHOICE_DIE_MARK if choice_index == 0}#{get_specal_die_str(dice_list[0])}"
199
+ second_die = "#{CHOICE_DIE_MARK if choice_index == 1}#{get_specal_die_str(dice_list[1])}"
200
+
201
+ feat_result_text = "[#{first_die}, #{second_die}]"
202
+ else
203
+ feat_result_text = "[#{get_specal_die_str(choice_die_number)}]"
204
+ end
205
+
206
+ return feat_result_text, choice_die_number, feat_dice_count
207
+ end
208
+
209
+ # 有利/不利を含めて判定ダイスの結果を取得
210
+ def die_choice(dice_list, favoured_state_value)
211
+ if favoured_state_value == FavouredState::ILLFAVOURED
212
+ if dice_list.count(SAURONS_EYE_NUMBER) >= 1
213
+ return SAURONS_EYE_NUMBER
214
+ else
215
+ return dice_list.min
216
+ end
217
+ elsif favoured_state_value == FavouredState::FAVOURED
218
+ if dice_list.count(GANDALF_RUNE_NUMBER) >= 1
219
+ return GANDALF_RUNE_NUMBER
220
+ else
221
+ # ガンダルフ・ルーンが無ければサウロンの目を除いた最大値を選ぶ
222
+ # ※ どちらもサウロンの目ならサウロンの目を返す
223
+ return dice_list.count(SAURONS_EYE_NUMBER) == 2 ? SAURONS_EYE_NUMBER : dice_list.reject { |x| x == SAURONS_EYE_NUMBER }.max
224
+ end
225
+ end
226
+ return dice_list[0]
227
+ end
228
+
229
+ # 判定ダイスが特殊ダイス目だった場合、該当文字列に変換する
230
+ def get_specal_die_str(die_number)
231
+ if die_number == GANDALF_RUNE_NUMBER
232
+ return "ガンダルフ・ルーン"
233
+ elsif die_number == SAURONS_EYE_NUMBER
234
+ return "サウロンの目"
235
+ end
236
+
237
+ return die_number
238
+ end
239
+
240
+ # ================ FDコマンド ================#
241
+
242
+ FD_ADJUST_NUMBER_INDEX = 2
243
+ FD_OPTION_START_INDEX = 3
244
+
245
+ # FDコマンド実行
246
+ def fd_command_exec(command)
247
+ m = /\A(FD)(-?\d*)?([FI]-?\d*)?([FI]-?\d*)?$/.match(command)
248
+ unless m
249
+ return ''
250
+ end
251
+
252
+ # コマンドパラメータ取得
253
+ adjust_number, opts = get_fd_params(m)
254
+
255
+ # 判定ダイス処理
256
+ feat_result_text, feat_die_number, feat_dice_count = make_featdice_roll(opts.favoured_state)
257
+ result_header_text = "(#{feat_dice_count}D12"
258
+
259
+ return get_fd_roll_result(result_header_text, feat_result_text, feat_die_number, feat_dice_count, adjust_number)
260
+ end
261
+
262
+ # FDコマンド判定結果の取得
263
+ def get_fd_roll_result(result_header_text, feat_result_text, feat_die_number, feat_dice_count, adjust_number)
264
+ # 修正値処理
265
+ reslt_die_number, adjust_number_text = get_fd_adjust(feat_die_number, adjust_number)
266
+
267
+ result_header_text = "#{result_header_text}#{adjust_number_text}) > #{feat_result_text}#{adjust_number_text}"
268
+ if adjust_number != 0 || feat_dice_count != 1
269
+ return "#{result_header_text} > [#{get_specal_die_str(reslt_die_number)}]"
270
+ end
271
+
272
+ return result_header_text
273
+ end
274
+
275
+ # FDコマンドの修正値取得
276
+ def get_fd_adjust(feat_die_number, adjust_number)
277
+ if [SAURONS_EYE_NUMBER, GANDALF_RUNE_NUMBER].include?(feat_die_number)
278
+ return feat_die_number, get_adjust_number_text(adjust_number)
279
+ end
280
+
281
+ res_total_num = feat_die_number + adjust_number
282
+ if res_total_num > 10
283
+ res_total_num = 10
284
+ elsif res_total_num < 1
285
+ res_total_num = 1
286
+ end
287
+ return res_total_num, get_adjust_number_text(adjust_number)
288
+ end
289
+
290
+ # FDコマンドパラメータの取得
291
+ def get_fd_params(m)
292
+ adjust_number = m[FD_ADJUST_NUMBER_INDEX].to_i
293
+
294
+ opt_params = m[FD_OPTION_START_INDEX..m.length].compact
295
+
296
+ return adjust_number, get_options(opt_params)
297
+ end
298
+
299
+ # ================ RGコマンド ================#
300
+
301
+ RG_DIFFICULTY_INDEX = 1
302
+ RG_SUCCESS_DICE_INDEX = 3
303
+ RG_PIERCING_BLOWS_INDEX = 5
304
+ RG_ADJUST_NUMBER_INDEX = 7
305
+ RG_OPTION_START_INDEX = 8
306
+
307
+ # RGコマンド実行
308
+ def rg_command_exec(command)
309
+ m = /\A(\d+)(RG)(\d*)(@(\d{0,2}))?(A(-?\d*))?([WFIM]-?\d*)?([WFIM]-?\d*)?([WFIM]-?\d*)?([WFIM]-?\d*)?$/.match(command)
310
+ unless m
311
+ return ''
312
+ end
313
+
314
+ success_count = 0
315
+
316
+ # コマンドパラメータ取得
317
+ difficulty, success_dice_count, piercing_blows_number, adjust_number, opts = get_rg_params(m)
318
+
319
+ # 判定ダイス処理
320
+ feat_result_text, feat_die_number, feat_dice_count = make_featdice_roll(opts.favoured_state)
321
+ total_dice_number = (feat_die_number != SAURONS_EYE_NUMBER ? feat_die_number : 0)
322
+
323
+ result_header_text = "(#{feat_dice_count}D12"
324
+ result_dice_text = feat_result_text
325
+
326
+ # 技量ダイスが指定されているならその処理
327
+ if success_dice_count > 0
328
+ success_result_text, success_total_number, success_count = make_successdice_roll(success_dice_count, opts.weary)
329
+ total_dice_number += success_total_number
330
+
331
+ result_header_text = "#{result_header_text}+#{success_dice_count}D6"
332
+ result_dice_text = "#{result_dice_text}+#{success_result_text}"
333
+ end
334
+
335
+ # 修正値処理
336
+ total_dice_number, adjust_number_text = get_rg_adjust(total_dice_number, adjust_number)
337
+
338
+ result_header_text = "#{result_header_text}#{adjust_number_text}) > #{result_dice_text}#{adjust_number_text}"
339
+
340
+ return get_rg_roll_result(result_header_text, difficulty, feat_die_number, piercing_blows_number, total_dice_number, success_count, opts)
341
+ end
342
+
343
+ # 修正値と修正値テキストの取得
344
+ def get_rg_adjust(total_dice_number, adjust_number)
345
+ total_dice_number += adjust_number
346
+ total_dice_number = 0 if total_dice_number < 0
347
+
348
+ return total_dice_number, get_adjust_number_text(adjust_number)
349
+ end
350
+
351
+ # RGコマンド判定結果の取得
352
+ def get_rg_roll_result(result_header_text, difficulty, feat_die_number, piercing_blows_number, total_dice_number, success_count, opts)
353
+ # 状態表示取得
354
+ condition_text = get_condition_text(opts)
355
+
356
+ success_count_text = "成功度 #{success_count}"
357
+
358
+ # 痛打判定をブロック化
359
+ piercing_blows = lambda() { |feat_die_num, piercing_blows_num, res_text, cond_text|
360
+ if piercing_blows_num > 0 && feat_die_num >= piercing_blows_num && feat_die_num != SAURONS_EYE_NUMBER
361
+ res_text = "#{res_text} 痛打発生!"
362
+ end
363
+ return "#{res_text}#{cond_text}"
364
+ }
365
+
366
+ if feat_die_number == GANDALF_RUNE_NUMBER
367
+ gandalf_rune_text = "#{result_header_text}:自動成功[#{success_count_text}]"
368
+ gandalf_rune_text = piercing_blows.call(feat_die_number, piercing_blows_number, gandalf_rune_text, condition_text)
369
+ if success_count >= 2
370
+ return Result.critical(gandalf_rune_text)
371
+ end
372
+
373
+ return Result.success(gandalf_rune_text)
374
+ elsif opts.miserable && feat_die_number == SAURONS_EYE_NUMBER
375
+ return Result.failure("#{result_header_text}:自動失敗#{condition_text}")
376
+ end
377
+
378
+ result_detail_text = "難易度 #{difficulty} 達成値 #{total_dice_number}"
379
+ if difficulty > total_dice_number
380
+ return Result.failure("#{result_header_text} #{result_detail_text}:失敗#{condition_text}")
381
+ end
382
+
383
+ success_text = "#{result_header_text} #{result_detail_text}:成功[#{success_count_text}]"
384
+ success_text = piercing_blows.call(feat_die_number, piercing_blows_number, success_text, condition_text)
385
+ if success_count >= 2
386
+ return Result.critical(success_text)
387
+ end
388
+
389
+ return Result.success(success_text)
390
+ end
391
+
392
+ # RGコマンドパラメータの取得
393
+ def get_rg_params(m)
394
+ difficulty = m[RG_DIFFICULTY_INDEX].to_i
395
+
396
+ success_dice_count = m[RG_SUCCESS_DICE_INDEX].to_i
397
+ adjust_number = m[RG_ADJUST_NUMBER_INDEX].to_i
398
+ piercing_blows_number = m[RG_PIERCING_BLOWS_INDEX]&.to_i || -1 # -1は痛打判定自体を行わない
399
+
400
+ opt_params = m[RG_OPTION_START_INDEX..m.length].compact
401
+
402
+ return difficulty, success_dice_count, piercing_blows_number, adjust_number, get_options(opt_params)
403
+ end
404
+ end
405
+ end
406
+ end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class TheUnofficialHollowKnightRPG < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'TheUnofficialHollowKnightRPG'
8
+
9
+ # ゲームシステム名
10
+ NAME = 'The Unofficial Hollow Knight RPG'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'しあんおふいしやるほろうないとRPG'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
+ ・能力値判定 [n]AD[+b][#r][>=t]
18
+  n: 能力値。小数可。省略不可。
19
+  b: ボーナス、ペナルティダイス。省略可。
20
+  r: 追加リロールダイス数。省略可。
21
+  t: 目標値。>=含めて省略可。
22
+  成功数を判定。
23
+  例)1AD, 2.5AD, 1.5AD+1, 2AD#1, 2.5AD+2#2>=4
24
+
25
+ ・イニシアチブ [n]INTI[+b][#r]
26
+  n: イニシアチブに使う能力値。省略不可。
27
+ b: ボーナス、ペナルティダイス。省略可。
28
+ r: 追加リロールダイス数。省略可。
29
+  振り直しを行ったうえでイニシアチブ値を計算。
30
+  例)1INTI, 2.5INTI, 1.5INTI+1, 2INTI#1, 2.5INTI+2#2
31
+ INFO_MESSAGE_TEXT
32
+
33
+ register_prefix('(\d+\.?\d*)?AD([+-](\d+))?(#(\d+))?(>=(\d+))?', '(\d+\.?\d*)?(INTI|inti)([+-](\d+))?(#(\d+))?')
34
+
35
+ def initialize(command)
36
+ super(command)
37
+
38
+ @sort_barabara_dice = false # バラバラロール(Bコマンド)でソート無
39
+ end
40
+
41
+ def eval_game_system_specific_command(command)
42
+ ability_roll(command) || initiative_roll(command)
43
+ end
44
+
45
+ def number_with_sign_from_int(number)
46
+ if number == 0
47
+ return ""
48
+ elsif number > 0
49
+ return "+#{number.abs}"
50
+ elsif number < 0
51
+ return "-#{number.abs}"
52
+ else
53
+ return number.to_s
54
+ end
55
+ end
56
+
57
+ def number_with_reroll_from_int(number)
58
+ if number == 0
59
+ return ""
60
+ elsif number > 0
61
+ return "\##{number}"
62
+ else
63
+ return number.to_s
64
+ end
65
+ end
66
+
67
+ # 能力値ロール
68
+ def ability_roll(command)
69
+ m = /^(\d+\.?\d*)?AD([+-](\d+))?(#(\d*))?(>=(\d+))?/.match(command)
70
+ unless m
71
+ return nil
72
+ end
73
+
74
+ num_of_die = m[1].to_f
75
+ bonus = m[3].to_i
76
+ reroll = m[5].to_i
77
+ difficulty = m[7].to_i
78
+
79
+ if /\.[1-9]+/ =~ num_of_die.to_s
80
+ dice_command = "#{num_of_die}AD#{number_with_sign_from_int(bonus)}#{number_with_reroll_from_int(reroll)}"
81
+ reroll += 1
82
+ else
83
+ dice_command = "#{num_of_die.to_i}AD#{number_with_sign_from_int(bonus)}#{number_with_reroll_from_int(reroll)}"
84
+ end
85
+
86
+ if difficulty == 0
87
+ difficulty = 5
88
+ else
89
+ dice_command += ">=#{difficulty}"
90
+ end
91
+
92
+ # 振られたダイスを入れる
93
+ values = @randomizer.roll_barabara(num_of_die.to_i + bonus, 6)
94
+ # 成功数
95
+ result = values.count { |num| num >= difficulty }
96
+ failed_roll = num_of_die.to_i - result
97
+
98
+ # ロールの結果の文字列
99
+ rolled_text = "[" + values.join(",") + "]"
100
+
101
+ reroll_values = []
102
+
103
+ if reroll == 1
104
+ reroll_values.push(@randomizer.roll_once(6))
105
+ elsif reroll > 1
106
+ reroll_values += @randomizer.roll_barabara(reroll, 6)
107
+ end
108
+
109
+ reroll_result = reroll_values.count { |num| num >= difficulty }
110
+ if failed_roll < reroll_result
111
+ reroll_result = failed_roll
112
+ end
113
+ result += reroll_result
114
+
115
+ # リロールの結果の文字列をロールの結果の文字列に追加する
116
+ unless reroll_values.empty?
117
+ rolled_text += " Reroll [" + reroll_values.join(",") + "]"
118
+ end
119
+
120
+ # 結果
121
+ return "(#{dice_command}) > #{rolled_text} > #{result}成功"
122
+ end
123
+
124
+ # イニシアチブロール
125
+ def initiative_roll(command)
126
+ m = /^(\d+\.?\d*)?(INTI|inti)([+-](\d+))?(#(\d+))?/.match(command)
127
+ unless m
128
+ return nil
129
+ end
130
+
131
+ grace = m[1].to_f
132
+ bonus = m[3].to_i
133
+ reroll = m[6].to_i
134
+
135
+ if /\.[1-9]+/ =~ grace.to_s
136
+ dice_command = "(#{grace}INTI#{number_with_sign_from_int(bonus)}#{number_with_reroll_from_int(reroll)})"
137
+ reroll += 1
138
+ else
139
+ dice_command = "(#{grace.to_i}INTI#{number_with_sign_from_int(bonus)}#{number_with_reroll_from_int(reroll)})"
140
+ end
141
+
142
+ values = @randomizer.roll_barabara(grace + bonus, 6)
143
+
144
+ revalue = []
145
+ unless reroll == 0
146
+ revalue = @randomizer.roll_barabara(reroll, 6)
147
+ end
148
+ revalue = revalue.sort
149
+
150
+ result = 0
151
+
152
+ res_text = "["
153
+ values.each do |value|
154
+ if revalue.empty? # リロールがなければ
155
+ res_text += value.to_s
156
+ result += value
157
+ else # リロールがあったら
158
+ is_min = false
159
+ index = -1
160
+ revalue.each do |re|
161
+ index += 1
162
+ next unless re > value # リロールしたダイス最小値か
163
+
164
+ res_text += "#{value}<<#{re}"
165
+ result += re
166
+ revalue.delete_at(index)
167
+ is_min = true
168
+ break
169
+ end
170
+ unless is_min # 最小値でなかったら
171
+ res_text += value.to_s
172
+ result += value
173
+ end
174
+ end
175
+
176
+ res_text += ","
177
+ end
178
+ res_text = res_text.chop
179
+ res_text += "]"
180
+
181
+ return "#{dice_command} > #{res_text} > #{result}"
182
+ end
183
+ end
184
+ end
185
+ end