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,263 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bcdice/arithmetic_evaluator'
4
+
5
+ # クトゥルフテックのダイスボット
6
+ module BCDice
7
+ module GameSystem
8
+ class CthulhuTech < Base
9
+ register_prefix(['\d+D10.*'])
10
+
11
+ # ゲームシステムの識別子
12
+ ID = 'CthulhuTech'
13
+
14
+ # ゲームシステム名
15
+ NAME = 'クトゥルフテック'
16
+
17
+ # ゲームシステム名の読みがな
18
+ SORT_KEY = 'くとうるふてつく'
19
+
20
+ # ダイスボットの使い方
21
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
22
+ ・行為判定(test):nD10+m>=d
23
+  n個のダイスを使用して、修正値m、難易度dで行為判定(test)を行います。
24
+  修正値mは省略可能、複数指定可能(例:+2-4)です。
25
+  成功、失敗、クリティカル、ファンブルを自動判定します。
26
+  例)2D10>=12 4D10+2>=28 5D10+2-4>=32
27
+
28
+ ・対抗判定(contest):nD10+m>d
29
+  行為判定と同様ですが、防御側有利のため「>=」ではなく「>」を入力します。
30
+  ダメージダイスも表示します。
31
+ INFO_MESSAGE_TEXT
32
+
33
+ # 行為判定のノード
34
+ class Test
35
+ # 判定で用いる比較演算子
36
+ #
37
+ # 対抗判定で変えられるように定数で定義する。
38
+ COMPARE_OP = :>=
39
+
40
+ # ノードを初期化する
41
+ # @param [Integer] num ダイス数
42
+ # @param [Integer] modifier 修正値
43
+ # @param [Integer] difficulty 難易度
44
+ def initialize(num, modifier, difficulty)
45
+ @num = num
46
+ @modifier = modifier
47
+ @difficulty = difficulty
48
+ end
49
+
50
+ # 判定を行う
51
+ # @param randomizer [Randoizer]
52
+ # @return [String] 判定結果
53
+ def execute(randomizer)
54
+ dice_values = randomizer.roll_barabara(@num, 10)
55
+
56
+ # ファンブル:出目の半分(小数点以下切り上げ)以上が1の場合
57
+ fumble = dice_values.count(1) >= (dice_values.length + 1) / 2
58
+
59
+ sorted_dice_values = dice_values.sort
60
+ roll_result = calculate_roll_result(sorted_dice_values)
61
+ test_value = roll_result + @modifier
62
+
63
+ diff = test_value - @difficulty
64
+
65
+ # diff と @difficulty との比較の演算子が変わるので、send で対応
66
+ # 例:COMPARE_OP が :>= ならば、diff >= 0 と同じ
67
+ success = !fumble && diff.send(self.class::COMPARE_OP, 0)
68
+
69
+ critical = diff >= 10
70
+
71
+ output_parts = [
72
+ "(#{expression()})",
73
+ test_value_expression(sorted_dice_values, roll_result),
74
+ test_value,
75
+ result_str(success, fumble, critical, diff)
76
+ ]
77
+
78
+ return output_parts.join(' > ')
79
+ end
80
+
81
+ private
82
+
83
+ # 数式表現を返す
84
+ # @return [String]
85
+ def expression
86
+ modifier_str = Format.modifier(@modifier)
87
+ return "#{@num}D10#{modifier_str}#{self.class::COMPARE_OP}#{@difficulty}"
88
+ end
89
+
90
+ # 判定値の数式表現を返す
91
+ # @param [Array<Integer>] dice_values 出目の配列
92
+ # @param [Integer] roll_result ダイスロール結果の値
93
+ # @return [String]
94
+ def test_value_expression(dice_values, roll_result)
95
+ dice_str = dice_values.join(',')
96
+ modifier_str = Format.modifier(@modifier)
97
+
98
+ return "#{roll_result}[#{dice_str}]#{modifier_str}"
99
+ end
100
+
101
+ # 判定結果の文字列を返す
102
+ # @param [Boolean] success 成功したか
103
+ # @param [Boolean] fumble ファンブルだったか
104
+ # @param [Boolean] critical クリティカルだったか
105
+ # @param [Integer] _diff 判定値と難易度の差
106
+ # @return [String]
107
+ def result_str(success, fumble, critical, _diff)
108
+ return 'ファンブル' if fumble
109
+ return 'クリティカル' if critical
110
+
111
+ return success ? '成功' : '失敗'
112
+ end
113
+
114
+ # ダイスロール結果を計算する
115
+ #
116
+ # 以下のうち最大のものを返す。
117
+ #
118
+ # * 出目の最大値
119
+ # * ゾロ目の和の最大値
120
+ # * ストレート(昇順で連続する3個以上の値)の和の最大値
121
+ #
122
+ # @param [Array<Integer>] sorted_dice_values 昇順でソートされた出目の配列
123
+ # @return [Integer]
124
+ def calculate_roll_result(sorted_dice_values)
125
+ highest_single_roll = sorted_dice_values.last
126
+
127
+ candidates = [
128
+ highest_single_roll,
129
+ sum_of_highest_set_of_multiples(sorted_dice_values),
130
+ sum_of_largest_straight(sorted_dice_values)
131
+ ]
132
+
133
+ return candidates.max
134
+ end
135
+
136
+ # ゾロ目の和の最大値を求める
137
+ # @param [Array<Integer>] dice_values 出目の配列
138
+ # @return [Integer]
139
+ def sum_of_highest_set_of_multiples(dice_values)
140
+ dice_values.
141
+ # TODO: Ruby 2.2以降では group_by(&:itself) が使える
142
+ group_by { |i| i }.
143
+ # TODO: Ruby 2.4以降では value_group.sum が使える
144
+ map { |_, value_group| value_group.reduce(0, &:+) }
145
+ .max
146
+ end
147
+
148
+ # ストレートの和の最大値を求める
149
+ #
150
+ # ストレートとは、昇順で3個以上連続した値のこと。
151
+ #
152
+ # @param [Array<Integer>] sorted_dice_values 昇順にソートされた出目の配列
153
+ # @return [Integer] ストレートの和の最大値
154
+ # @return [0] ストレートが存在しなかった場合
155
+ def sum_of_largest_straight(sorted_dice_values)
156
+ # 出目が3個未満ならば、ストレートは存在しない
157
+ return 0 if sorted_dice_values.length < 3
158
+
159
+ # ストレートの和の最大値
160
+ max_sum = 0
161
+
162
+ # 連続した値の数
163
+ n_consecutive_values = 0
164
+ # 連続した値の和
165
+ sum = 0
166
+ # 直前の値
167
+ # 初期値を負の値にして、最初の値と連続にならないようにする
168
+ last = -1
169
+
170
+ sorted_dice_values.uniq.each do |value|
171
+ # 値が連続でなければ、状態を初期化する(現在の値を連続1個目とする)
172
+ if value - last > 1
173
+ n_consecutive_values = 1
174
+ sum = value
175
+ last = value
176
+
177
+ next
178
+ end
179
+
180
+ # 連続した値なので溜める
181
+ n_consecutive_values += 1
182
+ sum += value
183
+ last = value
184
+
185
+ # ストレートならば、和の最大値を更新する
186
+ if n_consecutive_values >= 3 && sum > max_sum
187
+ max_sum = sum
188
+ end
189
+ end
190
+
191
+ return max_sum
192
+ end
193
+ end
194
+
195
+ # 対抗判定のノード
196
+ class Contest < Test
197
+ # 判定で用いる比較演算子
198
+ COMPARE_OP = :>
199
+
200
+ # 判定結果の文字列を返す
201
+ #
202
+ # 成功した場合(クリティカルを含む)、ダメージロールのコマンドを末尾に
203
+ # 追加する。
204
+ #
205
+ # @param [Boolean] success 成功したか
206
+ # @param [Integer] diff 判定値と難易度の差
207
+ # @return [String]
208
+ def result_str(success, _fumble, _critical, diff)
209
+ formatted = super
210
+
211
+ if success
212
+ damage_roll_num = (diff / 5.0).ceil
213
+ damage_roll = "#{damage_roll_num}D10"
214
+
215
+ "#{formatted}(ダメージ:#{damage_roll})"
216
+ else
217
+ formatted
218
+ end
219
+ end
220
+ end
221
+
222
+ # ダイスボットを初期化する
223
+ def initialize(command)
224
+ super(command)
225
+
226
+ # 加算ロールで出目をソートする
227
+ @sort_add_dice = true
228
+ end
229
+
230
+ # ダイスボット固有コマンドの処理を行う
231
+ # @param [String] command コマンド
232
+ # @return [String] ダイスボット固有コマンドの結果
233
+ # @return [nil] 無効なコマンドだった場合
234
+ def eval_game_system_specific_command(command)
235
+ node = parse(command)
236
+ return nil unless node
237
+
238
+ return node.execute(@randomizer)
239
+ end
240
+
241
+ private
242
+
243
+ # 判定コマンドの正規表現
244
+ TEST_RE = /\A(\d+)D10((?:[-+]\d+)+)?(>=?)(\d+)\z/.freeze
245
+
246
+ # 構文解析する
247
+ # @param [String] command コマンド
248
+ # @return [Test, Contest] 判定のノード
249
+ # @return [nil] 無効なコマンドだった場合
250
+ def parse(command)
251
+ m = TEST_RE.match(command)
252
+ return nil unless m
253
+
254
+ num = m[1].to_i
255
+ modifier = m[2] ? ArithmeticEvaluator.eval(m[2]) : 0
256
+ node_class = m[3] == '>' ? Contest : Test
257
+ difficulty = m[4].to_i
258
+
259
+ return node_class.new(num, modifier, difficulty)
260
+ end
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,243 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class Cthulhu_ChineseTraditional < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'Cthulhu:ChineseTraditional'
8
+
9
+ # ゲームシステム名
10
+ NAME = '克蘇魯神話'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = '国際化:Chinese Traditional:克蘇魯神話7'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
+ c=爆擊率 / f=大失敗值 / s=特殊
18
+
19
+ 1d100<=n c・f・s全關閉(只進行單純數值比較判定)
20
+
21
+ ・cfs付註判定指令
22
+
23
+ CC 1d100擲骰 c=1、f=100
24
+ CCB 同上、c=5、f=96
25
+
26
+ 例:CC<=80 (以技能值80來判定。cf適用於1%規則)
27
+ 例:CCB<=55 (以技能值55來判定。cf適用於5%規則)
28
+
29
+ ・關於組合骰組
30
+
31
+ CBR(x,y) c=1、f=100
32
+ CBRB(x,y) c=5、f=96
33
+
34
+ ・關於對抗骰
35
+ RES(x-y) c=1、f=100
36
+ RESB(x-y) c=5、f=96
37
+
38
+ ※故障率判定
39
+
40
+ ・CC(x) c=1、f=100
41
+ x=故障率。擲出骰值x以上時、需在大失敗發生同時輸出(參照「大失敗&故障」)
42
+ 沒有大失敗時,無論成功或失敗只需參考[故障]來輸出(並非成功或失敗來輸出,而是覆蓋上去並對其輸出)
43
+
44
+ ・CCB(x) c=5、f=96
45
+ 同上
46
+
47
+ ・瘋狂表
48
+ ・短期瘋期 Short/長期瘋狂 Longer
49
+
50
+ INFO_MESSAGE_TEXT
51
+
52
+ register_prefix(['CC(B)?\(\d+\)', 'CC(B)?.*', 'RES(B)?.*', 'CBR(B)?\(\d+,\d+\)'])
53
+
54
+ def initialize
55
+ # $isDebug = true
56
+ super
57
+ @special_percentage = 20
58
+ @critical_percentage = 1
59
+ @fumble_percentage = 1
60
+ end
61
+
62
+ def eval_game_system_specific_command(command)
63
+ case command
64
+ when /CCB/i
65
+ # 5%
66
+ @critical_percentage = 5
67
+ @fumble_percentage = 5
68
+ return getCheckResult(command)
69
+ when /CC/i
70
+ # 1%
71
+ @critical_percentage = 1
72
+ @fumble_percentage = 1
73
+ return getCheckResult(command)
74
+ when /RESB/i
75
+ # 5%
76
+ @critical_percentage = 5
77
+ @fumble_percentage = 5
78
+ return getRegistResult(command)
79
+ when /CBRB/i
80
+ # 5%
81
+ @critical_percentage = 5
82
+ @fumble_percentage = 5
83
+ return getCombineRoll(command)
84
+ when /RES/i
85
+ # 1%
86
+ @critical_percentage = 1
87
+ @fumble_percentage = 1
88
+ return getRegistResult(command)
89
+ when /CBR/i
90
+ # 1%
91
+ @critical_percentage = 1
92
+ @fumble_percentage = 1
93
+ return getCombineRoll(command)
94
+ end
95
+
96
+ return nil
97
+ end
98
+
99
+ def getCheckResult(command)
100
+ broken_num = 0
101
+ diff = 0
102
+
103
+ if (m = /CC(B)?(\d+)<=(\d+)/i.match(command))
104
+ # /\(\d+\)/の()はpattern-killerにカイシャクされる
105
+ broken_num = m[2].to_i
106
+ diff = m[3].to_i
107
+ elsif (m = /CC(B)?<=(\d+)/i.match(command))
108
+ diff = m[2].to_i
109
+ end
110
+
111
+ output = ""
112
+
113
+ if diff > 0
114
+ output = "(1D100<=#{diff})"
115
+
116
+ if broken_num > 0
117
+ output += " 故障率[#{broken_num}]"
118
+ end
119
+
120
+ total_n = @randomizer.roll_once(100)
121
+
122
+ output += " > #{total_n}"
123
+ output += " > #{getCheckResultText(total_n, diff, broken_num)}"
124
+ else
125
+ total_n = @randomizer.roll_once(100)
126
+ output = "(1D100) > #{total_n}"
127
+ end
128
+
129
+ return output
130
+ end
131
+
132
+ def getCheckResultText(total_n, diff, broken_num = 0)
133
+ result = ""
134
+ diff_special = 0
135
+ fumble = false
136
+
137
+ if @special_percentage > 0
138
+ # 需有special的數值設定才能做爆擊/大失敗的判定
139
+ diff_special = (diff * @special_percentage / 100).floor
140
+ if diff_special < 1
141
+ diff_special = 1
142
+ end
143
+ end
144
+
145
+ if (total_n <= diff) && (total_n < 100)
146
+ result = "成功"
147
+
148
+ if diff_special > 0
149
+ if total_n <= @critical_percentage
150
+ if total_n <= diff_special
151
+ result = "決定性的成功/特殊"
152
+ else
153
+ result = "決定性的成功"
154
+ end
155
+ else
156
+ if total_n <= diff_special
157
+ result = "特殊"
158
+ end
159
+ end
160
+ end
161
+ else
162
+ result = "失敗"
163
+
164
+ if diff_special > 0
165
+ if (total_n >= (101 - @fumble_percentage)) && (diff < 100)
166
+ result = "致命性失敗"
167
+ fumble = true
168
+ end
169
+ end
170
+ end
171
+
172
+ if broken_num > 0
173
+ if total_n >= broken_num
174
+ if fumble
175
+ result += "/故障"
176
+ else
177
+ result = "故障"
178
+ end
179
+ end
180
+ end
181
+
182
+ return result
183
+ end
184
+
185
+ def getRegistResult(command)
186
+ m = /RES(B)?([-\d]+)/i.match(command)
187
+ unless m
188
+ return "1"
189
+ end
190
+
191
+ value = m[2].to_i
192
+ target = value * 5 + 50
193
+
194
+ if target < 5
195
+ return "(1d100<=#{target}) > 自動失敗"
196
+ end
197
+
198
+ if target > 95
199
+ return "(1d100<=#{target}) > 自動成功"
200
+ end
201
+
202
+ # 通常判定
203
+ total_n = @randomizer.roll_once(100)
204
+ result = getCheckResultText(total_n, target)
205
+
206
+ return "(1d100<=#{target}) > #{total_n} > #{result}"
207
+ end
208
+
209
+ def getCombineRoll(command)
210
+ m = /CBR(B)?\((\d+),(\d+)\)/i.match(command)
211
+ unless m
212
+ return "1"
213
+ end
214
+
215
+ diff_1 = m[2].to_i
216
+ diff_2 = m[3].to_i
217
+
218
+ total = @randomizer.roll_once(100)
219
+
220
+ result_1 = getCheckResultText(total, diff_1)
221
+ result_2 = getCheckResultText(total, diff_2)
222
+
223
+ successList = ["決定性成功/特殊", "決定性成功", "特殊", "成功"]
224
+
225
+ succesCount = 0
226
+ succesCount += 1 if successList.include?(result_1)
227
+ succesCount += 1 if successList.include?(result_2)
228
+ debug("succesCount", succesCount)
229
+
230
+ rank =
231
+ if succesCount >= 2
232
+ "成功"
233
+ elsif succesCount == 1
234
+ "部分性成功"
235
+ else
236
+ "失敗"
237
+ end
238
+
239
+ return "(1d100<=#{diff_1},#{diff_2}) > #{total}[#{result_1},#{result_2}] > #{rank}"
240
+ end
241
+ end
242
+ end
243
+ end