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
data/lib/bcdice.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
module BCDice
|
2
|
+
#
|
3
|
+
# 四則演算を評価するクラス
|
4
|
+
#
|
5
|
+
class ArithmeticEvaluator
|
6
|
+
class << self
|
7
|
+
# 四則演算を評価する
|
8
|
+
# @param expr [String] 評価する式
|
9
|
+
# @param round_type [Symbol] 端数処理の種類
|
10
|
+
# @return [Integer] 評価結果を返す。不正な式の場合には0を返す。
|
11
|
+
def eval(expr, round_type: RoundType::FLOOR)
|
12
|
+
ArithmeticEvaluator.new(expr, round_type: round_type).eval()
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [String, nil] expr 評価する式
|
17
|
+
# @param [Symbol] round_type 端数処理の種類
|
18
|
+
def initialize(expr, round_type: RoundType::FLOOR)
|
19
|
+
@expr = expr
|
20
|
+
@round_type = round_type
|
21
|
+
|
22
|
+
@error = false
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Boolean] 式の評価時にエラーが発生したか
|
26
|
+
def error?
|
27
|
+
@error
|
28
|
+
end
|
29
|
+
|
30
|
+
# 四則演算を評価する
|
31
|
+
# 同一インスタンスでevalを二回以上実行した場合の挙動は未定義とする
|
32
|
+
#
|
33
|
+
# @return [Integer] 評価結果を返す。不正な式の場合には0を返す。
|
34
|
+
def eval
|
35
|
+
if @expr.nil?
|
36
|
+
return 0
|
37
|
+
end
|
38
|
+
|
39
|
+
unless @expr.is_a?(String)
|
40
|
+
raise TypeError, "expr must be String, not #{@expr.class}"
|
41
|
+
end
|
42
|
+
|
43
|
+
@tokens = tokenize(@expr)
|
44
|
+
@idx = 0
|
45
|
+
@error = false
|
46
|
+
|
47
|
+
ret = expr()
|
48
|
+
if @error
|
49
|
+
return 0
|
50
|
+
else
|
51
|
+
return ret
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def tokenize(expr)
|
58
|
+
expr.gsub(%r{[\(\)\+\-\*/]}) { |e| " #{e} " }.split(" ")
|
59
|
+
end
|
60
|
+
|
61
|
+
def add
|
62
|
+
ret = mul()
|
63
|
+
|
64
|
+
loop do
|
65
|
+
if consume("+")
|
66
|
+
ret += mul()
|
67
|
+
elsif consume("-")
|
68
|
+
ret -= mul()
|
69
|
+
else
|
70
|
+
break
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
return ret
|
75
|
+
end
|
76
|
+
alias expr add
|
77
|
+
|
78
|
+
def mul
|
79
|
+
ret = unary()
|
80
|
+
|
81
|
+
loop do
|
82
|
+
if consume("*")
|
83
|
+
ret *= unary()
|
84
|
+
elsif consume("/")
|
85
|
+
ret = div(ret, unary())
|
86
|
+
else
|
87
|
+
break
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
return ret
|
92
|
+
end
|
93
|
+
|
94
|
+
def div(left, right)
|
95
|
+
if right.zero?
|
96
|
+
@error = true
|
97
|
+
return 0
|
98
|
+
end
|
99
|
+
|
100
|
+
case @round_type
|
101
|
+
when RoundType::CEIL
|
102
|
+
return (left.to_f / right).ceil
|
103
|
+
when RoundType::ROUND
|
104
|
+
return (left.to_f / right).round
|
105
|
+
when RoundType::FLOOR
|
106
|
+
return left / right
|
107
|
+
else
|
108
|
+
raise ArgumentError, "unknown round type: #{@round_type.inspect}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def unary
|
113
|
+
if consume("+")
|
114
|
+
unary()
|
115
|
+
elsif consume("-")
|
116
|
+
-unary()
|
117
|
+
else
|
118
|
+
term()
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def term
|
123
|
+
if consume("(")
|
124
|
+
ret = expr()
|
125
|
+
expect(")")
|
126
|
+
return ret
|
127
|
+
else
|
128
|
+
return expect_number()
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def consume(str)
|
133
|
+
if @tokens[@idx] != str
|
134
|
+
return false
|
135
|
+
end
|
136
|
+
|
137
|
+
@idx += 1
|
138
|
+
return true
|
139
|
+
end
|
140
|
+
|
141
|
+
def expect(str)
|
142
|
+
if @tokens[@idx] != str
|
143
|
+
@error = true
|
144
|
+
end
|
145
|
+
|
146
|
+
@idx += 1
|
147
|
+
end
|
148
|
+
|
149
|
+
def expect_number()
|
150
|
+
unless integer?(@tokens[@idx])
|
151
|
+
@error = true
|
152
|
+
@idx += 1
|
153
|
+
return 0
|
154
|
+
end
|
155
|
+
|
156
|
+
ret = @tokens[@idx].to_i
|
157
|
+
@idx += 1
|
158
|
+
return ret
|
159
|
+
end
|
160
|
+
|
161
|
+
def integer?(str)
|
162
|
+
# Ruby 1.9 以降では Kernel.#Integer を使うべき
|
163
|
+
# Ruby 1.8 にもあるが、基数を指定できない問題がある
|
164
|
+
!/^\d+$/.match(str).nil?
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/lib/bcdice/base.rb
ADDED
@@ -0,0 +1,423 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bcdice/randomizer"
|
4
|
+
require "bcdice/dice_table"
|
5
|
+
require "bcdice/enum"
|
6
|
+
|
7
|
+
module BCDice
|
8
|
+
class Base
|
9
|
+
class << self
|
10
|
+
# 接頭辞(反応するコマンド)の配列を返す
|
11
|
+
# @return [Array<String>]
|
12
|
+
attr_reader :prefixes
|
13
|
+
|
14
|
+
# 応答するコマンドのprefixを登録する
|
15
|
+
# @param prefixes [Array<String>]
|
16
|
+
def register_prefix(*prefixes)
|
17
|
+
@prefixes ||= []
|
18
|
+
@prefixes.concat(prefixes.flatten)
|
19
|
+
end
|
20
|
+
|
21
|
+
# ゲームシステム固有のコマンドにマッチする正規表現を返す
|
22
|
+
# 正規表現を一度生成したら、以後コマンドの登録はできないようにする
|
23
|
+
#
|
24
|
+
# @return [Regexp]
|
25
|
+
def prefixes_pattern
|
26
|
+
@prefixes_pattern ||= nil
|
27
|
+
return @prefixes_pattern if @prefixes_pattern
|
28
|
+
|
29
|
+
@prefixes ||= []
|
30
|
+
@prefixes.freeze
|
31
|
+
@prefixes_pattern =
|
32
|
+
if @prefixes.empty?
|
33
|
+
/(?!)/ # 何にもマッチしない正規表現
|
34
|
+
else
|
35
|
+
/^(S)?(#{@prefixes.join('|')})/i
|
36
|
+
end.freeze
|
37
|
+
end
|
38
|
+
|
39
|
+
# 応答するコマンド全てにマッチする正規表現を返す
|
40
|
+
# 正規表現を一度生成したら、以後コマンドの登録はできないようにする
|
41
|
+
#
|
42
|
+
# @return [Regexp]
|
43
|
+
def command_pattern
|
44
|
+
@command_pattern ||= nil
|
45
|
+
return @command_pattern if @command_pattern
|
46
|
+
|
47
|
+
@prefixes ||= []
|
48
|
+
@prefixes.freeze
|
49
|
+
pattarns = CommonCommand::COMMANDS.map { |c| c::PREFIX_PATTERN.source } + @prefixes
|
50
|
+
|
51
|
+
@command_pattern = /^S?(#{pattarns.join("|")})/i.freeze
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(command)
|
56
|
+
@raw_input = command
|
57
|
+
|
58
|
+
@sort_add_dice = false # 加算ダイスでダイス目をソートするかどうか
|
59
|
+
@sort_barabara_dice = false # バラバラダイスでダイス目をソートするかどうか
|
60
|
+
|
61
|
+
@enabled_d66 = true # D66ダイスを利用するかどうか
|
62
|
+
@d66_sort_type = D66SortType::NO_SORT # 入れ替えの種類 詳しくはBCDice::D66SortTypeを参照すること
|
63
|
+
|
64
|
+
@enabled_d9 = false # D9ダイスを有効にするか(ガンドッグ)で使用
|
65
|
+
|
66
|
+
@round_type = RoundType::FLOOR # 割り算をした時の端数の扱い (FLOOR: 切り捨て, CEIL: 切り上げ, ROUND: 四捨五入)
|
67
|
+
|
68
|
+
@upper_dice_reroll_threshold = nil # UpperDiceで振り足しをする出目の閾値 nilの場合デフォルト設定なし
|
69
|
+
@reroll_dice_reroll_threshold = nil # RerollDiceで振り足しをする出目の閾値 nilの場合デフォルト設定なし
|
70
|
+
|
71
|
+
@default_cmp_op = nil # 目標値が空欄の場合の比較演算子をシンボルで指定する (:>, :>= :<, :<=, :==, :!=)
|
72
|
+
@default_target_number = nil # 目標値が空欄の場合の目標値 こちらだけnilにするのは想定していないので注意
|
73
|
+
|
74
|
+
@enabled_upcase_input = true # 入力を String#upcase するかどうか
|
75
|
+
|
76
|
+
@is_secret = false
|
77
|
+
@is_success = false
|
78
|
+
@is_failure = false
|
79
|
+
@is_critical = false
|
80
|
+
@is_fumble = false
|
81
|
+
|
82
|
+
@randomizer = BCDice::Randomizer.new
|
83
|
+
@debug = false
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_accessor :randomizer
|
87
|
+
|
88
|
+
# D66のダイス入れ替えの種類
|
89
|
+
#
|
90
|
+
# @return [Symbol]
|
91
|
+
attr_reader :d66_sort_type
|
92
|
+
|
93
|
+
# 端数処理の種類
|
94
|
+
#
|
95
|
+
# @return [Symbol]
|
96
|
+
attr_reader :round_type
|
97
|
+
|
98
|
+
# UpperDiceで振り足しをする出目の閾値
|
99
|
+
#
|
100
|
+
# @return [Integer, nil]
|
101
|
+
attr_reader :upper_dice_reroll_threshold
|
102
|
+
|
103
|
+
# RerollDiceで振り足しをする出目の閾値
|
104
|
+
#
|
105
|
+
# @return [Integer, nil]
|
106
|
+
attr_reader :reroll_dice_reroll_threshold
|
107
|
+
|
108
|
+
# デフォルトの比較演算子
|
109
|
+
#
|
110
|
+
# @return [Symbol, nil]
|
111
|
+
attr_reader :default_cmp_op
|
112
|
+
|
113
|
+
# デフォルトの目標値
|
114
|
+
#
|
115
|
+
# @return [Integer, nil]
|
116
|
+
attr_reader :default_target_number
|
117
|
+
|
118
|
+
# 加算ダイスでダイス目をソートするかどうか
|
119
|
+
#
|
120
|
+
# @return [Boolean]
|
121
|
+
def sort_add_dice?
|
122
|
+
@sort_add_dice
|
123
|
+
end
|
124
|
+
|
125
|
+
# バラバラダイスでダイス目をソートするかどうか
|
126
|
+
#
|
127
|
+
# @return [Boolean]
|
128
|
+
def sort_barabara_dice?
|
129
|
+
@sort_barabara_dice
|
130
|
+
end
|
131
|
+
|
132
|
+
# D66ダイスが有効か
|
133
|
+
#
|
134
|
+
# @return [Boolean]
|
135
|
+
def enabled_d66?
|
136
|
+
@enabled_d66
|
137
|
+
end
|
138
|
+
|
139
|
+
# D9ダイスが有効か
|
140
|
+
#
|
141
|
+
# @return [Boolean]
|
142
|
+
def enabled_d9?
|
143
|
+
@enabled_d9
|
144
|
+
end
|
145
|
+
|
146
|
+
# シークレットコマンドか
|
147
|
+
#
|
148
|
+
# @return [Boolean]
|
149
|
+
def secret?
|
150
|
+
@is_secret
|
151
|
+
end
|
152
|
+
|
153
|
+
# 結果が成功か
|
154
|
+
# @return [Boolean]
|
155
|
+
def success?
|
156
|
+
@is_success
|
157
|
+
end
|
158
|
+
|
159
|
+
# 結果が失敗か
|
160
|
+
# @return [Boolean]
|
161
|
+
def failure?
|
162
|
+
@is_failure
|
163
|
+
end
|
164
|
+
|
165
|
+
# 結果がクリティカルか
|
166
|
+
# @return [Boolean]
|
167
|
+
def critical?
|
168
|
+
@is_critical
|
169
|
+
end
|
170
|
+
|
171
|
+
# 結果がファンブルか
|
172
|
+
# @return [Boolean]
|
173
|
+
def fumble?
|
174
|
+
@is_fumble
|
175
|
+
end
|
176
|
+
|
177
|
+
# デバッグを有用にする
|
178
|
+
def enable_debug
|
179
|
+
@debug = true
|
180
|
+
end
|
181
|
+
|
182
|
+
# コマンドを評価する
|
183
|
+
# @return [String, nil] コマンド実行結果。コマンドが実行できなかった場合はnilを返す
|
184
|
+
def eval
|
185
|
+
command = BCDice::Preprocessor.process(@raw_input, @randomizer, self)
|
186
|
+
upcased_command = command.upcase
|
187
|
+
|
188
|
+
result = dice_command(command)
|
189
|
+
result ||= eval_common_command(upcased_command)
|
190
|
+
|
191
|
+
return result
|
192
|
+
end
|
193
|
+
|
194
|
+
# ゲームシステムごとの入力コマンドの前処理
|
195
|
+
# @deprecated これを使わずに +eval_common_command+ 内でパースすることを推奨する
|
196
|
+
# @param string [String]
|
197
|
+
# @return [String]
|
198
|
+
def change_text(string)
|
199
|
+
string
|
200
|
+
end
|
201
|
+
|
202
|
+
# @param total [Integer] コマンド合計値
|
203
|
+
# @param dice_total [Integer] ダイス目の合計値
|
204
|
+
# @param dice_list [Array<Integer>] ダイスの一覧
|
205
|
+
# @param sides [Integer] 振ったダイスの面数
|
206
|
+
# @param cmp_op [Symbol] 比較演算子
|
207
|
+
# @param target [Integer, String] 目標値の整数か'?'
|
208
|
+
# @return [String]
|
209
|
+
def check_result(total, dice_total, dice_list, sides, cmp_op, target)
|
210
|
+
ret =
|
211
|
+
case [dice_list.size, sides]
|
212
|
+
when [1, 100]
|
213
|
+
check_1D100(total, dice_total, cmp_op, target)
|
214
|
+
when [1, 20]
|
215
|
+
check_1D20(total, dice_total, cmp_op, target)
|
216
|
+
when [2, 6]
|
217
|
+
check_2D6(total, dice_total, dice_list, cmp_op, target)
|
218
|
+
end
|
219
|
+
|
220
|
+
return ret unless ret.nil? || ret.empty?
|
221
|
+
|
222
|
+
ret =
|
223
|
+
case sides
|
224
|
+
when 10
|
225
|
+
check_nD10(total, dice_total, dice_list, cmp_op, target)
|
226
|
+
when 6
|
227
|
+
check_nD6(total, dice_total, dice_list, cmp_op, target)
|
228
|
+
end
|
229
|
+
|
230
|
+
return ret unless ret.nil? || ret.empty?
|
231
|
+
|
232
|
+
check_nDx(total, cmp_op, target)
|
233
|
+
end
|
234
|
+
|
235
|
+
# シャドウラン用グリッチ判定
|
236
|
+
# @param count_one [Integer] 出目1の数
|
237
|
+
# @param dice_total_count [Integer] ダイスロールしたダイスの数
|
238
|
+
# @param count_success [Integer] 成功数
|
239
|
+
# @return [String, nil]
|
240
|
+
def grich_text(count_one, dice_total_count, count_success); end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
def eval_common_command(command)
|
245
|
+
CommonCommand::COMMANDS.each do |klass|
|
246
|
+
cmd = klass.new(command, @randomizer, self)
|
247
|
+
out = cmd.eval()
|
248
|
+
|
249
|
+
@is_secret = cmd.secret?
|
250
|
+
return out if out
|
251
|
+
end
|
252
|
+
|
253
|
+
return nil
|
254
|
+
end
|
255
|
+
|
256
|
+
def dice_command(command)
|
257
|
+
command = command.upcase if @enabled_upcase_input
|
258
|
+
|
259
|
+
m = self.class.prefixes_pattern.match(command)
|
260
|
+
unless m
|
261
|
+
return nil
|
262
|
+
end
|
263
|
+
|
264
|
+
secret = !m[1].nil?
|
265
|
+
command = command[1..-1] if secret # 先頭の 'S' をとる
|
266
|
+
|
267
|
+
output = eval_game_system_specific_command(command)
|
268
|
+
@is_secret ||= secret
|
269
|
+
if output.nil? || output.empty? || output == "1"
|
270
|
+
return nil
|
271
|
+
else
|
272
|
+
return output.to_s
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# @param command [String]
|
277
|
+
# @return [String, nil]
|
278
|
+
def eval_game_system_specific_command(command); end
|
279
|
+
|
280
|
+
# 成功か失敗かを文字列で返す
|
281
|
+
#
|
282
|
+
# @param (see #check_result)
|
283
|
+
# @return [String]
|
284
|
+
def check_nDx(total, cmp_op, target)
|
285
|
+
return " > 失敗" if target.is_a?(String)
|
286
|
+
|
287
|
+
if total.send(cmp_op, target)
|
288
|
+
" > 成功"
|
289
|
+
else
|
290
|
+
" > 失敗"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# @param (see #check_result)
|
295
|
+
# @return [nil]
|
296
|
+
def check_1D100(total, dice_total, cmp_op, target); end
|
297
|
+
|
298
|
+
# @param (see #check_result)
|
299
|
+
# @return [nil]
|
300
|
+
def check_1D20(total, dice_total, cmp_op, target); end
|
301
|
+
|
302
|
+
# @param (see #check_result)
|
303
|
+
# @return [nil]
|
304
|
+
def check_nD10(total, dice_total, dice_list, cmp_op, target); end
|
305
|
+
|
306
|
+
# @param (see #check_result)
|
307
|
+
# @return [nil]
|
308
|
+
def check_2D6(total, dice_total, dice_list, cmp_op, target); end
|
309
|
+
|
310
|
+
# @param (see #check_result)
|
311
|
+
# @return [nil]
|
312
|
+
def check_nD6(total, dice_total, dice_list, cmp_op, target); end
|
313
|
+
|
314
|
+
def get_table_by_2d6(table)
|
315
|
+
get_table_by_nD6(table, 2)
|
316
|
+
end
|
317
|
+
|
318
|
+
def get_table_by_1d6(table)
|
319
|
+
get_table_by_nD6(table, 1)
|
320
|
+
end
|
321
|
+
|
322
|
+
def get_table_by_nD6(table, count)
|
323
|
+
get_table_by_nDx(table, count, 6)
|
324
|
+
end
|
325
|
+
|
326
|
+
def get_table_by_nDx(table, count, diceType)
|
327
|
+
num = @randomizer.roll_sum(count, diceType)
|
328
|
+
|
329
|
+
text = get_table_value(table[num - count])
|
330
|
+
|
331
|
+
return "1", 0 if text.nil?
|
332
|
+
|
333
|
+
return text, num
|
334
|
+
end
|
335
|
+
|
336
|
+
def get_table_by_1d3(table)
|
337
|
+
debug("get_table_by_1d3")
|
338
|
+
|
339
|
+
count = 1
|
340
|
+
num = @randomizer.roll_sum(count, 6)
|
341
|
+
debug("num", num)
|
342
|
+
|
343
|
+
index = ((num - 1) / 2)
|
344
|
+
debug("index", index)
|
345
|
+
|
346
|
+
text = table[index]
|
347
|
+
|
348
|
+
return "1", 0 if text.nil?
|
349
|
+
|
350
|
+
return text, num
|
351
|
+
end
|
352
|
+
|
353
|
+
# D66 ロール用(スワップ、たとえば出目が【6,4】なら「64」ではなく「46」とする
|
354
|
+
def get_table_by_d66_swap(table)
|
355
|
+
number = @randomizer.roll_d66(D66SortType::ASC)
|
356
|
+
return get_table_by_number(number, table), number
|
357
|
+
end
|
358
|
+
|
359
|
+
# D66 ロール用
|
360
|
+
def get_table_by_d66(table)
|
361
|
+
dice1 = @randomizer.roll_once(6)
|
362
|
+
dice2 = @randomizer.roll_once(6)
|
363
|
+
|
364
|
+
num = (dice1 - 1) * 6 + (dice2 - 1)
|
365
|
+
|
366
|
+
text = table[num]
|
367
|
+
|
368
|
+
indexText = "#{dice1}#{dice2}"
|
369
|
+
|
370
|
+
return "1", indexText if text.nil?
|
371
|
+
|
372
|
+
return text, indexText
|
373
|
+
end
|
374
|
+
|
375
|
+
# ** 汎用表サブルーチン
|
376
|
+
def get_table_by_number(index, table, default = "1")
|
377
|
+
table.each do |item|
|
378
|
+
number = item[0]
|
379
|
+
if number >= index
|
380
|
+
return get_table_value(item[1])
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
return get_table_value(default)
|
385
|
+
end
|
386
|
+
|
387
|
+
def get_table_value(data)
|
388
|
+
if data.is_a?(Proc)
|
389
|
+
return data.call()
|
390
|
+
end
|
391
|
+
|
392
|
+
return data
|
393
|
+
end
|
394
|
+
|
395
|
+
def roll_tables(command, tables)
|
396
|
+
table = tables[command]
|
397
|
+
unless table
|
398
|
+
return nil
|
399
|
+
end
|
400
|
+
|
401
|
+
return table.roll(@randomizer).to_s
|
402
|
+
end
|
403
|
+
|
404
|
+
# デバッグ出力を行う
|
405
|
+
# @param [Object] target 対象項目
|
406
|
+
# @param [Object] values 値
|
407
|
+
def debug(target, *values)
|
408
|
+
return unless @debug
|
409
|
+
|
410
|
+
targetStr = target.is_a?(String) ? target : target.inspect
|
411
|
+
|
412
|
+
if values.empty?
|
413
|
+
warn targetStr
|
414
|
+
else
|
415
|
+
valueStrs = values.map do |value|
|
416
|
+
value.is_a?(String) ? %("#{value}") : value.inspect
|
417
|
+
end
|
418
|
+
|
419
|
+
warn "#{targetStr}: #{valueStrs.join(', ')}"
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|