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 |