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

ネクロニカのダイスボットを改善 #440

Merged
merged 11 commits into from
May 25, 2021
164 changes: 64 additions & 100 deletions lib/bcdice/game_system/Nechronica.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ class Nechronica < Base
# ダイスボットの使い方
HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
・判定 (nNC+m)
 ダイス数n、修正値mで判定ロールを行います
 ダイス数n、修正値mで判定ロールを行います(省略=1)
 ダイス数が2以上の時のパーツ破損数も表示します。
・攻撃判定 (nNA+m)
 ダイス数n、修正値mで攻撃判定ロールを行います
 ダイス数n、修正値mで攻撃判定ロールを行います(省略=1)
 命中部位とダイス数が2以上の時のパーツ破損数も表示します。

Expand All @@ -37,126 +37,90 @@ def initialize(command)
@default_target_number = 6 # 目標値が空欄の時の目標値
end

private

def replace_text(string)
string = string.gsub(/(\d+)NC(10)?([+\-][+\-\d]+)/i) { "#{Regexp.last_match(1)}R10#{Regexp.last_match(3)}[0]" }
string = string.gsub(/(\d+)NC(10)?/i) { "#{Regexp.last_match(1)}R10[0]" }
string = string.gsub(/(\d+)NA(10)?([+\-][+\-\d]+)/i) { "#{Regexp.last_match(1)}R10#{Regexp.last_match(3)}[1]" }
string = string.gsub(/(\d+)NA(10)?/i) { "#{Regexp.last_match(1)}R10[1]" }

return string
def eval_game_system_specific_command(command)
roll_tables(command, self.class::TABLES) || nechronica_check(command)
end

public
def result_nd10(total, _dice_total, value_list, cmp_op, target)
# 後方互換を維持するため、1d10>=nを目標値nの1NCとして処理
if value_list.count != 1 || cmp_op != :>= || target.nil? || target == "?"
return nil
end

def eval_game_system_specific_command(command)
return roll_tables(command, self.class::TABLES) || nechronica_check(command)
result_nechronica([total], target)
end

private

def result_nd10(total, _dice_total, dice_list, cmp_op, target) # ゲーム別成功度判定(nD10)
return Result.nothing if target == '?'
return nil unless cmp_op == :>=

if total >= 11
Result.critical(translate("Nechronica.critical"))
elsif total >= target
Result.success(translate("success"))
elsif dice_list.count { |i| i <= 1 } == 0
Result.failure(translate("failure"))
elsif dice_list.size > 1
fumble = translate("Nechronica.fumble")
def result_nechronica(value_list, target, output = [], na = nil)
if value_list.max >= target
if value_list.max >= 11
output << translate("Nechronica.critical") << na
Result.critical(output.compact.join(" > "))
else
output << translate("success") << na
Result.success(output.compact.join(" > "))
end
elsif value_list.count { |i| i <= 1 } == 0
output << translate("failure") << na
Result.failure(output.compact.join(" > "))
elsif value_list.size > 1
break_all_parts = translate("Nechronica.break_all_parts")
Result.fumble("#{fumble} > #{break_all_parts}")
fumble = translate("Nechronica.fumble")
output << "#{fumble} > #{break_all_parts}" << na
Result.fumble(output.compact.join(" > "))
else
Result.fumble(translate("Nechronica.fumble"))
output << translate("Nechronica.fumble") << na
Result.fumble(output.compact.join(" > "))
end
end

def result_nd10_text(total, dice_list, target)
text = result_nd10(total, 0, dice_list, :>=, target)&.text
# Rコマンドの後方互換を維持する
def r_backward_compatibility(command)
m = command.match(/^(\d)?R10([+\-\d]+)?(\[(\d+)\])?$/)
return command unless m

if text.nil?
""
if m[4] == "1"
"#{m[1]}NA#{m[2]}"
else
" > #{text}"
"#{m[1]}NC#{m[2]}"
end
end

def nechronica_check(string)
string = replace_text(string)
debug("nechronica_check string", string)

unless /(^|\s)S?((\d+)[rR]10([+\-\d]+)?(\[(\d+)\])?)(\s|$)/i =~ string
return nil
end

string = Regexp.last_match(2)

dice_n = 1
dice_n = Regexp.last_match(3).to_i if Regexp.last_match(3)

battleMode = Regexp.last_match(6).to_i

modText = Regexp.last_match(4)
mod = ArithmeticEvaluator.eval(modText)

# 0=判定モード, 1=戦闘モード
isBattleMode = (battleMode == 1)
debug("nechronica_check string", string)
debug("isBattleMode", isBattleMode)

diff = 6

dice = @randomizer.roll_barabara(dice_n, 10).sort
n_max = dice.max

total_n = n_max + mod

output = "(#{string}) > [#{dice.join(',')}]"
if mod < 0
output += mod.to_s
elsif mod > 0
output += "+#{mod}"
end

dice.map! { |i| i + mod }

dice_str = dice.join(",")
output += " > #{total_n}[#{dice_str}]"

output += result_nd10_text(total_n, dice, diff)

if isBattleMode
hit_loc = getHitLocation(total_n)
if hit_loc != '1'
output += " > #{hit_loc}"
end
end

return output
def nechronica_check(command)
command = r_backward_compatibility(command)
# 歴史的経緯で10を受理する
cmd = Command::Parser.new(/N(C|A)(10)?/, round_type: round_type)
.enable_prefix_number.parse(command)
return nil unless cmd

dice_count = [1, cmd.prefix_number.to_i].max
modify_number = cmd.modify_number || 0

dice = @randomizer.roll_barabara(dice_count, 10).sort
dice_mod = dice.map { |i| i + modify_number }
total = dice_mod.max

output = [
"(#{cmd})",
"[#{dice.join(',')}]#{Format.modifier(modify_number)}",
"#{total}[#{dice_mod.join(',')}]",
]
na = get_hit_location(total) if cmd.command.include?("NA")
result_nechronica(dice_mod, 6, output, na)
end

def getHitLocation(dice)
output = '1'

debug("getHitLocation dice", dice)
return output if dice <= 5
def get_hit_location(value)
return nil if value <= 5

table = translate("Nechronica.hit_location.table")
index = dice - 6
text = table[(value - 6).clamp(0, 5)]

addDamage = ""
if dice > 10
index = 5
addDamage = translate("Nechronica.hit_location.additional_damage", damage: dice - 10)
if value > 10
text + translate("Nechronica.hit_location.additional_damage", damage: value - 10)
else
text
end

output = table[index] + addDamage

return output
end

class << self
Expand All @@ -173,7 +137,7 @@ def translate_tables(locale)

TABLES = translate_tables(:ja_jp)

register_prefix('\d+NC', '\d+NA', '\d+R10', TABLES.keys)
register_prefix('\d?NC', '\d?NA', '\dR10', TABLES.keys)
end
end
end
Loading