bcdice 3.12.0 → 3.13.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 +27 -0
- data/lib/bcdice/arithmetic/parser.rb +4 -2
- data/lib/bcdice/base.rb +1 -1
- data/lib/bcdice/command/parser.rb +4 -2
- data/lib/bcdice/common_command/add_dice/parser.rb +4 -2
- data/lib/bcdice/common_command/barabara_dice/parser.rb +4 -2
- data/lib/bcdice/common_command/calc/parser.rb +4 -2
- data/lib/bcdice/common_command/reroll_dice/parser.rb +4 -2
- data/lib/bcdice/common_command/tally_dice/parser.rb +4 -2
- data/lib/bcdice/common_command/upper_dice/parser.rb +4 -2
- data/lib/bcdice/game_system/Airgetlamh.rb +1 -1
- data/lib/bcdice/game_system/Alsetto.rb +2 -2
- data/lib/bcdice/game_system/AniMalus.rb +221 -0
- data/lib/bcdice/game_system/ArknightsFan.rb +182 -0
- data/lib/bcdice/game_system/Avandner.rb +1 -1
- data/lib/bcdice/game_system/BBN.rb +1 -1
- data/lib/bcdice/game_system/BadLife.rb +3 -3
- data/lib/bcdice/game_system/BarnaKronika.rb +1 -1
- data/lib/bcdice/game_system/Chill3.rb +6 -6
- data/lib/bcdice/game_system/DarkSouls.rb +1 -1
- data/lib/bcdice/game_system/Elric.rb +1 -1
- data/lib/bcdice/game_system/FullFace.rb +92 -0
- data/lib/bcdice/game_system/InfiniteFantasia.rb +4 -1
- data/lib/bcdice/game_system/Irisbane.rb +1 -1
- data/lib/bcdice/game_system/KillDeathBusiness.rb +1 -1
- data/lib/bcdice/game_system/KyokoShinshoku.rb +158 -0
- data/lib/bcdice/game_system/Liminal.rb +136 -0
- data/lib/bcdice/game_system/MetalHead.rb +1 -1
- data/lib/bcdice/game_system/MetalHeadExtream.rb +1 -1
- data/lib/bcdice/game_system/NRR.rb +122 -0
- data/lib/bcdice/game_system/NSSQ.rb +1 -1
- data/lib/bcdice/game_system/NightWizard.rb +1 -1
- data/lib/bcdice/game_system/NightWizard3rd.rb +15 -2
- data/lib/bcdice/game_system/OneWayHeroics.rb +1 -1
- data/lib/bcdice/game_system/PastFutureParadox.rb +1238 -0
- data/lib/bcdice/game_system/Postman.rb +3 -3
- data/lib/bcdice/game_system/RecordOfSteam.rb +1 -1
- data/lib/bcdice/game_system/RuneQuestRoleplayingInGlorantha.rb +1 -1
- data/lib/bcdice/game_system/Ryutama.rb +4 -4
- data/lib/bcdice/game_system/Siren.rb +97 -0
- data/lib/bcdice/game_system/Skynauts.rb +1 -1
- data/lib/bcdice/game_system/Strave.rb +1 -1
- data/lib/bcdice/game_system/TherapieSein.rb +1 -1
- data/lib/bcdice/game_system/TrinitySeven.rb +1 -1
- data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +12 -6
- data/lib/bcdice/game_system/WerewolfTheApocalypse5th.rb +12 -6
- data/lib/bcdice/game_system/cthulhu7th/full_auto.rb +1 -1
- data/lib/bcdice/game_system/sword_world/rating_parser.rb +4 -2
- data/lib/bcdice/game_system.rb +8 -0
- data/lib/bcdice/loader.rb +1 -1
- data/lib/bcdice/version.rb +1 -1
- metadata +27 -5
@@ -0,0 +1,182 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BCDice
|
4
|
+
module GameSystem
|
5
|
+
class ArknightsFan < Base
|
6
|
+
# ゲームシステムの識別子
|
7
|
+
ID = "ArknightsFan"
|
8
|
+
|
9
|
+
# ゲームシステム名
|
10
|
+
NAME = "アークナイツTRPG by Dapto"
|
11
|
+
|
12
|
+
# ゲームシステム名の読みがな
|
13
|
+
SORT_KEY = "ああくないつTRPGはいたふと"
|
14
|
+
|
15
|
+
HELP_MESSAGE = <<~TEXT
|
16
|
+
■ 判定 (nADm>=x)
|
17
|
+
nDmのダイスロールをして、x 以下であれば成功。
|
18
|
+
出目が91以上でエラー。
|
19
|
+
出目が10以下でクリティカル。
|
20
|
+
|
21
|
+
■ 判定 (nABm>=x)
|
22
|
+
nBmのダイスロールをして、
|
23
|
+
x 以下であれば成功数+1。
|
24
|
+
出目が91以上でエラー。成功数+1。
|
25
|
+
出目が10以下でクリティカル。成功数-1。
|
26
|
+
上記による成功数をカウント。
|
27
|
+
|
28
|
+
■ 判定 (nABm>=x--役職)
|
29
|
+
nBmのダイスロールをして、
|
30
|
+
出目が x 以下であれば成功数+1。
|
31
|
+
出目が91以上でエラー。成功数+1。
|
32
|
+
出目が10以下でクリティカル。成功数-1。
|
33
|
+
上記による成功数をカウントした上で、以下の役職による成功数増加効果を適応。
|
34
|
+
狙撃(SNIPER) 成功数1以上のとき、成功数+1。
|
35
|
+
TEXT
|
36
|
+
|
37
|
+
register_prefix('\d*AD\d*', '\d*AB\d*', '--ADDICTION', '--WORSENING')
|
38
|
+
|
39
|
+
def eval_game_system_specific_command(command)
|
40
|
+
roll_ad(command) || roll_ab(command) || roll_addiction(command) || roll_worsening(command)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def roll_ad(command)
|
46
|
+
m = /^(\d*)AD(\d*)<=(\d+)$/.match(command)
|
47
|
+
return nil unless m
|
48
|
+
|
49
|
+
times = m[1]
|
50
|
+
sides = m[2]
|
51
|
+
target = m[3].to_i
|
52
|
+
times = !times.empty? ? times.to_i : 1
|
53
|
+
sides = !sides.empty? ? sides.to_i : 100
|
54
|
+
return roll_d(command, times, sides, target)
|
55
|
+
end
|
56
|
+
|
57
|
+
def roll_ab(command)
|
58
|
+
m = /^(\d*)AB(\d*)<=(\d+)(?:--([^\d\s]+)(0)?)?$/.match(command)
|
59
|
+
return nil unless m
|
60
|
+
|
61
|
+
times = m[1]
|
62
|
+
sides = m[2]
|
63
|
+
target = m[3].to_i
|
64
|
+
type = m[4]
|
65
|
+
suffix = m[5]
|
66
|
+
times = !times.empty? ? times.to_i : 1
|
67
|
+
sides = !sides.empty? ? sides.to_i : 100
|
68
|
+
|
69
|
+
if suffix || type.nil?
|
70
|
+
roll_b(command, times, sides, target)
|
71
|
+
else
|
72
|
+
roll_b_withtype(command, times, sides, target, type)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def roll_d(command, times, sides, target)
|
77
|
+
dice_list = @randomizer.roll_barabara(times, sides).sort
|
78
|
+
total = dice_list.sum
|
79
|
+
success = total <= target
|
80
|
+
|
81
|
+
crierror =
|
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
|
104
|
+
|
105
|
+
if times == 1
|
106
|
+
return "(#{command}) > #{dice_list.join(',')} > #{result}"
|
107
|
+
else
|
108
|
+
return "(#{command}) > #{total}[#{dice_list.join(',')}] > #{result}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def roll_b(command, times, sides, target)
|
113
|
+
dice_list, success_count, critical_count, error_count = process_b(times, sides, target)
|
114
|
+
result_count = success_count + critical_count - error_count
|
115
|
+
|
116
|
+
return "(#{command}) > [#{dice_list.join(',')}] > #{success_count}+#{critical_count}C-#{error_count}E > 成功数#{result_count}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def roll_b_withtype(command, times, sides, target, type)
|
120
|
+
dice_list, success_count, critical_count, error_count = process_b(times, sides, target)
|
121
|
+
result_count = success_count + critical_count - error_count
|
122
|
+
|
123
|
+
type_effect =
|
124
|
+
if (type == "SNIPER") && (result_count > 0)
|
125
|
+
1
|
126
|
+
else
|
127
|
+
0
|
128
|
+
end
|
129
|
+
result_count += type_effect
|
130
|
+
|
131
|
+
return "(#{command}) > [#{dice_list.join(',')}] > #{success_count}+#{critical_count}C-#{error_count}E+#{type_effect}(#{type}) > 成功数#{result_count}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def process_b(times, sides, target)
|
135
|
+
dice_list = @randomizer.roll_barabara(times, sides).sort
|
136
|
+
|
137
|
+
success_count = 0
|
138
|
+
critical_count = 0
|
139
|
+
error_count = 0
|
140
|
+
|
141
|
+
dice_list.each do |value|
|
142
|
+
success_count += 1 if value <= target
|
143
|
+
critical_count += 1 if value <= 10
|
144
|
+
error_count += 1 if value >= 91
|
145
|
+
end
|
146
|
+
|
147
|
+
return [dice_list, success_count, critical_count, error_count]
|
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}"
|
163
|
+
end
|
164
|
+
|
165
|
+
WORSENING_TABLE = [
|
166
|
+
"末梢神経障害",
|
167
|
+
"内臓機能不全",
|
168
|
+
"精神症状",
|
169
|
+
].freeze
|
170
|
+
|
171
|
+
def roll_worsening(command)
|
172
|
+
return nil if command != "--WORSENING"
|
173
|
+
|
174
|
+
value = @randomizer.roll_once(3)
|
175
|
+
chosen = WORSENING_TABLE[value - 1]
|
176
|
+
elapse = @randomizer.roll_once(6) + 1
|
177
|
+
|
178
|
+
return "--WORSENING > #{chosen}: #{elapse} rounds"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -85,7 +85,7 @@ module BCDice
|
|
85
85
|
totalDamage = totalSuccessCount * damage + totalCriticalCount * criticalTrigger
|
86
86
|
|
87
87
|
result += "(#{diceCount}D10\<\=#{target}) > #{text} > Hits:#{totalSuccessCount}*#{damage}"
|
88
|
-
result += " + Trigger:#{totalCriticalCount}*#{criticalTrigger}" if
|
88
|
+
result += " + Trigger:#{totalCriticalCount}*#{criticalTrigger}" if criticalTrigger > 0
|
89
89
|
result += " > #{totalDamage}ダメージ"
|
90
90
|
else
|
91
91
|
result += "(#{diceCount}D10\<\=#{target}) > #{text} > 成功数:#{totalSuccessCount}"
|
@@ -58,7 +58,7 @@ module BCDice
|
|
58
58
|
fumble = 1
|
59
59
|
|
60
60
|
isStormy = (m[2] == 'GL') # 波乱万丈
|
61
|
-
if
|
61
|
+
if isStormy
|
62
62
|
critical -= 3
|
63
63
|
fumble += 1
|
64
64
|
end
|
@@ -69,7 +69,7 @@ module BCDice
|
|
69
69
|
critical, fumble = get_critival_fumble(critical, fumble, m[8], m[9])
|
70
70
|
|
71
71
|
target = get_value(m[11])
|
72
|
-
optionalText =
|
72
|
+
optionalText = m[13] || ''
|
73
73
|
|
74
74
|
return checkRoll(diceCount, modify, critical, fumble, target, isStormy, optionalText)
|
75
75
|
end
|
@@ -116,7 +116,7 @@ module BCDice
|
|
116
116
|
|
117
117
|
if isCritical
|
118
118
|
result += "成功(クリティカル)"
|
119
|
-
elsif
|
119
|
+
elsif total >= target
|
120
120
|
result += "成功"
|
121
121
|
else
|
122
122
|
result += "失敗"
|
@@ -16,7 +16,7 @@ module BCDice
|
|
16
16
|
HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
|
17
17
|
・1D100で判定時に成否、Botchを判定
|
18
18
|
例)1D100<=50
|
19
|
-
|
19
|
+
(1D100<=50) > 55 > Botch
|
20
20
|
INFO_MESSAGE_TEXT
|
21
21
|
|
22
22
|
def result_1d100(total, dice_total, cmp_op, target)
|
@@ -30,21 +30,21 @@ module BCDice
|
|
30
30
|
if tens == ones
|
31
31
|
if (total > target) || (dice_total == 100) # 00は必ず失敗
|
32
32
|
if target > 100 # 目標値が100を超えている場合は、00を振ってもBotchにならない
|
33
|
-
return Result.failure("
|
33
|
+
return Result.failure("Failure")
|
34
34
|
else
|
35
35
|
return Result.fumble("Botch")
|
36
36
|
end
|
37
37
|
else
|
38
|
-
return Result.critical("
|
38
|
+
return Result.critical("Colossal Success")
|
39
39
|
end
|
40
40
|
elsif (total <= target) || (dice_total == 1) # 01は必ず成功
|
41
41
|
if total <= (target / 2)
|
42
|
-
return Result.success("
|
42
|
+
return Result.success("High Success")
|
43
43
|
else
|
44
|
-
return Result.success("
|
44
|
+
return Result.success("Low Success")
|
45
45
|
end
|
46
46
|
else
|
47
|
-
return Result.failure("
|
47
|
+
return Result.failure("Failure")
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BCDice
|
4
|
+
module GameSystem
|
5
|
+
class FullFace < Base
|
6
|
+
# ゲームシステムの識別子
|
7
|
+
ID = 'FullFace'
|
8
|
+
|
9
|
+
# ゲームシステム名
|
10
|
+
NAME = 'フルフェイス'
|
11
|
+
|
12
|
+
# ゲームシステム名の読みがな
|
13
|
+
SORT_KEY = 'ふるふえいす'
|
14
|
+
|
15
|
+
# ダイスボットの使い方
|
16
|
+
HELP_MESSAGE = <<~INFO_MESSAGETEXT
|
17
|
+
■判定 x+bFF<=t x:ヒート(省略時は3) b:判定修正 t:能力値
|
18
|
+
|
19
|
+
例)FF<=2: 能力値2で判定し、その結果(成功数,1の目の数,バースト)を表示。
|
20
|
+
6FF<=3: ヒート6,能力値3で戦闘判定し、その結果( 〃 )を表示。
|
21
|
+
8+2FF<=3:ヒート8,判定修正+2,能力値3で戦闘判定し、その結果( 〃 )を表示。
|
22
|
+
INFO_MESSAGETEXT
|
23
|
+
|
24
|
+
register_prefix('([+\d]+)*FF')
|
25
|
+
|
26
|
+
def eval_game_system_specific_command(command)
|
27
|
+
resolute_action(command)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# 技能判定
|
33
|
+
# @param [String] command
|
34
|
+
# @return [Result]
|
35
|
+
def resolute_action(command)
|
36
|
+
m = /^(\d*)([+\d]+)*FF<=(\d)$/.match(command)
|
37
|
+
return nil unless m
|
38
|
+
|
39
|
+
heat_level = m[1].to_i
|
40
|
+
heat_level = 3 if heat_level == 0
|
41
|
+
modify = Arithmetic.eval("0#{m[2]}", @round_type)
|
42
|
+
status_no = m[3].to_i
|
43
|
+
|
44
|
+
dice_array = []
|
45
|
+
|
46
|
+
dice = @randomizer.roll_barabara(heat_level, 6)
|
47
|
+
ones = dice.count(1)
|
48
|
+
sixs = dice.count(6)
|
49
|
+
success_num = dice.count { |val| val <= status_no }
|
50
|
+
dice_array.push(dice.join(","))
|
51
|
+
|
52
|
+
if modify > 0
|
53
|
+
dice = @randomizer.roll_barabara(modify, 6)
|
54
|
+
ones += dice.count(1)
|
55
|
+
success_num += dice.count { |val| val <= status_no }
|
56
|
+
dice_array.push(dice.join(","))
|
57
|
+
end
|
58
|
+
ones_total = ones
|
59
|
+
|
60
|
+
while ones > 0
|
61
|
+
dice = @randomizer.roll_barabara(ones, 6)
|
62
|
+
ones = dice.count(1)
|
63
|
+
ones_total += ones
|
64
|
+
success_num += dice.count { |val| val <= status_no }
|
65
|
+
dice_array.push(dice.join(","))
|
66
|
+
end
|
67
|
+
|
68
|
+
return Result.new.tap do |result|
|
69
|
+
if sixs >= 2
|
70
|
+
result.fumble = true
|
71
|
+
result.condition = false
|
72
|
+
else
|
73
|
+
result.condition = (success_num > 0)
|
74
|
+
result.critical = (ones_total > 0)
|
75
|
+
end
|
76
|
+
result_txt = []
|
77
|
+
result_txt.push("成功度(#{success_num})")
|
78
|
+
result_txt.push("1の目(#{ones_total})") if ones_total > 0
|
79
|
+
result_txt.push("バースト") if result.fumble?
|
80
|
+
|
81
|
+
sequence = [
|
82
|
+
"(#{heat_level}#{Format.modifier(modify)}FF<=#{status_no})",
|
83
|
+
dice_array.join('+').to_s,
|
84
|
+
result_txt.join(',').to_s,
|
85
|
+
].compact
|
86
|
+
|
87
|
+
result.text = sequence.join(" > ")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -13,7 +13,10 @@ module BCDice
|
|
13
13
|
SORT_KEY = 'むけんのふあんたしあ'
|
14
14
|
|
15
15
|
# ダイスボットの使い方
|
16
|
-
HELP_MESSAGE =
|
16
|
+
HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
|
17
|
+
1D20に目標値を設定した場合に、成功レベルの自動判定を行います。
|
18
|
+
例: 1D20<=16
|
19
|
+
INFO_MESSAGE_TEXT
|
17
20
|
|
18
21
|
# ゲーム別成功度判定(1d20)
|
19
22
|
def result_1d20(total, _dice_total, cmp_op, target)
|
@@ -37,7 +37,7 @@ module BCDice
|
|
37
37
|
SceneSituation, SSi
|
38
38
|
HELP
|
39
39
|
|
40
|
-
ATTACK_ROLL_REG = %r{^AT(TACK|K)?([+\-*/()\d]+)@([+\-*/()\d]+)<=([+\-*/()\d]+)(\[([
|
40
|
+
ATTACK_ROLL_REG = %r{^AT(TACK|K)?([+\-*/()\d]+)@([+\-*/()\d]+)<=([+\-*/()\d]+)(\[([+-])([+\-*/()\d]+)\])?}i.freeze
|
41
41
|
register_prefix('AT(TACK|K)?')
|
42
42
|
|
43
43
|
def initialize(command)
|
@@ -0,0 +1,158 @@
|
|
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
|
+
ダイスを指定数ダイスロールして、最も高い出目を出力します。難易度を指定すると成否を判定します。
|
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
|
+
・観測ロール
|
29
|
+
[現実乖離]の段階に応じたダイスを指定数ダイスロールして、最も高い出目を出力します。
|
30
|
+
KR(x)
|
31
|
+
x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
|
32
|
+
|
33
|
+
KR(x,y) 観測ロール(リアリティラインあり)
|
34
|
+
x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
|
35
|
+
y=[リアリティライン]のレベル(3=1個/2=2個/1=3個)
|
36
|
+
|
37
|
+
・虚構の収束の侵蝕度減少ロール
|
38
|
+
[現実乖離]の段階に応じたダイスを指定数ダイスロールして、その合計を出力します。
|
39
|
+
KRS(x,y)
|
40
|
+
x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
|
41
|
+
y=ダイスの個数
|
42
|
+
MESSAGETEXT
|
43
|
+
|
44
|
+
register_prefix('KS', 'KR', 'KRS')
|
45
|
+
|
46
|
+
def eval_game_system_specific_command(command)
|
47
|
+
roll_check(command) || roll_kansoku(command) || roll_shusoku(command)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
DICE_SIZE_TO_SIDES = {
|
53
|
+
1 => 4,
|
54
|
+
2 => 4,
|
55
|
+
3 => 4,
|
56
|
+
4 => 4,
|
57
|
+
6 => 6,
|
58
|
+
8 => 8,
|
59
|
+
10 => 10,
|
60
|
+
12 => 12,
|
61
|
+
20 => 20,
|
62
|
+
}.freeze
|
63
|
+
|
64
|
+
def roll_check(command)
|
65
|
+
m = /^KS(?:\((\d+),([-+\d]+)?\)|(\d+))(?:>=([-+\d]+))?$/.match(command)
|
66
|
+
return nil unless m
|
67
|
+
|
68
|
+
dice_size = m[1]&.to_i || m[3].to_i
|
69
|
+
times = m[2] ? Arithmetic.eval(m[2], @round_type) : 1
|
70
|
+
target = m[4] && Arithmetic.eval(m[4], @round_type)
|
71
|
+
|
72
|
+
sides = DICE_SIZE_TO_SIDES[dice_size]
|
73
|
+
|
74
|
+
return nil if sides.nil? || times.nil?
|
75
|
+
|
76
|
+
dice_list = @randomizer.roll_barabara(times, sides).sort
|
77
|
+
value = dice_list.max.clamp(1, dice_size)
|
78
|
+
|
79
|
+
result =
|
80
|
+
if value == 1
|
81
|
+
Result.fumble("ファンブル")
|
82
|
+
elsif target && value < target
|
83
|
+
Result.failure("失敗")
|
84
|
+
elsif target && value == sides
|
85
|
+
Result.critical("クリティカル")
|
86
|
+
elsif target && value >= target
|
87
|
+
Result.success("成功")
|
88
|
+
else
|
89
|
+
Result.new()
|
90
|
+
end
|
91
|
+
|
92
|
+
result.text = [
|
93
|
+
target ? "(KS(#{dice_size},#{times})>=#{target})" : "(KS(#{dice_size},#{times}))",
|
94
|
+
("#{value}[#{dice_list.join(',')}]" if times > 1),
|
95
|
+
value,
|
96
|
+
result.text,
|
97
|
+
].compact.join(" > ")
|
98
|
+
|
99
|
+
return result
|
100
|
+
end
|
101
|
+
|
102
|
+
GENJITU_KAIRI_TO_SIDES = [4, 6, 8, 10, 12, 20].freeze
|
103
|
+
REALITY_LINE_TO_TIMES = {
|
104
|
+
3 => 1,
|
105
|
+
2 => 2,
|
106
|
+
1 => 3,
|
107
|
+
}.freeze
|
108
|
+
|
109
|
+
def roll_kansoku(command)
|
110
|
+
m = /^KR(?:(\d+)|\((\d),(\d)\))$/.match(command)
|
111
|
+
return nil unless m
|
112
|
+
|
113
|
+
dice_size = m[1]&.to_i || m[2].to_i
|
114
|
+
reality_line = m[3]&.to_i
|
115
|
+
|
116
|
+
if reality_line && (reality_line > 3 || reality_line < 1)
|
117
|
+
return nil
|
118
|
+
end
|
119
|
+
|
120
|
+
sides = GENJITU_KAIRI_TO_SIDES[dice_size - 1]
|
121
|
+
times = REALITY_LINE_TO_TIMES[reality_line] || 1
|
122
|
+
|
123
|
+
return nil unless sides
|
124
|
+
|
125
|
+
dice_list = @randomizer.roll_barabara(times, sides).sort
|
126
|
+
value = dice_list.max
|
127
|
+
|
128
|
+
cmd = reality_line ? "KR(#{dice_size},#{reality_line})" : "KR(#{dice_size})"
|
129
|
+
|
130
|
+
if times == 1
|
131
|
+
"(#{cmd}) > #{value}"
|
132
|
+
else
|
133
|
+
"(#{cmd}) > #{value}[#{dice_list.join(',')}] > #{value}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def roll_shusoku(command)
|
138
|
+
m = /^KRS(?:\((\d),([-+\d]+)\))$/.match(command)
|
139
|
+
return nil unless m
|
140
|
+
|
141
|
+
dice_size = m[1].to_i
|
142
|
+
times = m[2] && Arithmetic.eval(m[2], @round_type)
|
143
|
+
|
144
|
+
sides = GENJITU_KAIRI_TO_SIDES[dice_size - 1]
|
145
|
+
return nil if sides.nil? || times.nil?
|
146
|
+
|
147
|
+
dice_list = @randomizer.roll_barabara(times, sides)
|
148
|
+
value = dice_list.sum
|
149
|
+
|
150
|
+
if times == 1
|
151
|
+
"(KRS(#{dice_size},#{times})) > #{value}"
|
152
|
+
else
|
153
|
+
"(KRS(#{dice_size},#{times})) > #{value}[#{dice_list.join(',')}] > #{value}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|