Author Topic: Cyber Knight translation  (Read 10387 times)

Black Tiger

  • Hero Member
  • *****
  • Posts: 11242
Re: Cyber Knight translation
« Reply #165 on: March 05, 2016, 09:18:28 AM »
Has this project progressed any further?
http://www.superpcenginegrafx.net/forum

Active and drama free PC Engine forum

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #166 on: April 15, 2016, 09:58:02 PM »
Sorry folks, real life has gotten in the way. I haven't had the time to touch this for probably a year now - a promotion at work to managing a team (and all the paperwork that comes with!) and more responsibilities at home mean I just don't have the time to devote to it.

esteban

  • Hero Member
  • *****
  • Posts: 24063
Re: Cyber Knight translation
« Reply #167 on: April 16, 2016, 05:40:19 AM »
Sorry folks, real life has gotten in the way. I haven't had the time to touch this for probably a year now - a promotion at work to managing a team (and all the paperwork that comes with!) and more responsibilities at home mean I just don't have the time to devote to it.

I hear you :(

:)

Thanks for the update.
  |    | 

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #168 on: October 22, 2016, 09:57:14 PM »
Hello, me again :)

So, I've decided to have a look at Cyber Knight again, after a break of over 2 years. Now's the time to do it, as things are probably going to change quite dramatically in my life in the next 6 months or so and I imagine I'll not have any spare time for the next ... ooh, 18 years or more!

So, where I got to with the translation was a point where the English text simply won't fit in to the space available. I had to start overflowing in to areas of the ROM that appear to be blank, although this gave me some extra space for NPC text for the first world, it broke the scrolling intro and I got random rubbish after finishing the first world, meaning I couldn't progress.

I really need the assistance of someone with more PCE programming knowledge who can help by either changing the text routines to point to blocks outside the main code section, or expand the ROM size, and, again move the text their. There just isn't the space available to replace the bulk of the text without overflowing in to the code sections.

Just as a reminder, Cyber Knight uses a fairly crude text block system, which makes it relatively easy to insert: the text is stored in several positions throughout the ROM, interspersed by code and graphics data. The text strings simply run on from each other and are seperated by a given byte sequence, the text display routine just counts over these text blocks until the right number of skipped sequences have been counted, then displays the next sequence. It makes it easy to modify the text (and its uncompressed, which is a big bonus for me). But expanding beyond the availabvle space, or moving it altogether is out of my league.

So, here's a request for help - would anyone be willing to assist in this particular part of the translation, i.e. changing the text routine, and/or expanding the ROM to include enough space to store the english text?

It's a shame for more of us not to get to play it, it really is a great little hucard rpg/strategy game.

NightWolve

  • Hero Member
  • *****
  • Posts: 5277
Re: Cyber Knight translation
« Reply #169 on: October 23, 2016, 03:34:21 AM »
Hey megatron, forgot about ya! You were the best status update provider I had seen, well, before elmer and SamIAm came along, that is. ;) Try talking to Bonknuts for help, elmer's too busy with his projects. Too bad you can't do it yourself, anyway, all the best!

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #170 on: October 23, 2016, 03:25:33 PM »
I really need the assistance of someone with more PCE programming knowledge who can help by either changing the text routines to point to blocks outside the main code section, or expand the ROM size, and, again move the text their. There just isn't the space available to replace the bulk of the text without overflowing in to the code sections.

Just as a reminder, Cyber Knight uses a fairly crude text block system, which makes it relatively easy to insert: the text is stored in several positions throughout the ROM, interspersed by code and graphics data. The text strings simply run on from each other and are seperated by a given byte sequence, the text display routine just counts over these text blocks until the right number of skipped sequences have been counted, then displays the next sequence. It makes it easy to modify the text (and its uncompressed, which is a big bonus for me). But expanding beyond the availabvle space, or moving it altogether is out of my league.

OK, a quick look at the game's scripting system shows that the data in the ROM uses a simple overall structure.

The scripts/data is broken up into 16KB blocks that are mapped into the $4000-$7FFF region.

Bank $0A/$0B, ROM offset $14000-$17FFF
Bank $0C/$0D, ROM offset $18000-$1BFFF
Bank $0E/$0F, ROM offset $1C000-$1FFFF
Bank $14/$15, ROM offset $28000-$2BFFF

Each block starts with 1 byte bank number (presumably just for reference)

Then there's a table of 2-byte pointers to each of the individual asset chunks within the block (a chunk is either script or graphics).

Those pointers are always going to be in the range $4000-$7FFF.

There's a table in bank $01 (mapped into $c000-$dfff) that the code uses to locate each of the script chunks, it's split into 2 parts.

The 1st part gives the bank number to map into $4000-$7fff, and the 2nd part gives the low byte of the address of the table of asset chunk pointers to load the actual pointer from to get to one of your "text blocks".

A number of those text blocks are contiguous in memory, so if you're just looking at the raw data in the ROM, then you're probably losing track of what the game thinks of as the actual start-end of the different individual asset blocks.

With this info, you should be able to expand the game's ROM and relocate any of the text blocks into the extra memory and so avoid the problems that you're having.

The 1st table of bank numbers is at $C939 (ROM $02939), and the 2nd table of asset pointer offsets is at $C95A (ROM $0295A).

The contents of those tables are ...

; rom $02939 : script bank

$c939 0e 0e 0e 0e 0e 0e 0c 0e
$c941 0e 00 00 00 00 00 00 00
$c949 14 0a 0a 0a 0a 0a 0c 0c
$c951 0c 0c 0c 0c 0c 0c 0c 0c
$c959 0c

; rom $0295a : script offset

$c95a 01 03 05 07 09 0b 17 0d
$c962 0f 00 00 00 00 00 00 00
$c96a 83 01 03 05 07 09 01 03
$c972 05 07 09 0b 0d 0f 11 13
$c97a 15


Does that make any sense?

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #171 on: October 23, 2016, 10:31:38 PM »
That does indeed explain why some of the expanded text seems to have broken other, unrelated parts of the game.

I think I've got my head around most of what you've explained (and thank you very much for taking the time to do so!). Those 4 text banks you've identified overlap with the text sections I have extracted and am injecting back in, so that makes sense why the bulk of what I'm doing works, but also why it starts to go awry later one.

I have a couple of clarifications though:

- In the 16kb text block 'banks' (0x0a/0x0b, 0x14/0x15 etc), In the table of 2-byte asset pointers immediately following the text bank number, how do I know how many of those such pointers there are before the assets begin?

- In the main bank 0x01, in the second table, what are those asset pointer offsets doing? I can see that when bank 0x14 is loaded for example, the corresponding offset is 0x83. But what does that actually result in?

Many thanks for the information so far, I think this will be an incredible step forward. I was at the point of contemplating going back to fixed-length string insertions, which, while it would have worked, would have resulted in some awful dialogue compared to the original Japanese.
 

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #172 on: October 24, 2016, 01:16:32 AM »
Okay, I think I can answer the first question myself now, having looked at one of the asset banks in more detail.

Here's the start of 0x0C bank:

ROM position 0x18000-0x1BFFF

0C 19 40 62 44 61 4C 47 51 27 59 16 5C 4B 63 17 6E A2 6E D5 71 DB 75 CE 78 00 .....

So, if I follow your advice, the first byte, 0x0C is the text bank number. Then there is a single byte 0x19 which is 25 in decimal. Count 25 bytes, take off 1 for the 'size' and then that's the number of pointers in the table. That gives the following:

Bank: 0x0C
Size: 0x19
Pointers: 0x4062, 0x4461, 0x4C47, 0x5127, 0x5916, 0x5C4B, 0x6317, 0x6EA2, 0x6ED5, 0x71DB, 0x75CE, 0x7800

That seems to work for the other asset banks, too, with asset bank 0x14 the biggest, with a 147 byte table.

So, (now the gears are turning in my mind...) does that mean that when bank 0x0E is loaded from the first entry in the main bank 0x01, it jumps to pointer 1 (offset 0x01 from the offset table) in the table? Likewise, the last load entry for table 0x0C jumps to position 0x15 in the header table?

Have I got that right?

I guess that once it jumps to pointer position 0x15 (which will point to a block of text at 0x5FFF, say), it will then follow the logic from before, of looping over the script fragments in that block at 0x5FFF, skipping end-of-string bytes until it finds the 93rd one (for example), then displays it?

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #173 on: October 24, 2016, 01:20:53 AM »
To clarify the number of pointers at the start of an asset bank:

Second byte = 0x19 = 25 = 24/2 = 12x 2-byte pointers

I think that's correct.

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #174 on: October 24, 2016, 03:43:15 AM »
Okay, I've written up a summary of the asset banks so far.

Code: [Select]
==============================================

Master Bank $01, always loaded at 0xC000-0xDFFF

Table A, ROM offset 0x02939, type = Script Text Bank pointers
This is a table of which Text Bank to load at any point.

Start byte position = 10553

Data:
0e 0e 0e 0e 0e 0e 0c 0e
0e 00 00 00 00 00 00 00
14 0a 0a 0a 0a 0a 0c 0c
0c 0c 0c 0c 0c 0c 0c 0c
0c

There are 33 bank load addresses, many of which, as shown, are duplicates.

---

Table B, ROM offset 0x0295a, type = Script Offset pointers.
This is a table of offsets into the pointer tables at the start of each text bank.

Start byte position = 10586

Data:
01 03 05 07 09 0b 17 0d
0f 00 00 00 00 00 00 00
83 01 03 05 07 09 01 03
05 07 09 0b 0d 0f 11 13
15

There are 33 asset chunk pointer offset addresses, one for each of the bank load entries in Table A.

=============================================

The below text banks are always loaded at 0x4000-0x7FFF

=============================================

Text Bank $0A/$0B, ROM offset $14000-$17FFF
First byte = Bank number = 0x0A
Second byte = 0x0B = 11 = 10/2 = 5x 2-byte pointers

Pointer Data
-------------
0A 0B 40 FD 54 6F 6A 29
6C C1 75 00

Pointer Table
----------------
Position / Value
0x00 = 0A = Bank ID
0x01 = 0B = Table size
0x02 = 40 FD - 0x4000 + 0x14000 = 0x140FD
0x03 = 54 6F - 0x4000 + 0x14000 = 0x1546F
0x04 = 6A 29 - 0x4000 + 0x14000 = 0x16A29
0x05 = 6C C1 - 0x4000 + 0x14000 = 0x16CC1
0x06 = 75 00 - 0x4000 + 0x14000 = 0x17500

=============================================

Text Bank $0C/$0D, ROM offset $18000-$1BFFF
First byte = Bank number = 0x0C
Second byte = 0x19 = 25 = 24/2 = 12x 2-byte pointers

Pointer Data
-------------
0C 19 40 62 44 61 4C 47
51 27 59 16 5C 4B 63 17
6E A2 6E D5 71 DB 75 CE
78 00

Pointer Table
----------------
Position / Value
0x00 = 0C = Bank ID
0x01 = 19 = Table size
0x02 = 40 62 - 0x4000 + 0x18000 = 0x18062
0x03 = 44 61 - 0x4000 + 0x18000 = 0x18461
0x04 = 4C 47 - 0x4000 + 0x18000 = 0x18C47
0x05 = 51 27 - 0x4000 + 0x18000 = 0x19127
0x06 = 59 16 - 0x4000 + 0x18000 = 0x19916
0x07 = 5C 4B - 0x4000 + 0x18000 = 0x19C4B
0x08 = 63 17 - 0x4000 + 0x18000 = 0x1A317
0x09 = 6E A2 - 0x4000 + 0x18000 = 0x1AEA2
0x0A = 6E D5 - 0x4000 + 0x18000 = 0x1AED5
0x0B = 71 DB - 0x4000 + 0x18000 = 0x1B1DB
0x0C = 75 CE - 0x4000 + 0x18000 = 0x1B5CE
0x0D = 78 00 - 0x4000 + 0x18000 = 0x1B800

=============================================

Text Bank $0E/$0F, ROM offset $1C000-$1FFFF
First byte = Bank number = 0x0E
Second byte = 0x11 = 17 bytes = 16/2 = 8x 2-byte pointers

Pointer Data
-------------
0E 11 40 4C 4B ED 4E 73
53 B2 55 86 5C FF 6B EC
70 00

Pointer Table
----------------
Position / Value
0x01 = 0E = Bank ID
0x02 = 11 = Table size
0x03 = 40 4C - 0x4000 + 0x1C000 = 0x1C04C
0x04 = 4B ED - 0x4000 + 0x1C000 = 0x1CBED
0x05 = 4E 73 - 0x4000 + 0x1C000 = 0x1CE73
0x06 = 53 B2 - 0x4000 + 0x1C000 = 0x1D3B2
0x07 = 55 86 - 0x4000 + 0x1C000 = 0x1D586
0x08 = 5C FF - 0x4000 + 0x1C000 = 0x1DCFF
0x09 = 6B EC - 0x4000 + 0x1C000 = 0x1EBEC
0x0A = 70 00 - 0x4000 + 0x1C000 = 0x1F000

=============================================

Text Bank $14/$15, ROM offset $28000-$2BFFF
First byte = Bank number = 0x14
Second byte = 0x93 = 147 bytes = 146/2 = 73x 2-byte pointers <- INCORRECT, only 66 pointers in this table.

Pointer Data
-------------
14 93 6D 95 6D A4 6D 36
6E 65 6E B7 6E 95 6D 0E
6F 95 6D 3D 6F 5E 70 95
6D 84 70 95 6D 93 6D 45
71 71 71 02 72 37 72 B2
72 95 6D 0E 73 DF 73 95
6D 20 74 81 74 AA 74 BD
74 D4 74 93 6D 93 6D 42
75 95 6D 74 75 B4 75 95
6D F7 75 49 76 95 6D 6F
76 F4 76 B4 77 CF 77 CF
77 95 6D 93 6D 93 6D 93
6D 93 6D 93 6D 93 6D 93
6D 93 6D 93 6D 93 6D DA
77 95 6D FA 77 6C 78 C1
78 E4 78 0C 79 93 6D 3D
79 15 6A 85 40 00

Pointer Table
----------------
Position / Value
0x01 = 14 = Bank ID
0x02 = 93 = Table size <- INCORRECT

TODO: The table size byte (0x93 == 147) doesn't appear to correlate to the actual number of entries (133 - 1 / 2 = 66) in the table for bank 0x0E, as there are not 73 entries in the table.

One problem I've found is that the second byte == pointer table size assumption doesn't hold true for bank 0x14/0x15 - it should have a 147 byte pointer table == 76 pointers, but it only appears to have 66 pointers if we assume they all have to be within 0x4000-0x7FFF. Something odd happening with that one.

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #175 on: October 24, 2016, 05:11:19 AM »
Okay, I've written up a summary of the asset banks so far.

Code: [Select]
==============================================

Text Bank $14/$15, ROM offset $28000-$2BFFF
First byte = Bank number = 0x14
Second byte = 0x93 = 147 bytes = 146/2 = 73x 2-byte pointers <- INCORRECT, only 66 pointers in this table.

Pointer Data
-------------
14 93 6D 95 6D A4 6D 36
6E 65 6E B7 6E 95 6D 0E
6F 95 6D 3D 6F 5E 70 95
6D 84 70 95 6D 93 6D 45
71 71 71 02 72 37 72 B2
72 95 6D 0E 73 DF 73 95
6D 20 74 81 74 AA 74 BD
74 D4 74 93 6D 93 6D 42
75 95 6D 74 75 B4 75 95
6D F7 75 49 76 95 6D 6F
76 F4 76 B4 77 CF 77 CF
77 95 6D 93 6D 93 6D 93
6D 93 6D 93 6D 93 6D 93
6D 93 6D 93 6D 93 6D DA
77 95 6D FA 77 6C 78 C1
78 E4 78 0C 79 93 6D 3D
79 15 6A 85 40 00

One problem I've found is that the second byte == pointer table size assumption doesn't hold true for bank 0x14/0x15 - it should have a 147 byte pointer table == 76 pointers, but it only appears to have 66 pointers if we assume they all have to be within 0x4000-0x7FFF. Something odd happening with that one.

You've made a logical-deduction that makes sense from a programmer's point-of-view, but it doesn't actually match reality.  :wink:

You're making the mistake of assuming that the 1st asset chunk in the 16KB block is actually always going to be the 1st entry in the table (I made that same mistake when I was doing the Zeroigar translation).

Since the table is a list of pointers, and the game will just refer to assets by block number & index number, then it's OK for a data block to have things stored out-of-order.

That's the case with bank $14 ... if you look, the last pointer in the table (at $4083) is the pointer to that script chunk in there that starts at $4085.

So the script chunk is located 1st in the 16KB block, but it's asset-index is $83, and all the other graphics chunks have lower asset-index values.

So to actually find out how many assets are in a 16KB block, you've got to read all of the 2-byte pointers, as 2-byte pointers, from the start of the table onwards, keeping track of the lowest value that you see, and then stop reading when you hit the point that the pointer to the table is the same as the lowest asset pointer.

Or you can just do it by-eye since there are so few chunks that you'll need to modify.


elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #176 on: October 24, 2016, 05:27:42 AM »
So, (now the gears are turning in my mind...) does that mean that when bank 0x0E is loaded from the first entry in the main bank 0x01, it jumps to pointer 1 (offset 0x01 from the offset table) in the table? Likewise, the last load entry for table 0x0C jumps to position 0x15 in the header table?

Have I got that right?

I guess that once it jumps to pointer position 0x15 (which will point to a block of text at 0x5FFF, say), it will then follow the logic from before, of looping over the script fragments in that block at 0x5FFF, skipping end-of-string bytes until it finds the 93rd one (for example), then displays it?

It's all just a way for the original game programmers to be able to move individual asset-chunks around inside a sort of pseudo file-system in the ROM so that they can pack each ROM bank as-full-as-possible and just refer to assets as a 2-byte bank+index.

Remember, ROM is (was) expensive, and the challenge of packing things into cartridge space was one of the biggest problems of that era of game programming.

The tables at $02939 & $0295a for the script bank and offset look like they're just for the text blocks.

There could easily be some other tables somewhere for graphics blocks or other assets, or maybe the original developers just used a list of equates/#defines for those in their source code.

The big thing is ... there's now nothing stopping you from creating new 16KB blocks of text assets in an expanded ROM for the translation, and then moving some/all of the English text asset-chunks into the new blocks.

You'd only need to change the tables at $02939 & $0295a to point to your new asset chunks.

You can do the same when it comes to changing any of the graphics that you want to (like the lower-case descenders on that font).

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #177 on: October 24, 2016, 05:43:21 AM »
I think I've got it, but I want to run through the pointer system a few times so that I'm clear. I think I've got where asset index $83 is coming from, and what it relates to, but want to be sure before asking more inane questions  #-o

I'll play around with a few examples this evening first.

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #178 on: October 24, 2016, 06:14:03 AM »
I think I've got it, but I want to run through the pointer system a few times so that I'm clear. I think I've got where asset index $83 is coming from, and what it relates to, but want to be sure before asking more inane questions  #-o

Things become clearer if you just reformat the data so that it's more like what a programmer would write ...

ROM     Idx   Pointer
----------------------
$4000         db  $14
$4001   $01   dw  $6D93
$4003   $03   dw  $6D95
$4005   $05   dw  $6DA4
$4007   $07   dw  $6E36
$4009   $09   dw  $6E65
$400b   $0b   dw  $6EB7
$400d   $0d   dw  $6D95
$400f   $0f   dw  $6F0E
$4011   $11   dw  $6D95
$4013   $13   dw  $6F3D
$4015   $15   dw  $705E
$4017   $17   dw  $6D95
$4019   $19   dw  $7084
$401b   $1b   dw  $6D95
$401d   $1d   dw  $6D93
$401f   $1f   dw  $7145
$4021   $21   dw  $7171
$4023   $23   dw  $7202
$4025   $25   dw  $7237
$4027   $27   dw  $72B2
$4029   $29   dw  $6D95
$402b   $2b   dw  $730E
$402d   $2d   dw  $73DF
$402f   $2f   dw  $6D95
$4031   $31   dw  $7420
$4033   $33   dw  $7481
$4035   $35   dw  $74AA
$4037   $37   dw  $74BD
$4039   $39   dw  $74D4
$403b   $3b   dw  $6D93
$403d   $3d   dw  $6D93
$403f   $3f   dw  $7542
$4041   $41   dw  $6D95
$4043   $43   dw  $7574
$4045   $45   dw  $75B4
$4047   $47   dw  $6D95
$4049   $49   dw  $75F7
$404b   $4b   dw  $7649
$404d   $4d   dw  $6D95
$404f   $4f   dw  $766F
$4051   $51   dw  $76F4
$4053   $53   dw  $77B4
$4055   $55   dw  $77CF
$4057   $57   dw  $77CF
$4059   $59   dw  $6D95
$405b   $5b   dw  $6D93
$405d   $5d   dw  $6D93
$405f   $5f   dw  $6D93
$4061   $61   dw  $6D93
$4063   $63   dw  $6D93
$4065   $65   dw  $6D93
$4067   $67   dw  $6D93
$4069   $69   dw  $6D93
$406b   $6b   dw  $6D93
$406d   $6d   dw  $6D93
$406f   $6f   dw  $77DA
$4071   $71   dw  $6D95
$4073   $73   dw  $77FA
$4075   $75   dw  $786C
$4077   $77   dw  $78C1
$4079   $79   dw  $78E4
$407b   $7b   dw  $790C
$407d   $7d   dw  $6D93
$407f   $7f   dw  $793D
$4081   $81   dw  $6A15
$4083   $83   dw  $4085


In particular, note the multiple table entries that refer to the same asset-chunk at $6D93 & $6D95.

That's some programming-trick going on, possibly for level-loading or something like that where you want to use the same graphics for the main character in the game.
« Last Edit: October 24, 2016, 06:20:58 AM by elmer »

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #179 on: October 24, 2016, 06:41:57 AM »
BTW ... there's no substitute for running the game in Mednafen when it comes to understanding what's going on (if you understand assembly language).

I'd recommend using my custom-built version that's linked in one of the other threads because the new larger fonts make it so much easier to read.

If you run the game in there, then here are the locations of some useful routines (all logical game addresses, and not ROM offsets) ...

$f1e0 - code that maps a 16KB data block into $4000-$7fff.
$f1ce - code that takes a Bank & Asset-Index and maps in the bank and returns a pointer to the asset.

$cd32 - code that takes a script number, and uses the tables at $c939 & $c95a to map in the correct data bank and then load the pointer to the script asset into $30/$31.