Author Topic: [FF7] 3D Battler RNG  (Read 4532 times)

ff7man

  • *
  • Posts: 31
    • View Profile
[FF7] 3D Battler RNG
« on: 2022-11-11 04:11:29 »
I didn't see much online about the 3D Battler so I took a look at it.

https://gamefaqs.gamespot.com/boards/197341-final-fantasy-vii/54471793

Here's what I learned.

It does not matter what you pick, just when you pick it. It doesn't look at your input at all, whether you win or lose is based entirely on random.
However random is a single byte that increments at about 10-12 per second depending on your movement to the arena and is continually generated by movement of the background characters.
This random random value is at 095dc8 on PSX and FF7_EN.exe+8BF588 on PC
Damage is a counter that increments to 10 at 75e30/FF7_EN.exe+8C14DC (you) and 75e31/FF7_EN.exe+8C14DD (enemy)

Fighter 1: You have a 65.93% chance of winning
Fighter 2: You have a 51.17% chance of winning
Fighter 3: You have a 33.33% chance of winning
Fighter 4: You have a 25% chance of winning
Fighter 5: Is a ghost you cannot kill. Low is a Hit, but the value does not increment in memory. Mid is a Tie. High is a loss.

All considered and random being fair you have a 2.81% chance of getting to the ghost and winning 300gp.

I was thinking maybe it would be possible to find a starting seed that won with a turbo controller, but with how fast RNG increments, this would be very hard to get frame perfectly.
With a turbo controller this could likely be exploited by simply running the game for a while pressing O+X repeatedly as it won't stop until you run out of money or hit the ghost.
That said you are definitely better off doing chocobo races for GP, but it is nice knowing how this mechanic works.


Here are the charts for each fighter. Each seed value has a guaranteed result no matter what input you pick.
If you can see the random seed, you can use these charts to better time your inputs to increase your chances of success.







« Last Edit: 2022-11-23 03:31:35 by ff7man »

nfitc1

  • *
  • Posts: 3010
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: [FF7] 3D Battler RNG
« Reply #1 on: 2022-11-11 11:50:40 »
I’ve done lots of reversing with the 3D battler, actually. The fifth fighter is a programming mistake that happens because defeating the fourth battler doesn’t properly end the game. The last action you took during the fourth fight is what dictates the “active” move the game will react to. If you won with a low punch then the script will continue to cause Cloud to react as if a low punch is a scoring strike. Freezing Cloud’s hit counter will show there’s no way to break this cycle. Since the script that plays this game doesn’t update its reactions after the fourth battle it repeatedly reacts the same way. Oddly it doesn’t update its own hit counter either so it’s impossible to win. I documented this behavior on the ffwiki, but left out the technical details to make it readable to a wider audience.

You are correct that it doesn’t read your input and which punch you decide to throw is completely arbitrary, but it’s unlikely a turbo controller could win. 3DB uses the field’s RNGLUT to pull its random values from and for a single punch to be used to win would require watching that value in memory and pushing a button when that value was within a certain range of values. I bet that could be scripted with relative ease, though thats not something I have experience with.

ff7man

  • *
  • Posts: 31
    • View Profile
Re: [FF7] 3D Battler RNG
« Reply #2 on: 2022-11-12 12:30:50 »
I didn't know the last move on fighter 4 impacts fighter 5's move set. Good to know and I updated the ff7 wiki with the correct stats. I also made a video using my charts. I still think a turbo controller has a chance of winning on certain seeds, it's a simple test. Buy a controller and set O+X to turbo, set a book on it and leave the game running for a while, if it gets to the end we can. A human timing that is a different story.

ff7man

  • *
  • Posts: 31
    • View Profile
Re: [FF7] 3D Battler RNG
« Reply #3 on: 2022-11-12 13:19:01 »
One thing I didn't mention is the RNGLUT is really sporadic and time spent on certain frames depends a lot.

For example on PSX each cycle 0-256 of RNG will wait different amounts of frames before incrementing the RNG value

Code: [Select]
RNG - Cycle1 - Cycle2
6 - 24 - 4
7 - 2  - 14
8 - 18 - 14
9 - 12 - 4
10 - 2 - 14
11 - 18 - 14
12 - 12 - 4
13 - 2 - 28
14 - 30 - 4
15 - 2 - 12
16 - 16 - 16
Once you start the battler it is sped up even more.
Code: [Select]
Frames before increment / Incremented value
8 - 1
8 - 2
8 - 2
4 - 1
4 - 1
8 - 2
8 - 1
8 - 2
8 - 1

I haven't manually counted out all the frames in two cycles either, but there's doesn't seem to be a pattern it follows.
« Last Edit: 2022-11-12 13:38:38 by ff7man »

nfitc1

  • *
  • Posts: 3010
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: [FF7] 3D Battler RNG
« Reply #4 on: 2022-11-12 16:55:45 »
There are a few NPCs in the same field as the battler that cause the RNGLUT to progress. As they move they will change the next value. When the NPCs complete their random action they will pick a new RNG value. Since they both use the same RNGLUT they have a moderate influence on each other.
The field’s RNGLUT doesn’t increment by frame. There’s only one RNG value in the game that I know of that does and it’s in battle and only very rarely used.
There might be some initial condition and set up that will allow for a turbo controller to win, but it would take a lot of math to figure out the ideal condition.

JBedford128

  • *
  • Posts: 113
    • View Profile
Re: [FF7] 3D Battler RNG
« Reply #5 on: 2022-11-12 17:51:31 »
I'm not a statistician, but there's no way you have a 25% chance of beating the fourth opponent.

There's a 25% chance you'll beat him in any given round, but to beat him overall you have to hit him ten times while avoiding being hit ten times. (I think) Since there's no ties, that means you have to roll a 4 on a d4 ten times in 19 contests.

Edit: This dice probability calculator says the probabiliy is 0.8903279303922318%.

Edit Edit: Opponent 1 is 92.58414292768207%. Opponent 2 is 54.13893634975759%. Opponent 3 is 6.4766172790962875%.
« Last Edit: 2022-11-12 20:43:09 by JBedford128 »

ff7man

  • *
  • Posts: 31
    • View Profile
Re: [FF7] 3D Battler RNG
« Reply #6 on: 2022-11-14 15:54:25 »
You are right.... balls. Thanks for correcting me, I don't want to be giving out wrong stats.

Your math checks out with a simple python script

Code: [Select]
import random

n = 0
win = 0
loss = 0
while n<1000000:
 ehealth = 0
 mhealth = 0
 while (ehealth < 10 and mhealth < 10):
  num = random.randint(0,3)
  if num == 1:
    ehealth +=1
  else:
    mhealth +=1
 if ehealth > mhealth:
  win+=1
 else:
  loss+=1
 n+=1

print(n)
print(win)
print(loss)
print(win/n)

Python random isn't precise but gives a .87-.90% depending on the run

So on the website I'm guessing you did:
Dice Type: Tetrahedron (4 faces)
Total number of dice: 19
I want to get: At least X dice equal to
The value: 1 (any of them really)
.. or: 0
Target number of dice (X): 10

How'd you get the numbers in the edit edit?

JBedford128

  • *
  • Posts: 113
    • View Profile
Re: [FF7] 3D Battler RNG
« Reply #7 on: 2022-11-14 19:42:54 »
The linked calculator page gave the formula for calculating the probability so I wrote a quick JavaScript script to execute in the console

Code: [Select]
//probability of succeeding a roll (win, loss)
function prob(w, l) {
  return 1/(w+l)*w;
}

function binomial(n, k) {
    let coeff = 1;
    for (let x = n-k+1; x <= n; x++) coeff *= x;
    for (x = 1; x <= k; x++) coeff /= x;
    return coeff;
}

//probability of rolling r number of successes at p probablity with n number of dice
function P(n, r, p) {
  return binomial(n,r) * Math.pow(p,r) * Math.pow(1-p,n-r)
};
//probability of rolling /at least/ r at p with n
function Pplus(n, r, p) {
  let out = 0;
  for(let i = r; i <= n; i++) {
    out += P(n, i, p);
  }
  return out;
}

function battler() {
  let opponents = [
    [120, 62],
    [ 87, 83],
    [ 64,128],
    [ 64,192]
  ];
  let rolls = 19;
  let wins = 10;
 
  let output = [];
 
  for(let [i, stack] = [0, 1]; i < opponents.length; i++) {
    let p = prob(...opponents[i]);
    let success = Pplus(rolls, wins, p);
    stack *= success;
    output[i] = [success*100, stack*100];
  }
 
  return output;
}

console.log(...battler());