+  RHDN Forum Archive
|-+  Romhacking
| |-+  ROM Hacking Discussion
| | |-+  School me, would ya?
Pages: [1] 2 3 ... 5
Author Topic: School me, would ya?  (Read 2 times)
Knux14
Guest
« on: March 26, 2007, 05:19:44 am »



-Summon Night Craft Sword Monogatari Hajimari no Ishi-
for Game Boy Advance

Well look at that. (Minus the garbled junk, don't mind that. I've corrected that text already.)

So far I've found the compressed dialogue, decompressed it, changed it, recompressed and inserted it,
and had it display the changes perfectly.

Until it reaches an event! UH OH!

A few lines after the moment the screenshot was taken, the dialogue calls an event where the boy's sprite does a little animation showing him taking out his hammer.

But that does not happen anymore. Instead, the game would rather start screeching, and wipe the screen totally blank. Smiley

So, just to throw away all the obvious suspicions, I've already doublechecked to make sure I haven't messed up any control codes.
In fact -- the exact same problem happens when I change one, and only one character in the text at all.

So, it is obviously not a problem with an event code within the dialogue.
What else could I come up with?
Maybe it was something outside of the compressed dialogue, whereafter I reinsert my new compressed text goes over some event data that sits exterior to it?

So I made sure when I inserted it, it's compressed size was the same or less bytes than the original.

Same exact problem. That rules out the event data being directly outside of the compressed dialogue.

If I were to make a guess at what would be most practical -- wouldn't they have a pointer inside the dialogue calling up whatever outside events they needed done?
If it worked like that though, why is it when I don't change all but one single byte of text that it ruins the event that takes place? It shouldn't ruin any pointers at all, should it?

If anyone has any good ideas on how I would go about finding out how this event is called, or why just changing a single byte ruins the whole thing, please suggest it! Smiley

(In case anyone wants anymore details -- the game stores large chunks of dialogue, compressed, in the rom. Only dialogue up to a certain point is needed. Later on when the game needs more dialogue, it will decompress more of it into memory. Decompressing and dumping these nice big chunks of script, I find lots of unknown bytes inbetween the lines of known dialogue. Some of which have been found to control which picture is shown above the textbox at the time, or a branching dialogue condition based on your character's gender.) So it would seem practical that the event data would be somewhere inbetween text, right?
Nightcrawler
Guest
« Reply #1 on: March 26, 2007, 10:53:22 am »

The event data can certainly be between text. It can even be embedded right in the text.

When you changed just one byte, how did you do that? It's difficult to just change one byte in a compressed stream. You need to be certain that byte is not then copied anywhere else to know that you actually did just change one byte the decompressed output.

Maybe you already accounted for this. You're telling me that if you change ONE letter in the text from say 'a' to 'b', it crashes the game?

If that's true, are you sure there's no checksum checks on the decompressed data or other odd thing like that? There's not many reasons why changing a single letter and nothing else would crash the game.
DaMarsMan
Guest
« Reply #2 on: March 26, 2007, 01:38:06 pm »

Your compressor code may be off a little.
Kajitani-Eizan
Guest
« Reply #3 on: March 26, 2007, 11:36:31 pm »

agree with damarsman. also, is it possible that compressed chunks of dialogue somehow have uncompressed bits of control code embedded?
Ryusui
Guest
« Reply #4 on: March 26, 2007, 11:50:40 pm »

Well, doesn't this sound familiar? Sylvanian Families does the exact same thing whenever it encounters a script error.

Here's my recommendation: trace the code as it rattles through the original routine and see what happens when it hits the event code. Now see if the same thing happens when it hits the event code - assuming it gets that far - and see what's different.
Knux14
Guest
« Reply #5 on: March 27, 2007, 06:06:01 am »

I've completely ruled out compression.
I've also managed to prove I hadn't changed one single bit of event code within the dialogue text (Yes it was changing just one letter in text that started showing the symptoms, Nightcrawler).

Romhacking Masters, listen to this, tell me what you think with the new following information --

At the end of the first block of compressed dialogue text, there were 2 bytes filling the space up till the next block of compressed dialogue. Hex value 10 29.

That was how it was in the untouched rom. So what did I do?
I put 10 29 directly after the end of my smaller edited block of compressed dialogue (filling the rest of the gap with 00s until the next compression block).

It worked perfectly.

Ok, so now theres 2 possibilities, right? This 1029 is either an "end of compression block" notifier (Even tho that seems pointless with LZ77 compression) -- OR

This 1029 is a pointer or an offset for an event table of some sort. Would that make sense?

I've checked the end of other compressed blocks of dialogue, and I see 1029 there too.

Also, for extra credit, I played around with the value a little (changing it to 104A and some other odd 10xx variants) and sometimes, depending on what I set it to, the game will just perform a software reset. I've also gotten the effect where the game pauses a second, forgets a couple lines of dialogue and events and just cuts to the first battle in the game as if you were supposed to be there. Ok?

Anyone have any idea what the byte 1029 directly after a compressed block of dialogue could really be?

Thanks for your time guys.
Nightcrawler
Guest
« Reply #6 on: March 27, 2007, 08:16:40 am »

Nice work on figuring it out. Yeah, it sounds like 1029 is probably used as starting offset to a table or something. Hard to guess without looking at the code. Bottom line is, it's important to game functionality, so you'll obviously need to make sure your inserted blocks recreate the necessary values after the end of the block.

It does sound a little fishy. I'd probably try and do some more investigation. See if ALL of the compressed blocks use this value and that it always occurs immediately after the end of the compressed stream. I'd hate for you to go to town on this game inserting and then find there are other problems because you didn't fully understand what those values were.

Maybe it is a simple as appending 1029 as a padding value for every block. However, just double check and be as certain as possible. I wouldn't be surprised if you found a difference in one of the other blocks. Generally, things are not done for no reason.
Knux14
Guest
« Reply #7 on: March 29, 2007, 06:58:05 am »

Thanks Nightcrawler.
I think I've also found that a set of bytes that come before 1029 even. F029.
Even though there were some variations on both parts, 8/10 of the time they turned out to be
"F029 1029".
I am curious what it does exactly, but I don't believe ill be needing it. As long as the events work if I put them directly after the compressed blocks of text, it will make due for translation purposes.

If I happen to need to do anything with these values, I'll try what Ryusui said.
So I have moved on from that. Problem solved.

The next issue I have is a little tougher, I believe:

---------------------------------------------------------------------
I want to change the text reading routine to read 1-byte (Mostly ASCII based) values, rather than
2-byte Shift-JIS values. That part should be the easier of my two tasks.

Apart from that, I also want to change the font reading/writing routine to take 8x12 characters
rather than it's original 16x12.

Original Font here-http://img256.imageshack.us/img256/321/output16x12aa2.png

I'm guessing that would be tougher to do, most likely?

I've also discovered, for myself, both good news and bad news.

Which first? Lets do bad news, or else the good won't make much sense Smiley

Bad News:

Theres 2 different drawing modes for text.


One writes it as unsizable normal text.


The other mode uses "sprites"(not sure how those are formed though) as text and lets you resize and reshape them and other special effects. That means I've got to fix both modes to do what I want, doesn't it?


Good News:

Both modes use the exact same font from within the rom(ALMOST SURE ABOUT THAT, will confirm soon). Both modes ALSO use the exact same byte values and read from the same places to obtain the dialogue text. So, that cuts down on at least a bit of double-stacking my work. Or, am I being paranoid and they both can be fixed within one routine?

----------------------------------------------------------------
Either way, if anyone has some advice,
Or just plain wants to help out...

Us Summon Night 3 Translators would love it. Smiley

++This game is in demand in english

I wonder if anyone would be willing to (NOT DO THE WORK FOR ME), but help walk me through with real-time help if they're available?  :laugh:

Thanks guys. Buh byes for now.  Wink
« Last Edit: March 29, 2007, 07:07:00 am by Knux14 »
Nightcrawler
Guest
« Reply #8 on: March 29, 2007, 12:56:14 pm »

You're going to need to do assembly hacks for both of those those things.

1. To change the 2 byte characters into one byte, you're going to need to find a string in the game. You're also going to want to know the offset of the font letter for the first letter of that string. And you're going to need a debugger. If you have all of that information, then you're ready to proceed. You're going to want to make a trace dump starting at the instruction where the first two byte character of the string is loaded. You're going to follow that code to the point where the font character was loaded from the ROM. The code you need is between those two points. There will be some sort of routine that takes those two bytes and figures out the offset the corresponding font character is located at. You're going to need to change that routine so only one byte is loaded and that byte can be newly manipulated to reference the font characters. That's generally how it's done.

2. The second hack is an 16x12 to 8x12. Same type of thing. This time, start your trace when the font character is loaded. You'll see the actual bytes being loaded from the ROM and they will go through a series of manipulations to be stored in RAM(to be DMA'd) or written to VRAM, however they are going to get to the screen. You're going to want to change this routine so it only loads one tile for the top and bottom of the letter. Sometimes, it's just a matter of commenting out a few lines. Other times, you'll need to write so new code and edit the tilemap.

These hacks will vary from easy as pie 5 minute job(quite a bit longer for you since you're new) to fairly challenging depending on the game. I think I've given you some starting pointers to get your feet wet. See what you can find out. The specifics of what you need to do are going to be different from game to game.
Knux14
Guest
« Reply #9 on: April 02, 2007, 02:47:53 pm »

Thanks for the advice, especially Nightcrawler. I believe it lead me in the correct direction...

But just when I think I have figured out how the game goes about it's font-writing ways, it throws another layer of complexity on me.

Let me show you what i've done, digging into this.



Obviously i've touched somewhere well within the drawing routine. In fact, I know exactly where the loop makes its check on whether or not to do another row of pixels (It goes up to 12 normally, but i've made it do 6 for testing purposes before). BUT THIS EFFECT you see right here, is not that. This is me basicly commenting out the part where it stores the processed bytes representing pixels 1-16(after adding shadows and such, I think), but I only stopped it after the first half. I was trying to get it to show 1 half of the normal font character width. Turns out being an odd 1/4th, or something?


And then, I just went all out and commented out all of the lines it went to store (processed:Shadowed and stuff) font character. Which oddly enough, in some other diagrams shown in the game, actually shows odd offseted characters, too.

Also, notice how every OTHER (i think somehow the game pairs them in two) character: it views perfectly fine, as if untouched by any code i've changed. What is that all about?

Should I be asking what to look for next? Tongue

I hope this doesn't confuse everyone else as much as it does me.
If theres any light to shed, pleeeeaase shed it. I really want to break this game and get it ready for easy english insertion.

Thanks for reading, again.
Nightcrawler
Guest
« Reply #10 on: April 02, 2007, 03:23:16 pm »

Ok.. I think I have an idea of what's going on.

First, stop thinking in terms of pixels so much and thinka bout tiles. Unless your font is drawn as sprites, it's ultimately drawn in tile form.

First let's clear up dimensions. Dimensions I speak about them are width x height.

It's my understanding that the original game's font is 12x16. Think about this very fact for a moment. Can you possibly have a 12x16 tile? No. Tiles must be 8x8, 16x16 etc. So, how would you get a width of 12 pixels? The game uses a bit of trickery in the code.

Typically, a game that uses 12x16 font will have a two character or two pass font routine. it does something DIFFERENT with the second character than it does with the first character. That's because the first character can start on an even tile boundary, however the second character starts mid tile, so it has to be OR'd in RAM with the second half of the previous letter.

It's a bit hard to explain without visuals. Keep following your font routine and see what it does for the second character. It's going to go through some different instructions.

Let's start by finding the SECOND character load. You'll want to disable that load altogether.

What's you're doing is disabling the second character load, cutting the first character load to load only one tile for width.  If you can get that far, then all you ned to do is cut out the space between the letters. This is either going to be done via a tilemap modification or if you're lucky you can simply change an addition instruction if it keeps track of the position right in the font routine.

It looks like you've almost got it with the Name Entry screen. However on the main dialog screen, you've modified the first character routine rather than the second. Get some blank spaces where the second character loads.
LilSnyperX
Guest
« Reply #11 on: April 02, 2007, 03:37:38 pm »

I'm not sure exactly how helpful this is, but aaactually..

The tiles are 16x12, that's 16 wide 12 high. Although, only 12x12 of the tiles is actually useable, with a 4x12 blank padding on the right side. Filling in the blank space has no effect.

I'd assume this wouldn't have a major effect on the process though.  Wink
Nightcrawler
Guest
« Reply #12 on: April 02, 2007, 04:26:11 pm »

Yes, actually it would affect it to some degree. That will change the way the routine is. It won't be a two pass I don't think. I don't have time to address this anymore today.
Knux14
Guest
« Reply #13 on: April 05, 2007, 10:47:28 am »

Stopping the routine from storing the first tile in a pair =

Success, of course.

Stopping the routine that comes after from storing the second tile in a pair (partially combined with the first) =

Success, thank you NightCrawler. When we get into the accrediting part of the finished translation,
I'll make sure you're remembered.
Along with RedComet, and maybe marsman too Smiley

ANYWAYS...

I could go ahead and just give this thing a spin and try and change it the way I'd like to,
but since I am not experienced, I will hold on my craving to finish chopping up this routine.
Just to make sure I do it the best way possible, I will wait this time for your suggestion, Nightcrawler (or if anyone else wants to send advice too.)

What is the best way to go about this?

I know where the first character's routine is, and I know where it branches off to load and combine the second character.

------------------------------------------------------------------------------------------------------------

The first character routine goes like this (Pseudo, anyways):

-Read a character (2 bytes) in the dialogue to tell what is being dealt with.
-Check if it is actually a text character or a control code.
-Manipulate these 2 Bytes to find out what offset in the font to use.
-Add that offset to the address of the first font character in the rom.

-Read in the first row of pixels(2 bytes), starting at the offsetted address found just earlier.
-Manipulate and process these pixels in some way.
-Then store these processed pixels into RAM.
-Initiate the counter signifying that 1 row has been done.

-Start a loop that does the same thing as above(may process the pixels a bit differently, though).
-*Store these processed pixels into RAM.
-Add 1 to the counter signifying how many rows have been done.
-If number of rows done is 12, then move along without looping.

After that, the second character's routine comes up something like this:

-Read a character (2 bytes) in the dialogue to tell what is being dealt with.
-Check if it is actually a text character or a control code.
-Manipulate these 2 Bytes to find out what offset in the font to use.
-Add that offset to the address of the first font character in the rom.
[Note: All of these above are the exact same lines of code used to find out the first character's font offset.]
[but the ones below are ran from a slightly different place in the rom (Hence them being 2 seperate routines).]
[but they are both similar]

-Read in the first row of pixels(2 bytes), starting at the offsetted address found just earlier.
-Manipulate and process these pixels in some way.
-Then store these processed pixels into RAM.
-Initiate the counter signifying that 1 row has been done.

-Start a loop that does the same thing as above(may process the pixels a bit differently, though).
-*Store these processed pixels into RAM.
-Add 1 to the counter signifying how many rows have been done.
-If number of rows done is 12, then move along without looping.

--------------------------------------------------------------------------------------------------------------
And there you have it.

I have signified the codes I basicly commented out(just made the opcode instead add 0 to a register) in order to get the effects you see in the screenshots above; with a *. I only have changed an opcode within the loops of the routines. The effect is obvious though. Smiley

Again, thanks so much for explaining that to me Nightcrawler.

Buh Bye for the moment! Tongue
Nightcrawler
Guest
« Reply #14 on: April 05, 2007, 12:00:40 pm »

Awesome! Nightcrawler's conceptual explanation strikes again and helps another victim. Concepts are far more valuable than lines of code. Wink

The 'best' way to do this is relative really. It's probably whatever will require the least amount of time and modification. Anyway, I'll tell how I would suggest you do it to make it a good learning experience.

Break it down into little tasks. You now know a lot about what's going on in the font routines.

1. Try disabling the second routine again, but this time DON'T let the game load the script letter. Say your string is 'ABCD' If you blank out the second routine like you've done, you'll currently get 'A C ', right? How about not allowing the game to call that second routine or grab the second letter so you then have.. 'A  B  C  D'. Maybe you've already done this, but this is an important step because now you've simplified things A LOT. You're now dealing with ONE routine that handles all the characters. No need to worry about number 2 anymore. Usually you can just nop out the instruction that increments the string pointer. or you can add a decrement in there to compensate somewhere depending on the code and your preference.

2. Now that we have one routine, we want to limit what it loads. You're still going to load your 12 rows, right? However, we want to limit the pixels for each row to just 8 because we ultimately want an 8x12 font, right? You may as well go ahead and stick a 8x12 font in the game to test that part out.

3. Now we've got one routine, it loads the proper characters, and it loads the correct size font. The last step remaining is get rid of that space between everything. How do we do this? That's a tricky question. You're going to need to examine the code again. Sometimes you can adjust the spots in RAM that the characters write to and that could eliminate it. Sometimes, you may need to adjust the tilemap to no longer include those blank tiles. That may be as easy as changing the increment on a tile counter. Or it may involve changing what's tiles are assigned to the map after each character pass. This really depends on what your code is doing exactly. You'll just need to figure out HOW the space is there and then what you can potentially do to make that not happen anymore.



If you can handle that, the 2 byte to 1 byte should be easy as well. You'll just be making the string pointer increment by one instead of two after each letter. Then you'll just change a few lines of code for the offset calculation so there is a new calculation based on one character that can point to the correct Font offset.
Pages: [1] 2 3 ... 5  


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