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,33 @@
|
|
1
|
+
module BCDice
|
2
|
+
module DiceTable
|
3
|
+
class ChainTable
|
4
|
+
# @param [String] name 表の名前
|
5
|
+
# @param [String] type 項目を選ぶときのダイスロールの方法 '1D6'など
|
6
|
+
# @param [Array<String, #roll>] items 表の項目の配列
|
7
|
+
def initialize(name, type, items)
|
8
|
+
@name = name
|
9
|
+
@items = items.freeze
|
10
|
+
|
11
|
+
m = /(\d+)D(\d+)/i.match(type)
|
12
|
+
unless m
|
13
|
+
raise ArgumentError, "Unexpected table type: #{type}"
|
14
|
+
end
|
15
|
+
|
16
|
+
@times = m[1].to_i
|
17
|
+
@sides = m[2].to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
# 表を振る
|
21
|
+
# @param randomizer [#roll_sum] ランダマイザ
|
22
|
+
# @return [String] 結果
|
23
|
+
def roll(randomizer)
|
24
|
+
value = randomizer.roll_sum(@times, @sides)
|
25
|
+
index = value - @times
|
26
|
+
chosen = @items[index]
|
27
|
+
chosen = chosen.roll(randomizer) if chosen.respond_to?(:roll)
|
28
|
+
|
29
|
+
return RollResult.new(@name, value, chosen)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BCDice
|
2
|
+
module DiceTable
|
3
|
+
# D66を振って6x6マスの表を参照する
|
4
|
+
class D66GridTable
|
5
|
+
# @param [String] name 表の名前
|
6
|
+
# @param [Array<Array<String>>] items 表の項目の配列
|
7
|
+
def initialize(name, items)
|
8
|
+
@name = name
|
9
|
+
@items = items.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
# 表を振る
|
13
|
+
# @param randomizer [#roll_once] ランダマイザ
|
14
|
+
# @return [String] 結果
|
15
|
+
def roll(randomizer)
|
16
|
+
dice1 = randomizer.roll_once(6)
|
17
|
+
dice2 = randomizer.roll_once(6)
|
18
|
+
value = dice1 * 10 + dice2
|
19
|
+
|
20
|
+
index1 = dice1 - 1
|
21
|
+
index2 = dice2 - 1
|
22
|
+
return RollResult.new(@name, value, @items[index1][index2])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BCDice
|
2
|
+
module DiceTable
|
3
|
+
# 項目をRangeを用いて参照するD66表
|
4
|
+
class D66RangeTable
|
5
|
+
# @param name [String] 表の名前
|
6
|
+
# @param items [Array<(Range, String)>] 表の項目の配列
|
7
|
+
def initialize(name, items)
|
8
|
+
@name = name
|
9
|
+
@items = items.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
# 表を振る
|
13
|
+
# @param randomizer [#roll_once] ランダマイザ
|
14
|
+
# @return [String] 結果
|
15
|
+
def roll(randomizer)
|
16
|
+
dice1 = randomizer.roll_once(6)
|
17
|
+
dice2 = randomizer.roll_once(6)
|
18
|
+
|
19
|
+
key = dice1 * 10 + dice2
|
20
|
+
|
21
|
+
chosen = @items.find { |row| row[0].include?(key) }
|
22
|
+
return RollResult.new(@name, key, chosen[1])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module BCDice
|
2
|
+
module DiceTable
|
3
|
+
# D66を振って出目を昇順/降順にして表を参照する
|
4
|
+
class D66Table
|
5
|
+
# @param [String] name 表の名前
|
6
|
+
# @param [Symbol] sort_type 出目入れ替えの方式 BCDice::D66SortType
|
7
|
+
# @param [Hash] items 表の項目 Key は数値
|
8
|
+
def initialize(name, sort_type, items)
|
9
|
+
@name = name
|
10
|
+
@sort_type = sort_type
|
11
|
+
@items = items.freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
# 表を振る
|
15
|
+
# @param randomizer [#roll_barabara] ランダマイザ
|
16
|
+
# @return [String] 結果
|
17
|
+
def roll(randomizer)
|
18
|
+
dice = randomizer.roll_barabara(2, 6)
|
19
|
+
|
20
|
+
case @sort_type
|
21
|
+
when D66SortType::ASC
|
22
|
+
dice.sort!
|
23
|
+
when D66SortType::DESC
|
24
|
+
dice.sort!.reverse!
|
25
|
+
end
|
26
|
+
|
27
|
+
key = dice[0] * 10 + dice[1]
|
28
|
+
chosen = @items[key]
|
29
|
+
chosen = chosen.roll(randomizer) if chosen.respond_to?(:roll)
|
30
|
+
return RollResult.new(@name, key, chosen)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BCDice
|
4
|
+
module DiceTable
|
5
|
+
# 各項目について、Rangeを用いて出目の合計の範囲を指定する、表のクラス。
|
6
|
+
#
|
7
|
+
# このクラスを使うと、表の定義を短く書ける。
|
8
|
+
# このクラスを使って表を定義するときは、各項目を以下の形で書く。
|
9
|
+
#
|
10
|
+
# [出目の合計の範囲, 内容]
|
11
|
+
#
|
12
|
+
# 「出目の合計の範囲」には、Integerを要素とするRangeか、Integerを置ける。
|
13
|
+
#
|
14
|
+
# roll メソッドで表を振ると、出目の合計値と対応する項目が選ばれる。
|
15
|
+
#
|
16
|
+
# @example 表の定義(バトルテックの致命的命中表)
|
17
|
+
# CRITICAL_TABLE = RangeTable.new(
|
18
|
+
# '致命的命中表',
|
19
|
+
# '2D6',
|
20
|
+
# [
|
21
|
+
# [2..7, '致命的命中はなかった'],
|
22
|
+
# [8..9, '1箇所の致命的命中'],
|
23
|
+
# [10..11, '2箇所の致命的命中'],
|
24
|
+
# [12, 'その部位が吹き飛ぶ(腕、脚、頭)または3箇所の致命的命中(胴)']
|
25
|
+
# ]
|
26
|
+
# )
|
27
|
+
#
|
28
|
+
# @example 表を振った結果
|
29
|
+
# CRITICAL_TABLE.roll(bcdice).formatted
|
30
|
+
# # 出目の合計が7の場合 :"致命的命中表(7) > 致命的命中はなかった"
|
31
|
+
# # 出目の合計が8の場合 :"致命的命中表(8) > 1箇所の致命的命中"
|
32
|
+
# # 出目の合計が9の場合 :"致命的命中表(9) > 1箇所の致命的命中"
|
33
|
+
# # 出目の合計が10の場合:"致命的命中表(10) > 2箇所の致命的命中"
|
34
|
+
class RangeTable
|
35
|
+
# 表を振った結果を表す構造体
|
36
|
+
# @!attribute [rw] sum
|
37
|
+
# @return [Integer] 出目の合計
|
38
|
+
# @!attribute [rw] values
|
39
|
+
# @return [Array<Integer>] 出目の配列
|
40
|
+
# @!attribute [rw] content
|
41
|
+
# @return [Object] 選ばれた項目の内容
|
42
|
+
# @!attribute [rw] formatted
|
43
|
+
# @return [String] 整形された結果
|
44
|
+
RollResult = Struct.new(:sum, :values, :content, :formatted) do
|
45
|
+
alias_method :to_s, :formatted
|
46
|
+
end
|
47
|
+
|
48
|
+
# 表の項目を表す構造体
|
49
|
+
# @!attribute [rw] range
|
50
|
+
# @return [Range] 出目の合計の範囲
|
51
|
+
# @!attribute [rw] content
|
52
|
+
# @return [Object] 内容
|
53
|
+
Item = Struct.new(:range, :content)
|
54
|
+
|
55
|
+
# 項目を選ぶときのダイスロールの方法を表す正規表現
|
56
|
+
DICE_ROLL_METHOD_RE = /\A(\d+)D(\d+)\z/i.freeze
|
57
|
+
|
58
|
+
# 表を振った結果の整形処理(既定の処理)
|
59
|
+
DEFAULT_FORMATTER = lambda do |table, result|
|
60
|
+
"#{table.name}(#{result.sum}) > #{result.content}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [String] 表の名前
|
64
|
+
attr_reader :name
|
65
|
+
# @return [Integer] 振るダイスの個数
|
66
|
+
attr_reader :num_of_dice
|
67
|
+
# @return [Integer] 振るダイスの面数
|
68
|
+
attr_reader :num_of_sides
|
69
|
+
|
70
|
+
# 表を初期化する
|
71
|
+
#
|
72
|
+
# ブロックを与えると、独自の結果整形処理を指定できる。
|
73
|
+
# ブロックは振った表(+table+)と振った結果(+result+)を引数として受け取る。
|
74
|
+
#
|
75
|
+
# @param [String] name 表の名前
|
76
|
+
# @param [String] dice_roll_method
|
77
|
+
# 項目を選ぶときのダイスロールの方法(+'1D6'+ など)
|
78
|
+
# @param [Array<(Range, Object)>, Array<(Integer, Object)>] items
|
79
|
+
# 表の項目の配列。[出目の合計の範囲, 内容]
|
80
|
+
# @yieldparam [RangeTable] table 振った表
|
81
|
+
# @yieldparam [RollResult] result 表を振った結果
|
82
|
+
# @raise [ArgumentError] ダイスロール方法が正しい書式で指定されていなかった場合
|
83
|
+
# @raise [TypeError] 範囲の型が正しくなかった場合
|
84
|
+
# @raise [RangeError] 出目の合計の最小値がカバーされていなかった場合
|
85
|
+
# @raise [RangeError] 出目の合計の最大値がカバーされていなかった場合
|
86
|
+
# @raise [RangeError] 出目の合計の範囲にずれや重なりがあった場合
|
87
|
+
#
|
88
|
+
# @example 表の定義(バトルテックの致命的命中表)
|
89
|
+
# CRITICAL_TABLE = RangeTable.new(
|
90
|
+
# '致命的命中表',
|
91
|
+
# '2D6',
|
92
|
+
# [
|
93
|
+
# [2..7, '致命的命中はなかった'],
|
94
|
+
# [8..9, '1箇所の致命的命中'],
|
95
|
+
# [10..11, '2箇所の致命的命中'],
|
96
|
+
# [12, 'その部位が吹き飛ぶ(腕、脚、頭)または3箇所の致命的命中(胴)']
|
97
|
+
# ]
|
98
|
+
# )
|
99
|
+
#
|
100
|
+
# @example 独自の結果整形処理を指定する場合
|
101
|
+
# CRITICAL_TABLE_WITH_FORMATTER = RangeTable.new(
|
102
|
+
# '致命的命中表',
|
103
|
+
# '2D6',
|
104
|
+
# [
|
105
|
+
# [2..7, '致命的命中はなかった'],
|
106
|
+
# [8..9, '1箇所の致命的命中'],
|
107
|
+
# [10..11, '2箇所の致命的命中'],
|
108
|
+
# [12, 'その部位が吹き飛ぶ(腕、脚、頭)または3箇所の致命的命中(胴)']
|
109
|
+
# ]
|
110
|
+
# ) do |table, result|
|
111
|
+
# "致命的命中発生? > #{result.sum}[#{result.values}] > #{result.content}"
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# CRITICAL_TABLE_WITH_FORMATTER.roll(bcdice).formatted
|
115
|
+
# #=> "致命的命中発生? > 11[5,6] > 2箇所の致命的命中"
|
116
|
+
def initialize(name, dice_roll_method, items, &formatter)
|
117
|
+
@name = name.freeze
|
118
|
+
@formatter = formatter || DEFAULT_FORMATTER
|
119
|
+
|
120
|
+
m = DICE_ROLL_METHOD_RE.match(dice_roll_method)
|
121
|
+
unless m
|
122
|
+
raise(
|
123
|
+
ArgumentError,
|
124
|
+
"#{@name}: invalid dice roll method: #{dice_roll_method}"
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
@num_of_dice = m[1].to_i
|
129
|
+
@num_of_sides = m[2].to_i
|
130
|
+
|
131
|
+
store(items)
|
132
|
+
end
|
133
|
+
|
134
|
+
# 指定された値に対応する項目を返す
|
135
|
+
# @param [Integer] value 値(出目の合計)
|
136
|
+
# @return [Item] 指定された値に対応する項目
|
137
|
+
# @raise [RangeError] 範囲外の値が指定された場合
|
138
|
+
def fetch(value)
|
139
|
+
item = @items.find { |i| i.range.include?(value) }
|
140
|
+
unless item
|
141
|
+
raise RangeError, "#{@name}: value is out of range: #{value}"
|
142
|
+
end
|
143
|
+
|
144
|
+
return item
|
145
|
+
end
|
146
|
+
|
147
|
+
# 表を振る
|
148
|
+
# @param randomizer [#roll_barabara] ランダマイザ
|
149
|
+
# @return [RollResult] 表を振った結果
|
150
|
+
def roll(randomizer)
|
151
|
+
values = randomizer.roll_barabara(@num_of_dice, @num_of_sides)
|
152
|
+
sum = values.sum()
|
153
|
+
|
154
|
+
result = RollResult.new(sum, values, fetch(sum).content)
|
155
|
+
result.formatted = @formatter[self, result]
|
156
|
+
|
157
|
+
return result
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
# 表の項目を格納する
|
163
|
+
# @param [Array<(Range, Object)>, Array<(Integer, Object)>] items
|
164
|
+
# 表の項目の配列。[出目の合計の範囲, 内容]
|
165
|
+
# @return [self]
|
166
|
+
# @raise [TypeError] 範囲の型が正しくなかった場合
|
167
|
+
# @raise [RangeError] 出目の合計の最小値がカバーされていなかった場合
|
168
|
+
# @raise [RangeError] 出目の合計の最大値がカバーされていなかった場合
|
169
|
+
# @raise [RangeError] 出目の合計の範囲にずれや重なりがあった場合
|
170
|
+
def store(items)
|
171
|
+
items_with_range = items.map { |r, c| [coerce_to_int_range(r), c] }
|
172
|
+
sorted_items = items_with_range.sort_by { |r, _| r.min }
|
173
|
+
|
174
|
+
assert_min_sum_is_covered(sorted_items)
|
175
|
+
assert_max_sum_is_covered(sorted_items)
|
176
|
+
assert_no_gap_or_overlap_in_ranges(sorted_items)
|
177
|
+
|
178
|
+
@items = sorted_items
|
179
|
+
.map { |range, content| Item.new(range, content.freeze).freeze }
|
180
|
+
.freeze
|
181
|
+
|
182
|
+
self
|
183
|
+
end
|
184
|
+
|
185
|
+
# 引数を強制的に整数を要素とするRangeに変換する
|
186
|
+
# @param [Range, Integer] x 変換対象
|
187
|
+
# @return [Range] 整数を要素とするRange
|
188
|
+
# @raise [TypeError] xの型に対応していなかった場合
|
189
|
+
def coerce_to_int_range(x)
|
190
|
+
case x
|
191
|
+
when Integer
|
192
|
+
return Range.new(x, x)
|
193
|
+
when Range
|
194
|
+
if x.begin.is_a?(Integer) && x.end.is_a?(Integer)
|
195
|
+
return x
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
raise(
|
200
|
+
TypeError,
|
201
|
+
"#{@name}: #{x} (#{x.class}) must be an Integer or a Range with Integers "
|
202
|
+
)
|
203
|
+
end
|
204
|
+
|
205
|
+
# 出目の合計の最小値がカバーされていることを確認する
|
206
|
+
# @param [Array<(Range, Object)>] sorted_items
|
207
|
+
# ソートされた、項目の配列
|
208
|
+
# @return [self]
|
209
|
+
# @raise [RangeError] 出目の合計の最小値がカバーされていなかった場合
|
210
|
+
def assert_min_sum_is_covered(sorted_items)
|
211
|
+
min_sum = @num_of_dice
|
212
|
+
range = sorted_items.first[0]
|
213
|
+
unless range.include?(min_sum)
|
214
|
+
raise(
|
215
|
+
RangeError,
|
216
|
+
"#{@name}: min value (#{min_sum}) is not covered: #{range}"
|
217
|
+
)
|
218
|
+
end
|
219
|
+
|
220
|
+
self
|
221
|
+
end
|
222
|
+
|
223
|
+
# 出目の合計の最大値がカバーされていることを確認する
|
224
|
+
# @param [Array<(Range, Object)>] sorted_items
|
225
|
+
# ソートされた、項目の配列
|
226
|
+
# @return [self]
|
227
|
+
# @raise [RangeError] 出目の合計の最大値がカバーされていなかった場合
|
228
|
+
def assert_max_sum_is_covered(sorted_items)
|
229
|
+
max_sum = @num_of_dice * @num_of_sides
|
230
|
+
range = sorted_items.last[0]
|
231
|
+
unless range.include?(max_sum)
|
232
|
+
raise(
|
233
|
+
RangeError,
|
234
|
+
"#{@name}: max value (#{max_sum}) is not covered: #{range}"
|
235
|
+
)
|
236
|
+
end
|
237
|
+
|
238
|
+
self
|
239
|
+
end
|
240
|
+
|
241
|
+
# 出目の合計の範囲にずれや重なりがないことを確認する
|
242
|
+
# @param [Array<(Range, Object)>] sorted_items
|
243
|
+
# ソートされた、項目の配列
|
244
|
+
# @return [self]
|
245
|
+
# @raise [RangeError] 出目の合計の範囲にずれや重なりがあった場合
|
246
|
+
def assert_no_gap_or_overlap_in_ranges(sorted_items)
|
247
|
+
sorted_items.each_cons(2) do |i1, i2|
|
248
|
+
r1 = i1[0]
|
249
|
+
r2 = i2[0]
|
250
|
+
|
251
|
+
max1 = r1.max
|
252
|
+
next_of_max1 = max1 + 1
|
253
|
+
|
254
|
+
if r2.include?(max1)
|
255
|
+
raise RangeError, "#{@name}: Range overlap: #{r1} and #{r2}"
|
256
|
+
end
|
257
|
+
|
258
|
+
unless r2.include?(next_of_max1)
|
259
|
+
raise RangeError, "#{@name}: Range gap: #{r1} and #{r2}"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
self
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module BCDice
|
2
|
+
module DiceTable
|
3
|
+
class RollResult
|
4
|
+
# @param table_name [String]
|
5
|
+
# @param value [Integer]
|
6
|
+
# @param body [String, RollResult]
|
7
|
+
def initialize(table_name, value, body)
|
8
|
+
@table_name = table_name
|
9
|
+
@value = value
|
10
|
+
@body = body
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :table_name
|
15
|
+
|
16
|
+
# @return [Integer]
|
17
|
+
attr_reader :value
|
18
|
+
|
19
|
+
# @return [String, RollResult]
|
20
|
+
attr_reader :body
|
21
|
+
|
22
|
+
# @return [String]
|
23
|
+
def to_s
|
24
|
+
"#{@table_name}(#{@value}) > #{@body}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String]
|
28
|
+
def last_body
|
29
|
+
if @body.is_a?(RollResult)
|
30
|
+
@body.last_body
|
31
|
+
else
|
32
|
+
@body
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# 一部のゲームシステムが String#empty? を想定してチェックしているため
|
37
|
+
# @return [false]
|
38
|
+
def empty?
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module BCDice
|
2
|
+
module DiceTable
|
3
|
+
class SaiFicSkillTable
|
4
|
+
def initialize(items, peekaboo_style: false)
|
5
|
+
@items = items
|
6
|
+
@peekaboo_style = peekaboo_style
|
7
|
+
end
|
8
|
+
|
9
|
+
def roll(randomizer)
|
10
|
+
category_dice = randomizer.roll_once(6)
|
11
|
+
cindex = category_dice - 1
|
12
|
+
category, skill_list = @items[cindex]
|
13
|
+
|
14
|
+
skill_dice = randomizer.roll_sum(2, 6)
|
15
|
+
sindex = skill_dice - 2
|
16
|
+
skill = skill_list[sindex]
|
17
|
+
|
18
|
+
return "ランダム指定特技表(#{category_dice},#{skill_dice}) > #{result(category, skill, skill_dice)}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def result(category, skill, skill_dice)
|
24
|
+
if @peekaboo_style
|
25
|
+
"《#{skill}/#{category}#{skill_dice}》"
|
26
|
+
else
|
27
|
+
"#{category}《#{skill}》"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|