bcdice 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -3
  3. data/README.md +1 -1
  4. data/i18n/MagicaLogia/zh_hans.yml +564 -0
  5. data/i18n/StellarKnights/ja_jp.yml +2 -0
  6. data/i18n/StellarKnights/ko_kr.yml +498 -0
  7. data/i18n/zh_hans.yml +7 -0
  8. data/lib/bcdice/command/parsed.rb +11 -3
  9. data/lib/bcdice/command/parser.rb +179 -100
  10. data/lib/bcdice/common_command/barabara_dice/node.rb +2 -2
  11. data/lib/bcdice/common_command/barabara_dice/result.rb +6 -0
  12. data/lib/bcdice/game_system.rb +3 -0
  13. data/lib/bcdice/game_system/Amadeus.rb +110 -93
  14. data/lib/bcdice/game_system/AnimaAnimus.rb +15 -8
  15. data/lib/bcdice/game_system/BattleTech.rb +109 -28
  16. data/lib/bcdice/game_system/BeastBindTrinity.rb +28 -12
  17. data/lib/bcdice/game_system/BlindMythos.rb +38 -37
  18. data/lib/bcdice/game_system/CodeLayerd.rb +39 -39
  19. data/lib/bcdice/game_system/ColossalHunter.rb +34 -47
  20. data/lib/bcdice/game_system/DeadlineHeroes.rb +9 -8
  21. data/lib/bcdice/game_system/DoubleCross.rb +2 -0
  22. data/lib/bcdice/game_system/Emoklore.rb +22 -17
  23. data/lib/bcdice/game_system/FutariSousa.rb +12 -10
  24. data/lib/bcdice/game_system/GardenOrder.rb +11 -6
  25. data/lib/bcdice/game_system/KemonoNoMori.rb +25 -38
  26. data/lib/bcdice/game_system/KurayamiCrying.rb +86 -0
  27. data/lib/bcdice/game_system/LiveraDoll.rb +254 -304
  28. data/lib/bcdice/game_system/LogHorizon.rb +10 -7
  29. data/lib/bcdice/game_system/MagicaLogia_SimplifiedChinese.rb +66 -0
  30. data/lib/bcdice/game_system/MeikyuKingdomBasic.rb +2 -1
  31. data/lib/bcdice/game_system/Nechronica.rb +57 -91
  32. data/lib/bcdice/game_system/NinjaSlayer.rb +2 -3
  33. data/lib/bcdice/game_system/SRS.rb +17 -16
  34. data/lib/bcdice/game_system/SamsaraBallad.rb +38 -11
  35. data/lib/bcdice/game_system/Satasupe.rb +31 -31
  36. data/lib/bcdice/game_system/ScreamHighSchool.rb +3 -3
  37. data/lib/bcdice/game_system/Skynauts.rb +101 -140
  38. data/lib/bcdice/game_system/StarryDolls.rb +318 -0
  39. data/lib/bcdice/game_system/SteamPunkers.rb +11 -6
  40. data/lib/bcdice/game_system/StellarKnights.rb +28 -12
  41. data/lib/bcdice/game_system/StellarKnights_Korean.rb +79 -0
  42. data/lib/bcdice/game_system/TokumeiTenkousei.rb +4 -3
  43. data/lib/bcdice/game_system/TrinitySeven.rb +275 -276
  44. data/lib/bcdice/game_system/Utakaze.rb +52 -47
  45. data/lib/bcdice/game_system/Yggdrasill.rb +1 -1
  46. data/lib/bcdice/game_system/ZettaiReido.rb +20 -25
  47. data/lib/bcdice/version.rb +1 -1
  48. metadata +8 -2
@@ -43,8 +43,8 @@ module BCDice
43
43
  Result.new.tap do |r|
44
44
  r.secret = @secret
45
45
  r.text = sequence.join(" > ")
46
- r.rands = randomizer.rand_results
47
- r.detailed_rands = randomizer.detailed_rand_results
46
+ r.last_dice_list_list = dice_list_list
47
+ r.last_dice_list = dice_list
48
48
  r.success_num = success_num
49
49
  end
50
50
  end
@@ -7,6 +7,10 @@ module BCDice
7
7
  module BarabaraDice
8
8
  # バラバラロールの結果を表すクラス
9
9
  class Result < ::BCDice::Result
10
+ # @return [Array<Array<Integer>>] 出目のグループの配列
11
+ attr_accessor :last_dice_list_list
12
+ # @return [Array<Integer>] すべての出目が格納される配列
13
+ attr_accessor :last_dice_list
10
14
  # @return [Integer] 成功数
11
15
  attr_accessor :success_num
12
16
 
@@ -14,6 +18,8 @@ module BCDice
14
18
  def initialize(text = nil)
15
19
  super(text)
16
20
 
21
+ @last_dice_list_list = []
22
+ @last_dice_list = []
17
23
  @success_num = 0
18
24
  end
19
25
  end
@@ -113,6 +113,7 @@ require "bcdice/game_system/LostRecord"
113
113
  require "bcdice/game_system/LostRoyal"
114
114
  require "bcdice/game_system/MagicaLogia"
115
115
  require "bcdice/game_system/MagicaLogia_Korean"
116
+ require "bcdice/game_system/MagicaLogia_SimplifiedChinese"
116
117
  require "bcdice/game_system/MeikyuDays"
117
118
  require "bcdice/game_system/MeikyuKingdom"
118
119
  require "bcdice/game_system/MeikyuKingdomBasic"
@@ -170,8 +171,10 @@ require "bcdice/game_system/ShinobiGami"
170
171
  require "bcdice/game_system/ShoujoTenrankai"
171
172
  require "bcdice/game_system/Skynauts"
172
173
  require "bcdice/game_system/SkynautsBouken"
174
+ require "bcdice/game_system/StarryDolls"
173
175
  require "bcdice/game_system/SteamPunkers"
174
176
  require "bcdice/game_system/StellarKnights"
177
+ require "bcdice/game_system/StellarKnights_Korean"
175
178
  require "bcdice/game_system/SterileLife"
176
179
  require "bcdice/game_system/StrangerOfSwordCity"
177
180
  require "bcdice/game_system/StratoShout"
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "bcdice/arithmetic_evaluator"
4
+ require "bcdice/format"
5
+ require "bcdice/normalize"
6
+
3
7
  module BCDice
4
8
  module GameSystem
5
9
  class Amadeus < Base
@@ -46,111 +50,124 @@ module BCDice
46
50
  end
47
51
 
48
52
  def eval_game_system_specific_command(command)
49
- text = amadeusDice(command)
50
- return text unless text.nil?
51
-
52
- return roll_tables(command, self.class::TABLES)
53
+ roll_amadeus(command) ||
54
+ roll_tables(command, self.class::TABLES)
53
55
  end
54
56
 
55
- def amadeusDice(command)
56
- return nil unless /^(R([A-DS])([+\-\d]*))(@(\d))?((>(=)?)([+\-\d]*))?(@(\d))?$/i =~ command
57
-
58
- commandText = Regexp.last_match(1)
59
- skillRank = Regexp.last_match(2)
60
- modifyText = Regexp.last_match(3)
61
- signOfInequality = (Regexp.last_match(7).nil? ? ">=" : Regexp.last_match(7))
62
- targetText = (Regexp.last_match(9).nil? ? "4" : Regexp.last_match(9))
63
- if nil | Regexp.last_match(5)
64
- specialNum = Regexp.last_match(5).to_i
65
- elsif nil | Regexp.last_match(11)
66
- specialNum = Regexp.last_match(11).to_i
67
- else
68
- specialNum = 6
57
+ private
58
+
59
+ def roll_amadeus(command)
60
+ m = /^R([A-DS])([+\-\d]*)(@(\d))?((>=?)([+\-\d]*))?(@(\d))?$/i.match(command)
61
+ unless m
62
+ return nil
69
63
  end
70
64
 
71
- diceCount = CHECK_DICE_COUNT[skillRank]
72
- modify = ArithmeticEvaluator.eval(modifyText)
73
- target = ArithmeticEvaluator.eval(targetText)
74
-
75
- diceList = @randomizer.roll_barabara(diceCount, 6)
76
- diceText = diceList.join(",")
77
- specialText = (specialNum == 6 ? "" : "@#{specialNum}")
78
-
79
- message = "(#{commandText}#{specialText}#{signOfInequality}#{targetText}) > [#{diceText}]#{modifyText} > "
80
- diceList = [diceList.min] if skillRank == "D"
81
- is_loop = false
82
- diceList.each do |dice|
83
- if is_loop
84
- message += " / "
85
- elsif diceList.length > 1
86
- is_loop = true
65
+ rank = m[1]
66
+ modifier = ArithmeticEvaluator.eval(m[2])
67
+ cmp_op = m[6] ? Normalize.comparison_operator(m[6]) : :>=
68
+ target = m[7] ? ArithmeticEvaluator.eval(m[7]) : 4
69
+ special = (m[4] || m[9] || 6).to_i
70
+
71
+ dice_count = CHECK_DICE_COUNT[rank]
72
+
73
+ dice_list = @randomizer.roll_barabara(dice_count, 6)
74
+ dice_text = dice_list.join(",")
75
+ special_text = (special == 6 ? "" : "@#{special}")
76
+
77
+ dice_list = [dice_list.min] if rank == "D"
78
+ available_inga = dice_list.size > 1
79
+ inga_table = translate("Amadeus.inga_table")
80
+
81
+ success = false
82
+ critical = false
83
+ fumble = false
84
+
85
+ results =
86
+ dice_list.map do |dice|
87
+ total = dice + modifier
88
+ result =
89
+ if dice == 1
90
+ fumble = true
91
+ translate("Amadeus.fumble")
92
+ elsif dice >= special
93
+ critical = true
94
+ success = true
95
+ translate("Amadeus.special")
96
+ elsif total.send(cmp_op, target)
97
+ success = true
98
+ translate("success")
99
+ else
100
+ translate("failure")
101
+ end
102
+
103
+ if available_inga
104
+ inga = inga_table[dice - 1]
105
+ "#{total}_#{result}[#{dice}#{inga}]"
106
+ else
107
+ "#{total}_#{result}[#{dice}]"
108
+ end
87
109
  end
88
- achieve = dice + modify
89
- result = check_success(achieve, dice, signOfInequality, target, specialNum)
90
- if is_loop
91
- inga_table = translate("Amadeus.inga_table")
92
- inga = inga_table[dice - 1]
93
- message += "#{achieve}_#{result}[#{dice}#{inga}]"
110
+
111
+ sequence = [
112
+ "(R#{rank}#{Format.modifier(modifier)}#{special_text}#{cmp_op}#{target})",
113
+ "[#{dice_text}]#{Format.modifier(modifier)}",
114
+ results.join(" / ")
115
+ ]
116
+
117
+ Result.new.tap do |r|
118
+ r.text = sequence.join(" > ")
119
+ if success
120
+ r.success = true
121
+ r.critical = critical
94
122
  else
95
- message += "#{achieve}_#{result}[#{dice}]"
123
+ r.failure = true
124
+ r.fumble = fumble
96
125
  end
97
126
  end
98
-
99
- return message
100
- end
101
-
102
- def check_success(total_n, dice_n, signOfInequality, diff, special_n)
103
- return translate("Amadeus.fumble") if dice_n == 1
104
- return translate("Amadeus.special") if dice_n >= special_n
105
-
106
- cmp_op = Normalize.comparison_operator(signOfInequality)
107
- target_num = diff.to_i
108
-
109
- if total_n.send(cmp_op, target_num)
110
- translate("success")
111
- else
112
- translate("failure")
113
- end
114
127
  end
115
128
 
116
129
  CHECK_DICE_COUNT = {"S" => 4, "A" => 3, "B" => 2, "C" => 1, "D" => 2}.freeze
117
130
 
118
- def self.translate_tables(locale)
119
- {
120
- "ECT" => DiceTable::Table.from_i18n("Amadeus.table.ECT", locale),
121
- "BST" => DiceTable::Table.from_i18n("Amadeus.table.BST", locale),
122
- "RT" => DiceTable::Table.from_i18n("Amadeus.table.RT", locale),
123
- "PRT" => DiceTable::Table.from_i18n("Amadeus.table.PRT", locale),
124
- "FT" => DiceTable::Table.from_i18n("Amadeus.table.FT", locale),
125
- "BT" => DiceTable::D66Table.from_i18n("Amadeus.table.BT", locale),
126
- "FWT" => DiceTable::Table.from_i18n("Amadeus.table.FWT", locale),
127
- "BRT" => DiceTable::Table.from_i18n("Amadeus.table.BRT", locale),
128
- "RIT" => DiceTable::Table.from_i18n("Amadeus.table.RIT", locale),
129
- "WT" => DiceTable::Table.from_i18n("Amadeus.table.WT", locale),
130
- "NMT" => DiceTable::Table.from_i18n("Amadeus.table.NMT", locale),
131
- "TGT" => DiceTable::Table.from_i18n("Amadeus.table.TGT", locale),
132
- "CST" => DiceTable::Table.from_i18n("Amadeus.table.CST", locale),
133
- "GCVT" => DiceTable::Table.from_i18n("Amadeus.table.GCVT", locale),
134
- "YCVT" => DiceTable::Table.from_i18n("Amadeus.table.YCVT", locale),
135
- "ECVT" => DiceTable::Table.from_i18n("Amadeus.table.ECVT", locale),
136
- "CCVT" => DiceTable::Table.from_i18n("Amadeus.table.CCVT", locale),
137
- "NCVT" => DiceTable::Table.from_i18n("Amadeus.table.NCVT", locale),
138
- "DGVT" => DiceTable::Table.from_i18n("Amadeus.table.DGVT", locale),
139
- "DAVT" => DiceTable::Table.from_i18n("Amadeus.table.DAVT", locale),
140
- "PRCT" => DiceTable::Table.from_i18n("Amadeus.table.PRCT", locale),
141
- "TCCT" => DiceTable::Table.from_i18n("Amadeus.table.TCCT", locale),
142
- "INCT" => DiceTable::Table.from_i18n("Amadeus.table.INCT", locale),
143
- "PSCT" => DiceTable::Table.from_i18n("Amadeus.table.PSCT", locale),
144
- "LVCT" => DiceTable::Table.from_i18n("Amadeus.table.LVCT", locale),
145
- "DACT" => DiceTable::Table.from_i18n("Amadeus.table.DACT", locale),
146
- "RGT" => DiceTable::Table.from_i18n("Amadeus.table.RGT", locale),
147
- "FBT" => DiceTable::Table.from_i18n("Amadeus.table.FBT", locale),
148
- "CHVT" => DiceTable::Table.from_i18n("Amadeus.table.CHVT", locale),
149
- "LCVT" => DiceTable::Table.from_i18n("Amadeus.table.LCVT", locale),
150
- "KCVT" => DiceTable::Table.from_i18n("Amadeus.table.KCVT", locale),
151
- "SAT" => DiceTable::D66Table.from_i18n("Amadeus.table.SAT", locale),
152
- "SMT" => DiceTable::D66Table.from_i18n("Amadeus.table.SMT", locale),
153
- }
131
+ class << self
132
+ private
133
+
134
+ def translate_tables(locale)
135
+ {
136
+ "ECT" => DiceTable::Table.from_i18n("Amadeus.table.ECT", locale),
137
+ "BST" => DiceTable::Table.from_i18n("Amadeus.table.BST", locale),
138
+ "RT" => DiceTable::Table.from_i18n("Amadeus.table.RT", locale),
139
+ "PRT" => DiceTable::Table.from_i18n("Amadeus.table.PRT", locale),
140
+ "FT" => DiceTable::Table.from_i18n("Amadeus.table.FT", locale),
141
+ "BT" => DiceTable::D66Table.from_i18n("Amadeus.table.BT", locale),
142
+ "FWT" => DiceTable::Table.from_i18n("Amadeus.table.FWT", locale),
143
+ "BRT" => DiceTable::Table.from_i18n("Amadeus.table.BRT", locale),
144
+ "RIT" => DiceTable::Table.from_i18n("Amadeus.table.RIT", locale),
145
+ "WT" => DiceTable::Table.from_i18n("Amadeus.table.WT", locale),
146
+ "NMT" => DiceTable::Table.from_i18n("Amadeus.table.NMT", locale),
147
+ "TGT" => DiceTable::Table.from_i18n("Amadeus.table.TGT", locale),
148
+ "CST" => DiceTable::Table.from_i18n("Amadeus.table.CST", locale),
149
+ "GCVT" => DiceTable::Table.from_i18n("Amadeus.table.GCVT", locale),
150
+ "YCVT" => DiceTable::Table.from_i18n("Amadeus.table.YCVT", locale),
151
+ "ECVT" => DiceTable::Table.from_i18n("Amadeus.table.ECVT", locale),
152
+ "CCVT" => DiceTable::Table.from_i18n("Amadeus.table.CCVT", locale),
153
+ "NCVT" => DiceTable::Table.from_i18n("Amadeus.table.NCVT", locale),
154
+ "DGVT" => DiceTable::Table.from_i18n("Amadeus.table.DGVT", locale),
155
+ "DAVT" => DiceTable::Table.from_i18n("Amadeus.table.DAVT", locale),
156
+ "PRCT" => DiceTable::Table.from_i18n("Amadeus.table.PRCT", locale),
157
+ "TCCT" => DiceTable::Table.from_i18n("Amadeus.table.TCCT", locale),
158
+ "INCT" => DiceTable::Table.from_i18n("Amadeus.table.INCT", locale),
159
+ "PSCT" => DiceTable::Table.from_i18n("Amadeus.table.PSCT", locale),
160
+ "LVCT" => DiceTable::Table.from_i18n("Amadeus.table.LVCT", locale),
161
+ "DACT" => DiceTable::Table.from_i18n("Amadeus.table.DACT", locale),
162
+ "RGT" => DiceTable::Table.from_i18n("Amadeus.table.RGT", locale),
163
+ "FBT" => DiceTable::Table.from_i18n("Amadeus.table.FBT", locale),
164
+ "CHVT" => DiceTable::Table.from_i18n("Amadeus.table.CHVT", locale),
165
+ "LCVT" => DiceTable::Table.from_i18n("Amadeus.table.LCVT", locale),
166
+ "KCVT" => DiceTable::Table.from_i18n("Amadeus.table.KCVT", locale),
167
+ "SAT" => DiceTable::D66Table.from_i18n("Amadeus.table.SAT", locale),
168
+ "SMT" => DiceTable::D66Table.from_i18n("Amadeus.table.SMT", locale),
169
+ }
170
+ end
154
171
  end
155
172
 
156
173
  TABLES = translate_tables(:ja_jp)
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'bcdice/dice_table/table'
4
4
  require 'bcdice/dice_table/range_table'
5
- require 'bcdice/arithmetic_evaluator'
5
+ require 'bcdice/arithmetic'
6
6
 
7
7
  module BCDice
8
8
  module GameSystem
@@ -32,17 +32,19 @@ module BCDice
32
32
  MESSAGETEXT
33
33
 
34
34
  def eval_game_system_specific_command(command)
35
- case command
36
- when /(\d+)AN<=(\d+([+\-]\d+)*)/i
37
- return check_action(Regexp.last_match)
38
- else
35
+ m = /(\d+)AN<=(\d+([+\-]\d+)*)/i.match(command)
36
+ if TABLES.key?(command)
39
37
  return roll_tables(command, TABLES)
38
+ elsif m
39
+ return check_action(m)
40
+ else
41
+ return nil
40
42
  end
41
43
  end
42
44
 
43
45
  def check_action(match_data)
44
- dice_cnt = ArithmeticEvaluator.eval(match_data[1])
45
- target = ArithmeticEvaluator.eval(match_data[2])
46
+ dice_cnt = Arithmetic.eval(match_data[1], RoundType::FLOOR)
47
+ target = Arithmetic.eval(match_data[2], RoundType::FLOOR)
46
48
  debug("dice_cnt", dice_cnt)
47
49
  debug("target", target)
48
50
 
@@ -52,7 +54,12 @@ module BCDice
52
54
  has_critical = dice_arr.include?(1)
53
55
  result = has_critical ? suc_cnt + 2 : suc_cnt
54
56
 
55
- return "(#{dice_cnt}B10<=#{target}) > #{dice_str} > #{result > 0 ? '成功' : '失敗'}(達成値:#{result})#{has_critical ? ' (クリティカル発生)' : ''}"
57
+ Result.new.tap do |r|
58
+ r.text = "(#{dice_cnt}B10<=#{target}) > #{dice_str} > #{result > 0 ? '成功' : '失敗'}(達成値:#{result})#{has_critical ? ' (クリティカル発生)' : ''}"
59
+ r.critical = has_critical
60
+ r.success = result > 0
61
+ r.failure = !r.success?
62
+ end
56
63
  end
57
64
 
58
65
  TABLES = {
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'bcdice/format'
4
+ require 'bcdice/command/parser'
3
5
  require 'bcdice/dice_table/table'
4
6
  require 'bcdice/dice_table/range_table'
5
7
 
@@ -26,24 +28,45 @@ module BCDice
26
28
    正面からダメージ3の攻撃を技能ベース2目標値4で1回判定
27
29
   例)2BT3RL+5>=8
28
30
    右下半身にダメージ3の攻撃を技能ベース5目標値8で2回判定
29
-  ミサイルによるダメージは BT(ダメージ)の変わりに SRM2/4/6, LRM5/10/15/20を指定
31
+  ミサイルによるダメージは BT(ダメージ) の代わりに SRM2/4/6, LRM5/10/15/20 を指定
30
32
   例)3SRM6LU+5>=8
31
33
    左上半身にSRM6連を技能ベース5目標値8で3回判定
34
+ BT(ダメージ) の代わりに PPC を指定するとダメージ10で判定
35
+ 例)2PPCR+3>=10
36
+  右側からPPC(ダメージ10)による攻撃を技能ベース3目標値10で2回判定
32
37
  ・CT:致命的命中表
33
38
  ・DW:転倒後の向き表
34
- ・CDx:メック戦士意識維持表。ダメージ値xで判定 例)CD3
39
+ ・CDx:メック戦士意識維持ロール。ダメージ値x(1〜6)で判定 例)CD3
35
40
  MESSAGETEXT
36
41
 
37
- register_prefix('\d*SRM', '\d*LRM', '\d*BT', 'PPC', 'CT', 'DW', 'CD')
42
+ register_prefix('\d*SRM', '\d*LRM', '\d*BT', '\d*PPC', 'CT', 'DW', 'CD')
38
43
 
39
44
  # 致命的命中が発生しない上限値
40
45
  NO_CRITICAL_HIT_LIMIT = 7
41
46
 
47
+ # @return [Command::Parser] PPCコマンドの構文解析器
48
+ def self.ppc_parser
49
+ return @ppc_parser if @ppc_parser
50
+
51
+ @ppc_parser = Command::Parser.new(/PPC(?:[LCR][LU]?)?/, round_type: RoundType::FLOOR)
52
+ @ppc_parser.enable_prefix_number
53
+ @ppc_parser.restrict_cmp_op_to(:>=)
54
+
55
+ @ppc_parser
56
+ end
57
+
58
+ # @return [Command::Parser] PPCコマンドの構文解析器
59
+ def ppc_parser
60
+ self.class.ppc_parser
61
+ end
62
+
42
63
  def eval_game_system_specific_command(command)
43
64
  result = roll_tables(command, TABLES)
44
65
  return result if result
45
66
 
46
- command = command.gsub("PPC", "BT10")
67
+ if (ppc_parse_result = ppc_parser.parse(command))
68
+ return execute_ppc(ppc_parse_result)
69
+ end
47
70
 
48
71
  count = 1
49
72
  if command =~ /^(\d+)(.+)/
@@ -55,9 +78,9 @@ module BCDice
55
78
  debug('executeCommandCatched command', command)
56
79
 
57
80
  case command
58
- when /^CD(\d+)$/
81
+ when /\ACD([1-6])\z/
59
82
  damage = Regexp.last_match(1).to_i
60
- return getCheckDieResult(damage)
83
+ return consciousness_roll(damage)
61
84
  when /^((S|L)RM\d+)(.+)/
62
85
  tail = Regexp.last_match(3)
63
86
  type = Regexp.last_match(1)
@@ -94,7 +117,7 @@ module BCDice
94
117
  LRM_LIMIT = 5
95
118
 
96
119
  def getHitResult(count, damageFunc, tail)
97
- m = /([LCR][LU]?)?(\+\d+)?>=(\d+)/.match(tail)
120
+ m = /\A([LCR][LU]?)?(\+\d+)?>=(\d+)/.match(tail)
98
121
  return nil unless m
99
122
 
100
123
  side = m[1] || 'C'
@@ -105,7 +128,7 @@ module BCDice
105
128
 
106
129
  partTable = HitPart::TABLES[side]
107
130
 
108
- resultTexts = []
131
+ resultLines = []
109
132
  damages = {}
110
133
  hitCount = 0
111
134
 
@@ -117,15 +140,24 @@ module BCDice
117
140
  damages, damageText = getDamages(damageFunc, partTable, damages)
118
141
  hitResult += damageText
119
142
  end
120
- resultTexts << hitResult
143
+ resultLines << hitResult
121
144
  end
122
145
 
123
- resultTexts.push(" > #{hitCount}回命中")
146
+ # 命中したか?
147
+ hit = hitCount > 0
124
148
 
125
- totalResultText = resultTexts.join("\n")
126
- totalResultText += " 命中箇所:" + getTotalDamage(damages) if hitCount > 0
149
+ hitCountText = " > #{hitCount}回命中"
150
+ hitDetails =
151
+ if hit
152
+ "#{hitCountText} 命中箇所:#{getTotalDamage(damages)}"
153
+ else
154
+ hitCountText
155
+ end
156
+ resultLines.push(hitDetails)
127
157
 
128
- return totalResultText
158
+ resultText = resultLines.join("\n")
159
+
160
+ return hit ? Result.success(resultText) : Result.failure(resultText)
129
161
  end
130
162
 
131
163
  def getBaseValue(baseString)
@@ -272,26 +304,75 @@ module BCDice
272
304
  return result_parts.join(' > '), hit_part.name, criticalText
273
305
  end
274
306
 
275
- def getCheckDieResult(damage)
276
- if damage >= 6
277
- return "死亡"
307
+ # メック戦士意識維持ロールを行う
308
+ #
309
+ # damageが6の場合は死亡。
310
+ # damageが5以下の場合は、2d6の結果が意識維持表の値以上かの成功判定。
311
+ #
312
+ # @param damage [Integer] メック戦士へのダメージ(1〜6)
313
+ # @return [Result]
314
+ # @see 「BattleTech: A Game of Armored Combat」ルールブックp. 44
315
+ def consciousness_roll(damage)
316
+ unless (1..6).include?(damage)
317
+ return nil
318
+ end
319
+
320
+ command = "CD#{damage}"
321
+
322
+ if damage == 6
323
+ return Result.fumble("#{command} > 死亡")
278
324
  end
279
325
 
280
- table = [[1, 3],
281
- [2, 5],
282
- [3, 7],
283
- [4, 10],
284
- [5, 11]]
326
+ consciousness_table = {
327
+ 1 => 3,
328
+ 2 => 5,
329
+ 3 => 7,
330
+ 4 => 10,
331
+ 5 => 11,
332
+ }
333
+
334
+ target = consciousness_table[damage]
335
+ expr = "(2D6>=#{target})"
336
+
337
+ values = @randomizer.roll_barabara(2, 6)
338
+ sum = values.sum
339
+ values_str = values.join(",")
340
+ sum_and_values = "#{sum}[#{values_str}]"
341
+
342
+ success = sum >= target
343
+ result = success ? "成功" : "失敗"
344
+
345
+ parts = [
346
+ command,
347
+ expr,
348
+ sum_and_values,
349
+ sum,
350
+ result,
351
+ ]
352
+ text = parts.join(" > ")
285
353
 
286
- target = get_table_by_number(damage, table, nil)
354
+ return success ? Result.success(text) : Result.failure(text)
355
+ end
287
356
 
288
- dice1 = @randomizer.roll_once(6)
289
- dice2 = @randomizer.roll_once(6)
290
- total = dice1 + dice2
291
- result = total >= target ? "成功" : "失敗"
292
- text = "#{total}[#{dice1},#{dice2}]>=#{target} #{result}"
357
+ # PPCコマンドを実行する
358
+ # @param parse_result [Command::Parsed] PPCコマンドの構文解析結果
359
+ # @return [Result, nil]
360
+ def execute_ppc(parse_result)
361
+ count = parse_result.prefix_number || 1
362
+
363
+ # getHitResult() の引数tailの形に合わせる
364
+ # TODO: 攻撃を表すクラスに変える
365
+
366
+ # "PPC" 以降の部位指定
367
+ side = parse_result.command[3..-1]
368
+
369
+ modifier = Format.modifier(parse_result.modify_number)
370
+ target = parse_result.target_number
371
+
372
+ tail = "#{side}#{modifier}>=#{target}"
293
373
 
294
- return text
374
+ # ダメージ10固定で命中判定を行う
375
+ return getHitResult(count, lambda { 10 }, tail)
295
376
  end
296
377
 
297
378
  # 表の集合