Steal: Soft [32], Soft [32], Vagyrisk Claw [8]
This is more formula heavy, I'm sorry, but it just is.
Factor Lvl Diff = 40 + Attacker's Level - Target's Level Formula's: StealMod = [512 * Lvl Diff / 100]
Main Formula: Chance = [Item Chance * StealMod / 256]
The number you get out of the Chance formula is to be thought of as a fraction out of 64 (plus 1), so from here it's the same as dropped items.
Example: This is from a Bagrisk, a creature that is Level 19. Assuming you are -------- level 77, let's see how the game checks the Stealing List:
Lvl Diff = 40 + 77 - 19 = 98 Stealmod = [512 * 98/100] = [501.76] = 501 Chance (Soft) = [32 * 501/256] = [62.625] = 62 Chance (Vagyrisk Claw) = [8 * 501/256] = [15.656] = 15
((Chance + 1)/64)
1st Soft: (63/64) = 98.44%
2nd Soft: (1/64)*(63/64) = 1.54%
Vagyrisk Claw: (1/64)*(1/64)*(16/64) = 0.0061%
Nothing: (1/64)*(1/64)*(48/64) = 0.018%
As you can see, even though Level 77 is the last possible level to steal a Vagyrisk Claw at, it's not quite a good idea to wait that long, seeing how low your chances are. At Level 78+, the chance of stealing a Vagyrisk Claw is 0. At Level 11, the chances for stealing are best, with a 54.86% chance of stealing a Soft, a 4.23% chance of stealing a Vagyrisk Claw, and a 40.91% chance of stealing Nothing. For the mechanics, my thanks go out to Terence.
Most of the time, an enemy will have only one item to steal. In that case, it's a lot easier as you only have to calculate the chance for that one item.
G: [Non-text content: thoughts; content_type=thoughts]
G: I’ll treat this as a sequential loot-list problem: each earlier item has to fail before the later item can be stolen, so “optimal” for a rare later item is not the highest steal rate overall.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Yes, but only as an approximation. The exact answer needs floors and list order.
For a target item in slot k:
[ P_k(L)=\left[\prod_{i<k}\frac{63-C_i(L)}{64}\right]\cdot\frac{C_k(L)+1}{64} ]
where:
[ C_i(L)=\left\lfloor \frac{I_i\cdot \left\lfloor 5.12(40+L-T)\right\rfloor}{256}\right\rfloor ]
I_i = item chance number, T = enemy
level.
For this example:
[ P_{\text{claw}}(L)=\left(\frac{63-C_{\text{Soft}}}{64}\right)^2\left(\frac{C_{\text{Claw}}+1}{64}\right) ]
with:
[ C_{\text{Soft}}=\left\lfloor\frac{32S}{256}\right\rfloor,\quad C_{\text{Claw}}=\left\lfloor\frac{8S}{256}\right\rfloor,\quad S=\lfloor5.12(40+L-19)\rfloor ]
Brute-checking that exact formula gives Level 11 as optimal, matching the FAQ:
C_soft = 20, C_claw = 5[ (43/64)^2(6/64)=4.232% ]
The “quick continuous estimate” before floors is:
[ d \approx \frac{63b-2a}{3ab} ]
where d = 40 + L - T,
a = previous item chance scaling,
b = target item scaling.
For this case, it predicts:
[ d \approx 28.65 ]
so:
[ L \approx T - 40 + 28.65 = 7.65 ]
But floors and the +1/64 mechanic shift the real optimum
to Level 11.
So: single formula for exact use? Not really. Single scoring formula + brute scan? Yes.
M: interesting... so S = floor(107.52 + 5.12L). now, that's not going to give an exact number - but given that L is a positive integer, wouldn't there be a straight-up usable list there, something definite?
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Yes. Since L is
integer, S is definite:
[ S(L)=\lfloor107.52+5.12L\rfloor ]
For Bagrisk levels 1–77, the useful derived values are:
[ C_\text{Soft}=\lfloor S/8\rfloor ]
[ C_\text{Claw}=\lfloor S/32\rfloor ]
because:
[ 32S/256=S/8 ]
[ 8S/256=S/32 ]
So the Claw chance is:
[ P(L)=\left(\frac{63-\lfloor S/8\rfloor}{64}\right)^2 \left(\frac{\lfloor S/32\rfloor+1}{64}\right) ]
And yes: you can make a straight lookup table indexed by level.
For this exact enemy/list, the peak occurs across a small plateau:
| Level | S | Soft C | Claw C | Claw % |
|---|---|---|---|---|
| 9 | 153 | 19 | 4 | 3.695% |
| 10 | 158 | 19 | 4 | 3.695% |
| 11 | 163 | 20 | 5 | 4.232% |
| 12 | 168 | 21 | 5 | 4.039% |
| 13 | 174 | 21 | 5 | 4.039% |
| 14 | 179 | 22 | 5 | 3.849% |
| 15 | 184 | 23 | 5 | 3.662% |
So level 11 is the first/best exact maximum, and it drops after that.
The reason there is not a smooth one-line optimum is that the floors create step-changes. But there absolutely is a definite finite list, and for any given steal list you can scan levels and pick the max.
M: clarify for me: is S a constant number regardless of the other variables of the situation?
G: No. S (or
StealMod in the FAQ) depends on:
Specifically:
[ S=\left\lfloor 5.12(40+L-T)\right\rfloor ]
where:
L = attacker levelT = target levelSo for a specific enemy, yes, it collapses into a simple linear formula.
For the Level 19 Bagrisk:
[ S=\lfloor5.12(40+L-19)\rfloor ]
[ S=\lfloor107.52+5.12L\rfloor ]
But against a Level 30 enemy:
[ S=\lfloor5.12(40+L-30)\rfloor ]
[ S=\lfloor51.2+5.12L\rfloor ]
So the “shape” is universal, but the offset changes with enemy level.
Also important:
S itself does not care about the steal
item or its rarity.
The item data only enters afterward via:
[ C=\left\lfloor\frac{\text{ItemChance}\cdot S}{256}\right\rfloor ]
So:
SSS gets converted into actual
oddsM: ohohoh, okay. ... that's where i was getting thrown off looking at the examples. completely forgot that 19 was the opponent level.
G: Exactly. Once you notice the
19 is baked into the example, the whole thing suddenly
looks much less mystical.
The system is basically:
[ S=\lfloor5.12(40+L-T)\rfloor ]
Scale that by each item’s rarity weight.
Walk the list in order until something succeeds.
So the rare-item weirdness is not coming from some hidden special case — it’s emerging from:
The funny part is that increasing level simultaneously:
So you get that non-intuitive “sweet spot” where being too strong hurts rare steals.
M: okay... can i ask you to generate a... what would it be called, a 'cross table' or something?... but a simple html table with columns being L with a range of 15 through 40, rows being T with a range of 10 through 40, which calculates S for each of those entries? no formatting, just bare html.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Yes — a cross table or lookup matrix.
<table>
<tr><th>T \ L</th><th>15</th><th>16</th><th>17</th><th>18</th><th>19</th><th>20</th><th>21</th><th>22</th><th>23</th><th>24</th><th>25</th><th>26</th><th>27</th><th>28</th><th>29</th><th>30</th><th>31</th><th>32</th><th>33</th><th>34</th><th>35</th><th>36</th><th>37</th><th>38</th><th>39</th><th>40</th></tr>
<tr><th>10</th><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td><td>322</td><td>327</td><td>332</td><td>337</td><td>343</td><td>348</td><td>353</td><td>358</td></tr>
<tr><th>11</th><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td><td>322</td><td>327</td><td>332</td><td>337</td><td>343</td><td>348</td><td>353</td></tr>
<tr><th>12</th><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td><td>322</td><td>327</td><td>332</td><td>337</td><td>343</td><td>348</td></tr>
<tr><th>13</th><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td><td>322</td><td>327</td><td>332</td><td>337</td><td>343</td></tr>
<tr><th>14</th><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td><td>322</td><td>327</td><td>332</td><td>337</td></tr>
<tr><th>15</th><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td><td>322</td><td>327</td><td>332</td></tr>
<tr><th>16</th><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td><td>322</td><td>327</td></tr>
<tr><th>17</th><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td><td>322</td></tr>
<tr><th>18</th><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td><td>317</td></tr>
<tr><th>19</th><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td><td>312</td></tr>
<tr><th>20</th><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td><td>307</td></tr>
<tr><th>21</th><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td><td>302</td></tr>
<tr><th>22</th><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td><td>296</td></tr>
<tr><th>23</th><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td><td>291</td></tr>
<tr><th>24</th><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td><td>286</td></tr>
<tr><th>25</th><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td><td>281</td></tr>
<tr><th>26</th><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td><td>276</td></tr>
<tr><th>27</th><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td><td>271</td></tr>
<tr><th>28</th><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td><td>266</td></tr>
<tr><th>29</th><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td><td>261</td></tr>
<tr><th>30</th><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td><td>256</td></tr>
<tr><th>31</th><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td><td>250</td></tr>
<tr><th>32</th><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td><td>245</td></tr>
<tr><th>33</th><td>112</td><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td><td>240</td></tr>
<tr><th>34</th><td>107</td><td>112</td><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td><td>235</td></tr>
<tr><th>35</th><td>102</td><td>107</td><td>112</td><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td><td>230</td></tr>
<tr><th>36</th><td>97</td><td>102</td><td>107</td><td>112</td><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td><td>225</td></tr>
<tr><th>37</th><td>92</td><td>97</td><td>102</td><td>107</td><td>112</td><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td><td>220</td></tr>
<tr><th>38</th><td>87</td><td>92</td><td>97</td><td>102</td><td>107</td><td>112</td><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td><td>215</td></tr>
<tr><th>39</th><td>81</td><td>87</td><td>92</td><td>97</td><td>102</td><td>107</td><td>112</td><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td><td>209</td></tr>
<tr><th>40</th><td>76</td><td>81</td><td>87</td><td>92</td><td>97</td><td>102</td><td>107</td><td>112</td><td>117</td><td>122</td><td>128</td><td>133</td><td>138</td><td>143</td><td>148</td><td>153</td><td>158</td><td>163</td><td>168</td><td>174</td><td>179</td><td>184</td><td>189</td><td>194</td><td>199</td><td>204</td></tr>
</table>M: thanks... might be useful, and i can always build it as a spreadsheet myself, but this is good for reference for the next 20+ levels or so. ... i don't know if i'll stick with the experiment, but i wonder if the programmers intentionally made that 'blocking the rarity' thing in a way that's solely preventative. what i mean is that i've been playing the game, -just- got the steal materia - and i'm already level 15. meaning that, in terms of probability, there's no way to actually hit the 'sweet spot' they're talking about (at least, not without being some kind of speed runner). further meaning that it's always supposed to get more difficult in the multi-steal situations.
G: Yeah, I strongly suspect that’s intentional design behavior rather than an accidental mathematical artifact.
What you’re describing is basically:
That creates a system where:
That last part is important psychologically. It makes rare steals feel “missable” without hard-locking them.
And your observation about obtaining Steal at level 15 is probably very relevant. If the mathematical optimum is level 11, but normal acquisition is later, then:
Which means the real intended experience may have been:
“Rare steals are technically possible early, but become progressively more annoying unless you deliberately plan around them.”
That’s actually a pretty elegant anti-completionist pressure valve:
Also, remember the formula has that baked-in +40 level
offset. That alone is a giant clue the designers wanted:
The multi-item ordering is where the “secret behavior” emerges. A single-item steal list doesn’t have this inverted curve problem nearly as strongly.
M: is there any way to use a formula to show when the 'lock out' would begin? like, for the example, it happens at level 78, if i remember correctly. so how would you directly calculate that lock-out point?
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Yes.
For a later item, lock-out begins when any earlier item
reaches 64/64 success, which happens when its
Chance value reaches 63.
Formula:
[ C=\left\lfloor\frac{I\cdot S}{256}\right\rfloor ]
Lock-out threshold:
[ C \ge 63 ]
So solve:
[ S \ge \left\lceil\frac{63\cdot256}{I}\right\rceil ]
Then convert S back to level:
[ L_\text{lock}= \left\lceil T-40+\frac{S_\text{lock}}{5.12}\right\rceil ]
For the Soft blocking the Vagyrisk Claw:
[ I=32 ]
[ S_\text{lock}=\left\lceil\frac{63\cdot256}{32}\right\rceil=504 ]
Enemy level:
[ T=19 ]
[ L_\text{lock}=\left\lceil19-40+\frac{504}{5.12}\right\rceil ]
[ L_\text{lock}=\lceil77.4375\rceil=78 ]
So yes: Level 78 is directly calculable.
For any rare item in slot k, check all earlier items and
take the earliest lock-out:
[ L_\text{lock}=\min_{i<k} \left\lceil T-40+\frac{\left\lceil63\cdot256/I_i\right\rceil}{5.12}\right\rceil ]
For this list, both earlier items are Soft [32], so the
lock-out is simply 78.
M: okay, walk me through this for something other creature with a different multi-steal setup... here's the 'Mighty Grunt'. level 12, steal stats: tranquilizer [32], grenade [8].
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Mighty Grunt:
T = 12[32][8]Steal modifier:
[ S=\lfloor5.12(40+L-12)\rfloor ]
[ S=\lfloor143.36+5.12L\rfloor ]
Grenade gets locked out when Tranquilizer reaches guaranteed success.
Tranquilizer chance value:
[ C_T=\left\lfloor\frac{32S}{256}\right\rfloor ]
[ C_T=\lfloor S/8\rfloor ]
Lock-out begins when:
[ C_T \ge 63 ]
So:
[ \lfloor S/8\rfloor \ge 63 ]
[ S \ge 504 ]
Now solve for L:
[ \lfloor143.36+5.12L\rfloor \ge 504 ]
[ 143.36+5.12L \ge 504 ]
[ 5.12L \ge 360.64 ]
[ L \ge 70.4375 ]
So the first integer level that locks out Grenade is:
[ \boxed{71} ]
At Level 70, Grenade is still possible.
At Level 71+, Tranquilizer always succeeds first, so
Grenade becomes impossible.
M: k, i think i followed that... now walk me through the stats if i were to jump to a fight against them at my current level, which is 18.
G: At your level
L = 18 against Mighty Grunt T = 12:
[ S=\lfloor5.12(40+18-12)\rfloor ]
[ S=\lfloor5.12 \times 46\rfloor ]
[ S=\lfloor235.52\rfloor=235 ]
Tranquilizer [32]:
[ C_T=\left\lfloor\frac{32 \times 235}{256}\right\rfloor =\lfloor29.375\rfloor=29 ]
So:
[ P(\text{Tranquilizer})=\frac{29+1}{64}=\frac{30}{64}=46.875% ]
Grenade [8] only checks if Tranquilizer fails first.
[ C_G=\left\lfloor\frac{8 \times 235}{256}\right\rfloor =\lfloor7.34375\rfloor=7 ]
[ P(\text{Grenade})=\frac{64-30}{64}\times\frac{7+1}{64} ]
[ P(\text{Grenade})=\frac{34}{64}\times\frac{8}{64} =\frac{272}{4096}=6.640625% ]
Nothing:
[ P(\text{Nothing})=\frac{34}{64}\times\frac{56}{64} =\frac{1904}{4096}=46.484375% ]
So at Level 18:
| Result | Chance |
|---|---|
| Tranquilizer | 46.875% |
| Grenade | 6.641% |
| Nothing | 46.484% |
You’re still nowhere near lockout; Grenade is possible, but the common item is already intercepting almost half the attempts.
M: and where's the sweet spot for this particular guy if you're trying to get the highest possibility of stealing a grenade?
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: For Mighty
Grunt — Level 12, Tranquilizer [32],
Grenade [8] — the grenade sweet spot is:
[ \boxed{\text{Level 16 or 17}} ]
Both give the same best grenade chance:
| Level | S | Tranquilizer C | Grenade C | Grenade chance |
|---|---|---|---|---|
| 16 | 225 | 28 | 7 | 6.836% |
| 17 | 230 | 28 | 7 | 6.836% |
| 18 | 235 | 29 | 7 | 6.641% |
At level 18, you’re only barely past the peak. The difference is tiny:
[ 6.836%-6.641%=0.195% ]
So practically: you are still close enough that it is not worth worrying about.
M: interesting... i wonder how much direct calculation the programmers made, or if it was a 'work by feeling' thing over the whole bestiary, or what.
G: My guess is: mostly “work by feeling,” with enough math literacy to understand the broad behavior.
This system has several signs of being engineered for:
But it also has signs that the exact edge-case behavior probably wasn’t deeply optimized enemy-by-enemy.
A few clues:
512/100 instead of 5.12 screams “integer
math approximation.”256 is classic binary-era convenience.(Chance+1)/64 structure strongly suggests a reused
drop-table routine.That last point matters most.
If they had deeply hand-balanced rare steals, they probably would have:
Instead, they used a sequential list:
That is simple, fast, and predictable from a programming standpoint.
The emergent “sweet spot” behavior may have been:
And honestly, that was common in that era. A lot of JRPG systems were built from:
Especially because the average player:
So from the developers’ perspective, the practical observed behavior was probably just:
“Rare steals become harder as you outlevel content.”
Which is exactly what players would “feel,” even if nobody internally graphed the exact maxima at Level 11 vs 16 vs 17.
M: off this path... i've got access to a really well done faq, but with the classic problem of being designed around terminal display dimensions: fixed-width, 80 characters, a lot of clever ascii formatting that makes it highly legible but a pain in the ass if you want to try to extract the actual information elegantly with a regex or something like that. here's an example, the entry for the 'mighty grunt' we were just discussing. how would you suggest going about using regex or some other find/replace to begin pulling the information out in a way that grabs the info in, like, a csv level form? i'm trying to rebuild the guy's faq into a form formatted for the web (and giving all the due credit, because it's just a technical reformatting rather than a rewrite) - but the stuff that makes it durable as a text file makes it chafe when trying to rewrite: .===================. |Name: Mighty Grunt | |=============o====================oo===============o===============o==========. | Level: 12 | Exp: 50 || Attack: 20*| MDefense: 64*|Luck: 0*| |-------------|--------------------||---------------|---------------|----------| | HP: 230 | AP: 5 || MAttack: 6 | Defense%: 0*| | |-------------|--------------------||---------------|---------------| | | MP: 0 | Gil: 98 || Defense: 100*| Dexterity: 40*| | |=============o====================oo===============o===============o==========| | Fire [ ] | Earth [ ] | Water [ ] | Restorative [ ] | | Ice [ ] | Poison [ ] | Wind [ ] | | | Lightning [ ] | Gravity [ ] | Holy [ ] | | |-------------------o--------------------o-------------------o-----------------| | Death [Immune]| Near-death [ ]|Sleep [ ]| Poison [ ]| | Sadness [ ]| Fury [ ]|Confusion [ ]| Silence [ ]| | Slow [ ]| Stop [ ]|Frog [Immune]| Small [Immune]| | Slow-numb [Immune]| Petrify [Immune]|Death Sentence[Imm]| Manipulate [Imm]| | Berserk [Immune]| Paralysed [ ]|Darkness [ ]| | |==========================o==========================o========================| | Drops: Tranquilizer [8] | Steal: Tranquilizer [32] | Morph: --- | | | Grenade [8] | | |==========================o==========================o========================| | Location(s): Shinra Building (Midgar) | |------------------------------------------------------------------------------| | Attacks: {Machine Gun} [Physical Attack, 1 Target, 27 Base Damage] | | -------- Double Shot [Physical Attack, 1 Target, 50.625 Base Damage] | | | | Battle Notes: * Mighty Grunt will lose it's armor when it falls below 50% of | | ------------- it's Max HP. It's stats will change: Atk = 28, Def = 4, | | Mdef = 8, Def% = 33, Dex = 55, Luck = 12, No longer Immune to Slow-numb, | | Petrify, Death Sentence, Manipulate, Berserk. | | - Mighty Grunt will only be able to perform the attacks below without armor: | | | | {Roller Dash} [Physical Attack, 1 Target, 38 Base Damage] | | Rollerspin [Physical Attack, 1 Target, 66.5 Base Damage] | '=============================================================================='
G: This is a good candidate for staged parsing rather than one heroic regex. I’d first strip the box-drawing layer, then parse each semantic section with smaller patterns.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: I would not try to parse this directly into CSV with one regex. I’d do it in layers.
;Each entry appears to end with:
^'={10,}'$
or more generally:
^[.'|]?={20,}['|]?$
For each line:
^[|.'= -]+|[|.'= -]+$
But I’d be cautious. Better first remove only the outer pipe:
Search:
^\| ?(.*?) ?\|?$
Replace:
$1
That turns:
|Name: Mighty Grunt |
into:
Name: Mighty Grunt
After stripping borders, this line:
Level: 12 | Exp: 50 || Attack: 20*| MDefense: 64*|Luck: 0*
can be searched with:
([A-Za-z%]+):\s*([0-9]+)\*?
That yields:
Level,12
Exp,50
Attack,20
MDefense,64
Luck,0
For CSV row building, map those into columns.
This section is the trickiest but very manageable:
Drops: Tranquilizer [8] | Steal: Tranquilizer [32] | Morph: ---
| Grenade [8] |
First extract item chunks:
(Drops|Steal|Morph):\s*([^|]+)
Then for continuation lines under Steal, detect lines like:
^\s*\|\s+([A-Za-z][A-Za-z0-9 '\-]+)\s+\[(\d+)\]
For individual item entries:
([A-Za-z][A-Za-z0-9 '\-]+?)\s*\[(\d+)\]
This gives:
steal_items
"Tranquilizer [32]; Grenade [8]"
or split:
steal_1_name,steal_1_chance,steal_2_name,steal_2_chance
Tranquilizer,32,Grenade,8
Location\(s\):\s*(.+)
Attack lines have a nice pattern:
\{?([A-Za-z0-9 '\-]+)\}?\s+\[([^\]]+)\]
That extracts:
Machine Gun,"Physical Attack, 1 Target, 27 Base Damage"
Double Shot,"Physical Attack, 1 Target, 50.625 Base Damage"
Roller Dash,"Physical Attack, 1 Target, 38 Base Damage"
Rollerspin,"Physical Attack, 1 Target, 66.5 Base Damage"
Use regex to make an intermediate cleaned text format, not final CSV.
Example target:
Name: Mighty Grunt
Level: 12
Exp: 50
HP: 230
MP: 0
Gil: 98
Drops: Tranquilizer [8]
Steal: Tranquilizer [32]; Grenade [8]
Morph: ---
Location: Shinra Building (Midgar)
Attacks: Machine Gun [Physical Attack, 1 Target, 27 Base Damage]; Double Shot [Physical Attack, 1 Target, 50.625 Base Damage]; Roller Dash [Physical Attack, 1 Target, 38 Base Damage]; Rollerspin [Physical Attack, 1 Target, 66.5 Base Damage]
Notes: Mighty Grunt will lose its armor...
Then convert that to CSV.
The ASCII layout is visually regular but semantically irregular. Regex should grab labels and values, not columns. The vertical bars are presentation, not structure. Treat them as noise except where they help identify sections.
M: do you know of a better way that isn't regex? i'm looking at it and, at least before the larger and more variable block at the end that includes attacks and advice and all that, it looks like, in the faq, every bit of information is exactly in the same place. i could hypothetically, like, identify 'line 6, characters 6-13' as being 'hp' for every entry, etc, so not being able to take advantage of this guy's precision just chafes a bit.
G: Yes. Use fixed-width parsing.
That is probably better than regex for the top/stat blocks because the FAQ author already did the hard work: he made a stable 80-column record layout.
Think of it like an old COBOL/mainframe file: each field lives at fixed line/column coordinates.
Example concept:
name = line[6:18].strip()
level = line[9:13].strip()
exp = line[22:27].strip()
attack = line[43:49].strip()The workflow would be:
lines = [line.rstrip("\n").ljust(80) for line in block]For the Mighty Grunt block, you’d map something like:
fields = {
"name": (0, 7, 20),
"level": (2, 10, 15),
"exp": (2, 22, 28),
"attack": (2, 43, 50),
"mdefense": (2, 58, 65),
"luck": (2, 72, 78),
"hp": (4, 10, 15),
"ap": (4, 22, 28),
"mattack": (4, 43, 50),
"defense_pct": (4, 58, 65),
"mp": (6, 10, 15),
"gil": (6, 22, 28),
"defense": (6, 43, 50),
"dexterity": (6, 58, 65),
}Then:
def get(lines, row, start, end):
return lines[row][start:end].strip().rstrip("*")
record = {}
for key, spec in fields.items():
row, start, end = spec
record[key] = get(lines, row, start, end)This is the right direction because it respects the author’s precision instead of fighting it.
The hybrid method I’d use:
Fixed-width parsing:
- name
- stats
- elements
- status immunities
- drops / steal / morph header zones
Regex/light parsing:
- item lists inside each fixed-width zone
- attacks
- battle notes
- variable trailing text
So you’d use slicing to isolate:
Steal zone = lines[22:24], columns 27:53
Then parse only inside that small extracted text.
That avoids “hero regex” and gives you a durable pipeline:
ASCII FAQ block
→ fixed-width zones
→ cleaned field strings
→ item parser
→ CSV/JSON/HTML
And yes, this is exactly the kind of situation where fixed-width parsing is not only valid but preferable.
M: splitting wouldn't need to be manual; every entry is begun by a line that matches ^.=+.$
G: Exactly. Then the block splitter is easy and reliable:
import re
blocks = re.split(r"(?m)(?=^\.=+\.$)", faq_text)
blocks = [b for b in blocks if b.strip()]That keeps the starting border line attached to each enemy block.
Then your parser can treat each block as:
lines = block.splitlines()
lines = [line.rstrip("\n").ljust(80) for line in lines]So the pipeline becomes:
split on ^\.=+\.$
→ fixed-width line/column slicing
→ light cleanup
→ CSV/JSON/HTML
That’s much cleaner than trying to regex the whole structure.
Small correction to my previous indexing: if the
.===================. line is included, then
Name: is on lines[1], not
lines[0].
So:
name = lines[1][7:20].strip()The nice thing is that once one block works, you can dump suspicious rows where expected labels are missing:
if "Level:" not in lines[3]:
print("layout drift:", name)That gives you a quick way to catch exceptions without hand-auditing the whole FAQ.