Author Topic: FF9 Trouble for editing ennemie's AI  (Read 1608 times)

Nesouk

  • Fast newbie
  • *
  • Posts: 8
  • Karma: 0
    • View Profile
FF9 Trouble for editing ennemie's AI
« on: 2017-01-09 18:29:46 »
So this is my first post here, so I'm truly sorry if this might be out of the place and also I'm french so I'm sorry if my english isn't very good.

So I'm currently attempting at creating a mod for the PSX version of FFIX (as I don't have access to the steam version for now). I'm using Tirlititi's Hades Workshop general editor, the tool is awesome and for the most part easy to use, I pretty much found everything I've need for and manage to do some interesting things. However I'm kind of struggling with editing ennemies AI, I'm really new to this, thing is I can't figure out how to start, I've looked on internet but can't found something good for starting, I attempted to make some modification but failed for now. 

So I'm asking if someone could provide some help for a good start to understand and edit AI's script ?

Tirlititi

  • Insane poster
  • *
  • Posts: 423
  • Karma: 55
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #1 on: 2017-01-09 21:08:34 »
Great to see you want to do some mod on your own :)

1st thing : there's a file "LocalVariableSettings_v1.hws" along with the program. Import it so the names of the variables make a bit more sense.
It'll easier to help if you have a specific request. I would then be able to connect it with the general AI system.

Also, looking at those few AI that I commented may help. Lani's might be the closest to the usual AI systems, minus the targeting system which tends to focus only one target. Kraken's AI is highly related to how the tentacles are connected with the main body, Necron's AI is very simple (he loops the pattern Blue Shockwave x3 + Grand Cross + Neutron Ring) but he has 3 assistants to cast spells for him, and Ozma's AI has a few interesting features.
Kraken's AI
Necron's AI
Ozma's AI
Lani's AI

Nesouk

  • Fast newbie
  • *
  • Posts: 8
  • Karma: 0
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #2 on: 2017-01-10 10:40:17 »
Thanks I think this will help indeed.
Fort now I want tout try making simple stuff, like for exemple during the duel between Zidane and Baku, I would like to make Baku use a buff on himself when he's low on HP (like 20-25%), so how can I do that ?

Tirlititi

  • Insane poster
  • *
  • Posts: 423
  • Karma: 55
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #3 on: 2017-01-10 13:37:02 »
You have two options for that :
1) Either you make it a counter. This way, Baku won't waste his turn and will also attack after buffing himself. It's also the safest way to make sure that Baku buffs himself as soon as he gets under 20-25% of max HP.
2) Either you make it a regular move that he'll use instead of a regular attack. If you do it this way, Baku might be tricked by the player to delay his buffing: if the player inputs his attack right before Baku's ATB gets full, he will receive damage after his ATB got full and thus after selecting his move. So he will attack once more (and not buffing himself) even though he's under 20-25% HP. That's kind of a subtility but it's used in speedrun, for instance, to avoid Beatrix 3 healing herself.

For the option 1), you'll do a "Baku_Counter" function.
For the option 2), you'll modify "Baku_ATB" function.

I'll develop the option 1).
- Right click on the function list and chose to add a function for the Baku's entry and of type 6 (counter).
- You want Baku to use his move only when he's under 20-25% HP. Normally, you'd write it like this :
Code: [Select]
if (FirstOf(SV_FunctionEnemy[HP]) < (FirstOf(SV_FunctionEnemy[MAX_HP])/4)) {
    set SV_Target = SV_FunctionEnemy
    Attack( 5 ) // or whichever attack ID your buff is
}
return
However, like a lot of bosses, Baku's HP in game are not his real HP. He has 10000 more HP than normally and ends the battle automatically as soon as he gets under 10000.
So the condition is more like this :
Code: [Select]
if ((FirstOf(SV_FunctionEnemy[HP]) - 10000) < ((FirstOf(SV_FunctionEnemy[MAX_HP]) - 10000) / 4))Now, there's one more choice for you : as it is, Baku will buff himself every turn as long as he is under 25% HP. You may want him to buff himself only once it the whole fight (in which case, you'll need a local variable serving as a flag) or only if his buff has expired (in which case, you don't need a local variable).

The latter case is done with this kind of condition :
Code: [Select]
if (!(Matching(SV_FunctionEnemy[STATUS_CURRENT_A], 8388608L) )) {
// Perform the buffing
}
8388608L is the status ID of Protect. So this condition is fulfilled if Baku doesn't have Protect.
To easily get the good ID associated with a status, look at the "Status List A/B" informations on the bottom left of the script window. You can write a status name there and press Enter : it will write the corresponding ID in the code.

The former case (Baku buffs himself only once), you need to declare a local variable in the local variable panel. By default, Baku's script use 34 bytes for local variables (hence the "allocate 34" line you see). Declare your own with these lines :
Code: [Select]
allocate 35
local uint8 flag_for_baku_buff VAR_B7_34
One of the advantages of importing the file "LocalVariableSettings_v1.hws" is that all the other local variables are already declared and given a name. In that situation, you can ignore the last word and write only "local uint8 flag_for_baku_buff" to declare a local variable. The tool will automatically give it an unused ID ("VAR_B7_34" in this case).
Now, the whole counter function can be written like this :
Code: [Select]
if ((!flag_for_baku_buff) && (FirstOf(SV_FunctionEnemy[HP]) - 10000) < ((FirstOf(SV_FunctionEnemy[MAX_HP]) - 10000) / 4)) {
    set SV_Target = SV_FunctionEnemy
    Attack( 5 ) // or whichever attack ID your buff is
    set flag_for_baku_buff = 1
}
return

If you go for the option 1), you basically have to do this in the ATB function instead, either at the very beginning, either at the end before the "Attack" line.
Code: [Select]
if ( Your Condition ) {
    set SV_Target = SV_FunctionEnemy
    Attack( 5 ) // or whichever attack ID your buff is
    return
}
// ... the rest of the function

I hope that you (and other people) will have a better grasp on the AI system after that :)
I would like to make tutorials for that kind of stuff someday.

Nesouk

  • Fast newbie
  • *
  • Posts: 8
  • Karma: 0
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #4 on: 2017-01-10 18:24:04 »
OK I've tried out making a counter it works fine.
However I have a little problem, turns out Baku's attacks list has no empty space so I had to replace one of his former attacks by the buff I choose to replace "Aïeuh !" (French name) I manage to make the new attack works perfectly (I had to edit the animation but it works fine even if the animation is kind of funny ^^) however it is implemented in his original script so while he uses it on him when he has less than 25% just like I wanted he also still uses it on Zidane before this point.

So is there a way to expend his attack list ? If not how can I prevent him from using it outside of the Counter I made ?

Tirlititi

  • Insane poster
  • *
  • Posts: 423
  • Karma: 55
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #5 on: 2017-01-10 18:48:13 »
You can add spells to enemies by right-clicking on their spell list (copy/paste).
Alternatively, you can remove the "Aïeuh !" from the spells he uses, as you wish, by looking in his "Init" function :
- the first line tells how many different moves he uses, so turn that 4 into 3,
- the second line tells which moves he uses, so turn that 794688L (list [ 0 ; 1 ; 2 ; 3 ]) into 12352 (list [ 0 ; 1 ; 3 ; 0 ]) since "Aïeuh !" is the move 2.
- Also, in the "ATB" function, there are 8 lines like "set #( SV_Target = Something )". The first 4 are the targets of the moves and the last 4 are unused (they are used when there are more moves). There, you don't need to change anything, but in similar AI, you'd have needed to change them accordingly to the new list in the function "Init".

I don't know if Baku has a channeling animation though.

Nesouk

  • Fast newbie
  • *
  • Posts: 8
  • Karma: 0
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #6 on: 2017-01-10 19:56:14 »
Alright so I test out the fight after doing everything, the fight work with no problem he does exactly what he is intended to do, I choose to remove "Aïeuh", for the channeling animation Baku use the "Ohla" animation except he jumps 2 or 3 times but it doesn't cause any glitch and it's actually funny to watch and in a way fits him in my opinion ^^.

Tirlititi

  • Insane poster
  • *
  • Posts: 423
  • Karma: 55
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #7 on: 2017-01-10 20:18:27 »
Well done

Nesouk

  • Fast newbie
  • *
  • Posts: 8
  • Karma: 0
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #8 on: 2017-01-11 05:14:36 »
OK si I have 2 questions :

For Plant Brain (I think that's his english name the evil's forest boss, I want him to use a particular attack every 5 turns, I looked up Necron AI I think the fonction that make him us Grand Cross after he did 3 attacks would do the job Am I correct ?

Also for Black Waltz 1 ans Sealion I would like to make Black Watz cast Might on Sealion before he dies I guess I would have to make a similar function to the one fort Baku's buff but changing the condition and targeting right ?

Tirlititi

  • Insane poster
  • *
  • Posts: 423
  • Karma: 55
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #9 on: 2017-01-11 07:50:55 »
Exactly.

For the Black Waltz + Sealion fight, the function names are swapped. I think it's only the case for Kuja's disc 3 fight (where Kuja and Trance Kuja are swapped in the script). The function "Sealion_Init" should be called "Black_Waltz_1_Init" and vice-versa for instance.

You have also the global variables "blackwaltz" and "sealion" in this particular fight, so you can use "FirstOf(sealion[HP])" for your checks.
In other fights, either you'd have to declare and setup a global for the enemies like they do here (or in the Necron's AI), either you can use the raw identifiers of the enemies :
FirstOf(16[HP]) for the 1st enemy
FirstOf(32[HP]) for the 2nd enemy
FirstOf(64[HP]) for the 3rd enemy
FirstOf(128[HP]) for the 4th enemy

Nesouk

  • Fast newbie
  • *
  • Posts: 8
  • Karma: 0
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #10 on: 2017-01-11 16:19:17 »
Alright so I try for Plant Brain I use this in this AI :

Code: [Select]
if ( turncounter >= 5 ) {
        set #( SV_Target = SV_PlayerTeam )
        set turncounter = 0
        set selectedattack = 2
    }

From what I've understand his AI is a big function for selecting the attack he will use, I let the rest untouch, I test it and the fight works as intended he effectivly use Pollen every 5 turns, now I will try for Black Waltz and Sealion but I think I'm starting to understand better how it works.
« Last Edit: 2017-01-21 14:35:19 by Nesouk »

Nesouk

  • Fast newbie
  • *
  • Posts: 8
  • Karma: 0
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #11 on: 2017-01-21 14:50:46 »
(sorry for the double post)

So I try for Black Waltz and Sealion honnestly I've a lot of trouble with editing this fight I had some problems I manage to found the solution but now I don't know what's going, here's the modification I've done : I've add 2 new attacks in their attack list and in their AI I only put this on blackwaltz's AI (named Sealion for the function if I've understand) :

Code: [Select]
Function Sealion_Counter
    if ( FirstOf(sealion[HP]) = 0 ) {
        set SV_Target = blackwaltz
        Attack( 11 )
    }

Creating a Counter function
And for Sealion's AI I add this in his counter function :

Code: [Select]
    case +2:
        if ( FirstOf(blackwaltz[HP]) = 0 ) {
            set SV_Target = SV_PlayerTeam
            Attack( 12 )

The rest of their script is untouch
When I start the fight the beginning is normal Blackwaltz summon Sealion then Sealion acts perfectly fine but as soon as it's Blackwaltz's turn the game just freeze and I can't figure out why.

Tirlititi

  • Insane poster
  • *
  • Posts: 423
  • Karma: 55
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #12 on: 2017-01-21 16:50:06 »
Don't forget to write a "return" line in your counter function. I'll make so it throws a warning if you forget.
Other than that, it seems all right. The case +2 at the end of Sealion's counter function connects only if his HP is more than 2/3 of his HP max (his gem is blue).

Nesouk

  • Fast newbie
  • *
  • Posts: 8
  • Karma: 0
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #13 on: 2017-01-22 06:16:58 »
Yeah totally forgot the return.

Other than that the function where not working I assuming the game disable the other functions when the ennemy die, however for Black Waltz 1 he already has a Death Function for his dialog so I test out to add an attack with this function and it works fine he effectively do an action just before dying, so I try to create a similar Death function for Sealion and..... it didn't work so I assume we can't create death function that works but we can modify a already exist death function or maybe this is specific to black waltz 1 so for Sealion I had to change my plan.

So after all this trouble I test the fight and it finally works well and I didn't edit their stats yet... well thanks god I didn't edit their stat cause Holy strawberries didn't expect to reach this difficulty basically the fight as it is now for me (at LV8 without editing Zidane's stats) start with the same difficulty as Vanilla but ends up being even harder than Unleashed, must say I'm quite happy with the result if I had to make anymore changes it would just be buffing Black Waltz's attacks a little for the beginning of the fight.
« Last Edit: 2017-01-22 06:21:34 by Nesouk »

Tirlititi

  • Insane poster
  • *
  • Posts: 423
  • Karma: 55
    • View Profile
Re: FF9 Trouble for editing ennemie's AI
« Reply #14 on: 2017-01-22 11:22:42 »
Yeah, adding a "Death" function never worked for me as well. I have yet to figure out why.