Author Topic: Cyber Knight translation  (Read 10346 times)

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #210 on: October 29, 2016, 06:31:01 AM »
Cheers!

I've modified the old mapScript.py code to work on the new JSON. I've run it through a few asset files and it's working the same as before, so it looks like I can get pretty much all of the automatic translations done again in no time.

The time sink will be the manual patches I did by hand in the old files.

I do prefer JSON to XML, it's much less noisy and XML always reminds me of LISP; matching opening and closing braces. I hated that at University.

JSON is a much lighter transfer format and it maps neatly to Python/Ruby/Javascript dictionaries and lists. Normally I wouldn't manually write JSON like I am doing now with file.write(), but because we've got a mix of ASCII and various Unicode fonts (shift-JIS, UTF-8, etc) all in the same file, it's a bit of pain to serialize it all just using a single json.dumps() call. Do as I say, not as I do, folks  :lol:
« Last Edit: October 29, 2016, 06:34:58 AM by megatron-uk »

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #211 on: October 31, 2016, 06:22:18 AM »
Update from a couple of passes through the mapAssets.py script, using only the first couple of 'quality' levels of the fuzzy matching against the SNES script. Each 'quality level' represents a pass through the code where I use a different level at which I consider a script to be matched. I start of at level 1 with only strings that are >80% as possible matches, then each level after that drops by 5-10%. Once you get to level 6 or so you really need to start comparing by eyeball.

There's a lot more automatic matches still to get:

Code: [Select]
mapAssets.py - Map untranslated patches from the PC-Engine CyberKnight to the SNES script
----------------

Configuration
=============
Verbose: False
Over-write: False
Pass Type: 1
SNES Script File: CyberKnightSNES.csv <- OK
Input Directory: assets/split <- OK
Output Directory: assets/converted <- OK
Patches Found: 26 <- OK

Patch Summary
=============
|--------|------------|------------|----------|----------|---------|--------|---------------
| Strings|Translations|SNES matches|SNES best |SNES worst|SNES avg.| Tiny   | Patch Name
|--------|------------|------------|----------|----------|---------|--------|---------------
|  198   |   7 / 198  |   48 / 198 |      100 |        0 |      56 |   114  | 0x14.0x83.dat
|  136   |   0 / 136  |   39 / 136 |       93 |        0 |      52 |    80  | 0xa.0x1.dat
|  131   |   0 / 131  |   41 / 131 |      100 |        0 |      56 |    69  | 0xa.0x3.dat
|   21   |   0 /  21  |    7 /  21 |      100 |        0 |      68 |    13  | 0xa.0x5.dat
|   42   |   0 /  42  |   12 /  42 |       92 |        0 |      62 |    22  | 0xa.0x7.dat
|   82   |   0 /  82  |   31 /  82 |      100 |        0 |      74 |    45  | 0xa.0x9.dat
|   24   |   0 /  24  |    2 /  24 |        0 |        0 |       0 |    13  | 0xc.0x1.dat
|   25   |   0 /  25  |    9 /  25 |       92 |        0 |      59 |    13  | 0xc.0x11.dat
|    9   |   0 /   9  |    3 /   9 |       90 |        0 |      57 |     6  | 0xc.0x13.dat
|   29   |  22 /  29  |   12 /  29 |       89 |        0 |      70 |    16  | 0xc.0x15.dat
|  105   | 105 / 105  |    1 / 105 |        0 |        0 |       0 |    65  | 0xc.0x17.dat
|   74   |   0 /  74  |   33 /  74 |      100 |        0 |      73 |    38  | 0xc.0x3.dat
|   50   |   0 /  50  |   20 /  50 |      100 |        0 |      82 |    27  | 0xc.0x5.dat
|   53   |   0 /  53  |   22 /  53 |       90 |        0 |      61 |    27  | 0xc.0x7.dat
|   42   |   0 /  42  |   14 /  42 |      100 |        0 |      63 |    25  | 0xc.0x9.dat
|   29   |   0 /  29  |   10 /  29 |       90 |        0 |      17 |    16  | 0xc.0xb.dat
|   93   |   0 /  93  |   37 /  93 |       92 |        0 |      46 |    47  | 0xc.0xd.dat
|    5   |   3 /   5  |    2 /   5 |       92 |       72 |      82 |     3  | 0xc.0xf.dat
|  277   |   0 / 277  |   17 / 277 |      100 |        0 |      62 |   151  | 0xe.0x1.dat
|  287   |   0 / 287  |   66 / 287 |      100 |        0 |      49 |   185  | 0xe.0x3.dat
|  161   |   0 / 161  |   20 / 161 |      100 |        0 |      69 |    93  | 0xe.0x5.dat
|  149   | 148 / 149  |   56 / 149 |       92 |        0 |      48 |    89  | 0xe.0x7.dat
|  260   |   0 / 260  |   77 / 260 |      100 |        0 |      71 |   153  | 0xe.0x9.dat
|  385   |   0 / 385  |   77 / 385 |      100 |        0 |      68 |   227  | 0xe.0xb.dat
|  221   |   0 / 221  |    0 / 221 |        0 |      100 |       0 |   152  | 0xe.0xd.dat
|  228   |   0 / 228  |   75 / 228 |      100 |        0 |      81 |   134  | 0xe.0xf.dat
|--------|------------|------------|----------|----------|---------|--------|---------------
| Strings|Translations|SNES matches|SNES best |SNES worst|SNES avg.| Tiny   | Patch Name
|--------|------------|------------|----------|----------|---------|--------|---------------
| 3116   | 285 / 3116 | 731 / 3116 |      100 |        0 |      14 |   1823  |

Patch Summary Key
=================
Strings      : Total number of text strings in the patch file
Translations : How many strings already have we added a full english translation for?
SNES Matches : How many strings have matching SNES english text that canbe used as a basis for an english translation?
SNES Best    : The most accurate SNES match in this patch file.
SNES Worst   : The least accurate SNES match in this patch file.
SNES average : The average accuracy of SNES matches in this patch file.
Tiny         : How many strings are sub-2 characters (ie not text)?

The key figures are the SNES matches and Translations columns. The former is the number of automatic matches my code made against the SNES script, by comparing the decoded PCE byte sequences, and the latter is the number of by-hand entries I've made, or cut-and-paste from the SNES matches. I don't automatically use the SNES script matches, as there's a lot of improvements that can be made by eye (available length of text boxes, some grammar, as well as some words/phrases that I think can be improved).

On that note I'm thinking about having all of the items, monsters and names parameterised,  liked I'm using <newbox> or <wait> to represent different byte sequences. I'm using <NPC_name> at present, to ease name replacement if I desire, but I could extend it to items and other things. One thing that I want to replace for a more 'science fiction' feel is the use of the phrase 'monopole coil' (which is an in-game widget that you need to find to fix your ship FTL drive). I think a far more appropriate phrase would be a 'singularity' coil or cell. I think there is quite a bit of that kind of stuff in the game though  :wink:

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #212 on: November 03, 2016, 11:10:13 AM »
Found a couple more text control codes:

0x19 0x71 - Move cursor to the box that was active 2 windows ago
0x19 0x72 - Move cursor to the box that was active 3 windows ago
0x19 0x73 - Move cursor to the box that was active before this one

These take effect during the intro cinema and there are matching control codes used throughout in-game dialogue (both prefixed with 0x19, but the second byte differs). It doesn't appear the second byte can be swapped between the values used in-game and the cinema section (random text appears instead).

It explains how the active text window changes, especially when multiple characters have open dialogue on screen at any one point. Also gives me a bit more flexibility when 'enhancing' the more in-depth segments.

I've updated the translation table to include these and will run the script through it again.

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #213 on: November 04, 2016, 02:16:55 PM »
More story and in-game text done. Some bits I've expanded substantially; reworking simple one-line , one-way dialogue into more developed conversations between the player party and NPC's. Nothing earth shattering. For example, later in the game you run into the Garaians, and advanced but quite staid and pacifist race. They are also extremely boring and dislike violence.

One of the conversations originally went something like this:

NPC: "X warring race is awful."
NPC: "So are the killer machines."
NPC: "In fact, so is anyone with weapons."

I added in a dialogue box from one of the players party after the second line to say:

Player Party: "That sounds like they're talking about the <bleep> there..."

Just to give you an indication that these alien dudes are talking about the same nasties that you start to encounter yourself :)

What I would like to do, and haven't found a way to do it yet, is any control codes that adjust font colour. It would be nice to have 'inner thought' type messages like that in a different colour. Same goes for 'You acquired the widget!' in game messages. Just to differentiate against spoken dialogue.

Here's the stats so far:

Code: [Select]
mapAssets.py - Map untranslated patches from the PC-Engine CyberKnight to the SNES script
----------------

Configuration
=============
Verbose: False
Over-write: False
Pass Type: 1
SNES Script File: CyberKnightSNES.csv <- OK
Input Directory: assets/split <- OK
Output Directory: assets/converted <- OK
Patches Found: 26 <- OK

Patch Summary
=============
|--------|------------|------------|----------|----------|---------|--------|---------------
| Strings|Translations|SNES matches|SNES best |SNES worst|SNES avg.| Tiny   | Patch Name
|--------|------------|------------|----------|----------|---------|--------|---------------
|  198   |   7 / 198  |   48 / 198 |      100 |        0 |      56 |   114  | 0x14.0x83.dat
|  136   |   0 / 136  |   39 / 136 |       93 |        0 |      52 |    80  | 0xa.0x1.dat
|  131   |   0 / 131  |   41 / 131 |      100 |        0 |      56 |    69  | 0xa.0x3.dat
|   21   |  21 /  21  |    7 /  21 |      100 |        0 |      53 |    13  | 0xa.0x5.dat COMPLETE
|   42   |   0 /  42  |   12 /  42 |       92 |        0 |      62 |    22  | 0xa.0x7.dat
|   82   |   0 /  82  |   31 /  82 |      100 |        0 |      74 |    45  | 0xa.0x9.dat
|   24   |  15 /  24  |    2 /  24 |        0 |        0 |       0 |    13  | 0xc.0x1.dat
|   25   |  25 /  25  |    9 /  25 |       92 |        0 |      59 |    13  | 0xc.0x11.dat COMPLETE
|    9   |   9 /   9  |    3 /   9 |       90 |        0 |      57 |     6  | 0xc.0x13.dat COMPLETE
|   29   |  29 /  29  |   12 /  29 |       89 |        0 |      70 |    16  | 0xc.0x15.dat COMPLETE
|  105   | 105 / 105  |    1 / 105 |        0 |        0 |       0 |    65  | 0xc.0x17.dat COMPLETE
|   74   |   0 /  74  |   33 /  74 |      100 |        0 |      73 |    38  | 0xc.0x3.dat
|   50   |   0 /  50  |   20 /  50 |      100 |        0 |      82 |    27  | 0xc.0x5.dat
|   53   |   0 /  53  |   22 /  53 |       90 |        0 |      61 |    27  | 0xc.0x7.dat
|   42   |   0 /  42  |   14 /  42 |      100 |        0 |      63 |    25  | 0xc.0x9.dat
|   29   |  28 /  29  |   11 /  29 |       90 |        0 |      15 |    16  | 0xc.0xb.dat
|   93   |   0 /  93  |   37 /  93 |       92 |        0 |      46 |    47  | 0xc.0xd.dat
|    5   |   5 /   5  |    2 /   5 |       92 |       72 |      82 |     3  | 0xc.0xf.dat COMPLETE
|  274   | 149 / 274  |   13 / 274 |       93 |        0 |      51 |   149  | 0xe.0x1.dat
|  287   |   0 / 287  |   66 / 287 |      100 |        0 |      49 |   185  | 0xe.0x3.dat
|  161   |   0 / 161  |   20 / 161 |      100 |        0 |      69 |    93  | 0xe.0x5.dat
|  149   | 148 / 149  |   56 / 149 |       92 |        0 |      48 |    89  | 0xe.0x7.dat
|  260   |   0 / 260  |   77 / 260 |      100 |        0 |      71 |   153  | 0xe.0x9.dat
|  385   |   0 / 385  |   77 / 385 |      100 |        0 |      68 |   227  | 0xe.0xb.dat
|  221   |   0 / 221  |    0 / 221 |        0 |      100 |       0 |   152  | 0xe.0xd.dat
|  228   |   0 / 228  |   75 / 228 |      100 |        0 |      81 |   134  | 0xe.0xf.dat
|--------|------------|------------|----------|----------|---------|--------|---------------
| Strings|Translations|SNES matches|SNES best |SNES worst|SNES avg.| Tiny   | Patch Name
|--------|------------|------------|----------|----------|---------|--------|---------------
| 3113   | 541 / 3113 | 728 / 3113 |      100 |        0 |      14 |   1821  |


Also found another control code: 0x07 - sets the printing speed of the text string that follows. It's controlled by the immediately following byte. Experimentation shows that setting 0x07 0x01 is very slow, about 1 character every 2 seconds, whereas 0x07 0x2F is very fast, perhaps 10 characters a second.

The expanded text isn't getting inserted just yet. I'd like to try and track down as much of the control codes as possible before then.

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #214 on: November 04, 2016, 04:07:13 PM »
Found a couple more text control codes:

0x19 0x71 - Move cursor to the box that was active 2 windows ago
0x19 0x72 - Move cursor to the box that was active 3 windows ago
0x19 0x73 - Move cursor to the box that was active before this one

Excellent detective work!  :D

You're finding and understanding things through alteration/experimentation that I'd have found by looking at the source-code itself.

The method isn't important ... for something like this, it's all about the result, and your persistence is paying off!

Congratulations!  :wink:


I added in a dialogue box from one of the players party after the second line to say:

Player Party: "That sounds like they're talking about the <bleep> there..."

And this is why I'm taking some of my time to hopefully provide a little help.

You care enough about the game that you want it to sound good to an English-speaking audience, and you're not just satisfied with making it understandable.

Some passions deserve to be supported, even if they're not initially understood or shared.

That's how I felt when I saw SamIAm's work on Zeroigar, and you can see where his passion and enthusiasm lead in our continuing work on Xanadu 1 and Xanadu 2.

At the end of the day, it all (and IMHO always) relies upon someone who has a belief and passion in something informing/educating everyone else into seeing why they love that thing (game/sport/food/etc), and becoming "believers" themselves.

SamIAm has managed to get me to "believe" in a couple of games now that I didn't even know existed a few years ago.

And after the introduction, and spending months working on them, I understand why he loves those games, and I've come to share that love, and to trust his opinion.

What megatron-uk is doing here with Cyber Knight seems (to me) to show that same kind of passion.

He's doing (as esteban would say) "God's Work!".


Speaking of which ...

... here's the data table that Cyber Knight uses to load up the ASCII font into VRAM.

They're grouping a number of individual graphical "assets" into different VRAM "layout" arrangements that get set up at different times.

The ASCII font itself is compressed in bank $16, asset $01 ... but as you can see, the reference to it will need to be modified in a lot of places if that font is going to be changed.

Code: [Select]
ASSET BANK $10 ASSET CHUNK $0d

                .org  $4875

                .dw  group_4807 ; idx $00 - $4785 (1st font data loaded @ $1000-$1fff)
                .dw  group_4843 ; idx $01 - $4787
                .dw  group_487f ; idx $02 - $4789
                .dw  group_4893 ; idx $03 - $478b
                .dw  group_4893 ; idx $04 - $478d
                .dw  group_48d9 ; idx $05 - $478f
                .dw  group_48ed ; idx $06 - $4791
                .dw  group_4901 ; idx $07 - $4793
                .dw  group_4915 ; idx $08 - $4795
                .dw  group_4929 ; idx $09 - $4797
                .dw  group_493d ; idx $0a - $4799
                .dw  group_4951 ; idx $0b - $479b
                .dw  group_495b ; idx $0c - $479d
                .dw  group_496f ; idx $0d - $479f
                .dw  group_49c9 ; idx $0e - $47a1
                .dw  group_49d3 ; idx $0f - $47a3
                .dw  group_49dd ; idx $10 - $47a5
                .dw  group_49dd ; idx $11 - $47a7
                .dw  group_4a41 ; idx $12 - $47a9
                .dw  group_4aa5 ; idx $13 - $47ab
                .dw  group_4b13 ; idx $14 - $47ad
                .dw  group_4b77 ; idx $15 - $47af
                .dw  group_4bef ; idx $16 - $47b1
                .dw  group_4c67 ; idx $17 - $47b3
                .dw  group_4c67 ; idx $18 - $47b5
                .dw  group_4cdf ; idx $19 - $47b7
                .dw  group_4cfd ; idx $1a - $47b9
                .dw  group_4d1b ; idx $1b - $47bb
                .dw  group_4d43 ; idx $1c - $47bd
                .dw  group_4da7 ; idx $1d - $47bf
                .dw  group_4dc5 ; idx $1e - $47c1
                .dw  group_4ded ; idx $1f - $47c3
                .dw  group_4ded ; idx $20 - $47c5
                .dw  group_4ded ; idx $21 - $47c7
                .dw  group_4ded ; idx $22 - $47c9
                .dw  group_4ded ; idx $23 - $47cb
                .dw  group_4ded ; idx $24 - $47cd
                .dw  group_4ded ; idx $25 - $47cf
                .dw  group_4ded ; idx $26 - $47d1
                .dw  group_4ded ; idx $27 - $47d3
                .dw  group_4ded ; idx $28 - $47d5
                .dw  group_4ded ; idx $29 - $47d7
                .dw  group_4ded ; idx $2a - $47d9
                .dw  group_4ded ; idx $2b - $47db
                .dw  group_4ded ; idx $2c - $47dd
                .dw  group_4ded ; idx $2d - $47df
                .dw  group_4ded ; idx $2e - $47e1
                .dw  group_4ded ; idx $2f - $47e3
                .dw  group_4ded ; idx $30 - $47e5
                .dw  group_4df7 ; idx $31 - $47e7
                .dw  group_4e01 ; idx $32 - $47e9
                .dw  group_4e1f ; idx $33 - $47eb
                .dw  group_4e29 ; idx $34 - $47ed
                .dw  group_4e47 ; idx $35 - $47ef
                .dw  group_4e51 ; idx $36 - $47f1
                .dw  group_4e5b ; idx $37 - $47f3
                .dw  group_4e5b ; idx $38 - $47f5
                .dw  group_4e5b ; idx $39 - $47f7
                .dw  group_4e97 ; idx $3a - $47f9
                .dw  group_4edd ; idx $3b - $47fb
                .dw  group_4f0f ; idx $3c - $47fd
                .dw  group_4f41 ; idx $3d - $47ff
                .dw  group_4f73 ; idx $3e - $4801
                .dw  group_4faf ; idx $3f - $4803
                .dw  group_4faf ; idx $40 - $4805

        ; idx $00 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4807:     .db $00,$11,  $6b,  $0c,  $80,$00,$80,$80,  $16,$01
group_4811:     .db $00,$18,  $80,  $0c,  $80,$00,$80,$80,  $16,$03
group_481b:     .db $b0,$17,  $04,  $24,  $00,$08,$10,$18,  $16,$05
group_4825:     .db $00,$11,  $01,  $08,  $c0,$80,$80,$80,  $16,$01
group_482f:     .db $00,$10,  $08,  $20,  $00,$08,$10,$18,  $16,$0d
group_4839:     .db $00,$20,  $00,  $0c,  $80,$00,$80,$80,  $16,$07

        ; idx $01 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4843:     .db $00,$11,  $6b,  $0c,  $40,$00,$40,$40,  $16,$01
group_484d:     .db $00,$18,  $80,  $0c,  $40,$00,$40,$40,  $16,$03
group_4857:     .db $b0,$17,  $04,  $24,  $00,$08,$10,$18,  $16,$05
group_4861:     .db $00,$11,  $01,  $08,  $c0,$80,$80,$80,  $16,$01
group_486b:     .db $00,$10,  $08,  $20,  $00,$08,$10,$18,  $16,$0d
group_4875:     .db $00,$20,  $00,  $0c,  $40,$00,$40,$40,  $16,$07

        ; idx $02 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_487f:     .db $00,$30,  $0c,  $1c,  $00,$08,$10,$80,  $1c,$11
group_4889:     .db $c0,$30,  $a7,  $1c,  $00,$08,$10,$c0,  $1c,$13

        ; idx $03 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4893:     .db $00,$11,  $6b,  $0c,  $40,$00,$40,$40,  $16,$01
group_489d:     .db $00,$18,  $80,  $0c,  $40,$00,$40,$40,  $16,$03
group_48a7:     .db $b0,$17,  $04,  $24,  $00,$08,$10,$18,  $16,$05
group_48b1:     .db $00,$11,  $01,  $08,  $c0,$80,$80,$80,  $16,$01
group_48bb:     .db $00,$10,  $07,  $20,  $00,$08,$10,$18,  $16,$0d
group_48c5:     .db $00,$21,  $20,  $0c,  $80,$00,$80,$80,  $16,$01
group_48cf:     .db $00,$21,  $01,  $08,  $c0,$80,$80,$80,  $16,$01

        ; idx $05 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_48d9:     .db $80,$24,  $08,  $0c,  $40,$00,$40,$40,  $16,$09
group_48e3:     .db $80,$26,  $08,  $0c,  $40,$00,$40,$40,  $16,$0b

        ; idx $06 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_48ed:     .db $00,$70,  $0d,  $24,  $00,$08,$10,$18,  $36,$05
group_48f7:     .db $d0,$70,  $30,  $1c,  $00,$08,$10,$80,  $36,$0f

        ; idx $07 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4901:     .db $00,$70,  $0a,  $24,  $00,$08,$10,$18,  $36,$07
group_490b:     .db $a0,$70,  $2a,  $1c,  $00,$08,$10,$80,  $36,$11

        ; idx $08 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4915:     .db $00,$70,  $0b,  $24,  $00,$08,$10,$18,  $36,$09
group_491f:     .db $b0,$70,  $3c,  $1c,  $00,$08,$10,$80,  $36,$13

        ; idx $09 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4929:     .db $00,$70,  $03,  $24,  $00,$08,$10,$18,  $36,$0b
group_4933:     .db $30,$70,  $46,  $1c,  $00,$08,$10,$80,  $36,$15

        ; idx $0a : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_493d:     .db $00,$70,  $0b,  $24,  $00,$08,$10,$18,  $36,$0d
group_4947:     .db $b0,$70,  $3f,  $1c,  $00,$08,$10,$80,  $36,$17

        ; idx $0b : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4951:     .db $00,$20,  $64,  $0c,  $80,$00,$80,$80,  $24,$13

        ; idx $0c : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_495b:     .db $00,$20,  $98,  $0c,  $80,$80,$80,$80,  $24,$15
group_4965:     .db $00,$30,  $98,  $0c,  $80,$00,$80,$80,  $24,$15

        ; idx $0d : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_496f:     .db $00,$10,  $01,  $20,  $00,$08,$10,$18,  $16,$0d
group_4979:     .db $00,$11,  $6b,  $0c,  $00,$80,$80,$80,  $16,$01
group_4983:     .db $00,$18,  $80,  $0c,  $00,$80,$80,$80,  $16,$03
group_498d:     .db $00,$21,  $6b,  $0c,  $80,$00,$80,$80,  $16,$01
group_4997:     .db $00,$28,  $80,  $0c,  $80,$00,$80,$80,  $16,$03
group_49a1:     .db $00,$31,  $6b,  $0c,  $00,$00,$80,$80,  $16,$01
group_49ab:     .db $00,$38,  $80,  $0c,  $00,$00,$80,$80,  $16,$03
group_49b5:     .db $00,$41,  $6b,  $0c,  $80,$80,$00,$80,  $16,$01
group_49bf:     .db $00,$48,  $80,  $0c,  $80,$80,$00,$80,  $16,$03

        ; idx $0e : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_49c9:     .db $00,$30,  $40,  $1c,  $00,$08,$10,$80,  $24,$11

        ; idx $0f : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_49d3:     .db $00,$30,  $f0,  $24,  $00,$08,$10,$18,  $24,$01

        ; idx $10 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_49dd:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_49e7:     .db $60,$43,  $04,  $1c,  $00,$08,$10,$80,  $2c,$05
group_49f1:     .db $a0,$43,  $20,  $1c,  $00,$08,$10,$80,  $2c,$07
group_49fb:     .db $a0,$45,  $31,  $1c,  $00,$08,$10,$80,  $2e,$0d
group_4a05:     .db $b0,$48,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$0b
group_4a0f:     .db $70,$49,  $01,  $1c,  $00,$08,$10,$80,  $2c,$0d
group_4a19:     .db $80,$49,  $43,  $1c,  $00,$08,$10,$80,  $2c,$0f
group_4a23:     .db $b0,$4d,  $05,  $1c,  $00,$08,$10,$80,  $2c,$11
group_4a2d:     .db $00,$4e,  $19,  $24,  $00,$08,$10,$18,  $2c,$13
group_4a37:     .db $90,$4f,  $04,  $1c,  $00,$08,$80,$10,  $2e,$19

        ; idx $12 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4a41:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4a4b:     .db $60,$43,  $04,  $1c,  $00,$08,$10,$80,  $2c,$05
group_4a55:     .db $a0,$43,  $02,  $1c,  $00,$08,$10,$80,  $2c,$15
group_4a5f:     .db $c0,$43,  $2f,  $1c,  $00,$08,$10,$80,  $2c,$09
group_4a69:     .db $b0,$46,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$1d
group_4a73:     .db $70,$47,  $01,  $1c,  $00,$08,$10,$80,  $2c,$33
group_4a7d:     .db $80,$47,  $10,  $1c,  $00,$08,$10,$80,  $2c,$35
group_4a87:     .db $80,$48,  $09,  $1c,  $00,$08,$10,$80,  $2c,$21
group_4a91:     .db $10,$49,  $22,  $1c,  $00,$08,$10,$10,  $2c,$25
group_4a9b:     .db $b0,$4b,  $44,  $1c,  $00,$08,$10,$c0,  $2e,$11

        ; idx $13 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4aa5:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4aaf:     .db $60,$43,  $04,  $1c,  $00,$08,$10,$80,  $2c,$05
group_4ab9:     .db $a0,$43,  $31,  $1c,  $00,$08,$10,$80,  $2e,$0d
group_4ac3:     .db $b0,$46,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$17
group_4acd:     .db $70,$47,  $01,  $1c,  $00,$08,$10,$80,  $2c,$19
group_4ad7:     .db $80,$47,  $22,  $1c,  $00,$08,$10,$80,  $2c,$1b
group_4ae1:     .db $a0,$49,  $02,  $1c,  $00,$08,$10,$80,  $2c,$15
group_4aeb:     .db $c0,$49,  $2f,  $1c,  $00,$08,$10,$80,  $2c,$09
group_4af5:     .db $b0,$4c,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$1d
group_4aff:     .db $70,$4d,  $01,  $1c,  $00,$08,$10,$80,  $2c,$1f
group_4b09:     .db $00,$4e,  $20,  $1c,  $00,$08,$10,$80,  $2c,$03

        ; idx $14 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4b13:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4b1d:     .db $60,$43,  $04,  $1c,  $00,$08,$10,$80,  $2c,$05
group_4b27:     .db $a0,$43,  $02,  $1c,  $00,$08,$10,$80,  $2c,$15
group_4b31:     .db $c0,$43,  $2f,  $1c,  $00,$08,$10,$80,  $2c,$09
group_4b3b:     .db $b0,$46,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$1d
group_4b45:     .db $70,$47,  $01,  $1c,  $00,$08,$10,$80,  $2c,$2b
group_4b4f:     .db $80,$47,  $10,  $1c,  $00,$08,$10,$80,  $2c,$2d
group_4b59:     .db $80,$48,  $09,  $1c,  $00,$08,$10,$80,  $2c,$21
group_4b63:     .db $10,$49,  $22,  $1c,  $00,$08,$10,$10,  $2c,$25
group_4b6d:     .db $30,$4b,  $3b,  $1c,  $00,$08,$80,$10,  $2c,$23

        ; idx $15 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4b77:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4b81:     .db $60,$43,  $04,  $1c,  $00,$08,$10,$80,  $2c,$05
group_4b8b:     .db $a0,$43,  $02,  $1c,  $00,$08,$10,$80,  $2e,$21
group_4b95:     .db $c0,$43,  $2f,  $1c,  $00,$08,$10,$80,  $2c,$09
group_4b9f:     .db $b0,$46,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$1d
group_4ba9:     .db $70,$47,  $01,  $1c,  $00,$08,$10,$80,  $2c,$2b
group_4bb3:     .db $80,$47,  $10,  $1c,  $00,$08,$10,$80,  $2c,$2d
group_4bbd:     .db $80,$48,  $09,  $1c,  $00,$08,$10,$80,  $2c,$21
group_4bc7:     .db $10,$49,  $22,  $24,  $00,$08,$10,$18,  $2e,$0f
group_4bd1:     .db $30,$4b,  $0b,  $1c,  $00,$08,$80,$10,  $2c,$27
group_4bdb:     .db $e0,$4b,  $3c,  $1c,  $00,$08,$80,$10,  $2c,$29
group_4be5:     .db $00,$4f,  $10,  $1c,  $00,$08,$80,$10,  $2c,$01

        ; idx $16 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4bef:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4bf9:     .db $60,$43,  $04,  $1c,  $00,$08,$10,$80,  $2c,$05
group_4c03:     .db $a0,$43,  $02,  $1c,  $00,$08,$10,$80,  $2c,$2f
group_4c0d:     .db $c0,$43,  $2f,  $1c,  $00,$08,$10,$80,  $2c,$09
group_4c17:     .db $b0,$46,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$1d
group_4c21:     .db $70,$47,  $01,  $1c,  $00,$08,$10,$80,  $2c,$2b
group_4c2b:     .db $80,$47,  $10,  $1c,  $00,$08,$10,$80,  $2c,$2d
group_4c35:     .db $80,$48,  $09,  $1c,  $00,$08,$10,$80,  $2c,$21
group_4c3f:     .db $10,$49,  $22,  $24,  $00,$08,$10,$18,  $2c,$25
group_4c49:     .db $30,$4b,  $0b,  $1c,  $00,$08,$80,$10,  $2c,$27
group_4c53:     .db $e0,$4b,  $30,  $1c,  $00,$08,$80,$10,  $2c,$31
group_4c5d:     .db $00,$4f,  $10,  $1c,  $00,$08,$80,$10,  $2c,$01

        ; idx $17 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4c67:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4c71:     .db $60,$43,  $04,  $1c,  $00,$08,$10,$80,  $2c,$05
group_4c7b:     .db $a0,$43,  $02,  $1c,  $00,$08,$10,$80,  $2c,$15
group_4c85:     .db $c0,$43,  $2f,  $1c,  $00,$08,$10,$80,  $2c,$09
group_4c8f:     .db $b0,$46,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$1d
group_4c99:     .db $70,$47,  $01,  $1c,  $00,$08,$10,$80,  $2c,$33
group_4ca3:     .db $80,$47,  $10,  $1c,  $00,$08,$10,$80,  $2c,$35
group_4cad:     .db $80,$48,  $09,  $1c,  $00,$08,$10,$80,  $2c,$21
group_4cb7:     .db $10,$49,  $22,  $24,  $00,$08,$10,$18,  $2c,$25
group_4cc1:     .db $30,$4b,  $0b,  $1c,  $00,$08,$80,$10,  $2c,$27
group_4ccb:     .db $e0,$4b,  $30,  $1c,  $00,$08,$80,$10,  $2c,$29
group_4cd5:     .db $00,$4f,  $10,  $1c,  $00,$08,$80,$10,  $2c,$01

        ; idx $19 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4cdf:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4ce9:     .db $60,$43,  $08,  $1c,  $00,$08,$10,$80,  $2e,$13
group_4cf3:     .db $e0,$43,  $92,  $1c,  $00,$08,$10,$c0,  $2e,$15

        ; idx $1a : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4cfd:     .db $00,$40,  $16,  $1c,  $00,$08,$10,$80,  $2e,$17
group_4d07:     .db $60,$41,  $1e,  $1c,  $00,$08,$80,$10,  $2e,$1f
group_4d11:     .db $40,$43,  $cc,  $1c,  $00,$08,$10,$c0,  $2e,$25

        ; idx $1b : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4d1b:     .db $00,$40,  $0b,  $1c,  $00,$08,$10,$80,  $2c,$37
group_4d25:     .db $b0,$40,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$39
group_4d2f:     .db $70,$41,  $98,  $1c,  $00,$08,$10,$c0,  $2c,$3b
group_4d39:     .db $f0,$4a,  $17,  $1c,  $00,$08,$10,$c0,  $2e,$23

        ; idx $1c : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4d43:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4d4d:     .db $60,$43,  $04,  $1c,  $00,$08,$10,$80,  $2c,$05
group_4d57:     .db $a0,$43,  $02,  $1c,  $00,$08,$10,$80,  $2c,$15
group_4d61:     .db $c0,$43,  $2f,  $1c,  $00,$08,$10,$80,  $2c,$09
group_4d6b:     .db $b0,$46,  $0c,  $1c,  $00,$08,$10,$80,  $2c,$1d
group_4d75:     .db $70,$47,  $01,  $1c,  $00,$08,$10,$80,  $2c,$1f
group_4d7f:     .db $80,$47,  $10,  $1c,  $00,$08,$10,$80,  $2e,$01
group_4d89:     .db $80,$48,  $09,  $1c,  $00,$08,$10,$80,  $2c,$21
group_4d93:     .db $30,$4a,  $1a,  $1c,  $00,$08,$10,$c0,  $2e,$03
group_4d9d:     .db $b0,$4a,  $08,  $24,  $00,$08,$10,$18,  $2e,$1b

        ; idx $1d : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4da7:     .db $40,$40,  $13,  $1c,  $00,$08,$10,$c0,  $2e,$05
group_4db1:     .db $70,$41,  $98,  $1c,  $00,$08,$10,$c0,  $2c,$3b
group_4dbb:     .db $f0,$4a,  $49,  $1c,  $00,$08,$10,$80,  $2e,$07

        ; idx $1e : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4dc5:     .db $00,$40,  $36,  $1c,  $00,$08,$10,$80,  $2c,$03
group_4dcf:     .db $60,$43,  $11,  $1c,  $00,$08,$10,$80,  $2e,$1d
group_4dd9:     .db $70,$44,  $0c,  $1c,  $00,$08,$80,$10,  $2e,$09
group_4de3:     .db $30,$45,  $96,  $1c,  $00,$08,$10,$c0,  $2e,$0b

        ; idx $1f : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4ded:     .db $00,$60,  $fb,  $1c,  $00,$08,$10,$80,  $22,$01

        ; idx $31 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4df7:     .db $00,$70,  $32,  $1c,  $00,$08,$10,$80,  $22,$03

        ; idx $32 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4e01:     .db $00,$70,  $b3,  $0c,  $00,$00,$00,$80,  $22,$07
group_4e0b:     .db $30,$7b,  $25,  $1c,  $00,$08,$10,$80,  $22,$09
group_4e15:     .db $80,$7d,  $09,  $1d,  $00,$08,$10,$c0,  $22,$0b

        ; idx $33 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4e1f:     .db $00,$70,  $a1,  $1c,  $00,$08,$10,$80,  $22,$05

        ; idx $34 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4e29:     .db $00,$70,  $b3,  $8c,  $00,$00,$00,$80,  $22,$07
group_4e33:     .db $30,$7b,  $25,  $9c,  $00,$08,$10,$80,  $22,$09
group_4e3d:     .db $80,$7d,  $03,  $9d,  $00,$08,$10,$c0,  $22,$0b

        ; idx $35 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4e47:     .db $00,$0e,  $10,  $0c,  $80,$00,$80,$80,  $16,$01

        ; idx $36 : $32 $33   $34   $35   $36 $37 $38 $39   BNK IDX

group_4e51:     .db $10,$70,  $7d,  $1c,  $00,$08,$10,$80,  $22,$0d

...

group_4faf:     .ds $42af - *
« Last Edit: November 04, 2016, 04:11:44 PM by elmer »

esteban

  • Hero Member
  • *****
  • Posts: 24063
Re: Cyber Knight translation
« Reply #215 on: November 04, 2016, 10:31:27 PM »
Elmer: there is a typo in line 3d2d: it should read "B$NK", not "BNK"

:)

I agree that megatron-UK's passion for Cyber Knight is going to awaken an appreciation for something that 99.6% of us were either completely ignorant of, or had barely any genuine experiences with.

:)

  |    | 

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #216 on: November 04, 2016, 10:57:42 PM »
Many thanks, I do appreciate it.

In respect to the font, one thing I have been thinking about is if I can truly get every bit of Japanese text replaced then it would mean I would I would have over 100 free 8x8 tiles. It should be possible to get several variations on the ASCII font in those remaining tiles; italic, bold, etc. That would be one way of doing it and not have to mess with the font loader - it could all remain the same and simply load  italic ascii tiles, rather than the katakana/hiragana tiles.

Back to the dialogue, I do love this game. It's a fab SRPG, the graphics could be better - especially the overworld, but the music and sound fx are really great and there are some nice mecha designs and, judging from the amount of dialogue (I still haven't actually played the game beyond the first world) it seems to be fairly big and varied in terms of maps, characters and enemies.

Having the SNES english text has made translating our PCE version significantly easier (google translate is great, but it really doesn't beat someone fluent in Japanese) although there are a few small differences between the two that meant I had to write the mapper script to do fuzzy matching between the two. The big thing is, like you say, the script is understandable, but, it does leave a little to be desired. With a bit of tweaking (and judicious use of those extra control codes!) it can be made much more interactive. Hopefully people will enjoy it when it is eventually done!

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #217 on: November 08, 2016, 10:29:56 AM »
Just about finished writing the updated insert tool. It can currently expand the rom by the correct number of extra banks and also does a double conversion of the english text - once to hex bytecodes and then back again, just to be doubly sure that my conversion table is working properly. Tracking down dodgy bytes once inserted would be a pain!

Hopefully actually start to insert the text again before the end of the week and then test whether the expanded bank scheme works. I'll have to mess around with the bank loader table by hand first, but should be able to automate it once done.

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #218 on: November 09, 2016, 03:49:34 AM »
Quickie - There are 27 text assets in the game, meaning 27 extra 8k banks. But that's an odd number so I've decided to up it to 32. That rounds the size up nicely to 768KB (64x8KB banks in the original ROM, plus 32 extra banks to hold the expanded English script).

There's only one asset that is larger than a single bank - it's already 10KB in Japanese (and thus in two consecutive banks already in the original game) and will probably expand to 14KB or more once fully converted. Everything else is well within the 8KB bank limit.

It's pretty wasteful though - the script is roughly 55-60KB in size so far, that's with about 20% English and 80% Japanese. That means we're wasting about 200KB of that extra ROM space... oh well, good job it's not a problem with SD card space!
« Last Edit: November 09, 2016, 03:51:47 AM by megatron-uk »

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #219 on: November 09, 2016, 04:26:40 PM »
It's pretty wasteful though - the script is roughly 55-60KB in size so far, that's with about 20% English and 80% Japanese. That means we're wasting about 200KB of that extra ROM space... oh well, good job it's not a problem with SD card space!

Space doesn't really matter in terms of ROM expansion these days, so you're doing the sensible and sane thing IMHO.  :clap:

Now ... programmer "bragging rights" ... well that's a different kettle-of-fish!  :wink:

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #220 on: November 10, 2016, 04:16:05 AM »
Well, I've got the text inserted into the expanded ROM banks, also altered the asset bank table and asset offset table and.... well... it still loads! Some of translated script displays, but it seems to be off by a few strings as the main menu and player creation screen is showing garbage for a few areas and a few sections are wrong ('Del' in place of the 'End' button for the name entry... that means just a couple of delimeters are out of place).

The original script is left as-is. It still occupies banks 0x0a to 0x15.

The intro cinematic plays nicely and most of that text is okay, which is another bank, so it, I must have that one pretty much spot on. I've got some work to do with the text box creation control codes - I must have counted the size wrong as I have a couple of characters spilling over what I thought was a 22 character box with 20 characters in it!  :roll:

So, it's looking promising; the relocation to the additional banks does seem to have worked, I now just need to track down the 'usual' problems of missing control bytes, delimiters, etc.  :)

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #221 on: November 12, 2016, 08:32:42 PM »
Starting to make real progress now. The intro cinema is back working again, the expanded scrolling story after the cinema works perfectly (unlike my original translation which bumped up against rom size limits!) and the 'power is out' dialogue that happens immediately after is 100%.

Shipboard menu entries are next - the move options are done, now working on the Kanji text. I did this by hand last time around, so unlike most dialogue in the game, they're not all seperated by 0x00 bytes (lots of Kanji which uses that byte as well!) so I'm having to do them by eyeball. But there's only a couple of dozen individual entries to do, so it's not like it's going to take forever.

Also added a automatic way to get the Git revision number into the game, so I now embed the revision into the main menu so that I know what version it is that I (or anyone else) is playing.

Latest script and patched assets up on Github. If you're savvy with Python on Linux, just clone the repo and drop a 'Cyber Knight (J).pce' rom in the folder then run 'expandRom.py'. You shouldn't need to do anything else.

If you want to play around with it, then the following sequence is how to get all the assets from the game:

extractAssets.py - Extract all text asset banks to ./assets/raw... e.g. ./assets/raw/0x0a.dat
splitAssets.py - Split asset banks by asset chunks e.g. ./assets/split/0x0a.0x01.dat
mapAssets.py - Programatically match SNES translations to the split assets, outputs to ./assets/converted
expandRom.py - Inserts assets from ./assets/converted back in to an expanded (768KB) ROM file.

At the moment I'm tweaking asset files and then re-running expandRom.py each time, then firing up Mednafen and either loading BRAM saves, or save states to test each time.

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #222 on: November 14, 2016, 03:44:14 AM »
Starting to make real progress now. The intro cinema is back working again, the expanded scrolling story after the cinema works perfectly (unlike my original translation which bumped up against rom size limits!) and the 'power is out' dialogue that happens immediately after is 100%.

Great progress!  :D


Quote
Latest script and patched assets up on Github. If you're savvy with Python on Linux, just clone the repo and drop a 'Cyber Knight (J).pce' rom in the folder then run 'expandRom.py'. You shouldn't need to do anything else.

I just gave it a try ... it's looking good!  8)

It was nice to see the intro in English.


Quote
At the moment I'm tweaking asset files and then re-running expandRom.py each time, then firing up Mednafen and either loading BRAM saves, or save states to test each time.

That's what we're doing with the Xanadu games, too.

megatron-uk

  • Full Member
  • ***
  • Posts: 219
Re: Cyber Knight translation
« Reply #223 on: November 19, 2016, 12:56:52 AM »
Okay, here is your chance to contribute, folks.

We have 5 playable mecha in the game, they are:

レックス,Rex
ウイナー,Winner
シェリフ,Sheriff
タイタン,Titan
サウルス,Saurus

Catchy, eh?  ](*,)

We have a restriction in that their displayed name can be no more than 4 characters in length - this is decided by the width of the status window in combat, the fact that all 5 are displayed horizontally, in a list in the hangar bay to select from, etc. Not a lot I can do about it without some serious hacking, or a variable width font (not at the moment, thank you!).

So, let's have your ideas, ladies and gentlemen. My first thought was to use something like Gundam model numbers; RX78 and similar, as there's not a lot of 'cool' names to fit in just four characters!

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Cyber Knight translation
« Reply #224 on: November 19, 2016, 03:15:04 AM »
We have a restriction in that their displayed name can be no more than 4 characters in length - this is decided by the width of the status window in combat, the fact that all 5 are displayed horizontally, in a list in the hangar bay to select from, etc. Not a lot I can do about it without some serious hacking, or a variable width font (not at the moment, thank you!).

You're never going to get a VWF in that game with any kind of reasonable-to-do hack ... the whole thing is too tile-based.

But ... when you get rid of the need for all of those Japanese characters, you can predraw certain strings in a VWF.

For instance, in this case you've got 5 mecha using 4 tiles each ... so if you have 20 tiles free in memory, then you just give them names like "abcd", "efgh", "ijkl", etc, and then draw each name into their unique set of 4 tiles.

It looks like you'll have 128 tiles free to do this trick in the main font in VRAM, and even more in the alternate font.

Perhaps that will be an option for you at some point?