bcdice 3.8.0 → 3.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d8674329cd5ca8a6efb98b170e0e3ddb5bb4a3fe527ee92fa0e3f1fefffa470
4
- data.tar.gz: 0abbe4f8973133644242a2b337138bd9297b4754dfe3be33046760836d90b4b3
3
+ metadata.gz: 42944751b9e1101ab29df8042cb267f762ec4626c02d1301130716f5117ae5a1
4
+ data.tar.gz: b273615ac178eb8f8f243961604dcdd9e6eb54a3ac90d41a3adc04005dae5d45
5
5
  SHA512:
6
- metadata.gz: 68c14cfcd28b29d424d37d65ae9e00e09fc3d6da8280df7f190fb18c674b838f9cbf8053f6b94e1f3540c5c981985d0d33d0466362caacbd5a253712f7dc0461
7
- data.tar.gz: 7acf5a2bb802bfffa9338a5a6a06f6070d27fcb5e62ce9d0ad51df987fae2ac818cb4acb5aba6c467f2872bf7419bc7c242a66dba08006014eddca60e9604738
6
+ metadata.gz: 8e1e55ae455c5b0b36bd8dd5e3f4351f0ee06b195795ca44e8384c85b0fd907c682049a9d37f6b55b57a729612e0f64a1ec75a0cf437ce694a55ec6b19c46f97
7
+ data.tar.gz: ca3a7a2f2c0fd78ecc60c4b99b3d692de1deb7aa9266ac1734ad4ae96bc9399488ced485590f0b29b69ca3807c947ad371756528a22a073493f9b98977ecd2c1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.9.0 2023/03/25
4
+
5
+ ### 対応ゲームシステムの追加
6
+ - 天下繚乱 (TenkaRyouran): 三木里 秀予さんありがとうっ! ([#604](https://github.com/bcdice/BCDice/pull/604))
7
+ - ワールドエンドフロントライン (WorldsEndFrontline): ([#611](https://github.com/bcdice/BCDice/pull/611))
8
+
9
+ ### 追加機能
10
+ - 初音ミクTRPG: 表をいくつか追加。カルメヤキさんありがとうっ! ([#602](https://github.com/bcdice/BCDice/pull/602))
11
+ - スタンダードRPGシステム系: クリティカルを `@` で、ファンブルを `#` で指定できるように。三木里 秀予さんありがとうっ! ([#605](https://github.com/bcdice/BCDice/pull/605))
12
+ - ダンジョンズ&ドラゴンズ第5版: 両手持ちのダメージ算出コマンドを追加。Facelessさんありがとうっ! ([#612](https://github.com/bcdice/BCDice/pull/612))
13
+ - ダンジョンズ&ドラゴンズ第5版: 攻撃ロールでクリティカル値を指定できるように。Facelessさんありがとうっ! ([#612](https://github.com/bcdice/BCDice/pull/612))
14
+
15
+ ### 変更
16
+ - シノビガミ: 変調表と戦場表の内容を改訂版に変更。 ([#588](https://github.com/bcdice/BCDice/pull/588))
17
+
18
+ ### 誤植修正
19
+ - 歯車の塔の探空士(冒険企画局): 航行イベント表 困難系の誤植を修正。おさむさんありがとうっ! ([#607](https://github.com/bcdice/BCDice/pull/607))
20
+ - サイバーパンクRED: 判定コマンドに対するヘルプメッセージの誤りを修正。 ([#609](https://github.com/bcdice/BCDice/pull/609))
21
+
22
+ ### バグ修正
23
+ - ブラドリウム: ダイスチェックで二桁以上のダイス数を指定できない問題を修正。ゆずあずさん指摘ありがとうっ! ([#606](https://github.com/bcdice/BCDice/pull/606))
24
+
3
25
  ## 3.8.0 2023/02/18
4
26
 
5
27
  ### 対応ゲームシステムの追加
@@ -13,7 +35,7 @@
13
35
 
14
36
  ### 追加機能
15
37
  - ワールド・オブ・ダークネス: 振り足しの1で成功数の打ち消しが発生するコマンド(STB)を追加。フレッド緑野さんありがとうっ! ([#571](https://github.com/bcdice/BCDice/pull/571))
16
- - トーグ エタニティ: 高揚コマンドで修正値指定が出来るように拡張。Facelessさんありがとうっ! ([#577](https://github.com/bcdice/BCDice/pull/577))
38
+ - トーグ エタニティ: 高揚コマンドで修正値指定が出来るように拡張。Facelessさんありがとうっ! ([#580](https://github.com/bcdice/BCDice/pull/580))
17
39
  - Vampire: The Masquerade 5th Edition: 判定コマンドの難易度省略時に判定結果のヒント出力を追加。フレッド緑野さんありがとうっ! ([#581](https://github.com/bcdice/BCDice/pull/581))
18
40
  - Vampire: The Masquerade 5th Edition: 難易度指定時に成功差分を表示する機能を追加。フレッド緑野さんありがとうっ! ([#591](https://github.com/bcdice/BCDice/pull/591))
19
41
  - 歯車の塔の探空士(冒険企画局): 航行イベント表を追加。前田さんありがとうっ! ([#601](https://github.com/bcdice/BCDice/pull/601))
@@ -22,7 +44,7 @@
22
44
  - シノビガミ: ファンブル表の内容を改訂版に変更。 ([#588](https://github.com/bcdice/BCDice/pull/588))
23
45
 
24
46
  ### 誤植修正
25
- - フタリソウサ: ヘルプメッセージにイベント表の記載漏れを追記。あまねさんありがとうっ! ([#580](https://github.com/bcdice/BCDice/pull/580))
47
+ - フタリソウサ: ヘルプメッセージにイベント表の記載漏れを追記。あまねさんありがとうっ! ([#579](https://github.com/bcdice/BCDice/pull/579))
26
48
  - ウォーハンマーRPG第4版: SLの誤植を修正。Facelessさんありがとうっ! ([#585](https://github.com/bcdice/BCDice/pull/585))
27
49
  - シノビガミ: 怪変調表の誤植を修正。なす車さんありがとうっ! ([#600](https://github.com/bcdice/BCDice/pull/600))
28
50
 
@@ -20,7 +20,7 @@ module BCDice
20
20
   y: 結果への修正値 (省略可)
21
21
  INFO_MESSAGE_TEXT
22
22
 
23
- register_prefix('\dDC')
23
+ register_prefix('\d+DC')
24
24
 
25
25
  def eval_game_system_specific_command(command)
26
26
  dicecheck(command)
@@ -16,9 +16,9 @@ module BCDice
16
16
 
17
17
  # ダイスボットの使い方
18
18
  HELP_MESSAGE = <<~HELP
19
- ・判定 CPx+y>=z
19
+ ・判定 CPx+y>z
20
20
   (x=能力値と技能値の合計、y=修正値、z=難易度 or 受動側 x、y、zは省略可)
21
-  例)CP12 CP10+2>=12 CP7-1 CP8+4 CP7>=12 CP CP>=9
21
+  例)CP12 CP10+2>12 CP7-1 CP8+4 CP7>12 CP CP>9
22
22
 
23
23
  各種表
24
24
  ・致命的損傷表
@@ -14,20 +14,26 @@ module BCDice
14
14
 
15
15
  # ダイスボットの使い方
16
16
  HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
- ・攻撃ロール AT[x][>=t][y]
17
+ ・攻撃ロール AT[x][@c][>=t][y]
18
18
   x:+-修正。省略可。
19
-  y:有利(A), 不利(D)。省略可。
19
+  c:クリティカル値。省略可。
20
20
   t:敵のアーマークラス。>=を含めて省略可。
21
+  y:有利(A), 不利(D)。省略可。
21
22
   ファンブル/失敗/成功/クリティカル を自動判定。
22
23
   例)AT AT>=10 AT+5>=18 AT-3>=16 ATA AT>=10A AT+3>=18A AT-3>=16 ATD AT>=10D AT+5>=18D AT-5>=16D
23
-
24
+   AT@19 AT+5@18 AT-2@19>=15
24
25
  ・能力値判定 AR[x][>=t][y]
25
26
   攻撃ロールと同様。失敗/成功を自動判定。
26
27
   例)AR AR>=10 AR+5>=18 AR-3>=16 ARA AR>=10A AR+3>=18A AR-3>=16 ARD AR>=10D AR+5>=18D AR-5>=16D
27
-
28
+ ・両手持ちのダメージ 2HnDx[m]
29
+  n:ダイスの個数
30
+  x:ダイスの面数
31
+  m:+-修正。省略可。
32
+  パラディンとファイターの武器の両手持ちによるダメージダイスの1,2の出目の振り直しを行います。
33
+  例)2H3D6 2H1D10+3 2H2D8-1
28
34
  INFO_MESSAGE_TEXT
29
35
 
30
- register_prefix('AT([+-]\d+)?(>=\d+)?[AD]?', 'AR([+-]\d+)?(>=\d+)?[AD]?')
36
+ register_prefix('AT([+-]\d+)?(@\d+)?(>=\d+)?[AD]?', 'AR([+-]\d+)?(>=\d+)?[AD]?', '2H(\d+)D(\d+)([+-]\d+)?')
31
37
 
32
38
  def initialize(command)
33
39
  super(command)
@@ -36,7 +42,7 @@ module BCDice
36
42
  end
37
43
 
38
44
  def eval_game_system_specific_command(command)
39
- attack_roll(command) || ability_roll(command)
45
+ attack_roll(command) || ability_roll(command) || twohands_damage_roll(command)
40
46
  end
41
47
 
42
48
  def number_with_sign_from_int(number)
@@ -49,20 +55,27 @@ module BCDice
49
55
  end
50
56
  end
51
57
 
58
+ # 攻撃ロール
52
59
  def attack_roll(command)
53
- m = /^AT([-+]\d+)?(>=(\d+))?([AD]?)/.match(command)
60
+ m = /^AT([-+]\d+)?(@(\d+))?(>=(\d+))?([AD]?)/.match(command)
54
61
  unless m
55
62
  return nil
56
63
  end
57
64
 
58
65
  modify = m[1].to_i
59
- difficulty = m[3].to_i
60
- advantage = m[4]
66
+ critical_no = m[3].to_i
67
+ difficulty = m[5].to_i
68
+ advantage = m[6]
61
69
 
62
70
  usedie = 0
63
71
  roll_die = ""
64
72
 
65
73
  dice_command = "AT#{number_with_sign_from_int(modify)}"
74
+ if critical_no > 0
75
+ dice_command += "@#{critical_no}"
76
+ else
77
+ critical_no = 20
78
+ end
66
79
  if difficulty > 0
67
80
  dice_command += ">=#{difficulty}"
68
81
  end
@@ -96,7 +109,7 @@ module BCDice
96
109
  end
97
110
 
98
111
  result = Result.new
99
- if usedie == 20
112
+ if usedie >= critical_no
100
113
  result.critical = true
101
114
  result.success = true
102
115
  output.push("クリティカル")
@@ -124,6 +137,7 @@ module BCDice
124
137
  end
125
138
  end
126
139
 
140
+ # 能力値ロール
127
141
  def ability_roll(command)
128
142
  m = /^AR([-+]\d+)?(>=(\d+))?([AD]?)/.match(command)
129
143
  unless m
@@ -191,6 +205,46 @@ module BCDice
191
205
  end
192
206
  end
193
207
  end
208
+
209
+ # 武器の両手持ちダメージ
210
+ def twohands_damage_roll(command)
211
+ m = /^2H(\d+)D(\d+)([+-]\d+)?/.match(command)
212
+ unless m
213
+ return nil
214
+ end
215
+
216
+ dice_count = m[1].to_i
217
+ dice_number = m[2].to_i
218
+ modify = m[3].to_i
219
+ mod_str = number_with_sign_from_int(modify)
220
+ output = ["(2H#{dice_count}D#{dice_number}#{mod_str})"]
221
+
222
+ dice = @randomizer.roll_barabara(dice_count, dice_number)
223
+ roll_dice = "[" + dice.join(",") + "]"
224
+ output.push("#{roll_dice}#{mod_str}")
225
+
226
+ ex_dice = []
227
+ new_dice = []
228
+ sum_dice = 0
229
+ dice.each do |num|
230
+ if num.to_i > 2
231
+ sum_dice += num.to_i
232
+ ex_dice.push(num)
233
+ else
234
+ one_die = @randomizer.roll_once(dice_number)
235
+ sum_dice += one_die.to_i
236
+ new_dice.push(one_die)
237
+ end
238
+ end
239
+ unless new_dice.empty?
240
+ output.push("[" + ex_dice.join(",") + "][" + new_dice.join(",") + "]#{mod_str}")
241
+ end
242
+ output.push((sum_dice + modify).to_s)
243
+
244
+ Result.new.tap do |r|
245
+ r.text = output.join(" > ")
246
+ end
247
+ end
194
248
  end
195
249
  end
196
250
  end
@@ -27,7 +27,7 @@ module BCDice
27
27
    ネイロに5(白)を取得した場合 3:失敗
28
28
  ・各種表
29
29
   ファンブル表 FT/致命傷表 CWT/休憩表 BT/目標表 TT/関係表 RT
30
-  障害表 OT/リクエスト表 RQT/情景表 ST
30
+  障害表 OT/リクエスト表 RQT/クロウル表 CLT/報酬表 RWT/悪夢表 NMT/情景表 ST
31
31
  ・キーワード表
32
32
   ダーク DKT/ホット HKT/ラブ LKT/エキセントリック EKT/メランコリー MKT
33
33
  ・名前表 NT
@@ -229,6 +229,47 @@ module BCDice
229
229
  "あなたの目の前に、あなたの死体が横たわっている。「お前を殺すものは何だ?お前は誰に殺される?」"
230
230
  ]
231
231
  ),
232
+ "CLT" => DiceTable::Table.new(
233
+ "クロウル表",
234
+ "2D6",
235
+ [
236
+ "パスワードが抜き取られていた! 所持金が無くなっている! 自分のコインを3枚失う。",
237
+ "過去に同様のオトクイと出会ったことのある人物に出会う。【技術】で判定を行う。成功すると、「特殊アプリの開発」を行うことができる(この間奏アクションには【タイム】は必要ない)。必要なコインは1枚少なくなる。",
238
+ "近所にあるパワースポットを教えてもらう。【霊力】で判定を行う。成功すると、自分の【生命力】を【活力】の値だけ回復することができる。",
239
+ "あなたのことを知る人物に出会う。どんな思い出話をしたのだろうか? この質問はリクエストとして扱う。",
240
+ "プライベートの友人からメールが届いている。【愛】で判定を行う。成功すると、好きなNPCを協力者として設定することができる。判定に失敗すると苦情のメールだった。ストレスを1点受ける。",
241
+ "ノイズメンバーから応援のメッセージをもらう。好きなネイロを1つ獲得する(この効果で。特定のネイロを7個以上にすることはできない)。",
242
+ "美味しい食べ物屋さんに関する情報を教えてもらう。【日常】で判定を行う。成功すると、自分のストレスを1点回復できる。",
243
+ "オトクイに関する情報を求めているノイズメンバーに出会う。公開されている脅威1つにつき、その情報をコイン1枚で売却できる。このイベントが2度以上起きた場合、すでに売却した脅威の情報を再び売ることはできない。",
244
+ "試作アプリの試験者を募集している。好きなアプリ1つを獲得する。ただし、このアプリを使用するときサイコロを1個振ること。1か2が出ると、そのアプリは効果を発揮しない。セッション中に、試作アプリを使用しているとセッション終了時にレポートを提出できる。【頭脳】で判定を行う。成功すると、コインを1枚獲得できる。",
245
+ "自分に関する悪口を見つける。そこには、どんな悪口が書かれていたのだろうか。 この質問は、リクエストとして扱う。",
246
+ "同じ種類のオトダマと契約しているオトダマ使いと意気投合。このセッションの間、自分のナンバー1つを、修得可能な別のナンバーに変更することができる。",
247
+ ]
248
+ ),
249
+ "RWT" => DiceTable::Table.new(
250
+ "報酬表",
251
+ "1D6",
252
+ [
253
+ "ノイズからオトクイ退治の報酬をもらうことができる。[倒したオトクイの本体のレベル]枚のコインを獲得する。",
254
+ "ノイズにオトダマの情報を売ることができる。[自分の【頭脳】のダイスの数]枚のコインを獲得する。",
255
+ "冒険を通じて因縁が芽生える。今回登場したキャラクターの中から一人を選ぶ。そのキャラクターを、自分の【想い人】にする。",
256
+ "冒険を通じて絆が結ばれる。今回登場したNPCの中から一人を選ぶ。そのキャラクターを、自分の【協力者】にする。",
257
+ "冒険の思い出が【ウタの欠片】になる。今回の冒険に登場した仲間、情景、出来事などなどから、キーワードを一つ選ぶ。そのキーワードを【ウタの欠片】のキーワード欄に追加する。",
258
+ "戦いの経験が【ウタの欠片】になる。今回の冒険に登場した敵、情景、出来事などなどから、キーワードを一つ選ぶ。そのキーワードを【ウタの欠片】のキーワード欄に追加する。",
259
+ ]
260
+ ),
261
+ "NMT" => DiceTable::Table.new(
262
+ "悪夢表",
263
+ "1D6",
264
+ [
265
+ "絶望のウタに知覚を遮断される。背後にオトクイの気配を感じたと思ったときは遅かった。卑劣な攻撃があなたを襲う。好きな能力値で判定を行う。失敗するとあなたのキャラクターは、オトナシとなり、二度と冒険に参加できない。",
266
+ "絶望のウタに混じり、悲痛な叫びが聞こえてくる。ココロダンジョンの持ち主だろうか。あなたは、救えなかったのだ。【日常】で判定を行う。失敗すると、自分の能力値一つを選ぶ。次回のセッションは、その能力値にストレスを受けた状態で始まる。",
267
+ "絶望のウタに混じり、オトクイの笑いがこだまする。それは嘲りの笑いだった。オトクイや仲間たち……何より自分への怒りがわき上がる。【日常】で判定を行う。失敗すると、自分の想い人への【想い】を一つ失う。",
268
+ "絶望のウタの中に一人取り残される。誰もあなたに気づかない。孤独に耐えながら、何とか日常へ帰還したが……そのときの恐怖がぬぐえない。【日常】で判定を行う。失敗すると、次回のセッションは、自分の【生命力】の現在値が通常の半分(端数切り上げ)の状態で始まる。",
269
+ "ココロダンジョンから帰還したあなたを待っていたのは、代わり映えのない日常だった。あなたが任務に失敗しても、世界は変わらない。なら、もう、あんな怖い目をする必要はないんじゃないか? 【日常】で判定を行う。失敗すると、自分のナンバー一つを選ぶ。次回のセッションは、そのナンバーにストレスを受けた状態で始まる。",
270
+ "絶望のウタの中を必死で逃げ出した。背後から仲間の声が聞こえた気がする。しかし、あなたは振り返ることができなかった。【日常】で判定を行う。失敗すると、自分に対して【想い】を持っているPC一人を選び、その自分に対する【想い】が失われる。",
271
+ ]
272
+ ),
232
273
  "ST" => DiceTable::D66Table.new(
233
274
  "情景表",
234
275
  D66SortType::ASC,
@@ -16,27 +16,33 @@ module BCDice
16
16
 
17
17
  HELP_MESSAGE_1 = <<~HELP_MESSAGE
18
18
  ・判定
19
-  ・通常判定:2D6+m>=t[c,f]
19
+  ・通常判定:2D6+m@c#f>=t または 2D6+m>=t[c,f]
20
20
    修正値m、目標値t、クリティカル値c、ファンブル値fで判定ロールを行います。
21
-   修正値、クリティカル値、ファンブル値は省略可能です([]ごと省略可)。
21
+   修正値、クリティカル値、ファンブル値は省略可能です([]ごと省略可、@c・#fの指定は順不同)。
22
22
    クリティカル値、ファンブル値の既定値は、それぞれ12、2です。
23
23
    自動成功、自動失敗、成功、失敗を自動表示します。
24
24
 
25
25
    例) 2d6>=10     修正値0、目標値10で判定
26
26
    例) 2d6+2>=10    修正値+2、目標値10で判定
27
27
    例) 2d6+2>=10[11]  ↑をクリティカル値11で判定
28
+   例) 2d6+2@11>=10   ↑をクリティカル値11で判定
28
29
    例) 2d6+2>=10[12,4] ↑をクリティカル値12、ファンブル値4で判定
30
+   例) 2d6+2@12#4>=10  ↑をクリティカル値12、ファンブル値4で判定
31
+   例) 2d6+2>=10[,4]  ↑をクリティカル値12、ファンブル値4で判定(クリティカル値の省略)
32
+   例) 2d6+2#4>=10   ↑をクリティカル値12、ファンブル値4で判定(クリティカル値の省略)
29
33
  HELP_MESSAGE
30
34
 
31
35
  HELP_MESSAGE_2 = <<~HELP_MESSAGE
32
-  ・クリティカルおよびファンブルのみの判定:2D6+m[c,f]
36
+  ・クリティカルおよびファンブルのみの判定:2D6+m@c#f または 2D6+m[c,f]
33
37
    目標値を指定せず、修正値m、クリティカル値c、ファンブル値fで判定ロールを行います。
34
-   修正値、クリティカル値、ファンブル値は省略可能です([]は省略不可)。
38
+   修正値、クリティカル値、ファンブル値は省略可能です([]は省略不可、@c・#fの指定は順不同)。
35
39
    自動成功、自動失敗を自動表示します。
36
40
 
37
41
    例) 2d6[]    修正値0、クリティカル値12、ファンブル値2で判定
38
42
    例) 2d6+2[11]  修正値+2、クリティカル値11、ファンブル値2で判定
43
+   例) 2d6+2@11   修正値+2、クリティカル値11、ファンブル値2で判定
39
44
    例) 2d6+2[12,4] 修正値+2、クリティカル値12、ファンブル値4で判定
45
+   例) 2d6+2@12#4  修正値+2、クリティカル値12、ファンブル値4で判定
40
46
  HELP_MESSAGE
41
47
 
42
48
  HELP_MESSAGE_3 = <<~HELP_MESSAGE
@@ -50,18 +56,14 @@ module BCDice
50
56
 
51
57
  # 成功判定のエイリアスコマンド定義用のクラスメソッドを提供するモジュール
52
58
  module ClassMethods
59
+ # 成功判定のエイリアスコマンドの一覧
60
+ # @return [Array<String>]
61
+ attr_reader :aliases
62
+
53
63
  # ダイスボットの説明文を返す
54
64
  # @return [String]
55
65
  attr_reader :help_message
56
66
 
57
- # 目標値あり成功判定のエイリアスコマンドの正規表現を返す
58
- # @return [Regexp, nil]
59
- attr_reader :aliases_re_for_srs_roll_with_target_value
60
-
61
- # 目標値なし成功判定のエイリアスコマンドの正規表現を返す
62
- # @return [Regexp, nil]
63
- attr_reader :aliases_re_for_srs_roll_without_target_value
64
-
65
67
  # 成功判定のエイリアスコマンドを設定する
66
68
  # @param [String] aliases エイリアスコマンド(可変長引数)
67
69
  # @return [self]
@@ -70,71 +72,48 @@ module BCDice
70
72
  # 実行時にそれが2D6に置換されるようになる。
71
73
  def set_aliases_for_srs_roll(*aliases)
72
74
  aliases_upcase = aliases.map(&:upcase)
73
- aliases_part = aliases_upcase
74
- .map { |a| Regexp.escape(a) }
75
- .join('|')
76
-
77
- @aliases_re_for_srs_roll_with_target_value = Regexp.new(
78
- '\A' \
79
- "(?:#{aliases_part})" \
80
- '((?:[-+][-+\d]+)?>=\d+(?:\[\d*(?:,\d+)?\])?)\z'
81
- )
82
-
83
- @aliases_re_for_srs_roll_without_target_value = Regexp.new(
84
- '\A' \
85
- "(?:#{aliases_part})" \
86
- '([-+][-+\d]+)?(\[\d*(?:,\d+)?\])?\z'
87
- )
88
-
89
- prepare_help_msg_for_aliases_for_srs_roll(aliases_upcase)
90
- @help_message = concatenate_help_messages
91
75
 
76
+ @aliases = aliases_upcase.map { |a| Regexp.escape(a) }
77
+ @help_message = concatenate_help_messages(aliases_upcase)
92
78
  return self
93
79
  end
94
80
 
95
81
  # 成功判定のエイリアスコマンドを未設定にする
96
82
  # @return [self]
97
83
  def clear_aliases_for_srs_roll
98
- @aliases_re_for_srs_roll_with_target_value = nil
99
- @aliases_re_for_srs_roll_without_target_value = nil
84
+ @aliases = []
100
85
  @help_message = SRS::DEFAULT_HELP_MESSAGE
101
-
102
86
  return self
103
87
  end
104
88
 
105
89
  private
106
90
 
107
- # 成功判定のエイリアスコマンドの説明文を用意する
91
+ # ダイスボットの説明文を結合する
108
92
  # @param [Array<String>] aliases エイリアスコマンドの配列
109
- # @return [self]
93
+ # @return [String] 結合された説明文
110
94
  # @todo 現在は2文字のエイリアスコマンドに幅を合わせてある。
111
95
  # エイリアスコマンドの文字数が変わる場合があれば、位置を調整するコードが
112
96
  # 必要。
113
- def prepare_help_msg_for_aliases_for_srs_roll(aliases)
114
- @help_msg_for_aliases_for_srs_roll_with_target_value =
97
+ def concatenate_help_messages(aliases)
98
+ help_msg_for_aliases_for_target_value =
115
99
  aliases
116
- .map { |a| "  例) #{a}+2>=10     2d6+2>=10と同じ(#{a}が2D6のショートカットコマンド)\n" }
100
+ .map do |a|
101
+ "  例) #{a}+2>=10     2d6+2>=10と同じ(#{a}が2D6のショートカットコマンド)\n"
102
+ end
117
103
  .join()
118
-
119
- @help_msg_for_aliases_for_srs_roll_without_target_value =
104
+ help_msg_for_aliases_for_without_target_value =
120
105
  aliases
121
106
  .map do |a|
122
107
  "  例) #{a}      2d6[]と同じ(#{a}が2D6のショートカットコマンド)\n" \
123
- "  例) #{a}+2[12,4]  2d6+2[12,4]と同じ(#{a}が2D6のショートカットコマンド)\n"
108
+ "  例) #{a}+2@12#4  2d6+2@12#4と同じ(#{a}が2D6のショートカットコマンド)\n"
124
109
  end
125
110
  .join()
126
111
 
127
- return self
128
- end
129
-
130
- # ダイスボットの説明文を結合する
131
- # @return [String] 結合された説明文
132
- def concatenate_help_messages
133
- "#{SRS::HELP_MESSAGE_1}" \
134
- "#{@help_msg_for_aliases_for_srs_roll_with_target_value}\n" \
135
- "#{SRS::HELP_MESSAGE_2}" \
136
- "#{@help_msg_for_aliases_for_srs_roll_without_target_value}\n" \
137
- "#{SRS::HELP_MESSAGE_3}"
112
+ return "#{SRS::HELP_MESSAGE_1}" \
113
+ "#{help_msg_for_aliases_for_target_value}\n" \
114
+ "#{SRS::HELP_MESSAGE_2}" \
115
+ "#{help_msg_for_aliases_for_without_target_value}\n" \
116
+ "#{SRS::HELP_MESSAGE_3}"
138
117
  end
139
118
  end
140
119
 
@@ -153,16 +132,10 @@ module BCDice
153
132
  DEFAULT_HELP_MESSAGE
154
133
  end
155
134
 
156
- # 目標値あり成功判定のエイリアスコマンドの正規表現を返す
157
- # @return [nil]
158
- def aliases_re_for_srs_roll_with_target_value
159
- nil
160
- end
161
-
162
- # 目標値なし成功判定のエイリアスコマンドの正規表現を返す
163
- # @return [nil]
164
- def aliases_re_for_srs_roll_without_target_value
165
- nil
135
+ # 成功判定のエイリアスコマンドの一覧
136
+ # @return [Array<String>]
137
+ def aliases
138
+ []
166
139
  end
167
140
  end
168
141
 
@@ -187,22 +160,17 @@ module BCDice
187
160
  self.class.help_message
188
161
  end
189
162
 
163
+ # 成功判定のエイリアスコマンドの一覧
164
+ # @return [Array<String>]
165
+ def aliases
166
+ self.class.aliases
167
+ end
168
+
190
169
  # 既定のクリティカル値
191
170
  DEFAULT_CRITICAL_VALUE = 12
192
171
  # 既定のファンブル値
193
172
  DEFAULT_FUMBLE_VALUE = 2
194
173
 
195
- # 目標値あり成功判定の正規表現
196
- SRS_ROLL_WITH_TARGET_VALUE_RE =
197
- /\A2D6([-+][-+\d]+)?>=(\d+)(?:\[(\d+)?(?:,(\d+))?\])?\z/.freeze
198
- # 目標値なし成功判定の正規表現
199
- SRS_ROLL_WITHOUT_TARGET_VALUE_RE =
200
- /\A2D6([-+][-+\d]+)?\[(\d+)?(?:,(\d+))?\]\z/.freeze
201
-
202
- # 既定の閾値指定表記
203
- SRS_ROLL_DEFAULT_THRESHOLDS =
204
- "[#{DEFAULT_CRITICAL_VALUE},#{DEFAULT_FUMBLE_VALUE}]"
205
-
206
174
  # 成功判定コマンドのノード
207
175
  SRSRollNode = Struct.new(
208
176
  :modifier, :critical_value, :fumble_value, :target_value
@@ -221,9 +189,15 @@ module BCDice
221
189
  # @param [String] command 入力されたコマンド
222
190
  # @return [Result, nil] ダイスロールコマンドの実行結果
223
191
  def eval_game_system_specific_command(command)
224
- alias_replaced_with_2d6 = replace_alias_for_srs_roll_with_2d6(command)
225
-
226
- if (node = parse(alias_replaced_with_2d6))
192
+ legacy_c_f_match = /(.+)\[(.*)\]\z/.match(command)
193
+ node =
194
+ if legacy_c_f_match
195
+ parse_legacy(legacy_c_f_match[1], legacy_c_f_match[2])
196
+ else
197
+ parse(command)
198
+ end
199
+
200
+ if node
227
201
  return execute_srs_roll(node)
228
202
  end
229
203
 
@@ -232,67 +206,46 @@ module BCDice
232
206
 
233
207
  private
234
208
 
235
- # 成功判定のエイリアスコマンドを2D6に置換する
236
- # @param [String] input 入力文字列
237
- # @return [String]
238
- def replace_alias_for_srs_roll_with_2d6(input)
239
- case input
240
- when self.class.aliases_re_for_srs_roll_with_target_value
241
- return "2D6#{Regexp.last_match(1)}"
242
- when self.class.aliases_re_for_srs_roll_without_target_value
243
- modifier = Regexp.last_match(1)
244
- thresholds = Regexp.last_match(2) || SRS_ROLL_DEFAULT_THRESHOLDS
245
-
246
- return "2D6#{modifier}#{thresholds}"
247
- else
248
- return input
209
+ def parse(command)
210
+ prefix_re = Regexp.new(["2D6"].concat(aliases()).join('|'), Regexp::IGNORECASE)
211
+ parser = Command::Parser.new(prefix_re, round_type: @round_type)
212
+ .enable_critical
213
+ .enable_fumble
214
+ .restrict_cmp_op_to(nil, :>=)
215
+ cmd = parser.parse(command)
216
+ unless cmd
217
+ return nil
249
218
  end
250
- end
251
219
 
252
- # 構文解析する
253
- # @param [String] command コマンド文字列
254
- # @return [SRSRollNode, nil]
255
- def parse(command)
256
- case command
257
- when SRS_ROLL_WITH_TARGET_VALUE_RE
258
- return parse_srs_roll_with_target_value(Regexp.last_match)
259
- when SRS_ROLL_WITHOUT_TARGET_VALUE_RE
260
- return parse_srs_roll_without_target_value(Regexp.last_match)
261
- else
220
+ if command.start_with?(/2D6/i) && cmd.critical.nil? && cmd.fumble.nil? && cmd.target_number.nil?
221
+ # fallback to default dice
262
222
  return nil
263
223
  end
264
- end
265
224
 
266
- # 修正値を評価する
267
- # @param [String, nil] modifier_str 修正値部分の文字列
268
- # @return [Integer] 修正値
269
- def eval_modifier(modifier_str)
270
- return 0 unless modifier_str
225
+ cmd.critical ||= DEFAULT_CRITICAL_VALUE
226
+ cmd.fumble ||= DEFAULT_FUMBLE_VALUE
271
227
 
272
- return ArithmeticEvaluator.eval(modifier_str, round_type: @round_type)
228
+ return SRSRollNode.new(cmd.modify_number, cmd.critical, cmd.fumble, cmd.target_number)
273
229
  end
274
230
 
275
- # 目標値あり成功判定の正規表現マッチ情報からノードを作る
276
- # @param [MatchData] m 正規表現のマッチ情報
277
- # @return [SRSRollNode]
278
- def parse_srs_roll_with_target_value(m)
279
- modifier = eval_modifier(m[1])
280
- target_value = m[2].to_i
281
- critical_value = m[3]&.to_i || DEFAULT_CRITICAL_VALUE
282
- fumble_value = m[4]&.to_i || DEFAULT_FUMBLE_VALUE
231
+ def parse_legacy(command, c_f)
232
+ m = /^(-?\d+)?(?:,(-?\d+))?$/.match(c_f)
233
+ unless m
234
+ return nil
235
+ end
283
236
 
284
- return SRSRollNode.new(modifier, critical_value, fumble_value, target_value)
285
- end
237
+ critical = m[1]&.to_i || DEFAULT_CRITICAL_VALUE
238
+ fumble = m[2]&.to_i || DEFAULT_FUMBLE_VALUE
286
239
 
287
- # 目標値なし成功判定の正規表現マッチ情報からノードを作る
288
- # @param [MatchData] m 正規表現のマッチ情報
289
- # @return [SRSRollNode]
290
- def parse_srs_roll_without_target_value(m)
291
- modifier = eval_modifier(m[1])
292
- critical_value = m[2]&.to_i || DEFAULT_CRITICAL_VALUE
293
- fumble_value = m[3]&.to_i || DEFAULT_FUMBLE_VALUE
240
+ prefix_re = Regexp.new(["2D6"].concat(aliases()).join('|'), Regexp::IGNORECASE)
241
+ parser = Command::Parser.new(prefix_re, round_type: @round_type)
242
+ .restrict_cmp_op_to(nil, :>=)
243
+ cmd = parser.parse(command)
244
+ unless cmd
245
+ return nil
246
+ end
294
247
 
295
- return SRSRollNode.new(modifier, critical_value, fumble_value, nil)
248
+ return SRSRollNode.new(cmd.modify_number, critical, fumble, cmd.target_number)
296
249
  end
297
250
 
298
251
  # 成功判定を実行する