News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: Puchi Carat (GBC) text editing - 1st project, good progress but hit a roadblock!  (Read 2236 times)

FlutterSprite

  • Jr. Member
  • **
  • Posts: 6
  • Fairy Type
    • View Profile
Hi everyone!

I've recently started dipping my toe into ROM hacking - recently I've gotten really into the Taito arcade puzzler Puchi Carat, especially its characters and setting - though all the English releases of the game have notoriously poor translations, so I decided to see how feasible it would be to edit a new script into the GBC version of the game. It seemed like a pretty good starter project - the game's already in English, and it's not particularly complex or text-heavy.

My first attempts involved poking around the memory. I found out that the text is just printed as tiles on a map and is really easy to change on the fly. Perfect!



I immediately started going mad with power.





Of course, changing a tilemap and changing text are two different things, but from what I found out about how text is displayed, I figured that nothing particularly complicated was going on here. I downloaded Transhextion, and its "relative search" feature quickly turned up results for familiar dialogue. From there, it was easy to make a table (link!) and start decoding the text in the ROM.



It turns out the text box system for Puchi Carat is super flexible! When I made changes, I found that not only could text be any length (even proceeding to print off the box and off the screen if you let it) but scenes could consist of any arbitrary number of text boxes - good news for me, since I planned on adding in more detailed dialogue for my new script. There's tons of extra empty space available in the ROM too.

After determining which values corresponded to text, I deciphered all the control codes (link!) and found out how to build essentially any scene possible in the game - including moving the speech bubble arrow or changing the left or right side portraits. There seem to be no obvious limits to when they can be used - portraits can even be changed mid-dialogue on the same text box if you want, something the game never does.



I also made another wonderful discovery - though the game only ever prints 2 or 3 lines of dialogue at a time, all the line spacing in the dialogue is totally manual, so you can use all five lines if you want! Good news for me and my dream of a more fleshed out script.



Unfortunately, this is where I'm hitting my biggest roadblock. The way dialogue is presented in the ROM, it's just one scene after another, scattered in a few different locations. There's a control code to end a scene, but no code for the start of a scene, so the dialogue system must be pointing to specific locations in the ROM for the text. This code must also be initializing the portraits at the start, as the control codes for portrait swapping only show up when there's a need for the portrait to change mid-scene, which doesn't happen too often.

The big problem is... I can't find it! I tried taking the locations of the start of some scenes and converting them to pointers, but that didn't turn up any results - I also am not experienced enough to look at any of the disassembly code that the emulator spits out and be able to tell what's going on. I imagine there must be a table or something somewhere that assigns each scene in the game a location in the ROM to load the scene data from, but unfortunately I can't even begin to find out where to find it.

In the meantime, what I can do is bookmark and label the location of every scene in the game for future reference - while I'm getting that done, any help on how to move forward would be much appreciated! Thanks for reading - I hope I have more to show before too long!

danke

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 2067
    • View Profile
I took at a peek at Garnet's first line in story mode.
The line appears in the ROM at 2C:4326.

The pointer is hard-coded, and not in an easily editable way...
In BANK 3:
4790 is the BANK byte for the text. (Bank 2C)
47B8 is the HIGH byte base for the first letter. (40).

I can't figure out where it gets the LOW byte of the address, though. It seems to cycle through the bank and look for FE01, and switches to text mode. And checking the ROM, each new "cutscene" of text starts with FE01. Magic!

The ROM will write the text address in RAM at C31D for the BANK, C31E for the LOW byte, C31F for the HIGH byte. You can set breakpoints on these to help track where the pointers are being loaded from.

FlutterSprite

  • Jr. Member
  • **
  • Posts: 6
  • Fairy Type
    • View Profile
Ohh, interesting! It looks like FE 01 pulls double duty as the control code for switching the arrow to the left side and for marking the start of a cutscene, since all cutscenes start that way. Not storing the low byte probably saves on space and does cut down on the precision needed to address the dialogue, which is probably pretty convenient - I'm guessing it initializes the portraits based on the player and opponent data too rather than set them in control codes for every cutscene over and over. Thanks a whole lot for the help!! Looks like the next step is to hunt down some of these pointers and see if I can't get them to point to some new dialogue in the unused space.

July 04, 2019, 09:22:41 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
All right, I'm getting a chance to poke around again - seems like a newbie question, but what's the best way to browse the hex data in the ROM that would divide it up into banks? I checked the cartridge header and it looks like it uses MBC5 + RAM + Battery - when I'm digging around in the hex editor, I'm not sure how to tell what bank I'm in or how to convert the address the editor gives me into one that the game code understands (which is probably part of why I couldn't find any pointers before...)
« Last Edit: July 04, 2019, 09:22:41 pm by FlutterSprite »

danke

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 2067
    • View Profile
I would suggest using the BGB emulator. This has a full-featured debugger, which has a hex editor that will divide into banks.

Otherwise, each 4000 bytes is a bank, and you can do the math to find them in a regular hex editor.

FlutterSprite

  • Jr. Member
  • **
  • Posts: 6
  • Fairy Type
    • View Profile
Got it! I've got BGB and I'm poking around in it now... I can't help but feel I'm already out of my depth, but I'll keep at it and see if I can't figure this out, haha.

danke

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 2067
    • View Profile
I found the pointer list.

3:4032 = 2443, which, when combined with the Bank 2C, points to 2C:4324 (B0324)... the location of the FE01 that starts Garnet's script.

3:4032 is C032 in the ROM. To get ROM addresses, you need to multiply the bank by 4000. Then you take the address, minus 4000, and add it to the bank address.
So (03 * 04000 = C000), then you take (4032 - 4000 = 0032), then you add the results, (C032).

But the only thing missing in the pointer table is the Bank pointer. But it looks like text is only in Banks 2C, 2D, and 2E. (2F is completely empty, so that should give you plenty of space.) Looking at the pointer list, you can see the pointers climb up, but then reset at C050, so that's likely the next Bank (2D). Or they are all Bank 2C, and the next bank's pointers are elsewhere.

FlutterSprite

  • Jr. Member
  • **
  • Posts: 6
  • Fairy Type
    • View Profile
Wahooo! That's perfect! I'll have to see if addressing new text is as easy as changing those pointers - when I was messing around before, I tried changing just the bank, and got a pretty strange result - Garnet's intro cycling through all of By's story text, but not ever ending even when it came across the end-of-cutscene flag. Once I get to poking around again, I'll have to see if it's possible to point to a brand new location and get a functioning result - 2F seems like a good place to start. Thanks again!!

UPDATE: It looks like 2C contains the text for every character's intro and ending sequences, as well as the versus dialogue for Garnet and Thyst's stories. To experiment a bit, I tried changing the pointer at 3:4790 from 2C to 2F - sure enough, every character printed out endless blank characters during their intro. Then, I copied the start of Bank 2C to Bank 2F, only Garnet's intro and ending and Thyst's intro - sure enough, now Garnet and Thyst's intros work as before, while everyone else's intros printed endless blank characters. Success! Looks like you can store and retrieve text in 2F after all!

I wonder if the data at the beginning of Bank 2C might have something to do with indicating what banks to pull text from for the pre-battle dialogue of other characters - it starts with "2C 2C 2C 38 38 38 38 2D 2D 2D 2D 2E 2E 2E", and knowing now that only banks 2C, 2D, and 2E have text in them, it looks an awful lot like it may be doing some redirecting here. The hex values that follow look a lot like more pointers to me too.

It doesn't seem like you'll be able to store all the different characters' intros and endings in different banks, since they normally are stored all together, but I have high hopes that all the intros and endings can be moved to 2F and that the mid-story dialogue could stay in 2C, 2D, and 2E and be redirected per character - 2F has more than enough room for all the intros and endings and even for them to be a good deal longer than before, and the space freed up in 2C would be really substantial!
« Last Edit: July 07, 2019, 10:31:13 pm by FlutterSprite »

danke

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 2067
    • View Profile
I wonder if the data at the beginning of Bank 2C might have something to do with indicating what banks to pull text from for the pre-battle dialogue of other characters - it starts with "2C 2C 2C 38 38 38 38 2D 2D 2D 2D 2E 2E 2E", and knowing now that only banks 2C, 2D, and 2E have text in them, it looks an awful lot like it may be doing some redirecting here. The hex values that follow look a lot like more pointers to me too.

It's entirely possible that there is some text in Bank 38. I never thought to check. But if that's the case, then it may be even easier to move text around!

FlutterSprite

  • Jr. Member
  • **
  • Posts: 6
  • Fairy Type
    • View Profile
Now that I know how to convert bank addresses to full hex addresses in the ROM, I took a peek in Bank 38, and sure enough - more story text, right off the bat! Here's the versus dialogue for Aqua!



The full string of hex codes at the start of Bank 2C is "2C 2C 38 38 38 38 2D 2D 2D 2D 2E 2E 2E 39 39" - that's 15 codes, which lines up with 15 playable characters, and also knowing both Garnet and Thyst are in 2C and Aqua is in 38, it seems to line up with the order the characters are usually presented, too. Which means that hidden characters Dale and Kumikumi's story text might be in 39... let's take a peek.



What do you know! That's Dale's versus dialogue! My hunch was right!! So it looks like I found where it stores which character uses which bank for dialogue - this is huge! I'll have to mess around with this and see if changing around these values changes the text that shows up!

UPDATE: I managed to do a successful 'text transplant'! I copied Garnet and Thyst's versus dialogue from Bank 2C to the equivalent location in Bank 2F, and then deleted it all out of Bank 2C - then I changed the "2C 2C" at the start of Bank 2C to "2F 2F". It worked! The game runs as normal, reading Garnet and Thyst's dialogue from 2F instead of 2C. That clears up a bunch of space in 2C to expand the intros and endings. Really making progress!
« Last Edit: July 08, 2019, 12:58:45 am by FlutterSprite »

danke

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 2067
    • View Profile
Congrats!

FlutterSprite

  • Jr. Member
  • **
  • Posts: 6
  • Fairy Type
    • View Profile
Thank you!! I think my next task now is to find and map out where all the mid-story cutscene pointers are, and then actually get to work on writing my expanded script now that I know this is possible. Now that I have a clearer idea of where this stuff is stored and how, it shouldn't be too difficult!

One last quick question! What's a good hex editor for adding lots of bookmarks and comments to a ROM? Right now I'm using Translhextion, but it only gives you eight bookmarks which is not nearly enough, haha...

danke

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 2067
    • View Profile
One last quick question! What's a good hex editor for adding lots of bookmarks and comments to a ROM? Right now I'm using Translhextion, but it only gives you eight bookmarks which is not nearly enough, haha...
I believe WindHex will allow for many bookmarks. IIRC, it stores bookmarks into the table file.