Author Topic: Adding a 'seizure' status to poison / linking statuses with AI  (Read 2582 times)

Bosola

  • Fire hazard!
  • *
  • Posts: 1752
    • View Profile
    • My YouTube Channel
As some of you may know, I've never been happy with the poison status in vanilla FFVII. 1/32 Max HP damage per turn just doesn't cut it in the endgame, when many monsters can be KOed in one or two hits anyway.

The usual solution is to add the 'dual drain' status to all poison-inflicting attacks and spells. This makes poison much more dangerous. But it has three main disadvantages:

1. Modifying *every* enemy and player attack is very time-consuming. And if you want to switch back, you have to be very thorough.
2. Just adding the status to poison attacks isn't enough - you now have to modify enemy status immunities (many creatures are vulnerable to the one status but not another). Again, this takes a lot of time.
3. You can't inflict your dual-drain status via added effect, because you can't give materia a dual-drain status affinity. Boo!

But do not despair! There is another way - to create an AI script that automatically gives poisoned creatures the dual-drain status, and removes it when they're cured. Here's the AI script:

Code: [Select]
12   0000
02   20E0
90
12   0020
61   0001
90
12   0040
02   0000
02   0020
35
90
02   0040
70   002E
12   0040
10   401B
80
02   0040
00   4003
80
90
02   0020
61   8000
45
70   0045
12   0020
02   0020
60   02
32
90
72   000E
73

The idea is to put this into Vincent's preTurn-counter and general-counter scripts, then link other characters to Vincent's scripts with the preBattle code

Code: [Select]
60 07
75
73

Now, poisoned characters and creatures will immediately take the Seizure status. The only potential bug is if a character has a counter ability, in which case, the seizure status will be delayed until another battle actor takes an action.

What if I want a disease status, rather than seizure / dual-drain?

Oh, that's simple. Use the code

Code: [Select]
12   0000
02   20E0
90
12   0020
61   0001
90
12   0040
02   0000
02   0020
35
90
02   0040
70   002E
12   0040
10   42A9
80
02   0040
00   4003
80
90
02   0020
61   8000
45
70   0045
12   0020
02   0020
60   02
32
90
72   000E
73

That should work just fine.

And if I want to link any statuses?

Then replace the values in the following:

Code: [Select]
12   0000
02   20E0
90
12   0020
61   0001
90
12   0040
02   0000
02   0020
35
90
02   0040
70   002E
12   0040
10   ADDRESS OF STATUS TO ADD (E.G. DUAL-DRAIN)
80
02   0040
00   ADDRESS OF STATUS THAT TRIGGERS IT (E.G. POISON)
80
90
02   0020
61   8000
45
70   0045
12   0020
02   0020
60   02
32
90
72   000E
73

So if you wanted to give Flag:PhysicalImmune to anyone with Flag:Defending (so Defend blocks *all* non-magic damage), you'd substitute the values 4028 and 4025 respectively, etc. etc.

How is this script any different to older ones?

This isn't the first time this has been attempted (see http://forums.qhimm.com/index.php?topic=11861.25). The problem with those attempts is that they attempted to directly set allActors.dualDrain = allActors.poison by simply copying a word of one status mask to another, which the battle engine doesn't support. The result was typically a buggy script where all creatures would suffer dualDrain if *any* were poisoned. Not good. Instead, this script directly iterates through all battle actors and sets statuses individually.

How does it do that?

The idea is simple. We put the AllUnitsMask in a local variable, then we perform a bitwise AND on it with an iterator that's logically shifted to the left with every loop (by multiplying by two). That means that every loop, we get a unitmask that points to each actor in the battle. If the mask isn't empty, we copy the unit's poison status to its dual-drain status. We don't do that for units that don't exist, because that might invoke glitches (probably not, but better safe than sorry).

Here's an annotated AI script:

Code: [Select]
12   0000
02   20E0
90      Put a mask of all actors in LocalVar 0000
12   0020
61   0001
90      Start our iterator (LocalVar 0020) at 1
12   0040
02   0000   
02   0020
35       Bitwise operation to cycle through bits in the LocalVar 0000, one at a time
90
02   0040
70   002E   If there's an active bit in the current position...
12   0040
10   401B   
80      Get the address of currentActor.dualDrain...
02   0040
00   4003
80      And currentActor.poison...
90      ... and finally make currentActor.dualDrain = currentActor.poison
02   0020
61   8000
45
70   0045   If the iterator is at 0x8000 (which means one 1 and fifteen 0s), exit
12   0020
02   0020
60   02
32
90      If not, double the iterator (which effectively applies a left shift) and go again
72   000E   Loops
73      End of script!

I've encountered a problem! Help!

...then post your issue here and I'll update the script if I can fix it.

Other than that, enjoy!
« Last Edit: 2012-02-11 20:51:08 by Bosola »