[FINALLY SOLVED] Trouble with AI scripting (FF7)...

  • Thread starter Thread starter titeguy3
  • Start date Start date
Status
Not open for further replies.
T

titeguy3

Guest
As you may or may not know, I've been working on remastering of the AI scripts in FF7 using PrC and an assembler that I coded myself. Normal enemies only get redone if they're too stupid/easy/pointless, or if they're glitchy, and bosses get anything from a minor tweak to a complete overhaul depending on their initial in-game difficulties (I want to make the game harder, but not IMPOSSIBLY hard--I'm trying to make it just barely doable on a lowish level playthrough).

So far everything's been smooth, until I tried to start using new concepts...

What I'm stuck on is Rude's main script for the Gelnika battle. This is what I've got (what PrC disassembly gives me):
Code: [Select]
Code:
LocalVar:0020 <- RandomBit(AllyMask)If ( ( ( (LocalVar:0020.HP < LocalVar:0020.MHP / 2)  And Random MOD 2)  And  (Self.MP >= 64) ) ){ TargetMask <- LocalVar:0020 Perform("Curaga"[0002], EnemyAttack)}ElseIf (Random MOD 2){ LocalVar:0000 <- RandomBit(AllActiveOpponentMask) // EDEF(LocalVar:0000, 8 ) If ( (TargetMask.GreatestElementalDamage <= 4)   Or  (TargetMask.GreatestElementalDamage == 255) ) {  Perform("Ground Punch 2"[0102], EnemyAttack) } // EDEF(LocalVar:0000, 1 ) ElseIf ( ( (TargetMask.GreatestElementalDamage < 4)  Or  (TargetMask.GreatestElementalDamage == 255) )   And  (Self.MP >= 52) ) {  Perform("Firaga"[001D], EnemyAttack) } // EDEF(LocalVar:0000, 2 ) ElseIf ( ( (TargetMask.GreatestElementalDamage < 4)  Or  (TargetMask.GreatestElementalDamage == 255) )   And  (Self.MP >= 52) ) {  Perform("Blizzaga"[0020], EnemyAttack) } // EDEF(LocalVar:0000, 4 ) ElseIf ( ( (TargetMask.GreatestElementalDamage < 4)  Or  (TargetMask.GreatestElementalDamage == 255) )   And  (Self.MP >= 52) ) {  Perform("Thundaga"[0023], EnemyAttack) } Else {  Perform("Shoulder Attack"[0374], EnemyAttack) }}Else{ TargetMask <- AllActiveOpponentMask Perform("Grand Punch 2"[0165], EnemyAttack)}SCRIPT END
This is the assembly code, which is more informative
Code: [Select]
Code:
;Rude Main Script  PUSH11 0020  PSHA01 ALLYMASK  RBYT ; Check whether to heal either yourself or Reno  STRA  PSHA01 0020  PSHA02 HP  MASK  PSHA01 0020  PSHA02 MHP  MASK  PUSH 02  DIV  LSTN  RWRD  PUSH 2  MOD  AND  PSHA01 SELF  PSHA02 MP  MASK  PUSH #64  GEQU  AND  JMP0 SINGATK  PUSH11 TARGETMASK  PSHA01 0020  STRA  PUSH 20  PUSH 02 ; Curaga  ATTK  JUMP FINSINGATK  RWRD  PUSH 02  MOD  JMP0 ALLATK  PUSH11 0000  PSHA01 ALLACTIVEOPPONENTMASK  RBYT  STRA  PSHA01 0000  PUSH 8 ; Earth bit  EDEF ; Load GreatestElementalDamage(Earth)  PSHA01 TARGETMASK  PSHA02 GREATESTELEMENTALDAMAGE  MASK  PUSH 4 ; 1/2 damage  LEQU  ; or better  PSHA01 TARGETMASK  PSHA02 GREATESTELEMENTALDAMAGE  MASK  PUSH FF ; gotta check nothing, too  EQU  OR  JMP0 TRYFIRE  PUSH 20  PUSH 102 ; Ground Punch 2, earth damage on one opponent  ATTK  JUMP FINTRYFIRE  PSHA01 0000  PUSH 1 ; Fire bit  EDEF ; Load GreatestElementalDamage(Fire)  PSHA01 TARGETMASK  PSHA02 GREATESTELEMENTALDAMAGE  MASK  PUSH 4 ; 1/2 damage  LSTN  ; ...isn't good enough  PSHA01 TARGETMASK  PSHA02 GREATESTELEMENTALDAMAGE  MASK  PUSH FF ; gotta check nothing, too  EQU  OR  PSHA01 SELF  PSHA02 MP  MASK  PUSH #52  GEQU  AND  JMP0 TRYICE  PUSH 20  PUSH 1D ; Firaga  ATTK  JUMP FINTRYICE  PSHA01 0000  PUSH 2 ; Ice bit  EDEF ; Load GreatestElementalDamage(Ice)  PSHA01 TARGETMASK  PSHA02 GREATESTELEMENTALDAMAGE  MASK  PUSH 4 ; 1/2 damage  LSTN  ; ...isn't good enough  PSHA01 TARGETMASK  PSHA02 GREATESTELEMENTALDAMAGE  MASK  PUSH FF ; gotta check nothing, too  EQU  OR  PSHA01 SELF  PSHA02 MP  MASK  PUSH #52  GEQU  AND  JMP0 TRYBOLT  PUSH 20  PUSH 20 ; Blizzaga  ATTK  JUMP FINTRYBOLT  PSHA01 0000  PUSH 4 ; Bolt bit  EDEF ; Load GreatestElementalDamage(Bolt)  PSHA01 TARGETMASK  PSHA02 GREATESTELEMENTALDAMAGE  MASK  PUSH 4 ; 1/2 damage  LSTN  ; ...isn't good enough  PSHA01 TARGETMASK  PSHA02 GREATESTELEMENTALDAMAGE  MASK  PUSH FF ; gotta check nothing, too  EQU  OR  PSHA01 SELF  PSHA02 MP  MASK  PUSH #52  GEQU  AND  JMP0 SHOULDER  PUSH 20  PUSH 23 ; Thundaga  ATTK  JUMP FINSHOULDER PUSH 20  PUSH 0374 ; Shoulder Attack, non-elemental phys damage  ATTK  JUMP FINALLATK  PUSH11 TARGETMASK  PSHA01 ALLACTIVEOPPONENTMASK  STRA  PUSH 20  PUSH 0165 ; Grand Punch 2, hits everyone  ATTKFIN  END
What this SHOULD do is determine if earth type magic is effective against a chosen opponent, then if it isn't, move on to other elements and finally, default to a physical attack if all elements are a no-go. Instead, Rude constantly defaults to the PHYSICAL attack regardless of elemental immunity (meaning it thinks every one is resistant to every element, which they're not).

Any input/inquiries would be gladly appreciated. Thanks.

Edit: I've switched my code over to using GreatestElementalDamage in conjunction with EDEF, and I got my values straight from the wiki, something's not right here...
 
Last edited:
This might shed some light on it, although it seems that no-one could find a completely satisfactory solution.
 
This might shed some light on it, although it seems that no-one could find a completely satisfactory solution.
That's not an issue with my rude anymore. I deleted his scripts and started them anew.
 
I don't know about your problem, titeguy3, but the original Rude here can be "fixed" by changing byte 0x005 from 40 to 90. This will reset his "I didn't hit Tifa" flag and his script will continue like normal. I think the intention was if he DOES hit Tifa that he wouldn't attack anyone again, but this fails pretty hard. ;) His whole script is just a big wad of mess.
 
I've completely removed the whole "Rude cares about tifa" aspect of Rude's AI for now...

The problem I'm having is with AbsorbElements(x4130) and NullElements(x42A0). I'm trying to make Rude know before attacking whether or not an attack is gonna be absorbed or nullified, but it's not working, I need some confirmation on how to use these variables.
 
Try using the elusive 96h command. The one that Sephiroth has. That might set resistance variables. Not much of it is known. I think Akari told me what he found, but I don't remember exactly what it was. It DOES set the 4058 of an enemy.
 
Thanks for the reply!
It looks like Sephi uses Edef(AllActiveOpponents, 8 ), I'll try that out, then try different second arguments if that doesn't work. Do you know what the significance of the 8 is by any chance?

EDIT: I've tried it with x0-xA, x10, and x20, and still no results...

I notice that Sephiroth's script uses the notion that

If(TargetMask.GreatestElementalDamage >= 5), TargetMask is resistant to Earth

but I don't quite get the functionality of GreatestElementalDamage (x4058), or ElementalWeakness (x4050) for that matter. I'm thinking perhaps it has something to do with the element order(?):
Code: [Select]
Code:
0       0x0000  Non Elemental1       0x0001  Fire 2       0x0002  Ice 3       0x0004  Lightning 4       0x0008  Earth 5       0x0010  Poison 6       0x0020  Gravity 7       0x0040  Water 8       0x0080  Wind 9       0x0100  Holy 10      0x0200  Restorative 11      0x0400  Cut 12      0x0800  Hit 13      0x1000  Punch 14      0x2000  Shoot 15      0x4000  Shout16      0x8000  Unknown
So if GreatestElementalWeakness is >= 5, its > 4, which would be Earth....as well as Fire, Ice, and Lightning...So maybe what this is supposed to do is something along the lines of:
"If [Fire/Ice/Lightning/Earth] Magic is effective, use magic. Else attack physically."
So maybe I can try something similar with Rude's AI? I'll make some changes and post the results...
 
Last edited:
The 8 happens to be the element in question. You can use this to find the greatest elemental weakness of each enemy.
 
I see... but if the 8 is supposed to represent the Earth element bit... what's the point of this statement:
Code: [Select]
Code:
TargetMask <-  (TargetMask.GreatestElementalDamage >= 5) If (TargetMask){ Debug.Print: "RESIST EARTH MONSTER" ; 0 LocalVar:0040 <- 1}
Does the EDEF opcode tell the game to load elemental data into memory? Because as far as I can tell, it doesn't put anything onto the stack, and if that is the case, I don't know why it would be necessary to specify an element.

EDIT: The theory in my previous post was a bust. I'm clueless regarding how to use these variables... I have confirmed, however, that for party members, AbsorbElements and NullElements are always zero even after calling Edef
DOUBLE-EDIT: I think I've got it! GreatestElementalDamage in conjunction with EDEF gives the Elemental Effect of that element on that character in this order:
Code: [Select]
Code:
x00 = no effect (x1 damage)x01 = "never miss"x02 = "Death" damage (like flash)x03 = x2 damagex04 = 1/2 damagex05 = nullify damage (0)x06 = absorb damagex07 = "Recovery" damage (like Great Gospel)
so in sephy's example, by checking if TargetMask.GreatestElementalDamage (the name should be changed if this is right) >= 5 after EDEF(AllActiveOpponentMask, 8 ), you're checking if earth (x08) is nullified or worse by an enemy in [AllActiveOpponentMask].
 
Last edited:
DOUBLE-EDIT: I think I've got it! GreatestElementalDamage in conjunction with EDEF gives the Elemental Effect of that element on that character in this order:
Code: [Select]
Code:
x00 = no effect (x1 damage)x01 = "never miss"x02 = "Death" damage (like flash)x03 = x2 damagex04 = 1/2 damagex05 = nullify damage (0)x06 = absorb damagex07 = "Recovery" damage (like Great Gospel)
so in sephy's example, by checking if TargetMask.GreatestElementalDamage (the name should be changed if this is right) >= 5 after EDEF(AllActiveOpponentMask, 8 ), you're checking if earth (x08) is nullified or worse by an enemy in [AllActiveOpponentMask].
Yes, but Flash just attempts to deal the death status effect and Great Gospel heals 100%. They don't use these elemental modifiers this way.
You can do the EDEF(AllActiveOpponentMask, 8); TargetMask.GreatestElementaDamage < 4; to see if they're vulnerable to earth. I believe that it also populates the TargetMask as well. But it does retrieve all targets' elemental modifiers for that element and stores it in that target's GreatestElementalDamage.
 
.....i want to understand wtf you guys are talking about so badly....

i wish i could understand programming like that but it looks so difficult...

i didnt even bother reading past the 3rd page of this c script manual becuase i was so baffled at the complexity  :oops: and :cry:
 
.....i want to understand wtf you guys are talking about so badly....

i wish i could understand programming like that but it looks so difficult...

i didnt even bother reading past the 3rd page of this c script manual becuase i was so baffled at the complexity  :oops: and :cry:
Haha. If it's any consolation, I wish I knew how the hell to create, texture or import models.

Or how to use meteor for that matter  :-D

Okay I just read the wiki, and I had the hex values wrong... The way it actually is is:
Code: [Select]
Code:
x00 - Deathx01 - Never miss (?, this wasn't in the wiki but it's in Hojo, go figure)x02 - Double Damagex03 - Normal, apparentlyx04 - Half Damagex05 - Nullify Damagex06 - Absorb 100%x07 - Full CurexFF - Nothing
So the reason mine isn't working is because FF > 4, apparently, so I have to put in a check for that... [sigh] :roll: Time to input the code for the 100th time and see if it works...
EDIT: just added a check for FF and rude just attacks physically still...
 
Last edited:
0 - death, 2 - 200%damage, 3 - normal, 4 - 50%damage, 5 - 0%damage, 6 - 100%absorb, 7 - fully recover
 
It works if i use these values....
Code: [Select]
Code:
none = nothing, there's literally no value for when there isn't a modifier...check for this case by checking for NOT(the other three)half = x0400null = x0500absorb = x0600
since those are the only elemental attributes available to the player. Don't ask me why though. That's just the way it is. [updates Rude's AI]

IMPORTANT EDIT
: This ended up being a stupid mistake on my part. I was calling GreatestElementalDamage as a word, whereas it's actually a byte, and that was causing my numbers to be left shifted twice. Problem solved, and I'll be more careful about my typecasting.
 
Last edited:
Status
Not open for further replies.
Back
Top