Qhimm.com Forums

Miscellaneous Forums => Scripting and Reverse Engineering => Topic started by: Armorvil on 2011-05-16 23:29:18

Title: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-16 23:29:18
I gave the Poison status the "Disease" effect from FFXII. In other words, when under Poison, the character's MaxHP becomes the character's CurrentHP. The consequence is, you can't restore HP to a character under Poison, anymore.

To do this, I added this script to the characters' General Counter AI scripts :

Code: [Select]
02 2060
00 4003
80
70 001B
12 2060
13 4180
80
02 2060
03 4160
80
90

It's working great, except that when Poison is finally cured, the character's maxHP doesn't return to normal. It won't continue decreasing as the character's currentHP decreases, but it won't be his original max either (until the battle is over, of course). Here is an example :

Cloud has full (2500) HP. A Bio spell is sent his way, hits him for 800 damage and poisons him. Cloud's HP is now 1700. Poison damage triggers (70), and HP is now at 1630. Tifa uses Cure2 on him. Useless : his HP stays at 1630. Cid uses an Antidote and Cloud is cured. Enemy attacks Cloud and deals 200 damage. Cloud has now 1430 HP. Tifa uses Cure2 on Cloud. Efficiency is +1500 HP, but Cloud's HP only increases to 1630 (the last maxHP the AI registered).

How can I make it, so that Tifa's final Cure2 brings him back to 2500 HP ? (there is also a disturbing little side-effect : when Poisoned, Cloud's HP increases or decreases as soon as someone or something decides to alter it - not after the attack/healing ocurred... ...but it's not so big a problem and I don't think there's a fix)
Title: Re: Turned Poison into Disease through AI, but...
Post by: nfitc1 on 2011-05-17 01:12:43
You need to store the initial MHP from the moment of infection (don't assume I counted correctly for those jumps to work).

Code: [Select]
02  2060
00  4003
80
70  0033
02  00E0   <--or whatever
60  00
44
70  001E
12  00E0
02  2060
02  4180  <-- for player characters, word values are fine.
80
90
12  2060
12  4180
80
02  2060
02  4160
80
90

Then when you get to the part where you heal, set the MHP back to the value you stored and set that stored value 0 so it'll work again.

This is what I'm going for if that's too hard to read:

Code: [Select]
If ( Self.Poisoned )
{
   If ( !(Local_Var:00E0 > 0 ) )
   {
      Local_Var:00E0 <- Self.MHP
   }
   Self.MHP <- Self.HP
}

And yes, because you have this on the general counter it'll only take effect after someone performs some action on Cloud. You could put it on the Pre-Attack script and probably get the effect you want by virtue of fuzzy logic.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-17 08:43:46
What would I do without you ?
Thanks again, I'll try that :D
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-05-17 14:05:37
Ah, so someone's finally done this! I'd been planning to do something similar at some point, except I intended to use the Null.Health property and tie it to the poison status, eg:

counter.pre-turn {
null.health status = poison status
}

I don't know how that would interact with armours / equipment that block / guard against heal naturally though.

There's a few other things you could do with AI scripts to make poison more dangerous, too. For instance, you could use my method to make poision cause a 'zombie' status (where the character takes damage from healing), or use NFITC1's method but swap out player level rather than MaxHP (so the character becomes weaker).

Oh, and you don't need to place a script like this on every character and enemy. I would explain how, but I'm a bit pressed for time. Basically, you can write a single pre-turn script that says 'give EVERYONE the same {attribute} as their {attribute}, then use script-link to have other characters use the same script (though I haven't really tested script links...)
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-17 22:01:54
Urgh. I'm still learning, and it looks like I still have problems with AI scripting -__-

I spent a lot of time trying to pull this off, tonight. Here is your script translated in words I understand more easily (= no POP, PUSH, MASK or STACK for me :P) :

Code: [Select]
02 2060 -> Load value of Target=Self
00 4003 -> Load value of Status=Poison
80 -> Combine the two above (Self+Poison)
70 002D -> If the above is not true, Jump to the address 0x02D. If true, continue with script:

02 00E0 -> Load value of {VAR E0}
60 00 -> Call for value : 00
44 -> Greater than (meaning of those 3 lines : if value of {VAR E0} is greater than 0)
70 001E -> If the above is not true, Jump to 0x01E. If true ({VAR E0}>0), continue with script :

12 00E0 -> Load address of {VAR E0}
02 2060 -> Target = self
02 4180 -> MaxHP
80 -> Combine the two above (Self+MaxHP)
90 -> Put value (Self+MaxHP) into address of {VAR E0}
12 2060 -> Load address of Target=Self
12 4180 -> Load address of MaxHP
80 -> Combine the two above (Self+MaxHP)
02 2060 -> Load value of Target=Self
02 4160 -> Load value of HP
80 -> Combine the two above (Self+HP)
90 -> Put value (Self+HP) into address (Self+MaxHP)

As you said this isn't complete, since when Poison is cleared, the value we saved into {VAR E0} needs to be inserted back into the address of (Self+MaxHP). This is the easy part. But what I don't get is why do we need to set the value of {VAR E0} to zero when Poison is cured (at the first jump address ?), since MaxHP will only drop again (when Cloud gets Poisoned again) if {VAR E0} is greater than zero...

I understand the logic, but here is my problem : in the beginning of your script, we need the value of {VAR E0} to be greater than 0, but we didn't set it to anything beforehand. Do all variables like this one have an initial value of 1 or something ?... ...It would have made more sense if variables had an initial value of zero (this is the case in FFVI, since, to make enemies talk once at the start of a battle, the script would look like this :

Code: [Select]
If {VAR E0} is 0,
Display message : "Go guys ! Ha Ha ha... ...Give up ?"
Set {VAR E0} to 1,
End if

Variables like this one always being 0 at the start of a battle, it ensures the dialog box only displays once, since we set it to 1 before the condition ends. End of the FFVI parenthesis)

Sooo, because of the fact that {VAR E0} is not 0 right from the start, I fail to see how we can use it as a condition, since the other value we will load into it is also greater than 0 (Cloud's maxHP ; ie 2500).

Anyways, since my attempts at creating a working script with the above ended up with Cloud's maxHP becoming 0 (when I set {VAR E0} to 0  :-P ) and thus killing him, I tried to use Bosola's idea instead : using NullRestorative. So I made this script (with my very-personal-and-not-very-accurate AI translation :D) :

Code: [Select]
02 2060 -> self
00 4003 -> poison
80 -> combine
70 XXXX -> if not, jump to end of script
12 2060 -> load self
10 42A9 -> load nullrestorative
80 -> combine
60 01 -> activate !
90 -> Go ! :P

LOL-worthy translation, ain't it ?  ;D
And I bet you guys already see the problem ^^;
...It works, but when Cloud is healed from Poison, the NullRestorative doesn't go away... I looked through your help files in Wall Market and brainstormed until I got a headache, but I don't see how I can make use of the "if" statement to tell the game : "don't nullify Restorative if Cloud doesn't have the Poison status anymore, you retard". God, this sure isn't easy, especially for someone like me who never followed programming lessons. How frustrating.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Vgr on 2011-05-17 22:32:55
I am pratically a n00b at AI-editing (did you remember AV? :P ) but something like this in general counter :

If Poison status = effective set var0 = 1
If Poison status = uneffective set var0 = 0
If var0 = 1 enable flag null.restorative
If var0 = 0 disable flag null.restorative
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-17 22:44:29
You have the right logic but it's not that easy to pull off, I'm afraid... And I only know how to enable something, not how to disable something.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Vgr on 2011-05-17 22:45:30
Enable a counter flag?...
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-18 08:28:07
I appreciate your interest, but shouldn't we wait for Bosola, NFITC1, or whoever who knows something about AI scripts to reply instead ?
Title: Re: Turned Poison into Disease through AI, but...
Post by: nfitc1 on 2011-05-18 12:05:44
Who's to say Vgr doesn't know anything about AI editing? I don't know who does and doesn't.

The Local_Var:00E0 thing is a little confusing. We're not testing if it's greater than 0 in the beginning, we're testing if it's NOT greater than 0.

If ( !( Local_Var:00E0 > 0 ) )

That exclamation mark means that result is NOT'ed. So we're logically testing if that value is less than or equal to 0. Notice that in the AI, if Local_Var:00E0 is greater than 0, then we're skipping assigning a value to it.

Also, you can easily set the NullRestorative with poison by setting it to the same value as your posion status.

12  2060
10  42A9
80
02  2060
00  4003
80
90

Now when Cloud is poisoned, Restorative elemental attacks do nothing. Then when Poison is lifted, so does that nulling. No fancy ifs are needed.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-05-18 12:38:37
In fact, you can basically say, 'take a word of everyone's poison status, make that everyone's nullRestore status'. Put that on all player charactesr (or maybe one character with script links) and every monster experiences the same thing too.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-18 18:55:08
Who's to say Vgr doesn't know anything about AI editing? I don't know who does and doesn't.

But something tells me Vgr is no expert in this field :

Quote from: Vgr
I am pratically a n00b at AI-editing (did you remember AV? )

:P (and yes Vrg, I do remember)

Quote
The Local_Var:00E0 thing is a little confusing. We're not testing if it's greater than 0 in the beginning, we're testing if it's NOT greater than 0.

If ( !( Local_Var:00E0 > 0 ) )

That exclamation mark means that result is NOT'ed. So we're logically testing if that value is less than or equal to 0. Notice that in the AI, if Local_Var:00E0 is greater than 0, then we're skipping assigning a value to it.

Aaahhh, now that makes sense. Thanks ! :)

Quote
Also, you can easily set the NullRestorative with poison by setting it to the same value as your posion status.

12  2060
10  42A9
80
02  2060
00  4003
80
90

Now when Cloud is poisoned, Restorative elemental attacks do nothing. Then when Poison is lifted, so does that nulling. No fancy ifs are needed.

*Brain asplodes* I'm in awe, sir. With my own vocabulary to decipher AI, this script means that you loaded the value of self+poison into the address of self+nullrestorative, huh. I find this concept hard to grasp, but I love the fact that it works ! :D Thank you very much ^^ When I understand it all, I could maybe write a "FFVII AI for the dummies" FAQ of sorts, with my own simple vocabulary (if that is even possible). ...But for now I still have to clean the gray matter that is dripping out of my right ear, and study more.

Quote from: Bosola
In fact, you can basically say, 'take a word of everyone's poison status, make that everyone's nullRestore status'. Put that on all player charactesr (or maybe one character with script links) and every monster experiences the same thing too.

This is really interesting. If I had known such a thing exists, I wouldn't have pasted the Seizure script into almost all enemies' AI scripts (because of this, my scene.bin grew to a whopping 304Ko).
Title: Re: Turned Poison into Disease through AI, but...
Post by: nfitc1 on 2011-05-18 20:12:55
*Brain asplodes* I'm in awe, sir. With my own vocabulary to decipher AI, this script means that you loaded the value of self+poison into the address of self+nullrestorative, huh. I find this concept hard to grasp, but I love the fact that it works ! :D Thank you very much ^^ When I understand it all, I could maybe write a "FFVII AI for the dummies" FAQ of sorts, with my own simple vocabulary (if that is even possible). ...But for now I still have to clean the gray matter that is dripping out of my right ear, and study more.

If your brain asploded from that, don't ask me how to write a function to toggle a bit at a variable position in a provided variable. Your whole face might meltdown. :)

Seems you grasped the concept pretty well, but this is less a FFVII AI trick than it is a general "assign a value to one thing when another is active" trick. It just so happens that we want the status of Poison and NullRestorative to be the same at all times. Since the game's engine is what assigns the Poison status and they're both just individual bits, just read that and indiscriminately dump that value into the NullRestore.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-18 20:18:41
Thanks for this explanation, NFITC1 :)

@Bosola : looking at the characters' AI script, I think I see what you mean. There is an extended  (but discarded) love function in Aeris' General Counter / Death Counter / Post Attack scripts, and in Tifa's/Barret's/Yuffie's pre-battle script, there is this code :

Code: [Select]
60 03
75
73

Which, when disassembled, translates into : "link with scripts on character : 3". Since character 3 is Aeris, I guess this means that Tifa, Barret and Yuffie share Aeris' AI scripts.

So, if I'm right and if I wanted to only enter the Null.Restore script into Cloud, all I need to do to make the other characters behave like Cloud, would be to enter this code in the other characters' Pre-Battle scripts :

Code: [Select]
60 00
75
73

I'm gonna try this ^^ (and delete all of the useless scripts regarding love points, that will save space)

EDIT:

Mmm, Vincent has a Main script to make his Limits behave correctly, it seems - so I won't be linking him to Cloud. Or is his main script really necessary for his Limits to work ?

EDIT2:

Ah yes : the
Code: [Select]
60 00
75
works perfectly ! :D Great stuff.

EDIT3:

Quote from: me
Mmm, Vincent has a Main script to make his Limits behave correctly, it seems - so I won't be linking him to Cloud. Or is his main script really necessary for his Limits to work ?

Just answered my own question through in-game testing. Vincent really needs his main script. Without it, his limit forms do nothing when his turn comes up, and the ATB gauge just resets.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-05-18 21:12:22
Yup, that's how you play with linked scripts. I don't know how it works if the original script holder dies or is kicked from battle, though.

Vincent's main script is absolutely vital. Without it, 'monster' Vincent just stands there doing nothing, discarding each turn which comes to him. His limit turns on the script whatever its contents.

That said, I don't know what would happen if you created a pre-turn script that set Vincent's Flag:MainScriptActive off. If it did anything, you'd probably just get a normal command menu, but a data error whenever Vincent attempted the animation for whatever you selected.

But that's a tangent. More on topic: You can also use AI scripts to make certain statuses (or spells / attacks, for that that matter) turn on counter scripts.

F'rinstance, you can write a general counter like

general counter {
if my berserk status == 0, skip this script
select last attacker and use attack
}

Other common status effects you can implement? You could create IX's trouble (albeit without damage display)

counter preturn {
if my trouble status == 0, skip this script
store my HP in a battle var
}

counter anything {
if my status == 1, do
    find difference between current HP and HP in battle var
    if difference < 1, skip
    divide difference by two
    make a group by taking active units and masking with enemies and self, creating a 'pal group'
    let pal HP = pal HP minus divided difference
make HP in battle var = 0
}

Another thing to melt your steaming stump of a neck, you can create your own status effects not tied to anything. It's simple.

counter anything {
if last attack took type and ID x and y (e.g. the id of your 'virus' spell)
    take a word from a battlevar I've assigned to record disease status
    turn my bit on
if last attack took type and ID a and b (e.g. the id of Esuna)
    take the battlevar word
    turn my bit off}

Then you can implement this status in AI scripts,

counter anything {
look up disease status word in battlevars
make my nullRestore state equal my bit in the disease status word
trollface
}
Title: Re: Turned Poison into Disease through AI, but...
Post by: nfitc1 on 2011-05-18 21:35:51
Just answered my own question through in-game testing. Vincent really needs his main script. Without it, his limit forms do nothing when his turn comes up, and the ATB gauge just resets.

Then put the Null.Restore on Vincent and have everyone link to him. Since their main scripts will never be activated it won't matter that their mains are linked to his.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-19 11:37:17
Yup, that's how you play with linked scripts. I don't know how it works if the original script holder dies or is kicked from battle, though.

It still works, apparently :)

Those ideas of yours are very nice, but I'm satisfied with those status effects for now. Still, I would have been interested in implementing an Overkill function, that would have worked the same as in FFX (with the exception of doubling the item drops). IE, if an enemy is killed with a damage equal or superior to a certain number (that would vary from enemy to enemy), display the "OVERKILL" message and multiply his exp/ap/gil gain by 1.5 or 2.

It's a function I really liked in FFX, but I bet it would be tricky to accomplish (and would require a different script for every enemy, thus drastically increasing Scene.bin's size).

Quote
counter anything {
look up disease status word in battlevars
make my nullRestore state equal my bit in the disease status word
trollface
}

Trollface ?
(http://2.bp.blogspot.com/_9AeLcpprMzs/TNVQglD4t9I/AAAAAAAAAW4/a_R5SKSlqs4/s400/cinoque.jpeg)

Then put the Null.Restore on Vincent and have everyone link to him. Since their main scripts will never be activated it won't matter that their mains are linked to his.

D'oh ! I was afraid his main script would interfere with the other characters. Thanks, I'll do that :)
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-05-19 13:12:50
It's a function I really liked in FFX, but I bet it would be tricky to accomplish (and would require a different script for every enemy, thus drastically increasing Scene.bin's size).

No, you don't need a script per species. You can multiply and divide with AI scripts.

And if you DID need a large Scene.bin, my disk extension patch will let you use PSX SCENE.BINs 2mb in size (I believe), which is the upper limit of any usable SCENE.BIN file.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-19 17:31:59
No, you don't need a script per species. You can multiply and divide with AI scripts.

Are you really sure ? Because if, to be overkilled, Nerosuferoth needs to be killed with 200+ damage, Zemzelett needs 400+ damage and Bottomswell needs 650+ damage, I don't see how the multiplications and divisions would help. Especially since some enemies would be overkilled when taking their HP x 150% worth of damage (for some random low-HP enemies you'd regularly 1-hit kill), while others would be overkilled when they sustained their HP x 5% or even 1% worth of damage (in the case of bosses with a lot of HP).

Quote
And if you DID need a large Scene.bin, my disk extension patch will let you use PSX SCENE.BINs 2mb in size (I believe), which is the upper limit of any usable SCENE.BIN file.

Yes, your disk extension patch is amazing. This reminds me that, as of right now, there is still only the .ppf patch for the first disk, though. So, in the worst case scenario, I could still release a different scene.bin for each disk - in which I'd delete the scenes you can't access in said disk. The resulting saved space would then be more than enough to fit into the iso, but I'd prefer to use your disk extension patch (especially for the kernel... ...I didn't check, but mine could possibly go over the PSX limit).

EDIT:

Or, about the Overkill AI scripts, one could make 3 different kinds of scripts : one for the easy random enemies, another one for the "tough" random enemies, and the last one for bosses, with a cap at 9,999.

I imagine something like this would work :

- for the easy random encounters, apply the Overkill script when they're killed by an attack dealing their HP x 80% minimum worth of damage

- for the strong random encounters, apply the Overkill script when they're killed by an attack dealing their HP x 35% minimum worth of damage, and

- for the bosses, apply the Overkill script when they're killed by an attack dealing their HP x 5% minimum worth of damage. This means that against a boss with 200,000 HP, you'd need to deal the maximum damage (9,999). And the cap would ensure that against Emerald or Ruby, the needed damage to overkill them would stay as 9,999.

You'd need to write each of these 3 scripts, then have the enemies in the same category be linked to the right script. How feasible would that be ?
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-05-20 08:50:42
Are you really sure ? Because if, to be overkilled, Nerosuferoth needs to be killed with 200+ damage, Zemzelett needs 400+ damage and Bottomswell needs 650+ damage, I don't see how the multiplications and divisions would help. Especially since some enemies would be overkilled when taking their HP x 150% worth of damage (for some random low-HP enemies you'd regularly 1-hit kill), while others would be overkilled when they sustained their HP x 5% or even 1% worth of damage (in the case of bosses with a lot of HP).

Well, it depends how you calculate overkill - I'm not actually sure how FF X handles it...

Quote
Yes, your disk extension patch is amazing. This reminds me that, as of right now, there is still only the .ppf patch for the first disk, though.

This will be resolved when I get my computer, hard drive and internet connection sorted. I'll be getting a connection tomorrow and a replacement drive around (I believe) next Wednesday.

Quote
(especially for the kernel... ...I didn't check, but mine could possibly go over the PSX limit).

One word about the kernel: whilst there's no on-disc size limit, KERNELs above 27,647 bytes *may* cause glitches. I haven't really investigated. That's still a 5kb increase, though.

Quote
Or, about the Overkill AI scripts, one could make 3 different kinds of scripts : one for the easy random enemies, another one for the "tough" random enemies, and the last one for bosses, with a cap at 9,999.

I imagine something like this would work :

- for the easy random encounters, apply the Overkill script when they're killed by an attack dealing their HP x 80% minimum worth of damage

- for the strong random encounters, apply the Overkill script when they're killed by an attack dealing their HP x 35% minimum worth of damage, and

- for the bosses, apply the Overkill script when they're killed by an attack dealing their HP x 5% minimum worth of damage. This means that against a boss with 200,000 HP, you'd need to deal the maximum damage (9,999). And the cap would ensure that against Emerald or Ruby, the needed damage to overkill them would stay as 9,999.

You'd need to write each of these 3 scripts, then have the enemies in the same category be linked to the right script. How feasible would that be ?

Feasible. There could be lots of ways of doing this, some more hacky than others. You could actually specify certain enemy IDs in the AI, but that would be bulky. You could make an enemy's prebattle script set a flag that turns on a different overkill script. You could make every 'strong' enemy turn on its bit in a targetmask held in a battlevar, then refer to that when working out which script to use. Or you could go for the simple method and make sure that only bosses have levels that are, say, multiples of twenty, and refer to this when choosing the right script.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-20 11:18:04
Well, it depends how you calculate overkill - I'm not actually sure how FF X handles it...

That's the whole problem actually : the different overkill values aren't calculated or dependent on MaxHP; they're just set. Most of the time though, overkill values are almost equal to the enemy's HP, so one-shotting it will overkill it. The random monster Ahriman for instance, has 2800 HP and is overkilled when the finishing blow hits for at least 4200 damage. But another random monster has 5000 HP and is overkilled by an attack dealing at least 2400. And a Dark Aeon (=optional boss) has millions of HP and is overkilled with finishing blows dealing at least 99999 (yes, there are 5 digits). So, with these mechanics, there is no set rule that could work for all enemies...

Quote
This will be resolved when I get my computer, hard drive and internet connection sorted. I'll be getting a connection tomorrow and a replacement drive around (I believe) next Wednesday.

This is great to hear :)

Quote
One word about the kernel: whilst there's no on-disc size limit, KERNELs above 27,647 bytes *may* cause glitches. I haven't really investigated. That's still a 5kb increase, though.

Yeah, I read what Lasyan said about the ram. But as you said, I don't think it's an issue, since 5kb should be more than enough.

Quote
Feasible. There could be lots of ways of doing this, some more hacky than others. You could actually specify certain enemy IDs in the AI, but that would be bulky. You could make an enemy's prebattle script set a flag that turns on a different overkill script. You could make every 'strong' enemy turn on its bit in a targetmask held in a battlevar, then refer to that when working out which script to use. Or you could go for the simple method and make sure that only bosses have levels that are, say, multiples of twenty, and refer to this when choosing the right script.

Thanks for this insight. Still, as much as I'd love such a function to be implemented into FF7, I don't think I'd be able to write such a script without bothering you or NFITC1 for days... I'm quite satisfied with my mod's mechanics right now. If all goes well, I should be able to release it in July.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-05-20 15:21:54
I don't mind writing AI scripts. I just can't do it in a timely manner at the moment thanks to my machine woes.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-23 09:03:40
Cool :) (about your will to write AI scripts, NOT about your machine woes >_>)

Correct me if I'm wrong, but I think this overkill script should be written in the Death Counter section. It's quite simple actually, as it should be something like this (for the easy enemies, overkilled when the final blow is their maxHP x 100%) :

- Check for self + max HP
- Put this value in memory
- Check if last damage taken is equal or greater than the value we just stored in memory
- If not, jump to the end of the script
- If true, display message: "OVERKILLED {VAR:TargetName}{VAR:TargetLetter} !" (this should display the correct monster name, right ?)
- Check for AP
- Check for XP
- Check for Gil
- multiply those by 2 (I'd rather it be 1.5, but I don't think it's possible?)
- END

I *might* be able to write this, but my biggest problem would be with the bolded part. I don't know how to check for the strength of an attack.

Also, another idea that popped in my mind : since the Blind status doesn't work on enemies, I've been wondering whether one could add the Oil effect to it. Oil comes from Final Fantasy Tactics, and Fire elemental attacks deal more damage to the inflicted (or should deal more damage - it was glitched and didn't work in FFT...). Problem once again is, I don't know how to check for the presence of an element... ...I guess the script would look like this (what I'm gonna write will undoubtedly be unrefined and full of mistakes, but I don't have time to correct them ATM) :

- if target status=blind
- if attack = fire elemental
- if not, jump
- if true,  damage = damage x3
- end

The tissue could be put to good use as a way to remove the Oil status :)
Title: Re: Turned Poison into Disease through AI, but...
Post by: nfitc1 on 2011-05-23 15:47:54
Cool :) (about your will to write AI scripts, NOT about your machine woes >_>)

Correct me if I'm wrong, but I think this overkill script should be written in the Death Counter section. It's quite simple actually, as it should be something like this (for the easy enemies, overkilled when the final blow is their maxHP x 100%) :

- Check for self + max HP
- Put this value in memory
- Check if last damage taken is equal to the value we just stored in memory
- If not, jump to the end of the script
- If true, display message: "OVERKILLED {VAR:TargetName}{VAR:TargetLetter} !" (this should display the correct monster name, right ?) This works for Battle Texts, but I don't know if it works inside scripts like that. The way you reference Character names (Barret, Cloud) inside the AI text is different.
- Check for AP
- Check for XP
- Check for Gil
- multiply those by 2 (I'd rather it be 1.5, but I don't think it's possible?) Multiply by 3, divide by 2. Boom, 1.5
- END

I *might* be able to write this, but my biggest problem would be with the bolded part. I don't know how to check for the strength of an attack. I believe there's a Var:4XXX battle address for this. I don't recall what it is though as my notes for that section are incomplete I know that there are a lot of values in there that aren't used in AI, but the battle engine itself might handle.

Also, another idea that popped in my mind : since the Blind status doesn't work on enemies, I've been wondering whether one could add the Oil effect to it. Oil comes from Final Fantasy Tactics, and Fire elemental attacks deal more damage to the inflicted (or should deal more damage - it was glitched and didn't work in FFT...). Problem once again is, I don't know how to check for the presence of an element... See previous comment ...I guess the script would look like this (what I'm gonna write will undoubtedly be unrefined and full of mistakes, but I don't have time to correct them ATM) :

- if target status=blind
- if attack = fire elemental
- if not, jump
- if true,  damage = damage x3
- end

The tissue could be put to good use as a way to remove the Oil status :)
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-05-23 18:43:13
Correct me if I'm wrong, but I think this overkill script should be written in the Death Counter section. It's quite simple actually, as it should be something like this (for the easy enemies, overkilled when the final blow is their maxHP x 100%) :

- Check for self + max HP
- Put this value in memory
- Check if last damage taken is equal or greater than the value we just stored in memory
- If not, jump to the end of the script
- If true, display message: "OVERKILLED {VAR:TargetName}{VAR:TargetLetter} !" (this should display the correct monster name, right ?)
- Check for AP
- Check for XP
- Check for Gil
- multiply those by 2 (I'd rather it be 1.5, but I don't think it's possible?)
- END

I *might* be able to write this, but my biggest problem would be with the bolded part. I don't know how to check for the strength of an attack.

Hmm. I don't know if you can find that info out. You can find out the amount of HP lost since last turn, but that's not the same thing. I'll have to investigate...

Quote
Also, another idea that popped in my mind : since the Blind status doesn't work on enemies, I've been wondering whether one could add the Oil effect to it. Oil comes from Final Fantasy Tactics, and Fire elemental attacks deal more damage to the inflicted (or should deal more damage - it was glitched and didn't work in FFT...). Problem once again is, I don't know how to check for the presence of an element... ...I guess the script would look like this (what I'm gonna write will undoubtedly be unrefined and full of mistakes, but I don't have time to correct them ATM) :

- if target status=blind
- if attack = fire elemental
- if not, jump
- if true,  damage = damage x3
- end

The tissue could be put to good use as a way to remove the Oil status :)

You can't really do it that way, because you can't query the element of the last attack. You can query its ID, however, so you can write

Code: [Select]
counter preturn {
is oil active? skip if not
if id of last attack == that of fire 1, fire 2 or fire 3, then
store current level in battle var
and set level as 1/2 current
}

counter general {
[implement oil however you feel]
if battle var with level has anything in it
set level to battle var
set battle var to zero
}

Some limitations with this, however:

1. You aren't quite multiplying damage taken. You can add and remove HP in an AI script, but it doesn't display. Changing level means your character takes a lot more damage from fire attacks, but it won't always be 150% damage.

2. You have to specify the IDs of the spells which have fire element. If you have lots of fire spells, specifying them individually could be space-consuming. It might be quicker to specify groups of spells, eg 'does spell have an ID which is > 0x29 but < 0x3A', then putting all fire spells within that range. This won't, however, help you combine Oil with Weapon Elemental - Fire, or any fire-based weapons you implement yourself.

The only other alternative is to find a way of setting a weakFire flag via AI. I can't really help at the moment because my machine is out of commission, but to find the weakFire flag, you would need to

- take Akari's memory map of the NTSC PSX build's battle engine
- run an emulator and compare memory maps for monsters with weakFire and without
- use a process of elimination to see where the weakFire might be stored
- look at the addresses in the memory map the AI can, uh, address, and see if some of the unknown addresses tally with the location of your weakFire variable
- set weakFire on when the target was Blind



Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-23 21:39:54
Quote
This works for Battle Texts, but I don't know if it works inside scripts like that. The way you reference Character names (Barret, Cloud) inside the AI text is different.

Ah yes. Cloud is {EA0000h} in the AI text, and Barret is {EA0001h}, etc... Actually, it looks a lot like the FF7-text format (http://wiki.qhimm.com/FF7/FF_Text), but all my different tests didn't net me any results regarding monster names. If this script becomes manageable in the future, I guess a simple "OVERKILL" message will do...

Quote
Multiply by 3, divide by 2. Boom, 1.5

lol, basic maths. I should have realized one can do more than one operation ^^;

Quote
I believe there's a Var:4XXX battle address for this. I don't recall what it is though as my notes for that section are incomplete I know that there are a lot of values in there that aren't used in AI, but the battle engine itself might handle.

Ah, this gives me hope - though I don't hold my breath.

Quote
Hmm. I don't know if you can find that info out. You can find out the amount of HP lost since last turn, but that's not the same thing. I'll have to investigate...

If those investigations will require you to in-game test each one of the 4xxx battles addresses not referenced into wallmarket.dat, I wish you good luck. Looking at them, there are 4041-4047, 4049, 4051-4057, 4059, 4061-4067, 4069, 4071-4077, 4079, 4081-4087, 4089 (I start to see a pattern :P), 4091-4097, ... (not gonna list them all, actually O_O). We're talking about hundreds - maybe thousands of battle addresses ! I may be crazy like that, but even I couldn't test them all - and I suggest you don't either, if you value your sanity. Still, perhaps many of those can already be ruled out ?

And about Oil : wouldn't it be possible to increase the level and/or the magic stat of the caster, instead ?... ...After all, levels can go up to 255 - might as well put this to good use.

And it's too bad about elemental weapons :( I asked in another thread if the AI could check for the presence of a piece of equipment, but I guess this means it can't.

Quote
The only other alternative is to find a way of setting a weakFire flag via AI. I can't really help at the moment because my machine is out of commission, but to find the weakFire flag, you would need to

- take Akari's memory map of the NTSC PSX build's battle engine
- run an emulator and compare memory maps for monsters with weakFire and without
- use a process of elimination to see where the weakFire might be stored
- look at the addresses in the memory map the AI can, uh, address, and see if some of the unknown addresses tally with the location of your weakFire variable
- set weakFire on when the target was Blind

Yeah, but weakFire is just a basic x2 damage. So, oiling an already fire-weak monster wouldn't reap any more benefits.

EDIT:

About Overkill, how about this :

In General Counter :

Code: [Select]
If HP < MaxHP
If target:self is NOT dead
Set {VAR:E0} to 1

In Death Counter :

Code: [Select]
If {VAR:E0} is 0
If attack ID is NOT 18 (=Death)
If attack ID is NOT 3D (=Odin)
Display message: "OVERKILLED!!"
Set Exp to 2x
Set Gil to 2x

What do you think ? Alternatively, I thought about using the in-game timer, and if you finished a battle quickly enough, you'd get added bonuses. FFVI can check a timer in its AI (some enemies can call backup, after a while), but I'm not sure FFVII can. And, third idea : couldn't we simply make use of the "Greatest elemental damage" battle address ? Since almost all attacks are elemental thanks to the physical elements, if one put, in the Death Counter script :

Code: [Select]
- Check for self + max HP
- Put this value in memory
- Check if the greatest elemental damage taken is equal or greater than the value we just stored in memory
- If not, jump to the end of the script
- If true, display message: "OVERKILL!"
- Check for AP
- Check for XP
- Check for Gil
- multiply those by 3
- divide them by 2
...

Wouldn't it work ?
Title: .
Post by: Jenova's Witness on 2011-05-23 22:44:40
.
Title: Re: Turned Poison into Disease through AI, but...
Post by: nfitc1 on 2011-05-24 04:59:06
Ah, this gives me hope - though I don't hold my breath.

Good idea. There's likely nothing like that, but you never know. :)

If those investigations will require you to in-game test each one of the 4xxx battles addresses not referenced into wallmarket.dat, I wish you good luck. Looking at them, there are 4041-4047, 4049, 4051-4057, 4059, 4061-4067, 4069, 4071-4077, 4079, 4081-4087, 4089 (I start to see a pattern :P), 4091-4097, ... (not gonna list them all, actually O_O). We're talking about hundreds - maybe thousands of battle addresses ! I may be crazy like that, but even I couldn't test them all - and I suggest you don't either, if you value your sanity. Still, perhaps many of those can already be ruled out ?

No, that's not how they work. Think of those addresses as pointers to BITS, not bytes. Every 8 is a different byte, and we're talking in Hexadecimal. So between 4008 and 4010 there are 8 values (4009, 400A, 400B, etc). My notes say that the highest 4XXX value is 42E0 which contains the total experience gained in that battle (technically, it goes to as far as 433F before it leaks into another actor's data, but it doesn't look like 4300 and beyond are used). Almost every value in between is used for something.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-05-24 08:41:24
Can these addresses leak into another actor's data? Which data exactly (it might well be data I want to manipulate)?

I need to get to know that memory map better. I'd like to see how data for different actors is positioned.

I wonder which function assigns pointers to 'relative' addresses like 0x4001 etc. I also wonder if we might hijack it.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-24 09:01:12
Quote
No, that's not how they work. Think of those addresses as pointers to BITS, not bytes. Every 8 is a different byte, and we're talking in Hexadecimal. So between 4008 and 4010 there are 8 values (4009, 400A, 400B, etc).

Why do you feel the need to tell me that, because I know this and- */me re-reads his previous post* ...OK, wow, I took the addresses as if they were decimals, I must have been really tired  ;D

So, what do you guys think about the three ideas I posted when I edited my previous post ? I'm especially interested in the GreatestElementalDamage battle address (VAR:4058).
Title: Re: Turned Poison into Disease through AI, but...
Post by: nfitc1 on 2011-05-24 12:12:16
As far as I can tell, 4058 is only modified when a 96 command is executed. I believe it's blank otherwise. You'll have to read my notes in WM's or PrC's readme for more details.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Armorvil on 2011-05-24 18:25:17
Thank you. Will do.
Title: Re: Turned Poison into Disease through AI, but...
Post by: nfitc1 on 2011-05-25 16:23:34
Can these addresses leak into another actor's data? Which data exactly (it might well be data I want to manipulate)?

Addresses can leak into other actors' data I don't see any restrictions in the AI code to cap the address it will access. Here are some of the findings that I've made. Each 4XXX structure is 104 bytes in memory. Normally, these will go up to 0x433F then another actor's data will start. Actor 0 (I believe this is the top slot of player characters) would be the only one to access everyone else's data. Starting at 0x4340, Actor (X) would be able to access Actor (X+1)'s active statuses. Adding another 340h to that and Actor (X) can access Actor (X+2)'s data, etc. Technically, I believe there are 10 actors (three playable characters, up to six enemies, and one "battle actor" that would contain formation-based scripts). For Actor (0) to access Actor (9)'s data, it would start at 0x5D40 and should be no greater than 0x607F. This applies to ANY 4XXX Battle variable. This doesn't apply to 2XXX addresses, because they are technically temporary to which ever character's turn it is.

So it IS possible for actor 9 to perform some DRASTIC memory leaks. I don't really know what's beyond the battle addresses, but Actor 9 can access quite a bit of it. Just shy of 6K outside of it as a matter of fact.

I need to get to know that memory map better. I'd like to see how data for different actors is positioned.

So follow this if you want to access other actors' data. Just add these amounts to the address of what you want to access:

Code: [Select]
Actor (X)   Actor (X+1)   Actor (X+2)   Actor (X+3)   Actor (X+4)   Actor (X+5)   Actor (X+6)   Actor (X+7)   Actor (X+8)   Actor (X+9)
        0           340           680           9C0           D00          1040          1380          16C0          1A00          1D40

I'm not certain about which actor is which, but I think it goes: PartyCharTop, PartyCharMid, PartyCharBottom, Battle, Enemy0, Enemy1, Enemy2, Enemy3, Enemy4, Enemy5

I wonder which function assigns pointers to 'relative' addresses like 0x4001 etc. I also wonder if we might hijack it.

There aren't really any pointers. It's all pretty hard-coded static address lookups in every location it gets read from/written to. You can't really hijack it because they're all referenced all over the place. I suppose you could hijack lookups to those addresses though, but that's a lot of hooks.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2011-07-02 00:39:50
I've been looking into this tonight. As far as I can tell, I just can't get a Counter:PreTurn script "Make Self.NullRestore = 1" or "Make Party.NullRestore = 1" to stop healing. I'm not holding any counter materia, so I'm developing a suspicion that the element control flags don't work outside the initialization scripts.

Will continue researching this.
Title: Re: Turned Poison into Disease through AI, but...
Post by: Bosola on 2012-01-01 19:49:50
*bump*

I finally got around to trying this out - I've uploaded a Youtube video here: http://youtu.be/hxhSvh5IHJI (http://youtu.be/hxhSvh5IHJI)

In this case, I created a pre-attack script on one character:

Code: [Select]
12 2060
10 42A9
80
02 2060
00 4003
80
90
73

Then I just linked my characters to the other's scripts and was on my way.

For some reason, trying to make the script set allActors.nullRestore = allActors.poison (using the address 20E0 rather than 20E0 in the script above) didn't work well - inflicting / curing poison on one character would apply / remove nullRestore on everyone. I'm not sure why this is - though I'd appreciate some pointers.

In any case, I just made my script set self.nullRestore = self.poison, and it worked fine for the player characters. Any ideas how I can make it work OK on enemies without having to give them all a similar script? Maybe if I take an activeMask and iterate through all the formation numbers?