bcdice 3.4.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/i18n/BeginningIdol/ja_jp.yml +2806 -0
  4. data/i18n/BeginningIdol/ko_kr.yml +1400 -0
  5. data/i18n/KillDeathBusiness/ja_jp.yml +1 -1
  6. data/i18n/MagicaLogia/ja_jp.yml +1 -1
  7. data/i18n/MonotoneMuseum/ko_kr.yml +526 -53
  8. data/lib/bcdice/common_command/choice.rb +5 -1
  9. data/lib/bcdice/common_command/tally_dice/node.rb +135 -0
  10. data/lib/bcdice/common_command/tally_dice/parser.rb +302 -0
  11. data/lib/bcdice/common_command/tally_dice.rb +19 -0
  12. data/lib/bcdice/common_command.rb +2 -0
  13. data/lib/bcdice/dice_table/d66_table.rb +5 -1
  14. data/lib/bcdice/game_system/Aoharubaan.rb +91 -0
  15. data/lib/bcdice/game_system/AssaultEngine.rb +91 -0
  16. data/lib/bcdice/game_system/BadLife.rb +264 -289
  17. data/lib/bcdice/game_system/Bakenokawa.rb +244 -0
  18. data/lib/bcdice/game_system/BeginningIdol.rb +116 -2390
  19. data/lib/bcdice/game_system/BeginningIdol_Korean.rb +10 -2312
  20. data/lib/bcdice/game_system/CastleInGray.rb +133 -0
  21. data/lib/bcdice/game_system/Cthulhu.rb +2 -2
  22. data/lib/bcdice/game_system/Cthulhu7th.rb +6 -6
  23. data/lib/bcdice/game_system/DoubleCross.rb +5 -0
  24. data/lib/bcdice/game_system/Emoklore.rb +1 -1
  25. data/lib/bcdice/game_system/FateCoreSystem.rb +117 -0
  26. data/lib/bcdice/game_system/Karukami.rb +84 -0
  27. data/lib/bcdice/game_system/KurayamiCrying.rb +1 -1
  28. data/lib/bcdice/game_system/MonotoneMuseum_Korean.rb +4 -4
  29. data/lib/bcdice/game_system/{SterileLife.rb → StellarLife.rb} +162 -226
  30. data/lib/bcdice/game_system/SwordWorld.rb +6 -2
  31. data/lib/bcdice/game_system/SwordWorld2_0.rb +20 -5
  32. data/lib/bcdice/game_system/SwordWorld2_5.rb +6 -0
  33. data/lib/bcdice/game_system/TalesFromTheLoop.rb +83 -0
  34. data/lib/bcdice/game_system/YearZeroEngine.rb +40 -19
  35. data/lib/bcdice/game_system/beginning_idol/accessories_table.rb +31 -0
  36. data/lib/bcdice/game_system/beginning_idol/bad_status_table.rb +43 -0
  37. data/lib/bcdice/game_system/beginning_idol/chain_d66_table.rb +29 -0
  38. data/lib/bcdice/game_system/beginning_idol/chain_table.rb +37 -0
  39. data/lib/bcdice/game_system/beginning_idol/costume_table.rb +37 -0
  40. data/lib/bcdice/game_system/beginning_idol/d6_twice_table.rb +36 -0
  41. data/lib/bcdice/game_system/beginning_idol/item_table.rb +51 -0
  42. data/lib/bcdice/game_system/beginning_idol/my_skill_name_table.rb +44 -0
  43. data/lib/bcdice/game_system/beginning_idol/random_event_table.rb +31 -0
  44. data/lib/bcdice/game_system/beginning_idol/skill_table.rb +63 -0
  45. data/lib/bcdice/game_system/beginning_idol/table.rb +193 -0
  46. data/lib/bcdice/game_system/beginning_idol/with_abnormality.rb +74 -0
  47. data/lib/bcdice/game_system/beginning_idol/work_table.rb +57 -0
  48. data/lib/bcdice/game_system/one_way_heroics/random_event_table.rb +4 -4
  49. data/lib/bcdice/game_system/sword_world/rating_parsed.rb +46 -3
  50. data/lib/bcdice/game_system/sword_world/rating_parser.rb +147 -106
  51. data/lib/bcdice/game_system.rb +8 -1
  52. data/lib/bcdice/version.rb +1 -1
  53. metadata +28 -3
@@ -30,7 +30,7 @@ module BCDice
30
30
  # choice(A[], B[], C[]) -> "A[]", "B[]", "C[]" から選ぶ
31
31
  # choice[A(), B(), C()] -> "A()", "B()", "C()" から選ぶ
32
32
  #
33
- # "choise"の後に数を指定することで、列挙した要素から重複なしで複数個を選ぶ
33
+ # "choice"の後に数を指定することで、列挙した要素から重複なしで複数個を選ぶ
34
34
  # choice2[A,B,C] -> "A", "B", "C" から重複なしで2個選ぶ
35
35
  #
36
36
  # 指定したい要素が「AからD」のように連続する項目の場合に「A-D」と省略して記述できる
@@ -192,6 +192,10 @@ module BCDice
192
192
  # @param randomizer [Randomizer]
193
193
  # @return [Result]
194
194
  def roll(randomizer)
195
+ if @items.size > 100
196
+ return Result.new("項目数は100以下としてください")
197
+ end
198
+
195
199
  items = @items.dup
196
200
  chosens = []
197
201
  @takes.times do
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bcdice/result"
4
+
5
+ module BCDice
6
+ module CommonCommand
7
+ module TallyDice
8
+ # 個数カウントダイスを表すノードをまとめるモジュール
9
+ module Node
10
+ # 個数カウントダイス:コマンドのノード
11
+ class Command
12
+ # 最大面数
13
+ MAX_SIDES = 20
14
+
15
+ # @param secret [Boolean] シークレットダイスか
16
+ # @param notation [Notation] ダイス表記
17
+ def initialize(secret:, notation:)
18
+ @secret = secret
19
+ @notation = notation
20
+ end
21
+
22
+ # @param game_system [Base] ゲームシステム
23
+ # @param randomizer [Randomizer] ランダマイザ
24
+ # @return [Result, nil]
25
+ def eval(game_system, randomizer)
26
+ dice = @notation.to_dice(game_system.round_type)
27
+ unless dice.valid?
28
+ return nil
29
+ end
30
+
31
+ if dice.sides > MAX_SIDES
32
+ return Result.new("(#{dice}) > 面数は1以上、#{MAX_SIDES}以下としてください")
33
+ end
34
+
35
+ values = dice.roll(randomizer)
36
+
37
+ values_str = (game_system.sort_barabara_dice? ? values.sort : values)
38
+ .join(",")
39
+
40
+ # TODO: Ruby 2.7以降のみサポートするようになった場合
41
+ # Enumerable#tally で書く
42
+ values_count = values
43
+ .group_by(&:itself)
44
+ .transform_values(&:length)
45
+
46
+ values_count_strs = (1..dice.sides).map do |v|
47
+ count = values_count.fetch(v, 0)
48
+
49
+ next nil if count == 0 && !dice.show_zeros?
50
+
51
+ "[#{v}]×#{values_count.fetch(v, 0)}"
52
+ end
53
+
54
+ sequence = [
55
+ "(#{dice})",
56
+ values_str,
57
+ values_count_strs.compact.join(", "),
58
+ ].compact
59
+
60
+ Result.new.tap do |r|
61
+ r.secret = @secret
62
+ r.text = sequence.join(" > ")
63
+ end
64
+ end
65
+ end
66
+
67
+ # 個数カウントダイス:ダイス表記のノード
68
+ class Notation
69
+ # @return [Integer] 振る回数
70
+ attr_reader :times
71
+ # @return [Integer] 面数
72
+ attr_reader :sides
73
+ # @return [Boolean] 個数0を表示するか
74
+ attr_reader :show_zeros
75
+
76
+ # @param times [#eval] 振る回数
77
+ # @param sides [#eval] 面数
78
+ # @param show_zeros [Boolean] 個数0を表示するか
79
+ def initialize(times:, sides:, show_zeros:)
80
+ @times = times
81
+ @sides = sides
82
+ @show_zeros = show_zeros
83
+ end
84
+
85
+ # @param round_type [Symbol] 除算の端数処理方法
86
+ # @return [Dice]
87
+ def to_dice(round_type)
88
+ times = @times.eval(round_type)
89
+ sides = @sides.eval(round_type)
90
+
91
+ Dice.new(times: times, sides: sides, show_zeros: @show_zeros)
92
+ end
93
+ end
94
+
95
+ # 個数カウントダイス:ダイスのノード
96
+ class Dice
97
+ # @return [Integer] 振る回数
98
+ attr_reader :times
99
+ # @return [Integer] 面数
100
+ attr_reader :sides
101
+ # @return [Boolean] 個数0を表示するか
102
+ attr_reader :show_zeros
103
+
104
+ alias show_zeros? show_zeros
105
+
106
+ # @param times [Integer] 振る回数
107
+ # @param sides [Integer] 面数
108
+ def initialize(times:, sides:, show_zeros:)
109
+ @times = times
110
+ @sides = sides
111
+ @show_zeros = show_zeros
112
+ end
113
+
114
+ # @return [Boolean] ダイスとして有効(振る回数、面数ともに正の数)か
115
+ def valid?
116
+ @times > 0 && @sides > 0
117
+ end
118
+
119
+ # ダイスを振る
120
+ # @param randomizer [BCDice::Randomizer] ランダマイザ
121
+ # @return [Array<Integer>] 出目の配列
122
+ def roll(randomizer)
123
+ randomizer.roll_barabara(@times, @sides)
124
+ end
125
+
126
+ # @return [String]
127
+ def to_s
128
+ show_zeros_symbol = @show_zeros ? "Z" : "Y"
129
+ "#{@times}T#{show_zeros_symbol}#{@sides}"
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,302 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by Racc 1.5.1
4
+ # from Racc grammar file "".
5
+ #
6
+
7
+ require 'racc/parser.rb'
8
+
9
+
10
+ require "bcdice/common_command/lexer"
11
+ require "bcdice/common_command/tally_dice/node"
12
+ require "bcdice/arithmetic/node"
13
+
14
+ module BCDice
15
+ module CommonCommand
16
+ module TallyDice
17
+ class Parser < Racc::Parser
18
+
19
+
20
+ def self.parse(source)
21
+ new.parse(source)
22
+ end
23
+
24
+ def parse(source)
25
+ @lexer = Lexer.new(source)
26
+ do_parse()
27
+ rescue ParseError
28
+ nil
29
+ end
30
+
31
+ private
32
+
33
+ def next_token
34
+ @lexer.next_token
35
+ end
36
+ ##### State transition tables begin ###
37
+
38
+ racc_action_table = [
39
+ 8, 8, 18, 19, 20, 21, 8, 8, 8, 22,
40
+ 14, 15, 3, 7, 7, 14, 15, 14, 15, 7,
41
+ 7, 7, 8, 4, 8, 35, 33, 34, 36, 8,
42
+ 9, 14, 15, 14, 15, 7, 8, 7, 14, 15,
43
+ 23, 24, 7, 23, 24, 14, 15, 23, 24, 7,
44
+ 10 ]
45
+
46
+ racc_action_check = [
47
+ 2, 7, 10, 10, 11, 11, 14, 17, 15, 11,
48
+ 7, 7, 0, 2, 7, 14, 14, 15, 15, 14,
49
+ 17, 15, 20, 1, 21, 31, 31, 31, 31, 23,
50
+ 4, 20, 20, 21, 21, 20, 24, 21, 23, 23,
51
+ 12, 12, 23, 28, 28, 24, 24, 29, 29, 24,
52
+ 6 ]
53
+
54
+ racc_action_pointer = [
55
+ 2, 23, -2, nil, 30, nil, 47, -1, nil, nil,
56
+ -2, -7, 27, nil, 4, 6, nil, 5, nil, nil,
57
+ 20, 22, nil, 27, 34, nil, nil, nil, 30, 34,
58
+ nil, 19, nil, nil, nil, nil, nil ]
59
+
60
+ racc_action_default = [
61
+ -2, -23, -23, -3, -23, -1, -23, -23, -22, 37,
62
+ -23, -23, -9, -12, -23, -23, -20, -23, -5, -6,
63
+ -23, -23, -21, -23, -23, -18, -19, -4, -7, -8,
64
+ -10, -13, -11, -14, -15, -16, -17 ]
65
+
66
+ racc_goto_table = [
67
+ 6, 25, 26, 12, 1, 2, 5, 17, 11, 32,
68
+ 30, 31, nil, nil, nil, 27, 28, 29 ]
69
+
70
+ racc_goto_check = [
71
+ 4, 8, 8, 7, 1, 2, 3, 5, 6, 9,
72
+ 8, 8, nil, nil, nil, 4, 7, 7 ]
73
+
74
+ racc_goto_pointer = [
75
+ nil, 4, 5, 4, -2, -3, 1, -4, -13, -22 ]
76
+
77
+ racc_goto_default = [
78
+ nil, nil, nil, nil, 16, nil, nil, nil, 13, nil ]
79
+
80
+ racc_reduce_table = [
81
+ 0, 0, :racc_error,
82
+ 2, 18, :_reduce_1,
83
+ 0, 19, :_reduce_2,
84
+ 1, 19, :_reduce_3,
85
+ 4, 20, :_reduce_4,
86
+ 1, 22, :_reduce_5,
87
+ 1, 22, :_reduce_6,
88
+ 3, 23, :_reduce_7,
89
+ 3, 23, :_reduce_8,
90
+ 1, 23, :_reduce_none,
91
+ 3, 24, :_reduce_10,
92
+ 4, 24, :_reduce_11,
93
+ 1, 24, :_reduce_none,
94
+ 0, 26, :_reduce_13,
95
+ 1, 26, :_reduce_14,
96
+ 1, 26, :_reduce_15,
97
+ 1, 26, :_reduce_16,
98
+ 1, 26, :_reduce_17,
99
+ 2, 25, :_reduce_18,
100
+ 2, 25, :_reduce_19,
101
+ 1, 25, :_reduce_none,
102
+ 3, 21, :_reduce_21,
103
+ 1, 21, :_reduce_22 ]
104
+
105
+ racc_reduce_n = 23
106
+
107
+ racc_shift_n = 37
108
+
109
+ racc_token_table = {
110
+ false => 0,
111
+ :error => 1,
112
+ :NUMBER => 2,
113
+ :T => 3,
114
+ :Y => 4,
115
+ :Z => 5,
116
+ :R => 6,
117
+ :U => 7,
118
+ :C => 8,
119
+ :F => 9,
120
+ :S => 10,
121
+ :PLUS => 11,
122
+ :MINUS => 12,
123
+ :ASTERISK => 13,
124
+ :SLASH => 14,
125
+ :PARENL => 15,
126
+ :PARENR => 16 }
127
+
128
+ racc_nt_base = 17
129
+
130
+ racc_use_result_var = true
131
+
132
+ Racc_arg = [
133
+ racc_action_table,
134
+ racc_action_check,
135
+ racc_action_default,
136
+ racc_action_pointer,
137
+ racc_goto_table,
138
+ racc_goto_check,
139
+ racc_goto_default,
140
+ racc_goto_pointer,
141
+ racc_nt_base,
142
+ racc_reduce_table,
143
+ racc_token_table,
144
+ racc_shift_n,
145
+ racc_reduce_n,
146
+ racc_use_result_var ]
147
+
148
+ Racc_token_to_s_table = [
149
+ "$end",
150
+ "error",
151
+ "NUMBER",
152
+ "T",
153
+ "Y",
154
+ "Z",
155
+ "R",
156
+ "U",
157
+ "C",
158
+ "F",
159
+ "S",
160
+ "PLUS",
161
+ "MINUS",
162
+ "ASTERISK",
163
+ "SLASH",
164
+ "PARENL",
165
+ "PARENR",
166
+ "$start",
167
+ "expr",
168
+ "secret",
169
+ "notation",
170
+ "term",
171
+ "show_zeros",
172
+ "add",
173
+ "mul",
174
+ "unary",
175
+ "round_type" ]
176
+
177
+ Racc_debug_parser = false
178
+
179
+ ##### State transition tables end #####
180
+
181
+ # reduce 0 omitted
182
+
183
+ def _reduce_1(val, _values, result)
184
+ result = Node::Command.new(
185
+ secret: val[0],
186
+ notation: val[1]
187
+ )
188
+
189
+ result
190
+ end
191
+
192
+ def _reduce_2(val, _values, result)
193
+ result = false
194
+ result
195
+ end
196
+
197
+ def _reduce_3(val, _values, result)
198
+ result = true
199
+ result
200
+ end
201
+
202
+ def _reduce_4(val, _values, result)
203
+ result = Node::Notation.new(
204
+ times: val[0],
205
+ sides: val[3],
206
+ show_zeros: val[2]
207
+ )
208
+
209
+ result
210
+ end
211
+
212
+ def _reduce_5(val, _values, result)
213
+ result = false
214
+ result
215
+ end
216
+
217
+ def _reduce_6(val, _values, result)
218
+ result = true
219
+ result
220
+ end
221
+
222
+ def _reduce_7(val, _values, result)
223
+ result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
224
+ result
225
+ end
226
+
227
+ def _reduce_8(val, _values, result)
228
+ result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
229
+ result
230
+ end
231
+
232
+ # reduce 9 omitted
233
+
234
+ def _reduce_10(val, _values, result)
235
+ result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
236
+ result
237
+ end
238
+
239
+ def _reduce_11(val, _values, result)
240
+ divied_class = val[3]
241
+ result = divied_class.new(val[0], val[2])
242
+
243
+ result
244
+ end
245
+
246
+ # reduce 12 omitted
247
+
248
+ def _reduce_13(val, _values, result)
249
+ result = Arithmetic::Node::DivideWithGameSystemDefault
250
+ result
251
+ end
252
+
253
+ def _reduce_14(val, _values, result)
254
+ result = Arithmetic::Node::DivideWithCeil
255
+ result
256
+ end
257
+
258
+ def _reduce_15(val, _values, result)
259
+ result = Arithmetic::Node::DivideWithCeil
260
+ result
261
+ end
262
+
263
+ def _reduce_16(val, _values, result)
264
+ result = Arithmetic::Node::DivideWithRound
265
+ result
266
+ end
267
+
268
+ def _reduce_17(val, _values, result)
269
+ result = Arithmetic::Node::DivideWithFloor
270
+ result
271
+ end
272
+
273
+ def _reduce_18(val, _values, result)
274
+ result = val[1]
275
+ result
276
+ end
277
+
278
+ def _reduce_19(val, _values, result)
279
+ result = Arithmetic::Node::Negative.new(val[1])
280
+ result
281
+ end
282
+
283
+ # reduce 20 omitted
284
+
285
+ def _reduce_21(val, _values, result)
286
+ result = val[1]
287
+ result
288
+ end
289
+
290
+ def _reduce_22(val, _values, result)
291
+ result = Arithmetic::Node::Number.new(val[0])
292
+ result
293
+ end
294
+
295
+ def _reduce_none(val, _values, result)
296
+ val[0]
297
+ end
298
+
299
+ end # class Parser
300
+ end # module TallyDice
301
+ end # module CommonCommand
302
+ end # module BCDice
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bcdice/common_command/tally_dice/parser"
4
+
5
+ module BCDice
6
+ module CommonCommand
7
+ # 個数カウントダイスのモジュール
8
+ module TallyDice
9
+ PREFIX_PATTERN = /\d+T[YZ]\d+/.freeze
10
+
11
+ class << self
12
+ def eval(command, game_system, randomizer)
13
+ cmd = Parser.parse(command)
14
+ cmd&.eval(game_system, randomizer)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "bcdice/common_command/add_dice"
4
4
  require "bcdice/common_command/barabara_dice"
5
+ require "bcdice/common_command/tally_dice"
5
6
  require "bcdice/common_command/calc"
6
7
  require "bcdice/common_command/choice"
7
8
  require "bcdice/common_command/d66_dice"
@@ -15,6 +16,7 @@ module BCDice
15
16
  COMMANDS = [
16
17
  AddDice,
17
18
  BarabaraDice,
19
+ TallyDice,
18
20
  Calc,
19
21
  Choice,
20
22
  D66Dice,
@@ -39,7 +39,11 @@ module BCDice
39
39
  key = dice[0] * 10 + dice[1]
40
40
  chosen = @items[key]
41
41
  chosen = chosen.roll(randomizer) if chosen.respond_to?(:roll)
42
- return RollResult.new(@name, key, chosen)
42
+ RollResult.new(@name, key, chosen)
43
+ end
44
+
45
+ def choice(key)
46
+ RollResult.new(@name, key, @items[key])
43
47
  end
44
48
  end
45
49
  end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class Aoharubaan < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'Aoharubaan'
8
+
9
+ # ゲームシステム名
10
+ NAME = 'あおはるばーんっ'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'あおはるはあんつ'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~HELP
17
+ カレカノ反応表( KR, KReaction )
18
+ HELP
19
+
20
+ JUDGE_ROLL_REG = /^(1d6?|d6)(\+\d+)?(>=|=>)(\d+)$/i.freeze
21
+ register_prefix('(1d6?|d6)(\+\d+)?(>=|=>)(\d+)')
22
+
23
+ def eval_game_system_specific_command(command)
24
+ command = ALIAS[command] || command
25
+
26
+ if (m = JUDGE_ROLL_REG.match(command))
27
+ roll_judge(m[2], m[4])
28
+ else
29
+ roll_tables(command, TABLES)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def roll_judge(modifier_expression, border_expression)
36
+ modifier = modifier_expression ? Arithmetic.eval(modifier_expression, RoundType::FLOOR) : nil
37
+ border = border_expression.to_i
38
+
39
+ command_text = make_command_text(modifier, border)
40
+
41
+ dice = @randomizer.roll_once(6)
42
+ score = dice + modifier.to_i
43
+
44
+ is_success = score >= border # 「成功」か?
45
+ is_right = is_success && score == border # 「ピタリ賞」か?
46
+ is_excellent = is_success && score >= 7 # 「限界突破」か?
47
+
48
+ result_elements = []
49
+ result_elements << (is_success ? '成功' : '失敗')
50
+ result_elements << "ピタリ賞" if is_right
51
+ result_elements << "限界突破" if is_excellent
52
+
53
+ message_elements = []
54
+ message_elements << command_text
55
+ message_elements << "#{dice}+#{modifier}" if modifier
56
+ message_elements << score
57
+ message_elements << result_elements.join(" & ")
58
+
59
+ Result.new(message_elements.join(' > ')).tap do |r|
60
+ r.condition = is_success
61
+ r.critical = is_right || is_excellent
62
+ end
63
+ end
64
+
65
+ def make_command_text(modifier, border)
66
+ command = "1D6"
67
+ command = "#{command}+#{modifier}" if modifier
68
+ command = "#{command}>=#{border}"
69
+ "(#{command})"
70
+ end
71
+
72
+ ALIAS = {
73
+ "KR" => "KReaction",
74
+ }.transform_keys(&:upcase).transform_values(&:upcase).freeze
75
+
76
+ TABLES = {
77
+ "KReaction" => DiceTable::RangeTable.new(
78
+ "カレカノ反応表",
79
+ "1D6",
80
+ [
81
+ [1..2, "何となく素っ気ない気がする。"],
82
+ [3..4, "いつもと変わらない安心感。"],
83
+ [5..6, "何故だかすごくデレてきた! 嬉しくて〈テンション〉1回復。"],
84
+ ]
85
+ ),
86
+ }.transform_keys(&:upcase).freeze
87
+
88
+ register_prefix(ALIAS.keys, TABLES.keys)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class AssaultEngine < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'AssaultEngine'
8
+
9
+ # ゲームシステム名
10
+ NAME = 'アサルトエンジン'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'あさるとえんしん'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~MESSAGETEXT
17
+ ・判定 AEt (t目標値)
18
+ 例: AE45 (目標値45)
19
+ ・リロール nAEt (nロール前の値、t目標値)
20
+ 例: 76AE45 (目標値45で、76を振り直す)
21
+
22
+ ・スワップ(t目標値) エネミーブックP11
23
+ 例: AES45 (目標値45、スワップ表示あり)
24
+ MESSAGETEXT
25
+
26
+ register_prefix('\d*AE')
27
+
28
+ def initialize(command)
29
+ super(command)
30
+ @round_type = RoundType::FLOOR # 端数切り捨て
31
+ end
32
+
33
+ def eval_game_system_specific_command(command)
34
+ cmd = Command::Parser.new(/AES?/, round_type: round_type).enable_prefix_number
35
+ .has_suffix_number.parse(command)
36
+ return nil unless cmd
37
+
38
+ target = cmd.suffix_number
39
+ target = 99 if target >= 100
40
+
41
+ if cmd.command.include?("AES") # SWAP初回
42
+ total = @randomizer.roll_once(100) % 100 # 0-99
43
+ swap = (total % 10) * 10 + (total / 10)
44
+ r1 = judge(target, total)
45
+ r2 = judge(target, swap)
46
+ text = "(AES#{format00(target)}) > #{r1.text} / スワップ#{r2.text}"
47
+ check_result(r1, r2, text)
48
+ elsif cmd.prefix_number.nil? # 初回ロール
49
+ total = @randomizer.roll_once(100) % 100 # 0-99
50
+ judge(target, total).tap do |r|
51
+ r.text = "(AE#{format00(target)}) > #{r.text}"
52
+ end
53
+ else # リロール
54
+ now = cmd.prefix_number
55
+ die = @randomizer.roll_once(10) % 10 # 0-9
56
+ new1 = judge(target, (now / 10 * 10) + die) # 1の位を振り直す
57
+ new2 = judge(target, now % 10 + die * 10) # 10の位を振り直す
58
+
59
+ text = "(#{format00(now)}AE#{format00(target)}) > #{die} > #{new1.text} / #{new2.text}"
60
+ check_result(new1, new2, text)
61
+ end
62
+ end
63
+
64
+ def format00(dice)
65
+ format("%02d", dice)
66
+ end
67
+
68
+ def check_result(result1, result2, text)
69
+ if result1.critical? || result2.critical?
70
+ Result.critical(text)
71
+ elsif result1.success? || result2.success?
72
+ Result.success(text)
73
+ elsif result1.fumble? && result2.fumble?
74
+ Result.fumble(text)
75
+ else
76
+ Result.failure(text)
77
+ end
78
+ end
79
+
80
+ def judge(target, total)
81
+ double = (total / 10) == (total % 10)
82
+ total_text = format00(total)
83
+ if total <= target
84
+ double ? Result.critical("(#{total_text})クリティカル") : Result.success("(#{total_text})成功")
85
+ else
86
+ double ? Result.fumble("(#{total_text})ファンブル") : Result.failure("(#{total_text})失敗")
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end