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.
- checksums.yaml +7 -0
- data/.editorconfig +21 -0
- data/.github/.codecov.yaml +10 -0
- data/.github/workflows/coverage.yaml +21 -0
- data/.github/workflows/lint.yaml +13 -0
- data/.github/workflows/test.yml +20 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +96 -0
- data/.rubocop_todo.yml +113 -0
- data/CHANGELOG.md +868 -0
- data/Gemfile +11 -0
- data/LICENSE +29 -0
- data/README.md +38 -0
- data/ROADMAP.md +30 -0
- data/Rakefile +118 -0
- data/bcdice.gemspec +27 -0
- data/bin/repl.rb +21 -0
- data/docs/README.txt +2028 -0
- data/docs/dicebot_sort_key.md +72 -0
- data/docs/how_to_make_dicebot.md +453 -0
- data/lib/bcdice.rb +8 -0
- data/lib/bcdice/arithmetic_evaluator.rb +167 -0
- data/lib/bcdice/base.rb +423 -0
- data/lib/bcdice/command_parser.rb +242 -0
- data/lib/bcdice/common_command.rb +23 -0
- data/lib/bcdice/common_command/add_dice.rb +54 -0
- data/lib/bcdice/common_command/add_dice/node.rb +488 -0
- data/lib/bcdice/common_command/add_dice/parser.rb +282 -0
- data/lib/bcdice/common_command/add_dice/randomizer.rb +48 -0
- data/lib/bcdice/common_command/barabara_dice.rb +57 -0
- data/lib/bcdice/common_command/calc.rb +39 -0
- data/lib/bcdice/common_command/choice.rb +35 -0
- data/lib/bcdice/common_command/d66_dice.rb +63 -0
- data/lib/bcdice/common_command/reroll_dice.rb +190 -0
- data/lib/bcdice/common_command/upper_dice.rb +165 -0
- data/lib/bcdice/common_command/version.rb +26 -0
- data/lib/bcdice/dice_table.rb +8 -0
- data/lib/bcdice/dice_table/chain_table.rb +33 -0
- data/lib/bcdice/dice_table/d66_grid_table.rb +26 -0
- data/lib/bcdice/dice_table/d66_range_table.rb +26 -0
- data/lib/bcdice/dice_table/d66_table.rb +34 -0
- data/lib/bcdice/dice_table/range_table.rb +267 -0
- data/lib/bcdice/dice_table/roll_result.rb +43 -0
- data/lib/bcdice/dice_table/sai_fic_skill_table.rb +32 -0
- data/lib/bcdice/dice_table/table.rb +35 -0
- data/lib/bcdice/enum.rb +15 -0
- data/lib/bcdice/format.rb +36 -0
- data/lib/bcdice/game_system.rb +187 -0
- data/lib/bcdice/game_system/AFF2e.rb +141 -0
- data/lib/bcdice/game_system/AceKillerGene.rb +55 -0
- data/lib/bcdice/game_system/Airgetlamh.rb +117 -0
- data/lib/bcdice/game_system/Alsetto.rb +124 -0
- data/lib/bcdice/game_system/Alshard.rb +27 -0
- data/lib/bcdice/game_system/AlterRaise.rb +282 -0
- data/lib/bcdice/game_system/Amadeus.rb +622 -0
- data/lib/bcdice/game_system/Amadeus_Korean.rb +501 -0
- data/lib/bcdice/game_system/AnimaAnimus.rb +96 -0
- data/lib/bcdice/game_system/Arianrhod.rb +50 -0
- data/lib/bcdice/game_system/ArsMagica.rb +149 -0
- data/lib/bcdice/game_system/Avandner.rb +101 -0
- data/lib/bcdice/game_system/BBN.rb +143 -0
- data/lib/bcdice/game_system/BadLife.rb +435 -0
- data/lib/bcdice/game_system/BarnaKronika.rb +188 -0
- data/lib/bcdice/game_system/BattleTech.rb +530 -0
- data/lib/bcdice/game_system/BeastBindTrinity.rb +348 -0
- data/lib/bcdice/game_system/BeginningIdol.rb +2527 -0
- data/lib/bcdice/game_system/BeginningIdol_Korean.rb +2378 -0
- data/lib/bcdice/game_system/BladeOfArcana.rb +252 -0
- data/lib/bcdice/game_system/BlindMythos.rb +460 -0
- data/lib/bcdice/game_system/BloodCrusade.rb +423 -0
- data/lib/bcdice/game_system/BloodMoon.rb +213 -0
- data/lib/bcdice/game_system/CardRanker.rb +249 -0
- data/lib/bcdice/game_system/ChaosFlare.rb +181 -0
- data/lib/bcdice/game_system/Chill.rb +163 -0
- data/lib/bcdice/game_system/Chill3.rb +52 -0
- data/lib/bcdice/game_system/CodeLayerd.rb +132 -0
- data/lib/bcdice/game_system/ColossalHunter.rb +569 -0
- data/lib/bcdice/game_system/CrashWorld.rb +81 -0
- data/lib/bcdice/game_system/Cthulhu.rb +252 -0
- data/lib/bcdice/game_system/Cthulhu7th.rb +767 -0
- data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb +386 -0
- data/lib/bcdice/game_system/Cthulhu7th_Korean.rb +383 -0
- data/lib/bcdice/game_system/CthulhuTech.rb +263 -0
- data/lib/bcdice/game_system/Cthulhu_ChineseTraditional.rb +243 -0
- data/lib/bcdice/game_system/Cthulhu_Korean.rb +240 -0
- data/lib/bcdice/game_system/DarkBlaze.rb +207 -0
- data/lib/bcdice/game_system/DarkDaysDrive.rb +425 -0
- data/lib/bcdice/game_system/DarkSouls.rb +91 -0
- data/lib/bcdice/game_system/DeadlineHeroes.rb +583 -0
- data/lib/bcdice/game_system/DemonParasite.rb +524 -0
- data/lib/bcdice/game_system/DetatokoSaga.rb +310 -0
- data/lib/bcdice/game_system/DetatokoSaga_Korean.rb +310 -0
- data/lib/bcdice/game_system/DiceBot.rb +17 -0
- data/lib/bcdice/game_system/DiceOfTheDead.rb +111 -0
- data/lib/bcdice/game_system/DoubleCross.rb +373 -0
- data/lib/bcdice/game_system/DoubleCross_Korean.rb +371 -0
- data/lib/bcdice/game_system/Dracurouge.rb +1856 -0
- data/lib/bcdice/game_system/Dracurouge_Korean.rb +310 -0
- data/lib/bcdice/game_system/DungeonsAndDragons.rb +19 -0
- data/lib/bcdice/game_system/EarthDawn.rb +225 -0
- data/lib/bcdice/game_system/EarthDawn3.rb +275 -0
- data/lib/bcdice/game_system/EarthDawn4.rb +272 -0
- data/lib/bcdice/game_system/EclipsePhase.rb +51 -0
- data/lib/bcdice/game_system/Elric.rb +36 -0
- data/lib/bcdice/game_system/Elysion.rb +1213 -0
- data/lib/bcdice/game_system/EmbryoMachine.rb +227 -0
- data/lib/bcdice/game_system/EndBreaker.rb +132 -0
- data/lib/bcdice/game_system/EtrianOdysseySRS.rb +27 -0
- data/lib/bcdice/game_system/Fiasco.rb +123 -0
- data/lib/bcdice/game_system/Fiasco_Korean.rb +122 -0
- data/lib/bcdice/game_system/FilledWith.rb +1543 -0
- data/lib/bcdice/game_system/FullMetalPanic.rb +27 -0
- data/lib/bcdice/game_system/FutariSousa.rb +994 -0
- data/lib/bcdice/game_system/FutariSousa_Korean.rb +994 -0
- data/lib/bcdice/game_system/Garako.rb +559 -0
- data/lib/bcdice/game_system/GardenOrder.rb +451 -0
- data/lib/bcdice/game_system/GehennaAn.rb +136 -0
- data/lib/bcdice/game_system/GeishaGirlwithKatana.rb +120 -0
- data/lib/bcdice/game_system/GoblinSlayer.rb +168 -0
- data/lib/bcdice/game_system/GoldenSkyStories.rb +77 -0
- data/lib/bcdice/game_system/Gorilla.rb +44 -0
- data/lib/bcdice/game_system/GranCrest.rb +518 -0
- data/lib/bcdice/game_system/Gundog.rb +52 -0
- data/lib/bcdice/game_system/GundogRevised.rb +294 -0
- data/lib/bcdice/game_system/GundogZero.rb +261 -0
- data/lib/bcdice/game_system/Gurps.rb +403 -0
- data/lib/bcdice/game_system/GurpsFW.rb +2330 -0
- data/lib/bcdice/game_system/HarnMaster.rb +208 -0
- data/lib/bcdice/game_system/HatsuneMiku.rb +706 -0
- data/lib/bcdice/game_system/Hieizan.rb +48 -0
- data/lib/bcdice/game_system/HouraiGakuen.rb +270 -0
- data/lib/bcdice/game_system/HuntersMoon.rb +503 -0
- data/lib/bcdice/game_system/Illusio.rb +89 -0
- data/lib/bcdice/game_system/InfiniteFantasia.rb +51 -0
- data/lib/bcdice/game_system/Insane.rb +822 -0
- data/lib/bcdice/game_system/Insane_Korean.rb +773 -0
- data/lib/bcdice/game_system/IthaWenUa.rb +38 -0
- data/lib/bcdice/game_system/JamesBond.rb +45 -0
- data/lib/bcdice/game_system/Kamigakari.rb +394 -0
- data/lib/bcdice/game_system/Kamigakari_Korean.rb +428 -0
- data/lib/bcdice/game_system/KanColle.rb +938 -0
- data/lib/bcdice/game_system/KemonoNoMori.rb +258 -0
- data/lib/bcdice/game_system/KillDeathBusiness.rb +1420 -0
- data/lib/bcdice/game_system/KillDeathBusiness_Korean.rb +1510 -0
- data/lib/bcdice/game_system/KurayamiCrying.rb +49 -0
- data/lib/bcdice/game_system/LiveraDoll.rb +375 -0
- data/lib/bcdice/game_system/LogHorizon.rb +3567 -0
- data/lib/bcdice/game_system/LogHorizon_Korean.rb +1407 -0
- data/lib/bcdice/game_system/LostRecord.rb +30 -0
- data/lib/bcdice/game_system/LostRoyal.rb +242 -0
- data/lib/bcdice/game_system/MagicaLogia.rb +1148 -0
- data/lib/bcdice/game_system/MeikyuDays.rb +415 -0
- data/lib/bcdice/game_system/MeikyuKingdom.rb +466 -0
- data/lib/bcdice/game_system/MeikyuKingdomBasic.rb +269 -0
- data/lib/bcdice/game_system/MetalHead.rb +249 -0
- data/lib/bcdice/game_system/MetalHeadExtream.rb +917 -0
- data/lib/bcdice/game_system/MetallicGuardian.rb +31 -0
- data/lib/bcdice/game_system/MonotoneMuseum.rb +354 -0
- data/lib/bcdice/game_system/MonotoneMuseum_Korean.rb +304 -0
- data/lib/bcdice/game_system/Nechronica.rb +211 -0
- data/lib/bcdice/game_system/Nechronica_Korean.rb +160 -0
- data/lib/bcdice/game_system/NeverCloud.rb +74 -0
- data/lib/bcdice/game_system/NightWizard.rb +231 -0
- data/lib/bcdice/game_system/NightWizard3rd.rb +24 -0
- data/lib/bcdice/game_system/NightmareHunterDeep.rb +117 -0
- data/lib/bcdice/game_system/NinjaSlayer.rb +274 -0
- data/lib/bcdice/game_system/NjslyrBattle.rb +54 -0
- data/lib/bcdice/game_system/Nuekagami.rb +293 -0
- data/lib/bcdice/game_system/OneWayHeroics.rb +134 -0
- data/lib/bcdice/game_system/OracleEngine.rb +265 -0
- data/lib/bcdice/game_system/OrgaRain.rb +77 -0
- data/lib/bcdice/game_system/Oukahoushin3rd.rb +162 -0
- data/lib/bcdice/game_system/Paradiso.rb +323 -0
- data/lib/bcdice/game_system/Paranoia.rb +64 -0
- data/lib/bcdice/game_system/ParanoiaRebooted.rb +109 -0
- data/lib/bcdice/game_system/ParasiteBlood.rb +231 -0
- data/lib/bcdice/game_system/Pathfinder.rb +21 -0
- data/lib/bcdice/game_system/Peekaboo.rb +324 -0
- data/lib/bcdice/game_system/Pendragon.rb +39 -0
- data/lib/bcdice/game_system/PhantasmAdventure.rb +73 -0
- data/lib/bcdice/game_system/Postman.rb +185 -0
- data/lib/bcdice/game_system/PulpCthulhu.rb +184 -0
- data/lib/bcdice/game_system/Raisondetre.rb +171 -0
- data/lib/bcdice/game_system/RecordOfLodossWar.rb +58 -0
- data/lib/bcdice/game_system/RecordOfSteam.rb +149 -0
- data/lib/bcdice/game_system/RokumonSekai2.rb +110 -0
- data/lib/bcdice/game_system/RoleMaster.rb +24 -0
- data/lib/bcdice/game_system/RuneQuest.rb +47 -0
- data/lib/bcdice/game_system/RyuTuber.rb +266 -0
- data/lib/bcdice/game_system/Ryutama.rb +199 -0
- data/lib/bcdice/game_system/SRS.rb +348 -0
- data/lib/bcdice/game_system/SamsaraBallad.rb +111 -0
- data/lib/bcdice/game_system/Satasupe.rb +1173 -0
- data/lib/bcdice/game_system/ScreamHighSchool.rb +128 -0
- data/lib/bcdice/game_system/SevenFortressMobius.rb +34 -0
- data/lib/bcdice/game_system/ShadowRun.rb +26 -0
- data/lib/bcdice/game_system/ShadowRun4.rb +49 -0
- data/lib/bcdice/game_system/ShadowRun5.rb +80 -0
- data/lib/bcdice/game_system/SharedFantasia.rb +69 -0
- data/lib/bcdice/game_system/ShinMegamiTenseiKakuseihen.rb +85 -0
- data/lib/bcdice/game_system/ShinkuuGakuen.rb +506 -0
- data/lib/bcdice/game_system/ShinobiGami.rb +680 -0
- data/lib/bcdice/game_system/ShoujoTenrankai.rb +677 -0
- data/lib/bcdice/game_system/Skynauts.rb +324 -0
- data/lib/bcdice/game_system/SteamPunkers.rb +485 -0
- data/lib/bcdice/game_system/StellarKnights.rb +856 -0
- data/lib/bcdice/game_system/SterileLife.rb +452 -0
- data/lib/bcdice/game_system/StrangerOfSwordCity.rb +103 -0
- data/lib/bcdice/game_system/StratoShout.rb +316 -0
- data/lib/bcdice/game_system/StratoShout_Korean.rb +314 -0
- data/lib/bcdice/game_system/Strave.rb +223 -0
- data/lib/bcdice/game_system/SwordWorld.rb +491 -0
- data/lib/bcdice/game_system/SwordWorld2_0.rb +295 -0
- data/lib/bcdice/game_system/SwordWorld2_5.rb +121 -0
- data/lib/bcdice/game_system/TherapieSein.rb +93 -0
- data/lib/bcdice/game_system/TokumeiTenkousei.rb +96 -0
- data/lib/bcdice/game_system/TokyoGhostResearch.rb +122 -0
- data/lib/bcdice/game_system/TokyoNova.rb +19 -0
- data/lib/bcdice/game_system/Torg.rb +364 -0
- data/lib/bcdice/game_system/Torg1_5.rb +139 -0
- data/lib/bcdice/game_system/TorgEternity.rb +414 -0
- data/lib/bcdice/game_system/TrinitySeven.rb +364 -0
- data/lib/bcdice/game_system/TunnelsAndTrolls.rb +287 -0
- data/lib/bcdice/game_system/TwilightGunsmoke.rb +527 -0
- data/lib/bcdice/game_system/Utakaze.rb +153 -0
- data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +132 -0
- data/lib/bcdice/game_system/Villaciel.rb +555 -0
- data/lib/bcdice/game_system/WARPS.rb +33 -0
- data/lib/bcdice/game_system/WaresBlade.rb +34 -0
- data/lib/bcdice/game_system/Warhammer.rb +336 -0
- data/lib/bcdice/game_system/WitchQuest.rb +275 -0
- data/lib/bcdice/game_system/WorldOfDarkness.rb +135 -0
- data/lib/bcdice/game_system/YankeeYogSothoth.rb +440 -0
- data/lib/bcdice/game_system/YearZeroEngine.rb +134 -0
- data/lib/bcdice/game_system/ZettaiReido.rb +142 -0
- data/lib/bcdice/game_system/meikyu_kingdom/item_table.rb +383 -0
- data/lib/bcdice/game_system/meikyu_kingdom/kingdom_name_table.rb +89 -0
- data/lib/bcdice/game_system/meikyu_kingdom/landscape_table.rb +196 -0
- data/lib/bcdice/game_system/meikyu_kingdom/name_tables.rb +223 -0
- data/lib/bcdice/game_system/meikyu_kingdom/placename_table.rb +214 -0
- data/lib/bcdice/game_system/meikyu_kingdom/tables.rb +610 -0
- data/lib/bcdice/game_system/meikyu_kingdom/word_table.rb +117 -0
- data/lib/bcdice/game_system/meikyu_kingdom_basic/item_table.rb +380 -0
- data/lib/bcdice/game_system/meikyu_kingdom_basic/kingdom_table.rb +184 -0
- data/lib/bcdice/game_system/meikyu_kingdom_basic/name_table.rb +417 -0
- data/lib/bcdice/game_system/meikyu_kingdom_basic/table.rb +912 -0
- data/lib/bcdice/game_system/meikyu_kingdom_basic/word_table.rb +121 -0
- data/lib/bcdice/game_system/one_way_heroics/dungeon_table.rb +67 -0
- data/lib/bcdice/game_system/one_way_heroics/random_event_table.rb +166 -0
- data/lib/bcdice/game_system/one_way_heroics/tables.rb +668 -0
- data/lib/bcdice/loader.rb +37 -0
- data/lib/bcdice/normalize.rb +38 -0
- data/lib/bcdice/preprocessor.rb +87 -0
- data/lib/bcdice/randomizer.rb +137 -0
- data/lib/bcdice/repl.rb +155 -0
- data/lib/bcdice/user_defined_dice_table.rb +153 -0
- data/lib/bcdice/version.rb +3 -0
- 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
|