Skip to content

Commit

Permalink
[Irisbane] 『瞳逸らさぬイリスベイン』のダイスボットを作成 (#482)
Browse files Browse the repository at this point in the history
* [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
ViVi-shark and ViVi authored Jul 14, 2021
1 parent 914e101 commit a9e040e
Show file tree
Hide file tree
Showing 6 changed files with 694 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/bcdice/dice_table.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require "bcdice/dice_table/d66_grid_table"
require "bcdice/dice_table/d66_half_grid_table"
require "bcdice/dice_table/d66_one_third_table"
require "bcdice/dice_table/d66_left_range_table"
require "bcdice/dice_table/d66_parity_table"
require "bcdice/dice_table/d66_range_table"
require "bcdice/dice_table/d66_table"
Expand Down
29 changes: 29 additions & 0 deletions lib/bcdice/dice_table/d66_left_range_table.rb
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
1 change: 1 addition & 0 deletions lib/bcdice/game_system.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
require "bcdice/game_system/InfiniteFantasia"
require "bcdice/game_system/Insane"
require "bcdice/game_system/Insane_Korean"
require "bcdice/game_system/Irisbane"
require "bcdice/game_system/IthaWenUa"
require "bcdice/game_system/JamesBond"
require "bcdice/game_system/JekyllAndHyde"
Expand Down
154 changes: 154 additions & 0 deletions lib/bcdice/game_system/Irisbane.rb
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
Loading

0 comments on commit a9e040e

Please sign in to comment.