Skip to content

Commit

Permalink
Merge pull request #308 from GenKuzumochi/fix/GarakoCommands
Browse files Browse the repository at this point in the history
ガラコと破戒の塔ダイスボット改良
  • Loading branch information
ysakasin authored Dec 11, 2020
2 parents 393b691 + 4d391ba commit 5cba97e
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 40 deletions.
170 changes: 131 additions & 39 deletions lib/bcdice/game_system/Garako.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ class Garako < Base

# ダイスボットの使い方
HELP_MESSAGE = <<~MESSAGETEXT
・判定
GR+n>=X:「+n」で判定値を指定、「X」で目標値を指定。
・判定 GR+n#f>=X (+n:判定値、#f:不安定による自動失敗基準値、X:目標値)
・部位決定チャート:HIT
・ダメージチャート:xDCy(CDC/EDC/FDC/ADC/LDC)
・ダメージ+部位決定:GAHn(n:火力)
・ダメージチャート:xDCy(CDC/EDC/FDC/ADC/LDC )
・ダメージチャートver2:xDTy(CDT/EDT/FDT/ADT/LDT)
 xは C:コックピット、E:エンジン、F:フレーム、A:アーム、L:レッグ
 yはダメージ値
各種表
Expand All @@ -41,7 +42,8 @@ class Garako < Base
def eval_game_system_specific_command(command)
roll_tables(command, TABLES) ||
roll_gr(command) ||
roll_damage_chart(command)
roll_damage_chart(command) ||
roll_attack_hit(command)
end

private
Expand All @@ -51,71 +53,87 @@ def eval_game_system_specific_command(command)
# @param command [String]
# @return [String, nil]
def roll_gr(command)
m = /^GR([+-]\d+)?>=(\d+)$/i.match(command)
unless m
return nil
end
parser = CommandParser.new("GR")
cmd = parser.parse(command)
return nil unless cmd
return nil if cmd.critical

modify_number = m[1].to_i
target_number = m[2].to_i
modify_number = cmd.modify_number || 0
auto_failure_number = cmd.fumble || 1
target_number = cmd.target_number

dice = @randomizer.roll_once(10)
total = dice + modify_number

result =
if dice == 1
"ファンブル"
elsif dice <= auto_failure_number # 公式FAQより、ファンブルと自動失敗を区別する可能性があるので分岐
"自動失敗"
elsif dice == 10
"クリティカル"
elsif total >= target_number
elsif target_number && total >= target_number
"成功"
else
elsif target_number
"失敗"
end

formated_modifier = Format.modifier(modify_number)
formated_auto_failure = "##{auto_failure_number}" if auto_failure_number >= 2
format_target = ">=#{target_number}" if target_number

sequence = [
"(1D10#{formated_modifier}>=#{target_number})",
"(1D10#{formated_modifier}#{formated_auto_failure}#{format_target})",
"#{dice}[#{dice}]#{formated_modifier}",
total.to_s,
result
]

return sequence.join(" > ")
return sequence.compact.join(" > ")
end

# 部位ダメージチャート
# ダメージ算出+部位決定チャート
#
# @param command [String]
# @return [String, nil]
def roll_damage_chart(command)
m = /^(\wDC)(\d+)$/i.match(command)
unless m
return nil
end

part = m[1]
damage = clamp(m[2].to_i, 1, 10)
index = damage - 1
def roll_attack_hit(command)
m = /^GHA([-+\d]+)$/i.match(command)
return nil unless m

chart = DAMAGE_CHARTS[part]
unless chart
return nil
modifier = ArithmeticEvaluator.eval(m[1])
attack = @randomizer.roll_once(10)
total = attack + modifier
hit_text = "#{total}(ダメージを受けない)"
if total > 0
hit = TABLES["HIT"].roll(@randomizer)
hit_dice = ", HIT[#{hit.value}]"
hit_text = "#{hit.body}#{total} -【部位装甲】"
end

chosen = chart[:table][index]
formated_modifier = Format.modifier(modifier)
sequence = [
"(1D10#{formated_modifier})",
"#{attack}[#{attack}]#{formated_modifier}#{hit_dice}",
hit_text
]

return "#{chart[:name]}(#{damage})#{chosen}"
return sequence.join("")
end

def clamp(i, min, max)
if i < min
min
elsif i > max
max
else
i
end
# 部位ダメージチャート
#
# @param command [String]
# @return [String, nil]
def roll_damage_chart(command)
m = /^([CEFAL]D[CT])([-+\d]+)$/i.match(command)
return nil unless m

chart = DAMAGE_CHARTS[m[1]]
damage = ArithmeticEvaluator.eval(m[2]).clamp(0, 10)
return "ダメージを受けない" if damage <= 0

result = chart[:table][damage - 1]
return "#{chart[:name]}(#{damage}) > #{result}"
end

DAMAGE_CHARTS = {
Expand Down Expand Up @@ -193,9 +211,83 @@ def clamp(i, min, max)
"大破(跛足):以後、【移動力】-2。この部位の【部位装甲】が0になる。[弱体1]を受ける。",
"修復不能(破壊):ダメージを受けた側のレッグが[修復不能]となる。【移動力】-2。[弱体2]を受ける。",
]
},
"CDT" => {
name: "部位ダメージチャートv2: コックピット",
table: [
"アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
"視界不良(小破/弱体0/装甲ダメージ1)モニターやハッチの歪み等により、視界を大きく遮られる。以後、【視認性】-1。",
"強震(小破/弱体0/装甲ダメージ1)大きく揺さぶられる。キミは【身体】10 の判定を行なう。失敗した場合、次のターンを失う。",
"貫通!(小破/弱体0/装甲ダメージ1)パイロットに被害が!キミはHPダメージ(1d10-【身体】)を受ける。",
"計器損傷(中破/弱体1/装甲ダメージ1)コンソールの一部が停止する。",
"制御不能(中破/弱体1/装甲ダメージ1)コントロールが効かなくなる。キミは次のターンを失う。",
"貫通!(中破/弱体1/装甲ダメージ1)パイロットに被害が!キミはHPダメージ(1d10-【身体】)を受ける。",
"故障(大破/弱体1/装甲ダメージ2)コックピットが完全にいかれる。キミは次のラウンド終了時まで、あらゆる判定に自動的にファンブルする。",
"貫通!(大破/弱体1/装甲ダメージ2)パイロットに被害が!キミはHPダメージ(1d10+3-【身体】)を受ける。",
"破壊(修復不能/弱体2/装甲ダメージ3)コックピットが「修復不能」となる。キミは2d10-【身体】点のHPダメージを受ける。ガラコはすべての機能を停止する。コックピットのハッチが自動的に開く。",
]
},
"EDT" => {
name: "部位ダメージチャートv2: エンジン",
table: [
"アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
"アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
"燃料漏れ(小破/弱体0/装甲ダメージ1)タンクから燃料が漏れる。燃料-1。",
"燃料漏れ(小破/弱体0/装甲ダメージ1)タンクから燃料が漏れる。燃料-2。",
"エンジン不調(中破/弱体1/装甲ダメージ1)エンジンの調子が安定しない。",
"オーバーヒート(中破/弱体1/装甲ダメージ1)オーバーヒートする。次のターンの終了時まで、移動と攻撃を行えない。",
"エンジン不調(中破/弱体1/装甲ダメージ1)なんだか調子悪い。キミは次のターンを失う。",
"燃料漏れ(大破/弱体1/装甲ダメージ2)タンクから燃料が漏れる。燃料-3。",
"貫通!(大破/弱体1/装甲ダメージ2)パイロットに被害が!キミはHPダメージ(1d10+3-【身体】)を受ける。",
"エンジン停止(修復不能/弱体2/装甲ダメージ3)エンジンが停止する。ガラコはすべての機能を停止する。コックピットのハッチが自動的に開く。【操作性】10の判定を行なうこと。失敗するとエンジンが爆発する。その場合、すべての部位が[修復不能]となり、キミは2d10-【身体】点のHPダメージを受ける",
]
},
"FDT" => {
name: "部位ダメージチャートv2: フレーム",
table: [
"アーマー損傷 (小破 /0/装甲ダメージ1)装甲に軽いひび割れが走る。",
"スクラッチ!(小破/弱体0/装甲ダメージ1)フレームに醜い傷が残る。",
"歪み(小破/弱体0/装甲ダメージ1)フレームが歪み、ガラコの動きを阻害し始める。【移動力】-1。",
"ハードポイント損傷(小破/弱体0/装甲ダメージ1)このフレームに装着している武器、及びオプションをすべて落とす。装着していた武器やオプションが外れかかる。キミは【身体】8の判定を行なう。失敗した場合、",
"放熱板損傷(中破/弱体1/装甲ダメージ1)熱を機体外に逃すことができなくなる。これはヤバい。",
"スタビライザー損傷(中破/弱体1/装甲ダメージ1)ターンを失う。機体のバランス調整装置が故障する。【身体】10の判定を行なうこと。失敗した場合、キミは次の",
"貫通!(中破/弱体1/装甲ダメージ1)パイロットに被害が!キミはHPダメージ(1d10-【身体】)を受ける。",
"停止(大破/弱体1/装甲ダメージ2)フレームが動かない。キミは次のターンを失う。",
"ハードポイント破壊(大破/弱体1/装甲ダメージ2)武器やオプションを取り付ける箇所が破壊される。以後、このフレームに(スロットを消費して)装着している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。",
"フレーム崩壊(修復不能/弱体2/装甲ダメージ3)フレームが「修復不能」となる。フレームの大部分が剥がれ落ち、ガラコの内部が晒される。以後キミに対して部位狙いが行われる場合、その命中判定に対する修正(『GHT』p21)は発生しない。",
]
},
"ADT" => {
name: "部位ダメージチャートv2: アーム",
table: [
"アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
"武器落とし!(小破/弱体0/装甲ダメージ1)キミは【身体】8の判定を行う。失敗した場合、ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。",
"マニピュレータ損傷(小破/弱体0/装甲ダメージ1)指が何本かちぎれ飛んだ。【操作性】-1。",
"機能停止(小破/弱体0/装甲ダメージ1)次のターンの終了時まで、このアームを使った攻撃はできない。",
"痙攣(中破/弱体1/装甲ダメージ1)アームの動きがぶれ始める。",
"武器落とし!(中破/弱体1/装甲ダメージ1)ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。",
"スピン(中破/弱体1/装甲ダメージ1)機体が大きく回転する。【身体】10の判定を行うこと。失敗した場合、[伏せ]状態となった上、次のターンを失う。",
"武器落とし!(大破/弱体1/装甲ダメージ2)ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。",
"ハードポイント破壊(大破/弱体1/装甲ダメージ2)している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。武器やオプションを取り付ける箇所が破壊される。以後、このアームに(スロットを消費して)装着している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。",
"破壊(修復不能/2/装甲ダメージ3)ダメージを受けた側のアームが「修復不能」となる。",
]
},
"LDT" => {
name: "部位ダメージチャートv2: レッグ",
table: [
"アーマー損傷 (小破 /弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
"よろめき (小破 /弱体0/装甲ダメージ1)次のターンの終了時まで、キミは移動できない。",
"スネア (小破 /弱体0/装甲ダメージ1)足元をすくわれる。【身体】8 の判定を行うこと。失敗した場合、キミは[伏せ]状態になる。",
"跛足 (小破 /弱体0/装甲ダメージ1)以後、【移動力】-1。",
"シャフト損傷 (中破 /弱体1/装甲ダメージ1)脚部の軸に歪みが生じる。",
"アクチュエータ損傷 (中破 /弱体1/装甲ダメージ1)脚部のアクチュエータに大きな損傷を受ける。【移動力】-1。",
"スピン (中破 /弱体1/装甲ダメージ1)機体が大きく回転する。【身体】10 の判定を行うこと。失敗した場合、[伏せ]状態となった上、次のターンを失う。",
"跛足 (大破 /弱体1/装甲ダメージ2)以後、【移動力】-2。",
"ハードポイント破壊 (大破 /弱体1/装甲ダメージ2)している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。 武器やオプションを取り付ける箇所が破壊される。以後、このレッグに(スロットを消費して)装着している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。",
"破壊 (修復不能 /弱体2/装甲ダメージ3)ダメージを受けた側のレッグが「修復不能」となる。【移動力】-2。",
]
}
}.freeze

TABLES = {
"PNM" => DiceTable::Table.new(
"名前表:ピグマー族(男)",
Expand Down Expand Up @@ -553,7 +645,7 @@ def clamp(i, min, max)
)
}.freeze

register_prefix('GR.*', '(C|E|F|A|L)DC\d+', TABLES.keys)
register_prefix('GR.*', '[CEFAL]D[CT][-+\d]+', 'GHA[-+\d]+', TABLES.keys)
end
end
end
63 changes: 62 additions & 1 deletion test/data/Garako.toml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ rands = [
{ sides = 10, value = 8 },
]

[[ test ]]
game_system = "Garako"
input = "GR+1+3-5+4>=10"
output = "(1D10+3>=10) > 8[8]+3 > 11 > 成功"
rands = [
{ sides = 10, value = 8 },
]

[[ test ]]
game_system = "Garako"
input = "GR+(1-1)>=10"
Expand Down Expand Up @@ -185,7 +193,7 @@ rands = [
[[ test ]]
game_system = "Garako"
input = "CDC0"
output = "部位ダメージチャート:コックピット(1) > 小破(アーマー損傷):以後、この部位の【部位装甲】-1。"
output = "ダメージを受けない"
rands = []

[[ test ]]
Expand Down Expand Up @@ -242,6 +250,42 @@ input = "LDC10"
output = "部位ダメージチャート:レッグ(10) > 修復不能(破壊):ダメージを受けた側のレッグが[修復不能]となる。【移動力】-2。[弱体2]を受ける。"
rands = []

[[ test ]]
game_system = "Garako"
input = "CDT0"
output = "ダメージを受けない"
rands = []

[[ test ]]
game_system = "Garako"
input = "CDT1"
output = "部位ダメージチャートv2: コックピット(1) > アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。"
rands = []

[[ test ]]
game_system = "Garako"
input = "CDT10"
output = "部位ダメージチャートv2: コックピット(10) > 破壊(修復不能/弱体2/装甲ダメージ3)コックピットが「修復不能」となる。キミは2d10-【身体】点のHPダメージを受ける。ガラコはすべての機能を停止する。コックピットのハッチが自動的に開く。"
rands = []

[[ test ]]
game_system = "Garako"
input = "CDT11"
output = "部位ダメージチャートv2: コックピット(10) > 破壊(修復不能/弱体2/装甲ダメージ3)コックピットが「修復不能」となる。キミは2d10-【身体】点のHPダメージを受ける。ガラコはすべての機能を停止する。コックピットのハッチが自動的に開く。"
rands = []

[[ test ]]
game_system = "Garako"
input = "LDT10"
output = "部位ダメージチャートv2: レッグ(10) > 破壊 (修復不能 /弱体2/装甲ダメージ3)ダメージを受けた側のレッグが「修復不能」となる。【移動力】-2。"
rands = []

[[ test ]]
game_system = "Garako"
input = "LDT5+5"
output = "部位ダメージチャートv2: レッグ(10) > 破壊 (修復不能 /弱体2/装甲ダメージ3)ダメージを受けた側のレッグが「修復不能」となる。【移動力】-2。"
rands = []

[[ test ]]
game_system = "Garako"
input = "GCC"
Expand Down Expand Up @@ -281,3 +325,20 @@ output = "戦闘開始距離(1) > 3マス"
rands = [
{ sides = 10, value = 1 },
]

[[ test ]]
game_system = "Garako"
input = "GHA5"
output = "(1D10+5) > 8[8]+5, HIT[4] > フレームに 13 -【部位装甲】"
rands = [
{ sides = 10, value = 8 },
{ sides = 10, value = 4 },
]

[[ test ]]
game_system = "Garako"
input = "GHA-7+5"
output = "(1D10-2) > 1[1]-2 > -1(ダメージを受けない)"
rands = [
{ sides = 10, value = 1 },
]

0 comments on commit 5cba97e

Please sign in to comment.