ref: 306bd81b628115bc2167ae40793b1c45365195ee
dir: /main.c/
// WL_MAIN.C #include <conio.h> #include "WL_DEF.H" #pragma hdrstop /* ============================================================================= WOLFENSTEIN 3-D An Id Software production by John Carmack ============================================================================= */ /* ============================================================================= LOCAL CONSTANTS ============================================================================= */ #define FOCALLENGTH (0x5700l) // in global coordinates #define VIEWGLOBAL 0x10000 // globals visable flush to wall /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ char str[80],str2[20]; s16int tedlevelnum; int tedlevel; s16int dirangle[9] = {0,ANGLES/8,2*ANGLES/8,3*ANGLES/8,4*ANGLES/8, 5*ANGLES/8,6*ANGLES/8,7*ANGLES/8,ANGLES}; // // proejection variables // s32int focallength; u16int screenofs; s16int viewwidth; s16int viewheight; s16int centerx; s16int shootdelta; // pixels away from centerx a target can be s32int scale,maxslope; s32int heightnumerator; s16int minheightdiv; void Quit (char *error); int startgame,loadedgame; s16int mouseadjustment; char configname[13]="CONFIG."; /* ============================================================================= LOCAL VARIABLES ============================================================================= */ /* ==================== = = ReadConfig = ==================== */ void ReadConfig(void) { s16int file; SDMode sd; SMMode sm; SDSMode sds; if ( (file = open(configname,O_BINARY | O_RDONLY)) != -1) { // // valid config file // read(file,Scores,sizeof(HighScore) * MaxScores); read(file,&sd,sizeof(sd)); read(file,&sm,sizeof(sm)); read(file,&sds,sizeof(sds)); read(file,&mouseenabled,sizeof(mouseenabled)); read(file,&joystickenabled,sizeof(joystickenabled)); read(file,&joypadenabled,sizeof(joypadenabled)); read(file,&joystickprogressive,sizeof(joystickprogressive)); read(file,&joystickport,sizeof(joystickport)); read(file,&dirscan,sizeof(dirscan)); read(file,&buttonscan,sizeof(buttonscan)); read(file,&buttonmouse,sizeof(buttonmouse)); read(file,&buttonjoy,sizeof(buttonjoy)); read(file,&viewsize,sizeof(viewsize)); read(file,&mouseadjustment,sizeof(mouseadjustment)); close(file); if (sd == sdm_AdLib && !AdLibPresent && !SoundBlasterPresent) { sd = sdm_PC; sd = smm_Off; } if ((sds == sds_SoundBlaster && !SoundBlasterPresent) || (sds == sds_SoundSource && !SoundSourcePresent)) sds = sds_Off; if (!MousePresent) mouseenabled = false; MainMenu[6].active=1; MainItems.curpos=0; } else { // // no config file, so select by hardware // if (SoundBlasterPresent || AdLibPresent) { sd = sdm_AdLib; sm = smm_AdLib; } else { sd = sdm_PC; sm = smm_Off; } if (SoundBlasterPresent) sds = sds_SoundBlaster; else if (SoundSourcePresent) sds = sds_SoundSource; else sds = sds_Off; if (MousePresent) mouseenabled = true; viewsize = 15; mouseadjustment=5; } SD_SetMusicMode (sm); SD_SetSoundMode (sd); SD_SetDigiDevice (sds); } /* ==================== = = WriteConfig = ==================== */ void WriteConfig(void) { s16int file; file = open(configname,O_CREAT | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE | S_IFREG); if (file != -1) { write(file,Scores,sizeof(HighScore) * MaxScores); write(file,&SoundMode,sizeof(SoundMode)); write(file,&MusicMode,sizeof(MusicMode)); write(file,&DigiMode,sizeof(DigiMode)); write(file,&mouseenabled,sizeof(mouseenabled)); write(file,&joystickenabled,sizeof(joystickenabled)); write(file,&joypadenabled,sizeof(joypadenabled)); write(file,&joystickprogressive,sizeof(joystickprogressive)); write(file,&joystickport,sizeof(joystickport)); write(file,&dirscan,sizeof(dirscan)); write(file,&buttonscan,sizeof(buttonscan)); write(file,&buttonmouse,sizeof(buttonmouse)); write(file,&buttonjoy,sizeof(buttonjoy)); write(file,&viewsize,sizeof(viewsize)); write(file,&mouseadjustment,sizeof(mouseadjustment)); close(file); } } /* ===================== = = NewGame = = Set up new game to start from the beginning = ===================== */ void NewGame (s16int difficulty,s16int episode) { memset (&gamestate,0,sizeof(gamestate)); gamestate.difficulty = difficulty; gamestate.weapon = gamestate.bestweapon = gamestate.chosenweapon = wp_pistol; gamestate.health = 100; gamestate.ammo = STARTAMMO; gamestate.lives = 3; gamestate.nextextra = EXTRAPOINTS; gamestate.episode=episode; startgame = true; } //=========================================================================== void DiskFlopAnim(s16int x,s16int y) { static char which=0; if (!x && !y) return; VWB_DrawPic(x,y,Pread1+which); VW_UpdateScreen(); which^=1; } s32int DoChecksum(u8int far *source,u16int size,s32int checksum) { u16int i; for (i=0;i<size-1;i++) checksum += source[i]^source[i+1]; return checksum; } /* ================== = = SaveTheGame = ================== */ int SaveTheGame(s16int file,s16int x,s16int y) { struct diskfree_t dfree; s32int avail,size,checksum; objtype *ob,nullobj; if (_dos_getdiskfree(0,&dfree)) Quit("Error in _dos_getdiskfree call"); avail = (s32int)dfree.avail_clusters * dfree.bytes_per_sector * dfree.sectors_per_cluster; size = 0; for (ob = player; ob ; ob=ob->next) size += sizeof(*ob); size += sizeof(nullobj); size += sizeof(gamestate) + sizeof(LRstruct)*8 + sizeof(tilemap) + sizeof(actorat) + sizeof(laststatobj) + sizeof(statobjlist) + sizeof(doorposition) + sizeof(pwallstate) + sizeof(pwallx) + sizeof(pwally) + sizeof(pwalldir) + sizeof(pwallpos); if (avail < size) { Message("There is not enough space\n" "on your disk to Save Game!"); return false; } checksum = 0; DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)&gamestate,sizeof(gamestate)); checksum = DoChecksum((u8int far *)&gamestate,sizeof(gamestate),checksum); DiskFlopAnim(x,y); #ifdef SPEAR CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20); checksum = DoChecksum((u8int far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum); #else CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8); checksum = DoChecksum((u8int far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum); #endif DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)tilemap,sizeof(tilemap)); checksum = DoChecksum((u8int far *)tilemap,sizeof(tilemap),checksum); DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)actorat,sizeof(actorat)); checksum = DoChecksum((u8int far *)actorat,sizeof(actorat),checksum); CA_FarWrite (file,(void far *)areaconnect,sizeof(areaconnect)); CA_FarWrite (file,(void far *)areabyplayer,sizeof(areabyplayer)); for (ob = player ; ob ; ob=ob->next) { DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)ob,sizeof(*ob)); } nullobj.active = ac_badobject; // end of file marker DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)&nullobj,sizeof(nullobj)); DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)&laststatobj,sizeof(laststatobj)); checksum = DoChecksum((u8int far *)&laststatobj,sizeof(laststatobj),checksum); DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)statobjlist,sizeof(statobjlist)); checksum = DoChecksum((u8int far *)statobjlist,sizeof(statobjlist),checksum); DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)doorposition,sizeof(doorposition)); checksum = DoChecksum((u8int far *)doorposition,sizeof(doorposition),checksum); DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)doorobjlist,sizeof(doorobjlist)); checksum = DoChecksum((u8int far *)doorobjlist,sizeof(doorobjlist),checksum); DiskFlopAnim(x,y); CA_FarWrite (file,(void far *)&pwallstate,sizeof(pwallstate)); checksum = DoChecksum((u8int far *)&pwallstate,sizeof(pwallstate),checksum); CA_FarWrite (file,(void far *)&pwallx,sizeof(pwallx)); checksum = DoChecksum((u8int far *)&pwallx,sizeof(pwallx),checksum); CA_FarWrite (file,(void far *)&pwally,sizeof(pwally)); checksum = DoChecksum((u8int far *)&pwally,sizeof(pwally),checksum); CA_FarWrite (file,(void far *)&pwalldir,sizeof(pwalldir)); checksum = DoChecksum((u8int far *)&pwalldir,sizeof(pwalldir),checksum); CA_FarWrite (file,(void far *)&pwallpos,sizeof(pwallpos)); checksum = DoChecksum((u8int far *)&pwallpos,sizeof(pwallpos),checksum); // // WRITE OUT CHECKSUM // CA_FarWrite (file,(void far *)&checksum,sizeof(checksum)); return(true); } //=========================================================================== /* ================== = = LoadTheGame = ================== */ int LoadTheGame(s16int file,s16int x,s16int y) { s32int checksum,oldchecksum; objtype *ob,nullobj; checksum = 0; DiskFlopAnim(x,y); CA_FarRead (file,(void far *)&gamestate,sizeof(gamestate)); checksum = DoChecksum((u8int far *)&gamestate,sizeof(gamestate),checksum); DiskFlopAnim(x,y); #ifdef SPEAR CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20); checksum = DoChecksum((u8int far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum); #else CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8); checksum = DoChecksum((u8int far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum); #endif DiskFlopAnim(x,y); SetupGameLevel (); DiskFlopAnim(x,y); CA_FarRead (file,(void far *)tilemap,sizeof(tilemap)); checksum = DoChecksum((u8int far *)tilemap,sizeof(tilemap),checksum); DiskFlopAnim(x,y); CA_FarRead (file,(void far *)actorat,sizeof(actorat)); checksum = DoChecksum((u8int far *)actorat,sizeof(actorat),checksum); CA_FarRead (file,(void far *)areaconnect,sizeof(areaconnect)); CA_FarRead (file,(void far *)areabyplayer,sizeof(areabyplayer)); InitActorList (); DiskFlopAnim(x,y); CA_FarRead (file,(void far *)player,sizeof(*player)); while (1) { DiskFlopAnim(x,y); CA_FarRead (file,(void far *)&nullobj,sizeof(nullobj)); if (nullobj.active == ac_badobject) break; GetNewActor (); // don't copy over the links memcpy (new,&nullobj,sizeof(nullobj)-4); } DiskFlopAnim(x,y); CA_FarRead (file,(void far *)&laststatobj,sizeof(laststatobj)); checksum = DoChecksum((u8int far *)&laststatobj,sizeof(laststatobj),checksum); DiskFlopAnim(x,y); CA_FarRead (file,(void far *)statobjlist,sizeof(statobjlist)); checksum = DoChecksum((u8int far *)statobjlist,sizeof(statobjlist),checksum); DiskFlopAnim(x,y); CA_FarRead (file,(void far *)doorposition,sizeof(doorposition)); checksum = DoChecksum((u8int far *)doorposition,sizeof(doorposition),checksum); DiskFlopAnim(x,y); CA_FarRead (file,(void far *)doorobjlist,sizeof(doorobjlist)); checksum = DoChecksum((u8int far *)doorobjlist,sizeof(doorobjlist),checksum); DiskFlopAnim(x,y); CA_FarRead (file,(void far *)&pwallstate,sizeof(pwallstate)); checksum = DoChecksum((u8int far *)&pwallstate,sizeof(pwallstate),checksum); CA_FarRead (file,(void far *)&pwallx,sizeof(pwallx)); checksum = DoChecksum((u8int far *)&pwallx,sizeof(pwallx),checksum); CA_FarRead (file,(void far *)&pwally,sizeof(pwally)); checksum = DoChecksum((u8int far *)&pwally,sizeof(pwally),checksum); CA_FarRead (file,(void far *)&pwalldir,sizeof(pwalldir)); checksum = DoChecksum((u8int far *)&pwalldir,sizeof(pwalldir),checksum); CA_FarRead (file,(void far *)&pwallpos,sizeof(pwallpos)); checksum = DoChecksum((u8int far *)&pwallpos,sizeof(pwallpos),checksum); CA_FarRead (file,(void far *)&oldchecksum,sizeof(oldchecksum)); if (oldchecksum != checksum) { Message("Your Save Game file is,\n" "shall we say, \"corrupted\".\n" "But I'll let you go on and\n" "play anyway...."); IN_ClearKeysDown(); IN_Ack(); gamestate.score = 0; gamestate.lives = 1; gamestate.weapon = gamestate.chosenweapon = gamestate.bestweapon = wp_pistol; gamestate.ammo = 8; } return true; } /* ================== = = BuildTables = = Calculates: = = scale projection constant = sintable/costable overlapping fractional tables = ================== */ const float radtoint = (float)FINEANGLES/2/PI; void BuildTables (void) { s16int i; float angle,anglestep; double tang; s32int value; // // calculate fine tangents // for (i=0;i<FINEANGLES/8;i++) { tang = tan( (i+0.5)/radtoint); finetangent[i] = tang*TILEGLOBAL; finetangent[FINEANGLES/4-1-i] = 1/tang*TILEGLOBAL; } // // costable overlays sintable with a quarter phase shift // ANGLES is assumed to be divisable by four // // The low word of the value is the fraction, the high bit is the sign bit, // bits 16-30 should be 0 // angle = 0; anglestep = PI/2/ANGLEQUAD; for (i=0;i<=ANGLEQUAD;i++) { value=GLOBAL1*sin(angle); sintable[i]= sintable[i+ANGLES]= sintable[ANGLES/2-i] = value; sintable[ANGLES-i]= sintable[ANGLES/2+i] = value | 0x80000000l; angle += anglestep; } } //=========================================================================== /* ==================== = = CalcProjection = = Uses focallength = ==================== */ void CalcProjection (s32int focal) { s16int i; s32int intang; float angle; double tang; double planedist; double globinhalf; s16int halfview; double halfangle,facedist; focallength = focal; facedist = focal+MINDIST; halfview = viewwidth/2; // half view in pixels // // calculate scale value for vertical height calculations // and sprite x calculations // scale = halfview*facedist/(VIEWGLOBAL/2); // // divide heightnumerator by a posts distance to get the posts height for // the heightbuffer. The pixel height is height>>2 // heightnumerator = (TILEGLOBAL*scale)>>6; minheightdiv = heightnumerator/0x7fff +1; // // calculate the angle offset from view angle of each pixel's ray // for (i=0;i<halfview;i++) { // start 1/2 pixel over, so viewangle bisects two middle pixels tang = (s32int)i*VIEWGLOBAL/viewwidth/facedist; angle = atan(tang); intang = angle*radtoint; pixelangle[halfview-1-i] = intang; pixelangle[halfview+i] = -intang; } // // if a point's abs(y/x) is greater than maxslope, the point is outside // the view area // maxslope = finetangent[pixelangle[0]]; maxslope >>= 8; } //=========================================================================== /* =================== = = SetupWalls = = Map tile values to scaled pics = =================== */ void SetupWalls (void) { s16int i; for (i=1;i<MAXWALLTILES;i++) { horizwall[i]=(i-1)*2; vertwall[i]=(i-1)*2+1; } } /* ========================== = = InitGame = = Load a few things right away = ========================== */ void InitGame (void) { s16int i,x,y; u16int *blockstart; mapon = -1; // // build some tables // for (i=0;i<MAPSIZE;i++) { farmapylookup[i] = i*64; } for (i=0;i<PORTTILESHIGH;i++) uwidthtable[i] = UPDATEWIDE*i; blockstart = &blockstarts[0]; for (y=0;y<UPDATEHIGH;y++) for (x=0;x<UPDATEWIDE;x++) *blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH; updateptr = &update[0]; bufferofs = 0; displayofs = 0; ReadConfig (); IntroScreen (); // // load in and lock down some basic chunks // LoadLatchMem (); BuildTables (); // trig tables SetupWalls (); NewViewSize (viewsize); // // initialize variables // InitRedShifts (); displayofs = PAGE1START; bufferofs = PAGE2START; } //=========================================================================== /* ========================== = = SetViewSize = ========================== */ int SetViewSize (u16int width, u16int height) { viewwidth = width&~15; // must be divisable by 16 viewheight = height&~1; // must be even centerx = viewwidth/2-1; shootdelta = viewwidth/10; screenofs = ((200-STATUSLINES-viewheight)/2*SCREENWIDTH+(320-viewwidth)/8); // // calculate trace angles and projection constants // CalcProjection (FOCALLENGTH); // // build all needed compiled scalers // SetupScaling (viewwidth*1.5); return true; } void ShowViewSize (s16int width) { s16int oldwidth,oldheight; oldwidth = viewwidth; oldheight = viewheight; viewwidth = width*16; viewheight = width*16*HEIGHTRATIO; DrawPlayBorder (); viewheight = oldheight; viewwidth = oldwidth; } void NewViewSize (s16int width) { CA_UpLevel (); MM_SortMem (); viewsize = width; SetViewSize (width*16,width*16*HEIGHTRATIO); CA_DownLevel (); } //=========================================================================== /* ========================== = = Quit = ========================== */ void Quit (char *error) { u16int finscreen; uchar *screen; ClearMemory (); if (!*error) { screen = Eorder; WriteConfig (); } else { screen = Eerror; } if (error && *error) { movedata ((u16int)screen,7,0xb800,0,7*160); gotoxy (10,4); puts(error); gotoxy (1,8); exit(1); } else if (!error || !(*error)) { clrscr(); movedata ((u16int)screen,7,0xb800,0,4000); gotoxy(1,24); //asm mov bh,0 //asm mov dh,23 // row //asm mov dl,0 // collumn //asm mov ah,2 //asm int 0x10 } exit(0); } //=========================================================================== /* ===================== = = DemoLoop = ===================== */ void DemoLoop (void) { static s16int LastDemo; s16int i,level; s32int nsize; uchar *nullblock; // // check for launch from ted // /* → if warping to map [tedlevel] */ if (tedlevel) { NoWait = true; NewGame(1,0); /* → set difficulty level 1-4 if parameter passed as * gamestate.difficulty */ #ifndef SPEAR gamestate.episode = tedlevelnum/10; gamestate.mapon = tedlevelnum%10; #else gamestate.episode = 0; gamestate.mapon = tedlevelnum; #endif GameLoop(); Quit (NULL); } // // main game cycle // // nsize = (s32int)40*1024; // MM_GetPtr(&nullblock,nsize); StartCPMusic(INTROSONG); if (!NoWait) PG13 (); while (1) { uchar *p = dems; while (!NoWait) { // // title page // MM_SortMem (); #ifdef SPEAR VWB_DrawPic (0,0,Ptitle1); VWB_DrawPic (0,80,Ptitle2); VW_UpdateScreen (); VL_FadeIn(0,255,Etitpal,30); #else CA_CacheScreen (Ptitle1); VW_UpdateScreen (); VW_FadeIn(); #endif if (IN_UserInput(TickBase*15)) break; VW_FadeOut(); // // credits page // CA_CacheScreen (Pcreds); VW_UpdateScreen(); VW_FadeIn (); if (IN_UserInput(TickBase*10)) break; VW_FadeOut (); // // high scores // DrawHighScores (); VW_UpdateScreen (); VW_FadeIn (); if (IN_UserInput(TickBase*10)) break; // // demo // PlayDemo(p++); if(p >= epis) p = dems; if (playstate == ex_abort) break; StartCPMusic(INTROSONG); } VW_FadeOut (); if (Keyboard[sc_Tab] && debug) RecordDemo (); else US_ControlPanel (0); if (startgame || loadedgame) { GameLoop (); VW_FadeOut(); StartCPMusic(INTROSONG); } } } //=========================================================================== /* ========================== = = main = ========================== */ void main (void) { if (wl6) { NewEmenu[2].active = NewEmenu[4].active = NewEmenu[6].active = NewEmenu[8].active = NewEmenu[10].active = EpisodeSelect[1] = EpisodeSelect[2] = EpisodeSelect[3] = EpisodeSelect[4] = EpisodeSelect[5] = 1; } InitGame (); DemoLoop(); }