bcdice 3.13.0 → 3.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -0
- data/i18n/Arianrhod/ko_kr.yml +3 -0
- data/i18n/Cthulhu/en_us.yml +11 -0
- data/i18n/CyberpunkRed/ja_jp.yml +389 -0
- data/i18n/FinalFantasyXIV/en_us.yml +4 -0
- data/i18n/FinalFantasyXIV/ja_jp.yml +4 -0
- data/i18n/FutariSousa/ja_jp.yml +158 -1
- data/i18n/KizunaBullet/ja_jp.yml +653 -0
- data/i18n/MonotoneMuseum/ja_jp.yml +246 -14
- data/i18n/SkynautsBouken/ja_jp.yml +114 -0
- data/i18n/TensaiGunshiNiNaro/ja_jp.yml +126 -0
- data/i18n/UnsungDuet/ja_jp.yml +62 -0
- data/i18n/UnsungDuet/ko_kr.yml +62 -0
- data/i18n/en_us.yml +5 -0
- data/lib/bcdice/dice_table/range_table.rb +24 -0
- data/lib/bcdice/game_system/Agnostos.rb +248 -0
- data/lib/bcdice/game_system/AniMalus.rb +99 -59
- data/lib/bcdice/game_system/Arianrhod_Korean.rb +30 -0
- data/lib/bcdice/game_system/BlackJacket.rb +244 -0
- data/lib/bcdice/game_system/ConvictorDrive.rb +5 -4
- data/lib/bcdice/game_system/Cthulhu_English.rb +59 -0
- data/lib/bcdice/game_system/CyberpunkRed.rb +14 -4
- data/lib/bcdice/game_system/DivineCharger.rb +841 -0
- data/lib/bcdice/game_system/FinalFantasyXIV.rb +115 -0
- data/lib/bcdice/game_system/FinalFantasyXIV_English.rb +39 -0
- data/lib/bcdice/game_system/FullFace.rb +39 -10
- data/lib/bcdice/game_system/FutariSousa.rb +88 -8
- data/lib/bcdice/game_system/Insane_Korean.rb +1 -1
- data/lib/bcdice/game_system/InvisibleLiar.rb +79 -0
- data/lib/bcdice/game_system/KizunaBullet.rb +240 -0
- data/lib/bcdice/game_system/KyokoShinshoku.rb +51 -8
- data/lib/bcdice/game_system/MonotoneMuseum.rb +14 -1
- data/lib/bcdice/game_system/NRR.rb +2 -2
- data/lib/bcdice/game_system/ShuumatsuBargainWars.rb +203 -0
- data/lib/bcdice/game_system/SkynautsBouken.rb +45 -130
- data/lib/bcdice/game_system/SwordWorld.rb +1 -1
- data/lib/bcdice/game_system/TensaiGunshiNiNaro.rb +228 -0
- data/lib/bcdice/game_system/TheOneRing2nd.rb +406 -0
- data/lib/bcdice/game_system/TheUnofficialHollowKnightRPG.rb +185 -0
- data/lib/bcdice/game_system/TrailOfCthulhu.rb +139 -0
- data/lib/bcdice/game_system/UnsungDuet.rb +17 -75
- data/lib/bcdice/game_system/UnsungDuet_Korean.rb +41 -0
- data/lib/bcdice/game_system/Utakaze.rb +55 -2
- data/lib/bcdice/game_system/Warhammer4.rb +124 -3
- data/lib/bcdice/game_system/Yotabana.rb +62 -0
- data/lib/bcdice/game_system/cyberpunk_red/tables.rb +111 -473
- data/lib/bcdice/game_system/kizuna_bullet/tables.rb +171 -0
- data/lib/bcdice/game_system.rb +16 -0
- data/lib/bcdice/version.rb +1 -1
- 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
|