[FFVII] Enemy AI Script questions

  • Thread starter Thread starter DynamixDJ
  • Start date Start date
Status
Not open for further replies.
Yeah, I've seen quite a lot of instances with dummied out script, particularly in instances where it's obvious that the scrip has been C+Ped from another enemy. The Elfadunk for example checks to see if the Battle Type is type 2 (back attack), but then does nothing with that check. The MP, Guard Hound, Mono Drive and Grunt all have disabled script; I get that it's easier and quicker just to overrite certain script than it is to tidy it, especially with the flevel.lgp, take Sector 7 as an example. Leaving in the dummied out script means that they can easily modify the scene if they wish to change it at a later dare.

@NFITC1 I need your help with this, the qhimm wiki states that formula 22 uses split damage, however, after going through TF's FAQ I can see that the majority of actions that use the regular damage formula 22 all have No Split damage when attacking all targets.

I was ready to change my database so that all 22 attacks use Split Damage, until I came to Motor Ball. Two of his attacks targets all opponents - Twin Burner and Rolling Fire. Both use 22, however, Twin Burner has split damage and Rolling fire has no split damage. Tried and tested.

So yeah, I'm banging my head against the wall with this. Why is it that an "All Opponents" Attack that uses 22 such as Beta will have No Split, and another attack that uses 22 such as Twin Burner will have split damage?
 
I’ll have to double check some of this, but IIRC 41E0 is the actor’s MMP. Maybe the mandragora use it as a sort of shared pool? I dunno.

As for the 22 having split damage, it certainly does. That might be the magic calf for either most magic damage actions the player has (fire, ice, etc) or magic healing (cure, et al). Either way, there is a flag on actions that can set to bypass the split damage calculations. Most likely the ones TF has listed as 22 and non-split have this override enabled.

I’ll have to check on 2040, though. It doesn’t seem familiar.
 
Ah, so there's a separate flag that can override the Split Damage, I'm guessing this is something similar to the fact that the M/Barrier check can also be overriden?

I have Actor's MMP as 4150 btw
 
Then 4160 is current HP. I’m transposing numbers in my head... I don’t remember what 41E0 is.

EDIT:
It looks like neither 41E0 or 2040 are set by the battle engine.

For Mandragora's part, it look like it's using 41E0 to direct AI for all the Mandragoras in the battle. If one is attacked with either physical or magical damage, then the next attacking mandragora will counter with a specific action based on the type and then declare to the others "I've avenged us".

As for 2040. The only enemies that use it are Bottomswell, Carry Armor/Left Arm/Right Arm, Elfadunk, Roulette Cannon, SOLDIER:2nd, Turks:Rude. Roulette Cannon and SOLDIER:2nd can appear in the same formation so they might be able to shed some light as to what the intended function is.
 
Last edited:
Thanks for looking, I'll keep my eyes peeled when I reach those enemies.

I was having trouble with the Zemzelett's use of [2120] in its general counter script:

If (BattleAddr(&ElementsOfLastAction) AND 3)

I was in the frame of mind that the Element check was for the Index ID, meaning that if 00 Fire, 04 Poison, 08 Holy or 0C Punch was used then the counter would not trigger. I couldn't work out why Fire was triggering the counter....

The qhimm wiki solved the problem. It's because it's looking at the bitmask of the Element, not the index, so only 0x0001 and 0x0002 (Fire and Ice) will trigger the counter script. Tried and tested :) quite glad to move on from that lol
 
I found that 41E0 and 41F0 ARE indeed being set....

*investigation music intensifies!*
*investigation music abruptly ends*

Well that took, literally 10 seconds. 41E0 is Initial HP and 41F0 is Initial MP...but only for playable characters. It also doesn't seem to ever be used this way. Mandragora is literally the only enemy that uses it. Possibly it was a convenient dummy value for enemies and the AI programmer just thought "I'll use this value that is never used to communicate between enemies of the same type". While a great idea, it is sadly underused even as that.

2040 is still unset by the battle engine. It's a convenient global value marker, however, since it will not be automatically changed/unset during the battle except through scripting.
 
OK cool, thanks for clearing that up (I actually read that as 41E0 being *investigation music intensifies!* and 41F0 being *investigation music abruptly ends* for a moment there lol).

Damn, my head is absolutely spinning. I've been working on Bottomswell for hours now, and I'm still not 100% sure I have it deciphered right. I could do with a fresh pair of eyes to check my work:


Code: [Select]
Code:
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  ||   Bottomswell's BATTLE PLAN:                                               ||                                                                            ||  SETUP: Disable default Death handling, sets Row value to 16 (Flying)      ||                                                                            ||                                                                            ||  PHASE 1: (Repeats)                                                        ||                                                                            ||   Bottomswell's HP > 75% AND been attacked less than 6 times               ||                                                                            ||    1ST ATTACK: Use Tail Attack on Rnd Target                               ||    2ND ATTACK: Use Tail Attack on Rnd Target                               ||    3RD ATTACK: Use Tail Attack on Rnd Target                               ||    4TH ATTACK:                                                             ||                                                                            ||     1/3 Chance: Use Tail Attack on 2nd Target; If 2nd Target has Death, do ||                  nothing                                                   ||      Follow-Up: Use Tail Attack on 1st Target; If 1st Target has Death, do ||                  nothing                                                   ||      Follow-Up: Use Tail Attack on 3rd Target; If 3rd Target has Death, do ||                  nothing                                                   ||                                                                            ||     2/3 Chance: Use <Bodyblow> on Target with Highest HP                   ||                                                                            ||                                                                            ||  PHASE 2:                                                                  ||                                                                            ||   Bottomswell's HP <=75% OR been attacked 6 times while in Phase 1         ||                                                                            ||    1ST ATTCK: Use Moonstrike on 2nd Target; If 2nd Target has Death, do    ||                nothing                                                     ||    FOLLOW-UP: Use Moonstrike on 1st Target; If 1st Target has Death, do    ||                nothing                                                     ||    FOLLOW-UP: Use Moonstrike on 3rd Target; If 3rd Target has Death, do    ||                nothing                                                     ||                                                                            ||    2ND ATTACK: Use <Bodyblow> on Target with Highest HP                    ||    3RD ATTACK: Use Moonstrike on Rnd Target                                ||    4TH ATTACK:                                                             ||                                                                            ||      Bottomswell's HP  > 75%: Use <Fury Blast> on Self, transformation to  ||                                Phase 1, sets Attack Count to 0             ||                                                                            ||      Bottomswell's HP <= 75%: Use Moonstrike on Rnd Target                 ||                    Follow-Up: 1/2 Chance jump to 1st Attack for next turn  ||                               1/2 Chance jump to 2nd Attack for next turn  ||                                                                            ||                                                                            ||  PHASE 3:                                                                  ||                                                                            ||   Bottomswell's HP <=50% OR been attacked 6 times while in Phase 2         ||                                                                            ||    1ST ATTCK: Use <Waterball> on Rnd Target without Seizure                ||    2ND ATTCK: Skip a turn                                                  ||    3RD ATTCK: Skip a turn                                                  ||    4TH ATTCK:                                                              ||                                                                            ||      Bottomswell's HP  > 50%: Use <Chill> on self, transformation to Phase ||                                1, sets Attack Count to 0                   ||                                                                            ||      Bottomswell's HP <= 50%: Big Wave on All Targets                      ||                                                                            ||    5TH ATTACK: Skip a turn                                                 ||                                                                            ||      After 5th Attack: Jump to 2nd Attack for next turn, If no Targets     ||                         have Imprisoned, jump to 1st Attack for next turn  ||                                                                            ||                                                                            ||  DEATH: Use Big Wave on All Targets, use <Vanish> on Self                  ||>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~o~~~~~~~~~~~~~~~~~~~~~~~~~~~~<|
This has been deciphered from the following heavily modified version of the AI script:

Code: [Select]
Code:
PRE-BATTLE:(Self) | (DeathImmunity) = 1LocalVar:1stChr = FlagBit(Player1)LocalVar:2ndChr = FlagBit(Player2)LocalVar:3rdChr = FlagBit(Player3)LocalVar:Waterpolo =  ((ActiveActors) | (SelfID) == 92) LocalVar:1stChrWaterpolo =  (LocalVar:Waterpolo.(PlayerID) == 0) LocalVar:2ndChrWaterpolo =  (LocalVar:Waterpolo.(PlayerID) == 1) LocalVar:3rdChrWaterpolo =  (LocalVar:Waterpolo.(PlayerID) == 2) LocalVar:HitCount = 6(Self) | (Row) = 16SCRIPT ENDMAIN: If ((Self) | (IdleAnimID) == 0) {  If (LocalVar:Count == 0)  {  }  Else  {   If (LocalVar:Count == 1)   {  }  Else  {   If (LocalVar:Count == 2)   {  (TarSelected) = Random (AllPlayers)  Perform ("Tail Attack" [0142])  LocalVar:Count = LocalVar:Count + 1  }  Else  {   }   Else   {   If (Rnd(0..2) == 0)   {    If ( (LocalVar:2ndChr) | (DeathStatus) == 0)    {    (TarSelected) = LocalVar:2ndChr    Perform ("Tail Attack" [0142])    If ( (LocalVar:1stChr) | (DeathStatus) == 0)    {    (TarSelected) = LocalVar:1stChr    Perform ("Tail Attack" [0142])    If ( (LocalVar:3rdChr) | (DeathStatus) == 0)    {    (TarSelected) = LocalVar:3rdChr    Perform ("Tail Attack" [0142])   }   Else   {    (TarSelected) = Random ((AllPlayers) | (HighestCurrentHP))   Perform ("Bodyblow" [012D])  LocalVar:Count = 0  }  Else  { POP(LocalVar:Count) } Else {  }  Else  {   If ((Self) | (IdleAnimID) == 6)   {   If (LocalVar:Count == 0)   {    If ( (LocalVar:2ndChr) | (DeathStatus) == 0)    {    (TarSelected) = LocalVar:2ndChr    Perform ("Moonstrike" [01CE])    If ( (LocalVar:1stChr) | (DeathStatus) == 0)    {    (TarSelected) = LocalVar:1stChr    Perform ("Moonstrike" [01CE])    If ( (LocalVar:3rdChr) | (DeathStatus) == 0)    {    (TarSelected) = LocalVar:3rdChr    Perform ("Moonstrike" [01CE])   LocalVar:Count = 1   }   Else   {    }    Else    {     If (LocalVar:Count == 1)     {     (TarSelected) = Random ((AllPlayers) | (HighestCurrentHP))    Perform ("Bodyblow" [01A9])    LocalVar:Count = 2    }    Else    {     }     Else     {      If (LocalVar:Count == 2)      {     (TarSelected) = Random (AllPlayers)     Perform ("Moonstrike" [01CE])     LocalVar:Count = 3     }     Else     {      }      Else      {      If ( (LocalVar:Stage < 1) )      {      (TarSelected) = (Self)      Perform ("Fury Blast" [01D0])      (Self) | (IdleAnimID) = 0      LocalVar:Count = 0      LocalVar:HitCount = 6      }      Else      {      (TarSelected) = Random (AllPlayers)      Perform ("Moonstrike" [01CE])       If (Rnd(0..1) == 0)       {       LocalVar:Count = 0       }       Else       {       LocalVar:Count = 1     }     Else     {  POP(LocalVar:Count)  }  Else  {   }   Else   {   If (LocalVar:Count == 0)   {   LocalVar:EnemyGrp = 0    If ( ( (LocalVar:1stChr) | (DeathStatus) == 0)  And  ( (LocalVar:1stChr) | (ImprisonedStatus) == 0) )    {    LocalVar:EnemyGrp = LocalVar:EnemyGrp OR 1    If ( ( (LocalVar:2ndChr) | (DeathStatus) == 0)  And  ( (LocalVar:2ndChr) | (ImprisonedStatus) == 0) )    {    LocalVar:EnemyGrp = LocalVar:EnemyGrp OR 2    If ( ( (LocalVar:3rdChr) | (DeathStatus) == 0)  And  ( (LocalVar:3rdChr) | (ImprisonedStatus) == 0) )    {    LocalVar:EnemyGrp = LocalVar:EnemyGrp OR 4    If ( (LocalVar:EnemyGrp AND 7 == 7) )    {     If (Rnd(0..2) == 0)     {     LocalVar:TarSelected = LocalVar:1stChr     }     Else     {      }      Else      {       If (Rnd(0..2) == 1)       {      LocalVar:TarSelected = LocalVar:2ndChr      }      Else      {       }       Else       {      LocalVar:TarSelected = LocalVar:3rdChr      }      Else      {    POP(Rnd(0..2))    }    Else    {     If ( (LocalVar:EnemyGrp AND 5 == 5) )     {      If (Rnd(0..1) == 0)      {      LocalVar:TarSelected = LocalVar:1stChr      }      Else      {      LocalVar:TarSelected = LocalVar:3rdChr     }     Else     {      If ( (LocalVar:EnemyGrp AND 3 == 3) )      {       If (Rnd(0..1) == 0)       {       LocalVar:TarSelected = LocalVar:1stChr       }       Else       {       LocalVar:TarSelected = LocalVar:2ndChr      }      Else      {       If ( (LocalVar:EnemyGrp AND 6 == 6) )       {        If (Rnd(0..1) == 0)        {        LocalVar:TarSelected = LocalVar:2ndChr        }        Else        {        LocalVar:TarSelected = LocalVar:3rdChr       }       Else       {       LocalVar:TarSelected = (ClearToZero)    If ( (LocalVar:TarSelected != (ClearToZero)) )    {    (TarSelected) = LocalVar:TarSelected     If ( (LocalVar:TarSelected == LocalVar:1stChr) )     {     Perform ("Waterball" [01D2])     (TarSelected) = LocalVar:1stChrWaterpolo     }     Else     {      If ( (LocalVar:TarSelected == LocalVar:2ndChr) )      {      Perform ("Waterball" [01D3])      (TarSelected) = LocalVar:2ndChrWaterpolo      }      Else      {      Perform ("Waterball" [01D4])      (TarSelected) = LocalVar:3rdChrWaterpolo    (TarSelected) | (DeathStatus) = 0    (TarSelected) | (SelfActive) = 1    (TarSelected) | (Targetable) = 1    (TarSelected) | (Needed2EndBattle) = 1    (TarSelected) | (AIScriptActive) = 1    (TarSelected) | (CurrentHP) = (TarSelected) | (MaxHP)    (TarSelected) | (PhysImmunity) = 1   LocalVar:Count = 1   }   Else   {    }    Else    {     If (LocalVar:Count == 1)     {    }    Else    {     If (LocalVar:Count == 2)     {    LocalVar:Count = LocalVar:Count + 1    }    Else    {     }     Else     {      If (LocalVar:Count == 3)      {      If ( (LocalVar:Stage < 2) )      {      (TarSelected) = (Self)      Perform ("Chill" [01D6])      (Self) | (IdleAnimID) = 0      LocalVar:Count = 0      LocalVar:HitCount = 6      }      Else      {      (TarSelected) = (AllPlayers)      Perform ("Big Wave" [01D5])      LocalVar:Count = 4     }     Else     {      }      Else      {     LocalVar:PlayerImprisoned = BitCount( ((AllPlayers) | (ImprisonedStatus) == 1) )     LocalVar:PlayerDeath = BitCount( ((AllPlayers) | (DeathStatus) == 1) )      If ( ( (LocalVar:PlayerDeath >= 1)  And  (LocalVar:PlayerImprisoned >= 1) ) )      {      LocalVar:Count = 1      }      Else      {      LocalVar:Count = 0     }     Else     {  POP(LocalVar:Count)  }  Else  {POP((Self) | (IdleAnimID))SCRIPT ENDGENERAL COUNTER: If ( ((Self) | (CurrentHP) <= (Self) | (MaxHP) / 4 * 2) ) { LocalVar:Stage = 2 LocalVar:HitCount = 0 } Else {  If ( ((Self) | (CurrentHP) <= (Self) | (MaxHP) / 4 * 3) )  {  LocalVar:Stage = 1  LocalVar:HitCount = 0  }  Else  {  LocalVar:Stage = 0 If ( ((Self) | (IdleAnimID) == 0) ) { (Self) | (DamagedAnimID) = 1  If (Not  (LocalVar:HitCount) )  {  (TarSelected) = (Self)  Perform ("Fury Blast" [01CF])  (Self) | (IdleAnimID) = 6  LocalVar:Count = 0  LocalVar:HitCount = 6   If ( (LocalVar:Stage == 2) )   {   (TarSelected) = (Self)   Perform ("Fury Blast" [01D1])   (Self) | (IdleAnimID) = 12   LocalVar:Count = 0   LocalVar:HitCount = 3  }  Else  {  LocalVar:HitCount = LocalVar:HitCount - 1 } Else {  If ( ((Self) | (IdleAnimID) == 6) )  {  (Self) | (DamagedAnimID) = 7   If (Not  (LocalVar:HitCount) )   {   (TarSelected) = (Self)   Perform ("Fury Blast" [01D1])   (Self) | (IdleAnimID) = 12   LocalVar:Count = 0   LocalVar:HitCount = 3   }   Else   {   LocalVar:HitCount = LocalVar:HitCount - 1  }  Else  {  (Self) | (DamagedAnimID) = 13SCRIPT ENDDEATH COUNTER:(TarSelected) = (AllPlayers)Perform ("Big Wave" [01D5]) If ( ((ActiveActors) | (ImprisonedStatus) == 1) ) { (TarSelected) =  ((ActiveActors) | (ImprisonedStatus) == 1)  (TarSelected) | (ImprisonedStatus) = 0(TarSelected) = (Self)Perform ("Vanish" [014E])LocalVar:Waterpolo.(SelfActive) = 0LocalVar:Waterpolo.(Targetable) = 0LocalVar:Waterpolo.(Needed2EndBattle) = 0LocalVar:Waterpolo.(AIScriptActive) = 0SCRIPT END
What's bugging me is "HitCount" being set to 3 once it reaches it's third 'phase' (once IdleAnimID gets set to 12 during the counter scruipt). I think there may have been something I've overlooked. These notes may help:


Code: [Select]
Code:
|                                                                            ||  COUNTER: [All Physical and Magical Attacks]                               ||                                                                            ||   PHASE 1: 1st Attack: DamagedAnimID = 1                                   ||            6th Attack: Use <Fury Blast> on Self, transformation to Phase 2 ||                                                   IdleAnimID = 6           ||                                                   Count = 0                ||                                                   HitCount = 6             ||                                                                            ||             HP <= 50%: Use <Fury Blast> on Self, transformation to Phase 3?||                                                   IdleAnimID = 12          ||                                                   Count = 0                ||                                                   HitCount = 3             ||                                                                            ||                                                                            ||   PHASE 2: 1st Attack: DamagedAnimID = 7                                   ||            6th Attack: Use <Fury Blast> on Self, transformation to Phase 3 ||                                                   IdleAnimID = 12          ||                                                   Count = 0                ||                                                   HitCount = 3             ||                                                                            ||                                                                            ||   PHASE 3: 1st Attack: DamagedAnimID = 13                                  ||                                                                            ||                                                                            ||  Phase 1 = IdleAnim 0                                                      ||  Phase 2 = IdleAnim 6                                                      ||  Phase 3 = IdleAnim 12 ?                                                   ||                                                                            ||                                                                            ||   Bottomswell' HP > 75%          Stage = 0                                 ||                                                                            ||   Bottomswell' HP <= 75%         Stage = 1                                 ||                                  Hit Count = 0                             ||                                                                            ||   Bottomswell' HP <= 50%         Stage = 2                                 ||                                  Hit Count = 0                             ||                                                                            ||  Fury Blast 1CF = To Phase 2                                               ||  Fury Blast 1D0 = To Phase 1                                               ||  Fury Blast 1D1 = To Phase 3                                               |

This has definitely been one of the more complicated scripts to work out

edit- i have overlooked something. After testing, Bottomswell will use Waterball once it reaches stage 2 (HP <= 75%). I'm not sure why this is.
 
Last edited:
I've just noticed that the Formation itself for Bottomswell has Death Counter script, which I nearly missed. I believe it deals with removing the Waterpolo once the player has died. I'm guessing this script just loops repeatedly in the background?

NFI, how many formations are there that I need to be aware of that contains AI script?

Also the wiki has 2180 dow as "Unknown (divisor of some sort related to limits)". It looks like 2180 is used as a "Character Flagbit", used for checking which target to look at.

This is the death counter script for the Bottomswell formation:

Code: [Select]
Code:
DEATH COUNTER:0x000BattleAddr(&2180) <- 00x006 If ( (BattleAddr(&2180) < 3) )0x006 {0x00F BattleAddr(&TarSelected) <- FlagBit(BattleAddr(&2180))0x017  If ( (BattleAddr(&TarSelected).BattleAddr(&DeathStatus) == 1) )0x017  {0x024   If ( (BattleAddr(&TarSelected).BattleAddr(&ImprisonedStatus) == 1) )0x024   {0x031   BattleAddr(&Self) <-  (BattleAddr(&ActiveActors).BattleAddr(&SelfID) == 92) 0x03F   BattleAddr(&Self) <-  (BattleAddr(&Self).BattleAddr(&PlayerID) == BattleAddr(&2180)) 0x04E   BattleAddr(&TarSelected).BattleAddr(&ImprisonedStatus) <- 00x058   BattleAddr(&TarSelected) <- BattleAddr(&Self)0x05F   Perform("Vanish"[014E], EnemyAttack)0x065   BattleAddr(&Self).BattleAddr(&DeathImmunity) <- 10x06F   BattleAddr(&Self).BattleAddr(&DeathStatus) <- 00x079   BattleAddr(&Self).BattleAddr(&SelfDead) <- 00x083   BattleAddr(&Self).BattleAddr(&Targetable) <- 00x08D BattleAddr(&2180) <- BattleAddr(&2180) + 10x097  LOOP 0x0060x09A SCRIPT END
 
Last edited:
NFI, how many formations are there that I need to be aware of that contains AI script?
Not as many as there should be. I can say that for certain. Most bosses that have "containers" like Rude's pyramids or Bottomswell's bubbles have them I think. Carry Armor might too. I only added editing them to PrC because I was told they exist. I never did much digging into them.

2180 might be another of those absconded memory addresses that had a function, but no implementation. I'm not sure why it's listed what it is in the wiki (I wrote it, I'm sure). I probably noticed it during a reversing session and just labeled it with the intention of revisiting it and just never did.
 
The Grangalan looks at 402B, which the wiki describes as "Was covered / Defers damage".

In what context could the Grangalan be "covered"? I have to assume that this refers to the binary cover flag, and in the instance of the Grangalan, it will be covered if the Granagalan Jr. is present, OR the Grangalan Jr.Jr. A is present.

I'm gonna go ahead and mark it down as such because I don't know what else it could be for now.

Edit - tried and tested 402B is definitely the cover flag (The Grangalan is only covered if the Grangalan Jr. or rightmost Grangalan Jr.Jr is present; kill those two and the Grangalan is no longer covered and moves into the other part of its script).
 
Last edited:
What's going on here with the Grangalan Jr.Jr.?

Code: [Select]
Code:
MAIN:0x000 If (Random MOD 4 == 0)0x000 {0x009 }0x009 Else0x009 {0x00C  }0x00C  Else0x00C  {0x00F BattleAddr(&TarSelected) <- RandomBit(BattleAddr(&AllPlayers))0x017 Perform("Silver Wheel"[01DC], EnemyAttack)0x01D }0x01D Else0x01D {0x020POP(Random MOD 4)0x021SCRIPT END
Is this a 1/4 chance of using silver wheel or a 3/4 chance?

the Jr.Jr. has an unused Attack (Stop Eye 01DB) which has a 71% chance of casting Stop on the target. It's likely that they decided this was too OP and removed the attack from the script (imagine how hard it would be in the battle square).

It looks to me as though they have removed the Stop Eye attack from the script but didn't clean it properly. I can't tell if this is running sequentially or not. I think it should have been initially a 1/4 chance use Stop Eye and a 3/4 chance use Silver Wheel.

Terrence Ferguson has deciphered it as a 1/4 chance of using Silver Wheel, but I suspect that it's wrong, it's actually a 3/4 chance and a 1/4 chance it'll do nothing. Testing against them seems to suggest so, anyway. NF?
 
Last edited:
When does the "Custom Event" script get played? On the Mystery Ninja, we can see script which disables the mystery ninja's AI script and target-ability. Does this get played upon the Enemy's death?

Also, what does "RunScript(15)" do?
 
Last edited:
RunScript(15) runs the enemy's sixteenth script: What Proud Clod calls "Custom Event 8". All custom scripts are executed in this way.
 
Ah OK, cool. That answers both questions :)

The wiki marks 2018 as "DUMMY. Used in one script in a test enemy." I suspect this is accessing Memory Bank 7/F (not that it does anything with it)
 
I made an interesting discovery yesterday. I was making a list of all of the test formations, and the backgrounds that they appear on. I didn't include any duplicate formations, only unique ones, and take note of the test Encounters found on the Debug Background:

Code: [Select]
Code:
  DEBUG TEST AREA BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 1000      1st Row: 1x êúô0(äñ)                  ||                      AP  - 100                                             ||                      GIL - 10,000                                          ||                                                                            ||   Test Encounter #2  EXP - 500,000   1st Row: 2x êúô2(ñ)                   ||                      AP  - 10,000    2nd Row: 2x êúô2(ñ)                   ||                      GIL - 500,000   3rd Row: 1x êúô2(ñ)                   ||                                                                            ||   Test Encounter #4  EXP - 16        1st Row: 1x êúô7(úñA), 1x êúô8(úñB)   ||                      AP  - 2                                               ||                      GIL - 10                                              ||                                                                            ||   Test Encounter #5  EXP - 24        1st Row: 1x êúô7(úñA), 1x êúô8(úñB),  ||                      AP  - 3                                  1x êúô9(úñC) ||                      GIL - 15                                              ||                                                                            ||   Test Encounter #6  EXP - 32        1st Row: 1x êúô7(úñA), 2x êúô8(úñB),  ||                      AP  - 4                                  1x êúô9(úñC) ||                      GIL - 20                                              ||                                                                            ||   Test Encounter #7  EXP - 1000      1st Row: 1x êúô0(äñ)                  ||      Back Attack     AP  - 100                                             ||          Run = 2     GIL - 10,000                                          || Battle Won't End                                                           ||                                                                            ||   Test Encounter #8  EXP - 1000      1st Row: 1x êúô0(äñ)                  ||      Side Attack     AP  - 100                                             ||                      GIL - 10,000                                          ||                                                                            ||   Test Encounter #9  EXP - 2000      1st Grp: 1x êúô0(äñ)                  ||      Pinc Attack     AP  - 200       2nd Grp: 1x êúô0(äñ)                  || Battle Won't End     GIL - 20,000                                          |'----------------------------------------------------------------------------'  FOREST BACKGROUND: NOTE - The first encounter could be found in the Well in Corel Prison in the          JORG version as a 12.5% encounter chance..----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 4000      1st Row: 4x êúô0(äñ)                  ||                      AP  - 400                                             ||                      GIL - 40,000                                          ||                                                                            ||   Test Encounter #2  EXP - 96        1st Row: 1x êúô4(ëöù)                 ||                      AP  - 6         2nd Row: 2x êúô4(ëöù)                 ||                      GIL - 240                                             ||                                                                            ||   Test Encounter #3  EXP - 80        1st Row: 1x êúô4(ëöù), 1x êúô5(áñô),  ||                      AP  - 5                                   1x êúô6(ñâ) ||                      GIL - 100                                             ||                                                                            ||   Test Encounter #4  EXP - 6000      1st Row: 6x êúô0(äñ)                  ||                      AP  - 600                                             ||                      GIL - 60,000                                          |'----------------------------------------------------------------------------'  TRAIN GRAVEYARD BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 101,012   1st Row: 1x êúô0(äñ)                  ||                      AP  - 2101      2nd Row: 1x êúô1(), 1x êúô2(ñ)        ||                      GIL - 110,025                                         |'----------------------------------------------------------------------------'  DIRT WASTELAND BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 72        1st Row: 2x êúô4(ëöù), 1x êúô6(ñâ)    ||      Back-Attack     AP  - 5                                               ||          Run = 2     GIL - 165                                             |'----------------------------------------------------------------------------'  SNOW BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 40        1st Row: 1x êúô6(ñâ), 1x êúô4(ëöù)    ||      Side-Attack     AP  - 3                                               ||                      GIL - 85                                              |'----------------------------------------------------------------------------'  SEWERS BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 128       1st Grp: 2x êúô4(ëöù)                 ||      Pinc Attack     AP  - 8         2nd Grp: 2x êúô4(ëöù)                 || Battle Won't End     GIL - 320                                             |'----------------------------------------------------------------------------'  COREL VALLEY BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 6000      1st Row: 2x êúô0(äñ) <C>              ||  No Victory Pose     AP  - 600       2nd Row: 1x êúô0(äñ) <C>              || Battle Won't End     GIL - 60,000    3rd Row: 3x êúô0(äñ)                  ||                                                                            ||   Test Encounter #2  EXP - 72        1st Row: 2x êúô1() <C>                ||  No Victory Pose     AP  - 6         2nd Row: 1x êúô1() <C>                ||                      GIL - 150       3rd Row: 3x êúô1()                    |'----------------------------------------------------------------------------'  BLANK BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 100,000   1st Row: 1x êúô2(ñ)                   ||                      AP  - 2000                                            ||                      GIL - 100,000                                         |'----------------------------------------------------------------------------'  SISTER RAY BASE BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 100,000   1st Row: 1x êúô2(ñ)                   ||                      AP  - 2000                                            ||                      GIL - 100,000                                         |'----------------------------------------------------------------------------'  KALM FLASHBACK DRAGON BATTLE BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 100       1st Row: 2x Mighty Grunt              ||     Auto Pre-Emp     AP  - 10                                              ||                      GIL - 196                                             |'----------------------------------------------------------------------------'  COREL TRAIN BATTLE BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 100       1st Row: 2x Mighty Grunt              ||                      AP  - 10                                              ||                      GIL - 196                                             |'----------------------------------------------------------------------------'  REACTOR 5 BACKGROUND:.----------------------------------------------------------------------------.|   Test Encounter #1  EXP - 4320      1st Row: 3x Adamantaimai              ||                      AP  - 600       2nd Row: 3x Adamantaimai              ||                      GIL - 12,000                                          |'----------------------------------------------------------------------------'
There are exactly enough formations on the Debug Background to fill out each slot on a field map! It's likely that these formations were once used on one of the blackbg maps to test encounters (the Back Attack would have filled both back-attack slots with a probable rating of 2 or 4 for each)
 
There's more debug info in the Japanese PSX edition. There is no scene.bin as that is unique to the PC edition, but the test enemies and formations were way different in the initial release. Every other edition after the first Japan release had their test enemies replaced with those pyramids.

As for 2018, this is only used in one of (all of?) the debug enemies and doesn't seem to be assigned anything.

What I'll say abou Grangalan Jr. Jr. is that PrC's AI disassembler isn't perfect. That's because the AI scripts themselves aren't perfect. Sometimes jumps will jump to jumps and other times jumps won't be reachable at all. This always throws off the disassemly. I think the Kalm wolf has some behavior like this, but it has a very simple script. Anyway, when this happens you'll have to diagnose the script by hand/sight.
TFergusson is incorrect and the script indicates a 3/4 chance of silver wheel. Take a look at the binary script:
Code: [Select]
Code:
8160  043460  0071  000F72  002072  000F...
This is the relevant part at least. The code 71 will jump if the top two pops ARE NOT EQUAL. So the (Random Mod 4) will NOT trigger this if it is equal 0 and it will jump to 0020 at the next step. The confusing bit is the unreachable 72  000F that is located at 0x00C. This is confusing the disassembly and causing the weird output. This actually may be an artifact of the removed Stop Eye action.
 
There is no scene.bin as that is unique to the PC edition
The PlayStation versions use a scene.bin. Same format too-- except the original Japanese releases which had some additional padding. I think the only difference between the original English PS and PC scene.bins is the AI for the Chocobo enemy.
 
Last edited:
Ahh, shoot! You’re right. I was thinking about the battle.lgp that contain the enemy model data. I’ve gotten less smart lately, apparently. :P
 
Thanks for clearing that up about the Grangalan, I had a feeling it had something to do with the way the jumps were working. I've spent a little bit of time looking at the non-disassembled version and things start to make a bit more sense. Also, whenever LMSK or HMSK is used to select the target with the highest/lowest X (HP/MP/Def etc), Pr Cl displays "Bade Code" and the address of the LMSK/HMSK.

The more I learn the easier this becomes. Note to self for my mod: c+p Bagnadrana's script as a template:

Code: [Select]
Code:
0x000: PUSH (2070) Type (12)0x003: PSHA (20A0) Type (02)0x006: RBYT0x007: STRA0x008: RWRD0x009: PUSH (04) Type (01)0x00B: MOD0x00C: PUSH (00) Type (01)0x00E: JNEQ (001D)0x011: PUSH (20) Type (01)0x013: PUSH (0189) Type (02)0x016: ATTK0x017: JUMP (0048)0x01A: JUMP (0022)0x01D: PUSH (01) Type (01)0x01F: JNEQ (002E)0x022: PUSH (20) Type (01)0x024: PUSH (01BE) Type (02)0x027: ATTK0x028: JUMP (0048)0x02B: JUMP (0033)0x02E: PUSH (02) Type (01)0x030: JNEQ (003F)0x033: PUSH (20) Type (01)0x035: PUSH (01E5) Type (02)0x038: ATTK0x039: JUMP (0048)0x03C: JUMP (003F)0x03F: PUSH (20) Type (01)0x041: PUSH (01E6) Type (02)0x044: ATTK0x045: JUMP (0048)0x048: POP 0x049: END
produces an even 1/4 chance of using one of four attacks. Lovely and simple :). Only use attacks that select a single target.
 
Last edited:
Does it actually say “bade code”? I wouldn’t put it past me back then. :P
 
Status
Not open for further replies.
Back
Top