| //------------------------------------------------------------------------- |
| /* |
| Copyright (C) 1996, 2003 - 3D Realms Entertainment |
| |
| This file is part of Duke Nukem 3D version 1.5 - Atomic Edition |
| |
| Duke Nukem 3D is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| |
| See the GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| aint32_t with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| |
| Original Source: 1996 - Todd Replogle |
| Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms |
| */ |
| //------------------------------------------------------------------------- |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <errno.h> |
| #include "global.h" |
| #include "duke3d.h" |
| |
| char *mymembuf; |
| uint8_t MusicPtr[72000]; |
| |
| |
| crc32_t crc32lookup[] = { |
| // good: |
| { CRC_BASE_GRP_SHAREWARE_13, "SHAREWARE 1.3D", 11035779 }, |
| { CRC_BASE_GRP_FULL_13, "FULL 1.3D ", 26524524 }, |
| { CRC_BASE_GRP_PLUTONIUM_14, "PLUTONIUM 1.4 ", 44348015 }, |
| { CRC_BASE_GRP_ATOMIC_15, "ATOMIC 1.5 ", 44356548 }, |
| // unknown: |
| { 0, "HACK/UNKNOWN ", 0} |
| }; |
| |
| uint8_t conVersion = 13; |
| uint8_t grpVersion = 0; |
| |
| // FIX_00015: Backward compliance with older demos (down to demos v27, 28, 116 and 117 only) |
| |
| // For BYTEVERSION diff, 27/116 vs 28/117 see extras\duke3d.h vs source\duke3d.h |
| // from the official source code release. |
| |
| int BYTEVERSION_27 = 27; // 1.3 under 1.4 Plutonium. Not supported anymore |
| int BYTEVERSION_116 = 116; // 1.4 Plutonium. Not supported anymore |
| |
| int BYTEVERSION_28 = 28; // 1.3 under 1.5 engine |
| int BYTEVERSION_117 = 117; // 1.5 Atomic |
| |
| int BYTEVERSION_29 = 29; // 1.3 under xDuke v19.6. |
| int BYTEVERSION_118 = 118; // 1.5 Atomic under xDuke v19.6. |
| |
| int BYTEVERSION_1_3 = 1; // for 1.3 demos (Not compatible) |
| |
| int BYTEVERSION = 119; // xDuke v19.7 |
| |
| short global_random; |
| short neartagsector, neartagwall, neartagsprite; |
| |
| int32_t gc,neartaghitdist,lockclock,max_player_health,max_armour_amount,max_ammo_amount[MAX_WEAPONS]; |
| |
| // int32_t temp_data[MAXSPRITES][6]; |
| struct weaponhit hittype[MAXSPRITES]; |
| short spriteq[1024],spriteqloc,spriteqamount=64; |
| |
| struct animwalltype animwall[MAXANIMWALLS]; |
| short numanimwalls; |
| int32_t *animateptr[MAXANIMATES], animategoal[MAXANIMATES], animatevel[MAXANIMATES], animatecnt; |
| // int32_t oanimateval[MAXANIMATES]; |
| short animatesect[MAXANIMATES]; |
| int32_t msx[2048],msy[2048]; |
| short cyclers[MAXCYCLERS][6],numcyclers; |
| |
| char fta_quotes[NUMOFFIRSTTIMEACTIVE][64]; |
| |
| uint8_t tempbuf[2048]; |
| uint8_t packbuf[576]; |
| |
| char buf[80]; |
| |
| short camsprite; |
| short mirrorwall[64], mirrorsector[64], mirrorcnt; |
| |
| int current_menu; |
| |
| uint8_t betaname[80]; |
| |
| char level_names[44][33]; |
| char level_file_names[44][128]; |
| int32_t partime[44],designertime[44]; |
| char volume_names[4][33] = { "L.A. MELTDOWN", "LUNAR APOCALYPSE", "SHRAPNEL CITY", "" }; // Names are not in 1.3 con files. MUST be in code. |
| char skill_names[5][33] = { "PIECE OF CAKE", "LET'S ROCK", "COME GET SOME", "DAMN I'M GOOD", "" }; |
| |
| volatile int32_t checksume; |
| int32_t soundsiz[NUM_SOUNDS]; |
| |
| short soundps[NUM_SOUNDS],soundpe[NUM_SOUNDS],soundvo[NUM_SOUNDS]; |
| uint8_t soundm[NUM_SOUNDS],soundpr[NUM_SOUNDS]; |
| char sounds[NUM_SOUNDS][14]; |
| |
| short title_zoom; |
| |
| fx_device device; |
| |
| SAMPLE Sound[ NUM_SOUNDS ]; |
| SOUNDOWNER SoundOwner[NUM_SOUNDS][4]; |
| |
| uint8_t numplayersprites,earthquaketime; |
| |
| int32_t fricxv,fricyv; |
| struct player_orig po[MAXPLAYERS]; |
| struct player_struct ps[MAXPLAYERS]; |
| struct user_defs ud; |
| |
| uint8_t pus, pub; |
| uint8_t syncstat, syncval[MAXPLAYERS][MOVEFIFOSIZ]; |
| int32_t syncvalhead[MAXPLAYERS], syncvaltail, syncvaltottail; |
| |
| input sync[MAXPLAYERS], loc; |
| input recsync[RECSYNCBUFSIZ]; |
| int32_t avgfvel, avgsvel, avgavel, avghorz, avgbits; |
| |
| |
| input inputfifo[MOVEFIFOSIZ][MAXPLAYERS]; |
| input recsync[RECSYNCBUFSIZ]; |
| |
| int32_t movefifosendplc; |
| |
| //Multiplayer syncing variables |
| short screenpeek; |
| int32_t movefifoend[MAXPLAYERS]; |
| |
| |
| //Game recording variables |
| |
| uint8_t playerreadyflag[MAXPLAYERS],ready2send; |
| uint8_t playerquitflag[MAXPLAYERS]; |
| int32_t vel, svel, angvel, horiz, ototalclock, respawnactortime=768, respawnitemtime=768, groupfile; |
| |
| int32_t script[MAXSCRIPTSIZE],*scriptptr,*insptr,*labelcode,labelcnt; |
| int32_t *actorscrptr[MAXTILES],*parsing_actor; |
| char *label,*textptr,error,warning ; |
| uint8_t killit_flag; |
| uint8_t *music_pointer; |
| uint8_t actortype[MAXTILES]; |
| |
| |
| uint8_t display_mirror,typebuflen; |
| char typebuf[41]; |
| |
| char music_fn[4][11][13]; |
| uint8_t music_select; |
| char env_music_fn[4][13]; |
| uint8_t rtsplaying; |
| |
| |
| short weaponsandammosprites[15] = { |
| RPGSPRITE, |
| CHAINGUNSPRITE, |
| DEVISTATORAMMO, |
| RPGAMMO, |
| RPGAMMO, |
| JETPACK, |
| SHIELD, |
| FIRSTAID, |
| STEROIDS, |
| RPGAMMO, |
| RPGAMMO, |
| RPGSPRITE, |
| RPGAMMO, |
| FREEZESPRITE, |
| FREEZEAMMO |
| }; |
| |
| int32_t impact_damage; |
| |
| //GLOBAL.C - replace the end "my's" with this |
| int32_t myx, omyx, myxvel, myy, omyy, myyvel, myz, omyz, myzvel; |
| short myhoriz, omyhoriz, myhorizoff, omyhorizoff; |
| short myang, omyang, mycursectnum, myjumpingcounter,frags[MAXPLAYERS][MAXPLAYERS]; |
| |
| uint8_t myjumpingtoggle, myonground, myhardlanding, myreturntocenter; |
| int8_t multiwho, multipos, multiwhat, multiflag; |
| |
| int32_t fakemovefifoplc,movefifoplc; |
| int32_t myxbak[MOVEFIFOSIZ], myybak[MOVEFIFOSIZ], myzbak[MOVEFIFOSIZ]; |
| int32_t myhorizbak[MOVEFIFOSIZ],dukefriction = 0xcc00, show_shareware; |
| |
| short myangbak[MOVEFIFOSIZ]; |
| char myname[2048] = "XDUKE"; |
| uint8_t camerashitable,freezerhurtowner=0,lasermode; |
| // CTW - MODIFICATION |
| // uint8_t networkmode = 255, movesperpacket = 1,gamequit = 0,playonten = 0,everyothertime; |
| uint8_t networkmode = 255, movesperpacket = 1,gamequit = 0,everyothertime; |
| // CTW END - MODIFICATION |
| int32_t numfreezebounces=3,rpgblastradius,pipebombblastradius,tripbombblastradius,shrinkerblastradius,morterblastradius,bouncemineblastradius,seenineblastradius; |
| STATUSBARTYPE sbar; |
| |
| int32_t myminlag[MAXPLAYERS], mymaxlag, otherminlag, bufferjitter = 1; |
| short numclouds,clouds[128],cloudx[128],cloudy[128]; |
| int32_t cloudtotalclock = 0,totalmemory = 0; |
| int32_t numinterpolations = 0, startofdynamicinterpolations = 0; |
| int32_t oldipos[MAXINTERPOLATIONS]; |
| int32_t bakipos[MAXINTERPOLATIONS]; |
| int32_t *curipos[MAXINTERPOLATIONS]; |
| |
| |
| // portability stuff. --ryan. |
| // A good portion of this was ripped from GPL'd Rise of the Triad. --ryan. |
| |
| #ifndef PATH_SEP_CHAR |
| #define PATH_SEP_CHAR '/' |
| #endif |
| |
| void FixFilePath(char *filename) |
| { |
| uint8_t *ptr; |
| uint8_t *lastsep = filename; |
| |
| if ((!filename) || (*filename == '\0')) |
| return; |
| if(filename[0] != '/') |
| LOGF("%s is not absolute", filename); |
| |
| if (rb->file_exists(filename)) /* File exists; we're good to go. */ |
| return; |
| |
| for (ptr = filename; 1; ptr++) |
| { |
| if (*ptr == '\\') |
| *ptr = PATH_SEP_CHAR; |
| |
| if ((*ptr == PATH_SEP_CHAR) || (*ptr == '\0')) |
| { |
| uint8_t pch = *ptr; |
| struct dirent *dent = NULL; |
| DIR *dir; |
| |
| if ((pch == PATH_SEP_CHAR) && (*(ptr + 1) == '\0')) |
| return; /* eos is pathsep; we're done. */ |
| |
| if (lastsep == ptr) |
| continue; /* absolute path; skip to next one. */ |
| |
| *ptr = '\0'; |
| if (lastsep == filename) { |
| dir = opendir((*lastsep == PATH_SEP_CHAR) ? "/" : "/"); |
| |
| if (*lastsep == PATH_SEP_CHAR) { |
| lastsep++; |
| } |
| } |
| else |
| { |
| *lastsep = '\0'; |
| dir = opendir(filename); |
| *lastsep = PATH_SEP_CHAR; |
| lastsep++; |
| } |
| |
| if (dir == NULL) |
| { |
| *ptr = PATH_SEP_CHAR; |
| return; /* maybe dir doesn't exist? give up. */ |
| } |
| |
| while ((dent = readdir(dir)) != NULL) |
| { |
| if (strcasecmp(dent->d_name, lastsep) == 0) |
| { |
| /* found match; replace it. */ |
| strcpy(lastsep, dent->d_name); |
| break; |
| } |
| } |
| |
| closedir(dir); |
| *ptr = pch; |
| lastsep = ptr; |
| |
| if (dent == NULL) |
| return; /* no match. oh well. */ |
| |
| if (pch == '\0') /* eos? */ |
| return; |
| } |
| } |
| } |
| |
| static int check_pattern_nocase(const char *x, const char *y) |
| { |
| if ((x == NULL) || (y == NULL)) |
| return(0); /* not a match. */ |
| |
| while ((*x) && (*y)) |
| { |
| if (*x == '*') |
| { |
| x++; |
| while (*y != '\0') |
| { |
| if (toupper((int) *x) == toupper((int) *y)) |
| break; |
| y++; |
| } |
| } |
| |
| else if (*x == '?') |
| { |
| if (*y == '\0') |
| return(0); /* anything but EOS is okay. */ |
| } |
| |
| else |
| { |
| if (toupper((int) *x) != toupper((int) *y)) |
| return(0); /* not a match. */ |
| } |
| |
| x++; |
| y++; |
| } |
| |
| return(*x == *y); /* it's a match (both should be EOS). */ |
| } |
| |
| int FindDistance2D(int ix, int iy) |
| { |
| int t; |
| |
| ix= abs(ix); /* absolute values */ |
| iy= abs(iy); |
| |
| if (ix<iy) |
| { |
| int tmp = ix; |
| ix = iy; |
| iy = tmp; |
| } |
| |
| t = iy + (iy>>1); |
| |
| return (ix - (ix>>5) - (ix>>7) + (t>>2) + (t>>6)); |
| } |
| |
| int FindDistance3D(int ix, int iy, int iz) |
| { |
| int t; |
| |
| ix= abs(ix); /* absolute values */ |
| iy= abs(iy); |
| iz= abs(iz); |
| |
| if (ix<iy) |
| { |
| int tmp = ix; |
| ix = iy; |
| iy = tmp; |
| } |
| |
| if (ix<iz) |
| { |
| int tmp = ix; |
| ix = iz; |
| iz = tmp; |
| } |
| |
| t = iy + iz; |
| |
| return (ix - (ix>>4) + (t>>2) + (t>>3)); |
| } |
| #include "SDL.h" |
| void Error (int errorType, char *error, ...) |
| { |
| va_list argptr; |
| |
| SDL_Quit(); |
| |
| //FCS: http://duke3d.m-klein.com is obscolete :/ ! |
| /* |
| if(errorType==EXIT_FAILURE) |
| printf("ERROR: Please copy that screen and visit http://duke3d.m-klein.com for report:\n"); |
| else |
| printf("http://duke3d.m-klein.com\n"); |
| */ |
| |
| |
| va_start (argptr, error); |
| vprintf(error, argptr); |
| va_end (argptr); |
| |
| //printf("Press any key to continue...\n"); |
| |
| // FIX_00043: Nicer exit on error. Ask the user to hit a key on exits and error exits. |
| //getch(); |
| |
| exit (errorType); |
| } |
| |
| void write2disk(int line, char * cfilename, char *filename2write, char *message) |
| { |
| // usage: write2disk(__LINE__, __FILE__, "c:\temp\my_dbug_file.txt", uint8_t * msg); |
| |
| int i, k=0; |
| char filename[2048]; |
| FILE *pFile; |
| |
| for(i=0; cfilename[i]; i++) |
| { |
| if(cfilename[i]=='\\') |
| { |
| i++; |
| k = 0; |
| } |
| filename[k++]=(cfilename[i]=='.')?0:cfilename[i]; |
| } |
| pFile = fopen(filename2write,"a"); |
| fprintf(pFile,"%-4d %-5s %s", line, filename, message); |
| fclose(pFile); |
| } |
| |
| int32 SafeOpenAppend (const char *_filename, int32 filetype) |
| { |
| int handle; |
| char filename[MAX_PATH]; |
| |
| strncpy(filename, _filename, sizeof (filename)); |
| filename[sizeof (filename) - 1] = '\0'; |
| FixFilePath(filename); |
| |
| handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_APPEND , 0666); |
| |
| if (handle == -1) |
| Error (EXIT_FAILURE, "Error opening for append %s: %s",filename,strerror(errno)); |
| |
| return handle; |
| } |
| |
| boolean SafeFileExists ( const char * _filename ) |
| { |
| char filename[MAX_PATH]; |
| strncpy(filename, _filename, sizeof (filename)); |
| filename[sizeof (filename) - 1] = '\0'; |
| FixFilePath(filename); |
| |
| return(rb->file_exists(filename)); |
| } |
| |
| |
| int32 SafeOpenWrite (const char *_filename, int32 filetype) |
| { |
| int handle; |
| char filename[MAX_PATH]; |
| strncpy(filename, _filename, sizeof (filename)); |
| filename[sizeof (filename) - 1] = '\0'; |
| FixFilePath(filename); |
| |
| handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_TRUNC |
| , 0666); |
| |
| if (handle == -1) |
| Error (EXIT_FAILURE, "Error opening %s: %s",filename,strerror(errno)); |
| |
| return handle; |
| } |
| |
| |
| |
| |
| int32 SafeOpenRead (const char *_filename, int32 filetype) |
| { |
| int handle; |
| char filename[MAX_PATH]; |
| strncpy(filename, _filename, sizeof (filename)); |
| filename[sizeof (filename) - 1] = '\0'; |
| FixFilePath(filename); |
| |
| handle = open(filename,O_RDONLY | O_BINARY); |
| |
| if (handle == -1) |
| Error (EXIT_FAILURE, "Error opening %s: %s",filename,strerror(errno)); |
| |
| return handle; |
| } |
| |
| |
| void SafeRead (int32 handle, void *buffer, int32 count) |
| { |
| unsigned iocount; |
| |
| while (count) |
| { |
| iocount = count > 0x8000 ? 0x8000 : count; |
| if (read (handle,buffer,iocount) != (int)iocount) |
| Error (EXIT_FAILURE, "File read failure reading %ld bytes",count); |
| buffer = (void *)( (byte *)buffer + iocount ); |
| count -= iocount; |
| } |
| } |
| |
| |
| void SafeWrite (int32 handle, void *buffer, int32 count) |
| { |
| unsigned iocount; |
| |
| while (count) |
| { |
| iocount = count > 0x8000 ? 0x8000 : count; |
| if (write (handle,buffer,iocount) != (int)iocount) |
| Error (EXIT_FAILURE, "File write failure writing %ld bytes",count); |
| buffer = (void *)( (byte *)buffer + iocount ); |
| count -= iocount; |
| } |
| } |
| |
| void SafeWriteString (int handle, char * buffer) |
| { |
| unsigned iocount; |
| |
| iocount=strlen(buffer); |
| if (write (handle,buffer,iocount) != (int)iocount) |
| Error (EXIT_FAILURE, "File write string failure writing %s\n",buffer); |
| } |
| |
| void *SafeMalloc (int32_t size) |
| { |
| void *ptr; |
| |
| ptr = malloc(size); |
| |
| if (!ptr) |
| Error (EXIT_FAILURE, "SafeMalloc failure for %lu bytes",size); |
| |
| return ptr; |
| } |
| |
| void SafeRealloc (void **x, int32 size) |
| { |
| void *ptr; |
| |
| ptr = realloc(*x, size); |
| |
| if (!ptr) |
| Error (EXIT_FAILURE, "SafeRealloc failure for %lu bytes",size); |
| |
| *x = ptr; |
| } |
| |
| void *SafeLevelMalloc (int32_t size) |
| { |
| void *ptr; |
| |
| ptr = malloc(size); |
| |
| if (!ptr) |
| Error (EXIT_FAILURE, "SafeLevelMalloc failure for %lu bytes",size); |
| |
| return ptr; |
| } |
| |
| void SafeFree (void * ptr) |
| { |
| if ( ptr == NULL ) |
| Error (EXIT_FAILURE, "SafeFree : Tried to free a freed pointer\n"); |
| |
| free(ptr); |
| |
| } |
| |
| short SwapShort (short l) |
| { |
| byte b1,b2; |
| |
| b1 = l&255; |
| b2 = (l>>8)&255; |
| |
| return (b1<<8) + b2; |
| } |
| |
| short KeepShort (short l) |
| { |
| return l; |
| } |
| |
| |
| int32_t Swapint32_t (int32_t l) |
| { |
| byte b1,b2,b3,b4; |
| |
| b1 = l&255; |
| b2 = (l>>8)&255; |
| b3 = (l>>16)&255; |
| b4 = (l>>24)&255; |
| |
| return ((int32_t)b1<<24) + ((int32_t)b2<<16) + ((int32_t)b3<<8) + b4; |
| } |
| |
| int32_t Keepint32_t (int32_t l) |
| { |
| return l; |
| } |
| |
| |
| #undef KeepShort |
| #undef KeepLong |
| #undef SwapShort |
| #undef SwapLong |
| |
| void SwapIntelLong(int32_t *l) |
| { |
| *l = IntelLong(*l); |
| } |
| |
| void SwapIntelShort(short *s) |
| { |
| *s = IntelShort(*s); |
| } |
| |
| void SwapIntelLongArray(int32_t *l, int num) |
| { |
| while (num--) { |
| SwapIntelLong(l); |
| l++; |
| } |
| } |
| |
| void SwapIntelShortArray(short *s, int num) |
| { |
| while (num--) { |
| SwapIntelShort(s); |
| s++; |
| } |
| } |
| |
| |
| /* |
| Copied over from Wolf3D Linux: http://www.icculus.org/wolf3d/ |
| Modified for ROTT. |
| Stolen for Duke3D, too. |
| */ |
| |
| uint8_t *strlwr(uint8_t *s) |
| { |
| uint8_t *p = s; |
| |
| while (*p) { |
| *p = tolower(*p); |
| p++; |
| } |
| |
| return s; |
| } |
| |
| uint8_t *strupr(uint8_t *s) |
| { |
| uint8_t *p = s; |
| |
| while (*p) { |
| *p = toupper(*p); |
| p++; |
| } |
| |
| return s; |
| } |
| |
| uint8_t *itoa(int value, uint8_t *string, int radix) |
| { |
| switch (radix) { |
| case 10: |
| sprintf(string, "%d", value); |
| break; |
| case 16: |
| sprintf(string, "%x", value); |
| break; |
| default: |
| STUBBED("unknown radix"); |
| break; |
| } |
| |
| return string; |
| } |
| |
| uint8_t *ltoa(int32_t value, uint8_t *string, int radix) |
| { |
| switch (radix) { |
| case 10: |
| sprintf(string, "%d", value); |
| break; |
| case 16: |
| sprintf(string, "%x", value); |
| break; |
| default: |
| STUBBED("unknown radix"); |
| break; |
| } |
| |
| return string; |
| } |
| |
| uint8_t *ultoa(uint32_t value, uint8_t *string, int radix) |
| { |
| switch (radix) { |
| case 10: |
| sprintf(string, "%u", value); |
| break; |
| case 16: |
| sprintf(string, "%ux", value); |
| break; |
| default: |
| STUBBED("unknown radix"); |
| break; |
| } |
| |
| return string; |
| } |
| |
| char ApogeePath[256]; |
| |
| int setup_homedir (void) |
| { |
| int err; |
| |
| snprintf (ApogeePath, sizeof (ApogeePath), "%s/.duke3d/", getenv ("HOME")); |
| |
| //err = mkdir (ApogeePath, S_IRWXU); |
| err = mkdir (ApogeePath); |
| if (err == -1 && errno != EEXIST) |
| { |
| fprintf (stderr, "Couldn't create preferences directory: %s\n", |
| strerror (errno)); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| uint8_t CheckParm (char *check) |
| { |
| int i; |
| for (i = 1; i < _argc; i++) |
| { |
| if ((*(_argv[i]) == '-') && (strcmpi(_argv[i] + 1, check) == 0)) |
| return(i); |
| } |
| |
| return(0); |
| } |
| |
| |
| static void (*shutdown_func)(void) = NULL; |
| |
| void RegisterShutdownFunction( void (* shutdown) (void) ) |
| { |
| shutdown_func = shutdown; |
| } |
| |
| void Shutdown(void) |
| { |
| if (shutdown_func != NULL) |
| { |
| shutdown_func(); |
| shutdown_func = NULL; |
| } |
| } |
| |
| |