bcdice 3.0.0.pre.alpha.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 (258) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +21 -0
  3. data/.github/.codecov.yaml +10 -0
  4. data/.github/workflows/coverage.yaml +21 -0
  5. data/.github/workflows/lint.yaml +13 -0
  6. data/.github/workflows/test.yml +20 -0
  7. data/.gitignore +14 -0
  8. data/.rubocop.yml +96 -0
  9. data/.rubocop_todo.yml +113 -0
  10. data/CHANGELOG.md +868 -0
  11. data/Gemfile +11 -0
  12. data/LICENSE +29 -0
  13. data/README.md +38 -0
  14. data/ROADMAP.md +30 -0
  15. data/Rakefile +118 -0
  16. data/bcdice.gemspec +27 -0
  17. data/bin/repl.rb +21 -0
  18. data/docs/README.txt +2028 -0
  19. data/docs/dicebot_sort_key.md +72 -0
  20. data/docs/how_to_make_dicebot.md +453 -0
  21. data/lib/bcdice.rb +8 -0
  22. data/lib/bcdice/arithmetic_evaluator.rb +167 -0
  23. data/lib/bcdice/base.rb +423 -0
  24. data/lib/bcdice/command_parser.rb +242 -0
  25. data/lib/bcdice/common_command.rb +23 -0
  26. data/lib/bcdice/common_command/add_dice.rb +54 -0
  27. data/lib/bcdice/common_command/add_dice/node.rb +488 -0
  28. data/lib/bcdice/common_command/add_dice/parser.rb +282 -0
  29. data/lib/bcdice/common_command/add_dice/randomizer.rb +48 -0
  30. data/lib/bcdice/common_command/barabara_dice.rb +57 -0
  31. data/lib/bcdice/common_command/calc.rb +39 -0
  32. data/lib/bcdice/common_command/choice.rb +35 -0
  33. data/lib/bcdice/common_command/d66_dice.rb +63 -0
  34. data/lib/bcdice/common_command/reroll_dice.rb +190 -0
  35. data/lib/bcdice/common_command/upper_dice.rb +165 -0
  36. data/lib/bcdice/common_command/version.rb +26 -0
  37. data/lib/bcdice/dice_table.rb +8 -0
  38. data/lib/bcdice/dice_table/chain_table.rb +33 -0
  39. data/lib/bcdice/dice_table/d66_grid_table.rb +26 -0
  40. data/lib/bcdice/dice_table/d66_range_table.rb +26 -0
  41. data/lib/bcdice/dice_table/d66_table.rb +34 -0
  42. data/lib/bcdice/dice_table/range_table.rb +267 -0
  43. data/lib/bcdice/dice_table/roll_result.rb +43 -0
  44. data/lib/bcdice/dice_table/sai_fic_skill_table.rb +32 -0
  45. data/lib/bcdice/dice_table/table.rb +35 -0
  46. data/lib/bcdice/enum.rb +15 -0
  47. data/lib/bcdice/format.rb +36 -0
  48. data/lib/bcdice/game_system.rb +187 -0
  49. data/lib/bcdice/game_system/AFF2e.rb +141 -0
  50. data/lib/bcdice/game_system/AceKillerGene.rb +55 -0
  51. data/lib/bcdice/game_system/Airgetlamh.rb +117 -0
  52. data/lib/bcdice/game_system/Alsetto.rb +124 -0
  53. data/lib/bcdice/game_system/Alshard.rb +27 -0
  54. data/lib/bcdice/game_system/AlterRaise.rb +282 -0
  55. data/lib/bcdice/game_system/Amadeus.rb +622 -0
  56. data/lib/bcdice/game_system/Amadeus_Korean.rb +501 -0
  57. data/lib/bcdice/game_system/AnimaAnimus.rb +96 -0
  58. data/lib/bcdice/game_system/Arianrhod.rb +50 -0
  59. data/lib/bcdice/game_system/ArsMagica.rb +149 -0
  60. data/lib/bcdice/game_system/Avandner.rb +101 -0
  61. data/lib/bcdice/game_system/BBN.rb +143 -0
  62. data/lib/bcdice/game_system/BadLife.rb +435 -0
  63. data/lib/bcdice/game_system/BarnaKronika.rb +188 -0
  64. data/lib/bcdice/game_system/BattleTech.rb +530 -0
  65. data/lib/bcdice/game_system/BeastBindTrinity.rb +348 -0
  66. data/lib/bcdice/game_system/BeginningIdol.rb +2527 -0
  67. data/lib/bcdice/game_system/BeginningIdol_Korean.rb +2378 -0
  68. data/lib/bcdice/game_system/BladeOfArcana.rb +252 -0
  69. data/lib/bcdice/game_system/BlindMythos.rb +460 -0
  70. data/lib/bcdice/game_system/BloodCrusade.rb +423 -0
  71. data/lib/bcdice/game_system/BloodMoon.rb +213 -0
  72. data/lib/bcdice/game_system/CardRanker.rb +249 -0
  73. data/lib/bcdice/game_system/ChaosFlare.rb +181 -0
  74. data/lib/bcdice/game_system/Chill.rb +163 -0
  75. data/lib/bcdice/game_system/Chill3.rb +52 -0
  76. data/lib/bcdice/game_system/CodeLayerd.rb +132 -0
  77. data/lib/bcdice/game_system/ColossalHunter.rb +569 -0
  78. data/lib/bcdice/game_system/CrashWorld.rb +81 -0
  79. data/lib/bcdice/game_system/Cthulhu.rb +252 -0
  80. data/lib/bcdice/game_system/Cthulhu7th.rb +767 -0
  81. data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb +386 -0
  82. data/lib/bcdice/game_system/Cthulhu7th_Korean.rb +383 -0
  83. data/lib/bcdice/game_system/CthulhuTech.rb +263 -0
  84. data/lib/bcdice/game_system/Cthulhu_ChineseTraditional.rb +243 -0
  85. data/lib/bcdice/game_system/Cthulhu_Korean.rb +240 -0
  86. data/lib/bcdice/game_system/DarkBlaze.rb +207 -0
  87. data/lib/bcdice/game_system/DarkDaysDrive.rb +425 -0
  88. data/lib/bcdice/game_system/DarkSouls.rb +91 -0
  89. data/lib/bcdice/game_system/DeadlineHeroes.rb +583 -0
  90. data/lib/bcdice/game_system/DemonParasite.rb +524 -0
  91. data/lib/bcdice/game_system/DetatokoSaga.rb +310 -0
  92. data/lib/bcdice/game_system/DetatokoSaga_Korean.rb +310 -0
  93. data/lib/bcdice/game_system/DiceBot.rb +17 -0
  94. data/lib/bcdice/game_system/DiceOfTheDead.rb +111 -0
  95. data/lib/bcdice/game_system/DoubleCross.rb +373 -0
  96. data/lib/bcdice/game_system/DoubleCross_Korean.rb +371 -0
  97. data/lib/bcdice/game_system/Dracurouge.rb +1856 -0
  98. data/lib/bcdice/game_system/Dracurouge_Korean.rb +310 -0
  99. data/lib/bcdice/game_system/DungeonsAndDragons.rb +19 -0
  100. data/lib/bcdice/game_system/EarthDawn.rb +225 -0
  101. data/lib/bcdice/game_system/EarthDawn3.rb +275 -0
  102. data/lib/bcdice/game_system/EarthDawn4.rb +272 -0
  103. data/lib/bcdice/game_system/EclipsePhase.rb +51 -0
  104. data/lib/bcdice/game_system/Elric.rb +36 -0
  105. data/lib/bcdice/game_system/Elysion.rb +1213 -0
  106. data/lib/bcdice/game_system/EmbryoMachine.rb +227 -0
  107. data/lib/bcdice/game_system/EndBreaker.rb +132 -0
  108. data/lib/bcdice/game_system/EtrianOdysseySRS.rb +27 -0
  109. data/lib/bcdice/game_system/Fiasco.rb +123 -0
  110. data/lib/bcdice/game_system/Fiasco_Korean.rb +122 -0
  111. data/lib/bcdice/game_system/FilledWith.rb +1543 -0
  112. data/lib/bcdice/game_system/FullMetalPanic.rb +27 -0
  113. data/lib/bcdice/game_system/FutariSousa.rb +994 -0
  114. data/lib/bcdice/game_system/FutariSousa_Korean.rb +994 -0
  115. data/lib/bcdice/game_system/Garako.rb +559 -0
  116. data/lib/bcdice/game_system/GardenOrder.rb +451 -0
  117. data/lib/bcdice/game_system/GehennaAn.rb +136 -0
  118. data/lib/bcdice/game_system/GeishaGirlwithKatana.rb +120 -0
  119. data/lib/bcdice/game_system/GoblinSlayer.rb +168 -0
  120. data/lib/bcdice/game_system/GoldenSkyStories.rb +77 -0
  121. data/lib/bcdice/game_system/Gorilla.rb +44 -0
  122. data/lib/bcdice/game_system/GranCrest.rb +518 -0
  123. data/lib/bcdice/game_system/Gundog.rb +52 -0
  124. data/lib/bcdice/game_system/GundogRevised.rb +294 -0
  125. data/lib/bcdice/game_system/GundogZero.rb +261 -0
  126. data/lib/bcdice/game_system/Gurps.rb +403 -0
  127. data/lib/bcdice/game_system/GurpsFW.rb +2330 -0
  128. data/lib/bcdice/game_system/HarnMaster.rb +208 -0
  129. data/lib/bcdice/game_system/HatsuneMiku.rb +706 -0
  130. data/lib/bcdice/game_system/Hieizan.rb +48 -0
  131. data/lib/bcdice/game_system/HouraiGakuen.rb +270 -0
  132. data/lib/bcdice/game_system/HuntersMoon.rb +503 -0
  133. data/lib/bcdice/game_system/Illusio.rb +89 -0
  134. data/lib/bcdice/game_system/InfiniteFantasia.rb +51 -0
  135. data/lib/bcdice/game_system/Insane.rb +822 -0
  136. data/lib/bcdice/game_system/Insane_Korean.rb +773 -0
  137. data/lib/bcdice/game_system/IthaWenUa.rb +38 -0
  138. data/lib/bcdice/game_system/JamesBond.rb +45 -0
  139. data/lib/bcdice/game_system/Kamigakari.rb +394 -0
  140. data/lib/bcdice/game_system/Kamigakari_Korean.rb +428 -0
  141. data/lib/bcdice/game_system/KanColle.rb +938 -0
  142. data/lib/bcdice/game_system/KemonoNoMori.rb +258 -0
  143. data/lib/bcdice/game_system/KillDeathBusiness.rb +1420 -0
  144. data/lib/bcdice/game_system/KillDeathBusiness_Korean.rb +1510 -0
  145. data/lib/bcdice/game_system/KurayamiCrying.rb +49 -0
  146. data/lib/bcdice/game_system/LiveraDoll.rb +375 -0
  147. data/lib/bcdice/game_system/LogHorizon.rb +3567 -0
  148. data/lib/bcdice/game_system/LogHorizon_Korean.rb +1407 -0
  149. data/lib/bcdice/game_system/LostRecord.rb +30 -0
  150. data/lib/bcdice/game_system/LostRoyal.rb +242 -0
  151. data/lib/bcdice/game_system/MagicaLogia.rb +1148 -0
  152. data/lib/bcdice/game_system/MeikyuDays.rb +415 -0
  153. data/lib/bcdice/game_system/MeikyuKingdom.rb +466 -0
  154. data/lib/bcdice/game_system/MeikyuKingdomBasic.rb +269 -0
  155. data/lib/bcdice/game_system/MetalHead.rb +249 -0
  156. data/lib/bcdice/game_system/MetalHeadExtream.rb +917 -0
  157. data/lib/bcdice/game_system/MetallicGuardian.rb +31 -0
  158. data/lib/bcdice/game_system/MonotoneMuseum.rb +354 -0
  159. data/lib/bcdice/game_system/MonotoneMuseum_Korean.rb +304 -0
  160. data/lib/bcdice/game_system/Nechronica.rb +211 -0
  161. data/lib/bcdice/game_system/Nechronica_Korean.rb +160 -0
  162. data/lib/bcdice/game_system/NeverCloud.rb +74 -0
  163. data/lib/bcdice/game_system/NightWizard.rb +231 -0
  164. data/lib/bcdice/game_system/NightWizard3rd.rb +24 -0
  165. data/lib/bcdice/game_system/NightmareHunterDeep.rb +117 -0
  166. data/lib/bcdice/game_system/NinjaSlayer.rb +274 -0
  167. data/lib/bcdice/game_system/NjslyrBattle.rb +54 -0
  168. data/lib/bcdice/game_system/Nuekagami.rb +293 -0
  169. data/lib/bcdice/game_system/OneWayHeroics.rb +134 -0
  170. data/lib/bcdice/game_system/OracleEngine.rb +265 -0
  171. data/lib/bcdice/game_system/OrgaRain.rb +77 -0
  172. data/lib/bcdice/game_system/Oukahoushin3rd.rb +162 -0
  173. data/lib/bcdice/game_system/Paradiso.rb +323 -0
  174. data/lib/bcdice/game_system/Paranoia.rb +64 -0
  175. data/lib/bcdice/game_system/ParanoiaRebooted.rb +109 -0
  176. data/lib/bcdice/game_system/ParasiteBlood.rb +231 -0
  177. data/lib/bcdice/game_system/Pathfinder.rb +21 -0
  178. data/lib/bcdice/game_system/Peekaboo.rb +324 -0
  179. data/lib/bcdice/game_system/Pendragon.rb +39 -0
  180. data/lib/bcdice/game_system/PhantasmAdventure.rb +73 -0
  181. data/lib/bcdice/game_system/Postman.rb +185 -0
  182. data/lib/bcdice/game_system/PulpCthulhu.rb +184 -0
  183. data/lib/bcdice/game_system/Raisondetre.rb +171 -0
  184. data/lib/bcdice/game_system/RecordOfLodossWar.rb +58 -0
  185. data/lib/bcdice/game_system/RecordOfSteam.rb +149 -0
  186. data/lib/bcdice/game_system/RokumonSekai2.rb +110 -0
  187. data/lib/bcdice/game_system/RoleMaster.rb +24 -0
  188. data/lib/bcdice/game_system/RuneQuest.rb +47 -0
  189. data/lib/bcdice/game_system/RyuTuber.rb +266 -0
  190. data/lib/bcdice/game_system/Ryutama.rb +199 -0
  191. data/lib/bcdice/game_system/SRS.rb +348 -0
  192. data/lib/bcdice/game_system/SamsaraBallad.rb +111 -0
  193. data/lib/bcdice/game_system/Satasupe.rb +1173 -0
  194. data/lib/bcdice/game_system/ScreamHighSchool.rb +128 -0
  195. data/lib/bcdice/game_system/SevenFortressMobius.rb +34 -0
  196. data/lib/bcdice/game_system/ShadowRun.rb +26 -0
  197. data/lib/bcdice/game_system/ShadowRun4.rb +49 -0
  198. data/lib/bcdice/game_system/ShadowRun5.rb +80 -0
  199. data/lib/bcdice/game_system/SharedFantasia.rb +69 -0
  200. data/lib/bcdice/game_system/ShinMegamiTenseiKakuseihen.rb +85 -0
  201. data/lib/bcdice/game_system/ShinkuuGakuen.rb +506 -0
  202. data/lib/bcdice/game_system/ShinobiGami.rb +680 -0
  203. data/lib/bcdice/game_system/ShoujoTenrankai.rb +677 -0
  204. data/lib/bcdice/game_system/Skynauts.rb +324 -0
  205. data/lib/bcdice/game_system/SteamPunkers.rb +485 -0
  206. data/lib/bcdice/game_system/StellarKnights.rb +856 -0
  207. data/lib/bcdice/game_system/SterileLife.rb +452 -0
  208. data/lib/bcdice/game_system/StrangerOfSwordCity.rb +103 -0
  209. data/lib/bcdice/game_system/StratoShout.rb +316 -0
  210. data/lib/bcdice/game_system/StratoShout_Korean.rb +314 -0
  211. data/lib/bcdice/game_system/Strave.rb +223 -0
  212. data/lib/bcdice/game_system/SwordWorld.rb +491 -0
  213. data/lib/bcdice/game_system/SwordWorld2_0.rb +295 -0
  214. data/lib/bcdice/game_system/SwordWorld2_5.rb +121 -0
  215. data/lib/bcdice/game_system/TherapieSein.rb +93 -0
  216. data/lib/bcdice/game_system/TokumeiTenkousei.rb +96 -0
  217. data/lib/bcdice/game_system/TokyoGhostResearch.rb +122 -0
  218. data/lib/bcdice/game_system/TokyoNova.rb +19 -0
  219. data/lib/bcdice/game_system/Torg.rb +364 -0
  220. data/lib/bcdice/game_system/Torg1_5.rb +139 -0
  221. data/lib/bcdice/game_system/TorgEternity.rb +414 -0
  222. data/lib/bcdice/game_system/TrinitySeven.rb +364 -0
  223. data/lib/bcdice/game_system/TunnelsAndTrolls.rb +287 -0
  224. data/lib/bcdice/game_system/TwilightGunsmoke.rb +527 -0
  225. data/lib/bcdice/game_system/Utakaze.rb +153 -0
  226. data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +132 -0
  227. data/lib/bcdice/game_system/Villaciel.rb +555 -0
  228. data/lib/bcdice/game_system/WARPS.rb +33 -0
  229. data/lib/bcdice/game_system/WaresBlade.rb +34 -0
  230. data/lib/bcdice/game_system/Warhammer.rb +336 -0
  231. data/lib/bcdice/game_system/WitchQuest.rb +275 -0
  232. data/lib/bcdice/game_system/WorldOfDarkness.rb +135 -0
  233. data/lib/bcdice/game_system/YankeeYogSothoth.rb +440 -0
  234. data/lib/bcdice/game_system/YearZeroEngine.rb +134 -0
  235. data/lib/bcdice/game_system/ZettaiReido.rb +142 -0
  236. data/lib/bcdice/game_system/meikyu_kingdom/item_table.rb +383 -0
  237. data/lib/bcdice/game_system/meikyu_kingdom/kingdom_name_table.rb +89 -0
  238. data/lib/bcdice/game_system/meikyu_kingdom/landscape_table.rb +196 -0
  239. data/lib/bcdice/game_system/meikyu_kingdom/name_tables.rb +223 -0
  240. data/lib/bcdice/game_system/meikyu_kingdom/placename_table.rb +214 -0
  241. data/lib/bcdice/game_system/meikyu_kingdom/tables.rb +610 -0
  242. data/lib/bcdice/game_system/meikyu_kingdom/word_table.rb +117 -0
  243. data/lib/bcdice/game_system/meikyu_kingdom_basic/item_table.rb +380 -0
  244. data/lib/bcdice/game_system/meikyu_kingdom_basic/kingdom_table.rb +184 -0
  245. data/lib/bcdice/game_system/meikyu_kingdom_basic/name_table.rb +417 -0
  246. data/lib/bcdice/game_system/meikyu_kingdom_basic/table.rb +912 -0
  247. data/lib/bcdice/game_system/meikyu_kingdom_basic/word_table.rb +121 -0
  248. data/lib/bcdice/game_system/one_way_heroics/dungeon_table.rb +67 -0
  249. data/lib/bcdice/game_system/one_way_heroics/random_event_table.rb +166 -0
  250. data/lib/bcdice/game_system/one_way_heroics/tables.rb +668 -0
  251. data/lib/bcdice/loader.rb +37 -0
  252. data/lib/bcdice/normalize.rb +38 -0
  253. data/lib/bcdice/preprocessor.rb +87 -0
  254. data/lib/bcdice/randomizer.rb +137 -0
  255. data/lib/bcdice/repl.rb +155 -0
  256. data/lib/bcdice/user_defined_dice_table.rb +153 -0
  257. data/lib/bcdice/version.rb +3 -0
  258. metadata +304 -0
@@ -0,0 +1,530 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bcdice/dice_table/table'
4
+ require 'bcdice/dice_table/range_table'
5
+
6
+ module BCDice
7
+ module GameSystem
8
+ class BattleTech < Base
9
+ # ゲームシステムの識別子
10
+ ID = 'BattleTech'
11
+
12
+ # ゲームシステム名
13
+ NAME = 'バトルテック'
14
+
15
+ # ゲームシステム名の読みがな
16
+ SORT_KEY = 'はとるてつく'
17
+
18
+ # ダイスボットの使い方
19
+ HELP_MESSAGE = <<~MESSAGETEXT
20
+ ・判定方法
21
+  (回数)BT(ダメージ)(部位)+(基本値)>=(目標値)
22
+  回数は省略時 1固定。
23
+  部位はC(正面)R(右)、L(左)。省略時はC(正面)固定
24
+  U(上半身)、L(下半身)を組み合わせ CU/RU/LU/CL/RL/LLも指定可能
25
+  例)BT3+2>=4
26
+   正面からダメージ3の攻撃を技能ベース2目標値4で1回判定
27
+  例)2BT3RL+5>=8
28
+   右下半身にダメージ3の攻撃を技能ベース5目標値8で2回判定
29
+  ミサイルによるダメージは BT(ダメージ)の変わりに SRM2/4/6, LRM5/10/15/20を指定
30
+  例)3SRM6LU+5>=8
31
+   左上半身にSRM6連を技能ベース5目標値8で3回判定
32
+ ・CT:致命的命中表
33
+ ・DW:転倒後の向き表
34
+ ・CDx:メック戦士意識維持表。ダメージ値xで判定 例)CD3
35
+ MESSAGETEXT
36
+
37
+ register_prefix('\d*SRM\d+.+', '\d*LRM\d+.+', '\d*BT.+', 'PPC', 'CT', 'DW', 'CD\d+')
38
+
39
+ # 致命的命中が発生しない上限値
40
+ NO_CRITICAL_HIT_LIMIT = 7
41
+
42
+ def eval_game_system_specific_command(command)
43
+ result = roll_tables(command, TABLES)
44
+ return result if result
45
+
46
+ command = command.gsub("PPC", "BT10")
47
+
48
+ count = 1
49
+ if command =~ /^(\d+)(.+)/
50
+ count = Regexp.last_match(1).to_i
51
+ command = Regexp.last_match(2)
52
+ end
53
+
54
+ debug('executeCommandCatched count', count)
55
+ debug('executeCommandCatched command', command)
56
+
57
+ case command
58
+ when /^CD(\d+)$/
59
+ damage = Regexp.last_match(1).to_i
60
+ return getCheckDieResult(damage)
61
+ when /^((S|L)RM\d+)(.+)/
62
+ tail = Regexp.last_match(3)
63
+ type = Regexp.last_match(1)
64
+ damageFunc = lambda { getXrmDamage(type) }
65
+ return getHitResult(count, damageFunc, tail)
66
+ when /^BT(\d+)(.+)/
67
+ debug('BT pattern')
68
+ tail = Regexp.last_match(2)
69
+ damageValue = Regexp.last_match(1).to_i
70
+ damageFunc = lambda { damageValue }
71
+ return getHitResult(count, damageFunc, tail)
72
+ end
73
+
74
+ return nil
75
+ rescue UnknownXRMError
76
+ return nil
77
+ end
78
+
79
+ class UnknownXRMError < StandardError; end
80
+
81
+ def getXrmDamage(type)
82
+ raise UnknownXRMError, "unknown XRM: #{type}" unless XRM_DAMAGE_TABLES.key?(type)
83
+
84
+ table = XRM_DAMAGE_TABLES[type]
85
+ roll_result = table.roll(@randomizer)
86
+
87
+ lrm = type.start_with?('L')
88
+ damage = roll_result.content
89
+ modified_damage = lrm ? damage : (2 * damage)
90
+
91
+ return modified_damage, roll_result.sum, lrm
92
+ end
93
+
94
+ LRM_LIMIT = 5
95
+
96
+ def getHitResult(count, damageFunc, tail)
97
+ m = /([LCR][LU]?)?(\+\d+)?>=(\d+)/.match(tail)
98
+ return nil unless m
99
+
100
+ side = m[1] || 'C'
101
+ baseString = m[2]
102
+ target = m[3].to_i
103
+ base = getBaseValue(baseString)
104
+ debug("side, base, target", side, base, target)
105
+
106
+ partTable = HitPart::TABLES[side]
107
+
108
+ resultTexts = []
109
+ damages = {}
110
+ hitCount = 0
111
+
112
+ count.times do
113
+ isHit, hitResult = getHitText(base, target)
114
+ if isHit
115
+ hitCount += 1
116
+
117
+ damages, damageText = getDamages(damageFunc, partTable, damages)
118
+ hitResult += damageText
119
+ end
120
+ resultTexts << hitResult
121
+ end
122
+
123
+ resultTexts.push(" > #{hitCount}回命中")
124
+
125
+ totalResultText = resultTexts.join("\n")
126
+ totalResultText += " 命中箇所:" + getTotalDamage(damages) if hitCount > 0
127
+
128
+ return totalResultText
129
+ end
130
+
131
+ def getBaseValue(baseString)
132
+ base = 0
133
+ return base if baseString.nil?
134
+
135
+ base = ArithmeticEvaluator.eval(baseString)
136
+ return base
137
+ end
138
+
139
+ def getHitText(base, target)
140
+ dice1 = @randomizer.roll_once(6)
141
+ dice2 = @randomizer.roll_once(6)
142
+ total = dice1 + dice2 + base
143
+ isHit = (total >= target)
144
+ baseString = (base > 0 ? "+#{base}" : "")
145
+
146
+ result = "#{total}[#{dice1},#{dice2}#{baseString}]>=#{target} > "
147
+
148
+ if isHit
149
+ result += "命中 > "
150
+ else
151
+ result += "外れ"
152
+ end
153
+
154
+ return isHit, result
155
+ end
156
+
157
+ # @param [Proc] damageFunc ダメージを返す手続き
158
+ # @param [RangeTable] partTable 命中部位表
159
+ # @param [Hash] damages 蓄積したダメージの情報
160
+ def getDamages(damageFunc, partTable, damages)
161
+ resultText = ''
162
+ damage, dice, isLrm = damageFunc.call()
163
+
164
+ damagePartCount = 1
165
+ if isLrm
166
+ damagePartCount = (1.0 * damage / LRM_LIMIT).ceil
167
+ resultText += "[#{dice}] #{damage}点"
168
+ end
169
+
170
+ damagePartCount.times do |damageIndex|
171
+ currentDamage, damageText = getDamageInfo(dice, damage, isLrm, damageIndex)
172
+
173
+ text, part, criticalText = getHitResultOne(damageText, partTable)
174
+ resultText += " " if isLrm
175
+ resultText += text
176
+
177
+ if damages[part].nil?
178
+ damages[part] = {
179
+ partDamages: [],
180
+ criticals: [],
181
+ }
182
+ end
183
+
184
+ damages[part][:partDamages] << currentDamage
185
+ damages[part][:criticals] << criticalText unless criticalText.empty?
186
+ end
187
+
188
+ return damages, resultText
189
+ end
190
+
191
+ def getDamageInfo(dice, damage, isLrm, index)
192
+ return damage, damage.to_s if dice.nil?
193
+ return damage, "[#{dice}] #{damage}" unless isLrm
194
+
195
+ currentDamage = damage - (LRM_LIMIT * index)
196
+ if currentDamage > LRM_LIMIT
197
+ currentDamage = LRM_LIMIT
198
+ end
199
+
200
+ return currentDamage, currentDamage.to_s
201
+ end
202
+
203
+ def getTotalDamage(damages)
204
+ parts = ['頭',
205
+ '胴中央',
206
+ '右胴',
207
+ '左胴',
208
+ '右脚',
209
+ '左脚',
210
+ '右腕',
211
+ '左腕',]
212
+
213
+ allDamage = 0
214
+ damageTexts = []
215
+ parts.each do |part|
216
+ damageInfo = damages.delete(part)
217
+ next if damageInfo.nil?
218
+
219
+ damage = damageInfo[:partDamages].inject(0) { |sum, i| sum + i }
220
+ allDamage += damage
221
+ damageCount = damageInfo[:partDamages].size
222
+ criticals = damageInfo[:criticals]
223
+
224
+ text = ""
225
+ text += "#{part}(#{damageCount}回) #{damage}点"
226
+ text += " #{criticals.join(' ')}" unless criticals.empty?
227
+
228
+ damageTexts << text
229
+ end
230
+
231
+ unless damages.empty?
232
+ raise "damages rest!! #{damages.inspect()}"
233
+ end
234
+
235
+ result = damageTexts.join(" / ")
236
+ result += " > 合計ダメージ #{allDamage}点"
237
+
238
+ return result
239
+ end
240
+
241
+ # 攻撃を1回行い、その結果を返す
242
+ # @param [String] damage_text ダメージを表す文字列
243
+ # @param [RangeTable] hit_part_table 命中部位表
244
+ def getHitResultOne(damage_text, hit_part_table)
245
+ hit_part_roll_result = hit_part_table.roll(@randomizer)
246
+ hit_part = hit_part_roll_result.content
247
+
248
+ critical_hit_may_occur_str =
249
+ hit_part.critical_hit_may_occur ? '(致命的命中)' : ''
250
+
251
+ result_parts = [
252
+ [
253
+ "[#{hit_part_roll_result.sum}]",
254
+ "#{hit_part.name}#{critical_hit_may_occur_str}",
255
+ "#{damage_text}点",
256
+ ].join(' ')
257
+ ]
258
+
259
+ criticalText = ''
260
+ if hit_part.critical_hit_may_occur
261
+ ct_roll_result = TABLES['CT'].roll(@randomizer)
262
+
263
+ # 致命的命中が発生したか
264
+ if ct_roll_result.sum > NO_CRITICAL_HIT_LIMIT
265
+ criticalText = ct_roll_result.content
266
+ end
267
+
268
+ result_parts.push("[#{ct_roll_result.sum}] #{ct_roll_result.content}")
269
+ end
270
+
271
+ # TODO: 構造体で表現する
272
+ return result_parts.join(' > '), hit_part.name, criticalText
273
+ end
274
+
275
+ def getCheckDieResult(damage)
276
+ if damage >= 6
277
+ return "死亡"
278
+ end
279
+
280
+ table = [[1, 3],
281
+ [2, 5],
282
+ [3, 7],
283
+ [4, 10],
284
+ [5, 11]]
285
+
286
+ target = get_table_by_number(damage, table, nil)
287
+
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}"
293
+
294
+ return text
295
+ end
296
+
297
+ # 表の集合
298
+ TABLES = {
299
+ 'CT' => DiceTable::RangeTable.new(
300
+ '致命的命中表',
301
+ '2D6',
302
+ [
303
+ [2..NO_CRITICAL_HIT_LIMIT, '致命的命中はなかった'],
304
+ [8..9, '1箇所の致命的命中'],
305
+ [10..11, '2箇所の致命的命中'],
306
+ [12, 'その部位が吹き飛ぶ(腕、脚、頭)または3箇所の致命的命中(胴)'],
307
+ ]
308
+ ),
309
+ 'DW' => DiceTable::Table.new(
310
+ '転倒後の向き表',
311
+ '1D6',
312
+ [
313
+ '同じ(前面から転倒) 正面/背面',
314
+ '1ヘクスサイド右(側面から転倒) 右側面',
315
+ '2ヘクスサイド右(側面から転倒) 右側面',
316
+ '180度逆(背面から転倒) 正面/背面',
317
+ '2ヘクスサイド左(側面から転倒) 左側面',
318
+ '1ヘクスサイド左(側面から転倒) 左側面',
319
+ ]
320
+ )
321
+ }.freeze
322
+
323
+ # 命中部位を表す構造体
324
+ # @!attribute [rw] name
325
+ # @return [String] 部位名
326
+ # @!attribute [rw] critical_hit_may_occur
327
+ # @return [Boolean] 致命的命中が発生し得るか
328
+ HitPart = Struct.new(:name, :critical_hit_may_occur)
329
+
330
+ class HitPart
331
+ LEFT_TORSO = '左胴'
332
+ CENTER_TORSO = '胴中央'
333
+ RIGHT_TORSO = '右胴'
334
+
335
+ LEFT_ARM = '左腕'
336
+ RIGHT_ARM = '右腕'
337
+
338
+ LEFT_LEG = '左脚'
339
+ RIGHT_LEG = '右脚'
340
+
341
+ HEAD = '頭'
342
+
343
+ # 命中部位表
344
+ TABLES = {
345
+ 'L' => DiceTable::RangeTable.new(
346
+ '命中部位表(左)',
347
+ '2D6',
348
+ [
349
+ [2, new(LEFT_TORSO, true)],
350
+ [3, new(LEFT_LEG, false)],
351
+ [4..5, new(LEFT_ARM, false)],
352
+ [6, new(LEFT_LEG, false)],
353
+ [7, new(LEFT_TORSO, false)],
354
+ [8, new(CENTER_TORSO, false)],
355
+ [9, new(RIGHT_TORSO, false)],
356
+ [10, new(RIGHT_ARM, false)],
357
+ [11, new(RIGHT_LEG, false)],
358
+ [12, new(HEAD, false)],
359
+ ]
360
+ ),
361
+ 'C' => DiceTable::RangeTable.new(
362
+ '命中部位表(正面)',
363
+ '2D6',
364
+ [
365
+ [2, new(CENTER_TORSO, true)],
366
+ [3..4, new(RIGHT_ARM, false)],
367
+ [5, new(RIGHT_LEG, false)],
368
+ [6, new(RIGHT_TORSO, false)],
369
+ [7, new(CENTER_TORSO, false)],
370
+ [8, new(LEFT_TORSO, false)],
371
+ [9, new(LEFT_LEG, false)],
372
+ [10..11, new(LEFT_ARM, false)],
373
+ [12, new(HEAD, false)],
374
+ ]
375
+ ),
376
+ 'R' => DiceTable::RangeTable.new(
377
+ '命中部位表(右)',
378
+ '2D6',
379
+ [
380
+ [2, new(RIGHT_TORSO, true)],
381
+ [3, new(RIGHT_LEG, false)],
382
+ [4..5, new(RIGHT_ARM, false)],
383
+ [6, new(RIGHT_LEG, false)],
384
+ [7, new(RIGHT_TORSO, false)],
385
+ [8, new(CENTER_TORSO, false)],
386
+ [9, new(LEFT_TORSO, false)],
387
+ [10, new(LEFT_ARM, false)],
388
+ [11, new(LEFT_LEG, false)],
389
+ [12, new(HEAD, false)],
390
+ ]
391
+ ),
392
+
393
+ 'LU' => DiceTable::RangeTable.new(
394
+ '命中部位表(左上半身)',
395
+ '1D6',
396
+ [
397
+ [1..2, new(LEFT_TORSO, false)],
398
+ [3, new(CENTER_TORSO, false)],
399
+ [4..5, new(LEFT_ARM, false)],
400
+ [6, new(HEAD, false)],
401
+ ]
402
+ ),
403
+ # TODO: 普通のTableで書く
404
+ 'CU' => DiceTable::RangeTable.new(
405
+ '命中部位表(正面上半身)',
406
+ '1D6',
407
+ [
408
+ [1, new(LEFT_ARM, false)],
409
+ [2, new(LEFT_TORSO, false)],
410
+ [3, new(CENTER_TORSO, false)],
411
+ [4, new(RIGHT_TORSO, false)],
412
+ [5, new(RIGHT_ARM, false)],
413
+ [6, new(HEAD, false)],
414
+ ]
415
+ ),
416
+ 'RU' => DiceTable::RangeTable.new(
417
+ '命中部位表(右上半身)',
418
+ '1D6',
419
+ [
420
+ [1..2, new(RIGHT_TORSO, false)],
421
+ [3, new(CENTER_TORSO, false)],
422
+ [4..5, new(RIGHT_ARM, false)],
423
+ [6, new(HEAD, false)],
424
+ ]
425
+ ),
426
+
427
+ 'LL' => DiceTable::RangeTable.new(
428
+ '命中部位表(左下半身)',
429
+ '1D6',
430
+ [
431
+ [1..6, new(LEFT_LEG, false)],
432
+ ]
433
+ ),
434
+ 'CL' => DiceTable::RangeTable.new(
435
+ '命中部位表(右下半身)',
436
+ '1D6',
437
+ [
438
+ [1..3, new(RIGHT_LEG, false)],
439
+ [4..6, new(LEFT_LEG, false)],
440
+ ]
441
+ ),
442
+ 'RL' => DiceTable::RangeTable.new(
443
+ '命中部位表(右下半身)',
444
+ '1D6',
445
+ [
446
+ [1..6, new(RIGHT_LEG, false)],
447
+ ]
448
+ ),
449
+ }.freeze
450
+ end
451
+
452
+ # ミサイルダメージ表
453
+ XRM_DAMAGE_TABLES = {
454
+ 'SRM2' => DiceTable::RangeTable.new(
455
+ 'SRM2ダメージ表',
456
+ '2D6',
457
+ [
458
+ [2..7, 1],
459
+ [8..12, 2],
460
+ ]
461
+ ),
462
+ 'SRM4' => DiceTable::RangeTable.new(
463
+ 'SRM4ダメージ表',
464
+ '2D6',
465
+ [
466
+ [2, 1],
467
+ [3..6, 2],
468
+ [7..10, 3],
469
+ [11..12, 4],
470
+ ]
471
+ ),
472
+ 'SRM6' => DiceTable::RangeTable.new(
473
+ 'SRM6ダメージ表',
474
+ '2D6',
475
+ [
476
+ [2..3, 2],
477
+ [4..5, 3],
478
+ [6..8, 4],
479
+ [9..10, 5],
480
+ [11..12, 6],
481
+ ]
482
+ ),
483
+ 'LRM5' => DiceTable::RangeTable.new(
484
+ 'LRM5ダメージ表',
485
+ '2D6',
486
+ [
487
+ [2, 1],
488
+ [3..4, 2],
489
+ [5..8, 3],
490
+ [9..10, 4],
491
+ [11..12, 5],
492
+ ]
493
+ ),
494
+ 'LRM10' => DiceTable::RangeTable.new(
495
+ 'LRM10ダメージ表',
496
+ '2D6',
497
+ [
498
+ [2..3, 3],
499
+ [4, 4],
500
+ [5..8, 6],
501
+ [9..10, 8],
502
+ [11..12, 10],
503
+ ]
504
+ ),
505
+ 'LRM15' => DiceTable::RangeTable.new(
506
+ 'LRM15ダメージ表',
507
+ '2D6',
508
+ [
509
+ [2..3, 5],
510
+ [4, 6],
511
+ [5..8, 9],
512
+ [9..10, 12],
513
+ [11..12, 15],
514
+ ]
515
+ ),
516
+ 'LRM20' => DiceTable::RangeTable.new(
517
+ 'LRM20ダメージ表',
518
+ '2D6',
519
+ [
520
+ [2..3, 6],
521
+ [4, 9],
522
+ [5..8, 12],
523
+ [9..10, 16],
524
+ [11..12, 20],
525
+ ]
526
+ )
527
+ }.freeze
528
+ end
529
+ end
530
+ end