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,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class CrashWorld < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'CrashWorld'
8
+
9
+ # ゲームシステム名
10
+ NAME = '墜落世界'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'ついらくせかい'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
+ ・判定 CWn
18
+ 初期目標値n (必須)
19
+ 例・CW8
20
+ INFO_MESSAGE_TEXT
21
+
22
+ register_prefix(['CW\d+'])
23
+
24
+ def eval_game_system_specific_command(command)
25
+ result = nil
26
+
27
+ case command
28
+ when /CW(\d+)/i
29
+ result = getCrashWorldRoll(Regexp.last_match(1).to_i)
30
+ end
31
+
32
+ return result
33
+ end
34
+
35
+ def getCrashWorldRoll(target)
36
+ debug("target", target)
37
+
38
+ output = "("
39
+ isEnd = false
40
+ successness = 0
41
+ num = 0
42
+
43
+ while !isEnd
44
+ num = @randomizer.roll_once(12)
45
+
46
+ # 振った数字を出力へ書き足す
47
+ if output == "("
48
+ output = "(#{num}"
49
+ else
50
+ output = "#{output}, #{num}"
51
+ end
52
+
53
+ if num <= target || num == 11
54
+ # 成功/クリティカル(11)。 次回の目標値を変更して継続
55
+ target = num
56
+ successness += 1
57
+ elsif num == 12
58
+ # ファンブルなら終了。
59
+ isEnd = true
60
+ else
61
+ # target < num < 11で終了
62
+ isEnd = true
63
+ end
64
+ end
65
+
66
+ if num == 12
67
+ # ファンブルの時、成功度は0
68
+ successness = 0
69
+ end
70
+
71
+ output = "#{output}) 成功度 : #{successness}"
72
+
73
+ if num == 12
74
+ output = "#{output} ファンブル"
75
+ end
76
+
77
+ return output
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,252 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bcdice/arithmetic_evaluator'
4
+
5
+ module BCDice
6
+ module GameSystem
7
+ class Cthulhu < Base
8
+ # ゲームシステムの識別子
9
+ ID = 'Cthulhu'
10
+
11
+ # ゲームシステム名
12
+ NAME = 'クトゥルフ神話TRPG'
13
+
14
+ # ゲームシステム名の読みがな
15
+ SORT_KEY = 'くとうるふしんわTRPG'
16
+
17
+ # ダイスボットの使い方
18
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
19
+ c=クリティカル値 / f=ファンブル値 / s=スペシャル
20
+
21
+ 1d100<=n c・f・sすべてオフ(単純な数値比較判定のみ行います)
22
+
23
+ ・cfs判定付き判定コマンド
24
+
25
+ CC 1d100ロールを行う c=1、f=100
26
+ CCB 同上、c=5、f=96
27
+
28
+ 例:CC<=80 (技能値80で行為判定。1%ルールでcf適用)
29
+ 例:CCB<=55 (技能値55で行為判定。5%ルールでcf適用)
30
+
31
+ ・組み合わせロールについて
32
+
33
+ CBR(x,y) c=1、f=100
34
+ CBRB(x,y) c=5、f=96
35
+
36
+ ・抵抗表ロールについて
37
+ RES(x-y) c=1、f=100
38
+ RESB(x-y) c=5、f=96
39
+
40
+ ※故障ナンバー判定
41
+
42
+ ・CC(x) c=1、f=100
43
+ x=故障ナンバー。出目x以上が出た上で、ファンブルが同時に発生した場合、共に出力する(テキスト「ファンブル&故障」)
44
+ ファンブルでない場合、成功・失敗に関わらずテキスト「故障」のみを出力する(成功・失敗を出力せず、上書きしたものを出力する形)
45
+
46
+ ・CCB(x) c=5、f=96
47
+ 同上
48
+
49
+ INFO_MESSAGE_TEXT
50
+
51
+ register_prefix(['CC(B)?\(\d+\)', 'CC(B)?.*', 'RES(B)?.*', 'CBR(B)?\(\d+,\d+\)'])
52
+
53
+ def initialize(command)
54
+ super(command)
55
+ @special_percentage = 20
56
+ @critical_percentage = 1
57
+ @fumble_percentage = 1
58
+ end
59
+
60
+ def eval_game_system_specific_command(command)
61
+ case command
62
+ when /CCB/i
63
+ # 5%
64
+ @critical_percentage = 5
65
+ @fumble_percentage = 5
66
+ return getCheckResult(command)
67
+ when /CC/i
68
+ # 1%
69
+ @critical_percentage = 1
70
+ @fumble_percentage = 1
71
+ return getCheckResult(command)
72
+ when /RESB/i
73
+ # 5%
74
+ @critical_percentage = 5
75
+ @fumble_percentage = 5
76
+ return getRegistResult(command)
77
+ when /CBRB/i
78
+ # 5%
79
+ @critical_percentage = 5
80
+ @fumble_percentage = 5
81
+ return getCombineRoll(command)
82
+ when /RES/i
83
+ # 1%
84
+ @critical_percentage = 1
85
+ @fumble_percentage = 1
86
+ return getRegistResult(command)
87
+ when /CBR/i
88
+ # 1%
89
+ @critical_percentage = 1
90
+ @fumble_percentage = 1
91
+ return getCombineRoll(command)
92
+ end
93
+
94
+ return nil
95
+ end
96
+
97
+ def getCheckResult(command)
98
+ broken_num = 0
99
+ diff = 0
100
+
101
+ if (m = %r{CCB?(\d+)?<=([+-/*\d]+)}i.match(command))
102
+ broken_num = m[1].to_i
103
+ diff = ArithmeticEvaluator.eval(m[2])
104
+ end
105
+
106
+ output = ""
107
+
108
+ if diff > 0
109
+ output = "(1D100<=#{diff})"
110
+
111
+ if broken_num > 0
112
+ output += " 故障ナンバー[#{broken_num}]"
113
+ end
114
+
115
+ total_n = @randomizer.roll_once(100)
116
+
117
+ output += " > #{total_n}"
118
+ output += " > #{getCheckResultText(total_n, diff, broken_num)}"
119
+ else
120
+ total_n = @randomizer.roll_once(100)
121
+ output = "(1D100) > #{total_n}"
122
+ end
123
+
124
+ return output
125
+ end
126
+
127
+ def getCheckResultText(total_n, diff, broken_num = 0)
128
+ result = ""
129
+ diff_special = 0
130
+ fumble = false
131
+
132
+ if @special_percentage > 0
133
+ # specialの値設定が無い場合はクリティカル/ファンブル判定もしない
134
+ diff_special = (diff * @special_percentage / 100).floor
135
+ if diff_special < 1
136
+ diff_special = 1
137
+ end
138
+ end
139
+
140
+ if (total_n <= diff) && (total_n < 100)
141
+ @is_success = true
142
+ result = "成功"
143
+
144
+ if diff_special > 0
145
+ if total_n <= @critical_percentage
146
+ @is_critical = true
147
+ if total_n <= diff_special
148
+ result = "決定的成功/スペシャル"
149
+ else
150
+ result = "決定的成功"
151
+ end
152
+ else
153
+ if total_n <= diff_special
154
+ result = "スペシャル"
155
+ end
156
+ end
157
+ end
158
+ else
159
+ @is_failure = true
160
+ result = "失敗"
161
+
162
+ if diff_special > 0
163
+ if (total_n >= (101 - @fumble_percentage)) && (diff < 100)
164
+ @is_fumble = true
165
+ result = "致命的失敗"
166
+ fumble = true
167
+ end
168
+ end
169
+ end
170
+
171
+ if broken_num > 0
172
+ if total_n >= broken_num
173
+ @is_success = false
174
+ @is_failure = true
175
+ if fumble
176
+ result += "/故障"
177
+ else
178
+ result = "故障"
179
+ end
180
+ end
181
+ end
182
+
183
+ return result
184
+ end
185
+
186
+ def getRegistResult(command)
187
+ m = /RES(B)?([-\d]+)/i.match(command)
188
+ unless m
189
+ return "1"
190
+ end
191
+
192
+ value = m[2].to_i
193
+ target = value * 5 + 50
194
+
195
+ if target < 5
196
+ @is_failure = true
197
+ return "(1d100<=#{target}) > 自動失敗"
198
+ end
199
+
200
+ if target > 95
201
+ @is_success = true
202
+ return "(1d100<=#{target}) > 自動成功"
203
+ end
204
+
205
+ # 通常判定
206
+ total_n = @randomizer.roll_once(100)
207
+ result = getCheckResultText(total_n, target)
208
+
209
+ return "(1d100<=#{target}) > #{total_n} > #{result}"
210
+ end
211
+
212
+ def getCombineRoll(command)
213
+ m = /CBR(B)?\((\d+),(\d+)\)/i.match(command)
214
+ unless m
215
+ return "1"
216
+ end
217
+
218
+ diff_1 = m[2].to_i
219
+ diff_2 = m[3].to_i
220
+
221
+ total = @randomizer.roll_once(100)
222
+
223
+ result_1 = getCheckResultText(total, diff_1)
224
+ result_2 = getCheckResultText(total, diff_2)
225
+
226
+ successList = ["決定的成功/スペシャル", "決定的成功", "スペシャル", "成功"]
227
+
228
+ succesCount = 0
229
+ succesCount += 1 if successList.include?(result_1)
230
+ succesCount += 1 if successList.include?(result_2)
231
+ debug("succesCount", succesCount)
232
+
233
+ @is_failure = false
234
+ @is_success = false
235
+
236
+ rank =
237
+ if succesCount >= 2
238
+ @is_success = true
239
+ "成功"
240
+ elsif succesCount == 1
241
+ @is_success = true
242
+ "部分的成功"
243
+ else
244
+ @is_failure = true
245
+ "失敗"
246
+ end
247
+
248
+ return "(1d100<=#{diff_1},#{diff_2}) > #{total}[#{result_1},#{result_2}] > #{rank}"
249
+ end
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,767 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class Cthulhu7th < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'Cthulhu7th'
8
+
9
+ # ゲームシステム名
10
+ NAME = '新クトゥルフ神話TRPG'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'しんくとうるふしんわTRPG'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
+ ※コマンドは入力内容の前方一致で検出しています。
18
+ ・判定 CC(x)<=(目標値)
19
+  x:ボーナス・ペナルティダイス (2~-2)。省略可。
20
+  目標値が無くても1D100は表示される。
21
+  ファンブル/失敗/ レギュラー成功/ハード成功/
22
+  イクストリーム成功/クリティカル を自動判定。
23
+ 例)CC<=30 CC(2)<=50 CC(+2)<=50 CC(-1)<=75 CC-1<=50 CC1<=65 CC+1<=65 CC
24
+
25
+ ・組み合わせ判定 (CBR(x,y))
26
+  目標値 x と y で%ロールを行い、成否を判定。
27
+  例)CBR(50,20)
28
+
29
+ ・自動火器の射撃判定 FAR(w,x,y,z,d,v)
30
+  w:弾丸の数(1~100)、x:技能値(1~100)、y:故障ナンバー、
31
+  z:ボーナス・ペナルティダイス(-2~2)。省略可。
32
+  d:指定難易度で連射を終える(レギュラー:r,ハード:h,イクストリーム:e)。省略可。
33
+  v:ボレーの弾丸の数を変更する。省略可。
34
+  命中数と貫通数、残弾数のみ算出。ダメージ算出はありません。
35
+ 例)FAR(25,70,98) FAR(50,80,98,-1) far(30,70,99,1,R)
36
+   far(25,88,96,2,h,5) FaR(40,77,100,,e,4) fAr(20,47,100,,,3)
37
+
38
+ ・各種表
39
+  【狂気関連】
40
+  ・狂気の発作(リアルタイム)(Bouts of Madness Real Time) BMR
41
+  ・狂気の発作(サマリー)(Bouts of Madness Summary) BMS
42
+  ・恐怖症(Sample Phobias)表 PH/マニア(Sample Manias)表 MA
43
+  【魔術関連】
44
+  ・プッシュ時のキャスティング・ロール(Casting Roll)の失敗表
45
+   強力でない呪文の場合 FCL/強力な呪文の場合 FCM
46
+ INFO_MESSAGE_TEXT
47
+
48
+ register_prefix(['CC\(\d+\)', 'CC.*', 'CBR\(\d+,\d+\)', 'FAR.*', 'BMR', 'BMS', 'FCL', 'FCM', 'PH', 'MA'])
49
+
50
+ def initialize(command)
51
+ super(command)
52
+
53
+ @bonus_dice_range = (-2..2)
54
+ end
55
+
56
+ def eval_game_system_specific_command(command)
57
+ case command
58
+ when /^CC/i
59
+ return getCheckResult(command)
60
+ when /^CBR/i
61
+ return getCombineRoll(command)
62
+ when /^FAR/i
63
+ return getFullAutoResult(command)
64
+ when /^BMR/i # 狂気の発作(リアルタイム)
65
+ return roll_bmr_table()
66
+ when /^BMS/i # 狂気の発作(サマリー)
67
+ return roll_bms_table()
68
+ when /^FCL/i # キャスティング・ロールのプッシュに失敗した場合(小)
69
+ return roll_1d8_table("キャスティング・ロール失敗(小)表", FAILED_CASTING_L_TABLE)
70
+ when /^FCM/i # キャスティング・ロールのプッシュに失敗した場合(大)
71
+ return roll_1d8_table("キャスティング・ロール失敗(大)表", FAILED_CASTING_M_TABLE)
72
+ when /^PH/i # 恐怖症表
73
+ return roll_1d100_table("恐怖症表", PHOBIAS_TABLE)
74
+ when /^MA/i # マニア表
75
+ return roll_1d100_table("マニア表", MANIAS_TABLE)
76
+ else
77
+ return nil
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def roll_1d8_table(table_name, table)
84
+ total_n = @randomizer.roll_once(8)
85
+ index = total_n - 1
86
+
87
+ text = table[index]
88
+
89
+ return "#{table_name}(#{total_n}) > #{text}"
90
+ end
91
+
92
+ def roll_1d100_table(table_name, table)
93
+ total_n = @randomizer.roll_once(100)
94
+ index = total_n - 1
95
+
96
+ text = table[index]
97
+
98
+ return "#{table_name}(#{total_n}) > #{text}"
99
+ end
100
+
101
+ def getCheckResult(command)
102
+ m = /^CC([-+]?\d+)?(<=(\d+))?/i.match(command)
103
+ unless m
104
+ return nil
105
+ end
106
+
107
+ bonus_dice_count = m[1].to_i # ボーナス・ペナルティダイスの個数
108
+ diff = m[3].to_i
109
+ without_compare = m[2].nil? || diff <= 0
110
+
111
+ if bonus_dice_count == 0 && diff <= 0
112
+ dice = @randomizer.roll_once(100)
113
+ return "1D100 > #{dice}"
114
+ end
115
+
116
+ unless @bonus_dice_range.include?(bonus_dice_count)
117
+ return "エラー。ボーナス・ペナルティダイスの値は#{@bonus_dice_range.min}~#{@bonus_dice_range.max}です。"
118
+ end
119
+
120
+ total, total_list = roll_with_bonus(bonus_dice_count)
121
+
122
+ if without_compare
123
+ output = "(1D100) ボーナス・ペナルティダイス[#{bonus_dice_count}]"
124
+ output += " > #{total_list.join(', ')} > #{total}"
125
+ else
126
+ result_text = getCheckResultText(total, diff)
127
+ output = "(1D100<=#{diff}) ボーナス・ペナルティダイス[#{bonus_dice_count}]"
128
+ output += " > #{total_list.join(', ')} > #{total} > #{result_text}"
129
+ end
130
+
131
+ return output
132
+ end
133
+
134
+ # 1D100の一の位用のダイスロール
135
+ # 0から9までの値を返す
136
+ #
137
+ # @return [Integer]
138
+ def roll_ones_d10
139
+ dice = @randomizer.roll_once(10)
140
+ return 0 if dice == 10
141
+
142
+ return dice
143
+ end
144
+
145
+ # @param bonus [Integer] ボーナス・ペナルティダイスの数。負の数ならペナルティダイス。
146
+ # @return [Array<(Integer, Array<Integer>)>]
147
+ def roll_with_bonus(bonus)
148
+ tens_list = Array.new(bonus.abs + 1) { @randomizer.roll_tens_d10 }
149
+ ones = roll_ones_d10()
150
+
151
+ dice_list = tens_list.map do |tens|
152
+ dice = tens + ones
153
+ dice == 0 ? 100 : dice
154
+ end
155
+
156
+ dice =
157
+ if bonus >= 0
158
+ dice_list.min
159
+ else
160
+ dice_list.max
161
+ end
162
+
163
+ return dice, dice_list
164
+ end
165
+
166
+ def getCheckResultText(total, diff, fumbleable = false)
167
+ if total <= diff
168
+ return "クリティカル" if total == 1
169
+ return "イクストリーム成功" if total <= (diff / 5)
170
+ return "ハード成功" if total <= (diff / 2)
171
+
172
+ return "レギュラー成功"
173
+ end
174
+
175
+ fumble_text = "ファンブル"
176
+
177
+ return fumble_text if total == 100
178
+
179
+ if total >= 96
180
+ if diff < 50
181
+ return fumble_text
182
+ else
183
+ return fumble_text if fumbleable
184
+ end
185
+ end
186
+
187
+ return "失敗"
188
+ end
189
+
190
+ def getCombineRoll(command)
191
+ return nil unless /CBR\((\d+),(\d+)\)/i =~ command
192
+
193
+ diff_1 = Regexp.last_match(1).to_i
194
+ diff_2 = Regexp.last_match(2).to_i
195
+
196
+ total = @randomizer.roll_once(100)
197
+
198
+ result_1 = getCheckResultText(total, diff_1)
199
+ result_2 = getCheckResultText(total, diff_2)
200
+
201
+ successList = ["クリティカル", "イクストリーム成功", "ハード成功", "レギュラー成功"]
202
+
203
+ succesCount = 0
204
+ succesCount += 1 if successList.include?(result_1)
205
+ succesCount += 1 if successList.include?(result_2)
206
+ debug("succesCount", succesCount)
207
+
208
+ rank =
209
+ if succesCount >= 2
210
+ "成功"
211
+ elsif succesCount == 1
212
+ "部分的成功"
213
+ else
214
+ "失敗"
215
+ end
216
+
217
+ return "(1d100<=#{diff_1},#{diff_2}) > #{total}[#{result_1},#{result_2}] > #{rank}"
218
+ end
219
+
220
+ def getFullAutoResult(command)
221
+ return nil unless /^FAR\((-?\d+),(-?\d+),(-?\d+)(?:,(-?\d+)?)?(?:,(-?\w+)?)?(?:,(-?\d+)?)?\)/i =~ command
222
+
223
+ bullet_count = Regexp.last_match(1).to_i
224
+ diff = Regexp.last_match(2).to_i
225
+ broken_number = Regexp.last_match(3).to_i
226
+ bonus_dice_count = (Regexp.last_match(4) || 0).to_i
227
+ stop_count = (Regexp.last_match(5) || "").to_s.downcase
228
+ bullet_set_count_cap = (Regexp.last_match(6) || diff / 10).to_i
229
+
230
+ output = ""
231
+
232
+ # 最大で(8回*(PC技能値最大値/10))=72発しか撃てないはずなので上限
233
+ bullet_count_limit = 100
234
+ if bullet_count > bullet_count_limit
235
+ output += "弾薬が多すぎます。装填された弾薬を#{bullet_count_limit}発に変更します。\n"
236
+ bullet_count = bullet_count_limit
237
+ end
238
+
239
+ # ボレーの上限の設定がおかしい場合の注意表示
240
+ if (bullet_set_count_cap > diff / 10) && (diff > 39) && !Regexp.last_match(6).nil?
241
+ bullet_set_count_cap = diff / 10
242
+ output += "ボレーの弾丸の数の上限は\[技能値÷10(切り捨て)\]発なので、それより高い数を指定できません。ボレーの弾丸の数を#{bullet_set_count_cap}発に変更します。\n"
243
+ elsif (diff <= 39) && (bullet_set_count_cap > 3) && !Regexp.last_match(6).nil?
244
+ bullet_set_count_cap = 3
245
+ output += "技能値が39以下ではボレーの弾丸の数の上限および下限は3発です。ボレーの弾丸の数を#{bullet_set_count_cap}発に変更します。\n"
246
+ end
247
+
248
+ # ボレーの下限の設定がおかしい場合の注意表示およびエラー表示
249
+ return "ボレーの弾丸の数は正の数です。" if (bullet_set_count_cap <= 0) && !Regexp.last_match(6).nil?
250
+
251
+ if (bullet_set_count_cap < 3) && !Regexp.last_match(6).nil?
252
+ bullet_set_count_cap = 3
253
+ output += "ボレーの弾丸の数の下限は3発です。ボレーの弾丸の数を3発に変更します。\n"
254
+ end
255
+
256
+ return "弾薬は正の数です。" if bullet_count <= 0
257
+ return "目標値は正の数です。" if diff <= 0
258
+
259
+ if broken_number < 0
260
+ output += "故障ナンバーは正の数です。マイナス記号を外します。\n"
261
+ broken_number = broken_number.abs
262
+ end
263
+
264
+ unless @bonus_dice_range.include?(bonus_dice_count)
265
+ return "エラー。ボーナス・ペナルティダイスの値は#{@bonus_dice_range.min}~#{@bonus_dice_range.max}です。"
266
+ end
267
+
268
+ output += "ボーナス・ペナルティダイス[#{bonus_dice_count}]"
269
+ output += rollFullAuto(bullet_count, diff, broken_number, bonus_dice_count, stop_count, bullet_set_count_cap)
270
+
271
+ return output
272
+ end
273
+
274
+ def rollFullAuto(bullet_count, diff, broken_number, dice_num, stop_count, bullet_set_count_cap)
275
+ output = ""
276
+ loopCount = 0
277
+
278
+ counts = {
279
+ hit_bullet: 0,
280
+ impale_bullet: 0,
281
+ bullet: bullet_count,
282
+ }
283
+
284
+ # 難易度変更用ループ
285
+ (0..3).each do |more_difficulty|
286
+ output += getNextDifficultyMessage(more_difficulty)
287
+
288
+ # ペナルティダイスを減らしながらロール用ループ
289
+ while dice_num >= @bonus_dice_range.min
290
+
291
+ loopCount += 1
292
+ hit_result, total, total_list = getHitResultInfos(dice_num, diff, more_difficulty)
293
+ output += "\n#{loopCount}回目: > #{total_list.join(', ')} > #{hit_result}"
294
+
295
+ if total >= broken_number
296
+ output += " ジャム"
297
+ return getHitResultText(output, counts)
298
+ end
299
+
300
+ hit_type = getHitType(more_difficulty, hit_result)
301
+ hit_bullet, impale_bullet, lost_bullet = getBulletResults(counts[:bullet], hit_type, diff, bullet_set_count_cap)
302
+
303
+ output += " (#{hit_bullet}発が命中、#{impale_bullet}発が貫通)"
304
+
305
+ counts[:hit_bullet] += hit_bullet
306
+ counts[:impale_bullet] += impale_bullet
307
+ counts[:bullet] -= lost_bullet
308
+
309
+ return getHitResultText(output, counts) if counts[:bullet] <= 0
310
+
311
+ dice_num -= 1
312
+ end
313
+
314
+ # 指定された難易度となった場合、連射処理を途中で止める
315
+ if shouldStopRollFullAuto?(stop_count, more_difficulty)
316
+ output += "\n【指定の難易度となったので、処理を終了します。】"
317
+ break
318
+ end
319
+
320
+ dice_num += 1
321
+ end
322
+
323
+ return getHitResultText(output, counts)
324
+ end
325
+
326
+ # 連射処理を止める条件(難易度の閾値)
327
+ # @return [Hash<String, Integer>]
328
+ #
329
+ # 成功の種類の小文字表記 => 難易度の閾値
330
+ ROLL_FULL_AUTO_DIFFICULTY_THRESHOLD = {
331
+ # レギュラー
332
+ 'r' => 0,
333
+ # ハード
334
+ 'h' => 1,
335
+ # イクストリーム
336
+ 'e' => 2
337
+ }.freeze
338
+
339
+ # 連射処理を止めるべきかどうかを返す
340
+ # @param [String] stop_count 成功の種類
341
+ # @param [Integer] difficulty 難易度
342
+ # @return [Boolean]
343
+ def shouldStopRollFullAuto?(stop_count, difficulty)
344
+ difficulty_threshold = ROLL_FULL_AUTO_DIFFICULTY_THRESHOLD[stop_count]
345
+ return difficulty_threshold && difficulty >= difficulty_threshold
346
+ end
347
+
348
+ def getHitResultInfos(dice_num, diff, more_difficulty)
349
+ total, total_list = roll_with_bonus(dice_num)
350
+
351
+ fumbleable = getFumbleable(more_difficulty)
352
+ hit_result = getCheckResultText(total, diff, fumbleable)
353
+
354
+ return hit_result, total, total_list
355
+ end
356
+
357
+ def getHitResultText(output, counts)
358
+ return "#{output}\n> #{counts[:hit_bullet]}発が通常命中、#{counts[:impale_bullet]}発が貫通、残弾#{counts[:bullet]}発"
359
+ end
360
+
361
+ def getHitType(more_difficulty, hit_result)
362
+ successList, impaleBulletList = getSuccessListImpaleBulletList(more_difficulty)
363
+
364
+ return :hit if successList.include?(hit_result)
365
+ return :impale if impaleBulletList.include?(hit_result)
366
+
367
+ return ""
368
+ end
369
+
370
+ def getBulletResults(bullet_count, hit_type, diff, bullet_set_count_cap)
371
+ bullet_set_count = getSetOfBullet(diff, bullet_set_count_cap)
372
+ hit_bullet_count_base = getHitBulletCountBase(diff, bullet_set_count)
373
+ impale_bullet_count_base = (bullet_set_count / 2.to_f)
374
+
375
+ lost_bullet_count = 0
376
+ hit_bullet_count = 0
377
+ impale_bullet_count = 0
378
+
379
+ if !isLastBulletTurn(bullet_count, bullet_set_count)
380
+
381
+ case hit_type
382
+ when :hit
383
+ hit_bullet_count = hit_bullet_count_base # 通常命中した弾数の計算
384
+
385
+ when :impale
386
+ impale_bullet_count = impale_bullet_count_base.floor # 貫通した弾数の計算
387
+ hit_bullet_count = impale_bullet_count_base.ceil
388
+ end
389
+
390
+ lost_bullet_count = bullet_set_count
391
+
392
+ else
393
+
394
+ case hit_type
395
+ when :hit
396
+ hit_bullet_count = getLastHitBulletCount(bullet_count)
397
+
398
+ when :impale
399
+ impale_bullet_count = getLastHitBulletCount(bullet_count)
400
+ hit_bullet_count = bullet_count - impale_bullet_count
401
+ end
402
+
403
+ lost_bullet_count = bullet_count
404
+ end
405
+
406
+ return hit_bullet_count, impale_bullet_count, lost_bullet_count
407
+ end
408
+
409
+ def getSuccessListImpaleBulletList(more_difficulty)
410
+ successList = []
411
+ impaleBulletList = []
412
+
413
+ case more_difficulty
414
+ when 0
415
+ successList = ["ハード成功", "レギュラー成功"]
416
+ impaleBulletList = ["クリティカル", "イクストリーム成功"]
417
+ when 1
418
+ successList = ["ハード成功"]
419
+ impaleBulletList = ["クリティカル", "イクストリーム成功"]
420
+ when 2
421
+ successList = []
422
+ impaleBulletList = ["クリティカル", "イクストリーム成功"]
423
+ when 3
424
+ successList = ["クリティカル"]
425
+ impaleBulletList = []
426
+ end
427
+
428
+ return successList, impaleBulletList
429
+ end
430
+
431
+ def getNextDifficultyMessage(more_difficulty)
432
+ case more_difficulty
433
+ when 1
434
+ return "\n【難易度がハードに変更】"
435
+ when 2
436
+ return "\n【難易度がイクストリームに変更】"
437
+ when 3
438
+ return "\n【難易度がクリティカルに変更】"
439
+ end
440
+
441
+ return ""
442
+ end
443
+
444
+ def getSetOfBullet(diff, bullet_set_count_cap)
445
+ bullet_set_count = diff / 10
446
+
447
+ if bullet_set_count_cap < bullet_set_count
448
+ bullet_set_count = bullet_set_count_cap
449
+ end
450
+
451
+ if (diff >= 1) && (diff < 30)
452
+ bullet_set_count = 3 # 技能値が29以下での最低値保障処理
453
+ end
454
+
455
+ return bullet_set_count
456
+ end
457
+
458
+ def getHitBulletCountBase(diff, bullet_set_count)
459
+ hit_bullet_count_base = (bullet_set_count / 2)
460
+
461
+ if (diff >= 1) && (diff < 30)
462
+ hit_bullet_count_base = 1 # 技能値29以下での最低値保障
463
+ end
464
+
465
+ return hit_bullet_count_base
466
+ end
467
+
468
+ def isLastBulletTurn(bullet_count, bullet_set_count)
469
+ ((bullet_count - bullet_set_count) < 0)
470
+ end
471
+
472
+ def getLastHitBulletCount(bullet_count)
473
+ # 残弾1での最低値保障処理
474
+ if bullet_count == 1
475
+ return 1
476
+ end
477
+
478
+ count = (bullet_count / 2.to_f).floor
479
+ return count
480
+ end
481
+
482
+ def getFumbleable(more_difficulty)
483
+ # 成功が49以下の出目のみとなるため、ファンブル値は上昇
484
+ return (more_difficulty >= 1)
485
+ end
486
+
487
+ # 表一式
488
+ # 即時の恐怖症表
489
+ def roll_bmr_table()
490
+ total_n = @randomizer.roll_once(10)
491
+ text = MADNESS_REAL_TIME_TABLE[total_n - 1]
492
+
493
+ time_n = @randomizer.roll_once(10)
494
+
495
+ return "狂気の発作(リアルタイム)(#{total_n}) > #{text}(1D10>#{time_n}ラウンド)"
496
+ end
497
+
498
+ MADNESS_REAL_TIME_TABLE = [
499
+ '健忘症:探索者は、最後に安全な場所にいた時からあとに起こった出来事の記憶を持たない。例えば、朝食を食べていた次の瞬間には怪物と向かい合っている。これは1D10ラウンド続く。',
500
+ '身体症状症:探索者は1D10ラウンドの間、狂気によって視覚や聴覚に異常が生じたり、四肢の1つまたは複数が動かなくなる。',
501
+ '暴力衝動:赤い霧が探索者に降り、1D10ラウンドの間、抑えの利かない暴力と破壊を敵味方を問わず周囲に向かって爆発させる。',
502
+ '偏執症:探索者は1D10ラウンドの間、重い偏執症に襲われる。誰もが探索者に襲い掛かろうとしている。信用できる者はいない。監視されている。裏切ったやつがいる。これはわなだ。',
503
+ '重要な人々:探索者のバックストーリーの重要な人々を見直す。探索者はその場にいた人物を、自分にとっての重要な人々だと思い込む。人間関係の性質を考慮した上で、探索者はそれに従って行動する。1D10ラウンド続く。',
504
+ '失神:探索者は失神する。1D10ラウンド後に回復する。',
505
+ 'パニックになって逃亡する:探索者は利用できるあらゆる手段を使って、可能なかぎり遠くへ逃げ出さずにはいられない。それが唯一の車両を奪って仲間を置き去りにすることであっても。探索者は1D10ラウンドの間、逃げ続ける。',
506
+ '身体的ヒステリーもしくは感情爆発:探索者は1D10ラウンドの間、笑ったり、泣いたり、あるいは叫んだりし続け、行動できなくなる。',
507
+ '恐怖症:探索者は新しい恐怖症に陥る。恐怖症表(PHコマンド)をロールするか、キーパーが恐怖症を1つ選ぶ。恐怖症の原因は存在しなくとも、その探索者は次の1D10ラウンドの間、それがそこにあると思い込む。',
508
+ 'マニア:探索者は新しいマニアに陥る。マニア表(MAコマンド)をロールするか、キーパーがマニアを1つ選ぶ。その探索者は次の1D10ラウンドの間、自分の新しいマニアに没頭しようとする。'
509
+ ].freeze
510
+
511
+ # 略式の恐怖表
512
+ def roll_bms_table()
513
+ total_n = @randomizer.roll_once(10)
514
+ text = MADNESS_SUMMARY_TABLE[total_n - 1]
515
+
516
+ time_n = @randomizer.roll_once(10)
517
+
518
+ return "狂気の発作(サマリー)(#{total_n}) > #{text}(1D10>#{time_n}時間)"
519
+ end
520
+
521
+ MADNESS_SUMMARY_TABLE = [
522
+ '健忘症:探索者が意識を取り戻すと、見知らぬ場所におり、自分が誰かもわからない。記憶は時間をかけてゆっくりと戻るだろう。',
523
+ '盗難:探索者は1D10時間後に意識を取り戻すが、盗難の被害を受けている。傷つけられてはいない。探索者が秘蔵の品を身に着けていた場合(「探索者のバックストーリー」参照)、〈幸運〉ロールを行い、それが盗まれていないか判定する。値打ちのあるものはすべて自動的に失われる。',
524
+ '暴行:探索者は1D10時間後に意識を取り戻し、自分が暴行を受け、傷ついていることに気づく。耐久力は狂気に陥る前の半分に減少している。ただし重症は生じていない。盗まれたものはない。どのようにダメージが加えられたかは、キーパーに委ねられる。',
525
+ '暴力:探索者は暴力と破壊の噴流を爆発させる。探索者が意識を取り戻した時、その行動を認識し記憶していることもあればそうでないこともある。探索者が暴力を振るった物、もしくは人、そして相手を殺してしまったのか、あるいは単に傷つけただけなのかはキーパーに委ねられる。',
526
+ 'イデオロギー/信念:探索者のバックストーリーのイデオロギーと信念を参照する。探索者はこれらの1つの権化となり、急進的かつ狂気じみて、感情もあらわに主張するようになる。例えば、宗教に関係する者は、その後地下鉄で声高に福音を説教しているところを目撃されるかもしれない。',
527
+ '重要な人々:探索者のバックストーリーの重要な人々を参照し、なぜその人物との関係が重要かを考える。時間がたってから(1D10時間以上)、探索者はその人物に近づくための最善の行動、そしてその人物との関係にとって最善の行動をとる。',
528
+ '収容:探索者は精神療養施設あるいは警察の留置所で意識を取り戻す。探索者は徐々にそこにいたった出来事を思い出すかもしれない。',
529
+ 'パニック:探索者は非常に遠い場所で意識を取り戻す。荒野で道に迷っているか、列車に乗っているか、長距離バスに乗っているかもしれない。',
530
+ '恐怖症:探索者は新たな恐怖症を獲得する。恐怖症表(PHコマンド)をロールするか、キーパーがどれか1つ選ぶ。探索者は1D10時間後に意識を取り戻し、この新たな恐怖症の対象を避けるためにあらゆる努力をする。',
531
+ 'マニア:探索者は新たなマニアを獲得する。マニア表(MAコマンド)をロールするか、キーパーがどれか1つ選ぶ。この狂気の発作の間、探索者はこの新たなマニアに完全に溺れているだろう。これがほかの人々に気づかれるかどうかは、キーパーとプレイヤーに委ねられる。'
532
+ ].freeze
533
+
534
+ # キャスティング・ロールのプッシュに失敗した場合(小)
535
+ FAILED_CASTING_L_TABLE = [
536
+ '視界がぼんやりするか、あるいは一時的な失明。',
537
+ '悲鳴、声、あるいはほかの雑音が肉体から発せられる。',
538
+ '強風やほかの大気の現象。',
539
+ '術者、ほかのその場に居合わせた者が出血する。あるいは環境(例えば、壁)から出血する。',
540
+ '奇妙な幻視と幻覚。',
541
+ 'その付近の小動物たちが爆発する。',
542
+ '硫黄の悪臭。',
543
+ 'クトゥルフ神話の怪物が偶然召喚される。'
544
+ ].freeze
545
+
546
+ # キャスティング・ロールのプッシュに失敗した場合(大)
547
+ FAILED_CASTING_M_TABLE = [
548
+ '大地が震え、壁に亀裂が入って崩れる。',
549
+ '叙事詩的な電撃。',
550
+ '血が空から降る。',
551
+ '術者の手がしなび、焼けただれる。',
552
+ '術者は不自然に年をとる(年齢に+2D10歳、30ページの「年齢」を参照し、能力値に修正を適用すること)。',
553
+ '強力な、あるいは無数のクトゥルフ神話存在が現れ、術者を手始めに、近くの全員を攻撃する!',
554
+ '術者や近くの全員が遠い時代か場所に吸い込まれる。',
555
+ 'クトゥルフ神話の神格が偶然招来される。'
556
+ ].freeze
557
+
558
+ # 恐怖症表
559
+ PHOBIAS_TABLE = [
560
+ '入浴恐怖症:体、手、顔を洗うのが怖い。',
561
+ '高所恐怖症:高いところが怖い。',
562
+ '飛行恐怖症:飛ぶのが怖い。',
563
+ '広場恐怖症:広場、公共の(混雑した)場所が怖い。',
564
+ '鶏肉恐怖症:鶏肉が怖い。',
565
+ 'ニンニク恐怖症:ニンニクが怖い。',
566
+ '乗車恐怖症:車両の中にいたり車両に乗るのが怖い。',
567
+ '風恐怖症:風が怖い。',
568
+ '男性恐怖症:男性が怖い。',
569
+ 'イングランド恐怖症:イングランド、もしくはイングランド文化などが怖い。',
570
+ '花恐怖症:花が怖い。',
571
+ '切断恐怖症:手足や指などが切断された人が怖い。',
572
+ 'クモ恐怖症:クモが怖い。',
573
+ '稲妻恐怖症:稲妻が怖い。',
574
+ '廃墟恐怖症:廃墟が怖い。',
575
+ '笛恐怖症:笛(フルート)が怖い。',
576
+ '細菌恐怖症:細菌、バクテリアが怖い。',
577
+ '銃弾恐怖症:投擲物や銃弾が怖い。',
578
+ '落下恐怖症:落下が怖い。',
579
+ '書物恐怖症:本が怖い。',
580
+ '植物恐怖症:植物が怖い。',
581
+ '美女恐怖症:美しい女性が怖い。',
582
+ '低温恐怖症:冷たいものが怖い。',
583
+ '時計恐怖症:時計が怖い。',
584
+ '閉所恐怖症:壁に囲まれた場所が怖い。',
585
+ '道化師恐怖症:道化師が怖い。',
586
+ '犬恐怖症:犬が怖い。',
587
+ '悪魔恐怖症:悪魔が怖い。',
588
+ '群集恐怖症:人混みが怖い。',
589
+ '歯科医恐怖症:歯科医が怖い。',
590
+ '処分恐怖症:物を捨てるのが怖い(ためこみ症)',
591
+ '毛皮恐怖症:毛皮が怖い。',
592
+ '構断恐怖症:道路を横断するのが怖い。',
593
+ '教会恐怖症:教会が怖い。',
594
+ '鏡恐怖症:鏡が怖い。',
595
+ 'ピン恐怖症:針やピンが怖い。',
596
+ '昆虫恐怖症:昆虫が怖い。',
597
+ '猫恐怖症:猫が怖い。',
598
+ '橋恐怖症:橋を渡るのが怖い。',
599
+ '老人恐怖症:老人や年をとることが怖い。',
600
+ '女性恐怖症:女性が怖い。',
601
+ '血液恐怖症:血が怖い。',
602
+ '過失恐怖症:失敗が怖い。',
603
+ '接触恐怖症:触ることが怖い。',
604
+ '爬虫類恐怖症:爬虫類が怖い。',
605
+ '霧恐怖症:霧が怖い。',
606
+ '銃器恐怖症:銃器が怖い。',
607
+ '水恐怖症:水が怖い。',
608
+ '睡眠恐怖症:眠ったり、催眠状態に陥るのが怖い。',
609
+ '医師恐怖症:医師が怖い。',
610
+ '魚恐怖症:魚が怖い。',
611
+ 'ゴキブリ恐怖症:ゴキブリが怖い。',
612
+ '雷鳴恐怖症:雷鳴が怖い。',
613
+ '野菜恐怖症:野菜が怖い。',
614
+ '大騒音恐怖症:大きな騒音が怖い。',
615
+ '湖恐怖症:湖が怖い。',
616
+ '機械恐怖症:機械や装置が怖い。',
617
+ '巨大物恐怖症:巨大なものが怖い。',
618
+ '拘束恐怖症:縛られたり結びつけられたりするのが怖い。',
619
+ '隕石恐怖症:流星や隕石が怖い。',
620
+ '孤独恐怖症:独りでいることが怖い。',
621
+ '汚染恐怖症:汚れたり汚染されたりするのが怖い。',
622
+ '粘液恐怖症:粘液、粘体が怖い。',
623
+ '死体恐怖症:死体が怖い。',
624
+ '8恐怖症:8の数字が怖い。',
625
+ '歯恐怖症:歯が怖い。',
626
+ '夢恐怖症:夢が怖い。',
627
+ '名称恐怖症:特定の言葉(1つまたは複数)を聞くのが怖い。',
628
+ '蛇恐怖症:蛇が怖い。',
629
+ '鳥恐怖症:鳥が怖い。',
630
+ '寄生生物恐怖症:寄生生物が怖い。',
631
+ '人形恐怖症:人形が怖い。',
632
+ '恐食症:のみ込むこと食べること、もしくは食べられることが怖い。',
633
+ '薬物恐怖症:薬物が怖い。',
634
+ '幽霊恐怖症:幽霊が怖い。',
635
+ '羞明:日光が怖い。',
636
+ 'ひげ恐怖症:ひげが怖い',
637
+ '河川恐怖症:川が怖い',
638
+ 'アルコール恐怖症:アルコールやアルコール飲料が怖い。',
639
+ '火恐怖症:火が怖い。',
640
+ '魔術恐怖症:魔術が怖い。',
641
+ '暗黒恐怖症:暗闇や夜が怖い。',
642
+ '月恐怖症:月が怖い。',
643
+ '鉄道恐怖症:列車の旅が怖い。',
644
+ '星恐怖症:星が怖い。',
645
+ '狭所恐怖症:狭いものや場所が怖い。',
646
+ '対称恐怖症:左右対称が怖い。',
647
+ '生き埋め恐怖症:生き埋めになることや墓地が怖い。',
648
+ '雄牛恐怖症:雄牛が怖い。',
649
+ '電話恐怖症:電話が怖い。',
650
+ '奇形恐怖症:怪物が怖い。',
651
+ '海洋恐怖症:海が怖い。',
652
+ '手術恐怖症:外科手術が怖い。',
653
+ '13恐怖症:13の数字が怖い。',
654
+ '衣類恐怖症:衣服が怖い。',
655
+ '魔女恐怖症:魔女と魔術が怖い。',
656
+ '黄色恐怖症:黄色や「黄色」という言葉が怖い。',
657
+ '外国語恐怖症:外国語が怖い。',
658
+ '外国人恐怖症:外国人が怖い。',
659
+ '動物恐怖症:動物が怖い。',
660
+ ].freeze
661
+
662
+ # マニア表
663
+ MANIAS_TABLE = [
664
+ '洗浄マニア:自分の体を洗わずにはいられない。',
665
+ '無為マニア:病的な優柔不断。',
666
+ '暗闇マニア:暗黒に関する過度の嗜好。',
667
+ '高所マニア:高い場所に登らずにはいられない。',
668
+ '善良マニア:病的な親切。',
669
+ '広場マニア:開けた場所にいたいという激しい願望。',
670
+ '先鋭マニア:鋭いもの、とがったものへの執着。',
671
+ '猫マニア:猫に関する異常な愛好心。',
672
+ '疼痛性愛:痛みへの執着。',
673
+ 'にんにくマニア:にんにくへの執着。',
674
+ '乗り物マニア:車の中にいることへの執着。',
675
+ '病的快活:不合理なほがらかさ。',
676
+ '花マニア:花への執着。',
677
+ '計算マニア:数への偏執的な没頭。',
678
+ '浪費マニア:衝動的あるいは無謀な浪費。',
679
+ '自己マニア:孤独への過度の嗜好。',
680
+ 'バレエマニア:バレエに関する異常な愛好心。',
681
+ '書籍約盗癖:本を盗みたいという強迫的衝動。',
682
+ '書物マニア:本または読書、あるいはその両方への執着。',
683
+ '歯ぎしりマニア:歯ぎしりしたいという強迫的衝動。',
684
+ '悪霊マニア:誰かの中に邪悪な精霊がいるという病的な信念。',
685
+ '自己愛マニア:自分自身の美への執着。',
686
+ '地図マニア:いたる所の地図を見る制御不可能な強迫的衝動。',
687
+ '飛び降りマニア:高い場所から跳躍することへの執着。',
688
+ '寒冷マニア:冷たさ、または冷たいもの、あるいはその両方への異常な欲望。',
689
+ '舞踏マニア:踊ることへの愛好もしくは制御不可能な熱狂。',
690
+ '睡眠マニア:寝ることへの過度の願望。',
691
+ '墓地マニア:墓地への執着。',
692
+ '色彩マニア:特定の色への執着。',
693
+ 'ピエロマニア:ピエロへの執着。',
694
+ '遭遇マニア:恐ろしい状況を経験したいという強迫的衝動。',
695
+ '殺害マニア:殺害への執着。',
696
+ '悪魔マニア:誰かが悪魔にとりつかれているという病的な信念。',
697
+ '皮膚マニア:人の皮膚を引っぱりたいという強迫的衝動。',
698
+ '正義マニア:正義が完遂されるのを見たいという執着。',
699
+ 'アルコールマニア:アルコールに関する異常な欲求。',
700
+ '毛皮マニア:毛皮を所有することへの執着。',
701
+ '贈り物マニア:贈り物を与えることへの執着。',
702
+ '逃走マニア:逃走することへの迫的衝動。',
703
+ '外出マニア:外を歩き回ることの強迫的衝動。',
704
+ '自己中心マニア:不合理な自心の態度か自己崇拝。',
705
+ '公職マニア:公的な職業に就きいという強欲な衝動。',
706
+ '戦慄マニア:誰かが罪を犯したという病的な信念',
707
+ '知識マニア:知識を得ることへ執着。',
708
+ '静寂マニア:静寂であることへ強迫的衝動。',
709
+ 'エーテルマニア:エーテルへの切望',
710
+ '求婚マニア:奇妙な求婚をすることへの執着。',
711
+ '笑いマニア:制御不可能な笑うことへの強迫的衝動。',
712
+ '魔術マニア:魔女と魔術への執着。',
713
+ '筆記マニア:すべてを書き留めることへの執着。',
714
+ '裸体マニア:裸になりたいという強迫的衝動。',
715
+ '幻想マニア:快い幻想(現実とは関係なく)にとらわれやすい異常な傾向。',
716
+ '蟲マニア:蟲に関する過度の嗜好。',
717
+ '火器マニア:火器への執着。',
718
+ '水マニア:水に関する不合理な渇望。',
719
+ '魚マニア:魚への執着。',
720
+ 'アイコンマニア:像や肖像への執着。',
721
+ 'アイドルマニア:偶像への執着または献身。',
722
+ '情報マニア:事実を集めることへの過度の献身。',
723
+ '絶叫マニア:叫ぶことへの説明できない強迫的衝動。',
724
+ '窃盗マニア:盗むことへの説明できない強迫的衝動。',
725
+ '騒音マニア:大きな、あるいは甲高い騒音を出すことへの制御不可能な強迫的衝動。',
726
+ 'ひもマニア:ひもへの執着。',
727
+ '宝くじマニア:宝くじに参加したいという極度の願望。',
728
+ 'うつマニア:異常に深くふさぎ込む傾向。',
729
+ '巨石マニア:環状列石/立石があると奇妙な考えにとらわれる異常な傾向。',
730
+ '音楽マニア:音楽もしくは特定の旋律への執着。',
731
+ '作詩マニア:詩を書くことへの強欲な願望。',
732
+ '憎悪マニア:何らかの対象あるいはグループの何もかもを憎む執着。',
733
+ '偏執マニア:ただ1つの思想やアイデアへの異常な執着。',
734
+ '虚言マニア:異常なほどにうそをついたり、誇張して話す。',
735
+ '疾病マニア:想像上の病気に苦められる幻想。',
736
+ '記録マニア:あらゆるものを記録に残そうという強迫的衝動。',
737
+ '名前マニア:人々、場所、ものなどの名前への執着',
738
+ '単語マニア:ある単語を繰り返したいという押さえ切れない欲求。',
739
+ '爪損傷マニア:指の爪をむしったりはがそうとする強迫的衝動。',
740
+ '美食マニア:1種類の食物への異常な愛。',
741
+ '不平マニア:不平を言うことへの異常な喜び。',
742
+ '仮面マニア:仮面や覆面を着けたいという強迫的衝動。',
743
+ '幽霊マニア:幽霊への執着。',
744
+ '殺人マニア:殺人への病的な傾向。',
745
+ '光線マニア:光への病的な願望。',
746
+ '放浪マニア:社会の規範に背きたいという異常な欲望。',
747
+ '長者マニア:富への強迫的な欲望。',
748
+ '病的虚言マニア:うそをつきたくてたまらない強迫的衝動。',
749
+ '放火マニア:火をつけることへの強迫的衝動。',
750
+ '質問マニア:質問したいという激しい強迫的衝動。',
751
+ '鼻マニア:鼻をいじりたいという強迫的衝動。',
752
+ '落書きマニア:いらずら書きや落書きへの執着。',
753
+ '列車マニア:列車と鉄道旅行への強い魅了。',
754
+ '知性マニア:誰かが信じられないほど知的であるという幻想。',
755
+ 'テクノマニア:新技術への執着。',
756
+ 'タナトスマニア:誰かが死を招く魔術によって呪われているという信念。',
757
+ '宗教マニア:その人が神であるという信仰。',
758
+ 'かき傷マニア:かき傷をつけることへの強迫的衝動。',
759
+ '手術マニア:外科手術を行なうことへの不合理な嗜好。',
760
+ '抜毛マニア:自分の髪を引き抜くことへの切望。',
761
+ '失明マニア:病的な視覚障害。',
762
+ '異国マニア:外国のものへの執着。',
763
+ '動物マニア:動物への正気でない溺愛。',
764
+ ].freeze
765
+ end
766
+ end
767
+ end