Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Irisbane] 『瞳逸らさぬイリスベイン』のダイスボットを作成 #482

Merged
merged 21 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
763f62f
[Irisbane] 「攻撃判定」(ルールブックp148)の基本的な挙動を実装
Jun 25, 2021
a06c1c3
[Irisbane] 攻撃判定の各パラメータに式を指定できるように
Jun 25, 2021
a843393
[Irisbane] バラバラダイスのソート、端数切り上げを設定
Jun 25, 2021
750c462
[Irisbane] 攻撃判定にダメージの増減を指定できるように
Jun 25, 2021
6b09ed9
[Irisbane] ヘルプメッセージ内の例をカンマで区切らないように
Jun 25, 2021
b1318fd
[Irisbane] Ruby2.6で動かなかったのを修正
Jun 25, 2021
6323f62
[Irisbane] 年齢チャート(p27)を実装
Jun 25, 2021
4506747
ダイス目の偶奇のみを見るテーブルを実装
Jun 25, 2021
47753f8
[Irisbane] 性別チャート(p27)を実装
Jun 25, 2021
b2bc244
左側ダイスを範囲で表現するD66テーブルを実装
Jun 25, 2021
8326119
[Irisbane] 欠落チャート(p30)を実装
Jun 25, 2021
5f1662d
[Irisbane] 願望チャート(p31)を実装
Jun 25, 2021
66b76e9
[Irisbane] 問い掛けチャート(p34-35)を実装
Jun 25, 2021
e11fdbb
[Irisbane] 復讐者のスタイルチャート(p40)を実装
Jun 25, 2021
2b86e09
[Irisbane] 掌握者のスタイルチャート(p41)を実装
Jun 25, 2021
9236f5a
[Irisbane] 望む執行の方向性チャート(p48)を実装
Jun 25, 2021
c0022bb
[Irisbane] シチュエーションチャート(p115)を実装
Jun 25, 2021
ae2c15f
[Irisbane] シルエットライン(p37)のダイスロールを実装
Jun 25, 2021
443f32a
[Irisbane] 「攻撃判定」のコマンド形式を変更
Jul 13, 2021
7a9650c
[Irisbane] いくつかの表を削除
Jul 14, 2021
96558af
Revert "ダイス目の偶奇のみを見るテーブルを実装"
Jul 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/bcdice/dice_table.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
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"
require "bcdice/dice_table/parity_table"
require "bcdice/dice_table/range_table"
require "bcdice/dice_table/sai_fic_skill_table"
require "bcdice/dice_table/table"
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
34 changes: 34 additions & 0 deletions lib/bcdice/dice_table/parity_table.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

module BCDice
module DiceTable
# 出目の偶奇による場合分け機能をもつ表
class ParityTable
# @param [String] name 表の名前
# @param [String] type 項目を選ぶときのダイスロールの方法 '1D6'など
# @param [String] odd ダイス目が奇数のときの結果
# @param [String] even ダイス目が偶数のときの結果
def initialize(name, type, odd, even)
@name = name
@odd = odd.freeze
@even = even.freeze

m = /(\d+)D(\d+)/i.match(type)
unless m
raise ArgumentError, "Unexpected table type: #{type}"
end

@times = m[1].to_i
@sides = m[2].to_i
end

# 表を振る
# @param [BCDice] bcdice ランダマイザ
# @return [String] 結果
def roll(bcdice)
value = bcdice.roll_sum(@times, @sides)
return RollResult.new(@name, value, value.odd? ? @odd : @even)
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