bcdice 3.12.0 → 3.14.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -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/arithmetic/parser.rb +4 -2
  17. data/lib/bcdice/base.rb +1 -1
  18. data/lib/bcdice/command/parser.rb +4 -2
  19. data/lib/bcdice/common_command/add_dice/parser.rb +4 -2
  20. data/lib/bcdice/common_command/barabara_dice/parser.rb +4 -2
  21. data/lib/bcdice/common_command/calc/parser.rb +4 -2
  22. data/lib/bcdice/common_command/reroll_dice/parser.rb +4 -2
  23. data/lib/bcdice/common_command/tally_dice/parser.rb +4 -2
  24. data/lib/bcdice/common_command/upper_dice/parser.rb +4 -2
  25. data/lib/bcdice/dice_table/range_table.rb +24 -0
  26. data/lib/bcdice/game_system/Agnostos.rb +248 -0
  27. data/lib/bcdice/game_system/Airgetlamh.rb +1 -1
  28. data/lib/bcdice/game_system/Alsetto.rb +2 -2
  29. data/lib/bcdice/game_system/AniMalus.rb +261 -0
  30. data/lib/bcdice/game_system/Arianrhod_Korean.rb +30 -0
  31. data/lib/bcdice/game_system/ArknightsFan.rb +182 -0
  32. data/lib/bcdice/game_system/Avandner.rb +1 -1
  33. data/lib/bcdice/game_system/BBN.rb +1 -1
  34. data/lib/bcdice/game_system/BadLife.rb +3 -3
  35. data/lib/bcdice/game_system/BarnaKronika.rb +1 -1
  36. data/lib/bcdice/game_system/BlackJacket.rb +244 -0
  37. data/lib/bcdice/game_system/Chill3.rb +6 -6
  38. data/lib/bcdice/game_system/ConvictorDrive.rb +5 -4
  39. data/lib/bcdice/game_system/Cthulhu_English.rb +59 -0
  40. data/lib/bcdice/game_system/CyberpunkRed.rb +14 -4
  41. data/lib/bcdice/game_system/DarkSouls.rb +1 -1
  42. data/lib/bcdice/game_system/DivineCharger.rb +841 -0
  43. data/lib/bcdice/game_system/Elric.rb +1 -1
  44. data/lib/bcdice/game_system/FinalFantasyXIV.rb +115 -0
  45. data/lib/bcdice/game_system/FinalFantasyXIV_English.rb +39 -0
  46. data/lib/bcdice/game_system/FullFace.rb +121 -0
  47. data/lib/bcdice/game_system/FutariSousa.rb +88 -8
  48. data/lib/bcdice/game_system/InfiniteFantasia.rb +4 -1
  49. data/lib/bcdice/game_system/Insane_Korean.rb +1 -1
  50. data/lib/bcdice/game_system/InvisibleLiar.rb +79 -0
  51. data/lib/bcdice/game_system/Irisbane.rb +1 -1
  52. data/lib/bcdice/game_system/KillDeathBusiness.rb +1 -1
  53. data/lib/bcdice/game_system/KizunaBullet.rb +240 -0
  54. data/lib/bcdice/game_system/KyokoShinshoku.rb +201 -0
  55. data/lib/bcdice/game_system/Liminal.rb +136 -0
  56. data/lib/bcdice/game_system/MetalHead.rb +1 -1
  57. data/lib/bcdice/game_system/MetalHeadExtream.rb +1 -1
  58. data/lib/bcdice/game_system/MonotoneMuseum.rb +14 -1
  59. data/lib/bcdice/game_system/NRR.rb +122 -0
  60. data/lib/bcdice/game_system/NSSQ.rb +1 -1
  61. data/lib/bcdice/game_system/NightWizard.rb +1 -1
  62. data/lib/bcdice/game_system/NightWizard3rd.rb +15 -2
  63. data/lib/bcdice/game_system/OneWayHeroics.rb +1 -1
  64. data/lib/bcdice/game_system/PastFutureParadox.rb +1238 -0
  65. data/lib/bcdice/game_system/Postman.rb +3 -3
  66. data/lib/bcdice/game_system/RecordOfSteam.rb +1 -1
  67. data/lib/bcdice/game_system/RuneQuestRoleplayingInGlorantha.rb +1 -1
  68. data/lib/bcdice/game_system/Ryutama.rb +4 -4
  69. data/lib/bcdice/game_system/ShuumatsuBargainWars.rb +203 -0
  70. data/lib/bcdice/game_system/Siren.rb +97 -0
  71. data/lib/bcdice/game_system/Skynauts.rb +1 -1
  72. data/lib/bcdice/game_system/SkynautsBouken.rb +45 -130
  73. data/lib/bcdice/game_system/Strave.rb +1 -1
  74. data/lib/bcdice/game_system/SwordWorld.rb +1 -1
  75. data/lib/bcdice/game_system/TensaiGunshiNiNaro.rb +228 -0
  76. data/lib/bcdice/game_system/TheOneRing2nd.rb +406 -0
  77. data/lib/bcdice/game_system/TheUnofficialHollowKnightRPG.rb +185 -0
  78. data/lib/bcdice/game_system/TherapieSein.rb +1 -1
  79. data/lib/bcdice/game_system/TrailOfCthulhu.rb +139 -0
  80. data/lib/bcdice/game_system/TrinitySeven.rb +1 -1
  81. data/lib/bcdice/game_system/UnsungDuet.rb +17 -75
  82. data/lib/bcdice/game_system/UnsungDuet_Korean.rb +41 -0
  83. data/lib/bcdice/game_system/Utakaze.rb +55 -2
  84. data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +12 -6
  85. data/lib/bcdice/game_system/Warhammer4.rb +124 -3
  86. data/lib/bcdice/game_system/WerewolfTheApocalypse5th.rb +12 -6
  87. data/lib/bcdice/game_system/Yotabana.rb +62 -0
  88. data/lib/bcdice/game_system/cthulhu7th/full_auto.rb +1 -1
  89. data/lib/bcdice/game_system/cyberpunk_red/tables.rb +111 -473
  90. data/lib/bcdice/game_system/kizuna_bullet/tables.rb +171 -0
  91. data/lib/bcdice/game_system/sword_world/rating_parser.rb +4 -2
  92. data/lib/bcdice/game_system.rb +24 -0
  93. data/lib/bcdice/loader.rb +1 -1
  94. data/lib/bcdice/version.rb +1 -1
  95. metadata +55 -5
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bcdice/game_system/kizuna_bullet/tables"
4
+
5
+ module BCDice
6
+ module GameSystem
7
+ class KizunaBullet < Base
8
+ # ゲームシステムの識別子
9
+ ID = 'KizunaBullet'
10
+
11
+ # ゲームシステム名
12
+ NAME = 'キズナバレット'
13
+
14
+ # ゲームシステム名の読みがな
15
+ SORT_KEY = 'きすなはれつと'
16
+
17
+ # ダイスボットの使い方
18
+ HELP_MESSAGE = <<~MESSAGETEXT
19
+ ・ダイスロール
20
+ nDM…n個の6面ダイスを転がして、一番高い出目を採用します。
21
+ ・[調査判定]
22
+ nIN…n個の6面ダイスを転がして、一番高い出目が5以上なら成功します。([パートナーのヘルプ]使用可)
23
+ ・[鎮静判定]
24
+ SEn…2個の6面ダイスを転がして、出目の合計値がn([ヒビワレ]状態の[キズナ]の個数)より高いと成功します。([強制鎮静]使用可)
25
+ ・[解決] [アクション]のダメージと[アクシデント]のダメージ軽減
26
+ nSO…2+n個の6面ダイスを転がして、出目をすべて合計します。(nは減らした【励起値】。省略可能)
27
+ ・各種表
28
+ 日常表・場所 OP
29
+ 日常表・内容 OC
30
+ 日常表・場所と内容 OPC
31
+ 日常表(仕事)・場所 OWP
32
+ 日常表(仕事)・内容 OWC
33
+ 日常表(仕事)・場所と内容 OWPC
34
+ 日常表(休暇)・場所 OHP
35
+ 日常表(休暇)・内容 OHC
36
+ 日常表(休暇)・場所と内容 OHPC
37
+ 日常表(出張)・場所 OTP
38
+ 日常表(出張)・内容 OTC
39
+ 日常表(出張)・場所と内容 OTPC
40
+ ターンテーマ表 TT
41
+ ターンテーマ表・親密 TTI
42
+ ターンテーマ表・クール TTC
43
+ ターンテーマ表・主従 TTH
44
+ 遭遇表・場所 EP
45
+ 遭遇表・登場順 EO
46
+ 遭遇表・状況(初対面) EF
47
+ 遭遇表・状況(知り合い) EA
48
+ 遭遇表・決着 EE
49
+ 遭遇表・場所と登場順と状況(初対面)と決着 EFA
50
+ 遭遇表・場所と登場順と状況(知り合い)と決着 EAA
51
+ 交流表・場所 CP
52
+ 交流表・内容 CC
53
+ 交流表・場所と内容 CPC
54
+ 調査表・ベーシック IB
55
+ 調査表・ダイナミック ID
56
+ 調査表・ベーシックとダイナミック IBD
57
+ ハザード表 HA
58
+ 通常ダイジェスト キミたちに新しい命令が下った(調査が依頼された)。
59
+ 1:その事件の内容は…… NI1
60
+ 2:捜査に向かった場所は…… NI2
61
+ 3:犯人のキセキ使いは…… NI3
62
+ 4:起きた出来事は…… NI4
63
+ 5:バレットの間では…… NI5
64
+ 6:戦いの結末は…… NI6
65
+ 通常ダイジェスト キミたちは旅行(出張)である場所を訪れた。
66
+ 1:その場所とは…… NT1
67
+ 2:そこで始まったのは…… NT2
68
+ 3:極限状態のなかで…… NT3
69
+ 4:犯人のキセキ使いは…… NT4
70
+ 5:バレットの間では…… NT5
71
+ 6:戦いの結末は…… NT6
72
+ ホリデーダイジェスト キミたちは休日に出かけることにした。
73
+ 1:その場所とは…… HH1
74
+ 2:待ち合わせをしたら…… HH2
75
+ 3:そしてなんと…… HH3
76
+ 4:ふたりが決めたのは…… HH4
77
+ 5:結果的に…… HH5
78
+ 6:バレットは最後に…… HH6
79
+ ホリデーダイジェスト キミたちは奇妙な事件に出くわした。
80
+ 1:その場所とは…… HC1
81
+ 2:起きた事件は…… HC2
82
+ 3:犯人のキセキ使いは…… HC3
83
+ 4:犯人を追い詰めるべく…… HC4
84
+ 5:戦いの結果は…… HC5
85
+ 6:バレットは最後に…… HC6
86
+ MESSAGETEXT
87
+
88
+ TABLES = translate_tables(@locale)
89
+
90
+ def initialize(command)
91
+ super(command)
92
+
93
+ @sides_implicit_d = 6
94
+ @round_type = RoundType::CEIL
95
+ @d66_sort_type = D66SortType::NO_SORT
96
+ end
97
+
98
+ def eval_game_system_specific_command(command)
99
+ roll_max(command) || roll_investigate(command) || roll_sedative(command) || roll_solve(command) || roll_tables(command, self.class::TABLES)
100
+ end
101
+
102
+ private
103
+
104
+ # 最大値
105
+ def roll_max(command)
106
+ parser = Command::Parser.new("DM", round_type: @round_type)
107
+ .has_prefix_number
108
+ parsed = parser.parse(command)
109
+ unless parsed
110
+ return nil
111
+ end
112
+
113
+ # 最大値計算
114
+ dice_list = @randomizer.roll_barabara(parsed.prefix_number, 6)
115
+ max = dice_list.max
116
+
117
+ return Result.new.tap do |r|
118
+ # テキストを整形
119
+ r.text = "#{command} > [#{dice_list.join(',')}] > #{max}"
120
+ end
121
+ end
122
+
123
+ # 調査判定
124
+ def roll_investigate(command)
125
+ parser = Command::Parser.new("IN", round_type: @round_type)
126
+ .has_prefix_number
127
+ parsed = parser.parse(command)
128
+ unless parsed
129
+ return nil
130
+ end
131
+
132
+ texts = []
133
+ is_success = false
134
+ is_fumble = false
135
+
136
+ # 最大値計算
137
+ dice_list = @randomizer.roll_barabara(parsed.prefix_number, 6)
138
+ max = dice_list.max
139
+
140
+ if max >= 5
141
+ # 5以上の出目があった場合
142
+ # 成功フラグを立てる
143
+ is_success = true
144
+ # 成功メッセージを追加
145
+ texts.push(translate("KizunaBullet.INVESTIGATE.success"))
146
+ elsif max >= 3
147
+ # 3以上の出目があった場合
148
+ # 失敗メッセージを追加
149
+ texts.push(translate("KizunaBullet.INVESTIGATE.failure"))
150
+ # [パートナーのヘルプ]メッセージを追加
151
+ texts.push(translate("KizunaBullet.INVESTIGATE.partnerHelp"))
152
+ else
153
+ # 上記以外
154
+ # ファンブルフラグを立てる
155
+ is_fumble = true
156
+ # 失敗メッセージを追加
157
+ texts.push(translate("KizunaBullet.INVESTIGATE.failure"))
158
+ # ファンブルメッセージを追加
159
+ texts.push(translate("KizunaBullet.INVESTIGATE.fumble"))
160
+ end
161
+
162
+ return Result.new.tap do |r|
163
+ # テキストを整形
164
+ r.text = "#{command} > [#{dice_list.join(',')}] > #{texts.join('')}"
165
+ # 各種成否を格納
166
+ r.condition = is_success
167
+ r.fumble = is_fumble
168
+ end
169
+ end
170
+
171
+ # 鎮静判定
172
+ def roll_sedative(command)
173
+ parser = Command::Parser.new("SE", round_type: @round_type)
174
+ .has_suffix_number
175
+ parsed = parser.parse(command)
176
+ unless parsed
177
+ return nil
178
+ end
179
+
180
+ text = ''
181
+ is_success = false
182
+
183
+ # 合計値計算
184
+ sum = @randomizer.roll_sum(2, 6)
185
+
186
+ if parsed.suffix_number > 12
187
+ # 目標値が12より大きい場合
188
+ # [晶滅]メッセージを追加
189
+ text = translate("KizunaBullet.SEDATIVE.burst")
190
+ elsif parsed.suffix_number < 6
191
+ # 目標値が6より小さい場合
192
+ # [生存]メッセージを追加
193
+ text = translate("KizunaBullet.SEDATIVE.alive")
194
+ elsif sum > parsed.suffix_number
195
+ # 合計値が目標値より大きい場合
196
+ # 成功フラグを立てる
197
+ is_success = true
198
+ # 成功メッセージを追加
199
+ text = translate("KizunaBullet.SEDATIVE.success")
200
+ else
201
+ # 上記以外
202
+ # [強制鎮静]に必要な[キズナ]のチェック数の計算
203
+ # 目標値と出目の差分を計算
204
+ dif = parsed.suffix_number - sum
205
+ # チェック一つごとに結果に+2
206
+ check = (dif / 2) + 1
207
+ # 失敗メッセージを追加
208
+ text = translate("KizunaBullet.SEDATIVE.failure", check: check.to_s)
209
+ end
210
+
211
+ return Result.new.tap do |r|
212
+ # テキストを整形
213
+ r.text = "#{command} > #{sum} > #{text}"
214
+ # 各種成否を格納
215
+ r.condition = is_success
216
+ end
217
+ end
218
+
219
+ # 解決 [アクション]のダメージと[アクシデント]のダメージ軽減
220
+ def roll_solve(command)
221
+ parser = Command::Parser.new("SO", round_type: @round_type)
222
+ .enable_prefix_number
223
+ parsed = parser.parse(command)
224
+ unless parsed
225
+ return nil
226
+ end
227
+
228
+ # 合計値計算
229
+ sum = @randomizer.roll_sum(parsed.prefix_number.to_i + 2, 6)
230
+
231
+ return Result.new.tap do |r|
232
+ # テキストを整形
233
+ r.text = "#{command} > #{sum}"
234
+ end
235
+ end
236
+
237
+ register_prefix('\d+DM', '\d+IN', 'SE\d+', '\d*SO', TABLES.keys)
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,201 @@
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
+  ダイスを指定数ダイスロールして、最も高い出目を出力します。難易度を指定すると成否を判定します。オプションでA、Dをつけると、[有利][不利]の条件で振れます(A=[有利]、D=[不利])。
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
+ KS(x,y)A>=z([有利]:KS(x,y)の判定を2回行い、それぞれの結果のより大きい方が結果となります)
29
+ 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
30
+ y:ダイス数(省略:1)
31
+ z:難易度
32
+
33
+ KS(x,y)D>=z([不利]:KS(x,y)の判定を2回行い、それぞれの結果のより小さい方が結果となります)
34
+ 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
35
+ y:ダイス数(省略:1)
36
+ z:難易度
37
+
38
+ ・観測ロール
39
+  [現実乖離]の段階に応じたダイスを指定数ダイスロールして、最も高い出目を出力します。
40
+ KR(x)
41
+ x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
42
+
43
+ KR(x,y) 観測ロール(リアリティラインあり)
44
+ x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
45
+ y=[リアリティライン]のレベル(3=1個/2=2個/1=3個)
46
+
47
+ ・虚構の収束の侵蝕度減少ロール
48
+  [現実乖離]の段階に応じたダイスを指定数ダイスロールして、その合計を出力します。
49
+ KRS(x,y)
50
+ x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
51
+ y=ダイスの個数
52
+ MESSAGETEXT
53
+
54
+ register_prefix('KS', 'KR', 'KRS')
55
+
56
+ def eval_game_system_specific_command(command)
57
+ roll_check(command) || roll_kansoku(command) || roll_shusoku(command)
58
+ end
59
+
60
+ private
61
+
62
+ DICE_SIZE_TO_SIDES = {
63
+ 1 => 4,
64
+ 2 => 4,
65
+ 3 => 4,
66
+ 4 => 4,
67
+ 6 => 6,
68
+ 8 => 8,
69
+ 10 => 10,
70
+ 12 => 12,
71
+ 20 => 20,
72
+ }.freeze
73
+
74
+ def roll_check(command)
75
+ m = /^KS(?:\(([-+\d]+),([-+\d]+)?\)|(\d+))([AD]?)(?:>=([-+\d]+))?$/.match(command)
76
+ return nil unless m
77
+
78
+ dice_size = m[1] ? Arithmetic.eval(m[1], @round_type) : Arithmetic.eval(m[3], @round_type).to_i
79
+ times = m[2] ? Arithmetic.eval(m[2], @round_type) : 1
80
+ target = m[5] && Arithmetic.eval(m[5], @round_type)
81
+
82
+ advantage = m[4]
83
+
84
+ sides = DICE_SIZE_TO_SIDES[dice_size]
85
+
86
+ return nil if sides.nil? || times.nil?
87
+
88
+ rolls = Array.new(advantage.empty? ? 1 : 2) { roll_check_once(times, dice_size, sides) }
89
+ values = rolls.map { |v| v[:value] }
90
+
91
+ value =
92
+ if advantage == "A"
93
+ values.max
94
+ elsif advantage == "D"
95
+ values.min
96
+ else
97
+ values.first
98
+ end
99
+
100
+ result =
101
+ if value == 1
102
+ Result.fumble("ファンブル")
103
+ elsif target && value < target
104
+ Result.failure("失敗")
105
+ elsif target && value == sides
106
+ Result.critical("クリティカル")
107
+ elsif target && value >= target
108
+ Result.success("成功")
109
+ else
110
+ Result.new()
111
+ end
112
+
113
+ result.text = [
114
+ target ? "(KS(#{dice_size},#{times})#{advantage}>=#{target})" : "(KS(#{dice_size},#{times})#{advantage})",
115
+ format_rolls(rolls),
116
+ value,
117
+ result.text,
118
+ ].compact.join(" > ")
119
+
120
+ return result
121
+ end
122
+
123
+ def roll_check_once(times, dice_size, sides)
124
+ if times < 1
125
+ dice_list = @randomizer.roll_barabara(2, sides).sort
126
+ value = dice_list.min.clamp(1, dice_size)
127
+ else
128
+ dice_list = @randomizer.roll_barabara(times, sides).sort
129
+ value = dice_list.max.clamp(1, dice_size)
130
+ end
131
+
132
+ return {dice_list: dice_list, value: value}
133
+ end
134
+
135
+ def format_rolls(rolls)
136
+ if rolls.length == 1 && rolls.first[:dice_list].length == 1
137
+ return nil
138
+ end
139
+
140
+ rolls.map do |v|
141
+ v[:dice_list].length == 1 ? v[:value].to_s : "#{v[:value]}[#{v[:dice_list].join(',')}]"
142
+ end.join(", ")
143
+ end
144
+
145
+ GENJITU_KAIRI_TO_SIDES = [4, 6, 8, 10, 12, 20].freeze
146
+ REALITY_LINE_TO_TIMES = {
147
+ 3 => 1,
148
+ 2 => 2,
149
+ 1 => 3,
150
+ }.freeze
151
+
152
+ def roll_kansoku(command)
153
+ m = /^KR(?:(\d+)|\((\d),(\d)\))$/.match(command)
154
+ return nil unless m
155
+
156
+ dice_size = m[1]&.to_i || m[2].to_i
157
+ reality_line = m[3]&.to_i
158
+
159
+ if reality_line && (reality_line > 3 || reality_line < 1)
160
+ return nil
161
+ end
162
+
163
+ sides = GENJITU_KAIRI_TO_SIDES[dice_size - 1]
164
+ times = REALITY_LINE_TO_TIMES[reality_line] || 1
165
+
166
+ return nil unless sides
167
+
168
+ dice_list = @randomizer.roll_barabara(times, sides).sort
169
+ value = dice_list.max
170
+
171
+ cmd = reality_line ? "KR(#{dice_size},#{reality_line})" : "KR(#{dice_size})"
172
+
173
+ if times == 1
174
+ "(#{cmd}) > #{value}"
175
+ else
176
+ "(#{cmd}) > #{value}[#{dice_list.join(',')}] > #{value}"
177
+ end
178
+ end
179
+
180
+ def roll_shusoku(command)
181
+ m = /^KRS(?:\((\d),([-+\d]+)\))$/.match(command)
182
+ return nil unless m
183
+
184
+ dice_size = m[1].to_i
185
+ times = m[2] && Arithmetic.eval(m[2], @round_type)
186
+
187
+ sides = GENJITU_KAIRI_TO_SIDES[dice_size - 1]
188
+ return nil if sides.nil? || times.nil?
189
+
190
+ dice_list = @randomizer.roll_barabara(times, sides)
191
+ value = dice_list.sum
192
+
193
+ if times == 1
194
+ "(KRS(#{dice_size},#{times})) > #{value}"
195
+ else
196
+ "(KRS(#{dice_size},#{times})) > #{value}[#{dice_list.join(',')}] > #{value}"
197
+ end
198
+ end
199
+ end
200
+ end
201
+ 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
@@ -25,9 +25,16 @@ module BCDice
25
25
    クリティカル値、ファンブル値は省略可能です。([]ごと省略できます)
26
26
    自動成功、自動失敗、成功、失敗を自動表示します。
27
27
  ・各種表
28
+ 【改訂版環境】
29
+  ・感情表 MET
30
+  ・兆候表(戦闘時) MBOT/兆候表(非戦闘時) MNOT
31
+  ・歪み表 MDT
32
+  ・世界歪曲表 MWDT
33
+  ・永劫消失表 MEDT
34
+ 【旧版環境】
28
35
   ・感情表 ET/感情表 2.0 ET2
29
36
   ・兆候表 OT/兆候表ver2.0 OT2/兆候表ver3.0 OT3
30
-  ・歪み表 DT/歪み表ver2.0 DT2/歪み表(野外) DTO/歪み表(海) DTS/歪み表(館・城) DTM
37
+  ・歪み表 DT/歪み表ver2.0 DT2/歪み表(野外) DTO/歪み表(海) DTS/歪み表(館・城) DTM
31
38
   ・世界歪曲表 WDT/世界歪曲表2.0 WDT2
32
39
   ・永劫消失表 EDT
33
40
  ・D66ダイスあり
@@ -146,6 +153,12 @@ module BCDice
146
153
  "EDT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.EDT", locale),
147
154
  "DTM" => MMTable.from_i18n("MonotoneMuseum.table.DTM", locale),
148
155
  "OT3" => DiceTable::Table.from_i18n("MonotoneMuseum.table.OT3", locale),
156
+ "MET" => DiceTable::D66GridTable.from_i18n("MonotoneMuseum.table.MET", locale),
157
+ "MBOT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.MBOT", locale),
158
+ "MNOT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.MNOT", locale),
159
+ "MDT" => MMTable.from_i18n("MonotoneMuseum.table.MDT", locale),
160
+ "MWDT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.MWDT", locale),
161
+ "MEDT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.MEDT", locale),
149
162
  }
150
163
  end
151
164
  end