bcdice 3.0.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +79 -2
  3. data/README.md +32 -0
  4. data/i18n/MonotoneMuseum/ja_jp.yml +3 -3
  5. data/i18n/StellarKnights/ja_jp.yml +496 -0
  6. data/lib/bcdice/common_command/add_dice.rb +1 -1
  7. data/lib/bcdice/common_command/calc.rb +1 -1
  8. data/lib/bcdice/dice_table.rb +2 -0
  9. data/lib/bcdice/dice_table/d66_half_grid_table.rb +33 -0
  10. data/lib/bcdice/dice_table/d66_one_third_table.rb +34 -0
  11. data/lib/bcdice/dice_table/sai_fic_skill_table.rb +1 -1
  12. data/lib/bcdice/game_system.rb +4 -0
  13. data/lib/bcdice/game_system/AceKillerGene.rb +1 -1
  14. data/lib/bcdice/game_system/Ainecadette.rb +68 -0
  15. data/lib/bcdice/game_system/Airgetlamh.rb +1 -1
  16. data/lib/bcdice/game_system/AlchemiaStruggle.rb +1 -1
  17. data/lib/bcdice/game_system/Alsetto.rb +1 -1
  18. data/lib/bcdice/game_system/Alshard.rb +1 -1
  19. data/lib/bcdice/game_system/AlterRaise.rb +2 -2
  20. data/lib/bcdice/game_system/AngelGear.rb +123 -0
  21. data/lib/bcdice/game_system/AnimaAnimus.rb +1 -1
  22. data/lib/bcdice/game_system/Arianrhod.rb +6 -8
  23. data/lib/bcdice/game_system/ArsMagica.rb +1 -1
  24. data/lib/bcdice/game_system/Avandner.rb +1 -1
  25. data/lib/bcdice/game_system/BBN.rb +1 -1
  26. data/lib/bcdice/game_system/BadLife.rb +1 -1
  27. data/lib/bcdice/game_system/BarnaKronika.rb +1 -1
  28. data/lib/bcdice/game_system/BattleTech.rb +1 -1
  29. data/lib/bcdice/game_system/BeastBindTrinity.rb +2 -2
  30. data/lib/bcdice/game_system/BeginningIdol.rb +5 -5
  31. data/lib/bcdice/game_system/BeginningIdol_Korean.rb +5 -5
  32. data/lib/bcdice/game_system/BladeOfArcana.rb +1 -1
  33. data/lib/bcdice/game_system/BlindMythos.rb +1 -1
  34. data/lib/bcdice/game_system/BloodCrusade.rb +48 -49
  35. data/lib/bcdice/game_system/BloodMoon.rb +50 -8
  36. data/lib/bcdice/game_system/CardRanker.rb +10 -9
  37. data/lib/bcdice/game_system/ChaosFlare.rb +21 -15
  38. data/lib/bcdice/game_system/Chill.rb +10 -10
  39. data/lib/bcdice/game_system/Chill3.rb +9 -9
  40. data/lib/bcdice/game_system/CodeLayerd.rb +1 -1
  41. data/lib/bcdice/game_system/CrashWorld.rb +1 -1
  42. data/lib/bcdice/game_system/Cthulhu.rb +8 -4
  43. data/lib/bcdice/game_system/Cthulhu7th.rb +86 -342
  44. data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb +2 -2
  45. data/lib/bcdice/game_system/Cthulhu7th_Korean.rb +2 -2
  46. data/lib/bcdice/game_system/CthulhuTech.rb +1 -1
  47. data/lib/bcdice/game_system/Cthulhu_ChineseTraditional.rb +1 -1
  48. data/lib/bcdice/game_system/Cthulhu_Korean.rb +1 -1
  49. data/lib/bcdice/game_system/DarkBlaze.rb +1 -12
  50. data/lib/bcdice/game_system/DarkDaysDrive.rb +8 -7
  51. data/lib/bcdice/game_system/DeadlineHeroes.rb +2 -2
  52. data/lib/bcdice/game_system/DemonParasite.rb +5 -13
  53. data/lib/bcdice/game_system/DesperateRun.rb +1 -1
  54. data/lib/bcdice/game_system/DiceOfTheDead.rb +1 -1
  55. data/lib/bcdice/game_system/DoubleCross.rb +2 -2
  56. data/lib/bcdice/game_system/Dracurouge.rb +1 -1
  57. data/lib/bcdice/game_system/EarthDawn.rb +1 -1
  58. data/lib/bcdice/game_system/EarthDawn3.rb +1 -1
  59. data/lib/bcdice/game_system/EarthDawn4.rb +1 -1
  60. data/lib/bcdice/game_system/EclipsePhase.rb +14 -14
  61. data/lib/bcdice/game_system/Elric.rb +18 -14
  62. data/lib/bcdice/game_system/Elysion.rb +3 -3
  63. data/lib/bcdice/game_system/EmbryoMachine.rb +9 -8
  64. data/lib/bcdice/game_system/Emoklore.rb +3 -3
  65. data/lib/bcdice/game_system/EtrianOdysseySRS.rb +1 -1
  66. data/lib/bcdice/game_system/Fiasco.rb +1 -1
  67. data/lib/bcdice/game_system/FilledWith.rb +205 -1272
  68. data/lib/bcdice/game_system/FullMetalPanic.rb +1 -1
  69. data/lib/bcdice/game_system/GURPS.rb +17 -28
  70. data/lib/bcdice/game_system/Garako.rb +12 -4
  71. data/lib/bcdice/game_system/GardenOrder.rb +1 -1
  72. data/lib/bcdice/game_system/GehennaAn.rb +1 -1
  73. data/lib/bcdice/game_system/GeishaGirlwithKatana.rb +1 -1
  74. data/lib/bcdice/game_system/GoblinSlayer.rb +1 -1
  75. data/lib/bcdice/game_system/Gorilla.rb +3 -9
  76. data/lib/bcdice/game_system/GranCrest.rb +18 -11
  77. data/lib/bcdice/game_system/Gundog.rb +9 -8
  78. data/lib/bcdice/game_system/GundogRevised.rb +10 -9
  79. data/lib/bcdice/game_system/GundogZero.rb +1 -1
  80. data/lib/bcdice/game_system/GurpsFW.rb +16 -16
  81. data/lib/bcdice/game_system/HarnMaster.rb +19 -26
  82. data/lib/bcdice/game_system/HatsuneMiku.rb +1 -1
  83. data/lib/bcdice/game_system/Hieizan.rb +12 -21
  84. data/lib/bcdice/game_system/HouraiGakuen.rb +1 -1
  85. data/lib/bcdice/game_system/HuntersMoon.rb +5 -10
  86. data/lib/bcdice/game_system/Illusio.rb +25 -34
  87. data/lib/bcdice/game_system/InfiniteFantasia.rb +19 -17
  88. data/lib/bcdice/game_system/Insane.rb +13 -20
  89. data/lib/bcdice/game_system/IthaWenUa.rb +8 -15
  90. data/lib/bcdice/game_system/JamesBond.rb +10 -10
  91. data/lib/bcdice/game_system/JekyllAndHyde.rb +1 -1
  92. data/lib/bcdice/game_system/Kamigakari.rb +1 -1
  93. data/lib/bcdice/game_system/KanColle.rb +4 -9
  94. data/lib/bcdice/game_system/KemonoNoMori.rb +1 -1
  95. data/lib/bcdice/game_system/KillDeathBusiness.rb +7 -15
  96. data/lib/bcdice/game_system/KurayamiCrying.rb +55 -2
  97. data/lib/bcdice/game_system/LogHorizon.rb +3 -3
  98. data/lib/bcdice/game_system/LostRoyal.rb +1 -1
  99. data/lib/bcdice/game_system/MeikyuDays.rb +11 -9
  100. data/lib/bcdice/game_system/MeikyuKingdom.rb +28 -28
  101. data/lib/bcdice/game_system/MeikyuKingdomBasic.rb +5 -5
  102. data/lib/bcdice/game_system/MetalHead.rb +12 -22
  103. data/lib/bcdice/game_system/MetalHeadExtream.rb +5 -5
  104. data/lib/bcdice/game_system/MetallicGuardian.rb +1 -1
  105. data/lib/bcdice/game_system/MonotoneMuseum.rb +9 -7
  106. data/lib/bcdice/game_system/Nechronica.rb +28 -21
  107. data/lib/bcdice/game_system/NeverCloud.rb +540 -5
  108. data/lib/bcdice/game_system/NightWizard.rb +1 -1
  109. data/lib/bcdice/game_system/NightWizard3rd.rb +1 -1
  110. data/lib/bcdice/game_system/NinjaSlayer.rb +4 -13
  111. data/lib/bcdice/game_system/NjslyrBattle.rb +8 -11
  112. data/lib/bcdice/game_system/OneWayHeroics.rb +1 -1
  113. data/lib/bcdice/game_system/OracleEngine.rb +1 -1
  114. data/lib/bcdice/game_system/OrgaRain.rb +17 -25
  115. data/lib/bcdice/game_system/Paradiso.rb +3 -3
  116. data/lib/bcdice/game_system/ParanoiaRebooted.rb +1 -1
  117. data/lib/bcdice/game_system/ParasiteBlood.rb +1 -1
  118. data/lib/bcdice/game_system/Peekaboo.rb +4 -9
  119. data/lib/bcdice/game_system/Pendragon.rb +7 -7
  120. data/lib/bcdice/game_system/PhantasmAdventure.rb +8 -8
  121. data/lib/bcdice/game_system/Postman.rb +2 -2
  122. data/lib/bcdice/game_system/PulpCthulhu.rb +1 -1
  123. data/lib/bcdice/game_system/Raisondetre.rb +2 -2
  124. data/lib/bcdice/game_system/RecordOfLodossWar.rb +1 -1
  125. data/lib/bcdice/game_system/RecordOfSteam.rb +1 -1
  126. data/lib/bcdice/game_system/Revulture.rb +123 -0
  127. data/lib/bcdice/game_system/RokumonSekai2.rb +1 -1
  128. data/lib/bcdice/game_system/RuneQuest.rb +8 -8
  129. data/lib/bcdice/game_system/Ryutama.rb +1 -1
  130. data/lib/bcdice/game_system/SRS.rb +1 -1
  131. data/lib/bcdice/game_system/SamsaraBallad.rb +1 -1
  132. data/lib/bcdice/game_system/Satasupe.rb +79 -860
  133. data/lib/bcdice/game_system/ScreamHighSchool.rb +2 -2
  134. data/lib/bcdice/game_system/SevenFortressMobius.rb +1 -1
  135. data/lib/bcdice/game_system/SharedFantasia.rb +20 -24
  136. data/lib/bcdice/game_system/ShinkuuGakuen.rb +2 -2
  137. data/lib/bcdice/game_system/ShinobiGami.rb +17 -9
  138. data/lib/bcdice/game_system/Skynauts.rb +4 -4
  139. data/lib/bcdice/game_system/SkynautsBouken.rb +228 -0
  140. data/lib/bcdice/game_system/SteamPunkers.rb +1 -1
  141. data/lib/bcdice/game_system/StellarKnights.rb +59 -696
  142. data/lib/bcdice/game_system/SterileLife.rb +2 -3
  143. data/lib/bcdice/game_system/StrangerOfSwordCity.rb +2 -2
  144. data/lib/bcdice/game_system/StratoShout.rb +8 -16
  145. data/lib/bcdice/game_system/Strave.rb +1 -1
  146. data/lib/bcdice/game_system/SwordWorld.rb +58 -185
  147. data/lib/bcdice/game_system/SwordWorld2_0.rb +22 -150
  148. data/lib/bcdice/game_system/SwordWorld2_5.rb +127 -41
  149. data/lib/bcdice/game_system/TherapieSein.rb +1 -1
  150. data/lib/bcdice/game_system/TokyoGhostResearch.rb +1 -1
  151. data/lib/bcdice/game_system/Torg.rb +1 -1
  152. data/lib/bcdice/game_system/TorgEternity.rb +2 -2
  153. data/lib/bcdice/game_system/TrinitySeven.rb +4 -4
  154. data/lib/bcdice/game_system/TunnelsAndTrolls.rb +1 -1
  155. data/lib/bcdice/game_system/TwilightGunsmoke.rb +1 -1
  156. data/lib/bcdice/game_system/UnsungDuet.rb +1 -1
  157. data/lib/bcdice/game_system/Utakaze.rb +1 -1
  158. data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +1 -1
  159. data/lib/bcdice/game_system/Villaciel.rb +1 -1
  160. data/lib/bcdice/game_system/WARPS.rb +11 -9
  161. data/lib/bcdice/game_system/WaresBlade.rb +4 -9
  162. data/lib/bcdice/game_system/Warhammer.rb +16 -7
  163. data/lib/bcdice/game_system/Warhammer4.rb +16 -12
  164. data/lib/bcdice/game_system/WitchQuest.rb +1 -1
  165. data/lib/bcdice/game_system/WorldOfDarkness.rb +1 -1
  166. data/lib/bcdice/game_system/YankeeYogSothoth.rb +4 -9
  167. data/lib/bcdice/game_system/YearZeroEngine.rb +1 -1
  168. data/lib/bcdice/game_system/ZettaiReido.rb +1 -1
  169. data/lib/bcdice/game_system/cthulhu7th/full_auto.rb +294 -0
  170. data/lib/bcdice/game_system/cthulhu7th/rollable.rb +41 -0
  171. data/lib/bcdice/game_system/filled_with/enemy_data_tables.rb +322 -0
  172. data/lib/bcdice/game_system/filled_with/event_tables.rb +392 -0
  173. data/lib/bcdice/game_system/filled_with/tresure_tables.rb +179 -0
  174. data/lib/bcdice/game_system/meikyu_kingdom_basic/kingdom_table.rb +1 -1
  175. data/lib/bcdice/game_system/satasupe/tables.rb +723 -0
  176. data/lib/bcdice/game_system/sword_world/rating_lexer.rb +47 -0
  177. data/lib/bcdice/game_system/sword_world/rating_parsed.rb +99 -0
  178. data/lib/bcdice/game_system/sword_world/rating_parser.rb +457 -0
  179. data/lib/bcdice/game_system/sword_world/transcendent_test.rb +122 -0
  180. data/lib/bcdice/repl.rb +1 -1
  181. data/lib/bcdice/result.rb +26 -0
  182. data/lib/bcdice/version.rb +1 -1
  183. metadata +20 -4
@@ -37,8 +37,7 @@ module BCDice
37
37
   ・超未来の宇宙船内 INT
38
38
  MESSAGETEXT
39
39
 
40
- register_prefix('(\d+)*DA.*\[(\d+),(\d+)(,(\d+))?\]', 'VPFT', 'VNFT', 'VNRT', 'AAFT', 'AST', 'RNST', 'RET', 'TRST', 'TRAT', 'TRMT', 'TROT', 'TET', 'ENT', 'CUT', 'NAT', 'INT') # '(\d+)*DA.*\[.*\]'
41
-
40
+ register_prefix('\d*DA', 'VPFT', 'VNFT', 'VNRT', 'AAFT', 'AST', 'RNST', 'RET', 'TRST', 'TRAT', 'TRMT', 'TROT', 'TET', 'ENT', 'CUT', 'NAT', 'INT')
42
41
  def eval_game_system_specific_command(command) # ダイスロールコマンド
43
42
  # 通常判定部分をgetJudgeResultコマンドに切り分け
44
43
  output = getJudgeResult(command)
@@ -104,7 +103,7 @@ module BCDice
104
103
 
105
104
  def getJudgeResult(command)
106
105
  case command
107
- when /(\d+)*DA([\d+*\-]*\d)?\[(\d+),(\d+)(,(\d+))?\]/i
106
+ when /(\d+)?DA([\d+*\-]*\d)?\[(\d+),(\d+)(,(\d+))?\]/i
108
107
  number = (Regexp.last_match(1) || 1).to_i
109
108
  correction = (Regexp.last_match(2) || 0).to_i
110
109
  single = (Regexp.last_match(3) || 4).to_i
@@ -10,7 +10,7 @@ module BCDice
10
10
  NAME = '剣の街の異邦人TRPG'
11
11
 
12
12
  # ゲームシステム名の読みがな
13
- SORT_KEY = 'けんのまちのいほうしんTRPG'
13
+ SORT_KEY = 'つるきのまちのいほうしんTRPG'
14
14
 
15
15
  # ダイスボットの使い方
16
16
  HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
@@ -21,7 +21,7 @@ module BCDice
21
21
  ・D66ダイスあり
22
22
  INFO_MESSAGE_TEXT
23
23
 
24
- register_prefix('\d+SR.*')
24
+ register_prefix('\d+SR')
25
25
 
26
26
  def initialize(command)
27
27
  super(command)
@@ -32,22 +32,14 @@ module BCDice
32
32
  @d66_sort_type = D66SortType::ASC
33
33
  end
34
34
 
35
- def check_2D6(total, dice_total, _dice_list, cmp_op, target)
36
- return '' if target == '?'
37
- return '' unless cmp_op == :>=
38
-
39
- result =
40
- if dice_total <= 2
41
- translate("StratoShout.fumble")
42
- elsif dice_total >= 12
43
- translate("StratoShout.critical")
44
- elsif total >= target
45
- translate("success")
46
- else
47
- translate("failure")
48
- end
49
-
50
- return " > #{result}"
35
+ def result_2d6(_total, dice_total, _dice_list, cmp_op, _target)
36
+ return nil unless cmp_op == :>=
37
+
38
+ if dice_total <= 2
39
+ Result.fumble(translate("StratoShout.fumble"))
40
+ elsif dice_total >= 12
41
+ Result.critical(translate("StratoShout.critical"))
42
+ end
51
43
  end
52
44
 
53
45
  def eval_game_system_specific_command(command)
@@ -33,7 +33,7 @@ module BCDice
33
33
  MESSAGETEXT
34
34
 
35
35
  register_prefix(
36
- 'MP\d+', '\d+ST\d+(x|\*)\d+',
36
+ 'MP', '\d+ST',
37
37
  'AFF', 'IDT', 'AFV', 'IDV'
38
38
  )
39
39
 
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "bcdice/base"
4
+ require "bcdice/game_system/sword_world/rating_parser"
5
+
3
6
  module BCDice
4
7
  module GameSystem
5
8
  class SwordWorld < Base
@@ -7,7 +10,7 @@ module BCDice
7
10
  ID = 'SwordWorld'
8
11
 
9
12
  # ゲームシステム名
10
- NAME = 'ソードワールドRPG'
13
+ NAME = 'ソード・ワールドRPG'
11
14
 
12
15
  # ゲームシステム名の読みがな
13
16
  SORT_KEY = 'そおとわあると'
@@ -15,35 +18,13 @@ module BCDice
15
18
  # ダイスボットの使い方
16
19
  HELP_MESSAGE = "・SW レーティング表 (Kx[c]+m$f) (x:キー, c:クリティカル値, m:ボーナス, f:出目修正)\n"
17
20
 
18
- register_prefix('H?K\d+.*')
21
+ register_prefix('H?K')
19
22
 
20
23
  def initialize(command)
21
24
  super(command)
22
25
  @rating_table = 0
23
26
  end
24
27
 
25
- # change_textで使うレーティング表コマンドの正規表現
26
- #
27
- # SW 2.5のダイスボットでも必要なため、共通化のために定数として定義する
28
- RATING_TABLE_RE_FOR_CHANGE_TEXT = /\AS?H?K\d+/i.freeze
29
-
30
- # コマンド実行前にメッセージを置換する
31
- # @param [String] string 受信したメッセージ
32
- # @return [String]
33
- def replace_text(string)
34
- return string unless RATING_TABLE_RE_FOR_CHANGE_TEXT.match?(string)
35
-
36
- string
37
- .gsub(/\[(\d+)\]/) { "c[#{Regexp.last_match(1)}]" }
38
- .gsub(/@(\d+)/) { "c[#{Regexp.last_match(1)}]" }
39
- .gsub(/\$([-+]?\d+)/) { "m[#{Regexp.last_match(1)}]" }
40
- .gsub(/r([-+]?\d+)/i) { "r[#{Regexp.last_match(1)}]" }
41
- end
42
-
43
- def getRatingCommandStrings
44
- "cmCM"
45
- end
46
-
47
28
  def result_2d6(total, dice_total, _dice_list, cmp_op, target)
48
29
  if dice_total >= 12
49
30
  Result.critical("自動的成功")
@@ -64,60 +45,32 @@ module BCDice
64
45
 
65
46
  private
66
47
 
48
+ def rating_parser
49
+ return RatingParser.new
50
+ end
51
+
67
52
  #################### SWレーティング表 ########################
68
53
  def rating(string) # レーティング表
69
- string = replace_text(string)
70
54
  debug("rating string", string)
55
+ command = rating_parser.parse(string)
71
56
 
72
- commands = getRatingCommandStrings
73
-
74
- m = /^S?(H?K[\d+\-]+([#{commands}]\[([\d+\-]+)\])*([\d+\-]*)([CMR]\[([\d+\-]+)\]|GF|H)*)/i.match(string)
75
- unless m
57
+ unless command
76
58
  debug("not matched")
77
59
  return '1'
78
60
  end
79
61
 
80
- string = m[1]
81
- half = string.include?("H")
82
-
83
- rateUp, string = getRateUpFromString(string)
84
- crit, string = getCriticalFromString(string, half)
85
- firstDiceChanteTo, firstDiceChangeModify, string = getDiceChangesFromString(string)
86
-
87
- key, addValue = getKeyAndAddValueFromString(string)
88
-
89
- return '1' unless key =~ /(\d+)/
90
-
91
- key = Regexp.last_match(1).to_i
92
-
93
62
  # 2.0対応
94
63
  rate_sw2_0 = getSW2_0_RatingTable
95
64
 
96
65
  keyMax = rate_sw2_0.length - 1
97
66
  debug("keyMax", keyMax)
98
- if key > keyMax
67
+ if command.rate > keyMax
99
68
  return "キーナンバーは#{keyMax}までです"
100
69
  end
101
70
 
102
71
  newRates = getNewRates(rate_sw2_0)
103
72
 
104
- output = "KeyNo.#{key}"
105
-
106
- output += "c[#{crit}]" if crit < 13
107
- output += "m[#{firstDiceChangeModify}]" if firstDiceChangeModify != 0
108
- output += "m[#{firstDiceChanteTo}]" if firstDiceChanteTo != 0
109
- output += "r[#{rateUp}]" if rateUp != 0
110
-
111
- output, values = getAdditionalString(string, output)
112
-
113
- debug('output', output)
114
-
115
- if addValue != 0
116
- output += "+#{addValue}" if addValue > 0
117
- output += addValue.to_s if addValue < 0
118
- end
119
-
120
- output += " > "
73
+ output = "#{command}"
121
74
 
122
75
  diceResultTotals = []
123
76
  diceResults = []
@@ -126,17 +79,19 @@ module BCDice
126
79
  diceOnlyTotal = 0
127
80
  totalValue = 0
128
81
  round = 0
82
+ first_to = command.first_to
83
+ first_modify = command.first_modify
129
84
 
130
85
  loop do
131
- dice_raw, diceText = rollDice(values)
86
+ dice_raw, diceText = rollDice(command)
132
87
  dice = dice_raw
133
88
 
134
- if firstDiceChanteTo != 0
135
- dice = dice_raw = firstDiceChanteTo
136
- firstDiceChanteTo = 0
137
- elsif firstDiceChangeModify != 0
138
- dice += firstDiceChangeModify.to_i
139
- firstDiceChangeModify = 0
89
+ if first_to != 0
90
+ dice = dice_raw = first_to
91
+ first_to = 0
92
+ elsif first_modify != 0
93
+ dice += first_modify
94
+ first_modify = 0
140
95
  end
141
96
 
142
97
  # 出目がピンゾロの時にはそこで終了
@@ -149,12 +104,12 @@ module BCDice
149
104
  break
150
105
  end
151
106
 
152
- dice += getAdditionalDiceValue(dice, values)
107
+ dice += command.kept_modify if (command.kept_modify != 0) && (dice != 2)
153
108
 
154
109
  dice = 2 if dice < 2
155
110
  dice = 12 if dice > 12
156
111
 
157
- currentKey = [key + round * rateUp, keyMax].min
112
+ currentKey = [command.rate + round * command.rateup, keyMax].min
158
113
  debug("currentKey", currentKey)
159
114
  rateValue = newRates[dice][currentKey]
160
115
  debug("rateValue", rateValue)
@@ -168,77 +123,20 @@ module BCDice
168
123
 
169
124
  round += 1
170
125
 
171
- break unless dice >= crit
126
+ break unless dice >= command.critical
172
127
  end
173
128
 
174
- output += getResultText(totalValue, addValue, diceResults, diceResultTotals,
175
- rateResults, diceOnlyTotal, round, half)
176
-
177
- return output
178
- end
179
-
180
- def getAdditionalString(_string, output)
181
- values = {}
182
- return output, values
183
- end
184
-
185
- def getAdditionalDiceValue(_dice, _values)
186
- 0
187
- end
188
-
189
- def getCriticalFromString(string, half)
190
- crit = half ? 13 : 10
129
+ result_text, critical, fumble = getResultText(
130
+ totalValue, command, diceResults, diceResultTotals,
131
+ rateResults, diceOnlyTotal, round
132
+ )
133
+ output += result_text
191
134
 
192
- regexp = /c\[(\d+)\]/i
193
-
194
- if regexp =~ string
195
- crit = Regexp.last_match(1).to_i
196
- crit = 3 if crit < 3 # エラートラップ(クリティカル値が3未満なら3とする)
197
- string = string.gsub(regexp, '')
135
+ return Result.new.tap do |r|
136
+ r.text = output
137
+ r.critical = critical
138
+ r.fumble = fumble
198
139
  end
199
-
200
- return crit, string
201
- end
202
-
203
- def getDiceChangesFromString(string)
204
- firstDiceChanteTo = 0
205
- firstDiceChangeModify = 0
206
-
207
- regexp = /m\[([\d+\-]+)\]/i
208
-
209
- if regexp =~ string
210
- firstDiceChangeModify = Regexp.last_match(1)
211
-
212
- unless /[+\-]/ =~ firstDiceChangeModify
213
- firstDiceChanteTo = firstDiceChangeModify.to_i
214
- firstDiceChangeModify = 0
215
- end
216
-
217
- string = string.gsub(regexp, '')
218
- end
219
-
220
- return firstDiceChanteTo, firstDiceChangeModify, string
221
- end
222
-
223
- def getRateUpFromString(string)
224
- rateUp = 0
225
- return rateUp, string
226
- end
227
-
228
- def getKeyAndAddValueFromString(string)
229
- key = nil
230
- addValue = 0
231
-
232
- if /K(\d+)([\d+\-]*)/i =~ string # ボーナスの抽出
233
- key = Regexp.last_match(1)
234
- if Regexp.last_match(2)
235
- addValue = ArithmeticEvaluator.eval(Regexp.last_match(2))
236
- end
237
- else
238
- key = string
239
- end
240
-
241
- return key, addValue
242
140
  end
243
141
 
244
142
  def getSW2_0_RatingTable
@@ -397,7 +295,7 @@ module BCDice
397
295
  return newRates
398
296
  end
399
297
 
400
- def rollDice(_values)
298
+ def rollDice(_command)
401
299
  dice_list = @randomizer.roll_barabara(2, 6)
402
300
  total = dice_list.sum()
403
301
  dice_str = dice_list.join(",")
@@ -405,15 +303,15 @@ module BCDice
405
303
  end
406
304
 
407
305
  # @param rating_total [Integer]
408
- # @param modifier [Integer]
306
+ # @param command [SwordWorld::RatingParsed]
409
307
  # @param diceResults [Array<String>]
410
308
  # @param diceResultTotals [Array<String>]
411
309
  # @param rateResults [Array<String>]
412
310
  # @param dice_total [Integer]
413
311
  # @param round [Integer]
414
- # @param half [Boolean]
415
- def getResultText(rating_total, modifier, diceResults, diceResultTotals,
416
- rateResults, dice_total, round, half)
312
+ # @return [Array(String, Boolean, Boolean)] output, critical, fumble
313
+ def getResultText(rating_total, command, diceResults, diceResultTotals,
314
+ rateResults, dice_total, round)
417
315
  sequence = []
418
316
 
419
317
  sequence.push("2D:[#{diceResults.join(' ')}]=#{diceResultTotals.join(',')}")
@@ -421,18 +319,25 @@ module BCDice
421
319
  if dice_total <= 2
422
320
  sequence.push(rateResults.join(','))
423
321
  sequence.push("自動的失敗")
424
- return sequence.join(" > ")
322
+ return sequence.join(" > "), false, true
425
323
  end
426
324
 
427
325
  # rate回数が1回で、修正値がない時には途中式と最終結果が一致するので、途中式を省略する
428
- if rateResults.size > 1 || modifier != 0
429
- text = rateResults.join(',') + Format.modifier(modifier)
430
- if half
326
+ if rateResults.size > 1 || command.modifier != 0
327
+ text = rateResults.join(',') + Format.modifier(command.modifier)
328
+ if command.half
431
329
  text = "(#{text})/2"
330
+ if command.modifier_after_half != 0
331
+ text += Format.modifier(command.modifier_after_half)
332
+ end
333
+ end
334
+ sequence.push(text)
335
+ elsif command.half
336
+ text = "#{rateResults.first}/2"
337
+ if command.modifier_after_half != 0
338
+ text += Format.modifier(command.modifier_after_half)
432
339
  end
433
340
  sequence.push(text)
434
- elsif half
435
- sequence.push("#{rateResults.first}/2")
436
341
  end
437
342
 
438
343
  if round > 1
@@ -440,50 +345,18 @@ module BCDice
440
345
  sequence.push(round_text)
441
346
  end
442
347
 
443
- total = rating_total + modifier
444
- if half
348
+ total = rating_total + command.modifier
349
+ if command.half
445
350
  total = (total / 2.0).ceil
351
+ if command.modifier_after_half != 0
352
+ total += command.modifier_after_half
353
+ end
446
354
  end
447
355
 
448
356
  total_text = total.to_s
449
357
  sequence.push(total_text)
450
358
 
451
- return sequence.join(" > ")
452
- end
453
-
454
- def setRatingTable(tnick)
455
- mode_str = ""
456
- pre_mode = @rating_table
457
-
458
- if /(\d+)/ =~ tnick
459
- @rating_table = Regexp.last_match(1).to_i
460
- if @rating_table > 1
461
- mode_str = "2.0-mode"
462
- @rating_table = 2
463
- elsif @rating_table > 0
464
- mode_str = "new-mode"
465
- @rating_table = 1
466
- else
467
- mode_str = "old-mode"
468
- @rating_table = 0
469
- end
470
- else
471
- case tnick
472
- when /old/i
473
- @rating_table = 0
474
- mode_str = "old-mode"
475
- when /new/i
476
- @rating_table = 1
477
- mode_str = "new-mode"
478
- when /2\.0/i
479
- @rating_table = 2
480
- mode_str = "2.0-mode"
481
- end
482
- end
483
-
484
- return '1' if @rating_table == pre_mode
485
-
486
- return "RatingTableを#{mode_str}に変更しました"
359
+ return sequence.join(" > "), round > 1, false
487
360
  end
488
361
  end
489
362
  end
@@ -3,6 +3,7 @@
3
3
  require 'bcdice/arithmetic_evaluator'
4
4
 
5
5
  require 'bcdice/game_system/SwordWorld'
6
+ require 'bcdice/game_system/sword_world/transcendent_test'
6
7
 
7
8
  module BCDice
8
9
  module GameSystem
@@ -11,7 +12,7 @@ module BCDice
11
12
  ID = 'SwordWorld2.0'
12
13
 
13
14
  # ゲームシステム名
14
- NAME = 'ソードワールド2.0'
15
+ NAME = 'ソード・ワールド2.0'
15
16
 
16
17
  # ゲームシステム名の読みがな
17
18
  SORT_KEY = 'そおとわあると2.0'
@@ -34,10 +35,12 @@ module BCDice
34
35
   またタイプの軽減化のために末尾に「@クリティカル値」でも処理するようにしました。
35
36
   例)K20[10]   K10+5[9]   k30[10]   k10[9]+10   k10-5@9
36
37
 
37
- ・レーティング表の半減 (HKx)
38
+ ・レーティング表の半減 (HKx, KxH+N)
38
39
   レーティング表の先頭または末尾に"H"をつけると、レーティング表を振って最終結果を半減させます。
40
+  末尾につけた場合、直後に修正ををつけることで、半減後の加減算を行うことができます。
41
+  この際、複数の項による修正にはカッコで囲うことが必要です(カッコがないとパースに失敗します)
39
42
   クリティカル値を指定しない場合、クリティカルなしと扱われます。
40
-  例)HK20  K20h  HK10-5@9  K10-5@9H  K20gfH
43
+  例)HK20  K20h  HK10-5@9  K10-5@9H  K20gfH  K20+8H+2  K20+8H(1+1)
41
44
 
42
45
  ・ダイス目の修正(運命変転やクリティカルレイ用)
43
46
   末尾に「$修正値」でダイス目に修正がかかります。
@@ -65,115 +68,13 @@ module BCDice
65
68
   絡み効果表を出すことができます。
66
69
  INFO_MESSAGE_TEXT
67
70
 
68
- register_prefix('H?K\d+.*', 'Gr(\d+)?', '2D6?@\d+.*', 'FT', 'TT')
69
-
70
- # 超越判定のノード
71
- class TranscendentTest
72
- # @param [Integer] critical_value クリティカル値
73
- # @param [Integer] modifier 修正値
74
- # @param [String, nil] cmp_op 比較演算子(> または >=)
75
- # @param [Integer, nil] target 目標値
76
- def initialize(critical_value, modifier, cmp_op, target)
77
- @critical_value = critical_value
78
- @modifier = modifier
79
- @cmp_op = cmp_op
80
- @target = target
81
-
82
- @modifier_str = Format.modifier(@modifier)
83
- @expression = node_expression()
84
- end
85
-
86
- # 超越判定を行う
87
- # @param randomizer [Randomizer]
88
- # @return [String]
89
- def execute(randomizer)
90
- if @critical_value < 3
91
- return "(#{@expression}) > クリティカル値が小さすぎます。3以上を指定してください。"
92
- end
93
-
94
- first_value_group = randomizer.roll_barabara(2, 6)
95
- value_groups = [first_value_group]
96
-
97
- fumble = first_value_group == [1, 1]
98
- critical = first_value_group == [6, 6]
99
-
100
- if !fumble && !critical
101
- while sum_of_dice(value_groups.last) >= @critical_value
102
- value_groups.push(randomizer.roll_barabara(2, 6))
103
- end
104
- end
105
-
106
- sum = sum_of_dice(value_groups)
107
- total_sum = sum + @modifier
108
-
109
- parts = [
110
- "(#{@expression})",
111
- "#{dice_str(value_groups, sum)}#{@modifier_str}",
112
- total_sum,
113
- @target && result_str(total_sum, value_groups.length, fumble, critical)
114
- ].compact
115
-
116
- return parts.join(' > ')
117
- end
118
-
119
- private
120
-
121
- # 数式表記を返す
122
- # @return [String]
123
- def node_expression
124
- lhs = "2D6@#{@critical_value}#{@modifier_str}"
125
-
126
- return @target ? "#{lhs}#{@cmp_op}#{@target}" : lhs
127
- end
128
-
129
- # 出目の合計を返す
130
- # @param [(Integer, Integer), Array<(Integer, Integer)>] value_groups
131
- # 出目のグループまたはその配列
132
- # @return [Integer]
133
- def sum_of_dice(value_groups)
134
- value_groups.flatten.sum
135
- end
136
-
137
- # ダイス部分の文字列を返す
138
- # @param [Array<(Integer, Integer)>] value_groups 出目のグループの配列
139
- # @param [Integer] sum 出目の合計
140
- # @return [String]
141
- def dice_str(value_groups, sum)
142
- value_groups_str =
143
- value_groups
144
- .map { |values| "[#{values.join(',')}]" }
145
- .join
146
-
147
- return "#{sum}#{value_groups_str}"
148
- end
149
-
150
- # 判定結果の文字列を返す
151
- # @param [Integer] total_sum 合計値
152
- # @param [Integer] n_value_groups 出目のグループの数
153
- # @param [Boolean] fumble ファンブルかどうか
154
- # @param [Boolean] critical クリティカルかどうか
155
- # @return [String]
156
- def result_str(total_sum, n_value_groups, fumble, critical)
157
- return '自動的失敗' if fumble
158
- return '自動的成功' if critical
159
-
160
- if total_sum.send(@cmp_op, @target)
161
- # 振り足しが行われ、合計値が41以上ならば「超成功」
162
- n_value_groups >= 2 && total_sum >= 41 ? '超成功' : '成功'
163
- else
164
- '失敗'
165
- end
166
- end
167
- end
71
+ register_prefix('H?K', 'Gr', '2D6?@\d+', 'FT', 'TT')
168
72
 
169
73
  def initialize(command)
170
74
  super(command)
171
75
  @rating_table = 2
172
76
  end
173
77
 
174
- # 超越判定のパターン
175
- TRANSCENDENT_TEST_RE = /\A2D6?@(\d+)([-+\d]+)?(?:(>=?)(\d+))?/.freeze
176
-
177
78
  def eval_game_system_specific_command(command)
178
79
  case command
179
80
  when /^Gr(\d+)?/i
@@ -182,15 +83,17 @@ module BCDice
182
83
  else
183
84
  growth
184
85
  end
185
- when TRANSCENDENT_TEST_RE
186
- m = Regexp.last_match
187
-
188
- critical_value = m[1].to_i
189
- modifier = m[2] ? ArithmeticEvaluator.eval(m[2]) : 0
190
- cmp_op = m[3]
191
- target = m[3] && m[4].to_i
86
+ when /^2D6?@\d+/i
87
+ transcendent_parser = Command::Parser.new(/2D6?/i, round_type: BCDice::RoundType::CEIL)
88
+ .enable_critical
89
+ .restrict_cmp_op_to(nil, :>=, :>)
90
+ cmd = transcendent_parser.parse(command)
91
+
92
+ unless cmd
93
+ return nil
94
+ end
192
95
 
193
- node = TranscendentTest.new(critical_value, modifier, cmp_op, target)
96
+ node = TranscendentTest.new(cmd.critical, cmd.modify_number, cmd.cmp_op, cmd.target_number)
194
97
  node.execute(@randomizer)
195
98
  when 'FT'
196
99
  get_fumble_table
@@ -201,32 +104,13 @@ module BCDice
201
104
  end
202
105
  end
203
106
 
204
- def getRateUpFromString(string)
205
- rateUp = 0
206
-
207
- regexp = /r\[(\d+)\]/i
208
- if (m = regexp.match(string))
209
- rateUp = m[1].to_i
210
- string = string.gsub(regexp, '')
211
- end
212
-
213
- return rateUp, string
214
- end
215
-
216
- def getAdditionalString(string, output)
217
- output, values = super(string, output)
218
-
219
- isGratestFortune, = getGratestFortuneFromString(string)
220
-
221
- values['isGratestFortune'] = isGratestFortune
222
- output += "gf" if isGratestFortune
223
-
224
- return output, values
107
+ def rating_parser
108
+ return RatingParser.new(version: :v2_0)
225
109
  end
226
110
 
227
- def rollDice(values)
228
- unless values['isGratestFortune']
229
- return super(values)
111
+ def rollDice(command)
112
+ unless command.greatest_fortune
113
+ return super(command)
230
114
  end
231
115
 
232
116
  dice = @randomizer.roll_once(6)
@@ -234,18 +118,6 @@ module BCDice
234
118
  return dice * 2, "#{dice},#{dice}"
235
119
  end
236
120
 
237
- def getGratestFortuneFromString(string)
238
- isGratestFortune = false
239
-
240
- regexp = /gf/i
241
- if regexp.match?(string)
242
- isGratestFortune = true
243
- string = string.gsub(regexp, '')
244
- end
245
-
246
- return isGratestFortune, string
247
- end
248
-
249
121
  def growth(count = 1)
250
122
  ((1..count).map { growth_step }).join " | "
251
123
  end