]> icculus.org git repositories - taylor/freespace2.git/blob - src/localization/localize.cpp
Polish language support (Janusz Dziemidowicz)
[taylor/freespace2.git] / src / localization / localize.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Localization/localize.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  *
16  * $Log$
17  * Revision 1.5  2003/06/03 04:00:40  taylor
18  * Polish language support (Janusz Dziemidowicz)
19  *
20  * Revision 1.4  2003/05/18 03:55:30  taylor
21  * automatic language selection support
22  *
23  * Revision 1.3  2002/06/09 04:41:22  relnev
24  * added copyright header
25  *
26  * Revision 1.2  2002/05/07 03:16:46  theoddone33
27  * The Great Newline Fix
28  *
29  * Revision 1.1.1.1  2002/05/03 03:28:09  root
30  * Initial import.
31  *
32  * 
33  * 91    6/16/00 3:16p Jefff
34  * sim of the year dvd version changes, a few german soty localization
35  * fixes
36  * 
37  * 90    11/02/99 8:20p Jefff
38  * more translation changes/additions
39  * 
40  * 89    11/02/99 3:24p Jefff
41  * added translation functions for a few key instances where english was
42  * showing up
43  * 
44  * 88    10/29/99 10:40p Jefff
45  * mo stirngs
46  * 
47  * 87    10/28/99 2:05a Jefff
48  * safety fix in localization stuff
49  * 
50  * 86    10/26/99 10:53a Jefff
51  * German builds now correctly default to German on first run
52  * 
53  * 85    10/25/99 11:22p Jefff
54  * mo' strings (launcher)
55  * 
56  * 84    10/25/99 5:46p Jefff
57  * Many localization fixes/changes for German builds
58  * 
59  * 83    10/14/99 3:25p Jefff
60  * soo...many....xstrs....
61  * 
62  * 82    10/14/99 2:52p Jefff
63  * localization fixes.  added support for hi-res specific xstr offsets
64  * 
65  * 81    10/13/99 3:58p Jefff
66  * added a bunch of missed XSTRs
67  * 
68  * 80    9/13/99 11:30a Dave
69  * Added checkboxes and functionality for disabling PXO banners as well as
70  * disabling d3d zbuffer biasing.
71  * 
72  * 79    9/08/99 9:59a Jefff
73  * 
74  * 78    9/07/99 4:01p Dave
75  * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
76  * does everything properly (setting up address when binding). Remove
77  * black rectangle background from UI_INPUTBOX.
78  * 
79  * 77    9/07/99 1:54p Jefff
80  * skip mission strings added
81  * 
82  * 76    9/03/99 10:55a Jefff
83  * xstr_size++
84  * 
85  * 75    9/03/99 1:31a Dave
86  * CD checking by act. Added support to play 2 cutscenes in a row
87  * seamlessly. Fixed super low level cfile bug related to files in the
88  * root directory of a CD. Added cheat code to set campaign mission # in
89  * main hall.
90  * 
91  * 74    8/27/99 12:04a Dave
92  * Campaign loop screen.
93  * 
94  * 73    8/26/99 12:48p Jefff
95  * 
96  * 72    8/22/99 5:53p Dave
97  * Scoring fixes. Added self destruct key. Put callsigns in the logfile
98  * instead of ship designations for multiplayer players.
99  * 
100  * 71    8/22/99 1:55p Dave
101  * Cleaned up host/team-captain leaving code.
102  * 
103  * 70    8/17/99 7:32p Jefff
104  * mo' strings
105  * 
106  * 69    8/16/99 5:15p Dave
107  * Upped string count.
108  * 
109  * 68    8/16/99 4:04p Dave
110  * Big honking checkin.
111  * 
112  * 67    8/11/99 2:09p Jefff
113  * ill give you three guesses.
114  * 
115  * 66    8/10/99 7:57p Jefff
116  * even more strings
117  * 
118  * 65    8/05/99 2:40p Jefff
119  * added string
120  * 
121  * 64    8/02/99 9:13p Dave
122  * Added popup tips.
123  * 
124  * 63    8/02/99 12:01p Jefff
125  * added a string
126  * 
127  * 62    7/29/99 10:47p Dave
128  * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
129  * 
130  * 61    7/29/99 9:44a Jefff
131  * added some strings for ingame objectives screen
132  * 
133  * 60    7/27/99 7:15p Jefff
134  * 3 new interface strings
135  * 
136  * 59    7/27/99 6:53p Dave
137  * Hi-res main hall support.
138  * 
139  * 58    7/24/99 1:54p Dave
140  * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
141  * missions.
142  * 
143  * 57    7/22/99 4:08p Jefff
144  * some new strings
145  * 
146  * 56    7/19/99 7:20p Dave
147  * Beam tooling. Specialized player-killed-self messages. Fixed d3d nebula
148  * pre-rendering.
149  * 
150  * 55    7/19/99 2:13p Dave
151  * Added some new strings for Heiko.
152  * 
153  * 54    7/15/99 2:37p Jefff
154  * 
155  * 53    7/13/99 6:07p Jefff
156  * Added support for localization string offsets.
157  * 
158  * 52    7/09/99 10:32p Dave
159  * Command brief and red alert screens.
160  * 
161  * 51    6/25/99 2:51p Jasons
162  * New string.
163  * 
164  * 50    6/25/99 11:59a Dave
165  * Multi options screen.
166  * 
167  * 49    6/24/99 12:34a Dave
168  * Main options screen.
169  * 
170  * 48    6/19/99 3:58p Dave
171  * More new strings.
172  * 
173  * 47    6/14/99 5:19p Dave
174  * 
175  * 46    6/04/99 11:32a Dave
176  * Added reset text to ship select screen. Fixed minor xstr bug in ui
177  * window
178  * 
179  * 45    6/01/99 6:07p Dave
180  * New loading/pause/please wait bar.
181  * 
182  * 44    6/01/99 4:03p Dave
183  * Changed some popup flag #defines. Upped string count to 1336
184  * 
185  * 43    5/26/99 11:46a Dave
186  * Added ship-blasting lighting and made the randomization of lighting
187  * much more customizable.
188  * 
189  * 42    5/22/99 6:05p Dave
190  * Fixed a few localization # problems.
191  * 
192  * 41    5/21/99 6:45p Dave
193  * Sped up ui loading a bit. Sped up localization disk access stuff. Multi
194  * start game screen, multi password, and multi pxo-help screen.
195  * 
196  * 40    5/17/99 2:52p Dave
197  * Fixed dumb localization problem.
198  * 
199  * 39    5/17/99 10:07a Dave
200  * Updated string count.
201  * 
202  * 38    5/04/99 6:38p Dave
203  * Finished multi join-wait screen.
204  * 
205  * 37    5/04/99 5:20p Dave
206  * Fixed up multiplayer join screen and host options screen. Should both
207  * be at 100% now.
208  * 
209  * 36    5/03/99 11:04p Dave
210  * Most of the way done with the multi join screen.
211  * 
212  * 35    5/03/99 8:32p Dave
213  * New version of multi host options screen.
214  * 
215  * 34    4/09/99 2:28p Dave
216  * Upped Xstring count.
217  * 
218  * 33    4/09/99 2:21p Dave
219  * Multiplayer beta stuff. CD checking.
220  * 
221  * 32    4/08/99 12:50p Neilk
222  * changed number of xstr constant
223  * 
224  * 31    4/07/99 5:54p Dave
225  * Fixes for encryption in updatelauncher.
226  * 
227  * 30    3/24/99 4:05p Dave
228  * Put in support for assigning the player to a specific squadron with a
229  * specific logo. Preliminary work for doing pos/orient checksumming in
230  * multiplayer to reduce bandwidth.
231  * 
232  * 29    3/23/99 3:35p Andsager
233  * Add error check for duplicate string indices
234  * 
235  * 28    3/22/99 2:56p Andsager
236  * Localize Launcher Updater
237  * 
238  * 27    2/23/99 11:18a Andsager
239  * Localize launcher using strings.tbl
240  * 
241  * 26    2/22/99 9:35p Andsager
242  * Add lcl_get_language_name() returns string with current lang.  Added
243  * localization for launcher.
244  * 
245  * 25    2/21/99 6:02p Dave
246  * Fixed standalone WSS packets. 
247  * 
248  * 24    2/17/99 2:11p Dave
249  * First full run of squad war. All freespace and tracker side stuff
250  * works.
251  * 
252  * 23    2/12/99 6:15p Dave
253  * Pre-mission Squad War code is 95% done.
254  * 
255  * 22    2/02/99 7:27p Neilk
256  * implemented lc_close() to free up some string memory when shutting down
257  * 
258  * 21    1/30/99 1:29a Dave
259  * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
260  * screen.  Fixed beam weapon death messages.
261  * 
262  * 20    1/29/99 7:56p Neilk
263  * Added new mission log interface
264  * 
265  * 19    1/29/99 4:17p Dave
266  * New interface screens.
267  * 
268  * 18    1/29/99 12:47a Dave
269  * Put in sounds for beam weapon. A bunch of interface screens (tech
270  * database stuff).
271  * 
272  * 17    1/13/99 2:10p Andsager
273  * added string
274  * 
275  * 16    12/14/98 12:13p Dave
276  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
277  * Need to test now.
278  * 
279  * 15    12/03/98 5:22p Dave
280  * Ported over Freespace 1 multiplayer ships.tbl and weapons.tbl
281  * checksumming.
282  * 
283  * 14    12/02/98 5:47p Dave
284  * Put in interface xstr code. Converted barracks screen to new format.
285  * 
286  * 13    12/01/98 4:46p Dave
287  * Put in targa bitmap support (16 bit).
288  *  
289  * $NoKeywords: $
290  */
291
292
293 #include <ctype.h>
294 #include "cfile.h"
295 #include "localize.h"
296 #include "parselo.h"
297 #include "osregistry.h"
298 #include "encrypt.h"
299 #include "2d.h"
300
301 // ------------------------------------------------------------------------------------------------------------
302 // LOCALIZE DEFINES/VARS
303 //
304
305 // general language/localization data ---------------------
306
307 // current language
308 int Lcl_current_lang = LCL_ENGLISH;
309
310 // language info table
311 typedef struct lang_info {
312         char lang_name[LCL_LANG_NAME_LEN + 1];                          // literal name of the language
313         char lang_ext[LCL_LANG_NAME_LEN + 1];                           // for adding to names on disk access
314 } lang_info;
315
316 lang_info Lcl_languages[LCL_NUM_LANGUAGES] = {
317         { "English",            "" },                                                                   // english
318         { "German",                     "gr" },                                                         // german
319         { "French",                     "fr" },                                                         // french
320         { "Polish",                     "pl" },                                                         // polish
321 };
322
323 //#if defined(GERMAN_BUILD)
324 //#define DEFAULT_LANGUAGE                                                      "German"
325 //#else
326 #define DEFAULT_LANGUAGE                                                        "English"
327 //#endif
328
329 // following is the offset where special characters start in our font
330 #define LCL_SPECIAL_CHARS_FR    164
331 #define LCL_SPECIAL_CHARS_GR    164
332 #define LCL_SPECIAL_CHARS_PL    127
333 #define LCL_SPECIAL_CHARS               127
334 int Lcl_special_chars;
335
336 // use these to replace *_BUILD, values before
337 // only 1 will be active at a time
338 int Lcl_fr = 0;
339 int Lcl_gr = 0 ;
340 int Lcl_pl = 0;
341 int Lcl_english = 1;
342
343
344 // executable string localization data --------------------
345
346 // XSTR_SIZE is the total count of unique XSTR index numbers.  An index is used to
347 // reference an entry in strings.tbl.  This is used for translation of strings from
348 // the english version (in the code) to a foreign version (in the table).  Thus, if you
349 // add a new string to the code, you must assign it a new index.  Use the number below for
350 // that index and increase the number below by one.
351 #define XSTR_SIZE       1570
352
353
354 // struct to allow for strings.tbl-determined x offset
355 // offset is 0 for english, by default
356 typedef struct {
357         char *str;
358         int  offset_x;                          // string offset in 640
359         int  offset_x_hi;                       // string offset in 1024
360 } lcl_xstr;
361
362 //char *Xstr_table[XSTR_SIZE];
363 lcl_xstr Xstr_table[XSTR_SIZE];
364 int Xstr_inited = 0;
365
366
367 // table/mission externalization stuff --------------------
368
369 #define TABLE_STRING_FILENAME                                           "tstrings.tbl"
370 // filename of the file to use when localizing table strings
371 char *Lcl_ext_filename = NULL;
372 CFILE *Lcl_ext_file = NULL;
373
374 // for scanning/parsing tstrings.tbl (from ExStr)
375 #define PARSE_TEXT_STRING_LEN                   2048
376 #define PARSE_ID_STRING_LEN                     128
377 #define TS_SCANNING                                             0                               // scanning for a line of text
378 #define TS_ID_STRING                                            1                               // reading in an id string
379 #define TS_OPEN_QUOTE                                   2                               // looking for an open quote
380 #define TS_STRING                                                       3                               // reading in the text string itself
381 int Ts_current_state = 0;
382 char Ts_text[PARSE_TEXT_STRING_LEN];                            // string we're currently working with
383 char Ts_id_text[PARSE_ID_STRING_LEN];                           // id string we're currently working with
384 int Ts_text_size;
385 int Ts_id_text_size;
386
387 // file pointers for optimized string lookups
388 // some example times for Freespace2 startup with granularities (mostly .tbl files, ~500 strings in the table file, many looked up more than once)
389 // granularity 20                       :               13 secs
390 // granularity 10                       :               11 secs
391 // granularity 5                        :               9 secs
392 // granularity 2                        :               7-8 secs
393 #define LCL_GRANULARITY                                 1                               // how many strings between each pointer (lower granularities should give faster lookup times)
394 #define LCL_MAX_POINTERS                                4500                    // max # of pointers
395 #define LCL_MAX_STRINGS                                 (LCL_GRANULARITY * LCL_MAX_POINTERS)
396 int Lcl_pointers[LCL_MAX_POINTERS];
397 int Lcl_pointer_count = 0;
398
399
400 // ------------------------------------------------------------------------------------------------------------
401 // LOCALIZE FORWARD DECLARATIONS
402 //
403
404 // associate table file externalization with the specified input file
405 void lcl_ext_associate(char *filename);
406
407 // given a valid XSTR() tag piece of text, extract the string portion, return it in out, nonzero on success
408 int lcl_ext_get_text(char *xstr, char *out);
409
410 // given a valid XSTR() tag piece of text, extract the id# portion, return the value in out, nonzero on success
411 int lcl_ext_get_id(char *xstr, int *out);
412
413 // given a valid XSTR() id#, lookup the string in tstrings.tbl, filling in out if found, nonzero on success
414 int lcl_ext_lookup(char *out, int id);
415
416 // if the char is a valid char for a signed integer value string
417 int lcl_is_valid_numeric_char(char c);
418
419 // sub-parse function for individual lines of tstrings.tbl (from Exstr)
420 // returns : integer with the low bits having the following values :
421 // 0 on fail, 1 on success, 2 if found a matching id/string pair, 3 if end of language has been found
422 // for cases 1 and 2 : the high bit (1<<31) will be set if the parser detected the beginning of a new string id on this line
423 // so be sure to mask this value out to get the low portion of the return value
424 //
425 int lcl_ext_lookup_sub(char *text, char *out, int id);
426
427 // initialize the pointer array into tstrings.tbl (call from lcl_ext_open() ONLY)
428 void lcl_ext_setup_pointers();
429
430
431 // ------------------------------------------------------------------------------------------------------------
432 // LOCALIZE FUNCTIONS
433 //
434
435 // initialize localization, if no language is passed - use the language specified in the registry
436 void lcl_init(int lang_init)
437 {
438         char lang_string[128];
439         char *ret;
440         int lang, idx;
441
442         // initialize encryption
443         encrypt_init();
444
445         // read the language from the registry
446         if(lang_init < 0){
447                 memset(lang_string, 0, 128);
448
449                 // default to DEFAULT_LANGUAGE (which should be english so we dont have to put German text 
450                 // in tstrings in the #default section
451                 ret = os_config_read_string(NULL, "Language", DEFAULT_LANGUAGE);
452
453                 if(ret == NULL){
454                         Int3();
455                         strcpy(lang_string, DEFAULT_LANGUAGE);
456                 } else {
457                         strcpy(lang_string, ret);
458                 }
459
460                 // look it up
461                 lang = -1;
462                 for(idx=0; idx<LCL_NUM_LANGUAGES; idx++){
463                         if(!stricmp(Lcl_languages[idx].lang_name, lang_string)){
464                                 lang = idx;
465                                 break;
466                         }
467                 }
468                 if(lang < 0){
469                         lang = 0;
470                 }       
471         } else {
472                 Assert((lang_init >= 0) && (lang_init < LCL_NUM_LANGUAGES));
473                 lang = lang_init;
474         }
475
476         // language markers
477         Lcl_pointer_count = 0;
478
479         // associate the table string file
480         lcl_ext_associate(TABLE_STRING_FILENAME);               
481
482         // set the language (this function takes care of setting up file pointers)
483         lcl_set_language(lang);         
484 }
485
486 // added 2.2.99 by NeilK to take care of fs2 launcher memory leaks
487 // shutdown localization
488 void lcl_close()
489 {
490         // if the filename exists, free it up
491         if(Lcl_ext_filename != NULL){
492                 free(Lcl_ext_filename);
493         }
494 };
495
496 // determine what language we're running in, see LCL_* defines above
497 int lcl_get_language()
498 {
499         return Lcl_current_lang;
500 }
501
502 // initialize the xstr table
503 void lcl_xstr_init()
504 {
505         char chr, buf[4096];
506         char language_tag[512]; 
507         int i, z, index, rval;
508         char *p_offset = NULL;
509         int offset_lo = 0, offset_hi = 0;
510
511         for (i=0; i<XSTR_SIZE; i++){
512                 Xstr_table[i].str = NULL;
513         }
514
515         if ((rval = setjmp(parse_abort)) != 0) {
516                 mprintf(("Error parsing 'strings.tbl'\nError code = %i.\n", rval));
517         } else {
518                 // make sure localization is NOT running
519                 lcl_ext_close();
520
521                 read_file_text("strings.tbl");
522                 reset_parse();
523
524                 // move down to the proper section              
525                 memset(language_tag, 0, 512);
526                 strcpy(language_tag, "#");
527                 strcat(language_tag, Lcl_languages[Lcl_current_lang].lang_name);
528                 if(skip_to_string(language_tag) != 1){
529                         Error(LOCATION, NOX("Strings.tbl is corrupt"));
530                 }               
531
532                 // parse all the strings in this section of the table
533                 while (!check_for_string("#")) {
534                         int num_offsets_on_this_line = 0;
535
536                         stuff_int(&index);
537                         stuff_string(buf, F_NAME, NULL, 4096);
538
539                         if(Lcl_pl) {
540                             lcl_fix_polish(buf);
541                         }
542
543                         i = strlen(buf);
544                         while (i--) {
545                                 if (!isspace(buf[i])) {
546                                         break;
547                                 }
548                         }
549
550                         // trim unneccesary end of string
551                         if (i >= 0) {
552                                 // Assert(buf[i] == '"');
553                                 if (buf[i] != '"') {
554                                         // probably an offset on this entry
555                                         buf[i+1] = 0;                                           // drop down a null terminator (prolly unnecessary)
556                                         while(!is_white_space(buf[i])) i--;     // back up over the potential offset
557                                         while(is_white_space(buf[i])) i--;      // now back up over intervening spaces
558                                         num_offsets_on_this_line = 1;
559                                         if (buf[i] != '"') {
560                                                 // could have a 2nd offset value (one for 640, one for 1024)
561                                                 // so back up again
562                                                 while(!is_white_space(buf[i])) i--;     // back up over the 2nd offset
563                                                 while(is_white_space(buf[i])) i--;      // now back up over intervening spaces
564                                                 num_offsets_on_this_line = 2;
565                                         }
566
567                                         p_offset = &buf[i+1];                   // get ptr to string section with offset in it
568                                         if (buf[i] != '"') {
569                                                 Error(LOCATION, NOX("Strings.tbl is corrupt"));         // now its an error
570                                         }
571                                 }
572
573                                 buf[i] = 0;
574                         }
575
576                         // copy string into buf
577                         z = 0;
578                         for (i=1; buf[i]; i++) {
579                                 chr = buf[i];
580                                 if (chr == '\\') {
581                                         chr = buf[++i];
582                                         if (chr == 'n') {
583                                                 chr = '\n';
584                                         } else if (chr == 'r') {
585                                                 chr = '\r';
586                                         }
587
588                                 }
589
590                                 buf[z++] = chr;
591                         }
592
593                         // null terminator on buf
594                         buf[z] = 0;
595
596                         // write into Xstr_table
597                         if (index >= 0 && index < XSTR_SIZE) {
598                                 if (Xstr_table[index].str != NULL) {
599                                         Warning(LOCATION, "Strings table index %d used more than once", index);
600                                 }
601                                 Xstr_table[index].str = strdup(buf);
602                         }
603
604                         // read offset information, assume 0 if nonexistant
605                         if (p_offset != NULL) {
606                                 if (sscanf(p_offset, "%d%d", &offset_lo, &offset_hi) < num_offsets_on_this_line) {
607                                         // whatever is in the file ain't a proper offset
608                                         Error(LOCATION, NOX("Strings.tbl is corrupt"));
609                                 }
610                         }
611                         Xstr_table[index].offset_x = offset_lo;
612                         if (num_offsets_on_this_line == 2) {
613                                 Xstr_table[index].offset_x_hi = offset_hi;
614                         } else {
615                                 Xstr_table[index].offset_x_hi = offset_lo;                                              
616                         }
617
618                         // clear out our vars
619                         p_offset = NULL;
620                         offset_lo = 0;
621                         offset_hi = 0;
622                         num_offsets_on_this_line = 0;
623                 }
624         }
625
626         Xstr_inited = 1;
627 }
628
629
630 // free Xstr table
631 void lcl_xstr_close()
632 {
633         for (int i=0; i<XSTR_SIZE; i++){
634                 if (Xstr_table[i].str != NULL) {
635                         free(Xstr_table[i].str);
636                         Xstr_table[i].str = NULL;
637                 }
638         }
639 }
640
641
642 // set our current language
643 void lcl_set_language(int lang)
644 {
645         Lcl_current_lang = lang;
646
647         nprintf(("General", "Setting language to %s\n", Lcl_languages[lang].lang_name));
648
649         // flag the proper language as being active
650         Lcl_fr = 0;
651         Lcl_gr = 0;
652         Lcl_pl = 0;
653         Lcl_english = 0;
654         switch(lang){
655         case LCL_ENGLISH:
656                 Lcl_english = 1;                
657                 Lcl_special_chars = LCL_SPECIAL_CHARS;
658                 break;
659         case LCL_FRENCH:
660                 Lcl_fr = 1;
661                 Lcl_special_chars = LCL_SPECIAL_CHARS_FR;
662                 break;
663         case LCL_GERMAN:
664                 Lcl_gr = 1;
665                 Lcl_special_chars = LCL_SPECIAL_CHARS_GR;
666                 break;
667         case LCL_POLISH:
668                 Lcl_pl = 1;
669                 Lcl_special_chars = LCL_SPECIAL_CHARS_PL;
670                 break;
671         }
672
673         // set to 0, so lcl_ext_open() knows to reset file pointers
674         Lcl_pointer_count = 0;
675
676         // reset file pointers to the proper language-section
677         if(Lcl_current_lang != LCL_DEFAULT_LANGUAGE){
678                 lcl_ext_setup_pointers();
679         }
680 }
681
682 // maybe add on an appropriate subdirectory when opening a localized file
683 void lcl_add_dir(char *current_path)
684 {
685         char last_char;
686         int path_len;
687
688         // if the disk extension is 0 length, don't add enything
689         if (strlen(Lcl_languages[Lcl_current_lang].lang_ext) <= 0) {
690                 return;
691         }
692
693         // get the length of the string so far
694         path_len = strlen(current_path);
695         if (path_len <= 0) {
696                 return;
697         }
698         
699         // get the current last char
700         last_char = current_path[path_len - 1];
701
702         // if the last char is a slash, just copy in the disk extension
703         if (last_char == '\\') {
704                 strcat(current_path, Lcl_languages[Lcl_current_lang].lang_ext);
705                 strcat(current_path, "\\");
706         } 
707         // otherwise add a slash, then copy in the disk extension
708         else {
709                 strcat(current_path, "\\");
710                 strcat(current_path, Lcl_languages[Lcl_current_lang].lang_ext);
711         }
712 }
713
714 // maybe add localized directory to full path with file name when opening a localized file
715 void lcl_add_dir_to_path_with_filename(char *current_path)
716 {
717         char temp[MAX_PATH_LEN];
718
719         // if the disk extension is 0 length, don't add enything
720         if (strlen(Lcl_languages[Lcl_current_lang].lang_ext) <= 0) {
721                 return;
722         }
723
724         // find position of last slash and copy rest of filename (not counting slash) to temp
725         // mark end of current path with '\0', so strcat will work
726         char *last_slash = strrchr(current_path, '\\');
727         if (last_slash == NULL) {
728                 strcpy(temp, current_path);
729                 current_path[0] = '\0';
730         } else {
731                 strcpy(temp, last_slash+1);
732                 last_slash[1] = '\0';
733         }
734
735         // add extension
736         strcat(current_path, Lcl_languages[Lcl_current_lang].lang_ext);
737         strcat(current_path, "\\");
738
739         // copy rest of filename from temp
740         strcat(current_path, temp);
741 }
742
743
744 // externalization of table/mission files ----------------------- 
745
746 // open the externalization file for use during parsing (call before parsing a given file)
747 void lcl_ext_open()
748 {
749         // if the file is already open, do nothing
750         Assert(Lcl_ext_file == NULL);   
751
752         // if we're running in the default language, do nothing
753         if(Lcl_current_lang == LCL_DEFAULT_LANGUAGE){
754                 return;
755         }
756
757         // otherwise open the file
758         Lcl_ext_file = cfopen(Lcl_ext_filename, "rt");
759         if(Lcl_ext_file == NULL){
760                 return;
761         }               
762 }
763
764 // close the externalization file (call after parsing a given file)
765 void lcl_ext_close()
766 {
767         // if the file is not open, do nothing
768         if(Lcl_ext_file == NULL){
769                 return;
770         }
771
772         // if we're running in the default language, do nothing
773         if(Lcl_current_lang == LCL_DEFAULT_LANGUAGE){
774                 return;
775         }
776                 
777         // otherwise close it
778         cfclose(Lcl_ext_file);
779         Lcl_ext_file = NULL;
780 }
781
782 // get the localized version of the string. if none exists, return the original string
783 // valid input to this function includes :
784 // "this is some text"
785 // XSTR("wheeee", -1)
786 // XSTR("whee", 20)
787 // and these should cover all the externalized string cases
788 // fills in id if non-NULL. a value of -2 indicates it is not an external string
789 void lcl_ext_localize(char *in, char *out, int max_len, int *id)
790 {                       
791         char first_four[5];
792         char text_str[2048]="";
793         char lookup_str[2048]="";
794         int str_id;     
795         int str_len;    
796
797         Assert(in);
798         Assert(out);
799
800         // default (non-external string) value
801         if(id != NULL){
802                 *id = -2;
803         }       
804
805         str_len = strlen(in);
806
807         // if the string is < 9 chars, it can't be an XSTR("",) tag, so just copy it
808         if(str_len < 9){
809                 if(str_len > max_len){
810                         error_display(0, "Token too long: [%s].  Length = %i.  Max is %i.\n", in, str_len, max_len);
811                         return;
812                 }               
813                 strcpy(out, in);
814                 if(id != NULL){
815                         *id = -2;
816                 }
817                 return;
818         }
819
820         // otherwise, check to see if it's an XSTR() tag
821         memset(first_four, 0, 5);
822         strncpy(first_four, in, 4);
823         if(stricmp(first_four, "XSTR")){
824                 // NOT an XSTR() tag
825                 if(str_len > max_len){
826                         error_display(0, "Token too long: [%s].  Length = %i.  Max is %i.\n", in, str_len, max_len);
827                         return;
828                 }               
829                 strcpy(out, in);
830                 if(id != NULL){
831                         *id = -2;
832                 }
833                 return;
834         }
835
836         // at this point we _know_ its an XSTR() tag, so split off the strings and id sections          
837         if(!lcl_ext_get_text(in, text_str)){
838                 Int3();
839                 strcpy(out, in);
840                 if(id != NULL){
841                         *id = -1;
842                 }
843                 return;
844         }
845         if(!lcl_ext_get_id(in, &str_id)){
846                 strcpy(out, in);
847                 if(id != NULL){
848                         *id = -1;
849                 }
850                 return;
851         }
852         
853         // if the localization file is not open, or we're running in the default language, return the original string
854         if((Lcl_ext_file == NULL) || (str_id < 0) || (Lcl_current_lang == LCL_DEFAULT_LANGUAGE)){
855                 strcpy(out, text_str);
856                 if(id != NULL){
857                         *id = str_id;
858                 }
859                 return;
860         }               
861
862         // attempt to find the string
863         if(lcl_ext_lookup(lookup_str, str_id)){
864                 // copy to the outgoing string
865                 Assert(strlen(lookup_str) <= (unsigned int)(max_len - 1));
866
867                 if (strlen(lookup_str) > (unsigned int)(max_len-1)) {
868                         // be safe and truncate string to fit
869                         strncpy(out, lookup_str, (size_t) (max_len-1));
870                         out[max_len-1] = '\0';          // ensure null terminator, since strncpy(...) doesnt.
871                 } else {
872                         strcpy(out, lookup_str);
873                 }
874
875         }
876         // otherwise use what we have - probably should Int3() or assert here
877         else {
878                 strcpy(out, text_str);
879         }       
880
881         // set the id #
882         if(id != NULL){
883                 *id = str_id;
884         }
885 }
886
887 // translate the specified string based upon the current language
888 char *XSTR(char *str, int index)
889 {
890         if(!Xstr_inited){
891                 return str;
892         }
893
894         // perform a lookup
895         if (index >= 0 && index < XSTR_SIZE) {
896                 if (Xstr_table[index].str){
897                         return Xstr_table[index].str;  // return translation of string
898                 }
899         }
900
901         // can't translate, return original english string
902         return str;
903 }
904
905 // retrieve the offset for a localized string
906 int lcl_get_xstr_offset(int index, int res)
907 {
908         if (res == GR_640) {
909                 return Xstr_table[index].offset_x;
910         } else {
911                 return Xstr_table[index].offset_x_hi;
912         }
913 }
914
915
916 // ------------------------------------------------------------------------------------------------------------
917 // LOCALIZE FORWARD DEFINITIONS
918 //
919
920 // associate table file externalization with the specified input file
921 void lcl_ext_associate(char *filename)
922 {
923         // if the filename already exists, free it up
924         if(Lcl_ext_filename != NULL){
925                 free(Lcl_ext_filename);
926         }
927
928         // set the new filename
929         Lcl_ext_filename = strdup(filename);
930 }
931
932 // given a valid XSTR() tag piece of text, extract the string portion, return it in out, nonzero on success
933 int lcl_ext_get_text(char *xstr, char *out)
934 {
935         int str_start, str_end;
936         int str_len;
937         char *p, *p2;
938
939         Assert(xstr != NULL);
940         Assert(out != NULL);
941         str_len = strlen(xstr);
942         
943         // this is some crazy wack-ass code.
944         // look for the open quote
945         str_start = str_end = 0;
946         p = strstr(xstr, "\"");
947         if(p == NULL){
948                 error_display(0, "Error parsing XSTR() tag %s\n", xstr);                
949                 return 0;
950         } else {
951                 str_start = p - xstr + 1;               
952         }
953         // make sure we're not about to walk past the end of the string
954         if((p - xstr) >= str_len){
955                 error_display(0, "Error parsing XSTR() tag %s\n", xstr);                
956                 return 0;
957         }
958
959         // look for the close quote
960         p2 = strstr(p+1, "\"");
961         if(p2 == NULL){
962                 error_display(0, "Error parsing XSTR() tag %s\n", xstr);                
963                 return 0;
964         } else {
965                 str_end = p2 - xstr;
966         }
967
968         // now that we know the boundaries of the actual string in the XSTR() tag. copy it
969         memcpy(out, xstr + str_start, str_end - str_start);     
970
971         if(Lcl_pl) {
972             lcl_fix_polish(out);
973         }
974
975         // success
976         return 1;
977 }
978
979 // given a valid XSTR() tag piece of text, extract the id# portion, return the value in out, nonzero on success
980 int lcl_ext_get_id(char *xstr, int *out)
981 {
982         char *p, *pnext;
983         int str_len;
984
985         Assert(xstr != NULL);
986         Assert(out != NULL);
987         
988         str_len = strlen(xstr);
989
990         // find the first quote
991         p = strstr(xstr, "\"");
992         if(p == NULL){
993                 error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
994                 return 0;
995         }
996         // make sure we're not about to walk off the end of the string
997         if((p - xstr) >= str_len){
998                 error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
999                 return 0;
1000         }
1001         p++;
1002
1003         // continue searching until we find the close quote
1004         while(1){
1005                 pnext = strstr(p, "\"");
1006                 if(pnext == NULL){
1007                         error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
1008                         return 0;
1009                 }
1010
1011                 // if the previous char is a \, we know its not the "end-of-string" quote
1012                 if(*(pnext - 1) != '\\'){
1013                         p = pnext;
1014                         break;
1015                 }
1016
1017                 // continue
1018                 p = pnext;
1019         }
1020
1021         // search until we find a ,     
1022         pnext = strstr(p, ",");
1023         if(pnext == NULL){
1024                 error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
1025                 return 0;
1026         }
1027         // make sure we're not about to walk off the end of the string
1028         if((pnext - xstr) >= str_len){
1029                 error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
1030                 return 0;
1031         }
1032         pnext++;
1033         
1034         // now get the id string
1035         p = pnext;
1036         pnext = strtok(p, ")");
1037         if(pnext == NULL){
1038                 error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
1039                 return 0;
1040         }
1041
1042         // get the value and we're done
1043         *out = atoi(pnext);
1044
1045         // success
1046         return 1;
1047 }
1048
1049 // given a valid XSTR() id#, lookup the string in tstrings.tbl, filling in out if found, nonzero on success
1050 int lcl_ext_lookup(char *out, int id)
1051 {
1052         char text[1024];
1053         int ret;
1054         int pointer;
1055         
1056         Assert(Lcl_pointer_count >= 0);
1057         Assert(Lcl_pointers[0] >= 0);
1058         Assert(Lcl_pointers[Lcl_pointer_count - 1] >= 0);
1059         Assert(Lcl_ext_file != NULL);
1060         Assert(id >= 0);
1061
1062         // seek to the closest pointer <= the id# we're looking for
1063         pointer = id / LCL_GRANULARITY;
1064         cfseek(Lcl_ext_file, Lcl_pointers[pointer], CF_SEEK_SET);
1065
1066         // reset parsing vars and go to town
1067         Ts_current_state = TS_SCANNING;
1068         Ts_id_text_size = 0;
1069         Ts_text_size;
1070         memset(Ts_text, 0, PARSE_TEXT_STRING_LEN);
1071         memset(Ts_id_text, 0, PARSE_ID_STRING_LEN);
1072         while((cftell(Lcl_ext_file) < Lcl_pointers[Lcl_pointer_count - 1]) && cfgets(text, 1024, Lcl_ext_file)){
1073                 ret = lcl_ext_lookup_sub(text, out, id);
1074                         
1075                 // run the line parse function          
1076                 switch(ret & 0x0fffffff){
1077                 // error
1078                 case 0 :
1079                         Int3();                 // should never get here - it means the string doens't exist in the table!!
1080                         return 0;
1081
1082                 // success parsing the line - please continue
1083                 case 1 :
1084                         break;
1085
1086                 // found a matching string/id pair
1087                 case 2 :                        
1088                         // success
1089                         if (Lcl_gr) {
1090                                 // this is because tstrings.tbl reads in as ANSI for some reason
1091                                 // opening tstrings with "rb" mode didnt seem to help, so its now still "rt" like before
1092                                 lcl_fix_umlauts(out, LCL_TO_ASCII);             
1093                         }       
1094                         return 1;
1095
1096                 // end of language found
1097                 case 3 :
1098                         Int3();                 // should never get here - it means the string doens't exist in the table!!
1099                         return 0;               
1100                 }
1101         }
1102         
1103         Int3();                 // should never get here - it means the string doens't exist in the table!!
1104         return 0;
1105 }
1106
1107 // sub-parse function for individual lines of tstrings.tbl (from Exstr)
1108 // returns : integer with the low bits having the following values :
1109 // 0 on fail, 1 on success, 2 if found a matching id/string pair, 3 if end of language has been found
1110 // for cases 1 and 2 : the high bit (1<<31) will be set if the parser detected the beginning of a new string id on this line
1111 //
1112 int lcl_ext_lookup_sub(char *text, char *out, int id)
1113 {
1114         char *front;                    // front of the line
1115         char *p;                                        // current ptr
1116         int len = strlen(text);
1117         int count;      
1118         char text_copy[1024];   
1119         char *tok;
1120         int found_new_string_id = 0;
1121
1122         front = text;
1123         p = text;
1124         count = 0;                      
1125         while(count < len){
1126                 // do something useful
1127                 switch(Ts_current_state){               
1128                 // scanning for a line of text
1129                 case TS_SCANNING:
1130                         // if the first word is #end, we're done with the file altogether
1131                         strcpy(text_copy, text);
1132                         tok = strtok(text_copy, " \n");
1133                         if((tok != NULL) && !stricmp(tok, "#end")){
1134                                 return 3;
1135                         }
1136                         // if its a commented line, skip it
1137                         else if((text[0] == ';') || (text[0] == ' ') || (text[0] == '\n')){
1138                                 return 1;
1139                         }
1140                         // otherwise we should have an ID #, so stuff it and move to the proper state
1141                         else {
1142                                 if(lcl_is_valid_numeric_char(*p)){
1143                                         memset(Ts_id_text, 0, PARSE_ID_STRING_LEN);
1144                                         Ts_id_text_size = 0;
1145                                         Ts_id_text[Ts_id_text_size++] = *p;
1146                                         Ts_current_state = TS_ID_STRING;
1147
1148                                         found_new_string_id = 1;
1149                                 }
1150                                 // error
1151                                 else {
1152                                         Int3();
1153                                         return 0;
1154                                 }
1155                         }
1156                         break;
1157
1158                 // scanning in an id string
1159                 case TS_ID_STRING:
1160                         // if we have another valid char
1161                         if(lcl_is_valid_numeric_char(*p)){
1162                                 Ts_id_text[Ts_id_text_size++] = *p;
1163                         }
1164                         // if we found a comma, our id# is finished, look for the open quote
1165                         else if(*p == ','){
1166                                 Ts_current_state = TS_OPEN_QUOTE;
1167                         } else {
1168                                 Int3();
1169                                 return 0;
1170                         }
1171                         break;
1172
1173                 case TS_OPEN_QUOTE:
1174                         // valid space or an open quote
1175                         if((*p == ' ') || (*p == '\"')){
1176                                 if(*p == '\"'){
1177                                         memset(Ts_text, 0, PARSE_TEXT_STRING_LEN);
1178                                         Ts_text_size = 0;
1179                                         Ts_current_state = TS_STRING;
1180                                 }
1181                         } else {
1182                                 Int3();
1183                                 return 0;
1184                         }
1185                         break;
1186
1187                 case TS_STRING:
1188                         // if we have an end quote, we need to look for a comma
1189                         if((*p == '\"') /*&& (Ts_text_size > 0)*/ && (Ts_text[Ts_text_size - 1] != '\\')){
1190                                 // we're now done - we have a string
1191                                 Ts_current_state = TS_SCANNING;
1192
1193                                 // if the id#'s match, copy the string and return "string found"
1194                                 if((atoi(Ts_id_text) == id) && (out != NULL)){
1195                                         strcpy(out, Ts_text);
1196
1197                                         return found_new_string_id ? (1<<1) | (1<<31) : (1<<1);                                 
1198                                 }
1199                                 
1200                                 // otherwise, just continue parsing                             
1201                                 return found_new_string_id ? (1<<0) | (1<<31) : (1<<0);
1202                         } 
1203                         // otherwise add to the string
1204                         else {
1205                                 Ts_text[Ts_text_size++] = *p;
1206                         }                                                                               
1207                         break;
1208                 }               
1209
1210                 // if we have a newline, return success, we're done with this line
1211                 if(*p == '\n'){
1212                         return found_new_string_id ? (1<<0) | (1<<31) : (1<<0);
1213                 }
1214
1215                 // next char in the line
1216                 p++;
1217                 count++;
1218         }       
1219
1220         // success
1221         return found_new_string_id ? (1<<0) | (1<<31) : (1<<0);
1222 }
1223
1224 // if the char is a valid char for a signed integer value
1225 int lcl_is_valid_numeric_char(char c)
1226 {
1227         return ( (c == '-') || (c == '0') || (c == '1') || (c == '2') || (c == '3') || (c == '4') ||
1228                                 (c == '5') || (c == '6') || (c == '7') || (c == '8') || (c == '9') ) ? 1 : 0;
1229 }
1230
1231 // initialize the pointer array into tstrings.tbl (call from lcl_ext_open() ONLY)
1232 void lcl_ext_setup_pointers()
1233 {
1234         char language_string[128];
1235         char line[1024];
1236         char *tok;      
1237         int string_count;
1238         int ret;
1239         int found_start = 0;
1240
1241         // open the localization file
1242         lcl_ext_open();
1243         if(Lcl_ext_file == NULL){
1244                 error_display(0, "Error opening externalization file! File likely does not exist or could not be found");
1245                 return;
1246         }
1247
1248         // seek to the currently active language
1249         memset(language_string, 0, 128);
1250         strcpy(language_string, "#");
1251         if(!stricmp(DEFAULT_LANGUAGE, Lcl_languages[Lcl_current_lang].lang_name)){
1252                 strcat(language_string, "default");
1253         } else {
1254                 strcat(language_string, Lcl_languages[Lcl_current_lang].lang_name);
1255         }
1256         memset(line, 0, 1024);
1257
1258         // reset seek variables and begin               
1259         Lcl_pointer_count = 0;
1260         while(cfgets(line, 1024, Lcl_ext_file)){
1261                 tok = strtok(line, " \n");
1262                 if(tok == NULL){
1263                         continue;                       
1264                 }
1265                 
1266                 // if the language matches, we're good to start parsing strings
1267                 if(!stricmp(language_string, tok)){
1268                         found_start = 1;                        
1269                         break;
1270                 }               
1271         }
1272
1273         // if we didn't find the language specified, error
1274         if(found_start <= 0){
1275                 error_display(0, "Could not find specified langauge in tstrings.tbl!\n");
1276                 lcl_ext_close();
1277                 return;
1278         }
1279
1280         string_count = 0;       
1281         while(cfgets(line, 1024, Lcl_ext_file)){
1282                 ret = lcl_ext_lookup_sub(line, NULL, -1);
1283
1284                 // do stuff
1285                 switch(ret & 0x0fffffff){
1286                 // error
1287                 case 0 :
1288                         lcl_ext_close();
1289                         return;         
1290
1291                 // end of language found
1292                 case 3 :
1293                         // mark one final pointer
1294                         Lcl_pointers[Lcl_pointer_count++] = cftell(Lcl_ext_file) - strlen(line) - 1;
1295                         lcl_ext_close();
1296                         return;
1297                 }
1298
1299                 // the only other case we care about is the beginning of a new id#
1300                 if(ret & (1<<31)){              
1301                         if((string_count % LCL_GRANULARITY) == 0){
1302                                 // mark the pointer down
1303                                 Lcl_pointers[Lcl_pointer_count++] = cftell(Lcl_ext_file) - strlen(line) - 1;
1304
1305                                 // if we're out of pointer slots
1306                                 if(Lcl_pointer_count >= LCL_MAX_POINTERS){
1307                                         error_display(0, "Out of pointer for tstrings.tbl lookup. Please increment LCL_MAX_POINTERS in localize.cpp");
1308                                         lcl_ext_close();
1309                                         return;
1310                                 }
1311                         }
1312                         // increment string count
1313                         string_count++;                 
1314                 }
1315         }
1316
1317         // should never get here. we should always be exiting through case 3 (end of language section) of the above switch
1318         // statement
1319         Int3();
1320         lcl_ext_close();
1321 }
1322
1323 void lcl_get_language_name(char *lang_name)
1324 {
1325         Assert(LCL_NUM_LANGUAGES == 3);
1326
1327         strcpy(lang_name, Lcl_languages[Lcl_current_lang].lang_name);
1328 }
1329
1330 // converts german umlauted chars from ASCII to ANSI
1331 // so they appear in the launcher
1332 // how friggin lame is this
1333 // pass in a null terminated string, foo!
1334 // returns ptr to string you sent in
1335 char* lcl_fix_umlauts(char *str, int which_way)
1336 {
1337         int i=0;
1338
1339         if (which_way == LCL_TO_ANSI) {
1340                 // moving to ANSI charset
1341                 // run thru string and perform appropriate conversions
1342                 while (str[i] != '\0') {
1343                         switch (str[i]) {
1344                         case '\x81':
1345                                 // lower umlaut u
1346                                 str[i] = '\xFC';
1347                                 break;
1348                         case '\x84':
1349                                 // lower umlaut a
1350                                 str[i] = '\xE4';
1351                                 break;
1352                         case '\x94':
1353                                 // lower umlaut o
1354                                 str[i] = '\xF6';
1355                                 break;
1356                         case '\x9A':
1357                                 // upper umlaut u
1358                                 str[i] = '\xDC';
1359                                 break;
1360                         case '\x8E':
1361                                 // upper umlaut a
1362                                 str[i] = '\xC4';
1363                                 break;
1364                         case '\x99':
1365                                 // upper umlaut o
1366                                 str[i] = '\xD6';
1367                                 break;
1368                         case '\xE1':
1369                                 // beta-lookin thing that means "ss"
1370                                 str[i] = '\xDF';
1371                                 break;
1372                         }
1373
1374                         i++;
1375                 }
1376         } else {
1377                 // moving to ASCII charset
1378                 // run thru string and perform appropriate conversions
1379                 while (str[i] != '\0') {
1380                         switch (str[i]) {
1381                         case '\xFC':
1382                                 // lower umlaut u
1383                                 str[i] = '\x81';
1384                                 break;
1385                         case '\xE4':
1386                                 // lower umlaut a
1387                                 str[i] = '\x84';
1388                                 break;
1389                         case '\xF6':
1390                                 // lower umlaut o
1391                                 str[i] = '\x94';
1392                                 break;
1393                         case '\xDC':
1394                                 // upper umlaut u
1395                                 str[i] = '\x9A';
1396                                 break;
1397                         case '\xC4':
1398                                 // upper umlaut a
1399                                 str[i] = '\x8E';
1400                                 break;
1401                         case '\xD6':
1402                                 // upper umlaut o
1403                                 str[i] = '\x99';
1404                                 break;
1405                         case '\xDF':
1406                                 // beta-lookin thing that means "ss"
1407                                 str[i] = '\xE1';
1408                                 break;
1409                         }
1410
1411                         i++;
1412                 }
1413         }
1414
1415         return str;
1416 }
1417
1418 // convert some of the polish characters
1419 void lcl_fix_polish(char *str)
1420 {
1421     for(;*str;str++) {
1422         if(*str == '\xA2') *str = '\xF3';
1423         else if(*str == '\x88') *str = '\xEA';
1424     }
1425 }
1426
1427 // ------------------------------------------------------------------
1428 // lcl_translate_wep_name()
1429 //
1430 // For displaying weapon names in german version
1431 // since we cant actually just change them outright.
1432 //
1433 void lcl_translate_wep_name(char *name)
1434 {
1435         if (!strcmp(name, "Morning Star")) {    
1436                 strcpy(name, "Morgenstern");
1437         } else if (!strcmp(name, "MorningStar")) {
1438                 strcpy(name, "Morgenstern D");
1439         } else if (!strcmp(name, "UD-8 Kayser")) {
1440                 strcpy(name, "Kayserstrahl");
1441         } else if (!strcmp(name, "UD-D Kayser")) {
1442                 strcpy(name, "Kayserstrahl");
1443         }
1444 }
1445
1446 // ------------------------------------------------------------------
1447 // lcl_translate_brief_icon_name()
1448 //
1449 // For displaying ship names in german version
1450 // since we cant actually just change them outright.
1451 //
1452 void lcl_translate_brief_icon_name(char *name)
1453 {
1454         char *pos;
1455         char buf[128];
1456
1457         if (!stricmp(name, "Subspace Portal")) {        
1458                 strcpy(name, "Subraum Portal");
1459
1460         } else if (!stricmp(name, "Alpha Wing")) {
1461                 strcpy(name, "Alpha");
1462
1463         } else if (!stricmp(name, "Beta Wing")) {
1464                 strcpy(name, "Beta");
1465
1466         } else if (!stricmp(name, "Zeta Wing")) {
1467                 strcpy(name, "Zeta");
1468
1469         } else if (!stricmp(name, "Capella Node")) {
1470                 strcpy(name, "Capella");
1471
1472         } else if (!stricmp(name, "Hostile")) {
1473                 strcpy(name, "Gegner");
1474
1475         } else if (!stricmp(name, "Hostile Craft")) {
1476                 strcpy(name, "Gegner");
1477
1478         } else if (!stricmp(name, "Rebel Wing")) {
1479                 strcpy(name, "Rebellen");
1480
1481         } else if (!stricmp(name, "Rebel Fleet")) {
1482                 strcpy(name, "Rebellenflotte");
1483
1484         } else if (!stricmp(name, "Sentry Gun")) {
1485                 strcpy(name, "Gesch\x81tz");
1486
1487         } else if (!stricmp(name, "Cargo")) {
1488                 strcpy(name, "Fracht");
1489
1490         } else if (!stricmp(name, "Knossos Device")) {
1491                 strcpy(name, "Knossosger\x84t");
1492         
1493         } else if (!stricmp(name, "Support")) {
1494                 strcpy(name, "Versorger");
1495
1496         } else if (!stricmp(name, "Unknown")) {
1497                 strcpy(name, "Unbekannt");
1498
1499         } else if (!stricmp(name, "Instructor")) {
1500                 strcpy(name, "Ausbilder");
1501         
1502         } else if (!stricmp(name, "Jump Node")) {
1503                 strcpy(name, "Sprungknoten");
1504
1505         } else if (!stricmp(name, "Escort")) {
1506                 strcpy(name, "Geleitschutz");
1507
1508         } else if (!stricmp(name, "Asteroid Field")) {
1509                 strcpy(name, "Asteroidenfeld");
1510
1511         } else if (!stricmp(name, "Enif Station")) {
1512                 strcpy(name, "Station Enif");
1513
1514         } else if (!stricmp(name, "Rally Point")) {
1515                 strcpy(name, "Sammelpunkt");
1516
1517         } else if ((pos = strstr(name, "Transport")) != NULL) {
1518                 pos += 9;               // strlen of "transport"
1519                 strcpy(buf, "Transporter");
1520                 strcat(buf, pos);
1521                 strcpy(name, buf);
1522
1523         } else if ((pos = strstr(name, "Jump Node")) != NULL) {
1524                 pos += 9;               // strlen of "jump node"
1525                 strcpy(buf, "Sprungknoten");
1526                 strcat(buf, pos);
1527                 strcpy(name, buf);
1528         
1529         } else if (!stricmp(name, "Orion under repair")) {
1530                 strcpy(name, "Orion wird repariert");
1531
1532         // SOTY-specific ones below!
1533         
1534         } else if (!stricmp(name, "Wayfarer Station")) {
1535                 strcpy(name, "Station Wayfarer");
1536         } else if (!stricmp(name, "Enemy")) {
1537                 strcpy(name, "Gegner");
1538         } else if (!stricmp(name, "Supply Depot")) {
1539                 strcpy(name, "Nachschubdepot");
1540         } else if (!stricmp(name, "Fighter Escort")) {
1541                 strcpy(name, "Jagdschutz");
1542         } else if (!stricmp(name, "Shivans")) {
1543                 strcpy(name, "Shivaner");
1544         } else if (!stricmp(name, "NTF Base of Operations")) {
1545                 strcpy(name, "NTF-Operationsbasis");
1546         } else if (!stricmp(name, "NTF Bombers")) {
1547                 strcpy(name, "NTF-Bomber");
1548         } else if (!stricmp(name, "NTF Fighters")) {
1549                 strcpy(name, "NTF-J\x84ger");
1550         } else if (!stricmp(name, "Sentry")) {
1551                 strcpy(name, "Sperrgesch\x81tz");
1552         } else if (!stricmp(name, "Cargo Containers")) {
1553                 strcpy(name, "Frachtbeh\x84lter");
1554         } else if (!stricmp(name, "NTF Reinforcements")) {
1555                 strcpy(name, "NTF-Verst\x84rkungen");
1556         } else if (!stricmp(name, "NTF Base")) {
1557                 strcpy(name, "NTF-St\x81tzpunkt");
1558         } else if (!stricmp(name, "Refugee Convoy")) {
1559                 strcpy(name, "Fl\x81""chtlingskonvoi");
1560         } else if (!stricmp(name, "Food Convoy")) {
1561                 strcpy(name, "Nachschubkonvoi");
1562         } else if (!stricmp(name, "Governor's Shuttle")) {
1563                 strcpy(name, "F\x84hre des Gouverneurs");
1564         } else if (!stricmp(name, "GTVA Patrol")) {
1565                 strcpy(name, "GTVA-Patrouille");
1566         } else if (!stricmp(name, "Escort fighters")) {
1567                 strcpy(name, "Geleitschutz");
1568         } else if (!stricmp(name, "Nagada Outpost")) {
1569                 strcpy(name, "Nagada-Aussenposten");
1570         } else if (!stricmp(name, "Fighters")) {
1571                 strcpy(name, "J\x84ger");
1572         } else if (!stricmp(name, "Bombers")) {
1573                 strcpy(name, "Bomber");
1574         } else if (!stricmp(name, "Enemy Destroyers")) {
1575                 strcpy(name, "Feindliche Zerst\x94rer");
1576         } else if (!stricmp(name, "Ross 128 System")) {
1577                 strcpy(name, "System Ross 128");
1578         } else if (!stricmp(name, "Knossos Station")) {
1579                 strcpy(name, "Knossos-Station");
1580         } else if (!stricmp(name, "Transporters")) {
1581                 strcpy(name, "Transporter");
1582         } else if (!stricmp(name, "Pirates?")) {
1583                 strcpy(name, "Piraten?");
1584         } else if (!stricmp(name, "Escorts")) {
1585                 strcpy(name, "Geleitschutz");
1586         } else if (!stricmp(name, "Shivan Fighters")) {
1587                 strcpy(name, "J\x84ger");
1588         } else if (!stricmp(name, "Shivan Territory")) {
1589                 strcpy(name, "Shivaner");
1590         }
1591 }
1592
1593 // ------------------------------------------------------------------
1594 // lcl_translate_brief_icon_name_pl()
1595 //
1596 // For displaying ship names in polish version
1597 // since we cant actually just change them outright.
1598 //
1599 void lcl_translate_brief_icon_name_pl(char *name)
1600 {
1601         char *pos;
1602         char buf[128];
1603
1604         if (!stricmp(name, "Subspace Portal")) {        
1605                 strcpy(name, "Portal podprz.");
1606
1607         } else if (!stricmp(name, "Alpha Wing")) {
1608                 strcpy(name, "Alfa");
1609
1610         } else if (!stricmp(name, "Beta Wing")) {
1611                 strcpy(name, "Beta");
1612
1613         } else if (!stricmp(name, "Zeta Wing")) {
1614                 strcpy(name, "Zeta");
1615
1616         } else if (!stricmp(name, "Capella Node")) {
1617                 strcpy(name, "Capella");
1618
1619         } else if (!stricmp(name, "Hostile")) {
1620                 strcpy(name, "Wr\xF3g");
1621
1622         } else if (!stricmp(name, "Hostile Craft")) {
1623                 strcpy(name, "Wr\xF3g");
1624
1625         } else if (!stricmp(name, "Rebel Wing")) {
1626                 strcpy(name, "Rebelianci");
1627
1628         } else if (!stricmp(name, "Rebel Fleet")) {
1629                 strcpy(name, "Flota Rebelii");
1630
1631         } else if (!stricmp(name, "Sentry Gun")) {
1632                 strcpy(name, "Dzia\xB3o str.");
1633
1634         } else if (!stricmp(name, "Cargo")) {
1635                 strcpy(name, "\xA3\x61\x64unek");
1636
1637         } else if (!stricmp(name, "Knossos Device")) {
1638                 strcpy(name, "Urz. Knossos");
1639         
1640         } else if (!stricmp(name, "Support")) {
1641                 strcpy(name, "Wsparcie");
1642
1643         } else if (!stricmp(name, "Unknown")) {
1644                 strcpy(name, "Nieznany");
1645
1646         } else if (!stricmp(name, "Instructor")) {
1647                 strcpy(name, "Instruktor");
1648         
1649         } else if (!stricmp(name, "Jump Node")) {
1650                 strcpy(name, "W\xEAze\xB3 skokowy");
1651
1652         } else if (!stricmp(name, "Escort")) {
1653                 strcpy(name, "Eskorta");
1654
1655         } else if (!stricmp(name, "Asteroid Field")) {
1656                 strcpy(name, "Pole asteroid");
1657
1658         } else if (!stricmp(name, "Enif Station")) {
1659                 strcpy(name, "Stacja Enif");
1660
1661         } else if (!stricmp(name, "Rally Point")) {
1662                 strcpy(name, "Pkt zborny");
1663
1664         } else if ((pos = strstr(name, "Transport")) != NULL) {
1665                 pos += 9;               // strlen of "transport"
1666                 strcpy(buf, "Transporter");
1667                 strcat(buf, pos);
1668                 strcpy(name, buf);
1669
1670         } else if ((pos = strstr(name, "Jump Node")) != NULL) {
1671                 pos += 9;               // strlen of "jump node"
1672                 strcpy(buf, "W\xEAze\xB3 skokowy");
1673                 strcat(buf, pos);
1674                 strcpy(name, buf);
1675         
1676         } else if (!stricmp(name, "Orion under repair")) {
1677                 strcpy(name, "Naprawiany Orion");
1678         }
1679 }
1680
1681 // ------------------------------------------------------------------
1682 // lcl_translate_ship_name()
1683 //
1684 // For displaying ship names in german version in the briefing
1685 // since we cant actually just change them outright.
1686 //
1687 void lcl_translate_ship_name(char *name)
1688 {
1689         if (!strcmp(name, "GTDR Amazon Advanced")) {    
1690                 strcpy(name, "GTDR Amazon VII");
1691         } 
1692 }
1693
1694 // ------------------------------------------------------------------
1695 // lcl_translate_targetbox_name()
1696 //
1697 // For displaying ship names in german version in the targetbox
1698 // since we cant actually just change them outright.
1699 //
1700 void lcl_translate_targetbox_name(char *name)
1701 {
1702         char *pos;
1703         char buf[128];
1704         
1705         if ((pos = strstr(name, "Sentry")) != NULL) {
1706                 pos += 6;               // strlen of "sentry"
1707                 strcpy(buf, "Sperrgesch\x81tz");
1708                 strcat(buf, pos);
1709                 strcpy(name, buf);
1710
1711         } else if ((pos = strstr(name, "Support")) != NULL) {
1712                 pos += 7;               // strlen of "support"
1713                 strcpy(buf, "Versorger");
1714                 strcat(buf, pos);
1715                 strcpy(name, buf);
1716
1717         } else if ((pos = strstr(name, "Unknown")) != NULL) {
1718                 pos += 7;               // strlen of "unknown"
1719                 strcpy(buf, "Unbekannt");
1720                 strcat(buf, pos);
1721                 strcpy(name, buf);
1722
1723         } else if ((pos = strstr(name, "Drone")) != NULL) {
1724                 pos += 5;               // strlen of "drone"
1725                 strcpy(buf, "Drohne");
1726                 strcat(buf, pos);
1727                 strcpy(name, buf);
1728
1729         } else if ((pos = strstr(name, "Jump Node")) != NULL) {
1730                 pos += 9;               // strlen of "jump node"
1731                 strcpy(buf, "Sprungknoten");
1732                 strcat(buf, pos);
1733                 strcpy(name, buf);
1734
1735         } else if (!stricmp(name, "Instructor")) {
1736                 strcpy(name, "Ausbilder");
1737
1738         } else if (!stricmp(name, "NTF Vessel")) {
1739                 strcpy(name, "NTF-Schiff");
1740
1741         } else if (!stricmp(name, "Enif Station")) {
1742                 strcpy(name, "Station Enif");
1743         }
1744 }
1745
1746 // ------------------------------------------------------------------
1747 // lcl_translate_targetbox_name_pl()
1748 //
1749 // For displaying ship names in polish version in the targetbox
1750 // since we cant actually just change them outright.
1751 //
1752 void lcl_translate_targetbox_name_pl(char *name)
1753 {
1754         char *pos;
1755         char buf[128];
1756         
1757         if ((pos = strstr(name, "Sentry")) != NULL) {
1758                 pos += 6;               // strlen of "sentry"
1759                 strcpy(buf, "Stra\xBFnik");
1760                 strcat(buf, pos);
1761                 strcpy(name, buf);
1762
1763         } else if ((pos = strstr(name, "Support")) != NULL) {
1764                 pos += 7;               // strlen of "support"
1765                 strcpy(buf, "Wsparcie");
1766                 strcat(buf, pos);
1767                 strcpy(name, buf);
1768
1769         } else if ((pos = strstr(name, "Unknown")) != NULL) {
1770                 pos += 7;               // strlen of "unknown"
1771                 strcpy(buf, "Nieznany");
1772                 strcat(buf, pos);
1773                 strcpy(name, buf);
1774
1775         } else if ((pos = strstr(name, "Drone")) != NULL) {
1776                 pos += 5;               // strlen of "drone"
1777                 strcpy(buf, "Sonda");
1778                 strcat(buf, pos);
1779                 strcpy(name, buf);
1780
1781         } else if ((pos = strstr(name, "Jump Node")) != NULL) {
1782                 pos += 9;               // strlen of "jump node"
1783                 strcpy(buf, "W\xEAze\xB3 skokowy");
1784                 strcat(buf, pos);
1785                 strcpy(name, buf);
1786
1787         } else if (!stricmp(name, "Instructor")) {
1788                 strcpy(name, "Instruktor");
1789
1790         } else if (!stricmp(name, "NTF Vessel")) {
1791                 strcpy(name, "Okr\xEAt NTF");
1792
1793         } else if (!stricmp(name, "Enif Station")) {
1794                 strcpy(name, "Stacja Enif");
1795         }
1796 }