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

ソード・ワールドの威力表ダイスをパーサを使用したものに変更、半減後修正に対応 #373

Merged
merged 21 commits into from
Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
be60cc7
パーサー作成
h-mikisato Jan 27, 2021
2ea85fe
パーサを使った形に書き換え
h-mikisato Jan 28, 2021
a2d5f1f
ダイステキストの作成およびサニタイズ処理をRatingParsedクラスに移管
h-mikisato Jan 28, 2021
5bdd1e4
ヘルプに半減後加算について記載
h-mikisato Jan 28, 2021
8883a8c
カッコのパターン追記
h-mikisato Jan 28, 2021
42c692f
複数箇所でのmodifierに対応
h-mikisato Jan 28, 2021
49591b9
rubocop
h-mikisato Jan 28, 2021
e653dcd
除算がバグっていたので修正、テスト追加
h-mikisato Jan 28, 2021
92f3005
2.5のヘルプテキストが不完全だったので修正
h-mikisato Jan 28, 2021
297e196
負数の処理をスキップしてしまっていたバグ修正
h-mikisato Jan 28, 2021
7c217a2
仕様が非直感的と指摘を受けたのでヘルプテキスト修正
h-mikisato Jan 28, 2021
c9cd903
レビュー反映
h-mikisato Jan 29, 2021
8aaeca0
rubocop
h-mikisato Jan 29, 2021
b2e7776
複数箇所でのmodifierの統合を許可しない
h-mikisato Jan 29, 2021
f1bddb3
コミット漏れ
h-mikisato Jan 29, 2021
657eddb
半減後加算修正なしの方のパースでエラー処理漏れ
h-mikisato Jan 30, 2021
2209b44
ヘルプメッセージがレビュー前の仕様だったので修正
h-mikisato Feb 2, 2021
bf95d5d
Merge branch 'master' into feature/sw_rating_racc
ysakasin Feb 25, 2021
1111cef
Remove set_round_type
ysakasin Feb 25, 2021
92db21a
sanitized_ではなくgetterで隠蔽する
ysakasin Feb 25, 2021
9e60567
SwordWorld#setRatingTable を削除
ysakasin Feb 25, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ lib/bcdice/common_command/barabara_dice/parser.rb
lib/bcdice/common_command/calc/parser.rb
lib/bcdice/common_command/reroll_dice/parser.rb
lib/bcdice/common_command/upper_dice/parser.rb
lib/bcdice/game_system/sword_world/rating_parser.rb
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ AllCops:
- lib/bcdice/common_command/calc/parser.rb
- lib/bcdice/common_command/reroll_dice/parser.rb
- lib/bcdice/common_command/upper_dice/parser.rb
- lib/bcdice/game_system/sword_world/rating_parser.rb

# Due to old Ruby 1.8.x
Style/Lambda:
Expand Down
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ RACC_TARGETS = [
"lib/bcdice/common_command/calc/parser.rb",
"lib/bcdice/common_command/reroll_dice/parser.rb",
"lib/bcdice/common_command/upper_dice/parser.rb",
"lib/bcdice/game_system/sword_world/rating_parser.rb",
].freeze

task racc: RACC_TARGETS
Expand Down
191 changes: 45 additions & 146 deletions lib/bcdice/game_system/SwordWorld.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require "bcdice/game_system/sword_world/rating_parser"

module BCDice
module GameSystem
class SwordWorld < Base
Expand All @@ -22,28 +24,6 @@ def initialize(command)
@rating_table = 0
end

# change_textで使うレーティング表コマンドの正規表現
#
# SW 2.5のダイスボットでも必要なため、共通化のために定数として定義する
RATING_TABLE_RE_FOR_CHANGE_TEXT = /\AS?H?K\d+/i.freeze

# コマンド実行前にメッセージを置換する
# @param [String] string 受信したメッセージ
# @return [String]
def replace_text(string)
return string unless RATING_TABLE_RE_FOR_CHANGE_TEXT.match?(string)

string
.gsub(/\[(\d+)\]/) { "c[#{Regexp.last_match(1)}]" }
.gsub(/@(\d+)/) { "c[#{Regexp.last_match(1)}]" }
.gsub(/\$([-+]?\d+)/) { "m[#{Regexp.last_match(1)}]" }
.gsub(/r([-+]?\d+)/i) { "r[#{Regexp.last_match(1)}]" }
end

def getRatingCommandStrings
"cmCM"
end

def result_2d6(total, dice_total, _dice_list, cmp_op, target)
if dice_total >= 12
Result.critical("自動的成功")
Expand All @@ -64,60 +44,32 @@ def eval_game_system_specific_command(command)

private

def rating_parser
return RatingParser.new
end

#################### SWレーティング表 ########################
def rating(string) # レーティング表
string = replace_text(string)
debug("rating string", string)
command = rating_parser.parse(string)

commands = getRatingCommandStrings

m = /^S?(H?K[\d+\-]+([#{commands}]\[([\d+\-]+)\])*([\d+\-]*)([CMR]\[([\d+\-]+)\]|GF|H)*)/i.match(string)
unless m
unless command
debug("not matched")
return '1'
end

string = m[1]
half = string.include?("H")

rateUp, string = getRateUpFromString(string)
crit, string = getCriticalFromString(string, half)
firstDiceChanteTo, firstDiceChangeModify, string = getDiceChangesFromString(string)

key, addValue = getKeyAndAddValueFromString(string)

return '1' unless key =~ /(\d+)/

key = Regexp.last_match(1).to_i

# 2.0対応
rate_sw2_0 = getSW2_0_RatingTable

keyMax = rate_sw2_0.length - 1
debug("keyMax", keyMax)
if key > keyMax
if command.rate > keyMax
return "キーナンバーは#{keyMax}までです"
end

newRates = getNewRates(rate_sw2_0)

output = "KeyNo.#{key}"

output += "c[#{crit}]" if crit < 13
output += "m[#{firstDiceChangeModify}]" if firstDiceChangeModify != 0
output += "m[#{firstDiceChanteTo}]" if firstDiceChanteTo != 0
output += "r[#{rateUp}]" if rateUp != 0

output, values = getAdditionalString(string, output)

debug('output', output)

if addValue != 0
output += "+#{addValue}" if addValue > 0
output += addValue.to_s if addValue < 0
end

output += " > "
output = "#{command} > "

diceResultTotals = []
diceResults = []
Expand All @@ -126,17 +78,19 @@ def rating(string) # レーティング表
diceOnlyTotal = 0
totalValue = 0
round = 0
first_to = command.sanitized_first_to
first_modify = command.sanitized_first_modify

loop do
dice_raw, diceText = rollDice(values)
dice_raw, diceText = rollDice(command)
dice = dice_raw

if firstDiceChanteTo != 0
dice = dice_raw = firstDiceChanteTo
firstDiceChanteTo = 0
elsif firstDiceChangeModify != 0
dice += firstDiceChangeModify.to_i
firstDiceChangeModify = 0
if first_to != 0
dice = dice_raw = first_to
first_to = 0
elsif first_modify != 0
dice += first_modify
first_modify = 0
end

# 出目がピンゾロの時にはそこで終了
Expand All @@ -149,12 +103,12 @@ def rating(string) # レーティング表
break
end

dice += getAdditionalDiceValue(dice, values)
dice += command.sanitized_kept_modify if (command.sanitized_kept_modify != 0) && (dice != 2)

dice = 2 if dice < 2
dice = 12 if dice > 12

currentKey = [key + round * rateUp, keyMax].min
currentKey = [command.rate + round * command.sanitized_rateup, keyMax].min
debug("currentKey", currentKey)
rateValue = newRates[dice][currentKey]
debug("rateValue", rateValue)
Expand All @@ -168,79 +122,15 @@ def rating(string) # レーティング表

round += 1

break unless dice >= crit
break unless dice >= command.sanitized_critical
end

output += getResultText(totalValue, addValue, diceResults, diceResultTotals,
rateResults, diceOnlyTotal, round, half)
output += getResultText(totalValue, command, diceResults, diceResultTotals,
rateResults, diceOnlyTotal, round)

return output
end

def getAdditionalString(_string, output)
values = {}
return output, values
end

def getAdditionalDiceValue(_dice, _values)
0
end

def getCriticalFromString(string, half)
crit = half ? 13 : 10

regexp = /c\[(\d+)\]/i

if regexp =~ string
crit = Regexp.last_match(1).to_i
crit = 3 if crit < 3 # エラートラップ(クリティカル値が3未満なら3とする)
string = string.gsub(regexp, '')
end

return crit, string
end

def getDiceChangesFromString(string)
firstDiceChanteTo = 0
firstDiceChangeModify = 0

regexp = /m\[([\d+\-]+)\]/i

if regexp =~ string
firstDiceChangeModify = Regexp.last_match(1)

unless /[+\-]/ =~ firstDiceChangeModify
firstDiceChanteTo = firstDiceChangeModify.to_i
firstDiceChangeModify = 0
end

string = string.gsub(regexp, '')
end

return firstDiceChanteTo, firstDiceChangeModify, string
end

def getRateUpFromString(string)
rateUp = 0
return rateUp, string
end

def getKeyAndAddValueFromString(string)
key = nil
addValue = 0

if /K(\d+)([\d+\-]*)/i =~ string # ボーナスの抽出
key = Regexp.last_match(1)
if Regexp.last_match(2)
addValue = ArithmeticEvaluator.eval(Regexp.last_match(2))
end
else
key = string
end

return key, addValue
end

def getSW2_0_RatingTable
rate_sw2_0 = [
# 0
Expand Down Expand Up @@ -397,23 +287,22 @@ def getNewRates(rate_sw2_0)
return newRates
end

def rollDice(_values)
def rollDice(_command)
dice_list = @randomizer.roll_barabara(2, 6)
total = dice_list.sum()
dice_str = dice_list.join(",")
return total, dice_str
end

# @param rating_total [Integer]
# @param modifier [Integer]
# @param command [SwordWorld::RatingParsed]
# @param diceResults [Array<String>]
# @param diceResultTotals [Array<String>]
# @param rateResults [Array<String>]
# @param dice_total [Integer]
# @param round [Integer]
# @param half [Boolean]
def getResultText(rating_total, modifier, diceResults, diceResultTotals,
rateResults, dice_total, round, half)
def getResultText(rating_total, command, diceResults, diceResultTotals,
rateResults, dice_total, round)
sequence = []

sequence.push("2D:[#{diceResults.join(' ')}]=#{diceResultTotals.join(',')}")
Expand All @@ -425,24 +314,34 @@ def getResultText(rating_total, modifier, diceResults, diceResultTotals,
end

# rate回数が1回で、修正値がない時には途中式と最終結果が一致するので、途中式を省略する
if rateResults.size > 1 || modifier != 0
text = rateResults.join(',') + Format.modifier(modifier)
if half
if rateResults.size > 1 || command.modifier != 0
text = rateResults.join(',') + Format.modifier(command.modifier)
if command.half
text = "(#{text})/2"
if command.sanitized_modifier_after_half != 0
text += Format.modifier(command.sanitized_modifier_after_half)
end
end
sequence.push(text)
elsif command.half
text = "#{rateResults.first}/2"
if command.sanitized_modifier_after_half != 0
text += Format.modifier(command.sanitized_modifier_after_half)
end
sequence.push(text)
elsif half
sequence.push("#{rateResults.first}/2")
end

if round > 1
round_text = "#{round - 1}回転"
sequence.push(round_text)
end

total = rating_total + modifier
if half
total = rating_total + command.modifier
if command.half
total = (total / 2.0).ceil
if command.sanitized_modifier_after_half != 0
total += command.sanitized_modifier_after_half
end
end

total_text = total.to_s
Expand Down
47 changes: 9 additions & 38 deletions lib/bcdice/game_system/SwordWorld2_0.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ class SwordWorld2_0 < SwordWorld
 またタイプの軽減化のために末尾に「@クリティカル値」でも処理するようにしました。
 例)K20[10]   K10+5[9]   k30[10]   k10[9]+10   k10-5@9

・レーティング表の半減 (HKx)
・レーティング表の半減 (HKx, KxH+N)
 レーティング表の先頭または末尾に"H"をつけると、レーティング表を振って最終結果を半減させます。
 末尾につけた場合、直後に修正ををつけることで、半減後の加減算を行うことができます。
 この際、複数の項による修正にはカッコで囲うことが必要です(カッコがないと、半減前の値の修正として扱われます)
 クリティカル値を指定しない場合、クリティカルなしと扱われます。
 例)HK20  K20h  HK10-5@9  K10-5@9H  K20gfH
 例)HK20  K20h  HK10-5@9  K10-5@9H  K20gfH  K20+8H+2  K20+8H(1+1)

・ダイス目の修正(運命変転やクリティカルレイ用)
 末尾に「$修正値」でダイス目に修正がかかります。
Expand Down Expand Up @@ -201,51 +203,20 @@ def eval_game_system_specific_command(command)
end
end

def getRateUpFromString(string)
rateUp = 0

regexp = /r\[(\d+)\]/i
if (m = regexp.match(string))
rateUp = m[1].to_i
string = string.gsub(regexp, '')
end

return rateUp, string
def rating_parser
return RatingParser.new.set_version(:v2_0)
end

def getAdditionalString(string, output)
output, values = super(string, output)

isGratestFortune, = getGratestFortuneFromString(string)

values['isGratestFortune'] = isGratestFortune
output += "gf" if isGratestFortune

return output, values
end

def rollDice(values)
unless values['isGratestFortune']
return super(values)
def rollDice(command)
unless command.greatest_fortune
return super(command)
end

dice = @randomizer.roll_once(6)

return dice * 2, "#{dice},#{dice}"
end

def getGratestFortuneFromString(string)
isGratestFortune = false

regexp = /gf/i
if regexp.match?(string)
isGratestFortune = true
string = string.gsub(regexp, '')
end

return isGratestFortune, string
end

def growth(count = 1)
((1..count).map { growth_step }).join " | "
end
Expand Down
Loading