bcdice 3.14.0 → 3.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -0
  3. data/i18n/Cthulhu/zh_hant.yml +1 -1
  4. data/i18n/CyberpunkRed/ko_kr.yml +389 -0
  5. data/i18n/DoubleCross/ja_jp.yml +53 -0
  6. data/i18n/DoubleCross/ko_kr.yml +52 -0
  7. data/i18n/Emoklore/ko_kr.yml +7 -0
  8. data/i18n/FutariSousa/ja_jp.yml +138 -138
  9. data/i18n/KillDeathBusiness/ja_jp.yml +198 -0
  10. data/i18n/MagicaLogia/ko_kr.yml +2 -2
  11. data/i18n/MonotoneMuseum/ko_kr.yml +227 -0
  12. data/i18n/SkynautsBouken/ja_jp.yml +28 -28
  13. data/i18n/SkynautsBouken/ko_kr.yml +114 -0
  14. data/i18n/StratoShout/ko_kr.yml +102 -102
  15. data/i18n/zh_hant.yml +5 -0
  16. data/lib/bcdice/game_system/Aionia.rb +131 -0
  17. data/lib/bcdice/game_system/Arianrhod_Korean.rb +2 -0
  18. data/lib/bcdice/game_system/ArknightsFan.rb +245 -87
  19. data/lib/bcdice/game_system/BlackJacket_Korean.rb +244 -0
  20. data/lib/bcdice/game_system/CharonSanctions.rb +112 -0
  21. data/lib/bcdice/game_system/Cthulhu7th.rb +1 -1
  22. data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional/full_auto.rb +293 -0
  23. data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional/rollable.rb +43 -0
  24. data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb +470 -306
  25. data/lib/bcdice/game_system/CyberpunkRed.rb +1 -2
  26. data/lib/bcdice/game_system/CyberpunkRed_Korean.rb +66 -0
  27. data/lib/bcdice/game_system/DoubleCross.rb +18 -1
  28. data/lib/bcdice/game_system/DoubleCross_Korean.rb +5 -1
  29. data/lib/bcdice/game_system/EdgeFlippers.rb +315 -0
  30. data/lib/bcdice/game_system/Emoklore_Korean.rb +42 -0
  31. data/lib/bcdice/game_system/FullFace.rb +25 -3
  32. data/lib/bcdice/game_system/FutariSousa.rb +17 -5
  33. data/lib/bcdice/game_system/Garactier.rb +479 -0
  34. data/lib/bcdice/game_system/GardenOrder.rb +390 -9
  35. data/lib/bcdice/game_system/GundogRevised.rb +8 -8
  36. data/lib/bcdice/game_system/JuinKansen_Korean.rb +251 -0
  37. data/lib/bcdice/game_system/KillDeathBusiness.rb +155 -3
  38. data/lib/bcdice/game_system/KimitoYell.rb +568 -0
  39. data/lib/bcdice/game_system/Magius.rb +125 -0
  40. data/lib/bcdice/game_system/Magius_3rdNewTokyoCity.rb +62 -0
  41. data/lib/bcdice/game_system/MeikyuKingdomBasic.rb +122 -2
  42. data/lib/bcdice/game_system/MonotoneMuseum_Korean.rb +4 -4
  43. data/lib/bcdice/game_system/NSSQ.rb +17 -9
  44. data/lib/bcdice/game_system/NervWhitePaper.rb +129 -0
  45. data/lib/bcdice/game_system/Revulture_Korean.rb +125 -0
  46. data/lib/bcdice/game_system/RogueLikeHalf.rb +198 -0
  47. data/lib/bcdice/game_system/RuneQuestRoleplayingInGlorantha.rb +16 -13
  48. data/lib/bcdice/game_system/ShinobiGami.rb +73 -43
  49. data/lib/bcdice/game_system/SkynautsBouken.rb +4 -4
  50. data/lib/bcdice/game_system/SkynautsBouken_Korean.rb +57 -0
  51. data/lib/bcdice/game_system/StratoShout_Korean.rb +1 -1
  52. data/lib/bcdice/game_system/SwordWorld.rb +4 -0
  53. data/lib/bcdice/game_system/SwordWorld2_5.rb +3 -2
  54. data/lib/bcdice/game_system/TensaiGunshiNiNaro.rb +51 -17
  55. data/lib/bcdice/game_system/TheIndieHack.rb +82 -0
  56. data/lib/bcdice/game_system/TorgEternity.rb +35 -6
  57. data/lib/bcdice/game_system/Ventangle_Korean.rb +130 -0
  58. data/lib/bcdice/game_system/WoW.rb +161 -0
  59. data/lib/bcdice/game_system/YankeeMustDie.rb +192 -0
  60. data/lib/bcdice/game_system/YearZeroEngine.rb +225 -28
  61. data/lib/bcdice/game_system/YuMyoKishi.rb +141 -0
  62. data/lib/bcdice/game_system/meikyu_kingdom_basic/atoz_table.rb +1184 -0
  63. data/lib/bcdice/game_system/meikyu_kingdom_basic/randr236_table.rb +254 -0
  64. data/lib/bcdice/game_system/meikyu_kingdom_basic/table.rb +54 -0
  65. data/lib/bcdice/game_system/meikyu_kingdom_basic/tk_table.rb +755 -0
  66. data/lib/bcdice/game_system/sword_world/rating_lexer.rb +1 -0
  67. data/lib/bcdice/game_system/sword_world/rating_options.rb +4 -1
  68. data/lib/bcdice/game_system/sword_world/rating_parsed.rb +5 -0
  69. data/lib/bcdice/game_system/sword_world/rating_parser.rb +129 -115
  70. data/lib/bcdice/game_system.rb +20 -0
  71. data/lib/bcdice/version.rb +1 -1
  72. metadata +31 -6
@@ -85,6 +85,7 @@ module BCDice
85
85
  round = 0
86
86
  first_to = command.first_to
87
87
  first_modify = command.first_modify
88
+ first_modify_ssp = command.first_modify_ssp
88
89
 
89
90
  loop do
90
91
  dice_raw, diceText = rollDice(command, round)
@@ -96,6 +97,9 @@ module BCDice
96
97
  elsif first_modify != 0
97
98
  dice += first_modify
98
99
  first_modify = 0
100
+ elsif first_modify_ssp != 0
101
+ dice += first_modify_ssp if dice_raw <= 10
102
+ first_modify_ssp = 0
99
103
  end
100
104
 
101
105
  # 出目がピンゾロの時にはそこで終了
@@ -46,11 +46,12 @@ module BCDice
46
46
   クリティカル値を指定しない場合、クリティカルなしと扱われます。
47
47
   例)OHK20  K20oh  OHK10-5@9  K20+8OH+2  K20+8OH+(1+1)
48
48
 
49
- ・ダイス目の修正(運命変転やクリティカルレイ用)
49
+ ・ダイス目の修正(運命変転やクリティカルレイ、魔女の火用)
50
50
   末尾に「$修正値」でダイス目に修正がかかります。
51
51
   $+1と修正表記ならダイス目に+修正、$9のように固定値ならダイス目をその出目に差し替え。
52
+  $~+1とチルダを追加して記述することで、出目10以下の場合のみダイス目に+修正(魔女の火用)
52
53
   クリティカルした場合でも固定値や修正値の適用は最初の一回だけです。
53
-  例)K20$+1   K10+5$9   k10-5@9$+2   k10[9]+10$9
54
+  例)K20$+1   K10+5$9   k10-5@9$+2   k10[9]+10$9   k20+6$~+1
54
55
 
55
56
  ・ダイス目の修正(必殺攻撃用)
56
57
   「#修正値」でダイス目に修正がかかります。
@@ -17,21 +17,34 @@ module BCDice
17
17
  ・行為判定
18
18
  TN6…「有利」を得ていない場合、6面ダイスを2つ振って判定します。
19
19
  TN10…「有利」を得ている場合、10面ダイスを2つ振って判定します。
20
- 不調 気づかぬうちの不満【C】…判定のダイス目が「4」でも判定に成功しません。数字の後ろに【C】をつけます。
20
+ 不調 気づかぬうちの不満【C】…このセッションの間、「4」の出目を出しても判定は成功になりません。数字の後ろに【C】をつけます。
21
21
   例)TN6C
22
22
  軍師スキル 〇〇サポート【S】…決戦フェイズの判定中「3」の出目を出しても判定に成功します。数字の後ろに【S】をつけます。
23
23
   例)TN6S
24
24
  英傑スキル/武人 煌めく刃【B】…決戦フェイズの判定中「3」の出目を出しても判定に成功となり、スペシャルが発生します。数字の後ろに【B】をつけます。
25
25
   例)TN6B
26
+ 英傑スキル/武人 力ずく…その判定のサイコロをすべて振った後、[使用者の【攻撃力】]個サイコロを振る。先頭に使用者の【攻撃力】をつけます。
27
+  例)4TN6
28
+ 英傑スキル/武人 必殺の剣【D】…《戦技》を使用している判定中「4」「5」の出目を出してもスペシャルが発生します。数字の後ろに【D】をつけます。
29
+  例)TN6K
30
+ 英傑スキル/武人 二刀流【T】…「攻撃」のスキルの判定中「2」の出目を出しても判定に成功となり、同じ出目のサイコロが2つ以上出ているとスペシャルが発生します。数字の後ろに【T】をつけます。
31
+  例)TN6T
26
32
  英傑スキル/カリスマ 御身のためならば【Y】…「交流」「スカウト」の判定中「3」の出目を出しても判定に成功となり、スペシャルが発生します。数字の後ろに【Y】をつけます。
27
33
   例)TN6Y
34
+ 英傑スキル/弓取り 愛用の弓【A】…「攻撃」のスキルの判定中「3」の出目を出しても判定に成功となり、スペシャルが発生します。数字の後ろに【A】をつけます。
35
+  例)TN6A
36
+ 英傑スキル/ヤンキー&マイルドヤンキー その辺の物を武器に【C】…「4」の出目を出しても判定は成功になりません。数字の後ろに【C】をつけます。
37
+  例)TN6C
38
+ 英傑スキル/ヤンキー&マイルドヤンキー 熱血判定【C】…「4」の出目を出しても判定は成功になりません。数字の後ろに【C】をつけます。
39
+  例)TN6C
28
40
  英傑スキル/英傑汎用 凄腕エージェント【A】…活動フェイズの判定中「3」の出目を出しても判定に成功となり、スペシャルが発生します。数字の後ろに【A】をつけます。
29
41
   例)TN6A
30
42
  数字の後ろに複数のコマンドを追加できます。
31
43
   例)TN10CYA
32
- ・ダメージ計算 xDM>=t
44
+ ・ダメージ計算 xDM+y>=t
33
45
   [ダメージ計算]を行う。成否と【HP】の減少量を表示する。
34
46
   x: 6面ダイス数
47
+  y: 補正値(省略可能)
35
48
   t: 防御力
36
49
  ・各種表
37
50
  関係決定表 RELA
@@ -48,7 +61,7 @@ module BCDice
48
61
  @round_type = RoundType::FLOOR
49
62
  end
50
63
 
51
- register_prefix('TN(6|10)[CSBYA]*', '\d+DM')
64
+ register_prefix('\d*TN(6|10)[ABCKSTY]*', '\d+DM')
52
65
 
53
66
  def eval_game_system_specific_command(command)
54
67
  roll_judge(command) || roll_damage(command) || roll_tables(command, self.class::TABLES)
@@ -58,7 +71,7 @@ module BCDice
58
71
 
59
72
  # 行為判定
60
73
  def roll_judge(command)
61
- m = /^TN(6|10)([CSBYA]*)$/.match(command)
74
+ m = /^(\d*)TN(6|10)([ABCKSTY]*)$/.match(command)
62
75
  unless m
63
76
  return nil
64
77
  end
@@ -73,51 +86,73 @@ module BCDice
73
86
  fumble_dices = [1]
74
87
 
75
88
  # 有利
76
- advantage = m[1] == "10"
89
+ advantage = m[2] == "10"
77
90
 
78
91
  # 不調 気づかぬうちの不満
79
- complaints = m[2].include?("C")
92
+ complaints = m[3].include?("C")
80
93
 
81
94
  # 軍師スキル 〇〇サポート
82
- support = m[2].include?("S")
95
+ support = m[3].include?("S")
83
96
 
84
97
  # 英傑スキル/武人 煌めく刃
85
- blade = m[2].include?("B")
98
+ blade = m[3].include?("B")
99
+
100
+ # 英傑スキル/武人 必殺の剣
101
+ killer = m[3].include?("K")
102
+
103
+ # 英傑スキル/武人 二刀流
104
+ twin = m[3].include?("T")
86
105
 
87
106
  # 英傑スキル/カリスマ 御身のためならば
88
- you = m[2].include?("Y")
107
+ you = m[3].include?("Y")
89
108
 
109
+ # 英傑スキル/弓取り 愛用の弓
90
110
  # 英傑スキル/英傑汎用 凄腕エージェント
91
- agent = m[2].include?("A")
111
+ agent = m[3].include?("A")
92
112
 
93
- # 〇〇サポート、煌めく刃、御身のためならば、凄腕エージェントいずれかの適用時
113
+ # 二刀流の適用時
114
+ if twin
115
+ # 成功となる出目に2を追加
116
+ success_dices.push(2)
117
+ end
118
+
119
+ # 〇〇サポート、煌めく刃、愛用の弓、御身のためならば、凄腕エージェントいずれかの適用時
94
120
  if support | blade | you | agent
95
121
  # 成功となる出目に3を追加
96
122
  success_dices.push(3)
97
123
  end
98
124
 
99
- # 煌めく刃、御身のためならば、凄腕エージェントいずれかの適用時
125
+ # 煌めく刃、御身のためならば、愛用の弓、凄腕エージェントいずれかの適用時
100
126
  if blade | you | agent
101
127
  # スペシャルとなる出目に3を追加
102
128
  special_dices.push(3)
103
129
  end
104
130
 
131
+ # 必殺の剣の適用時
132
+ if killer
133
+ # スペシャルとなる出目に4,5を追加
134
+ special_dices.push(4)
135
+ special_dices.push(5)
136
+ end
137
+
105
138
  # 気づかぬうちの不満適用時
106
139
  if complaints
107
140
  # 成功となる出目から4を削除
108
141
  success_dices.delete(4)
109
142
  end
110
143
 
144
+ # 英傑スキル/武人 力ずく
145
+ times = 2 + m[1].to_i
111
146
  dice_size = advantage ? 10 : 6
112
- dice_list = @randomizer.roll_barabara(2, dice_size)
147
+ dice_list = @randomizer.roll_barabara(times, dice_size)
113
148
 
114
149
  texts = []
115
150
  is_critical = false
116
151
  is_fumble = false
117
152
  is_success = false
118
153
 
119
- # スペシャルとなる出目を含む場合
120
- unless dice_list.intersection(special_dices).empty?
154
+ # スペシャルとなる出目を含む、または、二刀流の適用時かつ同じ出目のサイコロが2つ以上出ている場合
155
+ if !dice_list.intersection(special_dices).empty? | (twin & (dice_list.count != dice_list.uniq.count))
121
156
  # クリティカルフラグを立てる
122
157
  is_critical = true
123
158
  # スペシャルのシステムメッセージを追加
@@ -169,7 +204,6 @@ module BCDice
169
204
  def roll_damage(command)
170
205
  parser = Command::Parser.new("DM", round_type: @round_type)
171
206
  .has_prefix_number
172
- .disable_modifier
173
207
  .restrict_cmp_op_to(:>=)
174
208
  parsed = parser.parse(command)
175
209
  unless parsed
@@ -180,7 +214,7 @@ module BCDice
180
214
  is_success = false
181
215
 
182
216
  # ダメージ計算
183
- damage = @randomizer.roll_sum(parsed.prefix_number, 6)
217
+ damage = @randomizer.roll_sum(parsed.prefix_number, 6) + parsed.modify_number
184
218
  # HP減少量計算
185
219
  dec = damage / parsed.target_number
186
220
 
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class TheIndieHack < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'TheIndieHack'
8
+
9
+ # ゲームシステム名
10
+ NAME = 'The Indie Hack'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'しいんていはつく'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGETEXT
17
+ ■判定 cIH+a c:CL a:能力値
18
+
19
+ 例)IH: ライトダイスとダークダイスを1個ずつ振って、その結果を表示
20
+ INFO_MESSAGETEXT
21
+
22
+ register_prefix('([+-]?\d)?IH')
23
+
24
+ def eval_game_system_specific_command(command)
25
+ resolute_action(command)
26
+ end
27
+
28
+ private
29
+
30
+ # ダイス判定
31
+ # @param [String] command
32
+ # @return [Result]
33
+ def resolute_action(command)
34
+ m = /([+-]?\d)?IH([+-]\d)?/.match(command)
35
+ return nil unless m
36
+
37
+ cl = m[1].to_i
38
+ abilities = m[2].to_i
39
+
40
+ dices = @randomizer.roll_barabara(2, 6)
41
+ dice_text = dices.join(",")
42
+ dices[0] += cl
43
+ dices[1] += abilities
44
+ dice_text2 = dices.join(",")
45
+ diff = dices[1] - dices[0]
46
+ side = diff < 0 ? "ライト" : "ダーク"
47
+ side = "両" if diff == 0
48
+ if dice_text == dice_text2
49
+ output = "(IH) > #{dice_text} > #{side}#{get_success_level(diff)}"
50
+ else
51
+ output = "(#{m[1]}IH#{m[2]}) > [#{dice_text}] > #{dice_text2} > #{side}#{get_success_level(diff)}"
52
+ end
53
+ if diff > 0
54
+ return Result.success(output)
55
+ elsif diff < 0
56
+ return Result.failure(output)
57
+ else
58
+ return Result.new.tap do |result|
59
+ result.text = output
60
+ end
61
+ end
62
+ end
63
+
64
+ def get_success_level(die_difference)
65
+ case die_difference.abs
66
+ when 0
67
+ return "陣営がそれぞれ確定描写を1つ追加します"
68
+ when 1
69
+ return "陣営が確定描写を1つ追加しますが、味方によって追加されたネガティブな確定描写を1つ受けます"
70
+ when 2
71
+ return "陣営が確定描写を1つ追加します"
72
+ when 3
73
+ return "陣営が確定描写を1つ追加し、さらに場面描写を1つ追加します"
74
+ when 4
75
+ return "陣営が確定描写を1つ追加し、さらにその陣営の味方ひとりも確定描写を1つ追加します"
76
+ else
77
+ return "陣営が確定描写を2つ追加します"
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -31,6 +31,11 @@ module BCDice
31
31
    mはポシビリティを使用する前のロール結果を入れて下さい。
32
32
    出目が10未満の場合は、10への読み替えが行われます。
33
33
    また、振り足しを自動で行い、20の出目が出たときには技能無し値も並記します。
34
+  ・CPOS
35
+   "CPOSm"で、コズムポシビリティ使用による1d20のロールを行います。
36
+   mはポシビリティを使用する前のロール結果を入れて下さい。
37
+   出目が10未満の場合でも、10への読み替えが行われません。
38
+   振り足しは自動で行い、20の出目が出たときには技能無し値も並記します。
34
39
  ・ボーナスダメージロール
35
40
   "xBD[+y]"でロールします。[]内は省略可能。
36
41
   xはダメージダイス数。yはダメージ基本値 or 式を入れて下さい。
@@ -42,13 +47,14 @@ module BCDice
42
47
   ・ダメージ結果表「DTx or DAMAGEx」
43
48
   ・ロールボーナス表「BTx+y or BONUSx+y or TOTALx+y」 xは数値, yは技能基本値
44
49
  INFO_MESSAGE_TEXT
45
- register_prefix('TE', 'UP', 'POS', '\d+BD', 'TG', 'RT', 'Result', 'DT', 'damage', 'BT', 'bonus', 'total', '1R20')
50
+ register_prefix('TE', 'UP', 'POS', 'CPOS', '\d+BD', 'TG', 'RT', 'Result', 'DT', 'damage', 'BT', 'bonus', 'total', '1R20')
46
51
 
47
52
  def eval_game_system_specific_command(command)
48
53
  torg_check(command) ||
49
54
  getRolld20DiceCommandResult(command) ||
50
55
  getUpRollDiceCommandResult(command) ||
51
56
  getPossibilityRollDiceCommandResult(command) ||
57
+ getCosmPossibilityRollDiceCommandResult(command) ||
52
58
  getBonusDamageDiceCommandResult(command) ||
53
59
  getSuccessLevelDiceCommandResult(command) ||
54
60
  getDamageResultDiceCommandResult(command) ||
@@ -75,7 +81,7 @@ module BCDice
75
81
  mod = m[1]
76
82
 
77
83
  debug(mod)
78
- mod = ArithmeticEvaluator.eval(mod) if mod
84
+ mod = mod ? Arithmetic.eval(mod, @round_type) : 0
79
85
  debug(mod)
80
86
  mod = mod.to_i
81
87
  skilled, unskilled, dice_str, = torg_eternity_dice(false, false)
@@ -191,7 +197,7 @@ module BCDice
191
197
  return nil
192
198
  end
193
199
 
194
- output_modifier = ArithmeticEvaluator.eval(m[1])
200
+ output_modifier = m[1] ? Arithmetic.eval(m[1], @round_type) : 0
195
201
  skilled, unskilled, dice_str, = torg_eternity_dice(true, false)
196
202
  subtotal_skilled = skilled + output_modifier
197
203
  subtotal_unskilled = unskilled + output_modifier
@@ -206,6 +212,29 @@ module BCDice
206
212
  return output
207
213
  end
208
214
 
215
+ # ロールコマンド (コズムポシビリティロール)
216
+ def getCosmPossibilityRollDiceCommandResult(command)
217
+ debug("Torg Eternity CosmPossibility Roll Command ? ", command)
218
+ m = /^CPOS((\d+)(\+\d+)?)$/i.match(command)
219
+ unless m
220
+ return nil
221
+ end
222
+
223
+ output_modifier = m[1] ? Arithmetic.eval(m[1], @round_type) : 0
224
+ skilled, unskilled, dice_str, = torg_eternity_dice(false, false)
225
+ subtotal_skilled = skilled + output_modifier
226
+ subtotal_unskilled = unskilled + output_modifier
227
+ value_skilled = format("%+d", get_torg_eternity_bonus(subtotal_skilled))
228
+ if subtotal_skilled != subtotal_unskilled
229
+ value_unskilled = format("%+d", get_torg_eternity_bonus(subtotal_unskilled))
230
+ output = "d20ロール(ポシビリティ) > #{output_modifier}+1d20[#{dice_str}] > #{value_skilled}[#{subtotal_skilled}](技能有) / #{value_unskilled}[#{subtotal_unskilled}](技能無)"
231
+ else
232
+ output = "d20ロール(ポシビリティ) > #{output_modifier}+1d20[#{dice_str}] > #{value_skilled}[#{subtotal_skilled}]"
233
+ end
234
+
235
+ return output
236
+ end
237
+
209
238
  # ダメージボーナスコマンド
210
239
  def getBonusDamageDiceCommandResult(command)
211
240
  debug("TorgEternity Bonus Damage Roll Command ? ", command)
@@ -234,7 +263,7 @@ module BCDice
234
263
  return nil
235
264
  end
236
265
 
237
- value = ArithmeticEvaluator.eval(m[2])
266
+ value = m[2] ? Arithmetic.eval(m[2], @round_type) : 0
238
267
  debug(value)
239
268
  if value < 0
240
269
  output = "Failure."
@@ -254,7 +283,7 @@ module BCDice
254
283
  return nil
255
284
  end
256
285
 
257
- value = ArithmeticEvaluator.eval(m[2])
286
+ value = m[2] ? Arithmetic.eval(m[2], @round_type) : 0
258
287
  debug(value)
259
288
  output = get_torg_eternity_damage_result(value)
260
289
  output = "ダメージ結果表[#{value}] > #{output}"
@@ -307,7 +336,7 @@ module BCDice
307
336
  value_modifier = 0
308
337
  output_modifier = ""
309
338
  else
310
- value_modifier = ArithmeticEvaluator.eval(string_modifier)
339
+ value_modifier = string_modifier ? Arithmetic.eval(string_modifier, @round_type) : 0
311
340
  output_modifier = format("%+d", value_modifier)
312
341
  end
313
342
  debug(value_modifier)
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bcdice/base'
4
+
5
+ module BCDice
6
+ module GameSystem
7
+ class Ventangle_Korean < Ventangle
8
+ # ゲームシステムの識別子
9
+ ID = 'Ventangle:Korean'
10
+
11
+ # ゲームシステム名
12
+ NAME = '벤탱글'
13
+
14
+ # ゲームシステム名の読みがな
15
+ SORT_KEY = '国際化:Korean:벤탱글'
16
+
17
+ # ダイスボットの使い方
18
+ HELP_MESSAGE = <<~MESSAGETEXT
19
+ 기본 양식 VTn@s#f$g>=T n=주사위 개수(생략 시 2) s=스페셜치(생략 시 12) f=펌블치(생략 시 2) g=레벨 갭 판정치(생략 가능) T=목표치(생략 가능)
20
+
21
+ 예시:
22
+ VT 기본 스페셜치, 펌블치로 판정
23
+ VT@10#3 스페셜치 10、펌블치 3으로 판정
24
+ VT3@10#3 어드밴티지 1점을 사용해 스페셜치 10, 펌블치 3 판정을 주사위 3개로 판정
25
+
26
+ VT>=5 기본 스페셜치, 펌블치로 목표치 5 판정
27
+ VT@10#3>=5 스페셜치 10, 펌블치 3으로 목표치 5 판정
28
+ VT@10#3$5>=5 스페셜치 10, 펌블치 3으로 목표치 5 판정. 이때 달성치가 목표치보다 5이상 큰 경우, 갭 보너스를 표시
29
+ VT3@10#3>=5 어드밴티지 1점을 사용해 스페셜치 10, 펌블치 3, 목표치 5 판정을 주사위 3개로 판정
30
+ VT3@10#3$4>=5 어드밴티지 1점을 사용해 스페셜치 10, 펌블치 3, 목표치 5 판정을 주사위 3개로 판정. 이때 달성치가 목표치보다 4이상 큰 경우, 갭 보너스를 표시
31
+ MESSAGETEXT
32
+
33
+ # 既定のスペシャル値
34
+ DEFAULT_SPECIAL_VALUE = 12
35
+ # 既定のファンブル値
36
+ DEFAULT_FUMBLE_VALUE = 2
37
+ # 規定のダイス個数
38
+ DEFAULT_DICE_NUM = 2
39
+
40
+ # ダイスボットで使用するコマンドを配列で列挙する
41
+ register_prefix('VT')
42
+
43
+ def eval_game_system_specific_command(command)
44
+ debug("eval_game_system_specific_command Begin")
45
+
46
+ parser = Command::Parser.new('VT', round_type: round_type)
47
+ .enable_critical
48
+ .enable_fumble
49
+ .enable_dollar
50
+ .enable_suffix_number
51
+ .restrict_cmp_op_to(nil, :>=)
52
+ cmd = parser.parse(command)
53
+
54
+ unless cmd
55
+ return nil
56
+ end
57
+
58
+ dice_num = cmd.suffix_number || DEFAULT_DICE_NUM
59
+ if dice_num < DEFAULT_DICE_NUM
60
+ return nil
61
+ end
62
+
63
+ dice_list = @randomizer.roll_barabara(dice_num, 6)
64
+ if dice_num > 2
65
+ # 出目の順序を保存して上位2つの出目を取得
66
+ j = 0 # 安定ソートのために利用 cf. https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/sort_by.html
67
+ using_list = dice_list.map.with_index { |x, i| {index: i, value: x} }
68
+ .sort_by { |x| [x[:value], j += 1] }.reverse.take(2)
69
+ .sort_by { |x| x[:index] }.map { |x| x[:value] }
70
+ else
71
+ using_list = dice_list
72
+ end
73
+ dice_total = using_list.sum
74
+ total = dice_total + cmd.modify_number
75
+
76
+ result = compare(dice_total, total, cmd)
77
+
78
+ advantage_str =
79
+ if dice_num > 2
80
+ using_list.to_s
81
+ end
82
+
83
+ modifier_str =
84
+ if cmd.modify_number > 0
85
+ "#{dice_total}#{Format.modifier(cmd.modify_number)}"
86
+ end
87
+
88
+ level_gap_str =
89
+ if cmd.target_number && cmd.dollar && result.success? && (gap = total - cmd.target_number) >= cmd.dollar
90
+ "갭 보너스(#{gap})"
91
+ end
92
+
93
+ sequence = [
94
+ cmd.to_s,
95
+ dice_list.to_s,
96
+ advantage_str,
97
+ modifier_str,
98
+ total.to_s,
99
+ result.text,
100
+ level_gap_str,
101
+ ].compact
102
+
103
+ result.text = sequence.join(" > ")
104
+
105
+ return result
106
+ end
107
+
108
+ def compare(dice_total, total, cmd)
109
+ special = cmd.critical || DEFAULT_SPECIAL_VALUE
110
+ fumble = cmd.fumble || DEFAULT_FUMBLE_VALUE
111
+
112
+ if dice_total <= fumble
113
+ return Result.fumble('펌블')
114
+ elsif dice_total >= special
115
+ return Result.critical('스페셜')
116
+ end
117
+
118
+ if cmd.target_number
119
+ if total.send(cmd.cmp_op, cmd.target_number)
120
+ return Result.success('성공')
121
+ else
122
+ return Result.failure('실패')
123
+ end
124
+ else
125
+ return Result.new(nil)
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class WoW < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'WoW'
8
+
9
+ # ゲームシステム名
10
+ NAME = 'ワンダーオブワンダラー'
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = 'わんたあおふわんたらあ'
14
+
15
+ # ダイスボットの使い方
16
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
17
+ 行為判定 nWW12@s#f<=x
18
+ n: ダイス数
19
+ @s = 大成功値(省略可:デフォルトは1)
20
+ #f = 大失敗値(省略可:デフォルトは12)
21
+ x = 目標値(省略可:デフォルトは6)
22
+ 例)1WW12 5WW12<=6 6WW12@5#3<=7+1
23
+
24
+ ランダムギフトガチャ表 GG
25
+ ランダムギフトガチャ表(アルファベット指定) GGx 例)GGA GGB
26
+
27
+ ファンブル表 FT
28
+ INFO_MESSAGE_TEXT
29
+
30
+ register_prefix('\d*WW12', 'GG', 'GGA', 'GGB', 'GGC', 'GGD', 'GGE', 'GGF', 'GGG', 'GGH', 'FT')
31
+
32
+ TABLES = {
33
+ 'A' => [
34
+ '演者の声', '言いくるめ', '誤魔化し', '代弁者', '腕利き弁護人', '魔性', '魔術', '魔法的物理', '誤り指摘', '専門知識', '理力増幅', '協力的な有識者'
35
+ ],
36
+ 'B' => [
37
+ '百科全書', '地道な下調べ', '思い…出した!', '目星', 'ハッキング', '再考察', '迷探偵', '逆転の発想', '炯眼', '安楽椅子探偵', '密室トリック解明', '丁寧な処置'
38
+ ],
39
+ 'C' => [
40
+ '慈愛', 'クイックヒール', 'エリアヒール', 'クリアランス', '俯瞰視点', 'パターン化', '瞬時看破', '警鐘', '賢者の瞳', '千里眼', '危険感知', 'リバーサル'
41
+ ],
42
+ 'D' => [
43
+ '転禍為福', '受け身', '九死に一生', '軽業', 'バックドア', '着服', '闇に隠れる', '変装', '証拠隠滅', 'サポート', '技師の指', '妨害'
44
+ ],
45
+ 'E' => [
46
+ 'ゴッドハンド', '生存者の切り札', '狙撃', 'プラチナ免許', 'ドライバーズ・ハイ', '相乗り', '愛車/愛馬', 'ビーストフレンズ', 'ドゥ・ライブ', 'カツアゲ', 'マッドドッグ', '目の上の瘤'
47
+ ],
48
+ 'F' => [
49
+ '叱咤激励', 'ふいに見せた優しさ', 'スゴ味', '達人', '必殺技', '二刀流', '急所狙い', 'ジャンプショット', 'パルクール', '疾風怒濤', 'スパート', '走為上'
50
+ ],
51
+ 'G' => [
52
+ 'ヒット&アウェイ', 'ウーバー', '割れもの注意', 'もしもの備え', 'アブダクション', '追加機材', '自在配送', '不屈の精神', '防壁', '心頭滅却', '三時間しか寝てない', 'βエンドルフィン'
53
+ ],
54
+ 'H' => [
55
+ '怒髪天', '頭の体操', '精神統一', 'リトルラック', 'いいね!', '幻視', '慎重性', 'バレットストッパー', '褪せぬ想い', 'アピール上手', '土俵際の魔術師', '真実の愛'
56
+ ],
57
+ 'FT' => [
58
+ '何も起きなかった! ラッキー(?)',
59
+ 'ランダムに武器または防具が外れる。該当箇所に何も装備していなければ1点のダメージ(軽減無効)を受ける。',
60
+ 'GMの指定したLOVEの【深度】が1増加する。誰かに対するLOVEを新規取得させても良い。',
61
+ 'GMの指定したハンドアウト1つの強度が[自身のソウルLV/2]増加する。',
62
+ '1点のダメージ(軽減無効)を受ける。',
63
+ 'プレイス内のPCが所持している消耗品からGMが1つ指定し、破壊する。破壊したくない場合、かわりに自身のHPを最大値の1/3(切り捨て)減らす。',
64
+ '不調強度[自身のソウルLV/2]のランダムな不調を受ける。',
65
+ 'ファンブル表を2回振る。この効果は判定につき1度までで、以降は1点のダメージ(軽減無効)を受ける。',
66
+ 'ランダムなLOVEの【深度】が1減少する。',
67
+ 'ランダムなLOVEの【エモ】が2増加する。',
68
+ 'トラブルが発生する。ランダムトラブル表を使用し、場にトラブルのハンドアウトを追加する。',
69
+ 'ランダムなギフト1つのMPが0になる。'
70
+ ]
71
+ }.freeze
72
+
73
+ def eval_game_system_specific_command(command)
74
+ case command
75
+ when 'GG'
76
+ return roll_gg
77
+ when /^GG([A-H])$/
78
+ return roll_table(::Regexp.last_match(1))
79
+ when 'FT'
80
+ return roll_fumble_table
81
+ else
82
+ return roll_wow(command)
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def roll_gg
89
+ dice_results = @randomizer.roll_barabara(2, 12)
90
+ first_roll = dice_results[0]
91
+ second_roll = dice_results[1]
92
+
93
+ if first_roll >= 9
94
+ return "GG > 自由(アルファベットを決めてGGXを振る)"
95
+ end
96
+
97
+ alphabet = (64 + first_roll).chr
98
+ table = TABLES[alphabet]
99
+ return "ランダムギフトガチャ #{alphabet}-#{second_roll} > #{table[second_roll - 1]}"
100
+ end
101
+
102
+ def roll_table(alphabet)
103
+ table = TABLES[alphabet]
104
+ dice_result = @randomizer.roll_once(12)
105
+ return "ランダムギフトガチャ #{alphabet}-#{dice_result} > #{table[dice_result - 1]}"
106
+ end
107
+
108
+ def roll_fumble_table
109
+ dice_result = @randomizer.roll_once(12)
110
+ table = TABLES['FT']
111
+ return "FT(#{dice_result}) > #{table[dice_result - 1]}"
112
+ end
113
+
114
+ def roll_wow(command)
115
+ # コマンドの解析
116
+ m = /^(\d+)WW12(?:@(\d+))?(?:#(\d+))?(?:<=(\d+))?$/.match(command)
117
+ return nil unless m
118
+
119
+ num_dice = m[1].to_i # 振るダイスの数
120
+ critical_success_value = m[2] ? m[2].to_i : 1 # 大成功の値(デフォルトは1)
121
+ critical_fail_value = m[3] ? m[3].to_i : 12 # 大失敗の値(デフォルトは12)
122
+ success_threshold = m[4] ? m[4].to_i : 6 # 成功の閾値(デフォルトは6)
123
+
124
+ if m[4].nil?
125
+ command_with_defaults = "#{m[1]}WW12<=#{success_threshold}"
126
+ else
127
+ command_with_defaults = command
128
+ end
129
+
130
+ # ダイスを振る
131
+ dice_results = @randomizer.roll_barabara(num_dice, 12)
132
+
133
+ # 出目を分類
134
+ critical_success = dice_results.count { |r| r <= critical_success_value } # 大成功の数
135
+ critical_fail = dice_results.count { |r| r >= critical_fail_value } # 大失敗の数
136
+ normal_success = dice_results.count { |r| (r > critical_success_value) && (r <= success_threshold) && r < critical_fail_value }
137
+
138
+ critical_success_first = critical_success
139
+ critical_fail_first = critical_fail
140
+
141
+ # 大成功と大失敗の相殺
142
+ offset = [critical_success, critical_fail].min
143
+ critical_success -= offset
144
+ critical_fail -= offset
145
+
146
+ # 成功数とファンブルの判定
147
+ successes = normal_success + (critical_success * 2)
148
+ is_fumble = critical_fail > 0
149
+
150
+ # 結果をBCDICE::Resultで構造化
151
+ BCDice::Result.new.tap do |r|
152
+ r.text = "(#{command_with_defaults}) > [#{dice_results.join(',')}] > 成功数#{successes}(大成功#{critical_success_first}個、大失敗#{critical_fail_first}個)#{is_fumble ? ' > ファンブル!' : ''}"
153
+ r.critical = critical_success > 0
154
+ r.fumble = is_fumble
155
+ r.success = successes > 0 && !is_fumble # 成功数が0より大きく、ファンブルがない場合に成功
156
+ r.failure = successes == 0 || is_fumble # 成功数が0、またはファンブルがある場合に失敗
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end