Modding => Help! => Topic started by: Dokurider on March 27, 2014, 03:26:37 pm
Title: How do use ANDI to check if a flag is on?
Post by: Dokurider on March 27, 2014, 03:26:37 pm
It was either here or Final Fantasy Tactics Hacking, so idk.
So I'm on the cusp of making my very first hack. I'm trying to turn the 255 AoE check into something I can toggle in FFTP by attaching to a unused flag. I've identified all the code that governs this check, I just some help in figuring out how to intelligently use ANDI to my purposes.
For an example, in the targeting routine, ability flag 2 is ANDI'd against 0x0006 to see if the attack is a linear AoE or not.
Ideally, I wanted to use the Math Skill flag for this check, since most patches ban that skill, but the Targeting Routine doesn't load that flag, so I'm going to have to piggyback on some of the (hopefully) blank flags.
I could just attach this hack to the Top Down Targeting Flag if worst comes to worst, because it's such a rare map feature to have tiles above other tiles...
Title: Re: How do use ANDI to check if a flag is on?
Post by: Choto on March 27, 2014, 04:43:04 pm
basically, you'd just have to load the other set of flags (with math skill in it) and check vs. the math skill bit. I'm not sure where in the routine you're mentioning... if you post the code i could help a bit better.
Here's the set of data you want to use
8006fbf0 - Ability Data POinter 2 (loading to skillset?) 0x00 - Range 0x01 - Effect Area 0x02 - Vertical 0x03: Flags 1 0x80 - 0x40 - 0x20 - Ranged Weapon 0x10 - Vertical Fixed 0x08 - Vertical Tolerence 0x04 - Weapon Strike 0x02 - Auto 0x01 - Can't Target Self 0x04: Flags 2 0x80 - Can't Hit Enemies 0x40 - Can't Hit Allies 0x20 - 0x10 - Can't Follow Target 0x08 - Random Fire 0x04 - Linear Attack 0x02 - 3 Directions 0x01 - Can't Hit Caster 0x05: Flags 3 0x80 - Reflectable 0x40 - Math Skill 0x20 - Affected By Silence 0x10 - Can't Mimic 0x08 - Normal Attack? 0x04 - Persevere 0x02 - Quote 0x01 - Animate on Miss 0x06: Flags 4 0x80 - Counter Flood 0x40 - Counter Magic 0x20 - Direct 0x10 - Blade Grasp 0x08 - Requires Sword 0x04 - Requires Materia Blade 0x02 - Evadeable 0x01 - No Targeting 0x07 - Element 0x08 - Formula 0x09 - X 0x0a - Y 0x0b - Inflict Status 0x0c - CT 0x0d - MP Cost
I'm assuming in the routine they already load the pointer to this ability data since they load the AoE to check if it's 255. So then all you have to do:
lbu r1, 0x0005(r2) #assuming r2 is the ability data address nop andi r1, r1, 0x0040 #this will set r1 = 0x40 if math skill is checked, 00 otherwise beq, r1, r0, 0x00000000 #set this address to skip the following code for your hack nop
*Code for your hack goes here*
So all we do is load the byte, use andi this way to check the 0x40 bit(flag), and use a branch command to skip the code if that flag is not flagged. If you still are unsure, post the section of code and I can describe it a bit better.
Title: Re: How do use ANDI to check if a flag is on?
Post by: Glain on March 28, 2014, 10:08:39 am
You can also avoid hardcoding the address by doing something like this:
beq r1, r0, after_hack nop
*hack code*
after_hack: (first line of code after the hack)
(Either way, don't forget to change the address. :) Branching to the beginning of memory is probably not the desired effect... although it would be kind of funny...)
Title: Re: How do use ANDI to check if a flag is on?
Post by: Dokurider on March 28, 2014, 03:18:05 pm
Yeah, I'll just post the current code From the Targeting Routine (Thanks FFH wiki!) Assume that we are working with a 255 AoE spell or 0x00ff
0017b8d0: 90690003 lbu r9,0x0003(r3)ability flags 1 # loaded for vertical flags and self/auto target 0017b8d4: 90710004 lbu r17,0x0004(r3)ability flags 2 # Hit Allies/Enemies flags, Top Down Targeting, Linear/3 Direction and Hit Caster 0017b8d8: 90640006 lbu r4,0x0006(r3)ability flags 4 # Stop at Obstacle and maybe select target 0017b8dc: 90730001 lbu r19,0x0001(r3)load aoe # r19 is the big deal here 0017b8e0: 90750002 lbu r21,0x0002(r3)load verticle # whatevs 0017b8e4: 30840020 andi r4,r4,0x0020 # direct attack, aka Stop at Obstacle flag check 0017b8e8: 10800003 beq r4,r0,0x0017b8f8 # why don't we just pretend our spell is not direct and move on, hmm? 0017b8f8: 32220006 andi r2,r17,0x0006Check linear flag 0017b8fc: 10400006 beq r2,r0,0x0017b918Branch if not linear # our spell is not linear either, so let's skip ahead 0017b918:: 93a3001a lbu r3,0x001a(r29) # begin the target/caster x/y coordinate routines. This doesn't concern us now, so I'm just going to skip ahead 0017b9fc: 326300ff andi r3,r19,0x00ff # That's the gold here. This is the beginning of the 255 AoE check, what we want to mess with today. Since r19 is 0x00ff here, it will spit out a result of...0x00ff. Saved to r3. 0017ba00: 340200ff ori r2,r0,0x00ff # preparing a value for the branching routine 0017ba04: 1462000c bne r3,r2,0x0017ba38 # skipping some really dumb looking loop. 0017ba38: 3c038019 lui r3,0x8019 # Only to jump right into another one 0017ba3c: 24632dd8 addiu r3,r3,0x2dd8 0017ba40: a0600000 sb r0,0x0000(r3) 0017ba44: a0600001 sb r0,0x0001(r3) 0017ba48: 24840001 addiu r4,r4,0x0001 0017ba4c: 28820200 slti r2,r4,0x0200 0017ba50: 1440fffb bne r2,r0,0x0017ba40 # I'm befuddled at what this routine is supposed to do. Rewriting a RAM location is well and good, but what good does rewriting the exact same data to the exact same place...512 times do???? Whatever. 0017ba54: 24630005 addiu r3,r3,0x0005 # that above loop would make more sense with this line in there, but it's not apart of the loop. I think. Oh well. 0017ba58: 00061080 sll r2,r6,0x02 # the following code isn't important, but it does check r19 (the AoE a few times, but it's not for the 255 check, so let's skip ahead again. 0017bb60: 3a6700ff xori r7,r19,0x00ff # We are preparing to jump to the Allies/Enemies Targeting routine, so we are saving whether r19 = 255 or not. Since it is, r7 is 0x0000 0017bb64: 0c05ef1e jal 0x0017bc78 # we are now headed to the Allies/Enemies target routine
Allies/Enemies Targeting Routine
0017bc78: 27bdffc0 addiu r29,r29,0xffc0 0017bc7c: afb5002c sw r21,0x002c(r29) 0017bc80: 00a0a821 addu r21,r5,r0r21 = Can Hit Enemies Flag 0017bc84: afb60030 sw r22,0x0030(r29) 0017bc88: 00c0b021 addu r22,r6,r0r22 = Can Hit Allies Flag 0017bc8c: afb70034 sw r23,0x0034(r29) 0017bc90: 00e0b821 addu r23,r7,r0r23 = 255 AoE check # r23 is our register of interest here. r23 is not called until: 0017bd68: 32e200ff andi r2,r23,0x00ff 0017bd6c: 1440000c bne r2,r0,0x 0017bda0# Skip the Tile Counter Routine if not 255 AoE. This is why Song/Dance skills don't have tiles all over the map. Since we are equal to r0, we proceed into the routine. 0017bd84: 00000000 nop 0017bd88: 10400002 beq r2,r0,0x 0017bd94Branch if AoE = 0 0017bd8c: 26100001 addiu r16,r16,0x0001Tile Counter ++ 0017bd90: a0640001 sb r4,0x0001(r3)Store Tile Targeted? = True 0017bd94: 2a020200 slti r2,r16,0x0200 0017bd98: 1440fff9 bne r2,r0,0x 0017bd80Branch if Tile Counter < 0x200 0017bd9c: 24630005 addiu r3,r3,0x0005Pointer += 5 0017bda0: 8fbf0038 lw r31,0x0038(r29) 0017bda4: 8fb70034 lw r23,0x0034(r29) # The game is done with the check 0017bda8: 8fb60030 lw r22,0x0030(r29) 0017bdac: 8fb5002c lw r21,0x002c(r29) 0017bdb0: 8fb40028 lw r20,0x0028(r29) 0017bdb4: 8fb30024 lw r19,0x0024(r29) 0017bdb8: 8fb20020 lw r18,0x0020(r29) 0017bdbc: 8fb1001c lw r17,0x001c(r29) 0017bdc0: 8fb00018 lw r16,0x0018(r29) 0017bdc4: 27bd0040 addiu r29,r29,0x0040 0017bdc8: 03e00008 jr r31 0017bdcc: 00000000 nop
What I want to do: 0x17b9fc: 322300XX andi r3, r17, 0x00XX # if I want to check the Top Down Targeting Flag in Ability Flag 2 0x17b9fc: 312300XX andi r3, r9, 0x00XX # if I want to check against one of the blank flags in Ability Flag
0017ba00: 340200XX ori r2,r0,0x00XX # needs to equal r3
0017bb60: 3a6700XX xori r7,r19,0x00XX # needs to be result in r7 being 0x0000
The problem I see with just loading the Ability Flag 3 is that the loading flag data routine would have to be relocated to a location that has space and I have no idea where any free space would be. Even if we found some space, what register can take it?
I would just rather work out a way to check against the Top Down Flag. Seems to be a lot less trouble.
Title: Re: How do use ANDI to check if a flag is on?
Post by: Choto on March 28, 2014, 08:48:06 pm
Warning: Wall of text
First off, congrats on learning ASM. The biggest hurdle is the first one, it gets much smoother from here on out lol.
Ok, so what actually happens with the 255 aoe? Does the game target differently than if it were 254? I can't remember what it looks like in game >_>
couple things to note here. Check this data, it's used heavily in these routines:
80192dd8 - Moveable/Targetable Panel Grid (By rows of X panels, 0x10 in each row) 0x00 - AoE of panels to highlight (1 only highlights panel, 2 highlights AoE 1 panels, etc.) 0x01 - set to 01 when panel is green (targeted with ability) 0x02 - Unit Number (battle) of unit standing on panel? 0x03 - 0x04 - Obstructed (set to 0xff if panel is obstructed)/ Not reachable?
There are 0x200 panels, 0x100 for each map level. I forget how the panels progress in the grid... if it increases X or Y, but it should help give you an idea of what the big 0x200 long loops are doing. In each run through the loop they increase the counter of this grid data in some way to get to another panel. By writing algorithms you could progress through a different set of panels and set the ones you want targetable/highlighted/etc.
Unfortunately I think you have to get some more room to do what you want to do, but not much. At this point, you should learn how to find free space, jump to free space to make your code, and jump back anyway. It's not too terrible and you do this with most hacks:
1. Get a clean Iso 2. Use Raven's Kanji Space Nopper to erase all free space (I'll attach it to this post) 3. Apply your other hacks 4. Extract Battle.bin, open it in a hex editor, and all the free space should be 00000000's
Now to jump there in vanilla code. Pick a spot in the code to at which to jump. Think of it like the jump command is inserted at that spot and the original command is bumped down. The jump command should be the RAM address of free space that you pick.
After you put your code in free space, you just need to make sure your hack leaves things the way it found it, or that what you leave in the registers won't cause a problem.
To find registers that aren't in use, you can look for any load commands used after where you jumped from. If vanilla code loads to a register, it didn't need that register anymore. Also, at the end of some routines you'll see this:
. In case you don't know, they're loading the original registers before the routine started before returning to the next routine. So if those registers aren't used between where you jump from and where they're reloaded, they're fair game.
0017bd68: j 0x152000 #just some random address in free space atm 0017bd6c: andi r2,r23,0x00ff #r2 = aoe
Then in free space, you just need to set the return locations according to your logic. Also if you look back here:
0017bcbc: afb1001c sw r17,0x001c(r29)
This is where the game stores that set of flags in the Check Allies/Enemies routine. We can load from that when we want to check it ourselves. At this point, I'm going to post the code I wrote here. I know this is a blitzkreig of info but I think you're ready to handle it.
[0x00152000] bne r2, r0, 0x152020 # branch if 255 aoe [0x00152004] lw r20, 0x001c(r29) # load flags [0x00152008] nop [0x0015200c] andi r17, r20, 0x0040 # top down targeting flag check [0x00152010] bne r17, r0, 0x152020 # branch if flag is set [0x00152014] nop [0x00152018] j 0x17bd84 # return to routine if not one of the above [0x0015201c] nop [0x00152020] j 0x17bda0 # return to location of the original branch command that we moved [0x00152024] nop
Let me know if this helps or confuses the fuck out of you >_> Also, I re-uploaded that targeting routine with more notes
Title: Re: How do use ANDI to check if a flag is on?
Post by: Dokurider on March 31, 2014, 03:53:13 pm
(They're yellow, not green, goddamnit.)
Progress Report: I finally succeeded in spoofing the 255 AoE. My code works 100%!* I didn't even need to write over any kanji space because I figured out a way to do it without overwriting any extra space.
0x17b8d4: 90710004 lbu r17, 0x0004(r3) to 0x1148d4: 94710004 lhu r17, 0x0004(r3) BAM! (Of course, I adjusted all of the offsets and following commands.)
Problem is, it doesn't work like I thought it would (like anything ever does). See, instead of ignoring unoccupied space like I thought it would, it scans the entire map and sets occupied spaces as the targets. So, no matter what your AoE is, it'll always set every possible target on the map. Also, I think there's some...interaction with the Only Hit Enemies\Only Hit Allies/Self (As opposed to the Hit Enemies and Hit Allies Flags of Ability Flags 2). So my work's not done yet. I'll need to overwrite some instructions because I think I could program that functionality.
I think.
Fortunately, I found juuuust the perfect routine to overwrite.
Did you know that Morbol Virus, oh excuse me, Moldball Virus, has it's very own, unique targeting routine? I have no earthly clue what it's supposed to really do. The wiki says it's effects what depths it can target. The problem with that it that Moldball Virus has 0 Vertical and Vertical Threshold on by default. It cannot target anything you're not on level with! It's...pretty pointless. Even if it wasn't made redundant by default, I'm 90% certain it's actual function would still be dumb. C'mon now, it's just Moldball Virus. Why should it have custom targeting routine?
So, I'm overwriting for my purposes. It's a shame no one has mapped out the flags of the Tile Data Routine, so then I can know with certainty, or at least so I can satisfy my curiosity. Anyways, I want to avoid writing over Kanji space because I want to avoid potential conflicts with other codes that are or could overwrite the same space.
<?xml version="1.0" encoding="utf-8" ?> <Patches> <Patch name="Math Skill Flag into Target Units Only Flag"> <Description> Turn the Math Skill flag into a flag that targets only tiles with units on them. Basically it just spoofs the 255 AoE check.</Description> <Location file="BATTLE_BIN" offset="1148d4"> 04007194 </Location> <Location file="BATTLE_BIN" offset="1148f4"> 39403132 </Location> <Location file="BATTLE_BIN" offset="1149fc"> 00402332 </Location> <Location file="BATTLE_BIN" offset="114a00"> 00400234 </Location> <Location file="BATTLE_BIN" offset="114ae4"> 20002632 </Location> <Location file="BATTLE_BIN" offset="114aec"> 00000000 </Location> <Location file="BATTLE_BIN" offset="114b60"> 00402732 </Location> <Location file="BATTLE_BIN" offset="114b68"> 00000000 </Location> <Location file="BATTLE_BIN" offset="114d68"> 0040E23A </Location> </Patch> </Patches>
Still, it's technically a successful hack, just not very useful one right now, so yay go me.
I'd like to thank Xifaine, Glain, Pokey and Choto for their attempts at helping me as well as their ASM guides that helped me so much. I'd like to take everyone that has contributed to the FFHWiki's code depository, without it, this would not have been possible, or as fast as it was, and saving me a lot of potential headaches. I'd like to give a special thanks and shout out to FDC for his attempts at teaching me as well as inspiration and whatnot (oh and his guide too). And yes, I am kicking myself for not learning this earlier, so feel free to say I told you so. I'll be back in full as soon as I get internet here in my new home in Idaho.
*Statement is considered a figure of speech and is inadmissible in court of law.
QuoteOk, so what actually happens with the 255 aoe? Does the game target differently than if it were 254? I can't remember what it looks like in game >_>
When an ability is 255 AoE, it only targets panels with units on them, not the space. Just take the vanilla game, make it 254 AoE, and watch the map light up YELLOW, NOT GREEN. I'm hoping to combine this behavior with Random Fire to make Random Fire skills that can be practical when it's larger than 1 AoE. I listed my initial ideas here. (http://ffhacktics.com/smf/index.php?topic=10016.0) The point is, if I can succeed, this can have a lot of awesome applications.
Oh and thanks for the Kanji Buster.
Title: Re: How do use ANDI to check if a flag is on?
Post by: Choto on April 01, 2014, 10:22:47 pm
Nice work! now learning is going to start to get much easier as you understand more. I want to emphasize again that you should learn how to A. look for free space, B. be able to jump there and return. It may not have been needed here but it will be on many hacks in the future.
Also, I'm a little colorblind goddammit. Mah bad
And also know that all of the red routines on the wiki that I have, just haven't been uploaded. If you need one let me know and i'll put it up. Routines in locations that aren't listed haven't been gone through by anyone. You should also check the ASM starter kit thread for the most up-to-date Data Locations.txt that I have. Actually come to think of it I think "Battle.bin routines 2.txt" has alot of the red routines in it.
Title: Re: How do use ANDI to check if a flag is on?
Post by: Dokurider on April 07, 2014, 04:55:32 pm
Progress Report: So maybe my code wasn't really complete. There was some errors. Maybe I copied the wrong RAM data to the wrong offsets, maybe I missed a few checks here and there. I've since fixed them. But what was really throwing me off was the behavior that the 255 check was displaying. When I had both the Target Ally and Enemy on, all it did was throw tiles every where and pout. But, if I where to uncheck both Target Ally and Enemy, it would like it was supposed to if the flags were on in the first place!
I...don't really know why it does that. All at. Mainly because how the Ally/Enemy Flag check doesn't make much sense to me in the first place. But what is clear is that the routine was not really designed to handle normal team flagging. Makes sense, after all, I *am* bypassing the check that prevents the game from going into that routine if both flags are active. Too bad though, because in the vanilla game, you can't access the 255 AoE routine if both your team flags are active.
That's right, I tested it. In the vanilla game, this behavior is present. Go into FFTP and modify 255 AoEs to to either be 254, both ally/enemy flagged, neither flagged, or any combination of those, and you'll see why all 255 AoEs either attack only enemies or allies. Better yet, I'll just show you now. (This isn't going to be easy without actually being able to see the damn pictures in the first place. Thanks, 10+ year old computer and Internet Explorer.) Remember, this is vanilla code.
(http://i.imgur.com/B780dYS.png)
(http://i.imgur.com/rZgZoBo.png)
(http://i.imgur.com/Bn5MNoI.png)
(http://i.imgur.com/SsQp8EO.png)
(http://i.imgur.com/82oH2W1.png)
(http://i.imgur.com/9G0At6t.png)
(http://i.imgur.com/12B5LvR.png)
(http://i.imgur.com/UrAL5Fo.png)
I...can't really fix this behavior. Clearly the best way is to just roll with it. If you want to just target all units with a 255 AoE, unflag both target ally and enemy in the vanilla game.
With my hack, the same rules apply. My code...shouldn't have any more problems now. A word of caution, however. If you use my hack, do not make your AoE 255 without the Math Flag on. Otherwise, you'll overflow. Make it 254 if you must.
<Patch name="Math Skill into Target Unit Only"> <Description>Overwrites Morbol Depth Routine. Takes the 255 AoE check and modifies it to target only tiles with units in them. Good for Random Fire Skills. </Description> <Location file="BATTLE_BIN" offset="0011220c"> 0800E003 00000000 0E00E012 00000000 00006290 02007490 00000000 0100942E 0100422C 21105400 02004014 01001026 010064A0 0002022A F5FF4014 05006324 2000FF27 0800E003 00000000 00000000 </Location> <Location file="BATTLE_BIN" offset="001148d4"> 04007194 </Location> <Location file="BATTLE_BIN" offset="001148f4"> 39403132 </Location> <Location file="BATTLE_BIN" offset="00114ae4"> e0002632 </Location> <Location file="BATTLE_BIN" offset="00114aec"> 2000c630 </Location> <Location file="BATTLE_BIN" offset="00114b40"> c0403032 </Location> <Location file="BATTLE_BIN" offset="00114b60"> 00402732 </Location> <Location file="BATTLE_BIN" offset="00114b68"> 823b0700 </Location> <Location file="BATTLE_BIN" offset="00114cbc"> 1c00b1a3 </Location> <Location file="BATTLE_BIN" offset="00114d68"> 21800000 01000434 1980033C D82D6324 85E4050C 00000000 </Location> </Patch> </Patches>
Couple of things to note before you use this hack: Again, this overwrites the Morbol Depth Routine. Be sure to check if you have any hack applied that writes over that space. This uses the Math Skill Flag to determine what has this property. Most patches don't use Math Skill anymore, so I deemed it a safe choice for flagging. Be mindful if you do use Math Skill in your patch with this patch enabled. 255 AoE still has a hard code on it, meaning if you make a still with 255 AoE, this hack will not work and it'll just make the whole map yellow. If you want your skill to hit both ally and enemy, unflag both boxes. The Check Ally/Enemy Routine is simply not designed for both of them. Even if I knew how to correct this behavior, it's not really my prerogative. F_MA*Y doesn't take Weapon Elemental :(