(note: I'm not finished writing this. All contact should be sent to artaxerxes2 at iname.com)
If, like me, you were disappointed not to be able to play Serpent Isle in your own mother tongue, especially if the first part, Black Gate, was translated, and if you are not afraid to spend hours at it, you might want to translate Serpent Isle yourself. It took a team of 3-4 people over a year to do a usable translation, doing it during their free time, and about the same for the proofreading. This document will address the biggest questions you might face: where to start? what to do?
Important note: you cannot use Unicode. If your language requires Unicode, you cannot translate Serpent Isle the way I describe here. I do not know of any other way you could translate Serpent Isle. Sorry!
A fully translated Serpent Isle fits those criteria:
This document will help you out with descriptions, conversations and graphics. The rest will be briefly discussed at the end of this document.
You will need some tools for the translation. The Exult Team made available a package which contains some very important tools that you must acquire to translate Serpent Isle, otherwise you'll have to write your own! This package is available on their download page and is called "Exult Tools". You will also need some perl scripts you can download on **** TODO: PUT LINK HERE ****.
This is what you see when you single click on an item, NPC or, weirdly enough, when you are cold or hungry and a few other situations. All of that is found in the file text.flx
, from your static/
directory. A flex file shouldn't be edited directly. Since it holds text, use the tool textpack
, from the Exult tools you downloaded earlier. Convert the file into a text file using the following command:
textpack -x text.flx text.txt
The first few lines of the resulting text.txt
are as follow:
# Written by Exult Textpack tool 0:water 1:sidewalk 2: 3:icy water 4:floor 5:cavefloor 6:icy water 7:spring 8:water
You are now ready to edit the file text.txt
using a regular text editor. Do not alter the numbers in front of each line! Only change the text. This file is roughly split in three categories, grouped by line numbers:
Once you are finished translating this file (do not use Unicode, it is not supported and won't work!), you need to make it again a flex file. Use the following command:
textpack -c text.flx text.txt
It's time to try out your file! Edit your exult.cfg file and add a <patch> section under the <serpentisle> section if you did not have one already. My configuration file looks like that:
<config> <disk> <game> <serpentisle> <path> /home/aurelien/jeux/u7p2 </path> <gamedat_path> /home/aurelien/.exult/serpentisle/gamedat </gamedat_path> <savegame_path> /home/aurelien/.exult/serpentisle </savegame_path> <keys> (default) </keys> <patch> /home/aurelien/jeux/u7p2/patch </patch> </serpentisle> ... rest of config file here ... </config>Under Windows, it might be:
<config> <disk> <game> <serpentisle> <path> C:\games\ultima\serpentisle\ </path> <gamedat_path> C:\games\ultima\serpentisle\gamedat\ </gamedat_path> <savegame_path> C:\games\ultima\serpentisle\savegame\ </savegame_path> <keys> (default) </keys> <patch> C:\games\ultima\serpentisle\patch\ </patch> </serpentisle> ... rest of config file here ... </config>
Copy your brand new text.flx
to your patch/
directory as set in your configuration file. Under Linux
cp text.flx /home/aurelien/jeux/u7p2/patchUnder Windows:
copy text.flx C:\games\ultima\serpentisle\patch
Now start Exult, and start playing a bit of Serpent Isle. Click on the gangplank (line #150 in the text.flx file) once and see the name in your language appear! If it doesn't, make sure you have setup a <patch> directory in your exult.cfg file, make sure Exult uses the right exult.cfg file and make sure you read Patch : /home/aurelien/jeux/u7p2/patch
in either stdout.txt
or on your standard output. Also, make sure you copied the translated text.flx
into this directory! If it is still not working, contact me via email (address at the bottom of this document).
It might happen that you used non-ASCII characters in your text.flx
file and while playing, you quickly realised they didn't show in the descriptions. For instance, you translated "light" into "lumière", but when you click on the light in the floor of the cavern (where the bed roll is), it shows "lumire" instead. The reason is simple: each character you typed in the text.txt
file has an character-code. Character-code in the ASCII table have an associated bitmap in the file fonts.vga
but the non-ASCII character codes don't. To show the non-ASCII character codes, you will have to create the bitmaps yourself, or use my patched version of fonts.vga
which contains the (almost complete) iso8859-1 table bitmaps. If you use another character table (like iso8859-2 or others), or if you don't want to use my patched version of fonts.vga
, you will have to alter it yourself.
The simplest and fastest way I have found to alter fonts.vga
is to use yet another tools provided by the Exult Team, expack
. We will concentrate more on the default yellow text, but the same applies to all the fonts used in Serpent Isle (11 fonts in total!). Type the following command:
expack -x fonts.vga
This will create 12 files, named 00.u7o
, 01.u7o
, [...], 11.u7o
. Rename 00.u7o
to 00.shp
and edit it using the Gimp or Photoshop. You will need to install the plugins to edit a .shp file first. The plugins can be obtained from Exult's download page. I do not recommend putting bitmaps in the lower (<32) frames otherwise you will have troubles later on. Simply add layers to the image, each layer showing one bitmap. The layer number must represent the character-code you wish to use. For instance, the letter "é" is character-code #233 (0xE9) in iso8859-1. So it must the 233rd layer in your 00.shp
file. You should never have more than 256 characters in your character code. Exult does not support Unicode.
Once you are finished, you need to repack the file into a usable fonts.vga
. Rename the file 00.shp
to 00.u7o
first, then use the following command:
expack -c fonts.vga ??.u7o
Copy this new fonts.vga
to your patch/
directory and start Exult. Your new bitmaps should show now! (note: you could use this technique to use a different font if the default Gothic yellow gets on your nerves.)
This is the core of your translation effort. All conversations (when you double-click on most NPCs for instance) are found in the file usecode
from your static/
directory. The tools you downloaded earlier will help you to translate this file. At this point you have an alternative. Either you translate the content of the usecode
file using:
In either case there is some preparation to do. Put the usecode
file into a directory, say translation/
, as well as the script le_camomille.pl
(don't ask about the name) and the Exult Tools wud
, wuc
and rip
. From this translation/
directory, type the following command:
perl le_camomille.pl -prepare
After a few minutes, you'll see a large amount of new files and a few new directories. That's OK. The script splitted the usecode
file into a whole lot of individual compiled usecode functions (using rip
), decompiled each function (using wud
) and separated the data
section from the code
section in each of those decompiled usecode functions. For information, the new directories are:
code/
: contains the code
part of each decompiled usecode function. Leave it untouched for now.data/
: contains the data
part of each decompiled usecode function. The original text is there, but don't touch it.todo/
: contains the data
part of usecode functions not translated yet. That's the one you want to translate.french_data/
: contains the data
part of usecode functions already translated.
In either method, you must be very careful about certain pitfalls we encountered in our translation work. Here are some random notes you should get acquainted with.
This method works (we used it for the whole translation) but requires some rigor in your procedures. Also, unless you create a CVS repository, this method shouldn't be used if the translating team is more than 1 person. Pick a file from the todo/
directory, translate it and when you are done, move it to the french_data/
directory. Keep doing this until there is no more files in the todo/
directory.
An extract of what you would look at would be for instance:
.funcnumber 0401H .data L0000: db '@Dupre...@' L000A: db 00 L000B: db '@Yes, ' L0011: db 00 L0012: db '?@' L0014: db 00 L0015: db '@Bring to me a woman!@' L002B: db 00 L002C: db '@I will slay you all!@' L0042: db 00 L0043: db '@Fulfill thy desires!@' L0059: db 00 L005A: db '@I must have ale!@' L006C: db 00 L006D: db 'leave' L0072: db 00 L0073: db 'join' L0077: db 00 L0078: db '"How good to see thee again, ' L0095: db 00 L0096: db '! Knowing that thou wouldst soon return, I have waited for t' db 'hee at this establishment."' L00ED: db 00 L00EE: db '@And he hath developed quite a bar tab!@' L0116: db 00 L0117: db '"One that I shall pay, worry thou not!"' L013E: db 00 L013F: db '"And I have good news for thee, ' L015F: db 00 L0160: db '."' L0162: db 00 L0163: db 'good news' L016C: db 00 L016D: db 'join' L0171: db 00 L0172: db 'leave' L0177: db 00In this case, this function is from the file
0401.uc.data
and thus is for Dupre (NPC # + 0x400 = usecode function). You must not change the Lxxxx: db
part and ignore the lines where the text is only 00
(do not delete them though!).
Notice the first seven lines of actual text (L0000, L000B, L0012, L0015, L002C, L0043 and L005A) are barked. Also, the lines you reply are L006D, L0073, L0163, L016D and L0172, the rest is said by the NPC. You could also infer L00EE is said by another NPC given what is being said. This line is not barked however, but the actual NPC's face is shown and this text is displayed, unfortunately no visual clues will inform you of that.
Also, notice L000B and L0012: in this case, you can infer the Avatar's name will be inserted between the two. Same thing between L013F and L0160.
L0096 is split on two lines since it is too big to display on one. This limitation is due to wud
and is only for display purposes. When you translate, you can make a line almost as long as you want. Consequently, you could end up with the following for this line:
L0096: db ' ! Comme je savais que tu allais revenir bientôt, j'ai décidé de t'attendre dans cet établissement."' L00ED: db 00
Very important in this case, L006D and L0172 are identical, same for L0073 and L016D. If you make them different, you won't be able to click on them during the game. Try it once so that you will know what the symptoms are when that mistake is done.
Finally, there is a connection between L013F and L0163. When Dupre said "And I have good news for thee", the answer 'good news' is added. Try to keep it consistent.
Frequently, you want to check out the result of the translation. You must recreate the usecode
file using the newly translated data first. For this, you can again use my perl script le_camomille.pl
:
perl le_camomille.pl -creationThis command will use the files found in the
french_data/
directory when recombining the data
part from the code
part, will recompile each function (using wuc
) and put all usecode functions into one usecode
file (using rip
).
Simply copy this newly created usecode
file to your patch/
directory and try it out! I recommend you to get started with simple and short functions first, until you get the hang of it. You also might want to first translate either Iolo, Shamino or Dupre, so that you can see immediate results. For instance, replace every instance of 'bye' from your answers (= what you reply, thus surrounded only with simple quotes) into whatever way you say "bye" in your language. Run the command above and try it out (don't forget to put the translated version in the french_data/
directory).
If you intend to use the command line method and to share the work with others, you will need to setup a way to have a common repository fron which you will pull files to translate and push translated files. This is already possible is using le_camomille.pl
along with a CVS server. Before every translating sessions, run:
perl le_camomille.pl -synchroniseThis will update your local tree. You can then proceed to translate files in the
todo/
directory, or adjust files in the french_data/
directory. When finished, you need to update the CVS tree. Do it by typing:
perl le_camomille.pl -commitHowever, you need to discuss with the other team members how the workload will be shared, otherwise you might unnecessarily overstep each other.
If you have access to a web server that supports PHP and MySQL, you might want to have a look at my package called tisane
. This package is a set of PHP pages that will help you translate Serpent Isle. This is the recommended method, since you will save yourself a lot of time. Once everything is installed, all you will have to do is to point your browser to some web page, select a function to translate, edit the file, press a button and bam! you've just finished a function! You can also search through the original or the translated text for some words, download one or all usecode functions, review changes through a ChangeLog, create a list of recommended words for certain common words.
For instance, you can hint the translator that the recommended word used to translate "MageLord" has been chosen to be "Seigneur Mage". Each time the original text will show the word "MageLord", it will look different and putting the mouse cursor on top will pop the word "Seigneur Mage" in a tooltip.
The page where you edit a usecode function will show the original text on the left and either nothing on the right (if nothing was done), or the currently translated text. Each Lxxxx line to translate or proofread will be in its own textbox and you don't even have to worry anymore about the "Lxxxx", the "db", the "00" and the rest since only the text to translate is alterable.
To help even more, a description can be given to each usecode function, as well as some flags to identify functions, like: isNPC, isProofread, needCorrection, etc.
Finally, the page to edit a usecode function will show at the bottom of the screen a list of quick links in case you need help to translate. You enter a word in the box, select the search type and press the button. Current search types are: Definition (English), Definition (French), Synonymes (French), Conjugaison (French). If you know of a site that can be used to help in your translation, you can also add it there. The only requirement is that it must be possible to access the result page right away, via a GET or a POST method, so if the site requires cookies, tough! If parameters are required, they can be set in advance and are filled on-the-fly when you choose the associated search type.
There is a bit of work to do, but you will have to do it only once. Roughly, the steps are:
Copy the web pages to a directory your web server can serve from. Point your browser to this directory and more specifically to the file install.php
. Follow the instructions. When you are finished, you should end up with a fully prepared database. On to the next step.
As is, you cannot use the usecode file. Fortunately, if you've followed the steps recommended in this documentation, you should have almost everything ready. You ran the command:
perl le_camomille.pl -prepare
This command has done most of the work for you. The data/
directory contains all the original text and the french_data/
contains the translated version. Using my perl script usecode_convert.pl
, you can massage the data so that it becomes database friendly. Run it like this:
cat data/*.uc.data | perl usecode_convert.pl > english.txt cat french_data/*.uc.data | perl usecode_convert.pl > french.txt
Coming soon