Author
Topic: How to change the AI in Proud Clod (Read 7837 times)

Hi guys, I'm new here! I'm french and I'm making a Hard Mod for the french version. I'm using Proud Clod, an excellent tool, but I have a problem: change the IA. I want to know if there is a simple tuto somewhere for doing this.

Thanks and sorry for my bad english!

Edit: sorry this topic is unused, I have post my request in the right topic... if you want to delete it...

[Note: the abbreviation for IA is AI in English, which I start using later on in this post]

I saw the post on the Proud Clod thread recommending that this original thread be used so here we go:

First of all, you need this. It contains a list of the codes that the IA uses to determine things like target, which attack to use, and other things: http://www.mediafire.com/view/umiqacyau66u9c9/opcode_list.txtI don't know who put that list together, just that I got it from Bosola when he linked Karifean to it on an older thread that I can't find. Keep this document pinned to your Notepad, desktop, etc. It's invaluable when you're getting into IA editing.

The best thing to do is start small and get to grips with the basics of AI editing first and understand what the numbers mean. Kalm Fangs are a good place to start, as they have a very simple AI which consists of only two attacks, one of which has a lower chance of being used than the other.

So this Kalm Fang's Main AI. I've written a basic translation of what each set of numbers mean.

122070 - Target Mask0220A0 - All Opponent Mask82 - Random bit (it will select a random single target from the All Opponent mask; if deleted, the target will be All Opponents)90 - Closes the Target AI part (that's my understanding of it)

[The next part is for selecting an attack for the Kalm Fang to use]

81 - Random MOD (this is for determining the chance of the first attack listed being used)6003 (this is the number of probability. So 1/3)3452700019 - (Relates to the If/Else string)6020 - (This appears before most attacks are listed)610172 - (The attack ID for Bodyblow)92 - (Closes the attack part, like the 90 did for the targeting)72001F (part of the If/Else string, if the Random MOD check misses then it'll use the following attack instead)6020 - (same as before)610189 - (The second attack ID, Fang)92 - (closes the attack part)

So let's do a basic exercise. Let's say you want the Kalm Fang to attack itself. You'd open the IA screen for the scene with the Kalm Fang in it and select it's Main AI (it'll have a star next to it, that means there's code inside it; the rest will be blank as the Kalm Fang doesn't have any other special AI). When you've got the numbers for Kalm Fang's Main AI showing, click on Disassemble. This will translate the code and make it much easier to work with.

So if we want Kalm Fang to attack itself, we need to change it's target AI. If you open your OPcode list and look for 20A0, it'll show you that this is the code for All Opponent Mask. A few entries up from this is another code, 2060, which is called 'Self'. If you change 20A0 in Kalm Fang's AI to 2060, he'll target himself with his attacks instead of a random opponent. To do this, click on the cell that contains the code 20A0 in Kalm Fang's AI and then type 2060. Press the down or up arrow key after doing this to move away from the edited cell (if you hit enter, you'll create a new blank line by accident).

Click 'disassemble' again and it should now read 'Target Mask <- Random Bit (Self)'. The Random Bit is now no longer needed, so we can delete this. Click on the cell containing '82' which should be directly below the code you just edited. Press the 'delete' key (backspace doesn't seem to work) and the line containing 82 will disappear. Click on disassemble again and the line will now read 'Target Mask <- Self'. When finished, click 'Done' to have the editor remember your changes. Then save your scene.bin by clicking 'file' and then 'create scene.bin'.

If you make a mistake, however, then you can click Cancel to revert the AI back to what it was. If you get an error message for whatever reason, then click Continue and then click cancel before trying again.

Next thing we need to go over is copy-pasting AI. This is very useful for quickly constructing new enemies or changing the way in which old enemies behave. If you look at Jenova LIFE's AI, you'll see that she has a Magic Counter. This counter is quite simple: whenever Jenova is hit with magic, the AI will check for two conditions. The first condition checks if Jenova does not have the Reflect Status. The second condition checks if she has enough MP to cast Reflect. If both conditions are met, she will cast the Reflect spell on herself.

You can copy-paste this AI into any other enemy. You could also use it as a Physical Counter or even as Main AI. What you'd then do is edit it so that it triggers different attacks/spells under different conditions. So let's do another exercise and give Materia Keeper a Physical Counter based on Jenova LIFE's magic counter.

First thing to do is open Jenova LIFE's AI and select Magic Counter. Click Copy, and a screen will appear asking you for how much of the AI you want to Copy to the Clipboard. By default, it'll be all of it so click OK. Now go to Materia Keeper's AI. You'll notice that his Physical and Magical Counter AI is empty. Select Physical Counter and then click Paste. This will insert the Copied Jenova LIFE Magic Counter AI. Click Done and go back into Keeper's AI. You'll notice that the Physical Counter you just copied in has vanished. There's a trick to preventing this that I have. Copy the Counter AI back in again. Then select one of the cells, preferably one that's on its own. The '80' in the third row should do. Click on it and then re-type the number 80. This leaves the AI unchanged but now Proud Clod will record the pasted AI when you click Done. So click Done and then go back in, your new Physical Counter AI should be there this time.

So now we need to adjust this new Counter AI. There is no Reflect stored in the Materia Keeper scene so the game will try to reference a move that doesn't exist if this AI is triggered as it is now. Let's first change the attack/spell that this Counter uses to Cure2. If you check the Attack ID of Cure2 in Keeper's Scene, you'll see that it's 0001. Go back into the AI and you'll find that Reflect is just listed as 11 and that there's not enough space to enter 0001. This is because spells that can be used by the player, use 2-digit codes instead of the 4-digit codes you've been working with so far. That means Cure2 is actually just 01 instead of 0001. So replace the two instances of 11 with 01; this will replace Reflect with Cure2.

But now we've got this condition at the top, where the Counter will only be used if Keeper does NOT have the Reflect status. This is actually quite useful as you don't want him accidentally reflecting his Cure2 to the player. But we're going to change it anyway. If you look at the AI, you'll see that it starts with this:

This translates (roughly) as 'If Materia Keeper does not have the Reflect Status, and he has enough MP, then cast Cure2 on himself'.

'0' in this case means 'doesn't have', but if we change this to '1' then it becomes:'If Materia Keeper DOES have the Reflect Status, and enough MP, then cast Cure2 on himself'.

But we're going to change things to make this counter attack trigger only if Materia Keeper has been poisoned. So open up the OPcode list and look for 4012. It's listed as relating to the Reflect status. According to this list, we can change Reflect to Poison instead by changing 4012 to 4003. Click the cell containing the 4012 in Keeper's new Counter AI and enter 4003, like you did with the Kalm Fang AI. We also want this to trigger only when Keeper has been poisoned so change the '60 00' below it to '60 01'.

Now he will only use this Counter when he has been:A) Hit by a Physical AttackB) Has been PoisonedC) Has enough MP to cast Cure2

This was a basic example of how to change and adapt old AI. You could turn this Counter into something more aggressive by replacing Cure 2 with Trine and then changing the Target Mask so that it's used against All Opponents instead (swapping 2060 with 20A0).

Once you've got the basics down, you can start to do a lot more with the game's enemies. Before editing AI, though, read up about the enemy first so that you can make better sense of what the code means. For Safer, remember that he has a set pattern of attacks, some of which don't actually do any damage but are used to handle his change in altitude (when he flies up high and prepares to use Supernova for instance, or when he first descends as the fight starts). His death is also an 'attack' which he uses, in his Death Counter AI, to trigger the effect where he explodes and evaporates.

90 - Closes the Target AI part (that's my understanding of it)92 - (Closes the attack part, like the 90 did for the targeting)92 - (closes the attack part)

Please, please, PLEASE do not make a tutorial containing guesses like this. Either look up what it does based on the wiki or don't post. This is wildly the wrong way to think about it and will only confuse people trying to "learn" from this.

90 is the STOR command. It takes the top value on the stack and stores it at the next value on the stack.92 is the "Perform Action" command. It tells the battle engine to use the targeting data and the top two values on the stack to queue an action from the script's owner.

I'm not going to go through the entire post because it got larger after I clicked "quote", but I'm not going to endorse your response because this alone is misleading.

For Safer, I want to change the rule of his HPs and power. In the game, he's more powerfull when characters are lvl 99. I want him to be powerfull even if the characters are not lvl 99. I know this is in the Pre battle AI but I don't really know how to do that.

I want to explain why I wrote it the way I did, NFITC1. From my own experience, the Wiki is quite heavy on technical terms which can be tough to follow for folk like me who don't have a background in programming, and the AI is really daunting at first because it's essentially a wall of numbers. The disassembler helps, but it still takes time to figure out what's doing what.

So what I was trying to do was help Mexico perform some basic AI editing without getting too technical, so that he could maybe use that as a foundation for learning the more advanced mechanics behind AI. Gotta start slow, see?

Mexico, what you could do is delete the AI that changes his stats depending on the party, then you could set his stats normally like with other enemies. You have to be careful though, because parts of that pre-battle AI are needed for the fight to function properly. I'll have a go at editing it and pass the AI code along to you if it works.

I want to explain why I wrote it the way I did, NFITC1. From my own experience, the Wiki is quite heavy on technical terms which can be tough to follow for folk like me who don't have a background in programming

The thing is, AI scripting is programming, it must demand some grasp of technical concepts; asking for a "programming tutorial for non-programmers" is like asking for a photography course for the blind. You can't really hide the details and the caveats of it, because as soon as your reader tries to riff from your tutorial's procedure, they're going to run into trouble. Tutorials should be springboards, not recipes, so we have to equip readers to start understanding the foundations of what we're doing - not choose ambiguous analogies just for the sake of simplicity. That's why your definition of '92: closes the attack part' is problematic, because it's going to cause someone trouble as soon as they want to go beyond a basic script and choose from multiple attacks.

OP : Proud Clod's help files contain a solid, if slightly sparse, introduction to FFVII AI scripting. It's a good resource; I would begin there. It will take a little time to get up to speed, but once you've grasped AI editing, you'll have a lot of power at your disposal. Good luck.

That's fair enough. Sorry for causing any headaches, my choice of words on describing some of the things wasn't great. But I do think having some examples to work through can be helpful for getting some context to how the AI works, and it's always handy for getting some familiarity with the tools you're using.

Mexico, about Safer's AI; there's two ways to make his stats not depend on the player's party. First way is to delete the cells that alter his stats but leaving the other cells alone. Specifically what you want to leave alone are the Self.Flag that makes him Death Immune at the start and the Target/Attacks that are used at the end. Then you could set his stats normally like with other enemies.

This is what his pre-battle AI looks like without the stat-altering variables and equations:

12206010402C8060019012207002206090602061036892602061014F9273Alternatively, you could try changing some of the code so that it puts in a static number instead. If you look at the cells from 0x0B1 to 0x0BB, the '03 0000' refers to the Variable:0000, which carries a value that the AI pushes into Safer's Attack stat. If you changed that 03 0000 to a static number, say 61 0100 (it's a hex number which would translate to 256), then 256 will be pushed into Safer's attack stat instead (a higher number can be used). Same applies for the other stats relating to Defence, Magic, and Magic Defence.

Max HP using this method would be very similar. In the chunk of cells from 0x05D to 0x06B, if you change the 03 cells to 62 and input the Hex numbers 013880 (80,000) and 04E200 (320,000) then Safer's Max HP would be set to 400,000 every time you fight him. But there's a set of cells below this that determines his current HP by pushing his MaxHP into it and then subtracting the value of another variable*100. If you change the '03 0040' here to '60 00' (so that the equation uses 0 instead) then that'll prevent any changes being made to the 400kHP; or you could delete these cells and leave that line as Self.HP <- Self.MaxHP.

Yeah, you see that line where it says '03 0000' at 0x0B8? That's the 'Variable: 0000' that you want to change into a static number (click on Disassemble to translate the code on the right there). You're changing that '03 0000' line to '61 0100' which would make Safer have 256 Attack.

The number you want to put into the stat needs to be translated into Hex though, so if you wanted Safer to have 300 Attack instead of 256 Attack then type this into Google: '300 in hex'. That'll give you the hex value (012C) which you'd enter as '61 012C' instead of '61 0100'. That would set Safer's Attack stat to 300 instead.

You can edit the other primary stats in this way; the disassemble option will show you where they are in the AI:0x0CE - 0x0D8 = Physical Defence

0x0EB - 0x0F5 = Magic

0x108 - 0x112 = Magic Defence

Change the line that says '03 0000' in each of these groups of cells to the 61 code. Everything else should be left untouched. Make a back-up copy of your scene.bin file before you make changes, and remember to click 'Done' when you're finished. Also remember to go to File and click 'create scene.bin' to save your changes.

I haven't tested this but it should hopefully work unless I've overlooked something.

For Jenova's arms it's the same as setting Safer's stats. They're located in the pre-battle AI, right at the bottom. You need to set their MaxHP and their Current HP (so basically entering the same HP value twice).

The first tentacle's MaxHP (written as MHP in the disassembler) and CurrentHP is in cells 0x380 and 0x38B. Note that these cells start with 61. If we change this 61 to a 62, then the cell can take a 6-digit Hex number instead of a 4-digit one. If you want the tentacles to have more than 100,000HP then you'll need to change the 61 to a 62.

The second tentacle's MaxHP and CurrentHP will slightly change position if you convert the first tentacle's HP cells into a 62. So to find the second tentacle's HP cells, check the Disassembler and find out which cell that the line 'Self.MHP <- 8000' starts from. You're looking for the cell in this block that start with a 61. Do the same with the line 'Self.HP <- 8000' as well. That's the 'safe' part done, so you'll want to save your progress here.

Jenova Syn's Countdown is handled by the 00E0 variable. When she goes below 15,000HP, the General Counter pushes the value '5' into this variable. In her Main AI, at the top, you'll see the line 'If (LocalVar: 00E0 < 6); as 00E0 is now below 6, this top part of the AI triggers instead of the bottom part (where she attacks normally).

If you follow this down, you'll see that this trigger deducts 1 from variable 00E0 on each turn and as the variable 00E0 equals 4, 3, 2, etc. it displays a 'string' which is an in-battle text box telling the player that the Countdown is progressing. When the variable/Countdown reaches 0, Ultima is cast and a bunch of special variables are triggered that affect the last two boss fights.

Having this Countdown trigger at the beginning of the fight rather than the end can be problematic but it's not impossible. You'll want to delete (most) of the code starting from 0x029 to 0x0D1. If you start on 0x029 and hit Delete it'll move the remaining cells up to fill the gap; hit Delete until you see the two cells starting with 72. The code should like like this afterwards:

12 207002 20A0 (target for Ultima)9060 2060 34 (Ultima)9272 007272 0034This will stop Jenova from killing herself after casting Ultima. With that done, we now need to get Jenova away from her Ultima AI. Insert these lines after the 92 in the above example:

11 00E060 0690

This will set the 00E0 variable to 6, and have her skip the Ultima Countdown AI from now on. Now, you have two options. You can leave the General Counter alone, which means she'll use Countdown again when her HP falls below 15,000 (unless this number is changed). Or you can delete the General Counter completely so that she only uses Countdown at the start of the fight.

As far as the global variables go, these handle special stat adjustments for the last two bosses and determine which variation of Bizarro you get (one party, two parties, etc). Jenova's Death Counter AI should handle it all without incident, hopefully.

Regardless of what they should do, keep an eye on them. It doesn't always work when there are display strings involved.

Yes, you were right NFITC1.

That works, I have done what you said and I have delete the General counter but there's a problem: the battle against Bizarro begins with only one party, maybe got to change something in the Death counter?

And I have another request (it will be the last, I don't want to bore you...): in the Gelnika, Rude, after he casts Shoulder attack, he does nothing anymore, any idea of what I've got to do to change that?

I think you get a one-party fight if Jenova Synthesis gets more than 13 turns before using Countdown and if the average party level is lower than 54. But it's probably the 13 turns thing that's triggered it. In the death counter AI, it looks like this bit determines how many parties fight Bizarro:

The bit there at 0x089 & 0x08F matches up with the conditions for a 1 party fight (and sets that global variable there to 1). Var 00C0 must be for the number of turns (if greater than 13) and Var 0060 must be for the party's average level (If below 54). I think the last one might be if Var 0100 is set to 1 or higher by a character's individual level exceeding 34.

So I reckon setting all the numbers that're pushed into the GlobalAddress here to 3 will trigger a three-party fight regardless of what happens. That said, there's other places where that GlobalAddress has a value pushed into it (could maybe change these to 3 as well but I'm not confident because there's a line where 0 is pushed into it for some reason) so I can't say 100% that this will work without testing it a few times first; I've not worked with the Global things before. Make sure to create a back-up of your scene.bin before making changes just in case it doesn't go right.

Rude's AI for the Gelnika is busted to hell. He locks when he uses a spell; I think it's caused by the '1' being pushed into Var 0060 (which happens whenever he uses a spell); all of his Main AI requires Var 0060 = 0 to trigger so he goes into a loop of nothing. You can fix it by changing the 1 to a 0 in the four instances of Var 0060 <- 1 that appear.