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

Author Topic: Cartographer  (Read 33207 times)

C_CliFF

  • Jr. Member
  • **
  • Posts: 63
    • View Profile
    • General CoolNES Translations
Re: Cartographer
« Reply #60 on: April 04, 2011, 06:52:37 pm »
So the last string ends with an end control code or it doesn't end with an end control code? Your post is confusing.

Sorry, it doesn't end with an end control code.

-C_CliFF

Nightcrawler

  • Hero Member
  • *****
  • Posts: 5754
    • View Profile
    • Nightcrawler's Translation Corporation
Re: Cartographer
« Reply #61 on: April 05, 2011, 09:05:40 am »
It's the same for the last string. Doesn't end with an end byte. The script ends when it hits an end byte value, which in this case passes beyond this script block, the monster names and spells. The monster and spell names are fixed strings, though.

The last string is supposed to end at $270862 but ends at $272962. The whole block, with the available space included, is between $270200 and $270AFF, so the extraction gets quite far before it hits the end.

This is the only block in the game that has this kind of format, so fortunately, it's not a real biggie. But maybe this applies to other games besides this and RS2.

-C_CliFF

I don't understand what you're saying. When the game hits the last pointer to a string, how does it know when to stop? Is it like Gideon described where there is an extra pointer (that doesn't go to any text) at the end of the pointers? That makes sense to me. It seems for you, it just keeps reading past the end of the useful string until it hits some end indication at the end of your entire data area? If that's the case, what stops it from printing all that on the screen when that string is called until it gets there?
TransCorp - Over 20 years of community dedication.
Dual Orb 2, Wozz, Emerald Dragon, Tenshi No Uta, Glory of Heracles IV SFC/SNES Translations

C_CliFF

  • Jr. Member
  • **
  • Posts: 63
    • View Profile
    • General CoolNES Translations
Re: Cartographer
« Reply #62 on: April 05, 2011, 01:25:44 pm »
Your post is confusing.

I don't understand what you're saying.
I re-read my post a few times and I see that it was confusing.

It seems for you, it just keeps reading past the end of the useful string until it hits some end indication at the end of your entire data area? If that's the case, what stops it from printing all that on the screen when that string is called until it gets there?

This is what happens. The reason that it stops is because I got an end byte value in my table-file. ($00)

The text reads on and on til it gets to the end byte control code I have in my table file. I upload a file so you can see what the output looks like. I shortened it because the text's repeating til the pointer end offset I specified in the command settings above.

http://www.mediafire.com/?15yhrhfwo7i2w87

Sorry for the confusion.  My english is not good today.

EDIT: Oh, and the last pointer points to Elder Tree. The rest belongs to other script blocks.

-C_CliFF


« Last Edit: April 05, 2011, 01:43:03 pm by C_CliFF »

Nightcrawler

  • Hero Member
  • *****
  • Posts: 5754
    • View Profile
    • Nightcrawler's Translation Corporation
Re: Cartographer
« Reply #63 on: April 05, 2011, 03:18:23 pm »
OK. I see what issue is. You're explaining again why you are having trouble dumping the text with Cartographer. I already understood that part. When you use Cartographer it doesn't know where any of the strings end and overruns the entire area until it hits a $00 for each string. The result is you get a big mess of a block for each string.

What I want to know is how does the GAME know when a string ends? Most likely it uses the n+1 pointer to figure it out. That's not too big a deal. I could do that. The million dollar question is what does it do on the last string, where conceivably there would be no more pointers. Gideon's game, RS2, simply has an extra pointer at the end that serves no purpose other than to calculate the end of the last string. I wanted to know if your game did the same or used some other game specific method to know. That's the only way I can really help you out.

It seems you probably don't know what the game does. Are you experienced enough to find out? To dump this properly, you need to figure that out or just overdump on the last string and trim each block manually. You'd still need a dumper that can do fixed length string lengths based on pointer calculations (which it does not appear any public ones do).
« Last Edit: April 06, 2011, 08:13:22 am by Nightcrawler »
TransCorp - Over 20 years of community dedication.
Dual Orb 2, Wozz, Emerald Dragon, Tenshi No Uta, Glory of Heracles IV SFC/SNES Translations

C_CliFF

  • Jr. Member
  • **
  • Posts: 63
    • View Profile
    • General CoolNES Translations
Re: Cartographer
« Reply #64 on: April 05, 2011, 04:58:39 pm »
OK. I see what issue is. You're explaining again why you are having trouble dumping the text with Cartographer. I already understood that part. When you use Cartographer it doesn't know where any of the strings end and overruns the entire area until it hits a $00 for each string. The result is you get a big mess of a block for each string.

What I want to know is how does the GAME know when a string ends? Most likely it uses the n+1 pointer to figure it out. That's not too big a deal. I could do that. The million dollar question is what does it do on the last string, where conceivably there would be no more pointers. Gideon's game, RS2, simply has an extra pointer at the end that serves no purpose other than to calculate the end of the last string. I wanted to know if your game did the same or used some other game specific method to know. That's the only way I can really help you out.

It seems you probably don't know what the game does. Are you experienced enough to find out? To dump this properly, you need to figure that out or just overdump on the last string and trim each block manually. You'd still need a dumper that can do fixed length string lengths based on pointers (which it does not appear any public ones do).

The thing is that I already know why, the question I was asking in the first place was if Cartographer was able to dump text that use this kind of format. My purpoes wasn't to take this much further then that. I know you're working with TextAngel, and when Gid told me his game used this kind of format, I thought it would have been a good idea to explain how FF5 does with this text block and maybe this could be of some use for your tool, (which I'm not doing well, at all) unless it's not game specific.

This text is for the location names, and it's the only block that has this kind of format, the rest of the game's text uses either standard text handling and fixed strings for items, magics, monster names and such. This is how it looks at the end of the text block:



The rest of the text that comes after where my cursor is, is probably some old translated text that hasn't been deleted. But this is where the last pointer points to, and this is how it looks in the pointer table:



I hope this explains it more clearly and sorry for any missunderstanding on why I bumped this thread.

-C_CliFF



 

Gideon Zhi

  • IRC Staff
  • Hero Member
  • *****
  • Posts: 3502
    • View Profile
    • Aeon Genesis
Re: Cartographer
« Reply #65 on: April 05, 2011, 10:14:19 pm »
Maybe it's just that it's 10PM and I've come from a two-hour calculus review, but those pointers don't appear to match up to your data in any meaningful way, even if they're relative based on some offset. If we assume that "Oldest Tree" starts at relative address 0x662, then "Underground River" relatively starts at 0x66D, but the pointer is 0x673. If we instead assume that "Oldest Tree" starts at relative address 0x658, then "Underground River" relatively starts at address 0x663, but again, its pointer is 0x662.

RedComet

  • Hero Member
  • *****
  • Posts: 3163
    • View Profile
    • Twilight Translations
Re: Cartographer
« Reply #66 on: April 05, 2011, 10:30:14 pm »
You'd still need a dumper that can do fixed length string lengths based on pointers (which it does not appear any public ones do).

I'm pretty sure Cartographer does that. :P At least, I seem to remember coding it in there for Bare Knuckle 3. :huh:
Twilight Translations - More than just Dragonball Z. :P

Nightcrawler

  • Hero Member
  • *****
  • Posts: 5754
    • View Profile
    • Nightcrawler's Translation Corporation
Re: Cartographer
« Reply #67 on: April 06, 2011, 02:30:07 pm »
Red:
I meant to say "can do fixed length string lengths based on pointer math", such as the case here. By the way, are you interesting in possibly updating Cartographer in the event Klarth issues an update to TableLib that would use the new table file standard we were working on? He mentioned he would update Atlas as well when the time comes.

C_CliFF:
It looks like this is the same case as Gideons. Correct me if I'm mistaken, but pointer 0662 points to 'Underground River' which is the last string, correct? If so, there is one more pointer 0673 which points to where your cursor is, the end of the block. If so, we have the answer here. There's just one extra pointer that is simply used to calculate the end of the block and does not point to a string.

I will see about implementing this method in my WIP utility. I can't think of the game, but I know I have seen this elsewhere in the past. I think I still classify this as 'fixed length' string type. They are surely not C-style/end terminated or pascal. I don't know of any other string type to classify them as. So I will just treat it as an extra checkbox option extension for fixed length strings to determine the length by relative pointer math instead of the defined fixed length constant.
TransCorp - Over 20 years of community dedication.
Dual Orb 2, Wozz, Emerald Dragon, Tenshi No Uta, Glory of Heracles IV SFC/SNES Translations

C_CliFF

  • Jr. Member
  • **
  • Posts: 63
    • View Profile
    • General CoolNES Translations
Re: Cartographer
« Reply #68 on: April 06, 2011, 04:39:52 pm »
C_CliFF:
It looks like this is the same case as Gideons. Correct me if I'm mistaken, but pointer 0662 points to 'Underground River' which is the last string, correct? If so, there is one more pointer 0673 which points to where your cursor is, the end of the block. If so, we have the answer here. There's just one extra pointer that is simply used to calculate the end of the block and does not point to a string.

That's absolutely correct.

-C_CliFF

RedComet

  • Hero Member
  • *****
  • Posts: 3163
    • View Profile
    • Twilight Translations
Re: Cartographer
« Reply #69 on: April 06, 2011, 05:31:33 pm »
Red:
I meant to say "can do fixed length string lengths based on pointer math", such as the case here. By the way, are you interesting in possibly updating Cartographer in the event Klarth issues an update to TableLib that would use the new table file standard we were working on? He mentioned he would update Atlas as well when the time comes.

Yeah, I've been thinking about revisiting Cartographer for a while now and fixing a few things and adding a few others that people have brought up to me in the past year or so. Probably would be beneficial for both of us if the community spoke up and said what exactly they want out of a text dumper. I'm sure it would only improve TextAngel and Cartographer if we were able to cover all the bases. Who knows,  someone else may have a weird format like this that might come up later on.
Twilight Translations - More than just Dragonball Z. :P

Pennywise

  • Hero Member
  • *****
  • Posts: 2240
  • I'm curious
    • View Profile
    • Yojimbo's Translations
Re: Cartographer
« Reply #70 on: April 06, 2011, 07:52:36 pm »
I have a sort of weird format I've come across. I think it was somewhat similar to Cliff's.

Basically there are at least two large blocks of text where the text has a bunch of non-script data embedded into the text. I can dump by pointers easily and get all the data, but there's not a standard control code to signify an end to a string. So I end up with a lot of overlap because all the pointers are normal and follow logical increments in that the offsets don't jump around.

abw

  • Sr. Member
  • ****
  • Posts: 272
    • View Profile
Re: Cartographer
« Reply #71 on: April 06, 2011, 08:33:00 pm »
Probably would be beneficial for both of us if the community spoke up and said what exactly they want out of a text dumper.

I'll take that as an invitation to bring up an earlier discussion :P

I'm not sure whether this will be useful or not, but after thinking about it for a little bit, achieving the desired text-based effects from a pointer-based implementation is probably not as difficult as I had assumed:

Code: [Select]
sorted_ptrs = pointer_table.sort(by_target_address)
cur_text_pos = sorted_ptrs[0].target_address - 1

for (i = 0 to sorted_ptrs.length) {
    if (sorted_ptrs[i].target_address <= cur_text_pos) {
        if (sorted_ptrs[i].target_address == sorted_ptrs[i - 1].target_address) {
            // handle duplicate pointer
        } else {
            // handle partially overlapping text
        }
    } else {
        if (sorted_ptrs[i].target_address > cur_text_pos + 1) {
            // handle pointerless text between sorted_ptrs[i - 1] and sorted_ptrs[i]
        }
        // dump text as normal
    }
    // byte_length includes printable text as well as any applicable control codes
// (e.g. end token for C-style strings, length token for Pascal strings, screen position tokens, etc.)
    cur_text_pos = sorted_ptrs[i].target_address + sorted_ptrs[i].byte_length
}

The basic goal is to keep track of which bytes in the dump range have been dumped as well as how many times they've been dumped (0, 1, > 1). If we sort the pointer table by the addresses the pointers point to (their target addresses), figuring out the start and (to a lesser extent) the end points of the dump range becomes trivial, and from there it's just a linear scan through the dump range, moving from pointer to pointer in ascending target address order, with some backtracking if pointer ranges overlap.
« Last Edit: April 07, 2011, 09:45:48 am by Nightcrawler »

Nightcrawler

  • Hero Member
  • *****
  • Posts: 5754
    • View Profile
    • Nightcrawler's Translation Corporation
Re: Cartographer
« Reply #72 on: April 07, 2011, 10:24:11 am »
RedComet:
OK. I will keep you in the loop when I get back around to talking to Klarth again.

Pennywise:
It sounds like the same thing. Whether you have data or not in the mix is immaterial. You want to dump by having the program figure out the 'string' (even if it has data) length by pointer math. Although you may have a different case. How does your game know when it has reached the end of a 'string'?

abw:
I will handle duplicate strings. I provide for an option to both order strings by pointer location and combine duplicates if desired. I believe I can also handle the case where you have a pointer to a string contained within another string. It is a logical extension after strings are already ordered by pointer to check if the n+1 string is within the dumped range for the current string n. If so, combine output. Theoretically, you'd probably need to check n+2, n+3 or go down the line until it doesn't overlap to be most flexible. This extension does add a good deal of logic and post processing. I see the usefulness, however I don't know if I will implement this or not. What I can say though is I will ensure my internal data structure would be able to support such functionality if implemented. These kinds of things are quite possible when using an internal data structure with attributes for your string/pointer combinations. It allows for post-processing of this kind of thing before making any kind of output.
TransCorp - Over 20 years of community dedication.
Dual Orb 2, Wozz, Emerald Dragon, Tenshi No Uta, Glory of Heracles IV SFC/SNES Translations

Pennywise

  • Hero Member
  • *****
  • Posts: 2240
  • I'm curious
    • View Profile
    • Yojimbo's Translations
Re: Cartographer
« Reply #73 on: April 07, 2011, 05:49:21 pm »
Under normal circumstances, just a simple check for FF. However, the text I'm talking about is a little complicated and it doesn't appear to use an end of string control code. So far the only thing I've been able to determine that the non-text data starts when a value in the script is in the C0-E0 range then it will read a some more non-text data then without stopping it will switch the pointers. As an example we have $C2 $98 $01 $EB $03

As I mentioned before any value between C0-E0 seems to trigger the non-script data and $03 is how many pointers to skip to get to the desired pointer in the table. I haven't yet messed with other strings to see if after $C2, the end is 4 values away.

I did some more messing around and there's another control code that seems to correspond to presenting choices from you to pick from. The number of choices available is specified in the non-script data and so the more choices available, the longer the data.
« Last Edit: April 07, 2011, 07:50:01 pm by Pennywise »

abw

  • Sr. Member
  • ****
  • Posts: 272
    • View Profile
Re: Cartographer
« Reply #74 on: April 07, 2011, 09:47:43 pm »
A second post-processing pass is definitely the way I would go in a situation like this. For output a forward-facing loop probably would be better than my backward-facing loop. If you don't mind outputting in sorted pointer order (or if each pointer can figure out its next sorted sibling), something like this might work:

Code: [Select]
for (i = 0 to sorted_ptrs.length) {
    // if there is a next pointer and the current pointer finishes *after* the next pointer starts
    if (sorted_ptrs[i + 1] && sorted_ptrs[i].target_address + sorted_ptrs[i].data.length > sorted_ptrs[i + 1].target_address) {
        // handle overlapping text
        output sorted_ptrs[i].target_address // e.g. #W16($280F4)
        output sorted_ptrs[i].data up to sorted_ptrs[i + 1].target_address // nop for duplicate pointers
        // if the next pointer ends *before* the current pointer ends, make sure any trailing text from the current pointer will eventually get printed
        sorted_ptrs[i + 1].data += sorted_ptrs[i].data from (sorted_ptrs[i + 1].target_address + sorted_ptrs[i + 1].data.length to sorted_ptrs[i].target_address + sorted_ptrs[i].data.length)
        // rest of text will be output when dealing with next pointer
    } else {
        // dump text as normal
        output sorted_ptrs[i].target_address
        output sorted_ptrs[i].data
        // if there is a next pointer and there's a gap between where the current pointer finishes and the next pointer starts
        if (sorted_ptrs[i + 1] && sorted_ptrs[i].target_address + sorted_ptrs[i].data.length < sorted_ptrs[i + 1].target_address + 1) {
            output data from (sorted_ptrs[i].target_address + sorted_ptrs[i].data.length to sorted_ptrs[i + 1].target_address)
        }
    }
}

Nightcrawler

  • Hero Member
  • *****
  • Posts: 5754
    • View Profile
    • Nightcrawler's Translation Corporation
Re: Cartographer
« Reply #75 on: April 08, 2011, 08:40:21 am »
Under normal circumstances, just a simple check for FF. However, the text I'm talking about is a little complicated and it doesn't appear to use an end of string control code. So far the only thing I've been able to determine that the non-text data starts when a value in the script is in the C0-E0 range then it will read a some more non-text data then without stopping it will switch the pointers. As an example we have $C2 $98 $01 $EB $03

As I mentioned before any value between C0-E0 seems to trigger the non-script data and $03 is how many pointers to skip to get to the desired pointer in the table. I haven't yet messed with other strings to see if after $C2, the end is 4 values away.

I did some more messing around and there's another control code that seems to correspond to presenting choices from you to pick from. The number of choices available is specified in the non-script data and so the more choices available, the longer the data.

It seems as though there is insufficient data to dump this properly even if you were to make a custom dumper. You need to figure out what those game commands are doing more specifically. You know the end result is a pointer switch, but you don't know exactly how that occurs. So, how would you be able to dump based only on what you know so far? It helps to examine the game code in these cases.

Whatever you discover is going to be pretty game specific. It would probably still need a custom dumper. The way I would envision something like this working in a generic tool is figuring out more about those data commands and sticking them in the table as linked entries. You just need to know how many bytes, if any, are associated with each and not necessarily what they all do. We just need to be able to parse properly and not falsely hit parameter bytes. Then define the few that change the pointer or end the string to the dumper. So basically, it will dump until it hits a defined linked entry. I think you need to know most of this to dump the script anyway using any tool unless you do it the way you have with lots of overlap and garbage.

These types of scripts with embedded game commands require the most knowledge about the text system to be able to dump and insert. You typically need to know enough to be able to extract only the text, or parse or skip the commands. Insertion can be even trickier without knowing more about the commands. In most cases for insertion I end up adding a new relocation control code in the original blocks where the original text was so I don't have to alter any of the game commands.
TransCorp - Over 20 years of community dedication.
Dual Orb 2, Wozz, Emerald Dragon, Tenshi No Uta, Glory of Heracles IV SFC/SNES Translations