bcdice 3.0.0.pre.alpha.2 → 3.0.0.pre.rc.1

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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +1 -0
  4. data/i18n/KillDeathBusiness/ja_jp.yml +4 -4
  5. data/i18n/KillDeathBusiness/ko_kr.yml +5 -4
  6. data/i18n/MagicaLogia/ko_kr.yml +564 -0
  7. data/i18n/MonotoneMuseum/ja_jp.yml +37 -1
  8. data/i18n/StratoShout/ja_jp.yml +4 -4
  9. data/i18n/StratoShout/ko_kr.yml +4 -4
  10. data/lib/bcdice.rb +2 -1
  11. data/lib/bcdice/arithmetic.rb +22 -0
  12. data/lib/bcdice/arithmetic/node.rb +112 -43
  13. data/lib/bcdice/arithmetic/parser.rb +240 -0
  14. data/lib/bcdice/arithmetic_evaluator.rb +5 -156
  15. data/lib/bcdice/base.rb +8 -1
  16. data/lib/bcdice/command/lexer.rb +57 -0
  17. data/lib/bcdice/command/parsed.rb +65 -0
  18. data/lib/bcdice/command/parser.rb +489 -0
  19. data/lib/bcdice/common_command/add_dice.rb +1 -1
  20. data/lib/bcdice/common_command/add_dice/node.rb +142 -69
  21. data/lib/bcdice/common_command/add_dice/parser.rb +100 -83
  22. data/lib/bcdice/common_command/barabara_dice/node.rb +7 -1
  23. data/lib/bcdice/common_command/barabara_dice/result.rb +22 -0
  24. data/lib/bcdice/common_command/calc/node.rb +10 -1
  25. data/lib/bcdice/common_command/calc/parser.rb +1 -1
  26. data/lib/bcdice/common_command/d66_dice.rb +3 -1
  27. data/lib/bcdice/common_command/lexer.rb +2 -1
  28. data/lib/bcdice/common_command/upper_dice/parser.rb +118 -97
  29. data/lib/bcdice/common_command/version.rb +1 -1
  30. data/lib/bcdice/deprecated/checker.rb +6 -6
  31. data/lib/bcdice/dice_table.rb +1 -0
  32. data/lib/bcdice/dice_table/d66_parity_table.rb +34 -0
  33. data/lib/bcdice/game_system.rb +3 -0
  34. data/lib/bcdice/game_system/AceKillerGene.rb +1 -1
  35. data/lib/bcdice/game_system/AlchemiaStruggle.rb +312 -0
  36. data/lib/bcdice/game_system/Alshard.rb +0 -1
  37. data/lib/bcdice/game_system/Amadeus.rb +1 -1
  38. data/lib/bcdice/game_system/AnimaAnimus.rb +1 -5
  39. data/lib/bcdice/game_system/BadLife.rb +1 -1
  40. data/lib/bcdice/game_system/BeastBindTrinity.rb +1 -10
  41. data/lib/bcdice/game_system/BeginningIdol.rb +4 -4
  42. data/lib/bcdice/game_system/BeginningIdol_Korean.rb +4 -4
  43. data/lib/bcdice/game_system/BladeOfArcana.rb +4 -4
  44. data/lib/bcdice/game_system/BlindMythos.rb +12 -9
  45. data/lib/bcdice/game_system/BloodCrusade.rb +12 -38
  46. data/lib/bcdice/game_system/BloodMoon.rb +2 -2
  47. data/lib/bcdice/game_system/CardRanker.rb +23 -63
  48. data/lib/bcdice/game_system/ChaosFlare.rb +3 -3
  49. data/lib/bcdice/game_system/CodeLayerd.rb +1 -1
  50. data/lib/bcdice/game_system/ColossalHunter.rb +2 -2
  51. data/lib/bcdice/game_system/Cthulhu7th.rb +2 -2
  52. data/lib/bcdice/game_system/CthulhuTech.rb +0 -1
  53. data/lib/bcdice/game_system/DarkBlaze.rb +4 -4
  54. data/lib/bcdice/game_system/DeadlineHeroes.rb +1 -1
  55. data/lib/bcdice/game_system/DoubleCross.rb +60 -93
  56. data/lib/bcdice/game_system/EmbryoMachine.rb +5 -5
  57. data/lib/bcdice/game_system/EtrianOdysseySRS.rb +0 -1
  58. data/lib/bcdice/game_system/FilledWith.rb +3 -3
  59. data/lib/bcdice/game_system/FullMetalPanic.rb +0 -1
  60. data/lib/bcdice/game_system/GURPS.rb +1 -1
  61. data/lib/bcdice/game_system/Garako.rb +3 -2
  62. data/lib/bcdice/game_system/GardenOrder.rb +1 -1
  63. data/lib/bcdice/game_system/GehennaAn.rb +3 -3
  64. data/lib/bcdice/game_system/Gundog.rb +1 -1
  65. data/lib/bcdice/game_system/GundogRevised.rb +3 -3
  66. data/lib/bcdice/game_system/GundogZero.rb +2 -2
  67. data/lib/bcdice/game_system/GurpsFW.rb +2 -5
  68. data/lib/bcdice/game_system/HatsuneMiku.rb +1 -1
  69. data/lib/bcdice/game_system/HuntersMoon.rb +17 -110
  70. data/lib/bcdice/game_system/JuinKansen.rb +251 -0
  71. data/lib/bcdice/game_system/KanColle.rb +17 -166
  72. data/lib/bcdice/game_system/KillDeathBusiness.rb +35 -44
  73. data/lib/bcdice/game_system/KillDeathBusiness_Korean.rb +2 -1
  74. data/lib/bcdice/game_system/LogHorizon.rb +8 -8
  75. data/lib/bcdice/game_system/LostRoyal.rb +1 -3
  76. data/lib/bcdice/game_system/MagicaLogia.rb +3 -3
  77. data/lib/bcdice/game_system/MagicaLogia_Korean.rb +66 -0
  78. data/lib/bcdice/game_system/MeikyuDays.rb +1 -1
  79. data/lib/bcdice/game_system/MeikyuKingdom.rb +1 -1
  80. data/lib/bcdice/game_system/MeikyuKingdomBasic.rb +1 -1
  81. data/lib/bcdice/game_system/MetalHeadExtream.rb +4 -4
  82. data/lib/bcdice/game_system/MetallicGuardian.rb +0 -1
  83. data/lib/bcdice/game_system/MonotoneMuseum.rb +3 -2
  84. data/lib/bcdice/game_system/MonotoneMuseum_Korean.rb +1 -1
  85. data/lib/bcdice/game_system/NSSQ.rb +2 -2
  86. data/lib/bcdice/game_system/Nechronica.rb +3 -3
  87. data/lib/bcdice/game_system/NightWizard.rb +1 -1
  88. data/lib/bcdice/game_system/NightmareHunterDeep.rb +3 -4
  89. data/lib/bcdice/game_system/NinjaSlayer.rb +26 -28
  90. data/lib/bcdice/game_system/OracleEngine.rb +13 -17
  91. data/lib/bcdice/game_system/Paradiso.rb +2 -2
  92. data/lib/bcdice/game_system/PhantasmAdventure.rb +0 -4
  93. data/lib/bcdice/game_system/Raisondetre.rb +1 -1
  94. data/lib/bcdice/game_system/RecordOfLodossWar.rb +2 -3
  95. data/lib/bcdice/game_system/RokumonSekai2.rb +2 -2
  96. data/lib/bcdice/game_system/RuinBreakers.rb +1 -1
  97. data/lib/bcdice/game_system/Ryutama.rb +1 -1
  98. data/lib/bcdice/game_system/SRS.rb +0 -5
  99. data/lib/bcdice/game_system/SamsaraBallad.rb +4 -3
  100. data/lib/bcdice/game_system/Satasupe.rb +22 -14
  101. data/lib/bcdice/game_system/ScreamHighSchool.rb +2 -2
  102. data/lib/bcdice/game_system/ShinkuuGakuen.rb +1 -1
  103. data/lib/bcdice/game_system/ShinobiGami.rb +75 -39
  104. data/lib/bcdice/game_system/StellarKnights.rb +1 -3
  105. data/lib/bcdice/game_system/SterileLife.rb +1 -1
  106. data/lib/bcdice/game_system/StrangerOfSwordCity.rb +1 -1
  107. data/lib/bcdice/game_system/StratoShout.rb +10 -36
  108. data/lib/bcdice/game_system/StratoShout_Korean.rb +2 -1
  109. data/lib/bcdice/game_system/SwordWorld.rb +5 -5
  110. data/lib/bcdice/game_system/SwordWorld2_5.rb +1 -1
  111. data/lib/bcdice/game_system/TherapieSein.rb +2 -2
  112. data/lib/bcdice/game_system/TokumeiTenkousei.rb +2 -2
  113. data/lib/bcdice/game_system/Torg.rb +1 -1
  114. data/lib/bcdice/game_system/TorgEternity.rb +4 -7
  115. data/lib/bcdice/game_system/TrinitySeven.rb +2 -2
  116. data/lib/bcdice/game_system/TunnelsAndTrolls.rb +6 -6
  117. data/lib/bcdice/game_system/TwilightGunsmoke.rb +1 -1
  118. data/lib/bcdice/game_system/Utakaze.rb +1 -1
  119. data/lib/bcdice/game_system/Warhammer.rb +6 -6
  120. data/lib/bcdice/game_system/Warhammer4.rb +9 -12
  121. data/lib/bcdice/game_system/ZettaiReido.rb +1 -1
  122. data/lib/bcdice/normalize.rb +1 -1
  123. data/lib/bcdice/preprocessor.rb +12 -8
  124. data/lib/bcdice/randomizer.rb +12 -0
  125. data/lib/bcdice/repl.rb +1 -1
  126. data/lib/bcdice/result.rb +2 -0
  127. data/lib/bcdice/user_defined_dice_table.rb +26 -15
  128. data/lib/bcdice/version.rb +1 -1
  129. metadata +14 -25
  130. data/.editorconfig +0 -21
  131. data/.github/.codecov.yaml +0 -10
  132. data/.github/workflows/coverage.yaml +0 -21
  133. data/.github/workflows/lint.yaml +0 -13
  134. data/.github/workflows/test.yml +0 -20
  135. data/.gitignore +0 -14
  136. data/.rubocop.yml +0 -108
  137. data/.rubocop_todo.yml +0 -114
  138. data/Gemfile +0 -14
  139. data/ROADMAP.md +0 -30
  140. data/Rakefile +0 -152
  141. data/bcdice.gemspec +0 -29
  142. data/bin/repl.rb +0 -21
  143. data/docs/README.txt +0 -2028
  144. data/docs/dicebot_sort_key.md +0 -72
  145. data/docs/how_to_make_dicebot.md +0 -453
  146. data/lib/bcdice/command_parser.rb +0 -242
  147. data/lib/bcdice/common_command/add_dice/parser.y +0 -153
  148. data/lib/bcdice/common_command/barabara_dice/parser.y +0 -107
  149. data/lib/bcdice/common_command/calc/parser.y +0 -79
  150. data/lib/bcdice/common_command/reroll_dice/parser.y +0 -158
  151. data/lib/bcdice/common_command/upper_dice/parser.y +0 -143
@@ -40,9 +40,9 @@ module BCDice
40
40
  private
41
41
 
42
42
  def replace_text(string)
43
- string = string.gsub(/(\d+)NC(10)?([\+\-][\+\-\d]+)/i) { "#{Regexp.last_match(1)}R10#{Regexp.last_match(3)}[0]" }
43
+ string = string.gsub(/(\d+)NC(10)?([+\-][+\-\d]+)/i) { "#{Regexp.last_match(1)}R10#{Regexp.last_match(3)}[0]" }
44
44
  string = string.gsub(/(\d+)NC(10)?/i) { "#{Regexp.last_match(1)}R10[0]" }
45
- string = string.gsub(/(\d+)NA(10)?([\+\-][\+\-\d]+)/i) { "#{Regexp.last_match(1)}R10#{Regexp.last_match(3)}[1]" }
45
+ string = string.gsub(/(\d+)NA(10)?([+\-][+\-\d]+)/i) { "#{Regexp.last_match(1)}R10#{Regexp.last_match(3)}[1]" }
46
46
  string = string.gsub(/(\d+)NA(10)?/i) { "#{Regexp.last_match(1)}R10[1]" }
47
47
 
48
48
  return string
@@ -82,7 +82,7 @@ module BCDice
82
82
  string = replace_text(string)
83
83
  debug("nechronica_check string", string)
84
84
 
85
- unless /(^|\s)S?((\d+)[rR]10([\+\-\d]+)?(\[(\d+)\])?)(\s|$)/i =~ string
85
+ unless /(^|\s)S?((\d+)[rR]10([+\-\d]+)?(\[(\d+)\])?)(\s|$)/i =~ string
86
86
  return nil
87
87
  end
88
88
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "bcdice/normalize"
4
4
  require "bcdice/format"
5
- require "bcdice/command_parser"
6
5
 
7
6
  module BCDice
8
7
  module GameSystem
@@ -90,6 +89,7 @@ module BCDice
90
89
  attr_accessor :modify_number
91
90
 
92
91
  def initialize(command)
92
+ super()
93
93
  @command = command
94
94
  end
95
95
 
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bcdice/command_parser"
4
3
  require "bcdice/format"
5
4
 
6
5
  module BCDice
@@ -43,9 +42,9 @@ module BCDice
43
42
  .sub(/Lv(\d+)/i) { (Regexp.last_match(1).to_i * 5 - 1).to_s }
44
43
  .sub(/NL(\d+)/i) { (Regexp.last_match(1).to_i * 5 + 5).to_s }
45
44
 
46
- parser = CommandParser.new(/^\d+D6$/)
47
- .allow_cmp_op(nil, :>=)
48
- .enable_question_target()
45
+ parser = Command::Parser.new(/\d+D6/, round_type: round_type)
46
+ .restrict_cmp_op_to(nil, :>=)
47
+ .enable_question_target()
49
48
  cmd = parser.parse(command)
50
49
  unless cmd
51
50
  return nil
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'bcdice/common_command/barabara_dice'
3
4
  require 'bcdice/dice_table/table'
4
5
 
5
6
  module BCDice
@@ -69,9 +70,6 @@ module BCDice
69
70
  # 電子戦の正規表現
70
71
  EL_RE = /\AEL(\d+)#{DIFFICULTY_RE}?\z/io.freeze
71
72
 
72
- # バラバラロール結果の "(" の前までの先頭部分
73
- B_ROLL_RESULT_HEAD_RE = /\A[^(]+/.freeze
74
-
75
73
  # 回避判定のノード
76
74
  EV = Struct.new(:num, :difficulty, :targetValue)
77
75
  # 近接攻撃のノード
@@ -169,19 +167,15 @@ module BCDice
169
167
  # @return [String] 回避判定結果
170
168
  def executeEV(ev)
171
169
  command = bRollCommand(ev.num, ev.difficulty)
170
+ roll_result = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer)
172
171
 
173
- rollResult = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer).text.sub(B_ROLL_RESULT_HEAD_RE, '')
174
- return rollResult unless ev.targetValue
175
-
176
- m = /成功数(\d+)/.match(rollResult)
177
- raise '成功数が見つかりません' unless m
172
+ parts = [roll_result.text]
178
173
 
179
- numOfSuccesses = m[1].to_i
180
- if numOfSuccesses > ev.targetValue
181
- return "#{rollResult} > カウンターカラテ!!"
174
+ if ev.targetValue && roll_result.success_num > ev.targetValue
175
+ parts.push("カウンターカラテ!!")
182
176
  end
183
177
 
184
- return rollResult
178
+ return parts.join(" > ")
185
179
  end
186
180
 
187
181
  # 近接攻撃を行う
@@ -189,16 +183,18 @@ module BCDice
189
183
  # @return [String] 近接攻撃結果
190
184
  def executeAT(at)
191
185
  command = bRollCommand(at.num, at.difficulty)
192
- rollResult = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer).text.sub(B_ROLL_RESULT_HEAD_RE, '')
186
+ roll_result = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer)
187
+
188
+ values = roll_result.rands.map { |v, _| v }
189
+ num_of_max_values = values.count(6)
193
190
 
194
- # バラバラロールの出目を取得する
195
- # TODO: バラバラロールの結果として、出目を配列で取得できるようにする
196
- m = /> (\d+(?:,\d+)*)/.match(rollResult)
197
- values = m[1].split(',').map(&:to_i)
191
+ parts = [roll_result.text]
198
192
 
199
- numOfMaxValues = values.count(6)
193
+ if num_of_max_values >= 2
194
+ parts.push("サツバツ!!")
195
+ end
200
196
 
201
- return numOfMaxValues >= 2 ? "#{rollResult}サツバツ!!" : rollResult
197
+ return parts.join(" > ")
202
198
  end
203
199
 
204
200
  # 電子戦を行う
@@ -206,18 +202,20 @@ module BCDice
206
202
  # @return [String] 電子戦結果
207
203
  def executeEL(el)
208
204
  command = bRollCommand(el.num, el.difficulty)
209
- rollResult = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer).text.sub(B_ROLL_RESULT_HEAD_RE, '')
210
-
211
- # バラバラロールの出目を取得する
212
- # TODO: バラバラロールの結果として、出目を配列で取得できるようにする
213
- m = /> (\d+(?:,\d+)*)/.match(rollResult)
214
- values = m[1].split(',').map(&:to_i)
205
+ roll_result = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer)
215
206
 
216
- numOfMaxValues = values.count(6)
207
+ values = roll_result.rands.map { |v, _| v }
208
+ num_of_max_values = values.count(6)
209
+ sum_of_true_values = values.count { |v| v >= el.difficulty }
217
210
 
218
- sumOfTrueValues = values.count { |v| v >= el.difficulty }
211
+ if num_of_max_values >= 1
212
+ return [
213
+ "#{roll_result.text} + #{num_of_max_values}",
214
+ sum_of_true_values + num_of_max_values
215
+ ].join(" > ")
216
+ end
219
217
 
220
- return numOfMaxValues >= 1 ? "#{rollResult} + #{numOfMaxValues} > #{sumOfTrueValues + numOfMaxValues}" : rollResult
218
+ return roll_result.text
221
219
  end
222
220
 
223
221
  # 難易度の整数値を返す
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bcdice/command_parser'
4
3
  require 'bcdice/format'
5
4
 
6
5
  module BCDice
@@ -47,7 +46,7 @@ MESSAGETEXT
47
46
  case command
48
47
  when /\d+CL.*/i
49
48
  clutch_roll(command)
50
- when /\d+D6.*\$[\+\-]?\d.*/
49
+ when /\d+D6.*\$[+\-]?\d.*/
51
50
  damage_roll(command)
52
51
  when /\d+R6/
53
52
  r_roll(command)
@@ -58,17 +57,15 @@ MESSAGETEXT
58
57
  def clutch_roll(string)
59
58
  debug("clutch_roll begin", string)
60
59
 
61
- parser = CommandParser.new(/\d+CL[67]?/i)
60
+ parser = Command::Parser.new(/\d+CL[67]?/, round_type: round_type)
61
+ .restrict_cmp_op_to(nil, :>=)
62
+
62
63
  @cmd = parser.parse(string)
63
64
 
64
65
  unless @cmd
65
66
  return nil
66
67
  end
67
68
 
68
- unless [:>=, nil].include?(@cmd.cmp_op)
69
- return nil
70
- end
71
-
72
69
  @times, @max_shift = @cmd.command.split("CL").map(&:to_i)
73
70
  @max_shift ||= 6
74
71
  @cmd.target_number = clamp(@cmd.target_number, 1, @max_shift) if @cmd.cmp_op
@@ -120,16 +117,16 @@ MESSAGETEXT
120
117
 
121
118
  # 判定
122
119
  def r_roll(string)
123
- parser = CommandParser.new(/\d+R6/i)
120
+ parser = Command::Parser.new(/\d+R6/, round_type: round_type)
121
+ .restrict_cmp_op_to(nil, :>=)
122
+ .enable_critical
123
+ .enable_fumble
124
+ .enable_dollar
124
125
  @cmd = parser.parse(string)
125
126
  unless @cmd
126
127
  return nil
127
128
  end
128
129
 
129
- unless [:>=, nil].include?(@cmd.cmp_op)
130
- return nil
131
- end
132
-
133
130
  @times = @cmd.command.to_i
134
131
 
135
132
  if @times == 0
@@ -214,12 +211,11 @@ MESSAGETEXT
214
211
 
215
212
  # ダメージロール
216
213
  def damage_roll(string)
217
- parser = CommandParser.new(/\d+D6/i)
214
+ parser = Command::Parser.new(/\d+D6/, round_type: round_type)
215
+ .restrict_cmp_op_to(nil)
216
+ .enable_dollar
218
217
  @cmd = parser.parse(string)
219
-
220
- if @cmd.nil? || !@cmd.cmp_op.nil?
221
- return nil
222
- end
218
+ return nil unless @cmd
223
219
 
224
220
  @times = @cmd.command.to_i
225
221
  @break = (@cmd.dollar || 0).abs
@@ -53,13 +53,13 @@ module BCDice
53
53
  # 通常判定
54
54
  def getJudgeResult(command)
55
55
  case command
56
- when /^(\d+)*D20<=(\d+)?(\[(\d+)(,(\d+))?\])?(\@(\d+))?$/i
56
+ when /^(\d+)*D20<=(\d+)?(\[(\d+)(,(\d+))?\])?(@(\d+))?$/i
57
57
  number = (Regexp.last_match(1) || 1).to_i # ダイス数。省略時は1
58
58
  target = (Regexp.last_match(2) || 14).to_i # 目標値。省略時は14 if 空白 then 14 else 記載の値
59
59
  fumble1 = (Regexp.last_match(4) || 21).to_i # 追加ファンブル値。省略時は21
60
60
  fumble2 = (Regexp.last_match(6) || 21).to_i # 追加ファンブル値。省略時は21
61
61
  critical = (Regexp.last_match(8) || 21).to_i # 追加クリティカル値。省略時は21
62
- when /^(\d+)*CP(\d+)?(\[(\d+)(,(\d+))?\])?(\@(\d+))?$/i
62
+ when /^(\d+)*CP(\d+)?(\[(\d+)(,(\d+))?\])?(@(\d+))?$/i
63
63
  number = (Regexp.last_match(1) || 1).to_i
64
64
  target = (Regexp.last_match(2) || 14).to_i
65
65
  fumble1 = (Regexp.last_match(4) || 21).to_i
@@ -17,10 +17,6 @@ module BCDice
17
17
  成功、失敗、決定的成功、決定的失敗の表示とクリティカル・ファンブル値計算の実装。
18
18
  INFO_MESSAGE_TEXT
19
19
 
20
- def initialize(command)
21
- super(command)
22
- end
23
-
24
20
  # ゲーム別成功度判定(1d20)
25
21
  def check_1D20(total, _dice_total, cmp_op, diff)
26
22
  return '' if diff == '?'
@@ -52,7 +52,7 @@ module BCDice
52
52
 
53
53
  return checkRoll(diceCount, choiceCount, target)
54
54
 
55
- elsif command =~ /(-)?(\d+)?DD([1-9])?([\+\-]\d+)?$/i
55
+ elsif command =~ /(-)?(\d+)?DD([1-9])?([+\-]\d+)?$/i
56
56
  diceCount = (Regexp.last_match(2) || 1).to_i
57
57
  diceCount *= -1 unless Regexp.last_match(1).nil?
58
58
  armor = (Regexp.last_match(3) || 0).to_i
@@ -1,5 +1,3 @@
1
- require 'bcdice/command_parser'
2
-
3
1
  module BCDice
4
2
  module GameSystem
5
3
  class RecordOfLodossWar < Base
@@ -22,7 +20,8 @@ module BCDice
22
20
  register_prefix('LW.*')
23
21
 
24
22
  def eval_game_system_specific_command(command)
25
- parser = CommandParser.new("LW", "LWD")
23
+ parser = Command::Parser.new("LWD", "LW", round_type: round_type)
24
+ .restrict_cmp_op_to(nil, :<=)
26
25
  cmd = parser.parse(command)
27
26
 
28
27
  if cmd.nil? || ![nil, :<=].include?(cmd.cmp_op)
@@ -31,7 +31,7 @@ module BCDice
31
31
  end
32
32
 
33
33
  def replace_text(string)
34
- string = string.gsub(/(\d+)RS([\+\-][\+\-\d]+)<=(\d+)/i) { "3R6#{Regexp.last_match(2)}<=#{Regexp.last_match(3)}[#{Regexp.last_match(1)}]" }
34
+ string = string.gsub(/(\d+)RS([+\-][+\-\d]+)<=(\d+)/i) { "3R6#{Regexp.last_match(2)}<=#{Regexp.last_match(3)}[#{Regexp.last_match(1)}]" }
35
35
  string = string.gsub(/(\d+)RS<=(\d+)/i) { "3R6<=#{Regexp.last_match(2)}[#{Regexp.last_match(1)}]" }
36
36
 
37
37
  return string
@@ -39,7 +39,7 @@ module BCDice
39
39
 
40
40
  def eval_game_system_specific_command(string)
41
41
  string = replace_text(string)
42
- unless /3R6([\+\-\d]*)<=(\d+)\[(\d+)\]/i =~ string
42
+ unless /3R6([+\-\d]*)<=(\d+)\[(\d+)\]/i =~ string
43
43
  return nil
44
44
  end
45
45
 
@@ -62,7 +62,7 @@ module BCDice
62
62
  private
63
63
 
64
64
  def check_roll(command)
65
- m = %r{^RB(\-?\d+([\+\-\*/]\d+)*)(@(\d+))?(#(\d+))?$}.match(command)
65
+ m = %r{^RB(-?\d+([+\-*/]\d+)*)(@(\d+))?(#(\d+))?$}.match(command)
66
66
  unless m
67
67
  return nil
68
68
  end
@@ -31,7 +31,7 @@ module BCDice
31
31
  def eval_game_system_specific_command(command)
32
32
  debug('eval_game_system_specific_command begin')
33
33
 
34
- unless command =~ /^R(\d+)(,(\d+))?([\+\-\d]+)?(>=(\d+))?/
34
+ unless command =~ /^R(\d+)(,(\d+))?([+\-\d]+)?(>=(\d+))?/
35
35
  debug('unmatched!')
36
36
  return ''
37
37
  end
@@ -2,11 +2,6 @@
2
2
 
3
3
  require 'bcdice/arithmetic_evaluator'
4
4
 
5
- # スタンダードRPGシステムのダイスボット
6
- #
7
- # スタンダードRPGシステムにおいて共通な2D6成功判定を実装している。
8
- # また、各ゲームシステムに合わせた2D6成功判定のエイリアスコマンドを
9
- # 登録するクラスメソッド set_aliases_for_srs_roll を持つ。
10
5
  module BCDice
11
6
  module GameSystem
12
7
  class SRS < Base
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bcdice/command_parser"
4
-
5
3
  module BCDice
6
4
  module GameSystem
7
5
  class SamsaraBallad < Base
@@ -38,7 +36,10 @@ module BCDice
38
36
  def eval_game_system_specific_command(command)
39
37
  debug("eval_game_system_specific_command Begin")
40
38
 
41
- parser = CommandParser.new('SB', 'SBS')
39
+ parser = Command::Parser.new('SBS', 'SB', round_type: round_type)
40
+ .enable_critical
41
+ .enable_fumble
42
+ .restrict_cmp_op_to(nil, :<=, :<)
42
43
  cmd = parser.parse(command)
43
44
 
44
45
  unless cmd
@@ -131,13 +131,17 @@ module BCDice
131
131
  isCriticalStop = false
132
132
 
133
133
  # params => "[x,y,cS]"
134
- unless params.nil?
135
- if /\[(\d*)(,(\d*)?)?(,(\d*)(S)?)?\]/ =~ params
136
- min_suc = Regexp.last_match(1).to_i
137
- fumble = Regexp.last_match(3).to_i if Regexp.last_match(3).to_i != 0
138
- critical = Regexp.last_match(5).to_i if Regexp.last_match(4)
139
- isCriticalStop = !Regexp.last_match(6).nil?
140
- end
134
+ # frozen_string_literal: true
135
+ # ゲームシステムの識別子
136
+ # ゲームシステム名
137
+ # ゲームシステム名の読みがな
138
+ # ダイスボットの使い方
139
+ # params => "[x,y,cS]"
140
+ if !params.nil? && /\[(\d*)(,(\d*)?)?(,(\d*)(S)?)?\]/ =~ params
141
+ min_suc = Regexp.last_match(1).to_i
142
+ fumble = Regexp.last_match(3).to_i if Regexp.last_match(3).to_i != 0
143
+ critical = Regexp.last_match(5).to_i if Regexp.last_match(4)
144
+ isCriticalStop = !Regexp.last_match(6).nil?
141
145
  end
142
146
 
143
147
  return min_suc, fumble, critical, isCriticalStop
@@ -162,11 +166,15 @@ module BCDice
162
166
  debug('roll_times', roll_times)
163
167
 
164
168
  debug('min_suc, total_suc', min_suc, total_suc)
165
- if min_suc != 0
166
- if total_suc >= min_suc
167
- debug('(total_suc >= min_suc) break')
168
- break
169
- end
169
+ # frozen_string_literal: true
170
+ # ゲームシステムの識別子
171
+ # ゲームシステム名
172
+ # ゲームシステム名の読みがな
173
+ # ダイスボットの使い方
174
+ # params => "[x,y,cS]"
175
+ if min_suc != 0 && (total_suc >= min_suc)
176
+ debug('(total_suc >= min_suc) break')
177
+ break
170
178
  end
171
179
 
172
180
  d1 = @randomizer.roll_once(6)
@@ -200,7 +208,7 @@ module BCDice
200
208
  def check_seigou(string)
201
209
  debug("check_seigou begin string", string)
202
210
 
203
- return '' unless /^SR(\d+)(([+]|[-])(\d+))?$/i =~ string
211
+ return '' unless /^SR(\d+)(([+]|-)(\d+))?$/i =~ string
204
212
 
205
213
  target = Regexp.last_match(1).to_i
206
214
  operator = Regexp.last_match(3)
@@ -237,7 +245,7 @@ module BCDice
237
245
  command = command.upcase
238
246
  result = []
239
247
 
240
- return result unless command =~ /([A-Za-z]+)(\d+)?(([+]|[-]|[=])(\d+))?/
248
+ return result unless command =~ /([A-Za-z]+)(\d+)?(([+]|-|=)(\d+))?/
241
249
 
242
250
  command = Regexp.last_match(1)
243
251
  counts = 1
@@ -44,14 +44,14 @@ module BCDice
44
44
 
45
45
  def eval_game_system_specific_command(command)
46
46
  case command
47
- when /(EM|TR|FE)(\-?\d+)(@(\d+))?/i
47
+ when /(EM|TR|FE)(-?\d+)(@(\d+))?/i
48
48
  command_type = Regexp.last_match(1).upcase
49
49
  success_rate = Regexp.last_match(2).to_i
50
50
  critical_border_text = Regexp.last_match(4)
51
51
  critical_border = get_critical_border(critical_border_text, success_rate)
52
52
 
53
53
  return check_roll_sh(success_rate, critical_border, command_type)
54
- when %r{(SH|SHS)(\-?\d+)(/(\d+))?(@(\d+))?}i
54
+ when %r{(SH|SHS)(-?\d+)(/(\d+))?(@(\d+))?}i
55
55
  success_rate = Regexp.last_match(2).to_i
56
56
  repeat_count = (Regexp.last_match(4) || 1).to_i
57
57
  critical_border_text = Regexp.last_match(6)
@@ -39,7 +39,7 @@ module BCDice
39
39
  )
40
40
 
41
41
  def eval_game_system_specific_command(command)
42
- m = /^([A-Z]+)([\+\-]?\d+)?(?:>=(\d+))?$/i.match(command)
42
+ m = /^([A-Z]+)([+\-]?\d+)?(?:>=(\d+))?$/i.match(command)
43
43
  unless m
44
44
  return nil
45
45
  end
@@ -16,9 +16,18 @@ module BCDice
16
16
 
17
17
  # ダイスボットの使い方
18
18
  HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
19
+ ・行為判定 SG@s#f>=x
20
+  2D6の行為判定を行う
21
+  s: スペシャル値 (省略時 12)
22
+  f: ファンブル値 (省略時 2)
23
+  x: 目標値 (省略可)
24
+  例)SG, SG@11, SG@11#3, SG#3>=7
19
25
  ・各種表
20
26
   ・(無印)シーン表 ST/ファンブル表 FT/感情表 ET
21
-    /変調表 WT/戦場表 BT/異形表 MT/ランダム特技決定表 RTT
27
+    /変調表 WT/戦場表 BT/異形表 MT
28
+  ・ランダム特技決定表 RTTn (n:分野番号、省略可能)
29
+    1器術 2体術 3忍術 4謀術 5戦術 6妖術
30
+  ・ランダム分野表 RCT
22
31
   ・(弐)都市シーン表 CST/館シーン表  MST/出島シーン表 DST
23
32
   ・(参)トラブルシーン表 TST/日常シーン表 NST/回想シーン表 KST
24
33
   ・(死)東京シーン表 TKST/戦国シーン表 GST
@@ -41,49 +50,86 @@ module BCDice
41
50
  @d66_sort_type = D66SortType::ASC
42
51
  end
43
52
 
44
- def check_2D6(total, dice_total, _dice_list, cmp_op, target)
45
- return '' unless cmp_op == :>=
53
+ SPECIAL = "スペシャル(【生命力】1点か変調一つを回復)"
54
+
55
+ def result_2d6(total, dice_total, _dice_list, cmp_op, target)
56
+ return nil unless cmp_op == :>=
46
57
 
47
58
  if dice_total <= 2
48
- "ファンブル"
59
+ Result.fumble("ファンブル")
49
60
  elsif dice_total >= 12
50
- " > スペシャル(【生命力】1点か変調一つを回復)"
61
+ Result.critical(SPECIAL)
51
62
  elsif target == "?"
52
- ""
63
+ nil
53
64
  elsif total >= target
54
- "成功"
65
+ Result.success("成功")
55
66
  else
56
- "失敗"
67
+ Result.failure("失敗")
57
68
  end
58
69
  end
59
70
 
60
- def eval_game_system_specific_command(command)
61
- string = command.upcase
62
-
63
- result = roll_tables(command, TABLES)
64
- if result
65
- return result
66
- end
71
+ register_prefix("SG")
67
72
 
68
- case string
69
- when /\w*RTT/ # ランダム特技決定表
70
- return sinobigami_random_skill_table()
71
- when 'MT' # 異形表
72
- return sinobigami_metamorphose_table()
73
- end
73
+ def eval_game_system_specific_command(command)
74
+ result = action_roll(command) || roll_tables(command, TABLES) || RTT.roll_command(@randomizer, command)
75
+ return result if result
76
+ return sinobigami_metamorphose_table() if command == 'MT'
74
77
 
75
- return nil
78
+ nil
76
79
  end
77
80
 
81
+ RTT = DiceTable::SaiFicSkillTable.new(
82
+ [
83
+ ['器術', ['絡繰術', '火術', '水術', '針術', '仕込み', '衣装術', '縄術', '登術', '拷問術', '壊器術', '掘削術']],
84
+ ['体術', ['騎乗術', '砲術', '手裏剣術', '手練', '身体操術', '歩法', '走法', '飛術', '骨法術', '刀術', '怪力']],
85
+ ['忍術', ['生存術', '潜伏術', '遁走術', '盗聴術', '腹話術', '隠形術', '変装術', '香術', '分身の術', '隠蔽術', '第六感']],
86
+ ['謀術', ['医術', '毒術', '罠術', '調査術', '詐術', '対人術', '遊芸', '九ノ一の術', '傀儡の術', '流言の術', '経済力']],
87
+ ['戦術', ['兵糧術', '鳥獣術', '野戦術', '地の利', '意気', '用兵術', '記憶術', '見敵術', '暗号術', '伝達術', '人脈']],
88
+ ['妖術', ['異形化', '召喚術', '死霊術', '結界術', '封術', '言霊術', '幻術', '瞳術', '千里眼の術', '憑依術', '呪術']],
89
+ ],
90
+ s_format: "『%<category_name>s』%<skill_name>s",
91
+ rtt_format: "ランダム指定特技表(%<category_dice>d,%<row_dice>d) > %<text>s"
92
+ )
93
+
78
94
  private
79
95
 
80
- # ランダム指定特技表
81
- def sinobigami_random_skill_table()
82
- skill_table, value1 = get_table_by_1d6(RANDOM_SKILL_TABLE)
83
- table_name, skill_table = skill_table
84
- skill, value2 = get_table_by_2d6(skill_table)
96
+ def action_roll(command)
97
+ parser = Command::Parser.new("SG", round_type: round_type)
98
+ .restrict_cmp_op_to(:>=, nil)
99
+ .enable_critical
100
+ .enable_fumble
101
+ cmd = parser.parse(command)
102
+ return nil unless cmd
85
103
 
86
- return "ランダム指定特技表(#{value1},#{value2}) > 『#{table_name}』#{skill}"
104
+ cmd.critical ||= 12
105
+ cmd.fumble ||= 2
106
+
107
+ dice_list = @randomizer.roll_barabara(2, 6).sort
108
+ dice_total = dice_list.sum()
109
+ total = dice_total + cmd.modify_number
110
+
111
+ result =
112
+ if dice_total >= cmd.critical
113
+ Result.critical(SPECIAL)
114
+ elsif dice_total <= cmd.fumble
115
+ Result.fumble("ファンブル")
116
+ elsif cmd.cmp_op.nil?
117
+ Result.new
118
+ elsif total >= cmd.target_number
119
+ Result.success("成功")
120
+ else
121
+ Result.failure("失敗")
122
+ end
123
+
124
+ sequence = [
125
+ "(#{cmd.to_s(:after_modify_number)})",
126
+ "#{dice_total}[#{dice_list.join(',')}]#{Format.modifier(cmd.modify_number)}",
127
+ total,
128
+ result.text
129
+ ].compact
130
+
131
+ result.text = sequence.join(" > ")
132
+ result
87
133
  end
88
134
 
89
135
  # 異形表
@@ -613,16 +659,6 @@ module BCDice
613
659
  ),
614
660
  }.freeze
615
661
 
616
- # ランダム指定特技表
617
- RANDOM_SKILL_TABLE = [
618
- ['器術', ['絡繰術', '火術', '水術', '針術', '仕込み', '衣装術', '縄術', '登術', '拷問術', '壊器術', '掘削術']],
619
- ['体術', ['騎乗術', '砲術', '手裏剣術', '手練', '身体操術', '歩法', '走法', '飛術', '骨法術', '刀術', '怪力']],
620
- ['忍術', ['生存術', '潜伏術', '遁走術', '盗聴術', '腹話術', '隠形術', '変装術', '香術', '分身の術', '隠蔽術', '第六感']],
621
- ['謀術', ['医術', '毒術', '罠術', '調査術', '詐術', '対人術', '遊芸', '九ノ一の術', '傀儡の術', '流言の術', '経済力']],
622
- ['戦術', ['兵糧術', '鳥獣術', '野戦術', '地の利', '意気', '用兵術', '記憶術', '見敵術', '暗号術', '伝達術', '人脈']],
623
- ['妖術', ['異形化', '召喚術', '死霊術', '結界術', '封術', '言霊術', '幻術', '瞳術', '千里眼の術', '憑依術', '呪術']],
624
- ].freeze
625
-
626
662
  # 異形表
627
663
  METAMORPHOSE_TABLE = [
628
664
  '1D6を振り、「妖魔忍法表A」で、ランダムに忍法の種類を決定する。妖魔化している間、その妖魔忍法を修得しているものとして扱う。この異形は、違う種類の妖魔忍法である限り、違う異形として扱う。',
@@ -673,7 +709,7 @@ module BCDice
673
709
  }
674
710
  ].freeze
675
711
 
676
- register_prefix('MT', 'RTT', TABLES.keys)
712
+ register_prefix('MT', RTT.prefixes, TABLES.keys)
677
713
  end
678
714
  end
679
715
  end