bcdice 3.14.0 → 3.15.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 +4 -4
- data/CHANGELOG.md +59 -0
- data/i18n/Cthulhu/zh_hant.yml +1 -1
- data/i18n/CyberpunkRed/ko_kr.yml +389 -0
- data/i18n/DoubleCross/ja_jp.yml +53 -0
- data/i18n/DoubleCross/ko_kr.yml +52 -0
- data/i18n/FutariSousa/ja_jp.yml +138 -138
- data/i18n/KillDeathBusiness/ja_jp.yml +198 -0
- data/i18n/MagicaLogia/ko_kr.yml +2 -2
- data/i18n/MonotoneMuseum/ko_kr.yml +227 -0
- data/i18n/SkynautsBouken/ko_kr.yml +114 -0
- data/i18n/StratoShout/ko_kr.yml +102 -102
- data/i18n/zh_hant.yml +5 -0
- data/lib/bcdice/game_system/Aionia.rb +131 -0
- data/lib/bcdice/game_system/Arianrhod_Korean.rb +2 -0
- data/lib/bcdice/game_system/ArknightsFan.rb +245 -87
- data/lib/bcdice/game_system/BlackJacket_Korean.rb +244 -0
- data/lib/bcdice/game_system/CharonSanctions.rb +112 -0
- data/lib/bcdice/game_system/Cthulhu7th.rb +1 -1
- data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional/full_auto.rb +293 -0
- data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional/rollable.rb +43 -0
- data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb +470 -306
- data/lib/bcdice/game_system/CyberpunkRed.rb +1 -2
- data/lib/bcdice/game_system/CyberpunkRed_Korean.rb +66 -0
- data/lib/bcdice/game_system/DoubleCross.rb +18 -1
- data/lib/bcdice/game_system/DoubleCross_Korean.rb +5 -1
- data/lib/bcdice/game_system/FullFace.rb +25 -3
- data/lib/bcdice/game_system/FutariSousa.rb +17 -5
- data/lib/bcdice/game_system/Garactier.rb +479 -0
- data/lib/bcdice/game_system/GardenOrder.rb +390 -9
- data/lib/bcdice/game_system/GundogRevised.rb +8 -8
- data/lib/bcdice/game_system/KillDeathBusiness.rb +155 -3
- data/lib/bcdice/game_system/KimitoYell.rb +568 -0
- data/lib/bcdice/game_system/Magius.rb +125 -0
- data/lib/bcdice/game_system/Magius_3rdNewTokyoCity.rb +62 -0
- data/lib/bcdice/game_system/MonotoneMuseum_Korean.rb +4 -4
- data/lib/bcdice/game_system/NSSQ.rb +17 -9
- data/lib/bcdice/game_system/NervWhitePaper.rb +129 -0
- data/lib/bcdice/game_system/RogueLikeHalf.rb +198 -0
- data/lib/bcdice/game_system/RuneQuestRoleplayingInGlorantha.rb +16 -13
- data/lib/bcdice/game_system/ShinobiGami.rb +73 -43
- data/lib/bcdice/game_system/SkynautsBouken.rb +4 -4
- data/lib/bcdice/game_system/SkynautsBouken_Korean.rb +57 -0
- data/lib/bcdice/game_system/StratoShout_Korean.rb +1 -1
- data/lib/bcdice/game_system/SwordWorld.rb +4 -0
- data/lib/bcdice/game_system/SwordWorld2_5.rb +3 -2
- data/lib/bcdice/game_system/TensaiGunshiNiNaro.rb +51 -17
- data/lib/bcdice/game_system/TheIndieHack.rb +82 -0
- data/lib/bcdice/game_system/TorgEternity.rb +35 -6
- data/lib/bcdice/game_system/WoW.rb +161 -0
- data/lib/bcdice/game_system/YankeeMustDie.rb +192 -0
- data/lib/bcdice/game_system/YearZeroEngine.rb +225 -28
- data/lib/bcdice/game_system/YuMyoKishi.rb +141 -0
- data/lib/bcdice/game_system/sword_world/rating_lexer.rb +1 -0
- data/lib/bcdice/game_system/sword_world/rating_options.rb +4 -1
- data/lib/bcdice/game_system/sword_world/rating_parsed.rb +5 -0
- data/lib/bcdice/game_system/sword_world/rating_parser.rb +129 -115
- data/lib/bcdice/game_system.rb +15 -0
- data/lib/bcdice/version.rb +1 -1
- metadata +22 -6
@@ -7,159 +7,302 @@ module BCDice
|
|
7
7
|
ID = "ArknightsFan"
|
8
8
|
|
9
9
|
# ゲームシステム名
|
10
|
-
NAME = "アークナイツTRPG by
|
10
|
+
NAME = "アークナイツTRPG by daaaper"
|
11
11
|
|
12
12
|
# ゲームシステム名の読みがな
|
13
|
-
SORT_KEY = "ああくないつTRPG
|
13
|
+
SORT_KEY = "ああくないつTRPGはいてえはあ"
|
14
14
|
|
15
15
|
HELP_MESSAGE = <<~TEXT
|
16
|
-
■
|
17
|
-
nDm
|
16
|
+
■ 能力値判定 (nADm<=x)
|
17
|
+
nDmのダイスロールをして、出目が x 以下であれば成功。
|
18
18
|
出目が91以上でエラー。
|
19
19
|
出目が10以下でクリティカル。
|
20
20
|
|
21
|
-
■
|
21
|
+
■ 攻撃/防御判定 (nABm<=x)
|
22
22
|
nBmのダイスロールをして、
|
23
|
-
x 以下であれば成功数+1。
|
24
|
-
出目が91
|
25
|
-
出目が10
|
23
|
+
出目が x 以下であれば成功数+1。
|
24
|
+
出目が91以上でエラー。成功数-1。
|
25
|
+
出目が10以下でクリティカル。成功数+1。
|
26
26
|
上記による成功数をカウント。
|
27
27
|
|
28
|
-
■
|
28
|
+
■ 役職効果付き攻撃判定 (nABm<=x--役職名h)
|
29
|
+
h: 健康状態(0: 健康、1: 中等症、2: 重症)
|
29
30
|
nBmのダイスロールをして、
|
30
31
|
出目が x 以下であれば成功数+1。
|
31
|
-
出目が91
|
32
|
-
出目が10
|
33
|
-
|
34
|
-
狙撃(
|
32
|
+
出目が91以上でエラー。成功数-1。
|
33
|
+
出目が10以下でクリティカル。成功数+1。
|
34
|
+
上記による成功数をカウントした上で、以下の役職名による成功数増加効果を適応。
|
35
|
+
狙撃(SNI): 健康(h=0)かつ成功数1以上のとき、成功数+1。
|
36
|
+
健康状態hを省略した場合、健康(h=0)として扱われる。
|
37
|
+
|
38
|
+
■ 鉱石病判定 (ORPx@y+Dd+Tt)
|
39
|
+
x: 生理的耐性、y: 上昇後侵食度、d: ダイス補正、t: 判定値補正
|
40
|
+
生理的耐性xのOPが侵食度yに上昇した際の鉱石病判定を、ダイス数補正d、判定値補正tで行う。
|
41
|
+
ダイス数補正と判定値補正は省略可能。例えば ORP60@25 は ORP60@25+D0+T0 と同義。
|
42
|
+
また、ダイス数補正と判定値補正は逆順でも可。例えば ORP60@25+T10+D2 も可。
|
43
|
+
|
44
|
+
■ 増悪判定(--WORSENING)
|
45
|
+
症状を「末梢神経障害」「内臓機能不全」「精神症状」からランダムに選択。
|
46
|
+
継続ラウンド数を1d6+1で判定。
|
47
|
+
|
48
|
+
■ 中毒判定(--ADDICTION)
|
49
|
+
症状を「脳神経障害」「多臓器不全」「急性精神反応」からランダムに選択。
|
50
|
+
|
51
|
+
■ 判定の省略表記
|
52
|
+
nADm、nABm、nABmにおいて、
|
53
|
+
n(ダイス個数)を省略した場合、1として扱われる。
|
54
|
+
m(ダイス種類)を省略した場合、100として扱われる。
|
55
|
+
例えば、AD<=90は1AD100<=90として解釈される。
|
35
56
|
TEXT
|
36
57
|
|
37
|
-
register_prefix('
|
58
|
+
register_prefix('[-+*/\d]*AD\d*', '[-+*/\d]*AB\d*', 'ORP', '--WORSENING', '--ADDICTION')
|
59
|
+
|
60
|
+
def initialize(command)
|
61
|
+
super(command)
|
62
|
+
@sort_add_dice = true # 加算ダイスでダイス目をソートする
|
63
|
+
@sort_barabara_dice = true # バラバラダイスでダイス目をソートする
|
64
|
+
@sides_implicit_d = 100 # 1D のようにダイスの面数が指定されていない場合に100面ダイスにする
|
65
|
+
end
|
38
66
|
|
39
67
|
def eval_game_system_specific_command(command)
|
40
|
-
|
68
|
+
eval_ad(command) || eval_ab(command) || eval_orp(command) || eval_worsening(command) || eval_addiction(command)
|
41
69
|
end
|
42
70
|
|
43
71
|
private
|
44
72
|
|
45
|
-
|
46
|
-
|
73
|
+
module Status
|
74
|
+
CRITICAL = 1
|
75
|
+
SUCCESS = 2
|
76
|
+
FAILURE = 3
|
77
|
+
ERROR = 4
|
78
|
+
end
|
79
|
+
|
80
|
+
STATUS_NAME = {
|
81
|
+
Status::CRITICAL => 'クリティカル!',
|
82
|
+
Status::SUCCESS => '成功',
|
83
|
+
Status::FAILURE => '失敗',
|
84
|
+
Status::ERROR => 'エラー'
|
85
|
+
}.freeze
|
86
|
+
|
87
|
+
# クリティカル、エラー、成功失敗周りの閾値や優先関係が複雑かつルールが変動する可能性があるため、明示的にルール管理するための関数。
|
88
|
+
def check_roll(roll_result, target)
|
89
|
+
success = roll_result <= target
|
90
|
+
|
91
|
+
crierror =
|
92
|
+
if roll_result <= 10
|
93
|
+
"Critical"
|
94
|
+
elsif roll_result >= 91
|
95
|
+
"Error"
|
96
|
+
else
|
97
|
+
"Neutral"
|
98
|
+
end
|
99
|
+
|
100
|
+
result =
|
101
|
+
if success && (crierror == "Critical")
|
102
|
+
Status::CRITICAL
|
103
|
+
elsif success && (crierror == "Neutral")
|
104
|
+
Status::SUCCESS
|
105
|
+
elsif success && (crierror == "Error")
|
106
|
+
Status::SUCCESS
|
107
|
+
elsif !success && (crierror == "Critical")
|
108
|
+
Status::FAILURE
|
109
|
+
elsif !success && (crierror == "Neutral")
|
110
|
+
Status::FAILURE
|
111
|
+
elsif !success && (crierror == "Error")
|
112
|
+
Status::ERROR
|
113
|
+
end
|
114
|
+
|
115
|
+
return result
|
116
|
+
end
|
117
|
+
|
118
|
+
def eval_ad(command)
|
119
|
+
# -は文字クラスの先頭または最後に置く。
|
120
|
+
# そうしないと範囲指定子として解釈される。
|
121
|
+
m = %r{^([-+*/\d]*)AD(\d*)<=([-+*/\d]+)$}.match(command)
|
47
122
|
return nil unless m
|
48
123
|
|
49
124
|
times = m[1]
|
50
125
|
sides = m[2]
|
51
|
-
target = m[3]
|
52
|
-
times = !times.empty? ?
|
126
|
+
target = Arithmetic.eval(m[3], @round_type)
|
127
|
+
times = !times.empty? ? Arithmetic.eval(m[1], @round_type) : 1
|
53
128
|
sides = !sides.empty? ? sides.to_i : 100
|
54
|
-
|
129
|
+
|
130
|
+
roll_ad(command, times, sides, target)
|
55
131
|
end
|
56
132
|
|
57
|
-
def
|
58
|
-
m =
|
133
|
+
def eval_ab(command)
|
134
|
+
m = %r{^([-+*/\d]*)AB(\d*)<=([-+*/\d]+)(?:--([^\d\s]+)([0-2])?)?$}.match(command)
|
59
135
|
return nil unless m
|
60
136
|
|
61
137
|
times = m[1]
|
62
138
|
sides = m[2]
|
63
|
-
target = m[3]
|
139
|
+
target = Arithmetic.eval(m[3], @round_type)
|
64
140
|
type = m[4]
|
65
|
-
|
66
|
-
times = !times.empty? ?
|
141
|
+
type_status = m[5]
|
142
|
+
times = !times.empty? ? Arithmetic.eval(m[1], @round_type) : 1
|
67
143
|
sides = !sides.empty? ? sides.to_i : 100
|
144
|
+
if !type_status.nil?
|
145
|
+
type_status = type_status.to_i
|
146
|
+
elsif type == "SNIPER" # スプレッドシート版キャラシの後方互換性のために必要
|
147
|
+
type_status = 1
|
148
|
+
else
|
149
|
+
type_status = 0
|
150
|
+
end
|
68
151
|
|
69
|
-
if
|
70
|
-
|
152
|
+
if type.nil?
|
153
|
+
roll_ab(command, times, sides, target)
|
71
154
|
else
|
72
|
-
|
155
|
+
roll_ab_withtype(command, times, sides, target, type, type_status)
|
73
156
|
end
|
74
157
|
end
|
75
158
|
|
76
|
-
def
|
159
|
+
def eval_orp(command)
|
160
|
+
m = %r{^ORP(?'END'[-+*/\d]+)@(?'ORP'[-+*/\d]+)(?:\+D(?'DICE'[-+*/\d]+))?(?:\+T(?'TGT'[-+*/\d]+))?$}.match(command)
|
161
|
+
# D補正とT補正が逆順でも対応する
|
162
|
+
m ||= %r{^ORP(?'END'[-+*/\d]+)@(?'ORP'[-+*/\d]+)(?:\+T(?'TGT'[-+*/\d]+))?(?:\+D(?'DICE'[-+*/\d]+))?$}.match(command)
|
163
|
+
return nil unless m
|
164
|
+
|
165
|
+
endurance = Arithmetic.eval(m[:END], @round_type)
|
166
|
+
oripathy = Arithmetic.eval(m[:ORP], @round_type)
|
167
|
+
times_mod = !m[3].nil? ? Arithmetic.eval(m[:DICE], @round_type) : 0
|
168
|
+
target_mod = !m[4].nil? ? Arithmetic.eval(m[:TGT], @round_type) : 0
|
169
|
+
|
170
|
+
roll_orp(command, endurance, oripathy, times_mod, target_mod)
|
171
|
+
end
|
172
|
+
|
173
|
+
def roll_ad(command, times, sides, target)
|
77
174
|
dice_list = @randomizer.roll_barabara(times, sides).sort
|
78
175
|
total = dice_list.sum
|
79
|
-
success = total <= target
|
80
176
|
|
81
|
-
|
82
|
-
if total <= 10
|
83
|
-
"Critical"
|
84
|
-
elsif total >= 91
|
85
|
-
"Error"
|
86
|
-
else
|
87
|
-
"Neutral"
|
88
|
-
end
|
89
|
-
|
90
|
-
result =
|
91
|
-
if success && (crierror == "Critical")
|
92
|
-
"クリティカル!"
|
93
|
-
elsif success && (crierror == "Neutral")
|
94
|
-
"成功"
|
95
|
-
elsif success && (crierror == "Error")
|
96
|
-
"成功"
|
97
|
-
elsif !success && (crierror == "Critical")
|
98
|
-
"失敗"
|
99
|
-
elsif !success && (crierror == "Neutral")
|
100
|
-
"失敗"
|
101
|
-
elsif !success && (crierror == "Error")
|
102
|
-
"エラー"
|
103
|
-
end
|
177
|
+
result = check_roll(total, target)
|
104
178
|
|
105
179
|
if times == 1
|
106
|
-
|
180
|
+
result_text = "(#{command}) > #{dice_list.join(',')} > #{STATUS_NAME[result]}"
|
107
181
|
else
|
108
|
-
|
182
|
+
result_text = "(#{command}) > #{total}[#{dice_list.join(',')}] > #{STATUS_NAME[result]}"
|
183
|
+
end
|
184
|
+
case result
|
185
|
+
when Status::CRITICAL
|
186
|
+
Result.critical(result_text)
|
187
|
+
when Status::SUCCESS
|
188
|
+
Result.success(result_text)
|
189
|
+
when Status::FAILURE
|
190
|
+
Result.failure(result_text)
|
191
|
+
when Status::ERROR
|
192
|
+
Result.fumble(result_text)
|
109
193
|
end
|
110
194
|
end
|
111
195
|
|
112
|
-
def
|
113
|
-
dice_list
|
196
|
+
def roll_ab(command, times, sides, target)
|
197
|
+
dice_list = @randomizer.roll_barabara(times, sides).sort
|
198
|
+
|
199
|
+
success_count, critical_count, error_count = process_ab(dice_list, target)
|
114
200
|
result_count = success_count + critical_count - error_count
|
115
201
|
|
116
|
-
|
202
|
+
result_text = "(#{command}) > [#{dice_list.join(',')}] > #{success_count}+#{critical_count}C-#{error_count}E > 成功数#{result_count}"
|
203
|
+
Result.new.tap do |r|
|
204
|
+
r.text = result_text
|
205
|
+
r.condition = result_count > 0
|
206
|
+
r.critical = critical_count > 0
|
207
|
+
r.fumble = error_count > 0
|
208
|
+
end
|
117
209
|
end
|
118
210
|
|
119
|
-
def
|
120
|
-
dice_list
|
211
|
+
def roll_ab_withtype(command, times, sides, target, type, type_status)
|
212
|
+
dice_list = @randomizer.roll_barabara(times, sides).sort
|
213
|
+
|
214
|
+
success_count, critical_count, error_count = process_ab(dice_list, target)
|
121
215
|
result_count = success_count + critical_count - error_count
|
122
216
|
|
123
|
-
|
124
|
-
|
125
|
-
|
217
|
+
case type
|
218
|
+
when "SNI"
|
219
|
+
if (type_status == 0) && (result_count > 0)
|
220
|
+
result_mod = 1
|
221
|
+
else
|
222
|
+
result_mod = 0
|
223
|
+
end
|
224
|
+
when "SNIPER" # スプレッドシート版キャラシの後方互換性のため残している
|
225
|
+
if (type_status != 0) && (result_count > 0)
|
226
|
+
result_mod = 1
|
126
227
|
else
|
127
|
-
0
|
228
|
+
result_mod = 0
|
128
229
|
end
|
129
|
-
|
230
|
+
end
|
130
231
|
|
131
|
-
|
232
|
+
if !result_mod.nil?
|
233
|
+
result_count += result_mod
|
234
|
+
result_text = "(#{command}) > [#{dice_list.join(',')}] > #{success_count}+#{critical_count}C-#{error_count}E+#{result_mod}(#{type}) > 成功数#{result_count}"
|
235
|
+
else
|
236
|
+
result_text = "(#{command}) > [#{dice_list.join(',')}] > #{success_count}+#{critical_count}C-#{error_count}E > 成功数#{result_count}"
|
237
|
+
end
|
238
|
+
Result.new.tap do |r|
|
239
|
+
r.text = result_text
|
240
|
+
r.condition = result_count > 0
|
241
|
+
r.critical = critical_count > 0
|
242
|
+
r.fumble = error_count > 0
|
243
|
+
end
|
132
244
|
end
|
133
245
|
|
134
|
-
|
246
|
+
ENDURANCE_LEVEL_TABLE = [20, 40, 70, 90, Float::INFINITY].freeze # 生理的耐性の実数値から能力評価への変換テーブル
|
247
|
+
ORP_TIMES_TABLE = [1, 2, 2, 3, 4].freeze # 生理的耐性の能力評価ごとのダイス数基本値
|
248
|
+
def roll_orp(command, endurance, oripathy, times_mod, target_mod)
|
249
|
+
sides = 100
|
250
|
+
|
251
|
+
endurance_level = ENDURANCE_LEVEL_TABLE.find_index { |n| endurance <= n }
|
252
|
+
original_times = ORP_TIMES_TABLE[endurance_level]
|
253
|
+
times = original_times + times_mod
|
254
|
+
|
255
|
+
if oripathy <= 20
|
256
|
+
return Result.new("(#{command}) > 鉱石病判定が発生しない侵食度です。侵食度は21以上を指定してください。")
|
257
|
+
end
|
258
|
+
|
259
|
+
oripathy_stage = (oripathy / 20.0).ceil - 1
|
260
|
+
original_target = (80 - oripathy_stage * 20) - (oripathy - oripathy_stage * 20) * 5
|
261
|
+
target = original_target + target_mod
|
262
|
+
dice_and_target_text = "ダイス数#{original_times}" +
|
263
|
+
(times_mod > 0 ? "+#{times_mod}" : "") +
|
264
|
+
"、判定値#{original_target}" +
|
265
|
+
(target_mod > 0 ? "+#{target_mod}" : "")
|
266
|
+
result_texts = ["(#{command})", dice_and_target_text, "#{times}B100<=#{target}"]
|
267
|
+
|
268
|
+
if target <= 0
|
269
|
+
result_texts += ["自動失敗!"]
|
270
|
+
return Result.failure(result_texts.join(" > "))
|
271
|
+
end
|
272
|
+
|
273
|
+
# 複数振ったダイスのうち1つでも判定値を下回れば成功なので、最も出目の小さいダイスのみを確認すればよい。
|
274
|
+
# dice_listをソートした上で、dice_list[0]が最小の出目。
|
135
275
|
dice_list = @randomizer.roll_barabara(times, sides).sort
|
276
|
+
success_count = dice_list.count { |n| n <= target }
|
277
|
+
if success_count > 0
|
278
|
+
result_texts += ["[#{dice_list.join(',')}]", "成功数#{success_count}", "成功"]
|
279
|
+
Result.success(result_texts.join(" > "))
|
280
|
+
else
|
281
|
+
result_texts += ["[#{dice_list.join(',')}]", "成功数#{success_count}", "失敗"]
|
282
|
+
Result.failure(result_texts.join(" > "))
|
283
|
+
end
|
284
|
+
end
|
136
285
|
|
286
|
+
def process_ab(dice_list, target)
|
137
287
|
success_count = 0
|
138
288
|
critical_count = 0
|
139
289
|
error_count = 0
|
140
290
|
|
141
291
|
dice_list.each do |value|
|
142
|
-
|
143
|
-
|
144
|
-
|
292
|
+
case check_roll(value, target)
|
293
|
+
when Status::CRITICAL
|
294
|
+
critical_count += 1
|
295
|
+
success_count += 1
|
296
|
+
when Status::SUCCESS
|
297
|
+
success_count += 1
|
298
|
+
when Status::FAILURE
|
299
|
+
# Nothing to do
|
300
|
+
when Status::ERROR
|
301
|
+
error_count += 1
|
302
|
+
end
|
145
303
|
end
|
146
304
|
|
147
|
-
return [
|
148
|
-
end
|
149
|
-
|
150
|
-
ADDICTION_TABLE = [
|
151
|
-
"中枢神経障害",
|
152
|
-
"多臓器不全",
|
153
|
-
"急性ストレス反応",
|
154
|
-
].freeze
|
155
|
-
|
156
|
-
def roll_addiction(command)
|
157
|
-
return nil if command != "--ADDICTION"
|
158
|
-
|
159
|
-
value = @randomizer.roll_once(3)
|
160
|
-
chosen = ADDICTION_TABLE[value - 1]
|
161
|
-
|
162
|
-
return "--ADDICTION > #{chosen}"
|
305
|
+
return [success_count, critical_count, error_count]
|
163
306
|
end
|
164
307
|
|
165
308
|
WORSENING_TABLE = [
|
@@ -168,7 +311,7 @@ module BCDice
|
|
168
311
|
"精神症状",
|
169
312
|
].freeze
|
170
313
|
|
171
|
-
def
|
314
|
+
def eval_worsening(command)
|
172
315
|
return nil if command != "--WORSENING"
|
173
316
|
|
174
317
|
value = @randomizer.roll_once(3)
|
@@ -177,6 +320,21 @@ module BCDice
|
|
177
320
|
|
178
321
|
return "--WORSENING > #{chosen}: #{elapse} rounds"
|
179
322
|
end
|
323
|
+
|
324
|
+
ADDICTION_TABLE = [
|
325
|
+
"脳神経障害",
|
326
|
+
"多臓器不全",
|
327
|
+
"急性精神症状",
|
328
|
+
].freeze
|
329
|
+
|
330
|
+
def eval_addiction(command)
|
331
|
+
return nil if command != "--ADDICTION"
|
332
|
+
|
333
|
+
value = @randomizer.roll_once(3)
|
334
|
+
chosen = ADDICTION_TABLE[value - 1]
|
335
|
+
|
336
|
+
return "--ADDICTION > #{chosen}"
|
337
|
+
end
|
180
338
|
end
|
181
339
|
end
|
182
340
|
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bcdice/dice_table/range_table'
|
4
|
+
|
5
|
+
module BCDice
|
6
|
+
module GameSystem
|
7
|
+
class BlackJacket_Korean < BlackJacket
|
8
|
+
# ゲームシステムの識別子
|
9
|
+
ID = 'BlackJacket:Korean'
|
10
|
+
|
11
|
+
# ゲームシステム名
|
12
|
+
NAME = '블랙재킷RPG'
|
13
|
+
|
14
|
+
# ゲームシステム名の読みがな
|
15
|
+
SORT_KEY = '国際化:Korean:블랙재킷RPG'
|
16
|
+
|
17
|
+
# ダイスボットの使い方
|
18
|
+
HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
|
19
|
+
・행위 판정(BJx)
|
20
|
+
x:성공률
|
21
|
+
예)BJ80
|
22
|
+
크리티컬,펌블 여부는 자동으로 판정합니다.
|
23
|
+
「BJ50+20-30」처럼 값을 가감하여 기재할 수 있습니다.
|
24
|
+
성공률의 상한은 100%、하한은 0% 입니다.
|
25
|
+
・데스 차트 (DCxY)
|
26
|
+
x:차트 종류. 육체:DCL, 정신:DCS, 환경:DCC
|
27
|
+
Y=마이너스 값
|
28
|
+
예)DCL5:라이프 마이너스 값 5 + 1D10 판정
|
29
|
+
DCS3:새니티 마이너스 값 3 + 1D10 판정
|
30
|
+
DCC0:크레딧 마이너스 값 0 + 1D10 판정
|
31
|
+
・챌린지・패널티 차트(CPC)
|
32
|
+
・사이드 트랙 차트(STC)
|
33
|
+
INFO_MESSAGE_TEXT
|
34
|
+
|
35
|
+
def eval_game_system_specific_command(command)
|
36
|
+
resolute_action(command) || roll_death_chart(command) || roll_tables(command, TABLES)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def resolute_action(command)
|
42
|
+
m = /^BJ(\d+([+-]\d+)*)$/.match(command)
|
43
|
+
unless m
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
|
47
|
+
success_rate = ArithmeticEvaluator.eval(m[1])
|
48
|
+
|
49
|
+
roll_result, dice10, dice01 = roll_d100
|
50
|
+
roll_result_text = format('%02d', roll_result)
|
51
|
+
|
52
|
+
result = action_result(roll_result, dice10, dice01, success_rate)
|
53
|
+
|
54
|
+
sequence = [
|
55
|
+
"행위판정(성공률:#{success_rate}%)",
|
56
|
+
"1D100[#{dice10},#{dice01}]=#{roll_result_text}",
|
57
|
+
roll_result_text.to_s,
|
58
|
+
result.text
|
59
|
+
]
|
60
|
+
|
61
|
+
result.text = sequence.join(" > ")
|
62
|
+
result
|
63
|
+
end
|
64
|
+
|
65
|
+
SUCCESS_STR = "성공"
|
66
|
+
FAILURE_STR = "실패"
|
67
|
+
CRITICAL_STR = (SUCCESS_STR + " > 크리티컬! 파워의 대가(코스트) 절반으로 감소").freeze
|
68
|
+
FUMBLE_STR = (FAILURE_STR + " > 펌블! 파워의 대가(코스트) 2배 & 재굴림 불가").freeze
|
69
|
+
MISERY_STR = (FAILURE_STR + " > 미저리! 파워의 대가(코스트) 2배 & 재굴림 불가").freeze
|
70
|
+
|
71
|
+
def action_result(total, tens, ones, success_rate)
|
72
|
+
if total == 100
|
73
|
+
Result.fumble(MISERY_STR)
|
74
|
+
elsif success_rate <= 0
|
75
|
+
Result.fumble(FUMBLE_STR)
|
76
|
+
elsif total <= success_rate - 100
|
77
|
+
Result.critical(CRITICAL_STR)
|
78
|
+
elsif tens == ones
|
79
|
+
if total <= success_rate
|
80
|
+
Result.critical(CRITICAL_STR)
|
81
|
+
else
|
82
|
+
Result.fumble(FUMBLE_STR)
|
83
|
+
end
|
84
|
+
elsif total <= success_rate
|
85
|
+
Result.success(SUCCESS_STR)
|
86
|
+
else
|
87
|
+
Result.failure(FAILURE_STR)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def roll_d100
|
92
|
+
dice10 = @randomizer.roll_once(10)
|
93
|
+
dice10 = 0 if dice10 == 10
|
94
|
+
dice01 = @randomizer.roll_once(10)
|
95
|
+
dice01 = 0 if dice01 == 10
|
96
|
+
|
97
|
+
roll_result = dice10 * 10 + dice01
|
98
|
+
roll_result = 100 if roll_result == 0
|
99
|
+
|
100
|
+
return roll_result, dice10, dice01
|
101
|
+
end
|
102
|
+
|
103
|
+
class DeathChart
|
104
|
+
def initialize(name, chart)
|
105
|
+
@name = name
|
106
|
+
@chart = chart.freeze
|
107
|
+
|
108
|
+
if @chart.size != 11
|
109
|
+
raise ArgumentError, "unexpected chart size #{name.inspect} (given #{@chart.size}, expected 11)"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param randomizer [Randomizer]
|
114
|
+
# @param minus_score [Integer]
|
115
|
+
# @return [String]
|
116
|
+
def roll(randomizer, minus_score)
|
117
|
+
dice = randomizer.roll_once(10)
|
118
|
+
key_number = dice + minus_score
|
119
|
+
|
120
|
+
key_text, chosen = at(key_number)
|
121
|
+
|
122
|
+
return "데스 차트(#{@name})[마이너스 값:#{minus_score} + 1D10(->#{dice}) = #{key_number}] > #{key_text} : #{chosen}"
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
# key_numberの10から20がindexの0から10に対応する
|
128
|
+
def at(key_number)
|
129
|
+
if key_number < 10
|
130
|
+
["10이하", @chart.first]
|
131
|
+
elsif key_number > 20
|
132
|
+
["20이상", @chart.last]
|
133
|
+
else
|
134
|
+
[key_number.to_s, @chart[key_number - 10]]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def roll_death_chart(command)
|
140
|
+
m = /^DC([LSC])(\d+)$/i.match(command)
|
141
|
+
unless m
|
142
|
+
return m
|
143
|
+
end
|
144
|
+
|
145
|
+
chart = DEATH_CHARTS[m[1]]
|
146
|
+
minus_score = m[2].to_i
|
147
|
+
|
148
|
+
return chart.roll(@randomizer, minus_score)
|
149
|
+
end
|
150
|
+
|
151
|
+
DEATH_CHARTS = {
|
152
|
+
'L' => DeathChart.new(
|
153
|
+
'육체',
|
154
|
+
[
|
155
|
+
"효과 없음. 당신은 기적적으로 목숨을 건졌다. 싸움은 계속된다.",
|
156
|
+
"격한 통증을 느낀다. 이후 이벤트가 끝날 때까지 모든 판정의 성공률에 -10%.",
|
157
|
+
"더이상 몸이 움직이지 않는다…… 당신은 [경직 2]를 받는다.",
|
158
|
+
"혼신의 일격!! 당신은 〈생존〉 판정을 한다. 실패할 경우 [사망]한다.",
|
159
|
+
"갑자기 눈앞이 캄캄해진다. 당신은 [기절 2]를 받는다.",
|
160
|
+
"이후, 이벤트 종료까지 모든 판정의 성공률 -20%.",
|
161
|
+
"기록적인 일격!! 당신은 〈생존〉 -20% 으로 판정한다. 실패할 경우 [사망]한다.",
|
162
|
+
"사느냐 죽느냐. 당신은 [빈사 2]를 받는다.",
|
163
|
+
"역사에 한 획을 그을 일격!! 당신은 <생존> -30% 으로 판정한다. 실패할 경우 [사망]한다.",
|
164
|
+
"이후, 이벤트 종료 시까지 모든 판정의 성공률 -30%.",
|
165
|
+
"신화적 일격!! 공중에서 세 바퀴 정도 회전한 후 땅바닥에 내동댕이쳐진다. 보기에도 끔찍한 모습. 육체는 원형을 유지하지 못했다. 당신은 [사망]한다.",
|
166
|
+
]
|
167
|
+
),
|
168
|
+
'S' => DeathChart.new(
|
169
|
+
'정신',
|
170
|
+
[
|
171
|
+
"효과 없음. 당신은 이를 악물고 스트레스를 견뎌냈다.",
|
172
|
+
"이후, 이벤트 종료 시까지 모든 판정의 성공률 -10%.",
|
173
|
+
"말할 수 없는 공포가 당신을 엄습한다. 당신은 [공포 2]를 받는다.",
|
174
|
+
"상처를 많이 받았다. 당신은 〈의지〉 판정을 한다. 실패할 경우 [절망] 상태가 되어서 NPC가 된다.",
|
175
|
+
"의식을 잃었다. 당신은 [기절 2]를 받는다.",
|
176
|
+
"이후, 이벤트 종료 시까지 모든 판정의 성공률 -20%.",
|
177
|
+
"신뢰했던 자에게 속은 아픔. 당신은 〈의지〉 -20% 으로 판정한다. 실패할 경우, [절망] 상태가 되어서 NPC가 된다.",
|
178
|
+
"동료에게 배신 당한 것일지도 모른다. 당신은 [혼란 2]를 받는다.",
|
179
|
+
"너무나 참혹한 현실. 당신은 〈의지〉 -30% 으로 판정한다. 실패할 경우 [절망] 상태가 되어서 NPC가 된다.",
|
180
|
+
"이후, 이벤트 종료 시까지 모든 판정의 성공률 -30%.",
|
181
|
+
"천지개벽의 이치 그 이상. 그것은 인류의 인식한계를 뛰어넘는 무언가였다. 당신은 [절망] 상태가 된 후 NPC가 된다.",
|
182
|
+
]
|
183
|
+
),
|
184
|
+
'C' => DeathChart.new(
|
185
|
+
'환경',
|
186
|
+
[
|
187
|
+
"효과 없음. 당신은 뒤숭숭한 소문을 무시했다.",
|
188
|
+
"이후, 이벤트 종료 시까지 모든 판정의 성공률 -10%.",
|
189
|
+
"위험한 상태! 이후, 라운드 종료 시까지 당신은 카르마를 사용할 수 없다.",
|
190
|
+
"나쁜 소문이 돈다. 당신은 〈교섭〉 판정을 한다. 실패할 경우 당신은 동료들의 신뢰를 잃고 [무연고] 상태가 된 후 NPC가 된다.",
|
191
|
+
"이후, 시나리오 종료 시까지 대가(코스트)에 크레딧을 소비하는 파워를 사용할 수 없다.",
|
192
|
+
"당신의 악평이 세상에 널리 알려진다. 협력자로부터의 지원이 중단된다. 이후 시나리오 종료 시까지 모든 판정의 성공률 -20%.",
|
193
|
+
"배신!! 당신은 〈경제〉 -20% 으로 판정한다. 실패할 경우 당신은 주위로부터 신용을 잃고, [무연고] 상태가 되어 NPC가 된다.",
|
194
|
+
"이후, 시나리오 종료 시까지 【환경】 계열의 기능 레벨이 모두 0이 된다.",
|
195
|
+
"날조 보도? 기억나지 않는 배신 행위가 특종으로 보도된다. 당신은 〈심리〉 -30% 으로 판정한다. 실패할 경우 당신은 인간으로서의 존엄성을 잃고, [무연고]가 된다.",
|
196
|
+
"이후, 이벤트 종료 시까지 모든 판정 성공률 -30%.",
|
197
|
+
"당신의 이름은 사상 최악의 오점으로 영원히 역사에 새겨진다. 이제 당신을 믿는 동료는 없고 당신을 돕는 사회도 없다. 당신은 [무연고] 상태가 된 후 NPC가 된다.",
|
198
|
+
]
|
199
|
+
)
|
200
|
+
}.freeze
|
201
|
+
|
202
|
+
TABLES = {
|
203
|
+
"CPC" => DiceTable::Table.new(
|
204
|
+
"챌린지・패널티 차트",
|
205
|
+
"1D10",
|
206
|
+
[
|
207
|
+
"사망\n도와야 할 NPC (히로인 등)가 사망한다.",
|
208
|
+
"검은 별\n적이 목적을 성취하고, 사건은 PC의 패배로 끝난다. 그대로 여운 페이즈로 넘어갈 것.",
|
209
|
+
"활성\n적 보스의 라이프를 2배로 한 다음 결전 페이즈를 개시한다.",
|
210
|
+
"공세\n적 보스의 대미지에 +2D6의 수정을 준 후 결전 페이즈를 개시한다.",
|
211
|
+
"대거\n적의 수(보스 제외)를 2배로 한 후 결전 페이즈를 개시한다.",
|
212
|
+
"암흑\n모든 에리어(구역)을 [어둠]으로 만든 다음 결전 페이즈를 개시한다.",
|
213
|
+
"맹화\n전투 에리어(구역) 2개를 [대미지 존 2]로 취급한 후, 결전 페이즈를 개시한다.",
|
214
|
+
"복병\n적의 절반을 에리어(구역) 1과 에리어(구역) 2로 이동시킨 후, 결전 페이즈를 개시한다.",
|
215
|
+
"만복\n보스 이외의 적의 라이프를 모두 2배로 한 다음, 결전 페이즈를 개시한다.",
|
216
|
+
"봉인\nPC는 결전 페이즈 동안 카르마를 사용할 수 없다. 결전 페이즈를 개시한다."
|
217
|
+
]
|
218
|
+
),
|
219
|
+
"STC" => DiceTable::Table.new(
|
220
|
+
"사이드 트랙 차트",
|
221
|
+
"1D10",
|
222
|
+
[
|
223
|
+
"해후\n우연히 NPC와 만난다. 어떤 NPC가 나타날지는 GM이 결정한다.",
|
224
|
+
"사고\교통사고를 당한다. 주변에서 패닉이 일어나고 있을지도 모른다.",
|
225
|
+
"낮잠\n지독한 졸음이 몰려온다. 설마, 신참 빌런의 능력인가?",
|
226
|
+
"고백\nNPC 한 명이 지금까지 간직하고 있던 마음을 당신에게 고백한다.",
|
227
|
+
"설정\n새로운 설정이 밝혀진다. 사실은 NPC의 아버지였다든가, 선천적으로 눈이 보이지 않는다든가.",
|
228
|
+
"자객\n누군가로부터 공격을 받는다. 제3세력인가?",
|
229
|
+
"불청객\n우연히 원수 한 명과 마주친다. 상황에 따라서 바로 전투가 발생할지도 모른다.",
|
230
|
+
"의심\n수상한 사람을 눈치챘다. 따라가야 하나? 무시해야 하나?",
|
231
|
+
"조우\n시나리오와 관계없는 빌런 조직과 조우한다.",
|
232
|
+
"평화\n별일 없었다.",
|
233
|
+
]
|
234
|
+
),
|
235
|
+
}.freeze
|
236
|
+
|
237
|
+
register_prefix(
|
238
|
+
'BJ',
|
239
|
+
'DC[LSC]',
|
240
|
+
TABLES.keys
|
241
|
+
)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|