-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Irisbane] 『瞳逸らさぬイリスベイン』のダイスボットを作成 (#482)
* [Irisbane] 「攻撃判定」(ルールブックp148)の基本的な挙動を実装 * [Irisbane] 攻撃判定の各パラメータに式を指定できるように ゲームルール上、しばしば計算が発生するので。 * [Irisbane] バラバラダイスのソート、端数切り上げを設定 * [Irisbane] 攻撃判定にダメージの増減を指定できるように ルールブックp67 《私が守る》や《連鎖の起点》など * [Irisbane] ヘルプメッセージ内の例をカンマで区切らないように コマンドでカンマを使う以上、まぎらわしいので。 * [Irisbane] Ruby2.6で動かなかったのを修正 * [Irisbane] 年齢チャート(p27)を実装 * ダイス目の偶奇のみを見るテーブルを実装 * [Irisbane] 性別チャート(p27)を実装 * 左側ダイスを範囲で表現するD66テーブルを実装 * [Irisbane] 欠落チャート(p30)を実装 * [Irisbane] 願望チャート(p31)を実装 * [Irisbane] 問い掛けチャート(p34-35)を実装 * [Irisbane] 復讐者のスタイルチャート(p40)を実装 * [Irisbane] 掌握者のスタイルチャート(p41)を実装 * [Irisbane] 望む執行の方向性チャート(p48)を実装 * [Irisbane] シチュエーションチャート(p115)を実装 * [Irisbane] シルエットライン(p37)のダイスロールを実装 * [Irisbane] 「攻撃判定」のコマンド形式を変更 before: x,y,z after: x@y<=z * [Irisbane] いくつかの表を削除 - 年齢 - 性別 - 欠落 - 願望 - 問い掛け - 復讐者のスタイル - 掌握者のスタイル - 望む執行の方向性 - シルエットライン * Revert "ダイス目の偶奇のみを見るテーブルを実装" This reverts commit 4506747. Co-authored-by: ViVi <[email protected]>
- Loading branch information
1 parent
914e101
commit a9e040e
Showing
6 changed files
with
694 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# frozen_string_literal: true | ||
|
||
require "bcdice/dice_table/d66_table" | ||
|
||
module BCDice | ||
module DiceTable | ||
# 左側(十の位)のみ Range を用いる D66 表 | ||
class D66LeftRangeTable < D66Table | ||
# @param name [String] 表の名前 | ||
# @param sort_type [Symbol] 出目入れ替えの方式 BCDice::D66SortType | ||
# @param items [Array<(Range, Array<String>)>] 表の項目の配列 | ||
def initialize(name, sort_type, items) | ||
expanded_items = {} | ||
items.each do |item| | ||
range, right_items = item | ||
|
||
range.each do |left_value| | ||
right_items.each_with_index do |right_item, right_value| | ||
key = left_value * 10 + (right_value + 1) | ||
expanded_items[key] = right_item | ||
end | ||
end | ||
end | ||
|
||
super(name, sort_type, expanded_items) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
# frozen_string_literal: true | ||
|
||
module BCDice | ||
module GameSystem | ||
class Irisbane < Base | ||
# ゲームシステムの識別子 | ||
ID = 'Irisbane' | ||
|
||
# ゲームシステム名 | ||
NAME = '瞳逸らさぬイリスベイン' | ||
|
||
# ゲームシステム名の読みがな | ||
SORT_KEY = 'ひとみそらさぬいりすへいん' | ||
|
||
# ダイスボットの使い方 | ||
HELP_MESSAGE = <<~HELP | ||
■攻撃判定( ATTACKx@y<=z ) | ||
x: 攻撃力 | ||
y: 判定数 | ||
z: 目標値 | ||
(※ ATTACK は ATK または AT と簡略化可能) | ||
例) ATTACK2@3<=5 | ||
例) ATK10@2<=4 | ||
例) AT8@3<=2 | ||
上記 x y z にはそれぞれ四則演算を指定可能。 | ||
例) ATTACK2+7@3*2<=5-1 | ||
□攻撃判定のダメージ増減( ATTACKx@y<=z[+a] ATTACKx@y<=z[-a]) | ||
末尾に [+a] または [-a] と指定すると、最終的なダメージを増減できる。 | ||
a: 増減量 | ||
例) ATTACK2@3<=5[+10] | ||
例) ATK10@2<=4[-8] | ||
例) AT8@3<=2[-8+5] | ||
■シチュエーション(p115) | ||
SceneSituation, SSi | ||
HELP | ||
|
||
ATTACK_ROLL_REG = %r{^AT(TACK|K)?([+\-*/()\d]+)@([+\-*/()\d]+)<=([+\-*/()\d]+)(\[([+\-])([+\-*/()\d]+)\])?}i.freeze | ||
register_prefix('AT(TACK|K)?') | ||
|
||
def initialize(command) | ||
super(command) | ||
|
||
@sort_barabara_dice = true | ||
@round_type = RoundType::CEIL | ||
end | ||
|
||
def eval_game_system_specific_command(command) | ||
command = ALIAS[command] || command | ||
|
||
if (m = ATTACK_ROLL_REG.match(command)) | ||
roll_attack(m[2], m[3], m[4], m[6], m[7]) | ||
else | ||
roll_tables(command, TABLES) | ||
end | ||
end | ||
|
||
private | ||
|
||
def roll_attack(power_expression, dice_count_expression, border_expression, modification_operator, modification_expression) | ||
power = Arithmetic.eval(power_expression, RoundType::CEIL) | ||
dice_count = Arithmetic.eval(dice_count_expression, RoundType::CEIL) | ||
border = Arithmetic.eval(border_expression, RoundType::CEIL) | ||
modification_value = modification_expression.nil? ? nil : Arithmetic.eval(modification_expression, RoundType::CEIL) | ||
return if power.nil? || dice_count.nil? || border.nil? | ||
return if modification_operator && modification_value.nil? | ||
|
||
power = 0 if power < 0 | ||
border = border.clamp(1, 6) | ||
|
||
command = make_command_text(power, dice_count, border, modification_operator, modification_value) | ||
|
||
if dice_count <= 0 | ||
return "#{command} > 判定数が 0 です" | ||
end | ||
|
||
dices = @randomizer.roll_barabara(dice_count, 6).sort | ||
|
||
success_dice_count = dices.count { |dice| dice <= border } | ||
damage = success_dice_count * power | ||
|
||
message_elements = [] | ||
message_elements << command | ||
message_elements << dices.join(',') | ||
message_elements << "成功ダイス数 #{success_dice_count}" | ||
message_elements << "× 攻撃力 #{power}" if success_dice_count > 0 | ||
|
||
if success_dice_count > 0 | ||
if modification_operator && modification_value | ||
message_elements << "ダメージ #{damage}#{modification_operator}#{modification_value}" | ||
damage = parse_operator(modification_operator).call(damage, modification_value) | ||
damage = 0 if damage < 0 | ||
message_elements << damage.to_s | ||
else | ||
message_elements << "ダメージ #{damage}" | ||
end | ||
end | ||
|
||
Result.new(message_elements.join(' > ')).tap do |r| | ||
r.condition = success_dice_count > 0 | ||
end | ||
end | ||
|
||
def make_command_text(power, dice_count, border, modification_operator, modification_value) | ||
text = "(ATTACK#{power}@#{dice_count}<=#{border}" | ||
text += "[#{modification_operator}#{modification_value}]" if modification_operator | ||
text += ")" | ||
text | ||
end | ||
|
||
def parse_operator(operator) | ||
case operator | ||
when '+' | ||
lambda { |x, y| x + y } | ||
when '-' | ||
lambda { |x, y| x - y } | ||
end | ||
end | ||
|
||
TABLES = { | ||
"SceneSituation" => DiceTable::D66LeftRangeTable.new( | ||
"シチュエーション", | ||
BCDice::D66SortType::NO_SORT, | ||
[ | ||
[1..3, [ | ||
"【日常】何一つ変わることの無い日々の一幕。移ろい易い世界では、それはとても大切である。", | ||
"【準備】何かを為すための用意をする一幕。情報収集、買物遠征、やるべきことは一杯だ。", | ||
"【趣味】自分の時間を、有効活用している一幕。必要に追われていない分、心は軽く晴れやかだ。", | ||
"【喫茶】一息入れ、嗜好品を嗜む時の一幕。穏やかな空気は、だが、往々にして変わりやすい。", | ||
"【鍛錬】体を鍛え、心を養う修練の一幕。己さえ良ければ、その方法も何だって良い。", | ||
"【職務】役割の元、仕事に精を出す時の一幕。目的が何であれ、為すべきことに変わりはない。", | ||
]], | ||
[4..6, [ | ||
"【移動】何処かから何処かへと向かう一幕。進んでいるなら、手段も目的地も関係あるまい。", | ||
"【墓前】故人が眠る場所へと赴く一幕。共に眠ることだけは無いように。", | ||
"【操作】何かを操り、望みを果たしている一幕。運転にせよ何にせよ、脇見には注意が必要だ。", | ||
"【食事】何かを糧とし、己の力を蓄える一幕。行動すれば消耗する。腹が減っては何とやらだ。", | ||
"【休息】日々の合間の、憩いの一幕。“何もしない”というのも、立派な行いである。", | ||
"【夢幻】現実に存在しない何かへと耽る一幕。時間帯に関わらず、何時かは必ず覚めるだろう。", | ||
]], | ||
] | ||
), | ||
}.transform_keys(&:upcase).freeze | ||
|
||
ALIAS = { | ||
"SSi" => "SceneSituation", | ||
}.transform_keys(&:upcase).transform_values(&:upcase).freeze | ||
|
||
register_prefix(TABLES.keys, ALIAS.keys) | ||
end | ||
end | ||
end |
Oops, something went wrong.