Author Topic: Xanadu II Translation Development Blog  (Read 39461 times)

SamIAm

  • Hero Member
  • *****
  • Posts: 1835
Re: Xanadu II Translation Development Blog
« Reply #90 on: October 19, 2015, 02:34:39 PM »
*awesome stuff*

You should make this into your avatar:



:D

NightWolve

  • Hero Member
  • *****
  • Posts: 5277
Re: Xanadu II Translation Development Blog
« Reply #91 on: October 19, 2015, 02:35:25 PM »
Hah!

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Xanadu II Translation Development Blog
« Reply #92 on: October 20, 2015, 03:16:34 PM »
Oh wow, looks like the game was lucky enough to finally come into the hands of someone knowledgeable enough to do this!

Thanks, but I like to think that anyone could do this with enough time and a sufficiently bloody-minded refusal to let the problem beat them!  :wink:


Quote
I hope it doesn't come down to using the idea that's now available with the Turbo Everdrive's writable RAM and limiting the fan translation to that...

I think that there are definitely going to be translations out there that are only going to be possible or practical with extra memory, but I think that we got lucky on these 2 and that I can free up the necessary space.

I'd certainly like to keep them running within the original hardware.


You should make this into your avatar:

Haha ... thanks, but usually I feel more like the one of the Infinite Number of Monkeys!

https://en.wikipedia.org/wiki/Infinite_monkey_theorem


Sometimes a good plan just doesn't work out as neatly as a programmer believes that it's going to when he/she has that oh-so-brilliant idea!  :roll:

Case-in-point ...


If I choose option 2, then I've got to decide whether to use bank 0 or bank 7, and bank 7 is the obvious choice.

If I do that, then I can write new interrupt vectors and new BIOS function vectors, and just map the CD BIOS bank into $e000-$ffff when it actually needs to be there to handle an interrupt or a function call.

Well, this sounded like a good idea, and the thought of replacing every old ROM CD BIOS vector ...

e000: JMP $e0f3     ; CD_BOOT
e003: JMP $e8e3     ; CD_RESET
e006: JMP $eb8f     ; CD_BASE
....
e0f0: JMP $fddb     ; MA_CBASIS


with new vectors in the RAM bank ...

e000: JSR my_hack   ; CD_BOOT
e003: JSR my_hack   ; CD_RESET
e006: JSR my_hack   ; CD_BASE
....
e0f0: JSR my_hack   ; MA_CBASIS


... seemed really quite elegant.

The new "my_hack" routine would page in the original ROM bank, execute the original CD function, and then page the RAM bank back in.

The code isn't even very long ...

my_hack:   sta   .lda1+1
           pla
           sec
           sbc   #2
           sta   .callrom+1
           pla
           sbc   #0
           sta   .callrom+2
           tma   #$80
           pha
           lda   #$00
           tam   #$80
.lda1:     lda   #$00
.callrom:  jsr   $0000
           sta   .lda2+1
           pla
           tam   #$80
.lda2:     lda   #$00
           rts


Unfortunately, once I took a good look at it, I realized that it's not re-entrant, and that if an interrupt occurs part way through that routine that also calls a CD function, then you're going to get a random bug/crash.   :shock:

Now this can worked around by making sure that the interrupt handler also switches banks ...

my_irq1:   pha
           tma   #$80
           pha
           lda   #$00
           tam   #$80
           lda   #>my_rti
           pha
           lda   #<my_rti
           pha
           php
           jmp   ($FFF8)

my_rti:    pla
           tam   #$80
           pla
           rti


But now I've added a huge delay into the interrupt processing, which is exactly what I was trying to avoid by choosing "option 2"!  #-o

So it's back to "option 1", which turns out to both require less code and to also delay interrupts less.

// script_pc is stored in $37,$38.

read_pc:   lda   #RAMBANK
           php
           sei
           tam   #$80
           lda   ($37)
           sta   .lda1+1
           lda   #$00
           tam   #$80
           plp
           inc   $37
           bne   .lda1
           inc   $38
.lda1:     lda   #$nn
           rts


Whoops!  :oops:
« Last Edit: October 21, 2015, 05:16:18 AM by elmer »

dshadoff

  • Full Member
  • ***
  • Posts: 175
Re: Xanadu II Translation Development Blog
« Reply #93 on: October 20, 2015, 03:22:22 PM »

Falcom already compresses the original SJIS text by encoding the 192 most-common katankana/kanji into a single byte, and this really works out well for them.

Xanadu 1 has 235,523 SJIS glyphs stored using 271,679 bytes.
Xanadu 2 has  96,139 SJIS glyphs stored using 116,346 bytes.


That's an approx 1.2 multiplier, much better than the 2.0 multiplier of pure SJIS.

Apart from showing that Xanadu 2 really is a much shorter story than Xanadu 1, it shows that we've got a problem.

In order to get a good English translation, SamIAm estimates that we're going to need approx 1.5 to 2.0 times the amount of English characters as Kanji glyphs.

This gives me 2 problems ... how to fit all this English text into a level's compressed 176KB META-BLOCK that gets loaded into memory ... and then how to actually free up enough memory so that a large English script-chunk can be decompressed and accessed in the game.


That's really interesting - that they can already use 192 bytes of the character set to expand into 2-byte SJIS (I guess using a lookup table).  I take it that this is separate from the compression scheme ?

The reason I ask is that I wonder what the most common words/phrases in English would be, and whether they could be single-byte-substituted separately from the window-based compression (for example, names, "the ", "and " - including spaces - etc).  The longer the word, the less likely that it would show up in the past window.

But even if that kind of substitution were easy to capitalize on, it could still be a combinatoric problem of processing the script and deciding which substitutions would yield the best net compression.

...Just a thought.

-Dave

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Xanadu II Translation Development Blog
« Reply #94 on: October 21, 2015, 05:14:05 AM »
That's really interesting - that they can already use 192 bytes of the character set to expand into 2-byte SJIS (I guess using a lookup table).  I take it that this is separate from the compression scheme ?

Yep, they use the same lookup table for both Xanadu 1 and Xanadu 2. That's reversed back into a SJIS glyph only when each glyph is printed to the screen by the script interpreter.

So "yes", it's totally separate from the regular FALCOM1/FALCOM2 compression.


Quote
The reason I ask is that I wonder what the most common words/phrases in English would be, and whether they could be single-byte-substituted separately from the window-based compression (for example, names, "the ", "and " - including spaces - etc).  The longer the word, the less likely that it would show up in the past window.

If you're never going to "localize" the translation into any of the other EFIGS languages, then using a dictionary substitution like that is a perfect use for character codes $80-$FF.

In these "Internet" days it's easy to find lists of the most-common English words (like http://www.wordfrequency.info) that can give you a good starting point for any dictionary, without having to do the work of producing your own "optimal" list.

Now, writing the code to create that "optimal" dictionary may be the kind of challenge that some programmers would enjoy ... but I don't think that extra work would be overly useful in a case like this.

The big question when using such a static dictionary is "Do the benefits outweigh the costs?".

There isn't a huge CPU cost, but you are going to have to store that dictionary in memory somewhere, so there's definitely a cost there.

There's also a question of the effect that it's going to have on the LZSS compression.

With 2-byte (or less) LZSS codes already acting as a dynamic dictionary, you're reducing the "gain" that you're going to get from using a static dictionary as well.

In the case of the Xanadu games, Falcom already take advantage of the "dictionary" idea by only storing some strings (such as speaker's names) once, and then using a script "call" to print them out.

So ... you've got a good idea  :)

... but I'm going to hold it in "reserve", and only use it if I run out of memory later.  :wink:

dshadoff

  • Full Member
  • ***
  • Posts: 175
Re: Xanadu II Translation Development Blog
« Reply #95 on: October 21, 2015, 09:27:18 AM »
Quote
The reason I ask is that I wonder what the most common words/phrases in English would be, and whether they could be single-byte-substituted separately from the window-based compression (for example, names, "the ", "and " - including spaces - etc).  The longer the word, the less likely that it would show up in the past window.

If you're never going to "localize" the translation into any of the other EFIGS languages, then using a dictionary substitution like that is a perfect use for character codes $80-$FF.

In these "Internet" days it's easy to find lists of the most-common English words (like http://www.wordfrequency.info) that can give you a good starting point for any dictionary, without having to do the work of producing your own "optimal" list.

Now, writing the code to create that "optimal" dictionary may be the kind of challenge that some programmers would enjoy ... but I don't think that extra work would be overly useful in a case like this.

The big question when using such a static dictionary is "Do the benefits outweigh the costs?".


That's exactly what I meant when I said that it would be a combinatoric exercise - it's not just whole words, but rather partial words which could benefit, and it would be highly dependent on the actual script as well.  For example, maybe simple letter-pairs such as "sh", "st", "th", "tr", and "ea" yield good benefit without going as far as creating additional code for full words, and maybe they don't interfere with compression either.

One could find out the "net benefit" for character groups by finding groups of "n" characters and number of occurrences, running for "n" groups from 2 to the maximum size of a substitute.   This would be a very long list which would need to be sorted to determine maximum benefit.  Then, re-run again - but this time under the presumption that substitute #1 has been implemented...  All the while, keeping in mind that if you take advantage of the #1 benefit, you may reduce the effectiveness of #2 and #3... which turns it into a combinatoric problem, identifying all of the possible permutations and their maximal benefit.

But hopefully, it isn't such a brute force problem.

Quote
There's also a question of the effect that it's going to have on the LZSS compression.

With 2-byte (or less) LZSS codes already acting as a dynamic dictionary, you're reducing the "gain" that you're going to get from using a static dictionary as well.


Very true.

Quote
So ... you've got a good idea  :)

... but I'm going to hold it in "reserve", and only use it if I run out of memory later.  :wink:


Fair enough !  More complexity is more work, and more opportunity for bugs/issues.
Just thought I'd mention an idea that came to me while reading your reply.

-Dave

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Xanadu II Translation Development Blog
« Reply #96 on: October 23, 2015, 10:33:57 AM »
I think that "investigation" is over for a while, and it's time to get back to actually getting the text inserted into the game.

I've finally added all the programmer-garbage at the top of each extracted-script, so that I've got the information that I should need for the re-insertion, and now it's time to write that code.

When that's done, I'll test it by making sure that the existing scripts insert identically to the originals, and then it'll be time to try some test English in there.

For anyone that's interested, here's an example of what SamIAm will be working with over the next few weeks/months.

It is the complete script for the very first chunk in the Xanadu 2 game, when Arios is on the ship.

If you're interested, you can actually run the game and see when these pieces of text pop up; and if you've done any simple programming, then you should be able to follow the basic idea of what's going on with all the branches and calls, even if the exact details aren't clear.

  @chunkdefn( $a000, $bfff, $000fb800, 15 )

  @memregion( $a695, $ad97 )
  @memregion( $ae05, $bfff )

  @extscript( $9eb7, .script9EB7 )

  @scriptref( $a174, TYPE_JSR90D8, .scriptA6A3 )
  @scriptref( $a188, TYPE_JSR90D8, .scriptA8EF )
  @scriptref( $a18a, TYPE_JSR90D8, .scriptA95F )
  @scriptref( $a18c, TYPE_JSR90D8, .scriptA9E8 )
  @scriptref( $a18e, TYPE_JSR90D8, .scriptAAEF )
  @scriptref( $a262, TYPE_IMM37,   .scriptA695 )
  @scriptref( $a35b, TYPE_JSR9298, .scriptAB88 )
  @scriptref( $a37f, TYPE_JSR9298, .scriptAC22 )

.scriptA695:
  {帆船ローランディア号}
  _end()

.scriptA6A3:
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .scriptAE05 )
  _disable_8x12_font()
  _tst_2b03_x_bnz( $01, $02, .scriptA877 )
  _tst_2b03_x_bnz( $01, $10, .scriptA748 )
  _tst_2b03_x_bnz( $01, $20, .scriptA71B )
  _tst_2b03_x_beq( $20, $01, .scriptA8AB )
  _tst_2b03_x_beq( $20, $02, .scriptA8AB )
  _tst_2b03_x_beq( $20, $04, .scriptA8AB )
  _tst_2b03_x_beq( $20, $08, .scriptA8AB )
  {アリオスさま、準備が整ったようですな。そういえば、航海長が}
  _eol()
  {お話があるとのことです。}
  _wait_for_keypress_then_clear()
  {後部甲板に行ってみてはいかがですか?}
  _set_bits_2b03_x( $01, $20 )
  _wait_for_keypress_then_end()

.scriptA71B:
  {航海長がお話があるとのことです。}
  _eol()
  {後部甲板に行ってみてはいかがですか?}
  _wait_for_keypress_then_end()

.scriptA748:
  _tst_2b03_x_bnz( $01, $20, .scriptA762 )
  {アリオスさま。どうかされましたか?}
  _wait_for_keypress_then_clear()
  _jump( .scriptA775 )

.scriptA762:
  {アリオスさま。航海長はなんと?}
  _wait_for_keypress_then_clear()

.scriptA775:
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {うん‥‥}
  _eol()
  {航海長から新しい海域に入ったので、}
  _eol()
  {海図を描いてくれと頼まれたんだ。}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .scriptAE05 )
  _disable_8x12_font()
  {そうですか。}
  _eol()
  {‥‥確かアリオスさまは、}
  _eol()
  {絵画などは苦手のはずでは‥‥}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {はは、仕方ないさ。}
  _eol()
  {ところで、ダイモス‥‥その‥‥}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .scriptAE05 )
  _disable_8x12_font()
  {なんでしょう? アリオスさま。}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {私はもう、百騎長ではないのだから、}
  _eol()
  {いいかげん『さま』はよせ。}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .scriptAE05 )
  _disable_8x12_font()
  {はい。アリオスさま。}
  _eol()
  {‥‥あッ!!}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {やっぱりダメか‥‥}
  _set_bits_2b03_x( $01, $02 )
  _wait_for_keypress_then_end()

.scriptA877:
  {アリオスさまは、}
  _eol()
  {私めにとって大事な主君。}
  _wait_for_keypress_then_clear()
  {『アリオスさま』とお呼びしては}
  _eol()
  {いけませんか?}
  _wait_for_keypress_then_end()

.scriptA8AB:
  {アリオスさま。}
  _eol()
  {船倉の方に装備品がそろえてあります。}
  _wait_for_keypress_then_clear()
  {お急ぎにならずとも結構ですから、}
  _eol()
  {準備をなさってください。}
  _wait_for_keypress_then_end()

.scriptA8EF:
  _set_pen_then_call_then_eol( orange, .scriptAE0A )
  _tst_2b03_x_beq( $20, $01, .scriptA934 )
  _tst_2b03_x_beq( $20, $02, .scriptA934 )
  _tst_2b03_x_beq( $20, $04, .scriptA934 )
  _tst_2b03_x_beq( $20, $08, .scriptA934 )
  {しっかし、ここいらへんの海は}
  _eol()
  {穏やかだねぇ。}
  _wait_for_keypress_then_clear()
  {オレたちの故郷たぁ大違いさね。}
  _wait_for_keypress_then_end()

.scriptA934:
  {アリオスさん、結構広い船だからって、}
  _eol()
  {迷子になんかならないでくだせぇよ。}
  _wait_for_keypress_then_end()

.scriptA95F:
  _set_pen_then_call_then_eol( orange, .scriptAE0A )
  _tst_2b03_x_bnz( $01, $10, .scriptA9B8 )
  _tst_2b03_x_beq( $20, $01, .scriptA990 )
  _tst_2b03_x_beq( $20, $02, .scriptA990 )
  _tst_2b03_x_beq( $20, $04, .scriptA990 )
  _tst_2b03_x_beq( $20, $08, .scriptA990 )
  {船長、ご用は済んだんですかい?}
  _wait_for_keypress_then_end()

.scriptA990:
  {おや、船長。}
  _eol()
  {船倉は階段を下りて右、}
  _eol()
  {厨房のとなりですぜ。}
  _wait_for_keypress_then_end()

.scriptA9B8:
  {もうすぐ、見張り番を交代しますぜ。}
  _eol()
  {でも、マストに登るのは}
  _eol()
  {おっかねぇからなぁ‥‥}
  _wait_for_keypress_then_end()

.scriptA9E8:
  _set_pen_then_call_then_eol( orange, .scriptAE0A )
  _tst_2b03_x_bnz( $01, $10, .scriptAABD )
  _tst_2b03_x_bnz( $01, $04, .scriptAA8A )
  _tst_2b03_x_beq( $20, $01, .scriptAA55 )
  _tst_2b03_x_beq( $20, $02, .scriptAA55 )
  _tst_2b03_x_beq( $20, $04, .scriptAA55 )
  _tst_2b03_x_beq( $20, $08, .scriptAA55 )
  _conditional_jump( $c9, $b0, $10, $2aa5, .scriptAA66 )
  _conditional_jump( $c9, $b0, $20, $2aa6, .scriptAA66 )
  _conditional_jump( $c9, $b0, $30, $2aa7, .scriptAA66 )
  {いや~ 武器を持つと}
  _eol()
  {船長は見違えるね~}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {よ、よしてくれないか。}
  _set_bits_2b03_x( $01, $04 )
  _wait_for_keypress_then_end()

.scriptAA55:
  {いや~ 男はやっぱ海だよね~}
  _wait_for_keypress_then_end()

.scriptAA66:
  {船長、武器とかは}
  _eol()
  {ちゃんと装備しておいた方がいいですぜ。}
  _wait_for_keypress_then_end()

.scriptAA8A:
  {しかし、思い出すね~}
  _wait_for_keypress_then_clear()
  {3年前、船長を乗せて}
  _eol()
  {イクティア島まで運んだときのことを‥‥}
  _wait_for_keypress_then_end()

.scriptAABD:
  {船長、武器や防具は、}
  _eol()
  {装備してこそ意味があるんです。}
  _eol()
  {忘れねぇでくだせぇよ。}
  _wait_for_keypress_then_end()

.scriptAAEF:
  _set_pen_then_call_then_eol( orange, .scriptAE0A )
  _tst_2b03_x_bnz( $01, $10, .scriptAB65 )
  _tst_2b03_x_beq( $20, $01, .scriptAB30 )
  _tst_2b03_x_beq( $20, $02, .scriptAB30 )
  _tst_2b03_x_beq( $20, $04, .scriptAB30 )
  _tst_2b03_x_beq( $20, $08, .scriptAB30 )
  {もうすぐで、久しぶりの陸ですぜ。}
  _eol()
  {あと少し、ガマンしてくだせえ。}
  _wait_for_keypress_then_end()

.scriptAB30:
  {3年前、船を使ってもらった先生に}
  _eol()
  {頼まれたとはいえ、}
  _eol()
  {まさかこんな所までくるとはなぁ‥‥}
  _wait_for_keypress_then_end()

.scriptAB65:
  {ようやく、陸が見えるように}
  _eol()
  {なってきやした。}
  _eol()
  {長かったなぁ‥‥}
  _wait_for_keypress_then_end()

.scriptAB88:
  _modify_script_variable( $01, $10 )
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .scriptAE05 )
  _disable_8x12_font()
  {アリオスさま。いよいよですな。}
  _wait_for_keypress_then_clear()
  _modify_script_variable( $00, $11 )
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {うん。}
  _eol()
  {もうすぐリュコスの向かった新大陸か。}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .scriptAE05 )
  _disable_8x12_font()
  {そうです。}
  _eol()
  {上陸にそなえてください。}
  _wait_for_keypress_then_clear()
  {船倉の方に装備品がそろえてあります。}
  _eol()
  {お急ぎにならずとも結構ですから、}
  _eol()
  {準備をなさってください。}
  _wait_for_keypress_then_end()

.scriptAC22:
  _set_pen_then_call_then_eol( orange, .scriptAE0F )
  {大変です! 船長!!}
  _wait_for_keypress_then_clear()
  _call_asm_from_script( .codeAD98 )
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .scriptAE05 )
  _disable_8x12_font()
  {どうした、なにがあった?}
  _wait_for_keypress_then_clear()
  _set_pen_then_call_then_eol( orange, .scriptAE0F )
  {お捜しの船を見つけたんです!}
  _wait_for_keypress_then_clear()
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {なんだって!?}
  _wait_for_keypress_then_clear()
  _set_pen_then_call_then_eol( orange, .scriptAE0F )
  {前方の島の暗礁地帯に}
  _eol()
  {乗り上げているのを確認しました。}
  _eol()
  {間違いありません。}
  _wait_for_keypress_then_clear()
  _modify_script_variable( $00, $11 )
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {リュコスの船だ!}
  _eol()
  {やはり遭難していたんだ。}
  _eol()
  {すぐに向かおう。}
  _wait_for_keypress_then_clear()
  _modify_script_variable( $01, $10 )
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .scriptAE05 )
  _disable_8x12_font()
  {しかし困りましたな‥‥}
  _eol()
  {あのような岩ばかりでは}
  _eol()
  {近寄ることも難しい。}
  _wait_for_keypress_then_clear()
  _call_asm_from_script( .codeADBE )
  _set_pen_then_call_then_eol( orange, .scriptAE0A )
  {なに、島をぐるりと回りゃ}
  _eol()
  {船の入れるところもあるでしょう。}
  _wait_for_keypress_then_clear()
  {いざとなったら、ボートを使えばいい。}
  _wait_for_keypress_then_clear()
  _call_asm_from_script( .codeADDC )
  _enable_8x12_font()
  _set_pen_then_call_then_eol( orange, .script9EB7 )
  _disable_8x12_font()
  {よし、右舷回頭、面舵一杯!}
  _eol()
  {暗礁地帯をさけて、島に近づくぞ。}
  _eol()
  {急いでくれ!!}
  _wait_for_keypress_then_clear()
  _set_pen_then_call_then_eol( orange, .scriptAE17 )
  {アイアイサー!}
  _call_asm_from_script( .codeADFF )
  _wait_for_keypress_then_end()

.scriptAE05: ; 8x12 font
  {ダイモス}
  _end()

.scriptAE0A:
  {船員}
  _end()

.scriptAE0F:
  {見張り番}
  _end()

.scriptAE17:
  {船員たち}
  _end()

.endAE1E:


NightWolve

  • Hero Member
  • *****
  • Posts: 5277
Re: Xanadu II Translation Development Blog
« Reply #97 on: October 23, 2015, 11:14:28 AM »
Dang, that's a messy job, so they spread text around inbetween code... :/ Falcom does usually go with a text block model of null-terminated strings and indexing into the block, but I believe Zwei! was one other exception (plus here for Xanadu) where you had most of the script stored as in-lined strings inbetween code.

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Xanadu II Translation Development Blog
« Reply #98 on: October 23, 2015, 12:28:36 PM »
Dang, that's a messy job, so they spread text around inbetween code...

Hahaha ... that's the clean version!  :wink:

Back when I was still trying to reverse-engineer complete script-blocks back into editable-source, you'd also see assembly code and data interleaved in there, too!  ](*,)

It's a powerful script-language, and a very powerful technique for making an 8-bit machine's macro-assembler to act as a high(ish)-level language.

I think that the whole scheme fell out of favor in the early years of the 5th generation when the "C" compiler replaced the macro-assembler ... but these kind of languages are back-with-a-vengence these days with Lua, Unreal Script, and every-other-developer's-proprietary-bytecode-interpreted-language.

At least most developers build games now with the knowledge that they need to think about localization into other languages.
« Last Edit: October 23, 2015, 03:58:23 PM by elmer »

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Xanadu II Translation Development Blog
« Reply #99 on: October 24, 2015, 12:01:38 PM »
As I'm sitting here, writing the script-assembler (it's too simple to call a compiler), and wondering if it's too early for a beer ... I'm dragging in various bits of code from old projects to help.

Since Bonknuts talked about writing a scripting language in another thread, I thought that I'd point out this article (and concept) for any programmer that's not seen it.

http://cowboyprogramming.com/2007/01/04/practical-hash-ids/

The first time that I saw it totally integrated into a game's engine/toolchain was in NeverSoft's Tony Hawk Engine.

It's an amazingly powerful method for solving a lot of game asset-management issues on 32-bit machines, and for dynamically linking script bytecode to "C" code.

I've been using my own version of the idea since the early 2000's ... and when I finally get back to working on a PC-FX toolchain/library, you'll probably see it as one of the "core concepts".

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Xanadu II Translation Development Blog
« Reply #100 on: October 26, 2015, 04:48:35 AM »
From the "System Card Dreams" thread ...

I could make the Xanadu translations require extra memory in order to create a market ... and it would definitely make my job easier. But that doesn't seem like a nice thing to do, even if it might slightly lower the chance of a PCEWorks boxed-set.

For anyone that's reading through both these threads, I though that I'd explain how this would make things easier ...

If I had another 256KB RAM on a "Translation Card", then I'd just load Xanadu's META_BLOCKs directly into the extra RAM.

That would avoid the need to change the game's compressor to a new one, and SamIAm's translations could be as-big-as-they-need with little effort on my part.

The extra RAM would also make it easy to solve the space-in-the-game problem for the decompressed English scripts, and also give me plenty of room for English fonts and a new VFW font routine.

These are things that would save me a fair amount of time-and-effort in getting the translation done.

The downside would be that then the META_BLOCKs wouldn't fit onto the CD anymore.

That can be solved by increasing the size of the ISO ... but it does show that there's no quick-fix that doesn't have consequences, and we're just moving programmer-effort from one problem into a different one.

Now ... if I wasn't able save memory by switching the compressor, then having this extra memory would be the only way that you'd get a decent translation.

Food-for-thought.  :-k

TheOldMan

  • Hero Member
  • *****
  • Posts: 958
Re: Xanadu II Translation Development Blog
« Reply #101 on: October 26, 2015, 06:14:07 AM »
Quote
there's no quick-fix that doesn't have consequences,

There never is <lol>. It's always a trade-off :)

A very silly question: Would it be possible to load the meta-blocks 'on the fly' from the cd? Or are they dependant on each other? (ie, block A calls block B such that both have to be in memory at once)

Bonknuts

  • Hero Member
  • *****
  • Posts: 3292
Re: Xanadu II Translation Development Blog
« Reply #102 on: October 26, 2015, 06:43:32 AM »
There's lot of free space in the ISO track - you don't need to expand it. It might look full, but there are lots of segments of left over 16bit PCM data in there. If you open the ISO track into a view than can interpret all data as PCE sprite format, you'll see that 16bit wave files have a very unmistakably unique signature to them. I usually run TMOD2 under dosbox (runs in XP too, but not on my win7 setup), with Dshadoffs PCE plugins for it.

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Xanadu II Translation Development Blog
« Reply #103 on: October 26, 2015, 07:34:34 AM »
There never is <lol>. It's always a trade-off :)

Haha .. "yep", such is the life of a programmer ... or an electrical engineer, or most "design" jobs for that matter.   :wink:


Quote
A very silly question: Would it be possible to load the meta-blocks 'on the fly' from the cd? Or are they dependant on each other? (ie, block A calls block B such that both have to be in memory at once)

AFAIK Xanadu 1 just loads a single large META_BLOCK (176KB max size) for each game level.

That's a mix of graphics and code and script.

For instance, the 1st level's META_BLOCK is 160KB large and contains 71 individual DATA_CHUNKs, only 13 of which actually contain Falcom's script-language data.

In order to "split" that into 2 META_BLOCKs and dynamically swith between them, I'd have to totally understand exactly what's going on inside each of the 71 DATA_CHUNKs, and to then copy the ones that are needed for each of the 2 new META_BLOCKs, and also fix up the code/script in each to use the new DATA_CHUNK indexes.

Then I'd also need to understand the game well enough to hack in this dynamic-loading system, and to trigger it in places that won't break anything.

I suspect that it would just be easier to rewrite the game from scratch!

Now Xanadu 2 already implements a dynamic loading system ... that's it's big improvement, and it's why it can afford to use much prettier graphics.

So it's somewhat more possible to split it's META_BLOCKs into 2, but it would still be a major nightmare that would IMHO mean completely reverse-engineering the entire game.

So "possible"? Probably so with enough time and will, but not even slightly "practical" in any sane definition of the word.

Nope ... IMHO in order to get this actually done and not have it die-on-the-vine like the previous attempt, we're going to have to keep the basic structure of the game unaltered, and just change the details (such as the language of the text).

It's going to be the same when it comes to the font code.

While it would be "nice" to change things to use a full VWF ... the structure of the code is going to make that a little awkward.

The first step will be to use the 12x12 English SJIS glyphs in the ROM font, just like EsperKnight did.

It'll be ugly ... but it's just going to be a stop-gap measure to make sure that things don't break.

Then it'll be time to see what's the best way to make it all look nice, and to give SamIAm plenty of room on the screen for his translated text.

But that's really a problem that will get more serious attention when the English scripts are inserting correctly.
« Last Edit: October 26, 2015, 07:59:00 AM by elmer »

elmer

  • Hero Member
  • *****
  • Posts: 2153
Re: Xanadu II Translation Development Blog
« Reply #104 on: October 26, 2015, 07:54:18 AM »
There's lot of free space in the ISO track - you don't need to expand it. ... I usually run TMOD2 under dosbox (runs in XP too, but not on my win7 setup), with Dshadoffs PCE plugins for it.

Thanks for the suggestion!

I've never heard of those tools, and will have to check them out.  :D

It looks like the CD is pretty full on Xanadu 2, so that's great to hear.

They're definitely using fixed intervals for the data in the ISO track, and they didn't clean out all the old stuff in there ... so it'll be good to have some help in identifying what data is just left-over junk.

Xanadu 1 looks to have plenty of space left to just expand the ISO ... but then they could have hard-coded the CD audio locations, which would be annoying.

Either way ... I'm really hoping to avoid having to change any of the data locations at this point.