+  RHDN Forum Archive
|-+  Romhacking
| |-+  General Romhacking
| | |-+  SNES ROM Expansion and Moving Pointer Tables.
Pages: [1] 2 3 ... 5
Author Topic: SNES ROM Expansion and Moving Pointer Tables.  (Read 1 times)
DarknessSavior
Guest
« on: August 13, 2007, 01:51:17 pm »

FF:MQ does have space issues in some parts (item/monster lists, I'm looking at YOU!), but many of the other portions (dialogue, the menu, and such) would easily fit more text if I just had the room. I know SNES expansion is easy, but is moving the pointer tables? I have no idea how to do that, and I need to do it for Fire Emblem as well (already expanded the ROM and KingMike had moved the item and character name ptables over already, but not the dialogue and status menus and such).

Can anyone point me to a doc that tells how to do this, or perhaps explain it? I don't think there is one (I looked at all the pointer-related docs already).

~DS
Nightcrawler
Guest
« Reply #1 on: August 13, 2007, 02:18:31 pm »

Moving pointer tables is very game specific. And you may or may not need some assembly knowledge to do it. It's going to depend on how the game finds those pointers.

I'm assuming you've already found a group of pointers that point to text? You need to know how the game finds that group of pointers. Sometimes, it's easy and you can do simply by finding the SNES address where the group of pointers start and then do a search for that offset. If you're lucky, you'll find another pointer that points to that section. Might be 24-bits, Might be 16-bits long. Could be either.

Anyway, there's a pointer to the group of pointers. Changing that pointer will allow you to relocate the entire group of pointers and everything they point to to a new location.

It's really tough to say exactly how you should do this. As I said, each can be different on how it stores and locates it's data. Could be a one step easy as pie process or it could require several modifications.

Since you don't know assembly yet, I'd start with finding the beginning of the group of pointers and seeing if you can find something that points to them. Although, there's a good chance this is a simple job if you want to get to know a debugger. A trigger or two might be all you need to find the information you're looking for.
Gideon Zhi
Guest
« Reply #2 on: August 14, 2007, 12:30:27 am »

I do want to add that though this typically does require an assembly-level hack, it's usually a very easy assembly-level hack. Hell, a similar hack was _my_ first ASM hack!

I'd be happy to post some sample code for you to peruse if you'd like.
DarknessSavior
Guest
« Reply #3 on: August 14, 2007, 01:16:45 pm »

Thanks for the help guys. I'll look into it pretty soon, I'll (well, I'll try to) find the pointer tables for the dialogue and the menu (those are the only ones that use linebreaks to determine the length of a string, so expanding those would be the best).

So in this case, I know I should probably set a read breakpoint, but where should I do it, at the menu text (obviously, converted to an SNES addy, via Lunar Address)?

And Gideon, thank you, that would be extremely helpful: I find that if I can look at ASM code and actually apply it to something, it makes it easier to understand.

~DS

mit_mis
Guest
« Reply #4 on: August 14, 2007, 02:18:58 pm »

I believe you should put a read breakpoint at the beginning of the pointer table and see how it is loaded.
Gideon Zhi
Guest
« Reply #5 on: August 14, 2007, 02:25:48 pm »

Here's the code from Ys 4.

Code:
;Pointer calculate voodoo
;$81/8003: 8E 8D 08     STX $088D [$00:088D]      A:0000 X:0002 Y:0001 D:0000 DB:00 S:01EA P:envmxdiZc HC:688 VC:152
;$81/8006: 8E 8B 08     STX $088B [$00:088B]      A:0000 X:0002 Y:0001 D:0000 DB:00 S:01EA P:envmxdiZc HC:752 VC:152
;$81/8009: 8A           TXA                       A:0000 X:0002 Y:0001 D:0000 DB:00 S:01EA P:envmxdiZc HC:816 VC:152
;$81/800A: C9 FF FF     CMP #$FFFF                A:0002 X:0002 Y:0001 D:0000 DB:00 S:01EA P:envmxdizc HC:858 VC:152
;$81/800D: D0 0D        BNE $0D [$801C]           A:0002 X:0002 Y:0001 D:0000 DB:00 S:01EA P:envmxdizc HC:906 VC:152
;$81/801C: C2 20        REP #$20                  A:0002 X:0002 Y:0001 D:0000 DB:00 S:01EA P:envmxdizc HC:954 VC:152
;$81/801E: C9 E2 04     CMP #$04E2                A:0002 X:0002 Y:0001 D:0000 DB:00 S:01EA P:envmxdizc HC:1002 VC:152
;$81/8021: 90 0E        BCC $0E [$8031]           A:0002 X:0002 Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:1050 VC:152
;$81/8031: C9 58 02     CMP #$0258                A:0002 X:0002 Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:1098 VC:152
;$81/8034: 90 09        BCC $09 [$803F]           A:0002 X:0002 Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:1146 VC:152
;$81/803F: A2 8C 00     LDX #$008C                A:0002 X:0002 Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:1194 VC:152
;$81/8042: 0A           ASL A                     A:0002 X:008C Y:0001 D:0000 DB:00 S:01EA P:envmxdizc HC:1242 VC:152
;$81/8043: 18           CLC                       A:0004 X:008C Y:0001 D:0000 DB:00 S:01EA P:envmxdizc HC:1284 VC:152
;$81/8044: 69 00 80     ADC #$8000                A:0004 X:008C Y:0001 D:0000 DB:00 S:01EA P:envmxdizc HC:1326 VC:152
;$81/8047: 85 4F        STA $4F [$00:004F]        A:8004 X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:1374 VC:152
;$81/8049: E2 20        SEP #$20                  A:8004 X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:064 VC:153
;$81/804B: 8A           TXA                       A:8004 X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvMxdizc HC:112 VC:153
;$81/804C: 85 51        STA $51 [$00:0051]        A:808C X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvMxdizc HC:154 VC:153
;$81/804E: C2 20        REP #$20                  A:808C X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvMxdizc HC:204 VC:153
;$81/8050: A7 4F        LDA [$4F] [$8C:8004]      A:808C X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:276 VC:153
;$81/8052: 85 4F        STA $4F [$00:004F]        A:84C6 X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:354 VC:153
;$81/8054: E2 20        SEP #$20                  A:84C6 X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvmxdizc HC:412 VC:153
;$81/8056: AD F3 08     LDA $08F3 [$00:08F3]      A:84C6 X:008C Y:0001 D:0000 DB:00 S:01EA P:eNvMxdizc HC:460 VC:153
;$81/8059: 8D F5 08     STA $08F5 [$00:08F5]      A:8405 X:008C Y:0001 D:0000 DB:00 S:01EA P:envMxdizc HC:516 VC:153

org $81801C
  REP #$20
  ASL A
  CLC
  ADC $088B
  TAX
  LDA $8F9200,X
  STA $4F
  SEP #$20
  LDA $8F9202,X
  STA $51
  JMP $818056

The original code starts with the string # in X, runs a bunch of hardcoded string # compares to figure out which segment (bank, in this case) the text is in. If it hit any of the branch conditions, it would have done some subtraction, but we're okay.

In this case, it's accessing String 0002 from bank 8C. Since our pointers are originally 16-bit, it has to double the string number then (because it's a lorom game) add #$8000 to get the address of the pointer. If the pointer table started at 8C:CC00, it'd add #$CC00 instead. Then it stores the full pointer address loads into 4F-51, and loads [4F] indirectly to get the value of the pointer, which it then places right back into 4F.

My code is comparatively simple. Rather than split the pointer table across multiple segments I've mashed it all into one, so there are no messy compares to deal with. The string number is still stored to 088D and 088B, but all I do is *triple* the string number instead of doubling it, load directly from my new pointer table at 8F9200, then slot the resultant pointer into its proper place in memory.
DarknessSavior
Guest
« Reply #6 on: August 14, 2007, 02:36:22 pm »

*saves that*

I'm gonna give that a thorough looking through when I get home and have all of my reference docs. Thanks though, it doesn't look as complicated as some of the other things I've dug through (CT default character code, for example, was like...2 MB of code...-.-).

So I should find the pointer table, then set a read breakpoint for its SNES addy. Then I'll get something similar to this, hopefully. I'll do the menu first, since that'd probably be the easier of the two.

~DS

New Post: *grumbles*

Well, that sucks. I tried finding the pointers themselves yesterday, and I couldn't even do that (and I replaced all of the FE pointers by hand, so I'm not pointer-stupid). I think that perhaps FF:MQ uses a system of pointers that I'm unfamiliar with.

The location for the menu is at 1AD09. The pointer for that should be F9AC, right? Searching for that comes up with nothing (at least, searching upward, there's something lower, but that shouldn't be a pointer, right?).

Same thing for the dialogue. The first line is at 1F912. The pointer should be 02F9. Searching for that comes up with nothing.

Is there something that I'm not doing right, or is this just a separate system than the "standard" pointers I'm used to?

~DS#2.

« Last Edit: August 15, 2007, 01:11:21 pm by DarknessSavior »
KingMike
Guest
« Reply #7 on: August 16, 2007, 01:01:22 am »

You're confusing NES and SNES.

$1AD09, huh?

You need to know if your ROM has a header and if it's a LoROM or HiROM game.
ZSNES or SNES9X will tell you when booting up if it's Lo or Hi.

If the game has a header, subtract $200 from the header. Otherwise, skip this step.

Now, if it's a HiROM, just drop all but the last four digits. Go to the next step.
If it's a LoROM (likely for games under 2MB), you still drop all but the last four digits. But now you need to make sure the remainder is between $8000 and $FFFF. (just $8000 if it isn't).

So, it looks like we should have $AD09 (assuming no header).

Reverse the bytes, so we get 09 AD.
Gideon Zhi
Guest
« Reply #8 on: August 16, 2007, 09:39:27 am »

Quote from: KingMike on August 16, 2007, 01:01:22 am
If the game has a header, subtract $200 from the header. Otherwise, skip this step.

No. If the game has a header, use a hex editor to delete the header :p Header data in SNES roms is largely vestigal and should generally be removed prior to starting the hacking process.
KingMike
Guest
« Reply #9 on: August 16, 2007, 10:06:40 am »

I know. I do that, but I was just explaining to him how to calculate SNES pointers. Wink
creaothceann
Guest
« Reply #10 on: August 16, 2007, 10:57:06 am »

It's noteworthy that these $0200 bytes are the copier/dumper header, or ROM file header if you want.

SNES ROMs also have an internal header of their own which (usually) follows Nintendo's standards. Its offset is $7FB0 or $FFB0 or even somewhere else, depending on the cartridge format.
Nightcrawler
Guest
« Reply #11 on: August 16, 2007, 11:52:36 am »

Quote from: Gideon Zhi on August 16, 2007, 09:39:27 am
Quote from: KingMike on August 16, 2007, 01:01:22 am
If the game has a header, subtract $200 from the header. Otherwise, skip this step.

No. If the game has a header, use a hex editor to delete the header :p Header data in SNES roms is largely vestigal and should generally be removed prior to starting the hacking process.

If you're going to do that, you best use a patcher custom or otherwise that supports BOTH. I got nothing but headaches with the Wozz translation releasing a patch for a headerless ROM when the ROMs most people had contained a header. Far more nonsense came of it than my Dual Orb 2 patch which was for a ROM w/header and had several times more people using it. I will never make that mistake again. It's not worth user base out lashing! That's important when you only have a user base on the order of a few dozen.  :laugh:

Custom patcher for me from here on out regardless of any formats that may arise. This nonsense has been going on for too long.
Gideon Zhi
Guest
« Reply #12 on: August 16, 2007, 12:13:05 pm »

You can always re-add the header once the project's done if you need to :p
Nightcrawler
Guest
« Reply #13 on: August 16, 2007, 12:17:26 pm »

Quote from: Gideon Zhi on August 16, 2007, 12:13:05 pm
You can always re-add the header once the project's done if you need to :p

Then why take it out to begin with? Tongue Tongue
creaothceann
Guest
« Reply #14 on: August 16, 2007, 12:20:39 pm »

To make working with the ROM easier?
Pages: [1] 2 3 ... 5  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC