bcdice 3.3.0 → 3.6.0

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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +158 -74
  3. data/README.md +2 -1
  4. data/i18n/BeginningIdol/ja_jp.yml +2806 -0
  5. data/i18n/BeginningIdol/ko_kr.yml +1400 -0
  6. data/i18n/Cthulhu/zh_hans.yml +11 -0
  7. data/i18n/FutariSousa/ja_jp.yml +705 -9
  8. data/i18n/KillDeathBusiness/ja_jp.yml +2 -2
  9. data/i18n/MagicaLogia/ja_jp.yml +1 -1
  10. data/i18n/MonotoneMuseum/ko_kr.yml +526 -53
  11. data/i18n/SwordWorld/ja_jp.yml +6 -0
  12. data/i18n/SwordWorld2_0/ja_jp.yml +37 -0
  13. data/i18n/SwordWorld2_5/ja_jp.yml +57 -0
  14. data/lib/bcdice/common_command/add_dice/node.rb +28 -4
  15. data/lib/bcdice/common_command/add_dice/parser.rb +149 -85
  16. data/lib/bcdice/common_command/choice.rb +82 -7
  17. data/lib/bcdice/common_command/tally_dice/node.rb +135 -0
  18. data/lib/bcdice/common_command/tally_dice/parser.rb +302 -0
  19. data/lib/bcdice/common_command/tally_dice.rb +19 -0
  20. data/lib/bcdice/common_command.rb +2 -0
  21. data/lib/bcdice/dice_table/d66_left_range_table.rb +29 -0
  22. data/lib/bcdice/dice_table/d66_parity_table.rb +8 -0
  23. data/lib/bcdice/dice_table/d66_table.rb +5 -1
  24. data/lib/bcdice/dice_table.rb +1 -0
  25. data/lib/bcdice/game_system/AngelGear.rb +9 -4
  26. data/lib/bcdice/game_system/Aoharubaan.rb +91 -0
  27. data/lib/bcdice/game_system/AssaultEngine.rb +91 -0
  28. data/lib/bcdice/game_system/Avandner.rb +1 -2
  29. data/lib/bcdice/game_system/Ayabito.rb +229 -0
  30. data/lib/bcdice/game_system/BadLife.rb +264 -289
  31. data/lib/bcdice/game_system/Bakenokawa.rb +244 -0
  32. data/lib/bcdice/game_system/BattleTech.rb +1 -1
  33. data/lib/bcdice/game_system/BeginningIdol.rb +116 -2390
  34. data/lib/bcdice/game_system/BeginningIdol_Korean.rb +10 -2312
  35. data/lib/bcdice/game_system/CastleInGray.rb +133 -0
  36. data/lib/bcdice/game_system/Cthulhu.rb +2 -2
  37. data/lib/bcdice/game_system/Cthulhu7th.rb +10 -10
  38. data/lib/bcdice/game_system/Cthulhu_SimplifiedChinese.rb +60 -0
  39. data/lib/bcdice/game_system/CyberpunkRed.rb +135 -0
  40. data/lib/bcdice/game_system/DarkDaysDrive.rb +76 -41
  41. data/lib/bcdice/game_system/DoubleCross.rb +5 -0
  42. data/lib/bcdice/game_system/Dracurouge.rb +2 -1
  43. data/lib/bcdice/game_system/Elysion.rb +36 -20
  44. data/lib/bcdice/game_system/Emoklore.rb +1 -1
  45. data/lib/bcdice/game_system/FateCoreSystem.rb +117 -0
  46. data/lib/bcdice/game_system/FutariSousa.rb +48 -4
  47. data/lib/bcdice/game_system/GranCrest.rb +171 -406
  48. data/lib/bcdice/game_system/Irisbane.rb +154 -0
  49. data/lib/bcdice/game_system/Karukami.rb +84 -0
  50. data/lib/bcdice/game_system/KemonoNoMori.rb +17 -17
  51. data/lib/bcdice/game_system/KurayamiCrying.rb +1 -1
  52. data/lib/bcdice/game_system/MonotoneMuseum_Korean.rb +4 -4
  53. data/lib/bcdice/game_system/NeverCloud.rb +19 -8
  54. data/lib/bcdice/game_system/PersonaO.rb +86 -0
  55. data/lib/bcdice/game_system/Revulture.rb +2 -2
  56. data/lib/bcdice/game_system/Shiranui.rb +145 -0
  57. data/lib/bcdice/game_system/ShuumatsuKikou.rb +298 -0
  58. data/lib/bcdice/game_system/StarryDolls.rb +318 -0
  59. data/lib/bcdice/game_system/SteamPunkers.rb +14 -1
  60. data/lib/bcdice/game_system/StellarKnights.rb +1 -1
  61. data/lib/bcdice/game_system/{SterileLife.rb → StellarLife.rb} +162 -226
  62. data/lib/bcdice/game_system/StrangerOfSwordCity.rb +18 -5
  63. data/lib/bcdice/game_system/SwordWorld.rb +11 -7
  64. data/lib/bcdice/game_system/SwordWorld2_0.rb +30 -38
  65. data/lib/bcdice/game_system/SwordWorld2_5.rb +9 -63
  66. data/lib/bcdice/game_system/TalesFromTheLoop.rb +83 -0
  67. data/lib/bcdice/game_system/TorgEternity.rb +2 -2
  68. data/lib/bcdice/game_system/ToshiakiHolyGrailWar.rb +92 -0
  69. data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +29 -28
  70. data/lib/bcdice/game_system/YearZeroEngine.rb +40 -19
  71. data/lib/bcdice/game_system/beginning_idol/accessories_table.rb +31 -0
  72. data/lib/bcdice/game_system/beginning_idol/bad_status_table.rb +43 -0
  73. data/lib/bcdice/game_system/beginning_idol/chain_d66_table.rb +29 -0
  74. data/lib/bcdice/game_system/beginning_idol/chain_table.rb +37 -0
  75. data/lib/bcdice/game_system/beginning_idol/costume_table.rb +37 -0
  76. data/lib/bcdice/game_system/beginning_idol/d6_twice_table.rb +36 -0
  77. data/lib/bcdice/game_system/beginning_idol/item_table.rb +51 -0
  78. data/lib/bcdice/game_system/beginning_idol/my_skill_name_table.rb +44 -0
  79. data/lib/bcdice/game_system/beginning_idol/random_event_table.rb +31 -0
  80. data/lib/bcdice/game_system/beginning_idol/skill_table.rb +63 -0
  81. data/lib/bcdice/game_system/beginning_idol/table.rb +193 -0
  82. data/lib/bcdice/game_system/beginning_idol/with_abnormality.rb +74 -0
  83. data/lib/bcdice/game_system/beginning_idol/work_table.rb +57 -0
  84. data/lib/bcdice/game_system/cyberpunk_red/tables.rb +530 -0
  85. data/lib/bcdice/game_system/meikyu_kingdom/tables.rb +1 -1
  86. data/lib/bcdice/game_system/meikyu_kingdom_basic/table.rb +1 -1
  87. data/lib/bcdice/game_system/one_way_heroics/random_event_table.rb +4 -4
  88. data/lib/bcdice/game_system/satasupe/tables.rb +1 -1
  89. data/lib/bcdice/game_system/sword_world/rating_options.rb +47 -0
  90. data/lib/bcdice/game_system/sword_world/rating_parsed.rb +40 -45
  91. data/lib/bcdice/game_system/sword_world/rating_parser.rb +172 -141
  92. data/lib/bcdice/game_system/sword_world/transcendent_test.rb +14 -10
  93. data/lib/bcdice/game_system.rb +16 -1
  94. data/lib/bcdice/randomizer.rb +1 -1
  95. data/lib/bcdice/version.rb +1 -1
  96. metadata +45 -5
@@ -27,15 +27,15 @@ module BCDice
27
27
 
28
28
  def result_2d6(total, dice_total, _dice_list, cmp_op, target)
29
29
  if dice_total >= 12
30
- Result.critical("自動的成功")
30
+ Result.critical(translate('SwordWorld.critical'))
31
31
  elsif dice_total <= 2
32
- Result.fumble("自動的失敗")
32
+ Result.fumble(translate('SwordWorld.fumble'))
33
33
  elsif cmp_op != :>= || target == "?"
34
34
  nil
35
35
  elsif total >= target
36
- Result.success("成功")
36
+ Result.success(translate('success'))
37
37
  else
38
- Result.failure("失敗")
38
+ Result.failure(translate('failure'))
39
39
  end
40
40
  end
41
41
 
@@ -65,7 +65,11 @@ module BCDice
65
65
  keyMax = rate_sw2_0.length - 1
66
66
  debug("keyMax", keyMax)
67
67
  if command.rate > keyMax
68
- return "キーナンバーは#{keyMax}までです"
68
+ return Result.new(translate('SwordWorld.keynumber_exceeds', keyMax: keyMax))
69
+ end
70
+
71
+ if command.infinite_roll?
72
+ return Result.new(translate('SwordWorld.infinite_critical', min_critical: command.min_critical))
69
73
  end
70
74
 
71
75
  newRates = getNewRates(rate_sw2_0)
@@ -83,7 +87,7 @@ module BCDice
83
87
  first_modify = command.first_modify
84
88
 
85
89
  loop do
86
- dice_raw, diceText = rollDice(command)
90
+ dice_raw, diceText = rollDice(command, round)
87
91
  dice = dice_raw
88
92
 
89
93
  if first_to != 0
@@ -295,7 +299,7 @@ module BCDice
295
299
  return newRates
296
300
  end
297
301
 
298
- def rollDice(_command)
302
+ def rollDice(_command, _round)
299
303
  dice_list = @randomizer.roll_barabara(2, 6)
300
304
  total = dice_list.sum()
301
305
  dice_str = dice_list.join(",")
@@ -54,6 +54,12 @@ module BCDice
54
54
  ・グレイテストフォーチュンは末尾に gf
55
55
   例)K20gf K30+24@8GF K40+24@8$12r10gf
56
56
 
57
+ ・威力表を1d+sfで参照 クリティカル後も継続 sf4
58
+  例)k10sf4 k0+5SF4@13 k70+26sf3@9
59
+
60
+ ・威力表を1d+tfで参照 クリティカル後は2dで参照 tf3
61
+  例)k10tf3 k0+5TF4@13 k70+26tf3@9
62
+
57
63
  ・超越判定用に2d6ロールに 2D6@10 書式でクリティカル値付与が可能に。
58
64
   例)2D6@10 2D6@10+11>=30
59
65
 
@@ -93,7 +99,7 @@ module BCDice
93
99
  return nil
94
100
  end
95
101
 
96
- node = TranscendentTest.new(cmd.critical, cmd.modify_number, cmd.cmp_op, cmd.target_number)
102
+ node = TranscendentTest.new(cmd.critical, cmd.modify_number, cmd.cmp_op, cmd.target_number, @locale)
97
103
  node.execute(@randomizer)
98
104
  when 'FT'
99
105
  get_fumble_table
@@ -108,14 +114,22 @@ module BCDice
108
114
  return RatingParser.new(version: :v2_0)
109
115
  end
110
116
 
111
- def rollDice(command)
112
- unless command.greatest_fortune
113
- return super(command)
117
+ def rollDice(command, round)
118
+ if command.semi_fixed_val > 0
119
+ # 常に片方の出目を固定
120
+ dice = @randomizer.roll_once(6)
121
+ return dice + command.semi_fixed_val, "#{dice},#{command.semi_fixed_val}"
122
+ elsif round == 0 && command.tmp_fixed_val > 0
123
+ # 回転前だけ片方の出目を固定
124
+ dice = @randomizer.roll_once(6)
125
+ return dice + command.tmp_fixed_val, "#{dice},#{command.tmp_fixed_val}"
126
+ elsif command.greatest_fortune
127
+ # グレイテスト・フォーチュン
128
+ dice = @randomizer.roll_once(6)
129
+ return dice * 2, "#{dice},#{dice}"
130
+ else
131
+ return super(command, round)
114
132
  end
115
-
116
- dice = @randomizer.roll_once(6)
117
-
118
- return dice * 2, "#{dice},#{dice}"
119
133
  end
120
134
 
121
135
  def growth(count = 1)
@@ -123,43 +137,21 @@ module BCDice
123
137
  end
124
138
 
125
139
  def growth_step
126
- d1 = @randomizer.roll_once(6)
127
- d2 = @randomizer.roll_once(6)
128
-
129
- a1 = get_ability_by_dice(d1)
130
- a2 = get_ability_by_dice(d2)
131
-
132
- return a1 != a2 ? "[#{d1},#{d2}]->(#{a1} or #{a2})" : "[#{d1},#{d2}]->(#{a1})"
133
- end
140
+ table = DiceTable::Table.from_i18n("SwordWorld2_0.GrowthTable", @locale)
141
+ r1 = table.roll(@randomizer)
142
+ r2 = table.roll(@randomizer)
134
143
 
135
- def get_ability_by_dice(dice)
136
- ['器用度', '敏捷度', '筋力', '生命力', '知力', '精神力'][dice - 1]
144
+ return r1.value != r2.value ? "[#{r1.value},#{r2.value}]->(#{r1.body} or #{r2.body})" : "[#{r1.value},#{r2.value}]->(#{r1.body})"
137
145
  end
138
146
 
139
147
  def get_fumble_table()
140
- table = [
141
- 'この表を2回振り、その両方を適用する。(同じ出目による影響は累積しない)。この自動失敗により得られる経験点は、+50点される',
142
- 'ダメージに、攻撃者を強化している「剣のかけら」の数が追加される',
143
- 'ダメージに、攻撃者の「レベル」が追加される',
144
- 'ダメージ決定を2回行い、より高い方を採用する',
145
- '合算ダメージを2倍する',
146
- '防護点無効'
147
- ]
148
- text, num = get_table_by_1d6(table)
149
- return "防御ファンブル表(#{num}) → #{text}"
148
+ table = DiceTable::Table.from_i18n("SwordWorld2_0.FumbleTable", @locale)
149
+ return table.roll(@randomizer)
150
150
  end
151
151
 
152
152
  def get_tangle_table()
153
- table = [
154
- '頭や顔:牙や噛みつきなどにおける命中力判定及び、魔法の行使やブレスに-2のペナルティ修正を受ける',
155
- '武器や盾:武器の使用不可、又は盾の回避力修正及び防護点を無効化する',
156
- '腕や手:武器や爪などにおける命中力判定に-2のペナルティ修正、盾を持つ腕方の腕ならその盾の回避力修正及び防護点を無効化する',
157
- '脚や足:移動不可、更に回避力判定に-2のペナルティ修正を受ける ※両足に絡んでも累積しない',
158
- '胴体:生命・精神抵抗力を基準値に用いる判定を除き、あらゆる行為判定に-1のペナルティ修正を受ける',
159
- '特殊:尻尾や翼などに命中。絡められた部位を使用する判定において-2のペナルティ修正、またはそこが使えていたことによるボーナス修正を失う ※存在しない場合は決め直し'
160
- ]
161
- text, num = get_table_by_1d6(table)
162
- return "絡み効果表(#{num}) → #{text}"
153
+ table = DiceTable::Table.from_i18n("SwordWorld2_0.TangleTable", @locale)
154
+ return table.roll(@randomizer)
163
155
  end
164
156
  end
165
157
  end
@@ -56,6 +56,12 @@ module BCDice
56
56
  ・グレイテストフォーチュンは末尾に gf
57
57
   例)K20gf K30+24@8GF K40+24@8$12r5gf
58
58
 
59
+ ・威力表を1d+sfで参照 クリティカル後も継続 sf4
60
+  例)k10sf4 k0+5sf4@13 k70+26sf3@9
61
+
62
+ ・威力表を1d+tfで参照 クリティカル後は2dで参照 tf3
63
+  例)k10tf3 k0+5tf4@13 k70+26tf3@9
64
+
59
65
  ・超越判定用に2d6ロールに 2D6@10 書式でクリティカル値付与が可能に。
60
66
   例)2D6@10 2D6@10+11>=30
61
67
 
@@ -78,66 +84,6 @@ module BCDice
78
84
 
79
85
  register_prefix('H?K', 'Gr', '2D6?@\d+', 'FT', 'TT', 'Dru', 'ABT')
80
86
 
81
- ABYSS_CURSE_TABLE = DiceTable::D66GridTable.new(
82
- 'アビスカース表', [
83
- [
84
- "「自傷の」 装備時 この武具を装備中に装備者がクリティカルを発生させた時、装備者のHPが5点減少する。",
85
- "「嘆きの」 装備時 近くに敵がいたり、長い緊張状態が続くと涙が止まらなくなる。戦闘中なら「射程:術者(自身)」「射程:接触」以外の効果で対象を選べなくなる。",
86
- "「優しき」 装備時 敵に同情してしまう。敵対するキャラクターを対象にする場合、対象のHPが1点以上減少しているなら命中力判定、魔法行使判定に-2のペナルティ修正を受ける。",
87
- "「差別の」 装備時 特定の分類に対して与える物理ダメージ・魔法ダメージが2点減少する。分類は「分類決定表」で無作為に決定する。",
88
- "「脆弱な」 装備時 魔法ダメージを受けるたび、そのダメージが+1点される。",
89
- "「無謀な」 装備時 防護点が2点減少する(最低0)。",
90
- ], [
91
- "「重い」 装備時 強化した武具の必要筋力が+2される。威力、防護点などは変化なし。",
92
- "「難しい」 装備時 いかなる威力表使用時でも、③④欄の数値が威力に関係なく「0」になる(自動失敗ではない)。",
93
- "「軟弱な」 装備時 精神抵抗力判定に-1のペナルティ修正を受ける。",
94
- "「病弱な」 装備時 生命抵抗力判定に-1のペナルティ修正を受ける。",
95
- "「過敏な」 装備時 特定の属性から受ける物理ダメージ、魔法ダメージが2点上昇する。属性は「属性決定表」で無作為に決定する。",
96
- "「陽気な」 装備時 精神抵抗判定に失敗するたび、笑いが止まらなくなる。次の手番終了時まで行動判定(『Ⅰ』123頁)に-1のペナルティ修正を受ける。この効果は累積する。",
97
- ], [
98
- "「たどたどしい」 装備時 話をする時に言葉に詰まったり、言い間違えたりしやすくなる。魔法行使判定に-1のペナルティ修正を受ける。",
99
- "「代弁する」 装備時 自身の会話は、そのまま武具が魔法文明語の聞き取りづらい声で話す。装備中は魔法文明語以外の言語で会話は行えず、妖精魔法、魔動機術を行使できなくなる。",
100
- "「施しは受けない」 装備時 戦闘中、「抵抗:任意」の効果を受け入れた場合、次の手番終了時まで生命抵抗力、精神抵抗力に-2のペナルティ修正を受ける。",
101
- "「死に近い」 携行時 常に生死判定に「冒険者レベル」と同じ値のペナルティ修正を受ける。",
102
- "「おしゃれな」 携行時 その武具を常に華美に飾りたくなる。収入を得るたび、その1割以上をこの武具の装飾に費やさなければならない(効果などに変化はない)。",
103
- "「マナを吸う」 携行時 魔法や練技など、自身の意思でMPを消費する効果を使用する場合、すべてのMP消費が1点上昇する。",
104
- ], [
105
- "「鈍重な」 携行時 移動力が半分(端数切り上げ)になる。",
106
- "「定まらない」 携行時 戦闘中の手番開始時に1dし、出目が「1」なら《ターゲッティング》とそれを前提とした戦闘特技を習得していないものとして扱う。",
107
- "「錯乱の」 携行時 戦闘中の手番開始時に1dし、出目が「1」なら近接攻撃を含む「射程:接触」の対象に効果を使用する際、対象は同じ位置(エリア、座標)の全てのキャラクター(敵味方含む)から無作為に選ばれる。",
108
- "「足絡みの」 携行時 戦闘中の手番開始時に1dし、出目が「1」ならその場で即座に転倒する。手番中には起き上がれない。",
109
- "「滑り落ちる」 携行時 戦闘中の手番開始時に1dし、出目が「1」なら手に装備または保持しているものをすべてその場に落とす(その手番の主動作で拾う事は可能)。",
110
- "「悪臭放つ」 携行時 強い悪臭を放つ。所持しているだけで他のキャラクターに不快感を与え、隠密判定に-2のペナルティ修正を受ける。さらに冒険者ランク(『Ⅱ』137頁)が1段階低いものとして扱われる。",
111
- ], [
112
- "「醜悪な」 携行時 武具の見た目が悪く、魅力がない。売却する際、基本取引価格の4分の1の価格で売却する。さらに冒険者ランク(『Ⅱ』137頁)が1段階低いものとして扱われる。",
113
- "「唸る」 携行時 その武具から常に羽虫が飛び交うような音が響く。隠密判定、危険感知判定に-4のペナルティ修正を受ける。",
114
- "「ふやけた」 携行時 水を吸ったようにふやけた質感をしている。追加ダメージ-1(武器)、防護点-1(鎧、盾)。病気属性の効果に対する生命抵抗力、精神抵抗力判定に-4のペナルティ修正を受ける。",
115
- "「古傷の」 携行時 HPを回復する効果(休息による回復を含む)を受けた場合、その回復量が1点減少する。",
116
- "「まばゆい」 携行時 光などを弾いて強く輝く。自身は常に視界が悪い事による-1のペナルティ修正を受ける。",
117
- "「栄光なき」 携行時 行為判定で自動成功した際、自動成功とは扱わず、2dを振り直し、その後の出目に従う。この効果は1日に1回のみ発揮される。",
118
- ], [
119
- "「正直者の」 携行時 嘘、方便がすぐばれるようになる。真偽判定の対象となる場合、-4のペナルティ修正を受ける。",
120
- "「乗り物酔いの」 携行時 揺れに弱くなる。自身の足以外の手段で10分以上移動した後、1時間、行動判定に-1のペナルティ修正を受ける。",
121
- "「碧を厭う」 携行時 自然の中では落ち着かなくなる。自然環境(『Ⅰ』108頁)では行動判定に-1のペナルティ修正を受ける。",
122
- "「我慢できない」 携行時 セッション中に1日の始まりを迎えるたび、趣味や嗜好品などに「冒険者レベル×10」ガメルを出費しなければならない。趣味や嗜好品が消費できない環境であれば、翌日の朝まで最大HP、最大MPが「冒険者レベル」点減少する。",
123
- "「つきまとう」 携行時 この武具が気がつけば身の回りにある。この武具以外での命中力判定、魔法行使判定(武器)、回避力判定(鎧、盾)に-4のペナルティ修正を受ける。",
124
- "「のろまな」 携行時 戦闘開始処理の「戦闘準備」をいっさい行えなくなる。",
125
- ],
126
- ]
127
- )
128
-
129
- ABYSS_CURSE_CATEGORY_TABLE = DiceTable::D66ParityTable.new(
130
- "アビスカース分類決定表",
131
- ["蛮族", "動物", "植物", "アンデッド", "魔法生物", "「蛮族」「動物」「植物」「アンデッド」「魔法生物」から任意"],
132
- ["魔動機", "幻獣", "妖精", "魔神", "人族", "「魔動機」「幻獣」「妖精」「魔神」「人族」から任意"]
133
- )
134
-
135
- ABYSS_CURSE_ATTR_TABLE = DiceTable::D66ParityTable.new(
136
- "アビスカース属性決定表",
137
- ["土", "水・氷", "炎", "風", "雷", "純粋エネルギー"],
138
- ["断空", "衝撃", "毒", "病気", "呪い", "精神効果"]
139
- )
140
-
141
87
  def eval_game_system_specific_command(command)
142
88
  case command
143
89
  when /^dru\[(\d+),(\d+),(\d+)\]/i
@@ -186,13 +132,13 @@ module BCDice
186
132
  end
187
133
 
188
134
  def get_abyss_curse_table
189
- table_result = ABYSS_CURSE_TABLE.roll(@randomizer)
135
+ table_result = DiceTable::D66GridTable.from_i18n('SwordWorld2_5.AbyssCurseTable', @locale).roll(@randomizer)
190
136
  additional =
191
137
  case table_result.value
192
138
  when 14 # 「差別の」における分類決定表
193
- ABYSS_CURSE_CATEGORY_TABLE.roll(@randomizer).to_s
139
+ DiceTable::D66ParityTable.from_i18n('SwordWorld2_5.AbyssCurseCategoryTable', @locale).roll(@randomizer).to_s
194
140
  when 25 # 「過敏な」における属性決定表
195
- ABYSS_CURSE_ATTR_TABLE.roll(@randomizer).to_s
141
+ DiceTable::D66ParityTable.from_i18n('SwordWorld2_5.AbyssCurseAttrTable', @locale).roll(@randomizer).to_s
196
142
  end
197
143
  final_result = [
198
144
  table_result.to_s,
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class TalesFromTheLoop < Base
6
+ # ゲームシステムの識別子
7
+ ID = "TalesFromTheLoop"
8
+
9
+ # ゲームシステム名
10
+ NAME = "ザ・ループTRPG"
11
+
12
+ # ゲームシステム名の読みがな
13
+ SORT_KEY = "さるうふTRPG"
14
+
15
+ HELP_MESSAGE = <<~TEXT
16
+ ■ 判定コマンド(nTFLx-x+x or nTFLx+x-x)
17
+ (必要成功数)TFL(判定ダイス数)+/-(修正ダイス数)
18
+
19
+ ※ 必要成功数と修正ダイス数は省略可能
20
+
21
+ 例1) 必要成功数1、判定ダイスは能力値3
22
+ 1TFL3
23
+
24
+ 例2)必要成功数不明、あるいはダイスボットの成功判定を使わない、判定ダイスは能力値3+技能1で4、アイテムの修正+1
25
+ TFL4+1
26
+
27
+ 例3)必要成功数1、判定ダイスは能力値2+技能1で3、コンディションにチェックが2つ、アイテムの修正+1
28
+ 1TFL3-2+1
29
+ あるいは以下のようにカッコ書きで内訳を詳細に記述することも可能。
30
+ 1TFL(2+1)-(1+1)+1
31
+ 修正ダイスのプラスとマイナスは逆でもよい。
32
+ 1TFL(2+1)+1-(1+1)
33
+ TEXT
34
+
35
+ register_prefix('(\d+)?(TFL)')
36
+
37
+ def eval_game_system_specific_command(command)
38
+ parser = Command::Parser.new(/\d*TFL\d+/, round_type: round_type)
39
+ parsed = parser.parse(command)
40
+ return nil unless parsed
41
+
42
+ difficulty, dice_pool = parsed.command.split("TFL", 2).map(&:to_i)
43
+ dice_pool += parsed.modify_number
44
+ if dice_pool <= 0
45
+ dice_pool = 1
46
+ end
47
+
48
+ ability_dice_text, success_dice = make_dice_roll(dice_pool)
49
+
50
+ return make_dice_roll_text(difficulty, dice_pool, ability_dice_text, success_dice)
51
+ end
52
+
53
+ private
54
+
55
+ def make_dice_roll_text(difficulty, dice_pool, ability_dice_text, success_dice)
56
+ dice_count_text = "(#{dice_pool}D6) > #{ability_dice_text} 成功数:#{success_dice}"
57
+ push_dice = (dice_pool - success_dice)
58
+
59
+ if push_dice > 0
60
+ dice_count_text = "#{dice_count_text} 振り直し可能:#{push_dice}"
61
+ reroll_command = "\n振り直しコマンド: TFL#{push_dice}"
62
+ end
63
+
64
+ if difficulty > 0
65
+ if success_dice >= difficulty
66
+ return Result.success("#{dice_count_text} 成功!#{reroll_command}")
67
+ else
68
+ return Result.failure("#{dice_count_text} 失敗!#{reroll_command}")
69
+ end
70
+ end
71
+
72
+ return "#{dice_count_text}#{reroll_command}"
73
+ end
74
+
75
+ def make_dice_roll(dice_pool)
76
+ dice_list = @randomizer.roll_barabara(dice_pool, 6)
77
+ success_dice = dice_list.count(6)
78
+
79
+ return "[#{dice_list.join(',')}]", success_dice
80
+ end
81
+ end
82
+ end
83
+ end
@@ -6,9 +6,9 @@ module BCDice
6
6
  # ゲームシステムの識別子
7
7
  ID = 'TorgEternity'
8
8
  # ゲームシステム名
9
- NAME = 'TORG Eternity'
9
+ NAME = 'トーグ エタニティ'
10
10
  # ゲームシステム名の読みがな
11
- SORT_KEY = 'とおくえたあにてい'
11
+ SORT_KEY = 'とおくえたにてい'
12
12
  # ダイスボットの使い方
13
13
  HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
14
14
  ・判定
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BCDice
4
+ module GameSystem
5
+ class ToshiakiHolyGrailWar < Base
6
+ # ゲームシステムの識別子
7
+ ID = 'ToshiakiHolyGrailWar'
8
+ # ゲームシステム名
9
+ NAME = 'としあきの聖杯戦争TRPG'
10
+ # ゲームシステム名の読みがな
11
+ SORT_KEY = 'としあきのせいはいせんそうTRPG'
12
+ # ダイスボットの使い方
13
+ HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
14
+ ■ 判定 (Fx+y-z@a>=t)
15
+ 補正値ペナルティを自動計算してダイスの面数を決定しダイスロールを実行します。
16
+ ダイス面数は2以上、10以下の範囲に制限されます。
17
+ x: ステータス
18
+ y: 補正値 (任意)
19
+ z: マイナス補正値 (任意)
20
+ a: ダイス面数の増量 (任意)
21
+ t: 目標値 (任意)
22
+ 例)
23
+ F8+11, F8+11-5, F8+11-5@1, F8+11+9-3-2@-1, F8+11-5>=50, F8
24
+ INFO_MESSAGE_TEXT
25
+
26
+ register_prefix('F')
27
+
28
+ def eval_game_system_specific_command(command)
29
+ roll_f(command)
30
+ end
31
+
32
+ private
33
+
34
+ def roll_f(command)
35
+ parser = Command::Parser.new(/F(\d+)(\+\d+)*(-\d+)*/, round_type: RoundType::CEIL)
36
+ .disable_modifier
37
+ .enable_critical
38
+ cmd = parser.parse(command)
39
+ unless cmd
40
+ return nil
41
+ end
42
+
43
+ m = cmd.command.match(/^F(\d+)((?:\+\d+)+)?((?:-\d+)+)?$/)
44
+ unless m
45
+ return nil
46
+ end
47
+
48
+ status = m[1].to_i
49
+ positive_modifier = m[2] ? Arithmetic.eval(m[2], RoundType::CEIL) : 0
50
+ negative_modifier = m[3] ? Arithmetic.eval(m[3], RoundType::CEIL) : 0
51
+ side_bonus = cmd.critical || 0
52
+
53
+ times = [status + positive_modifier + negative_modifier, 0].max
54
+ sides = (6 - positive_modifier_penalty(positive_modifier) + negative_modifier_bonus(negative_modifier) + side_bonus).clamp(2, 10)
55
+
56
+ list = @randomizer.roll_barabara(times, sides)
57
+ total = list.sum()
58
+ result =
59
+ if cmd.cmp_op.nil?
60
+ Result.new
61
+ elsif total.send(cmd.cmp_op, cmd.target_number)
62
+ Result.success("成功")
63
+ else
64
+ Result.failure("失敗")
65
+ end
66
+
67
+ sequence = [
68
+ cmd,
69
+ "(#{times}D#{sides}#{cmd.cmp_op}#{cmd.target_number})",
70
+ "#{total}[#{list.join(',')}]",
71
+ total,
72
+ result.text,
73
+ ].compact
74
+
75
+ result.text = sequence.join(" > ")
76
+ return result
77
+ end
78
+
79
+ def positive_modifier_penalty(modifier)
80
+ if modifier <= 10
81
+ 0
82
+ else
83
+ modifier / 10
84
+ end
85
+ end
86
+
87
+ def negative_modifier_bonus(modifier)
88
+ modifier <= -5 ? 1 : 0
89
+ end
90
+ end
91
+ end
92
+ end
@@ -71,25 +71,46 @@ module BCDice
71
71
 
72
72
  difficulty = m[DIFFICULTY_INDEX] ? m[DIFFICULTY_INDEX].to_i : NOT_CHECK_SUCCESS
73
73
 
74
+ return get_roll_result(result_text, success_dice, ten_dice, hunger_ten_dice, hunger_botch_dice, difficulty)
75
+ end
76
+
77
+ private
78
+
79
+ def get_roll_result(result_text, success_dice, ten_dice, hunger_ten_dice, hunger_botch_dice, difficulty)
74
80
  result_text = "#{result_text} 成功数=#{success_dice}"
75
81
 
76
82
  if difficulty > 0
83
+ result_text = "#{result_text} 難易度=#{difficulty}"
84
+
77
85
  if success_dice >= difficulty
78
- judgment_result = get_success_result(ten_dice >= 2, hunger_ten_dice)
86
+ is_critical = ten_dice >= 2
87
+
88
+ if hunger_ten_dice > 0 && is_critical
89
+ return Result.critical("#{result_text}:判定成功! [Messy Critical]")
90
+ elsif is_critical
91
+ return Result.critical("#{result_text}:判定成功! [Critical Win]")
92
+ end
93
+
94
+ return Result.success("#{result_text}:判定成功!")
79
95
  else
80
- judgment_result = get_fail_result(hunger_botch_dice)
96
+ if hunger_botch_dice > 0
97
+ return Result.fumble("#{result_text}:判定失敗! [Bestial Failure]")
98
+ end
99
+
100
+ return Result.failure("#{result_text}:判定失敗!")
81
101
  end
82
- result_text = "#{result_text} 難易度=#{difficulty}#{judgment_result}"
83
102
  elsif difficulty < 0
84
103
  if success_dice == 0
85
- judgment_result = get_fail_result(hunger_botch_dice)
86
- else
87
- judgment_result = ""
104
+ if hunger_botch_dice > 0
105
+ return Result.fumble("#{result_text}:判定失敗! [Bestial Failure]")
106
+ end
107
+
108
+ return Result.failure("#{result_text}:判定失敗!")
88
109
  end
89
- result_text = "#{result_text}#{judgment_result}"
90
110
  end
91
111
 
92
- return result_text
112
+ # 難易度0指定(=全ての判定チェックを行わない)
113
+ return result_text.to_s
93
114
  end
94
115
 
95
116
  def get_critical_success(ten_dice)
@@ -107,26 +128,6 @@ module BCDice
107
128
 
108
129
  return dice_text, success_dice, ten_dice, botch_dice
109
130
  end
110
-
111
- def get_success_result(is_critical, hunger_ten_dice)
112
- judgment_result = ":判定成功!"
113
- if hunger_ten_dice > 0 && is_critical
114
- return "#{judgment_result} [Messy Critical]"
115
- elsif is_critical
116
- return "#{judgment_result} [Critical Win]"
117
- end
118
-
119
- return judgment_result
120
- end
121
-
122
- def get_fail_result(hunger_botch_dice)
123
- judgment_result = ":判定失敗!"
124
- if hunger_botch_dice > 0
125
- return "#{judgment_result} [Bestial Failure]"
126
- end
127
-
128
- return judgment_result
129
- end
130
131
  end
131
132
  end
132
133
  end
@@ -19,15 +19,17 @@ module BCDice
19
19
 
20
20
  ・判定コマンド(nMYZx+x+x)
21
21
  (難易度)MYZ(能力ダイス数)+(技能ダイス数)+(アイテムダイス数) # (1と6を数え、プッシュ可能数を表示)
22
+ (難易度)MYZ(能力ダイス数)-(技能ダイス数)+(アイテムダイス数) # (1と6を数え、プッシュ可能数を表示、技能のマイナス指定)
22
23
 
23
24
  ※ 難易度と技能、アイテムダイス数は省略可能
24
25
  INFO_MESSAGE_TEXT
25
26
 
26
- DIFFICULTY_INDEX = 1 # 難易度のインデックス
27
- COMMAND_TYPE_INDEX = 2 # コマンドタイプのインデックス
28
- ABILITY_INDEX = 3 # 能力値ダイスのインデックス
29
- SKILL_INDEX = 5 # 技能値ダイスのインデックス
30
- MODIFIED_INDEX = 7 # 修正ダイスのインデックス
27
+ DIFFICULTY_INDEX = 1 # 難易度のインデックス
28
+ COMMAND_TYPE_INDEX = 2 # コマンドタイプのインデックス
29
+ ABILITY_INDEX = 3 # 能力値ダイスのインデックス
30
+ SKILL_SIGNED_INDEX = 5 # 技能値ダイス符号のインデックス
31
+ SKILL_INDEX = 6 # 技能値ダイスのインデックス
32
+ GEAR_INDEX = 8 # アイテムダイスのインデックス
31
33
 
32
34
  register_prefix('(\d+)?(YZE|MYZ)')
33
35
 
@@ -42,7 +44,7 @@ module BCDice
42
44
  end
43
45
 
44
46
  def eval_game_system_specific_command(command)
45
- m = /\A(\d+)?(YZE|MYZ)(\d+)(\+(\d+))?(\+(\d+))?/.match(command)
47
+ m = /\A(\d+)?(YZE|MYZ)(\d+)((\+|-)(\d+))?(\+(\d+))?/.match(command)
46
48
  unless m
47
49
  return ''
48
50
  end
@@ -70,18 +72,27 @@ module BCDice
70
72
  dice_pool = m[SKILL_INDEX].to_i
71
73
  skill_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
72
74
 
73
- @total_success_dice += success_dice
75
+ skill_unsigned = m[SKILL_SIGNED_INDEX]
76
+ if command_type == 'YZE' && skill_unsigned == '-'
77
+ # YZEはシンプルに動作するコマンドなのでマイナス技能の処理は対応しない。
78
+ return "YZEコマンドでは技能ダイスをマイナス指定できません。"
79
+ elsif command_type == 'MYZ' && skill_unsigned == '-'
80
+ @total_success_dice -= success_dice # マイナス技能の成功は通常の成功と相殺される
81
+ else
82
+ @total_success_dice += success_dice
83
+ end
84
+
74
85
  @total_botch_dice += botch_dice
75
- @skill_botch_dice += botch_dice # 技能ダイスの1はpushで振り直し可能
76
- @push_dice += (dice_pool - success_dice) # 技能ダイスのみ1を含む
86
+ @skill_botch_dice += botch_dice # 技能ダイスの1はpushで振り直し可能(例えマイナス技能でも)
87
+ @push_dice += (dice_pool - success_dice) # 技能ダイスのみ1を含むので、ここでは1を計算に入れない
77
88
 
78
- dice_count_text += "+(#{dice_pool}D6)"
79
- dice_text += "+#{skill_dice_text}"
89
+ dice_count_text += "#{skill_unsigned}(#{dice_pool}D6)"
90
+ dice_text += "#{skill_unsigned}#{skill_dice_text}"
80
91
  end
81
92
 
82
- if m[MODIFIED_INDEX]
83
- dice_pool = m[MODIFIED_INDEX].to_i
84
- modified_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
93
+ if m[GEAR_INDEX]
94
+ dice_pool = m[GEAR_INDEX].to_i
95
+ gear_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
85
96
 
86
97
  @total_success_dice += success_dice
87
98
  @total_botch_dice += botch_dice
@@ -89,8 +100,9 @@ module BCDice
89
100
  @push_dice += (dice_pool - (success_dice + botch_dice))
90
101
 
91
102
  dice_count_text += "+(#{dice_pool}D6)"
92
- dice_text += "+#{modified_dice_text}"
103
+ dice_text += "+#{gear_dice_text}"
93
104
  end
105
+
94
106
  return make_result_text(command_type, dice_count_text, dice_text)
95
107
  end
96
108
 
@@ -108,18 +120,27 @@ module BCDice
108
120
  result_text = "#{dice_count_text} > #{dice_text} 成功数:#{@total_success_dice}"
109
121
  if @difficulty > 0
110
122
  if @total_success_dice >= @difficulty
111
- result_text = "#{result_text} 難易度=#{@difficulty}:判定成功!"
123
+ return Result.success("#{result_text} 難易度=#{@difficulty}:判定成功!")
112
124
  else
113
- result_text = "#{result_text} 難易度=#{@difficulty}:判定失敗!"
125
+ return Result.failure("#{result_text} 難易度=#{@difficulty}:判定失敗!")
114
126
  end
115
127
  end
116
128
  return result_text
117
129
  end
118
130
 
119
131
  def make_result_with_myz(dice_count_text, dice_text)
120
- result_text = make_result_with_yze(dice_count_text, dice_text)
132
+ result_text = "#{dice_count_text} > #{dice_text} 成功数:#{@total_success_dice}"
133
+ atter_text = "\n出目1:[能力:#{@base_botch_dice},技能:#{@skill_botch_dice},アイテム:#{@gear_botch_dice}) プッシュ可能=#{@push_dice}ダイス"
134
+
135
+ if @difficulty > 0
136
+ if @total_success_dice >= @difficulty
137
+ return Result.success("#{result_text} 難易度=#{@difficulty}:判定成功!#{atter_text}")
138
+ else
139
+ return Result.failure("#{result_text} 難易度=#{@difficulty}:判定失敗!#{atter_text}")
140
+ end
141
+ end
121
142
 
122
- return "#{result_text}\n出目1:[能力:#{@base_botch_dice},技能:#{@skill_botch_dice},アイテム:#{@gear_botch_dice}) プッシュ可能=#{@push_dice}ダイス"
143
+ return "#{result_text}#{atter_text}"
123
144
  end
124
145
 
125
146
  def make_dice_roll(dice_pool)