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

Author Topic: [NDS] Ghost Trick "NG+ Mode" (Warning: Game Spoilers Discussed)  (Read 370 times)


  • Jr. Member
  • **
  • Posts: 3
    • View Profile
This is my first ROMHack but it's been a lot of fun while also extremely frustrating. My primary goal is to replace all instances of a particular character's talk sprites (both the full-scale talk sprites and the smaller mini talk-sprites that accompany thought bubbles, etc), but this game is pretty un-documented from what I've found. So I've been mostly working from scratch. My "I'm dreaming" vision for a "complete" version of this would somehow implement a button or something that lets you turn this on/off (revert to the original as desired), but my primary focus is just getting it to work to start with.

Specifically, I want to play as the cat the whole time.  ;)

After a lot of trial and error, I recently made some tangible progress - I've found a kind of "master list" of the sprites in cpac_3d.bin (note: I found an ancient thread somewhere in my initial research that implied cpac_2d.bin was where I might find these, but that was not correct, all talk sprite data is in cpac_3d.bin. cpac_2d.bin appears to mostly contain background assets), around memory address 04ED4280. They are of the following format:

## ## ## 00 ## ## 00 80

(I found them while poking around in CrystalTile's tile viewer because the 00 80 created these distinct black and salmon bars viewed with tile form GBA 8bpp. I may get into this later but that tile form is what you are going to want if you ever want to look at the background assets in cpac_2d.bin.)

Basically I found that if you copy the hex code of whatever sprite/asset you want and paste it over the hex code of the asset you want to replace, every single instance of that asset in the game will be replaced.

I actually have a full list of the hex codes pointing to all of the talk sprites. I can post a list later if there is interest. What concerns ME, are the protagonist's talk sprites, values listed here:

9C4003007C190080neutral smirk
185A030044190080neutral frown/serious
5C730300E4180080hand on chin/thinking
38A50300501A0080the angular gag “shocked” face
18D90300BC090080ghost with sunglasses
D4E20300D81B0080shrug with one palm out
ACFE0300CC190080mouth slightly open/gape/slight surprise
7818040098180080Facing down, flat line lips, serious and melancholy
103104009C180080angry/emotional yelling

And the code for the cat, which I want to use to replace all of these, is:

AC 49 04 00 54 10 00 80

(In addition for these full-size sprites, I also wanted to replace the mini-talk sprites, but thankfully that was easy. I replaced 502A0D00E4020080 at memory address 04ED45E8, with 342D0D0064020080.)

The good news is that I playtested the first 14 chapters of the game and confirmed that this works perfectly.

The bad news is, as anyone who has played this game knows (and this is unfortunately impossible to discuss without game spoilers so I apologize)... there is another character who uses those same sprites from chapter 15 onward, and well, I have unfortunately confirmed that this janky way of doing it turns him into a cat too:

Moreover, both characters - protagonist and this guy - use almost the full range of sprites in the chapter, too. There is virtually no easy way about this as it currently stands.

My other problem is that I had hoped to eventually give the cat a full range of original emotions/reactions to replace the originals, but that is going to be extremely difficult because the source images are in a format I can't make heads or tails of. All of the data in this game does not seem accessible using any of the NDS tools I've tried - they all find the main containers (e.g. cpac_3d.bin, cpac_2d.bin, etc...) but not the individual files within, likely because the format is unrecognized. I've been able to get as far as I have mostly by blacking out random blocks of hex code/tiles and loading the ROM to see what changes. Unfortunately, I'm hitting the limits of what I can do with that approach. For example, I narrowed down that the location for the sprite of the protagonist "thinking" is from ~04F0D340 - 04F0EC40, because when i messed with the data in that portion the sprite got messed up; but I have no idea how to actually make sense of it as a file and CrystalTile doesn't see any individual files within cpac_3d.bin.

At any rate, since I am probably going to need to look at the code for the specific scenes where BOTH characters are present, I have started looking at all the bits in this ROM with names like "st01/st01_game000_Expand.xml.lz". First of all, these are all compressed, so in order to read them I needed to export them from CrystalTile and decompress them with Batch77 and then re-compress them to re-insert and check my changes. I'm still digging through these, but so far, this is what I can gather on their format--

  • They appear to be separated by location. st01 referring to the junkyard, st02 the supervisor's office basement, st05 Lynne's apartment, st14 submarine, etc. The stages that exist as labeled in the ROM are 01, 02, 03, 04, (04_01?), 05, 06, 07, 09, 11, 13, 14, and 15.
  • Modifying the first legible line in decompressed "st01/st01_root.xml" from "st01/st01_game000_Expand.xml" to anything else (for example, "st14/st14_game050_Expand.xml") will cause whatever that scene is to be loaded when you select "New Game," which is a thankfully pretty easy way to test late game stuff without a completed game file.
  • Lines of text appear to be referred to in these scenes in the format "m##_####." The first two digits match the stage level in most cases. For example, if it is found in a st01 file, it will likely be of format m01_####.
  • The "demo" files refer to animated cutscenes, such as the "watch so-and-so get murdered" sequences. These are sometimes called from within a game file on a different stage (for example a st01 demo file might be called from an st14 game file), in which case any associated dialogue will have an m## digit matching the game stage as opposed to the demo stage.
  • For reasons I have not yet been able to determine, it does not appear to be possible to call an m##_#### that does not exist already in the scene. For example, if I try changing m01_0090 to m01_2000 or another value that is not already present in that scene, it will load the protagonist saying "Will I really be able to find the truth before dawn...?" It loads that same text regardless of the scene. I have no idea what causes this.
  • At the bottom of these files is what appears to be a directory of sorts that I thought were instructions on where the referred to items (models, text, etc) are drawn. However, blocking out this entire portion of code and re-inserting into the ROM does absolutely nothing.
  • The reference "m##_####" refers to a specific line of dialogue AND TALK SPRITE. If I swap one with another in the same scene, the text changes as WELL as the sprite.

What I really need to understand is where these "m##_####" variables(?) are defined, and if I can figure that out, what part of that tells it what sprite to use. My assumption is that they must be defined in the specific stage .xml files because otherwise there should be no reason they can't load outside the ones already included. I've been trying to mess around with other bits and pieces of these files outside of the legible text but so far I haven't narrowed it down that far, and more often than not messing with it too much just causes the ROM to crash before it can load the scene at all.

So this is where I am currently at. Still trying to make heads or tails of how the data in this game works so I can try and figure out how to make it do what I want. Incredible how a simple fix that works for 70% of the game has turned into such a headache for the last few chapters.

Will certainly post updates here if I manage to find anything out that leads me toward a breakthrough. I know this is a very very niche mod for a very very niche game, but I am determined to figure this out. Any input is welcome also for other tools that may help, since as I mentioned this is my first attempt at ROMHacking and I'm learning as I go. :)
« Last Edit: June 06, 2021, 12:09:15 am by ArcanaXIX »


  • Jr. Member
  • **
  • Posts: 3
    • View Profile
It's been about a week and I have made significant progress! I found what I've been looking for and have been able to implement it for most of chapter 1 and am confident it will work for the remainder of the game. It's going to take a while to actually DO the remainder of the game, and I still have extra/additional features I want to work on after I get that much done, but this is still huge.

The big breakthrough: "m##_####" variables, which I correctly realized indicate both dialogue AND associated talk sprite, are defined uniquely for every specific localization.

By which I mean that the talk sprite for any given line of dialogue is separately hard-coded for English, French, German, Spanish, and Italian on a case-by-case basis. There is nothing in the greater game###.xml file for each stage that can change this, you must edit the individual language .xml file(s) (e.g. en.xml, sp.xml, it.xml, fr.xml...). So I can change every single talk sprite in English and French will still look like normal.

(As such I am going to focus on just implementing this in English for now. I make no guarantees for any other languages down the line, but I'll try to provide some clear documentation so others could replicate this if desired.)

Once I realized this I was able to narrow down my search and have identified the following properties of talk sprites in the localization files (st##/st##_game###_Expand.en.xml, specifically):

  • Full-length talk sprites are associated with a 2-digit hexadecimal number. For example, the protagonist's default smirk is 27 (left) and 28 (right). I'll list a full table of the relevant ones below.
  • As implied by above; each sprite has 2 entries that correspond to whether it is pulled up as the "left" character or "right" character in a conversation.
  • Mini talk sprites are also associated with a 2-digit hex number (one per character). The protagonist's default being 01.
  • The full-lengh talk sprites - as far as my testing has revealed at any rate - will be called by one of two hex code patterns: 08 FF ## 00, or 19 FF ## 00 (## corresponding to the code for an individual sprite)
  • The mini talk sprites - again, based on testing thus far - are indicated with the hex code pattern 1B FF ## 00

The hex codes relevant to my project that point to Sissel's various sprites are as follows:

[26 - no sprite]
27 - default smirk (left)
28 - default smirk (right)
29 - default neutral/frown (left)
2a - default neutral/frown (right)
2b - thinking hand on chin (left)
2c - thinking hand on chin (right)
2d - sweating (left)
2e - sweating (right)
2f - angular “shocked” gag face (left)
30 - angular “shocked” gag face (right)
31 - ghost with sunglasses (left)
32 - ghost with sunglasses (right)
[33 - no sprite]
34 - shrugging with palm up (left)
35 - shrugging with palm up (right)
36 - mouth agape, slight shock (left)
37 - mouth agape, slight shock (right)
38 - thin line mouth, looking down, melancholy (left)
39 - thin line mouth, looking down, melancholy (right)
3a - angry emotional yelling (left)
3b - angry emotional yelling (right)
3c - cat (left)
3d - cat (right)

(As for the mini talk sprites, the default - as mentioned above - is 01, whereas the cat's is 08. I forget the sunglasses ghost one, I believe it is one of 0d or 0f but will need to double check when I get that far.)

This has given me a very straightforward method of replacing talk sprites that I've implemented for st01/game000, game001, game010, game011, game012, and game013 so far.

  • (Obvious, but should be stated) Extract the en.xml.lz file from the ROM, decompress it with BatchLZ77, and open it in CrystalTile2.
  • Determine whether left-facing, right-facing, and/or mini talk sprites need to be replaced. In many cases just left + mini will do it but this will get more complicated in later scenes.
  • Ctrl+R to pull up the find and replace dialogue in CrystalTile2, and run "replace all" for the relevant codes (see below)
  • Save the file, re-compress it with BatchLZ77, and re-insert it into the ROM over the original.

The specifics for what to find and replace are as follows:

For Mini Talk Sprites

* In cases where Sissel is using Yomiel's face (i.e. most of the game), simply FIND 1BFF0100 and REPLACE WITH 1BFF0800.
* In cases where Sissel is using the ghost with sunglasses, FIND 1BFF0D?00 and REPLACE WITH 1BFF0800. (I will come back and edit this when I remember what the actual code is, it may not be 0D.
* If there are any cases where Sissel and Yomiel both use this in the same scene it will need to be manually vetted.

For Full Talk Sprites (Left)

* In cases where Sissel is using Yomiel's face:




* In cases where Sissel is using the ghost with sunglasses, FIND 08FF3100 and REPLACE WITH 08FF3C00, and the same with FIND 19FF3100 and REPLACE WITH 19FF3C00.
* In cases where Sissel and Yomiel both appear in the scene, hopefully one will be on the left and the other is on the right so you can just do one or the other, but if not it'll have to be manually vetted.

For Full Talk Sprites (Right)

Same deal as the left, but replacing all the remaining codes and pointing them to 3D instead of 3C.

* In cases where Sissel is using Yomiel's face:




* In cases where Sissel is using the ghost with sunglasses, FIND 08FF3200 and REPLACE WITH 08FF3D00, and the same with FIND 19FF3200 and REPLACE WITH 19FF3D00.
* In cases where Sissel and Yomiel both appear in the scene, hopefully one will be on the left and the other is on the right so you can just do one or the other, but if not it'll have to be manually vetted.

SO. I know that's a lot but I just wanted to document that for clarity because it's very manual and it needs to be done for all 145 .lang.xml files in the ROM for every language you want the change to be reflected in.

That said; I've confirmed it does exactly what I expect it to in the scenes I've tested so far. The only exceptions are the log book and "rewind time" scenes, which still populate human Sissel (rewind pictured):

Furthermore, you MUST use the 08 and 19 preceding pointers and not just find/replace all instances of FF ## 00 because it will otherwise catch some false positives, resulting in uhhh miscellaneous text getting replaced with the letter "y":

At any rate, this appears to be working for now. I'm going to work through all of the en.xml files, and only when I'm completely finished with those will I try to pin down where the sprite information for the log book and "rewind time" might be if they aren't already covered by then.

The good news is, I am considering implementing this as a mode to select in place of the "language select" screen, since you need to do this one language at a time anyway and sprites appear to be language-independent. That is the next step on the road once I get these all done. :)