ref: 0441e14568c0254ba99e516d1282fd196cb1e0a3
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;
}
//===========================================================================
/*
==========================
=
= ShutdownId
=
= Shuts down all ID_?? managers
=
==========================
*/
void ShutdownId (void)
{
SD_Shutdown ();
}
//===========================================================================
/*
==================
=
= 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;
SD_Startup ();
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;
}
ShutdownId ();
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)
{
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
//
#ifndef SPEARDEMO
PlayDemo (LastDemo++%4);
#else
PlayDemo (0);
#endif
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();
}