B
Bosola
Guest
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]
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]
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]
That should work just fine.
And if I want to link any statuses?
Then replace the values in the following:
Code: [Select]
So if you wanted to give Flag
hysicalImmune to anyone with Flag
efending (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 https://www.ff7catalog.com/threads/7909/). 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]
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!
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]
Code:
12 000002 20E09012 002061 00019012 004002 000002 0020359002 004070 002E12 004010 401B8002 004000 4003809002 002061 80004570 004512 002002 002060 02329072 000E73
Code: [Select]
Code:
60 077573
What if I want a disease status, rather than seizure / dual-drain?
Oh, that's simple. Use the code
Code: [Select]
Code:
12 000002 20E09012 002061 00019012 004002 000002 0020359002 004070 002E12 004010 42A98002 004000 4003809002 002061 80004570 004512 002002 002060 02329072 000E73
And if I want to link any statuses?
Then replace the values in the following:
Code: [Select]
Code:
12 000002 20E09012 002061 00019012 004002 000002 0020359002 004070 002E12 004010 ADDRESS OF STATUS TO ADD (E.G. DUAL-DRAIN)8002 004000 ADDRESS OF STATUS THAT TRIGGERS IT (E.G. POISON)809002 002061 80004570 004512 002002 002060 02329072 000E73
How is this script any different to older ones?
This isn't the first time this has been attempted (see https://www.ff7catalog.com/threads/7909/). 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]
Code:
12 000002 20E090 Put a mask of all actors in LocalVar 000012 002061 000190 Start our iterator (LocalVar 0020) at 112 004002 0000 02 002035 Bitwise operation to cycle through bits in the LocalVar 0000, one at a time9002 004070 002E If there's an active bit in the current position...12 004010 401B 80 Get the address of currentActor.dualDrain...02 004000 400380 And currentActor.poison...90 ... and finally make currentActor.dualDrain = currentActor.poison02 002061 80004570 0045 If the iterator is at 0x8000 (which means one 1 and fifteen 0s), exit12 002002 002060 023290 If not, double the iterator (which effectively applies a left shift) and go again72 000E Loops73 End of script!
...then post your issue here and I'll update the script if I can fix it.
Other than that, enjoy!
Last edited: