Users browsing this thread: 1 Guest(s)
Making a Weapon Deal 2x Damage to a New Monster Type

#1
Posts: 61
Threads: 18
Thanks Received: 1
Thanks Given: 47
Joined: May 2014
Status
None
Note that this thread is tagged for the OpCodes that it highlights or explains (BIT, BEQ, LDA, INC)
This post has been edited due to replies to this post.

Here's what I labored over today to try and figure out some hacking (any criticisms or corrections welcome).  For this episode of newbie coding, we are looking at having a new special weapon attack that allows the weapon deal 2x damage to a new monster type that we want to add to the game.  The monsters in the game can be marked (aka "flagged") for certain properties/traits/types and then other actions are based from what traits the monster has for those special flags.  In this case we'll be looking at special byte 3, which is where a group of the flags for monsters is stored.  For instance, monsters in the game can already be marked human or undead.

Here is the result of my code on how to do this, by reverse engineering Ghost XIII's "dragonslayer" patch, which uses a copy of the code from the "2x human" effect in the C2 bank.
==========================================================================
$3C95 = Special Byte 3:
Dies at 0 MP, No name, Human, Auto critical if Imp, Undead

Note: Technically the bits of this Byte are:
Bit 1: Dies at 0 MP
Bit 2: nothing (replaced with ignore-ignore defense flag if patched)
Bit 3: No name (used by something, it sounds like)
Bit 4:
Bit 5: Human
Bit 6:
Bit 7: Auto critical if Imp
Bit 8: Undead


Meaning $3C95 is the address for some special byte that, depending on the individual bits (0s or 1s) in each space of the byte (8 bits = byte) acts as a flag, and other effects in the game act based on those identifying flags.  In this code, $3C95 is monster data, letting us know if the monster is human or undead, etc.


The code for dealing 2x damage to Human:
Code:
C2/38F2: B9 95 3C     LDA $3C95,Y
Loads the special byte into the A register, indexed by Y.  This means that whatever is in the Y register will increase the address, looking at bytes after $3C95.  Why would we look at different bytes?  Each special byte will be different for each monster, which allows for each monster to have its own flags.  What is probably happening is that the special bytes are all sitting in a line, with each byte corresponding to a different monster.  The indexed search allows the Y register to be a trigger that changes the search from $3C95 (just one special byte for monster 1) to whichever monster is being targeted. 

Now that we've grabbed the special byte for weapon we're using, we'll compare what's loaded in A (the special byte, a.k.a. the flags) to the desired flags within the byte via BIT below.
Code:
C2/38F5: 89 10        BIT #$10
This is checking to see if the 4th bit, the human flag, is set, because 10h (10 in hexidecimal) is 16 in decimal and in bit form, this is literally and physically 00010000.  But wait!  Why do we call that bit with a 1 the 4th bit?  We call it the 4th bit not because it's 4th from the left, but instead the 5th from the right!  The order is REVERSED for all 8 bits based on how hexadecimal progresses (01h = 00000001, 02h = 00000010, etc.) and the first bit is called "bit 0".  If the byte at $3C95,Y was 10000001, then the 4th bit isn't set, the 0th bit and 7th bit are, so the BIT function would.  Checking for both 10000001 would be done via BIT #$81.  Technically, any matches of bits from the compared bytes results in a non-zero amount, meaning the Z flag isn't "set."  The Z flag is a special tracking device during calculations that is set to 1 when a zero occurs.  If we check 10000001 against 0001000 then no matches occur, so because of the BIT functionality, the Z flag is set.
Code:
C2/38F7: F0 04        BEQ $38FD   (Exit if target not human)
BEQ doesn't branch if "equal", it branches if something is ZERO, or more technically, if the zero flag is set.  Since previously using BIT, if the Z flag wasn't set from a comparison of two similar properties, we wouldn't get zero!  So this branches if the comparison fails.  If the comparison succeeds, then a non-zero amount would occur and the Z flag isn't set, and we keep going.

Code:
C2/38F9: E6 BC        INC $BC
C2/38FB: E6 BC        INC $BC     (Double damage dealt)
C2/38FD: 60           RTS
This doubles the damage and returns out of the routine.

Now if we wanted to make 2x damage to something other than human, then we just enter this code into another special weapon attack that we'd like to replace (such as the ogre nix breaks code at C2/3ECA).  This is limited to certain areas because there are only 15 possible special attack effects (other than normal attack) according to the way the ROM currently refers to this data.

This code must be then changed with the BIT function to a different comparison that represents the new bit of the Special Byte 3 which will be marked onto your monsters.  Bit 4 is unused, for example, so BIT #$08
Code:
C2/38F5: 89 08        BIT #$08
would compare 00001000, or the 4th bit from the right (the "3rd" bit), and in the FF3USME editor, we can go to any monster and check on the 4th box for that section, 3rd below from the 0mp=death checkbox.
  Find
Quote  

#2
Posts: 3,966
Threads: 279
Thanks Received: 234
Thanks Given: 56
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
Good little detailed tutorial!

There's only a small thing that seems not really on point:

(01-30-2016, 09:45 PM)ReturnerScum Wrote: Technically, any matches of bits from the compared byte versus the BIT operation in the A register results in a "1" bit in the byte of the A register.  So all 1s that match go into the A register byte.

The accumulator remains unaltered from the BIT operation. It's like an AND that doesn't affect A and the result is stored in Z (like you say after) and not in A.
  Find
Quote  
[-] The following 1 user says Thank You to madsiur for this post:
  • ReturnerScum (01-30-2016)

#3
Posts: 290
Threads: 3
Thanks Received: 40
Thanks Given: 1
Joined: Apr 2012
Reputation: 9
Status
None
(01-30-2016, 09:45 PM)ReturnerScum Wrote: The code for dealing 2x damage to Human:
Code:
C2/38F2: B9 95 3C     LDA $3C95,Y
Loads the specialy byte into the Y register, which will be compared by whatever is put into the A register via BIT below

That's not quite right. The Y register is unaffected; this is actually loading the value into A, indexed by Y at $3C95. You can basically read this as:

Load value at ($3C95 + Y) into A.

So if Y = 0, it loads the value at $3C95. If Y = 7, then it loads the value at $3C9C. If Y = B4 (180), then it loads the value at $3D50.

(01-30-2016, 09:45 PM)ReturnerScum Wrote:
Code:
C2/38F5: 89 10        BIT #$10
This is checking to see if the 5th bit, the human flag is set, because 10h (10 in hexidecimal) is 16 in decimal and in bit form, this is literally and physically 00010000.  But wait!  Doesn't it look like it's checking for a 1 in the 4th bit?  No, we're just noobs, because the order is REVERSED for all 8 bits based on how hexadecimal progresses (01h = 00000001, 02h = 00000010, etc.  If the byte at $3C95 was 10000001, then the 5th bit isn't set, the 1st and 8th are, so nothing is loaded into the A register for comparison or calculation.  Checking for both 10000001 would be done via BIT #$81.  Technically, any matches of bits from the compared byte versus the BIT operation in the A register results in a "1" bit in the byte of the A register.  So all 1s that match go into the A register byte.

The only quibble I have here (aside from what Madsiur mentioned - that BIT doesn't actually alter the A register at all) is that most of the time, you will see people start at 0 instead of 1 when talking about individual bits in a byte. So, while BIT #$10 does check the fifth bit, most documentation or commentary will call it bit 4. Likewise, in your second example (BIT #$81), a potential hacker is more likely to see those bits listed as bit 0 and bit 7, rather than 1 and 8.

Otherwise, this is a pretty good jumping point for anyone that wants to start writing new weapon effects.


GET A SILK BAG FROM THE GRAVEYARD DUCK TO LIVE LONGER.

Brave New World
  Find
Quote  
[-] The following 1 user says Thank You to Synchysi for this post:
  • ReturnerScum (01-31-2016)

#4
Posts: 3,966
Threads: 279
Thanks Received: 234
Thanks Given: 56
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
I've mode this in the tutorial section though I realize now we have no coding section here so I've put it in the general section. And no, coding is not a branch of hex editing. You can code without knowing even 1 opcode hex value and having never touched a hex editor.
  Find
Quote  

#5
Posts: 2,548
Threads: 98
Thanks Received: 147
Thanks Given: 156
Joined: Aug 2009
Reputation: 52
Status
Nattak\'d
I have a bit of a question regarding this: I just attempted to do this, also for dragons. I set it up to the weapon extra effect of 0xC 'Curative attributes', which is the Heal Rod code which I have unused. So, I set up my weapon, then, since I'm already using the unused bit 4 for the Special Byte 3 flags, I went with the one directly after the 'is Human' flag, which would be unused bit 6... So, I set the dragon monster to have this flag, and tested it out, and it would not pick up the flag being checked and thus skip the double damage part:

$C2/3F7E 4C DA 41    JMP $41DA  [$C2:41DA] (had to jump to free space due to needing 1 more byte)
$C2/41DA B9 95 3C    LDA $3C95,y[$7E:3C99]
$C2/41DD 89 20       BIT #$20
$C2/41DF F0 04       BEQ $04    [$41E5]
$C2/41E5 60          RTS

Now, according to this tutorial I'm pretty sure I did it correctly, putting the BIT check as $20, because since it is the bit directly after the Human one, it would be $20, right?
00100000 = bit 6 (unused) = 32 dec = 20 hex = 89 20

But like I say this did not work. So I tried just putting the human check of A9 10, and it seems to work as intended:

$C2/3F7E 4C DA 41    JMP $41DA  [$C2:41DA] (had to jump to free space due to needing 1 more byte)
$C2/41DA B9 95 3C    LDA $3C95,y[$7E:3C99]
$C2/41DD 89 10       BIT #$10
$C2/41DF F0 04       BEQ $04    [$41E5]
$C2/41E1 E6 BC       INC $BC    [$00:00BC]
$C2/41E3 E6 BC       INC $BC    [$00:00BC]
$C2/41E5 60          RTS        

But I am confused as to why it does, and why what I first tried did not. The monster in question has the new unused bit directly after human, not human, so...why would it still work with $10? And why wouldn't it work with $20, which is the unused bit I intended to use. Thank you.

EDIT: Annnnnd crap I see that this 2x to dragon-type weapon/flag is also triggering on 'is human' monsters, probably from sharing the BIT #$10 bit I'd imagine... So that's a fail. So my question persists about why the unused bit 6 I'm trying to use is not working.


We are born, live, die and then do the same thing over again.
Quote  

#6
Posts: 3,966
Threads: 279
Thanks Received: 234
Thanks Given: 56
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
Code:
$C2/41DD 89 20       BIT #$20
$C2/41DF F0 04       BEQ $04    [$41E5]
$C2/41E5 60          RTS

This is not good I think. Where do you want to branch? Why do you put a condition with nothing after if you want to branch to the RTS? F0 04 will branch 4 bytes after the command so 3 bytes after the RTS.
  Find
Quote  

#7
Posts: 2,548
Threads: 98
Thanks Received: 147
Thanks Given: 156
Joined: Aug 2009
Reputation: 52
Status
Nattak\'d
Ah I just copy/pasted that from the debugger, when it did not pick up the flag. The actual code is a direct copy (except for the special byte 3 bit) of the 'is human' code, so it looks like it would branch 4 bytes past the double damage part to the RTS, yes, if not a Dragon. Problem is it is reading a dragon-type monster as a not dragon-type monster and branching to the RTS.
I have my weapon set up to the extra effect of the Heal Rod code, where it jumps to free space because I needed 1 more byte, and there I have the duplicate Human flag code but with BIT $20 instead of 10, and I have the special byte 3 of the monster data unused bit 6 under the Human flag checked. I'm not sure what I'm doing wrong here. Sad Sad Sad Sad Sad Sad


We are born, live, die and then do the same thing over again.
Quote  

#8
Posts: 48
Threads: 7
Thanks Received: 0
Thanks Given: 0
Joined: Dec 2017
Reputation: 0
Status
None
Does it read a normal enemy as a dragon-type enemy? If not, does it read a human-type enemy as dragon-type?

Also, for this line:

Code:
$C2/41DA B9 95 3C    LDA $3C95,y[$7E:3C99]

The value in brackets indicates 3C99, yet the bytes used are 3C95. It is a typo or is the "y" value adding 4? (I'm used to high-level programming languages, ASM is still baffling me, so my apologies if my questions are stupid! Tongue )

Finally, about the BIT opcode, there is a flag that targets "bit 6 or 14" specifically, yet there is no info about how to set up that flag
  Find
Quote  

#9
Posts: 2,548
Threads: 98
Thanks Received: 147
Thanks Given: 156
Joined: Aug 2009
Reputation: 52
Status
Nattak\'d
With BIT #$20 set, which I believe is the flag right after the 'is human' one (need conformation), when the weapon in question attacks a monster, it breakpoints in the debugger, but it always will branch past the double damage part. If I use BIT #$10, it will do the double damage part but for both 'is human' and 'is dragon', so that's not right. I'm fairly sure BIT #$20 is the correct one for the flag right after Human, but tis not working.

About that y value bracket, that's not a typo, that's how the debugger is putting it, but I have no idea what to make of that as I have extremely little assembly/coding knowledge myself lol.

This Heal Rod extra effect seems okay to use for it, as it is being picked up in the debugger for the weapon in question,
but my new flag for the monster being a dragon is not and branches to the return...


We are born, live, die and then do the same thing over again.
Quote  

#10
Posts: 3,966
Threads: 279
Thanks Received: 234
Thanks Given: 56
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
For the record there was a problem with the heal rod effect being once-per-strike instead of once per target.You need to switch the two entries in the pointer table, so $C23DE5 = 7E3F and $C242F9 = 8C38. In his case, Gi Nattak had room at $C21692 so he changed $C23DE5 to 9216.

Finally hooking up the following code did the job:
Code:
org $C21692
LDA $3C95,Y
BIT #$20
BEQ .branch
INC $BC
INC $BC
.branch
RTS
  Find
Quote  
[-] The following 1 user says Thank You to madsiur for this post:
  • Gi Nattak (01-29-2018)



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite