Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 1 | pmbaty | 1 | /* | 
| 2 |  * Portions of this file are copyright Rebirth contributors and licensed as | ||
| 3 |  * described in COPYING.txt. | ||
| 4 |  * Portions of this file are copyright Parallax Software and licensed | ||
| 5 |  * according to the Parallax license below. | ||
| 6 |  * See COPYING.txt for license details. | ||
| 7 | |||
| 8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX | ||
| 9 | SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO | ||
| 10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A | ||
| 11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS | ||
| 12 | IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS | ||
| 13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE | ||
| 14 | FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE | ||
| 15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS | ||
| 16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. | ||
| 17 | COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED. | ||
| 18 | */ | ||
| 19 | |||
| 20 | /* | ||
| 21 |  * | ||
| 22 |  * Code for localizable text | ||
| 23 |  * | ||
| 24 |  */ | ||
| 25 | |||
| 26 | |||
| 27 | #include <stdlib.h> | ||
| 28 | #include <string.h> | ||
| 29 | |||
| 30 | #include "physfsx.h" | ||
| 31 | #include "pstypes.h" | ||
| 32 | #include "u_mem.h" | ||
| 33 | #include "dxxerror.h" | ||
| 34 | #include "inferno.h" | ||
| 35 | #include "text.h" | ||
| 36 | #include "strutil.h" | ||
| 37 | #include "args.h" | ||
| 38 | #include <memory> | ||
| 39 | |||
| 40 | #ifdef GENERATE_BUILTIN_TEXT_TABLE | ||
| 41 | #include <ctype.h> | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #if defined(DXX_BUILD_DESCENT_I) | ||
| 45 | #define IDX_TEXT_OVERWRITTEN    330 | ||
| 46 | #elif defined(DXX_BUILD_DESCENT_II) | ||
| 47 | #define IDX_TEXT_OVERWRITTEN    350 | ||
| 48 | #define SHAREWARE_TEXTSIZE  14677 | ||
| 49 | #endif | ||
| 50 | |||
| 51 | static std::unique_ptr<char[]> text; | ||
| 52 | static std::unique_ptr<char[]> overwritten_text; | ||
| 53 | |||
| 54 | // rotates a byte left one bit, preserving the bit falling off the right | ||
| 55 | static uint8_t encode_rotate_left(const uint8_t v) | ||
| 56 | { | ||
| 57 | return (v >> 7) | (v << 1); | ||
| 58 | } | ||
| 59 | |||
| 60 | constexpr std::integral_constant<uint8_t, 0xd3> BITMAP_TBL_XOR{}; | ||
| 61 | |||
| 62 | static uint8_t decode_char(const uint8_t c) | ||
| 63 | { | ||
| 64 | const auto c1 = encode_rotate_left(c); | ||
| 65 | const auto c2 = c1 ^ BITMAP_TBL_XOR; | ||
| 66 | return encode_rotate_left(c2); | ||
| 67 | } | ||
| 68 | |||
| 69 | //decode an encoded line of text of bitmaps.tbl | ||
| 70 | void decode_text_line(char *p) | ||
| 71 | { | ||
| 72 | for (; const char c = *p; p++) | ||
| 73 | *p = decode_char(c); | ||
| 74 | } | ||
| 75 | |||
| 76 | // decode buffer of text, preserves newlines | ||
| 77 | void decode_text(char *ptr, unsigned len) | ||
| 78 | { | ||
| 79 | for (; len--; ptr++) | ||
| 80 |         { | ||
| 81 | const char c = *ptr; | ||
| 82 | if (c != '\n') | ||
| 83 | *ptr = decode_char(c); | ||
| 84 |         } | ||
| 85 | } | ||
| 86 | |||
| 87 | //load all the text strings for Descent | ||
| 88 | namespace dsx { | ||
| 89 | |||
| 90 | #ifdef USE_BUILTIN_ENGLISH_TEXT_STRINGS | ||
| 91 | static | ||
| 92 | #endif | ||
| 93 | std::array<const char *, N_TEXT_STRINGS> Text_string; | ||
| 94 | |||
| 95 | void load_text() | ||
| 96 | { | ||
| 97 | int len,i, have_binary = 0; | ||
| 98 | char *tptr; | ||
| 99 | const char *filename="descent.tex"; | ||
| 100 | #if defined(DXX_BUILD_DESCENT_I) | ||
| 101 | static const char *const extra_strings[] = { | ||
| 102 |                 "done", | ||
| 103 |                 "I am a", | ||
| 104 |                 "CHEATER!", | ||
| 105 |                 "Loading Data", | ||
| 106 |                 "ALT-F2\t  Save Game", | ||
| 107 |                 "ALT-F3\t  Load Game", | ||
| 108 |                 "Only in Registered version!", | ||
| 109 |                 "Concussion", | ||
| 110 |                 "Homing", | ||
| 111 |                 "ProxBomb", | ||
| 112 |                 "Smart", | ||
| 113 |                 "Mega", | ||
| 114 |                 "Mission '%s' not found.\nYou must have this mission\nfile in order to playback\nthis demo.", | ||
| 115 |                 "All player callsigns on screen", | ||
| 116 |                 "There is already a game\nin progress with that name", | ||
| 117 |                 "This mission is designated\nAnarchy-only", | ||
| 118 |                 "Force level start", | ||
| 119 |                 "Quitting now means ending the\nentire netgame\n\nAre you sure?", | ||
| 120 |                 "The mission for that netgame\nis not installed on your\nsystem.  Cannot join.", | ||
| 121 |                 "Start Multiplayer Game\n\nSelect mission", | ||
| 122 |                 "Error loading mission file", | ||
| 123 |                 "Custom (return to set)", | ||
| 124 |                 "Base address (in Hex)", | ||
| 125 |                 "IRQ Number", | ||
| 126 |                 "Reset to Default", | ||
| 127 |                 "Valid IRQ values are 2-7", | ||
| 128 |                 "No UART was detected\nat those settings", | ||
| 129 |                 "You will pay dearly for that!", | ||
| 130 |                 "Revenge is mine!!", | ||
| 131 |                 "Man I'm good!", | ||
| 132 |                 "Its almost too easy!", | ||
| 133 |                 "   Mission:", | ||
| 134 |                 "+/- Changes viewing distance", | ||
| 135 |                 "Alternate exit found!\n\nProceeding to Secret Level!", | ||
| 136 |                 "Show all players on automap", | ||
| 137 |                 "Killed by a robot", | ||
| 138 |                 "Baud", | ||
| 139 |                 "A consistency error has been\ndetected in your network connection.\nCheck you hardware and re-join", | ||
| 140 |                 "Press any key to continue (Print Screen to save screenshot)", | ||
| 141 |                 "An error occured while writing\ndemo.  Demo is likely corrupted.\nEnter demo name now or\npress ESC to delete demo.", | ||
| 142 |                 "The main reactor is invulnerable for", | ||
| 143 |                 "The level being loaded is not\navailable in Destination Saturn.\nUnable to continue demo playback.\n\nPress any key to continue.", | ||
| 144 |                 "Reactor life", | ||
| 145 |                 "min", | ||
| 146 |                 "Current IPX Socket is default", | ||
| 147 |                 "This program requires MS-DOS 5.0 or higher.\nYou are using MS-DOS", | ||
| 148 |                 "You can use the -nodoscheck command line\nswitch to override this check, but it\nmay have unpredictable results, namely\nwith DOS file error handling.\n", | ||
| 149 |                 "Not enough file handles!", | ||
| 150 |                 "of the necessary file handles\nthat Descent requires to execute properly.  You will\nneed to increase the FILES=n line in your config.sys.", | ||
| 151 |                 "If you are running with a clean boot, then you will need\nto create a CONFIG.SYS file in your root directory, with\nthe line FILES=15 in it.  If you need help with this,\ncontact Interplay technical support.", | ||
| 152 |                 "You may also run with the -nofilecheck command line option\nthat will disable this check, but you might get errors\nwhen loading saved games or playing demos.", | ||
| 153 |                 "Available memory", | ||
| 154 |                 "more bytes of DOS memory needed!", | ||
| 155 |                 "more bytes of virtual memory needed.  Reconfigure VMM.", | ||
| 156 |                 "more bytes of extended/expanded memory needed!", | ||
| 157 |                 "Or else you you need to use virtual memory (See README.TXT)", | ||
| 158 |                 "more bytes of physical memory needed!", | ||
| 159 |                 "Check to see that your virtual memory settings allow\nyou to use all of your physical memory (See README.TXT)", | ||
| 160 |                 "Initializing DPMI services", | ||
| 161 |                 "Initializing critical error handler", | ||
| 162 |                 "Enables Virtual I/O Iglasses! stereo display", | ||
| 163 |                 "Enables Iglasses! head tracking via COM port", | ||
| 164 |                 "Enables Kasan's 3dMax stereo display in low res.", | ||
| 165 |                 "3DBios must be installed for 3dMax operation.", | ||
| 166 |                 "Enables Kasan's 3dMax stereo display in high res", | ||
| 167 |                 "Press any key for more options...", | ||
| 168 |                 "Enables dynamic socket changing", | ||
| 169 |                 "Disables the file handles check", | ||
| 170 |                 "Getting settings from DESCENT.CFG...", | ||
| 171 |                 "Initializing timer system...", | ||
| 172 |                 "Initializing keyboard handler...", | ||
| 173 |                 "Initializing mouse handler...", | ||
| 174 |                 "Mouse support disabled...", | ||
| 175 |                 "Initializing joystick handler...", | ||
| 176 |                 "Slow joystick reading enabled...", | ||
| 177 |                 "Polled joystick reading enabled...", | ||
| 178 |                 "BIOS joystick reading enabled...", | ||
| 179 |                 "Joystick support disabled...", | ||
| 180 |                 "Initializing divide by zero handler...", | ||
| 181 |                 "Initializing network...", | ||
| 182 |                 "Using IPX network support on channel", | ||
| 183 |                 "No IPX compatible network found.", | ||
| 184 |                 "Error opening socket", | ||
| 185 |                 "Not enough low memory for IPX buffers.", | ||
| 186 |                 "Error initializing IPX.  Error code:", | ||
| 187 |                 "Network support disabled...", | ||
| 188 |                 "Initializing graphics system...", | ||
| 189 |                 "SOUND: Error opening", | ||
| 190 |                 "SOUND: Error locking down instruments", | ||
| 191 |                 "SOUND: (HMI)", | ||
| 192 |                 "SOUND: Error locking down drums", | ||
| 193 |                 "SOUND: Error locking midi track map!", | ||
| 194 |                 "SOUND: Error locking midi callback function!", | ||
| 195 |                 "Using external control:", | ||
| 196 |                 "Invalid serial port parameter for -itrak!", | ||
| 197 |                 "Initializing i-glasses! head tracking on serial port %d", | ||
| 198 |                 "Make sure the glasses are turned on!", | ||
| 199 |                 "Press ESC to abort", | ||
| 200 |                 "Failed to open serial port.  Status =", | ||
| 201 |                 "Message", | ||
| 202 |                 "Macro", | ||
| 203 |                 "Error locking serial interrupt routine!", | ||
| 204 |                 "Error locking serial port data!", | ||
| 205 |                 "Robots are normal", | ||
| 206 |                 "Robots move fast, fire seldom", | ||
| 207 |                 "Robot painting OFF", | ||
| 208 |                 "Robot painting with texture %d" | ||
| 209 | }; | ||
| 210 | #endif | ||
| 211 | |||
| 212 | if (!CGameArg.DbgAltTex.empty()) | ||
| 213 | filename = CGameArg.DbgAltTex.c_str(); | ||
| 214 | |||
| 215 | auto tfile = PHYSFSX_openReadBuffered(filename); | ||
| 216 | if (!tfile) | ||
| 217 |         { | ||
| 218 | filename="descent.txb"; | ||
| 219 | auto ifile = PHYSFSX_openReadBuffered(filename); | ||
| 220 | if (!ifile) | ||
| 221 |                 { | ||
| 222 | Error("Cannot open file DESCENT.TEX or DESCENT.TXB"); | ||
| 223 | return; | ||
| 224 |                 } | ||
| 225 | have_binary = 1; | ||
| 226 | |||
| 227 | len = PHYSFS_fileLength(ifile); | ||
| 228 | |||
| 229 | //edited 05/17/99 Matt Mueller - malloc an extra byte, and null terminate. | ||
| 230 | text = std::make_unique<char[]>(len + 1); | ||
| 231 | PHYSFS_read(ifile,text,1,len); | ||
| 232 | text[len]=0; | ||
| 233 | //end edit -MM | ||
| 234 | } else { | ||
| 235 | int c; | ||
| 236 | char * p; | ||
| 237 | |||
| 238 | len = PHYSFS_fileLength(tfile); | ||
| 239 | |||
| 240 | //edited 05/17/99 Matt Mueller - malloc an extra byte, and null terminate. | ||
| 241 | text = std::make_unique<char[]>(len + 1); | ||
| 242 |                 //fread(text,1,len,tfile); | ||
| 243 | p = text.get(); | ||
| 244 | do { | ||
| 245 | c = PHYSFSX_fgetc( tfile ); | ||
| 246 | if ( c != 13 ) | ||
| 247 | *p++ = c; | ||
| 248 | } while ( c!=EOF ); | ||
| 249 | *p=0; | ||
| 250 | //end edit -MM | ||
| 251 |         } | ||
| 252 | |||
| 253 | for (i=0,tptr=text.get();i<N_TEXT_STRINGS;i++) { | ||
| 254 | char *p; | ||
| 255 | |||
| 256 | #if defined(DXX_BUILD_DESCENT_I) | ||
| 257 | if (!tptr && i >= N_TEXT_STRINGS_MIN) // account for non-registered 1.4/1.5 text files | ||
| 258 |                 { | ||
| 259 | Text_string[i-1] = extra_strings[i - N_TEXT_STRINGS_MIN - 1]; | ||
| 260 | Text_string[i] = extra_strings[i - N_TEXT_STRINGS_MIN]; | ||
| 261 | continue; | ||
| 262 |                 } | ||
| 263 | else if (!tptr && i < N_TEXT_STRINGS_MIN) | ||
| 264 |                 { | ||
| 265 | Error("Not enough strings in text file - expecting %d (or at least %d), found %d",N_TEXT_STRINGS,N_TEXT_STRINGS_MIN,i); | ||
| 266 |                 } | ||
| 267 | #endif | ||
| 268 | Text_string[i] = tptr; | ||
| 269 | char *ts = tptr; | ||
| 270 | |||
| 271 | tptr = strchr(tptr,'\n'); | ||
| 272 | |||
| 273 | #if defined(DXX_BUILD_DESCENT_II) | ||
| 274 | if (!tptr) | ||
| 275 |                 { | ||
| 276 | if (i == 644) break; /* older datafiles */ | ||
| 277 | |||
| 278 | Error("Not enough strings in text file - expecting %d, found %d\n", N_TEXT_STRINGS, i); | ||
| 279 |                 } | ||
| 280 | #endif | ||
| 281 | if ( tptr ) *tptr++ = 0; | ||
| 282 | |||
| 283 | if (have_binary) | ||
| 284 | decode_text_line(ts); | ||
| 285 | |||
| 286 |                 //scan for special chars (like \n) | ||
| 287 | if ((p = strchr(ts, '\\')) != NULL) { | ||
| 288 | for (char *q = p; assert(*p == '\\'), *p;) { | ||
| 289 | char newchar; | ||
| 290 | |||
| 291 | if (p[1] == 'n') newchar = '\n'; | ||
| 292 | else if (p[1] == 't') newchar = '\t'; | ||
| 293 | else if (p[1] == '\\') newchar = '\\'; | ||
| 294 |                         else | ||
| 295 | Error("Unsupported key sequence <\\%c> on line %d of file <%s>",p[1],i+1,filename); | ||
| 296 | |||
| 297 | *q++ = newchar; | ||
| 298 | p += 2; | ||
| 299 | char *r = strchr(p, '\\'); | ||
| 300 | if (!r) | ||
| 301 |                                 { | ||
| 302 | r = tptr; | ||
| 303 | assert(!r[-1]); | ||
| 304 | assert(r == 1 + p + strlen(p)); | ||
| 305 | memmove(q, p, r - p); | ||
| 306 | break; | ||
| 307 |                                 } | ||
| 308 | memmove(q, p, r - p); | ||
| 309 | q += (r - p); | ||
| 310 | p = r; | ||
| 311 |                         } | ||
| 312 |                 } | ||
| 313 | |||
| 314 | switch(i) { | ||
| 315 | #if defined(DXX_BUILD_DESCENT_I) | ||
| 316 | case 116: | ||
| 317 | if (!d_stricmp(ts, "SPREADFIRE")) // This string is too long to fit in the cockpit-box | ||
| 318 |                                 { | ||
| 319 | ts[6] = 0; | ||
| 320 |                                 } | ||
| 321 | break; | ||
| 322 | #endif | ||
| 323 | |||
| 324 | case IDX_TEXT_OVERWRITTEN: | ||
| 325 |                                 { | ||
| 326 | static const char extra[] = "\n<Ctrl-C> converts format\nIntel <-> PowerPC"; | ||
| 327 | std::size_t l = strlen(ts); | ||
| 328 | overwritten_text = std::make_unique<char[]>(l + sizeof(extra)); | ||
| 329 | char *o = overwritten_text.get(); | ||
| 330 | std::copy_n(extra, sizeof(extra), std::copy_n(ts, l, o)); | ||
| 331 | Text_string[i] = o; | ||
| 332 | break; | ||
| 333 |                                 } | ||
| 334 |           } | ||
| 335 | |||
| 336 |         } | ||
| 337 | |||
| 338 | #if defined(DXX_BUILD_DESCENT_II) | ||
| 339 | if (i == 644) | ||
| 340 |         { | ||
| 341 | if (len == SHAREWARE_TEXTSIZE) | ||
| 342 |                 { | ||
| 343 | Text_string[173] = Text_string[172]; | ||
| 344 | Text_string[172] = Text_string[171]; | ||
| 345 | Text_string[171] = Text_string[170]; | ||
| 346 | Text_string[170] = Text_string[169]; | ||
| 347 | Text_string[169] = "Windows Joystick"; | ||
| 348 |                 } | ||
| 349 | |||
| 350 | Text_string[644] = "Z1"; | ||
| 351 | Text_string[645] = "UN"; | ||
| 352 | Text_string[646] = "P1"; | ||
| 353 | Text_string[647] = "R1"; | ||
| 354 | Text_string[648] = "Y1"; | ||
| 355 |         } | ||
| 356 | #endif | ||
| 357 | |||
| 358 | #ifdef GENERATE_BUILTIN_TEXT_TABLE | ||
| 359 | for (unsigned u = 0; u < std::size(Text_string); ++u) | ||
| 360 |         { | ||
| 361 | printf("\t%u\t\"", u); | ||
| 362 | for (char *px = Text_string[u]; *px; ++px) { | ||
| 363 | unsigned x = (unsigned)*px; | ||
| 364 | if (isprint(x)) | ||
| 365 | putchar(x); | ||
| 366 | else if (x == '\t') | ||
| 367 | printf("\\t"); | ||
| 368 | else if (x == '\r') | ||
| 369 | printf("\\r"); | ||
| 370 | else if (x == '\n') | ||
| 371 | printf("\\n"); | ||
| 372 |                         else | ||
| 373 | printf("\\x%.2x", x); | ||
| 374 |                 } | ||
| 375 | printf("\"\n"); | ||
| 376 |         }       | ||
| 377 | #endif | ||
| 378 | |||
| 379 |         //Assert(tptr==text+len || tptr==text+len-2); | ||
| 380 | |||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 |