planet-strike/3D_MAIN.C
2013-07-08 00:00:00 +00:00

1905 lines
43 KiB
C

// 3D_MAIN.C
#include "3D_DEF.H"
#pragma hdrstop
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <mem.h>
#include <fcntl.h>
#include <io.h>
#include <dos.h>
#include <sys/stat.h>
#include <time.h>
#include <ctype.h>
#include "jm_io.h"
#include "jm_cio.h"
#include "jm_lzh.h"
#include "jm_error.h"
/*
=============================================================================
BLAKE STONE
(C)opyright 1993, JAM Productions, Inc.
3D engine licensed by ID Software, Inc.
Shareware distribution by Apogee Software, Inc.
=============================================================================
*/
/*
=============================================================================
LOCAL CONSTANTS
=============================================================================
*/
#define SKIP_TITLE_AND_CREDITS (false)
#define FOCALLENGTH (0x5700l) // in global coordinates
#define VIEWGLOBAL 0x10000 // globals visable flush to wall
#define VIEWWIDTH 256 // size of view window
#define VIEWHEIGHT 144
#define MAX_DEST_PATH_LEN 30
/*
=============================================================================
GLOBAL VARIABLES
=============================================================================
*/
extern int pickquick;
void DrawCreditsPage(void);
void unfreed_main(void);
void ShowPromo(void);
char far * far MainStrs[] = {
"q","nowait","l","e",
"version","system",
"dval","tics","mem","powerball","music","d",
"radar",BETA_CODE,
nil
};
short starting_episode,starting_level,starting_difficulty;
char destPath[MAX_DEST_PATH_LEN+1];
char tempPath[MAX_DEST_PATH_LEN+15];
#if BETA_TEST
char far bc_buffer[]=BETA_CODE;
#endif
void InitPlaytemp(void);
char QuitMsg[] = {"Unit: $%02x Error: $%02x"};
#ifdef CEILING_FLOOR_COLORS
unsigned TopColor,BottomColor;
#endif
boolean nospr;
boolean IsA386;
int 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
//
fixed focallength;
unsigned screenofs;
int viewwidth;
int viewheight;
int centerx;
int shootdelta; // pixels away from centerx a target can be
fixed scale,maxslope;
long heightnumerator;
int minheightdiv;
boolean startgame,loadedgame;
int mouseadjustment;
char configname[13]="CONFIG.";
short view_xl,view_xh,view_yl,view_yh;
#if IN_DEVELOPMENT
unsigned democount=0,jim=0;
#endif
/*
=============================================================================
LOCAL VARIABLES
=============================================================================
*/
#if 0
unsigned mspeed;
void CalcSpeedRating()
{
short loop;
for (loop=0; loop<10; loop++)
{
ThreeDRefresh();
mspeed += tics;
}
}
#endif
/*
====================
=
= WriteConfig
=
====================
*/
void WriteConfig(void)
{
int file;
MakeDestPath(configname);
file = open(tempPath,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));
write(file,&gamestate.flags,sizeof(gamestate.flags));
close(file);
}
}
//===========================================================================
/*
=====================
=
= NewGame
=
= Set up new game to start from the beginning
=
=====================
*/
boolean ShowQuickMsg;
void NewGame (int difficulty,int episode)
{
unsigned oldf=gamestate.flags,loop;
InitPlaytemp();
playstate = ex_stillplaying;
ShowQuickMsg=true;
_fmemset (&gamestuff,0,sizeof(gamestuff));
memset (&gamestate,0,sizeof(gamestate));
memset(&gamestate.barrier_table,0xff,sizeof(gamestate.barrier_table));
memset(&gamestate.old_barrier_table,0xff,sizeof(gamestate.old_barrier_table));
gamestate.flags = oldf & ~(GS_KILL_INF_WARN);
// LoadAccessCodes();
gamestate.difficulty = difficulty;
//
// The following are set to 0 by the memset() to gamestate - Good catch! :JR
//
// gamestate.rzoom
// gamestate.rpower
// gamestate.old_door_bombs
// gamestate.plasma_detonators
//
gamestate.weapons = 1<<wp_autocharge; // |1<<wp_plasma_detonators;
gamestate.weapon = gamestate.chosenweapon = wp_autocharge;
gamestate.old_weapons[0] = gamestate.weapons;
gamestate.old_weapons[1] = gamestate.weapon;
gamestate.old_weapons[2] = gamestate.chosenweapon;
gamestate.health = 100;
gamestate.old_ammo = gamestate.ammo = STARTAMMO;
// gamestate.dollars = START_DOLLARS;
// gamestate.cents = START_CENTS;
gamestate.lives = 3;
gamestate.nextextra = EXTRAPOINTS;
gamestate.episode=episode;
gamestate.flags |= (GS_CLIP_WALLS|GS_ATTACK_INFOAREA); //|GS_DRAW_CEILING|GS_DRAW_FLOOR);
#if IN_DEVELOPMENT || TECH_SUPPORT_VERSION
if (gamestate.flags & GS_STARTLEVEL)
{
gamestate.mapon = starting_level;
gamestate.difficulty = starting_difficulty;
gamestate.episode = starting_episode;
}
else
#endif
gamestate.mapon = 0;
gamestate.key_floor = gamestate.mapon+1;
startgame = true;
for (loop=0; loop<MAPS_WITH_STATS; loop++)
{
gamestuff.old_levelinfo[loop].stats.overall_floor=100;
if (loop)
gamestuff.old_levelinfo[loop].locked=true;
}
// normalshade_div = SHADE_DIV;
// shade_max = SHADE_MAX;
ExtraRadarFlags = InstantWin = InstantQuit = 0;
pickquick = 0;
}
//===========================================================================
//==========================================================================
//
// 'LOAD/SAVE game' and 'LOAD/SAVE level' code
//
//==========================================================================
boolean LevelInPlaytemp(char levelnum);
#define WriteIt(c,p,s) cksize+=WriteInfo(c,(char far *)p,s,handle)
#define ReadIt(d,p,s) ReadInfo(d,(char far *)p,s,handle)
#define LZH_WORK_BUFFER_SIZE 8192
memptr lzh_work_buffer;
long checksum;
//--------------------------------------------------------------------------
// InitPlaytemp()
//--------------------------------------------------------------------------
void InitPlaytemp()
{
int handle;
long size;
MakeDestPath(PLAYTEMP_FILE);
if ((handle=open(tempPath,O_CREAT|O_TRUNC|O_RDWR|O_BINARY,S_IREAD|S_IWRITE))==-1)
MAIN_ERROR(INITPLAYTEMP_OPEN_ERR);
close(handle);
}
//--------------------------------------------------------------------------
// DoChecksum()
//--------------------------------------------------------------------------
long DoChecksum(byte far *source,unsigned size,long checksum)
{
unsigned i;
for (i=0;i<size-1;i++)
checksum += source[i]^source[i+1];
return(checksum);
}
//--------------------------------------------------------------------------
// FindChunk()
//--------------------------------------------------------------------------
long FindChunk(int file, char *chunk)
{
long chunklen;
char fchunk[5]={0,0,0,0,0};
while (1)
{
if (read(file,fchunk,4)!=4) // read chunk id
break;
read(file,&chunklen,4); // read chunk length
if (strstr(fchunk,chunk)) // look for chunk (sub-check!)
return(chunklen); // chunk found!
lseek(file,chunklen,SEEK_CUR); // skip this chunk
}
lseek(file,0,SEEK_END); // make sure we're at the end
return(0);
}
//--------------------------------------------------------------------------
// NextChunk()
//--------------------------------------------------------------------------
long NextChunk(int file)
{
long chunklen;
char fchunk[5]={0,0,0,0,0};
if (read(file,fchunk,4) != 4) // read chunk id
{
lseek(file,0,SEEK_END); // make sure we're at the end
return(0);
}
read(file,&chunklen,4); // read chunk length
return(chunklen);
}
char LS_current=-1,LS_total=-1;
//--------------------------------------------------------------------------
// ReadInfo()
//--------------------------------------------------------------------------
void ReadInfo(boolean decompress,char far *dst, unsigned size, int file)
{
unsigned csize,dsize;
PreloadUpdate(LS_current++,LS_total);
if (decompress)
{
IO_FarRead(file,(char far *)&csize,sizeof(csize));
IO_FarRead(file,lzh_work_buffer,csize);
checksum=DoChecksum(lzh_work_buffer,csize,checksum);
dsize=LZH_Decompress(lzh_work_buffer,dst,size,csize,SRC_MEM|DEST_MEM);
if (dsize != size)
MAIN_ERROR(READINFO_BAD_DECOMP);
}
else
{
IO_FarRead(file,dst,size);
checksum=DoChecksum(dst,size,checksum);
}
}
//--------------------------------------------------------------------------
// WriteInfo()
//--------------------------------------------------------------------------
unsigned WriteInfo(boolean compress, char far *src, unsigned size, int file)
{
unsigned csize;
PreloadUpdate(LS_current++,LS_total);
if (compress)
{
csize=LZH_Compress(src,lzh_work_buffer,size,SRC_MEM|DEST_MEM);
if (csize > LZH_WORK_BUFFER_SIZE)
MAIN_ERROR(WRITEINFO_BIGGER_BUF);
IO_FarWrite (file,(char far *)&csize,sizeof(csize));
IO_FarWrite (file,lzh_work_buffer,csize);
checksum=DoChecksum(lzh_work_buffer,csize,checksum);
csize += sizeof(csize);
}
else
{
IO_FarWrite (file,src,size);
checksum=DoChecksum(src,size,checksum);
csize=size;
}
return(csize);
}
//--------------------------------------------------------------------------
// LoadLevel()
//--------------------------------------------------------------------------
boolean LoadLevel(short levelnum)
{
extern boolean ShowQuickMsg;
extern boolean ForceLoadDefault;
extern unsigned destoff;
boolean oldloaded=loadedgame;
long oldchecksum;
objtype *ob;
statobj_t *statptr;
int handle,picnum;
memptr temp;
unsigned count;
char far *ptr;
char chunk[5]="LVxx";
extern int nsd_table[];
extern int sm_table[];
char mod;
WindowY=181;
gamestuff.level[levelnum].locked=false;
mod = levelnum % 6;
normalshade_div = nsd_table[mod];
shade_max = sm_table[mod];
normalshade=(3*(maxscale>>2))/normalshade_div;
// Open PLAYTEMP file
//
MakeDestPath(PLAYTEMP_FILE);
handle=open(tempPath,O_RDONLY|O_BINARY);
// If level exists in PLAYTEMP file, use it; otherwise, load it from scratch!
//
sprintf(&chunk[2],"%02x",levelnum);
if ((handle==-1) || (!FindChunk(handle,chunk)) || ForceLoadDefault)
{
close(handle);
PreloadUpdate(LS_current+((LS_total-LS_current)>>1),LS_total);
SetupGameLevel();
gamestate.flags |= GS_VIRGIN_LEVEL;
gamestate.turn_around=0;
PreloadUpdate(1,1);
ForceLoadDefault=false;
goto overlay;
}
gamestate.flags &= ~GS_VIRGIN_LEVEL;
// Setup for LZH decompression
//
LZH_Startup();
MM_GetPtr(&lzh_work_buffer,LZH_WORK_BUFFER_SIZE);
// Read all sorts of stuff...
//
checksum = 0;
loadedgame=true;
SetupGameLevel();
loadedgame=oldloaded;
ReadIt(true, tilemap, sizeof(tilemap));
ReadIt(true, actorat, sizeof(actorat));
ReadIt(true, areaconnect, sizeof(areaconnect));
ReadIt(true, areabyplayer, sizeof(areabyplayer));
// Restore 'save game' actors
//
ReadIt(false, &count, sizeof(count));
MM_GetPtr(&temp,count*sizeof(*ob));
ReadIt(true, temp, count*sizeof(*ob));
ptr=temp;
InitActorList (); // start with "player" actor
_fmemcpy(new,ptr,sizeof(*ob)-4); // don't copy over links!
ptr += sizeof(*ob); //
while (--count)
{
GetNewActor();
_fmemcpy(new,ptr,sizeof(*ob)-4); // don't copy over links!
actorat[new->tilex][new->tiley]=new;
#if LOOK_FOR_DEAD_GUYS
if (new->flags & FL_DEADGUY)
DeadGuys[NumDeadGuys++]=new;
#endif
ptr += sizeof(*ob);
}
MM_FreePtr(&temp);
//
// Re-Establish links to barrier switches
//
#pragma warn -pia
ob = objlist;
do
{
switch (ob->obclass)
{
case arc_barrierobj:
case post_barrierobj:
case vspike_barrierobj:
case vpost_barrierobj:
ob->temp2 = ScanBarrierTable(ob->tilex,ob->tiley);
break;
}
} while (ob = ob->next);
#pragma warn +pia
ConnectBarriers();
// Read all sorts of stuff...
//
ReadIt(false, &laststatobj, sizeof(laststatobj));
ReadIt(true, statobjlist, sizeof(statobjlist));
ReadIt(true, doorposition, sizeof(doorposition));
ReadIt(true, doorobjlist, sizeof(doorobjlist));
ReadIt(false, &pwallstate, sizeof(pwallstate));
ReadIt(false, &pwallx, sizeof(pwallx));
ReadIt(false, &pwally, sizeof(pwally));
ReadIt(false, &pwalldir, sizeof(pwalldir));
ReadIt(false, &pwallpos, sizeof(pwallpos));
ReadIt(false, &pwalldist, sizeof(pwalldist));
ReadIt(true, TravelTable, sizeof(TravelTable));
ReadIt(true, &ConHintList, sizeof(ConHintList));
ReadIt(true, eaList, sizeof(eaWallInfo)*MAXEAWALLS);
ReadIt(true, &GoldsternInfo, sizeof(GoldsternInfo));
ReadIt(true, &GoldieList,sizeof(GoldieList));
ReadIt(false, gamestate.barrier_table,sizeof(gamestate.barrier_table));
ReadIt(false, &gamestate.plasma_detonators,sizeof(gamestate.plasma_detonators));
// Read and evaluate checksum
//
PreloadUpdate(LS_current++,LS_total);
IO_FarRead (handle,(void far *)&oldchecksum,sizeof(oldchecksum));
if (oldchecksum != checksum)
{
int old_wx=WindowX,old_wy=WindowY,old_ww=WindowW,old_wh=WindowH,
old_px=px,old_py=py;
WindowX=0; WindowY=16; WindowW=320; WindowH=168;
CacheMessage(BADINFO_TEXT);
WindowX=old_wx; WindowY=old_wy; WindowW=old_ww; WindowH=old_wh;
px=old_px; py=old_py;
IN_ClearKeysDown();
IN_Ack();
gamestate.score = 0;
gamestate.nextextra = EXTRAPOINTS;
gamestate.lives = 1;
gamestate.weapon = gamestate.chosenweapon = wp_autocharge;
gamestate.weapons = 1<<wp_autocharge; // |1<<wp_plasma_detonators;
gamestate.ammo = 8;
}
close(handle);
// Clean-up LZH compression
//
MM_FreePtr(&lzh_work_buffer);
LZH_Shutdown();
NewViewSize(viewsize);
// Check for Strange Door and Actor combos
//
CleanUpDoors_N_Actors();
overlay:;
return(true);
}
//--------------------------------------------------------------------------
// SaveLevel()
//--------------------------------------------------------------------------
boolean SaveLevel(short levelnum)
{
objtype *ob;
int handle;
struct ffblk finfo;
long offset,cksize;
char chunk[5]="LVxx";
unsigned gflags = gamestate.flags;
boolean rt_value=false;
memptr temp;
unsigned count;
char far *ptr;
char oldmapon;
WindowY=181;
// Make sure floor stats are saved!
//
oldmapon=gamestate.mapon;
gamestate.mapon=gamestate.lastmapon;
ShowStats(0,0,ss_justcalc,&gamestuff.level[gamestate.mapon].stats);
gamestate.mapon=oldmapon;
// Yeah! We're no longer a virgin!
//
gamestate.flags &= ~GS_VIRGIN_LEVEL;
// Open PLAYTEMP file
//
MakeDestPath(PLAYTEMP_FILE);
if ((handle=open(tempPath,O_CREAT|O_RDWR|O_BINARY,S_IREAD|S_IWRITE))==-1)
MAIN_ERROR(SAVELEVEL_DISKERR);
// Remove level chunk from file
//
sprintf(&chunk[2],"%02x",levelnum);
DeleteChunk(handle,chunk);
// Setup LZH compression
//
LZH_Startup();
MM_GetPtr(&lzh_work_buffer,LZH_WORK_BUFFER_SIZE);
// Write level chunk id
//
write(handle,chunk,4);
lseek(handle,4,SEEK_CUR); // leave four bytes for chunk size
// Write all sorts of info...
//
checksum = cksize = 0;
WriteIt(true, tilemap, sizeof(tilemap));
WriteIt(true, actorat, sizeof(actorat));
WriteIt(true, areaconnect, sizeof(areaconnect));
WriteIt(true, areabyplayer, sizeof(areabyplayer));
// Write actor list...
//
MM_GetPtr(&temp,sizeof(objlist));
for (ob=player,count=0,ptr=temp; ob; ob=ob->next,count++,ptr+=sizeof(*ob))
_fmemcpy(ptr,ob,sizeof(*ob));
WriteIt(false, &count, sizeof(count));
WriteIt(true, temp, count*sizeof(*ob));
MM_FreePtr(&temp);
// Write all sorts of info...
//
WriteIt(false, &laststatobj, sizeof(laststatobj));
WriteIt(true, statobjlist, sizeof(statobjlist));
WriteIt(true, doorposition, sizeof(doorposition));
WriteIt(true, doorobjlist, sizeof(doorobjlist));
WriteIt(false, &pwallstate, sizeof(pwallstate));
WriteIt(false, &pwallx, sizeof(pwallx));
WriteIt(false, &pwally, sizeof(pwally));
WriteIt(false, &pwalldir, sizeof(pwalldir));
WriteIt(false, &pwallpos, sizeof(pwallpos));
WriteIt(false, &pwalldist, sizeof(pwalldist));
WriteIt(true, TravelTable, sizeof(TravelTable));
WriteIt(true, &ConHintList, sizeof(ConHintList));
WriteIt(true, eaList, sizeof(eaWallInfo)*MAXEAWALLS);
WriteIt(true, &GoldsternInfo, sizeof(GoldsternInfo));
WriteIt(true, &GoldieList,sizeof(GoldieList));
WriteIt(false, gamestate.barrier_table,sizeof(gamestate.barrier_table));
WriteIt(false, &gamestate.plasma_detonators,sizeof(gamestate.plasma_detonators));
// Write checksum and determine size of file
//
WriteIt(false, &checksum, sizeof(checksum));
offset=tell(handle);
// Write chunk size, set file size, and close file
//
lseek(handle,-(cksize+4),SEEK_CUR);
write(handle,&cksize,4);
chsize(handle,offset);
close(handle);
rt_value=true;
// Clean-up LZH compression
//
exit_func:;
MM_FreePtr(&lzh_work_buffer);
LZH_Shutdown();
NewViewSize(viewsize);
gamestate.flags = gflags;
return(rt_value);
}
#pragma warn -pia
//--------------------------------------------------------------------------
// DeleteChunk()
//--------------------------------------------------------------------------
long DeleteChunk(int handle, char *chunk)
{
long filesize,cksize,offset,bmove;
int dhandle;
lseek(handle,0,SEEK_SET);
filesize=lseek(handle,0,SEEK_END);
lseek(handle,0,SEEK_SET);
if (cksize=FindChunk(handle,chunk))
{
offset=lseek(handle,0,SEEK_CUR)-8; // move back to CKID/SIZE
bmove=filesize-(offset+8+cksize); // figure bytes to move
if (bmove) // any data to move?
{
// Move data: FROM --> the start of NEXT chunk through the end of file.
// TO --> the start of THIS chunk.
//
// (ie: erase THIS chunk and re-write it at the end of the file!)
//
lseek(handle,cksize,SEEK_CUR); // seek source to NEXT chunk
MakeDestPath(PLAYTEMP_FILE);
if ((dhandle=open(tempPath,O_CREAT|O_RDWR|O_BINARY,S_IREAD|S_IWRITE))==-1)
MAIN_ERROR(SAVELEVEL_DISKERR);
lseek(dhandle,offset,SEEK_SET); // seek dest to THIS chunk
IO_CopyHandle(handle,dhandle,bmove); // copy "bmove" bytes
close(dhandle);
lseek(handle,offset+bmove,SEEK_SET); // go to end of data moved
}
else
lseek(handle,offset,SEEK_SET);
}
return(cksize);
}
#pragma warn +pia
char far SavegameInfoText[]="\n\r"
"\n\r"
"-------------------------------------\n\r"
" Blake Stone: Aliens Of Gold\n\r"
"Copyright 1993, JAM Productions, Inc.\n\r"
"\n\r"
"SAVEGAME file is from version: "__VERSION__"\n\r"
" Compile Date :"__DATE__" : "__TIME__"\n\r"
"-------------------------------------\n\r"
"\x1a";
//--------------------------------------------------------------------------
// LoadTheGame()
//--------------------------------------------------------------------------
boolean LoadTheGame(int handle)
{
extern int lastmenumusic;
int shandle;
long cksize;
memptr temp=NULL;
boolean rt_value=false;
char InfoSpace[400];
memptr tempspace;
// Setup LZH decompression
//
LZH_Startup();
MM_GetPtr(&lzh_work_buffer,LZH_WORK_BUFFER_SIZE);
// Read in VERSion chunk
//
if (!FindChunk(handle,"VERS"))
goto cleanup;
cksize = sizeof(SavegameInfoText);
read(handle, InfoSpace, cksize);
if (_fmemcmp(InfoSpace, SavegameInfoText, cksize))
{
// Old Version of game
int old_wx=WindowX,old_wy=WindowY,old_ww=WindowW,old_wh=WindowH,
old_px=px,old_py=py;
WindowX=0; WindowY=16; WindowW=320; WindowH=168;
CacheMessage(BADSAVEGAME_TEXT);
SD_PlaySound (NOWAYSND);
WindowX=old_wx; WindowY=old_wy; WindowW=old_ww; WindowH=old_wh;
px=old_px; py=old_py;
IN_ClearKeysDown();
IN_Ack();
VW_FadeOut();
screenfaded = true;
goto cleanup;
}
// Read in HEAD chunk
//
if (!FindChunk(handle,"HEAD"))
goto cleanup;
ReadIt(true, &gamestate, sizeof(gamestate));
ReadIt(true, &gamestuff, sizeof(gamestuff));
// Reinitialize page manager
//
#if DUAL_SWAP_FILES
PM_Shutdown();
PM_Startup ();
PM_UnlockMainMem();
#endif
// Start music for the starting level in this loaded game.
//
FreeMusic();
StartMusic(false);
// Copy all remaining chunks to PLAYTEMP file
//
MakeDestPath(PLAYTEMP_FILE);
if ((shandle=open(tempPath,O_CREAT|O_RDWR|O_TRUNC|O_BINARY,S_IREAD|S_IWRITE))==-1)
goto cleanup;
#pragma warn -pia
while (cksize=NextChunk(handle))
{
cksize += 8; // include chunk ID and LENGTH
lseek(handle,-8,SEEK_CUR); // seek to start of chunk
MM_GetPtr(&temp,cksize); // alloc temp buffer
IO_FarRead(handle,temp,cksize); // read chunk from SAVEGAME file
IO_FarWrite(shandle,temp,cksize); // write chunk to PLAYTEMP file
MM_FreePtr(&temp); // free temp buffer
}
#pragma warn +pia
close(shandle);
rt_value=true;
// Clean-up LZH decompression
//
cleanup:;
MM_FreePtr(&lzh_work_buffer);
LZH_Shutdown();
NewViewSize(viewsize);
// Load current level
//
if (rt_value)
{
LoadLevel(0xff);
ShowQuickMsg=false;
}
return(rt_value);
}
//--------------------------------------------------------------------------
// SaveTheGame()
//--------------------------------------------------------------------------
boolean SaveTheGame(int handle, char far *description)
{
struct ffblk finfo;
unsigned long cksize,offset;
int shandle;
memptr temp;
char nbuff[GAME_DESCRIPTION_LEN+1];
boolean rt_value=false,exists;
//
// Save PLAYTEMP becuase we'll want to restore it to the way it was
// before the save.
//
// IO_CopyFile(PLAYTEMP_FILE,OLD_PLAYTEMP_FILE);
//
// Save current level -- saves it into PLAYTEMP.
//
SaveLevel(0xff);
// Setup LZH compression
//
LZH_Startup();
MM_GetPtr(&lzh_work_buffer,LZH_WORK_BUFFER_SIZE);
// Write VERSion chunk
//
cksize=sizeof(SavegameInfoText);
write(handle,"VERS",4);
write(handle,&cksize,4);
IO_FarWrite(handle,SavegameInfoText,cksize);
// Write DESC chunk
//
_fmemcpy(nbuff,description,sizeof(nbuff));
cksize=strlen(nbuff)+1;
write(handle,"DESC",4);
write(handle,&cksize,4);
write(handle,nbuff,cksize);
// Write HEAD chunk
//
cksize=0;
write(handle,"HEAD",4);
lseek(handle,4,SEEK_CUR); // leave four bytes for chunk size
WriteIt(true, &gamestate, sizeof(gamestate));
WriteIt(true, &gamestuff, sizeof(gamestuff));
lseek(handle,-(cksize+4),SEEK_CUR);
write(handle,&cksize,4);
lseek(handle,cksize,SEEK_CUR);
// Append PLAYTEMP file to savegame file
//
MakeDestPath(PLAYTEMP_FILE);
if (findfirst(tempPath,&finfo,0))
goto cleanup;
if ((shandle=open(tempPath,O_RDONLY|O_BINARY))==-1)
goto cleanup;
IO_CopyHandle(shandle,handle,-1);
close(shandle);
rt_value=true;
// Clean-up LZH compression
//
cleanup:;
MM_FreePtr(&lzh_work_buffer);
LZH_Shutdown();
NewViewSize(viewsize);
//
// Return PLAYTEMP to original state!
//
// remove(PLAYTEMP_FILE);
// rename(OLD_PLAYTEMP_FILE,PLAYTEMP_FILE);
//
return(rt_value);
}
//--------------------------------------------------------------------------
// LevelInPlaytemp()
//--------------------------------------------------------------------------
boolean LevelInPlaytemp(char levelnum)
{
int handle;
char chunk[5]="LVxx";
boolean rt_value;
// Open PLAYTEMP file
//
MakeDestPath(PLAYTEMP_FILE);
handle=open(tempPath,O_RDONLY|O_BINARY);
// See if level exists in PLAYTEMP file...
//
sprintf(&chunk[2],"%02x",levelnum);
rt_value=FindChunk(handle,chunk);
// Close PLAYTEMP file
//
close(handle);
return(rt_value);
}
//--------------------------------------------------------------------------
// CheckDiskSpace()
//--------------------------------------------------------------------------
boolean CheckDiskSpace(long needed,char far *text,cds_io_type io_type)
{
struct ffblk finfo;
struct diskfree_t dfree;
long avail;
// Figure amount of space free on hard disk and let the gamer know if
// disk space is too low.
//
if (_dos_getdiskfree(0,&dfree))
MAIN_ERROR(CHECKDISK_GDFREE);
avail = (long)dfree.avail_clusters *
dfree.bytes_per_sector *
dfree.sectors_per_cluster;
if (avail < needed)
{
unsigned old_DS=_DS;
switch (io_type)
{
case cds_dos_print:
_DS=FP_SEG(text);
printf("%s",text);
_DS=old_DS;
exit(0);
break;
case cds_menu_print:
case cds_id_print:
WindowX=0; WindowY=16; WindowW=320; WindowH=168;
SD_PlaySound (NOWAYSND);
Message(text);
IN_ClearKeysDown();
IN_Ack();
if (io_type==cds_menu_print)
MenuFadeOut();
break;
}
return(false);
}
return(true);
}
//--------------------------------------------------------------------------
// CleanUpDoors_N_Actors()
//--------------------------------------------------------------------------
void CleanUpDoors_N_Actors(void)
{
char x,y;
objtype *obj;
objtype **actor_ptr;
byte *tile_ptr;
unsigned door;
actor_ptr = (objtype **)actorat;
tile_ptr = (byte *)tilemap;
for (y=0;y<mapheight;y++)
for (x=0;x<mapwidth;x++)
{
if (*tile_ptr & 0x80)
{
// Found a door
//
obj = *actor_ptr;
if ((obj >= objlist) && (obj < &objlist[MAXACTORS]))
{
// Found an actor
// Determine door number...
door = *tile_ptr & 0x3F;
if ((obj->flags & (FL_SOLID|FL_DEADGUY)) == (FL_SOLID|FL_DEADGUY))
obj->flags &= ~(FL_SHOOTABLE | FL_SOLID | FL_FAKE_STATIC);
// Make sure door is open
doorobjlist[door].ticcount = 0;
doorobjlist[door].action = dr_open;
doorposition[door] = 0xffff;
}
}
tile_ptr++;
actor_ptr++;
}
}
//--------------------------------------------------------------------------
// ClearNClose() - Use when changing levels via standard elevator.
//
// - This code doesn't CLEAR the elevator door as originally
// planned because, actors were coded to stay out of the
// elevator doorway.
//
//--------------------------------------------------------------------------
void ClearNClose()
{
char x,y,tx=0,ty=0,px=player->x>>TILESHIFT,py=player->y>>TILESHIFT;
// Locate the door.
//
for (x=-1; x<2 && !tx; x+=2)
for (y=-1; y<2; y+=2)
if (tilemap[px+x][py+y] & 0x80)
{
tx=px+x;
ty=py+y;
break;
}
// Close the door!
//
if (tx)
{
char doornum=tilemap[tx][ty]&63;
doorobjlist[doornum].action = dr_closed; // this door is closed!
doorposition[doornum]=0; // draw it closed!
(unsigned)actorat[tx][ty] = doornum | 0x80; // make it solid!
}
}
//--------------------------------------------------------------------------
// CycleColors()
//--------------------------------------------------------------------------
void CycleColors()
{
#define NUM_RANGES 5
#define CRNG_LOW 0xf0
#define CRNG_HIGH 0xfe
#define CRNG_SIZE (CRNG_HIGH-CRNG_LOW+1)
static CycleInfo crng[NUM_RANGES] = {{7,0,0xf0,0xf1},
{15,0,0xf2,0xf3},
{30,0,0xf4,0xf5},
{10,0,0xf6,0xf9},
{12,0,0xfa,0xfe},
};
byte loop,cbuffer[CRNG_SIZE][3];
boolean changes=false;
for (loop=0; loop<NUM_RANGES; loop++)
{
CycleInfo *c=&crng[loop];
if (tics >= c->delay_count)
{
byte temp[3],first,last,numregs;
if (!changes)
{
VL_GetPalette(CRNG_LOW,CRNG_SIZE,(byte far *)cbuffer);
changes=true;
}
first = c->firstreg-CRNG_LOW;
numregs = c->lastreg-c->firstreg; // is one less than in range
last = first+numregs;
memcpy(temp,cbuffer[last],3);
memmove(cbuffer[first+1],cbuffer[first],numregs*3);
memcpy(cbuffer[first],temp,3);
c->delay_count = c->init_delay;
}
else
c->delay_count -= tics;
}
if (changes)
VL_SetPalette(CRNG_LOW,CRNG_SIZE,(byte far *)cbuffer);
else
VW_WaitVBL(1);
}
//===========================================================================
/*
==========================
=
= ShutdownId
=
= Shuts down all ID_?? managers
=
==========================
*/
void ShutdownId (void)
{
US_Shutdown ();
SD_Shutdown ();
PM_Shutdown ();
IN_Shutdown ();
VW_Shutdown ();
CA_Shutdown ();
MM_Shutdown ();
}
//===========================================================================
/*
====================
=
= CalcProjection
=
= Uses focallength
=
====================
*/
void CalcProjection (long focal)
{
int i;
long intang;
float angle;
double tang;
double planedist;
double globinhalf;
int 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 = (long)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;
}
//===========================================================================
//--------------------------------------------------------------------------
// DoMovie()
//--------------------------------------------------------------------------
boolean DoMovie(movie_t movie, memptr palette)
{
boolean ReturnVal;
// StopMusic();
SD_StopSound();
ClearMemory();
UnCacheLump(STARTFONT,STARTFONT+NUMFONT);
CA_LoadAllSounds();
if (palette)
Movies[movie].palette = palette;
else
Movies[movie].palette = (memptr)FP_SEG(&vgapal);
ReturnVal = MOVIE_Play(&Movies[movie]);
SD_StopSound();
ClearMemory();
LoadFonts();
return(ReturnVal);
}
//===========================================================================
/*
=================
=
= MS_CheckParm
=
=================
*/
boolean MS_CheckParm (char far *check)
{
int i;
char *parm;
for (i = 1;i<_argc;i++)
{
parm = _argv[i];
while ( !isalpha(*parm) ) // skip - / \ etc.. in front of parm
if (!*parm++)
break; // hit end of string without an alphanum
if ( !_fstricmp(check,parm) )
return true;
}
return false;
}
//===========================================================================
//--------------------------------------------------------------------------
// LoadFonts()
//--------------------------------------------------------------------------
void LoadFonts(void)
{
CA_CacheGrChunk(STARTFONT+4);
MM_SetLock (&grsegs[STARTFONT+4],true);
CA_CacheGrChunk(STARTFONT+2);
MM_SetLock (&grsegs[STARTFONT+2],true);
}
//===========================================================================
/*
==========================
=
= SetViewSize
=
==========================
*/
boolean SetViewSize (unsigned width, unsigned 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+TOP_STRIP_HEIGHT)/2*SCREENWIDTH+(320-viewwidth)/8);
//
// calculate trace angles and projection constants
//
CalcProjection (FOCALLENGTH);
//
// build all needed compiled scalers
//
SetupScaling (viewwidth*1.5);
view_xl=0;
view_xh=view_xl+viewwidth-1;
view_yl=0;
view_yh=view_yl+viewheight-1;
return true;
}
void ShowViewSize (int width)
{
int oldwidth,oldheight;
oldwidth = viewwidth;
oldheight = viewheight;
viewwidth = width*16;
viewheight = width*16*HEIGHTRATIO;
VWB_Bar (0,TOP_STRIP_HEIGHT,320,200-STATUSLINES-TOP_STRIP_HEIGHT,BORDER_MED_COLOR);
// VWB_Bar (0,0,320,200-STATUSLINES,BORDER_MED_COLOR);
DrawPlayBorder ();
viewheight = oldheight;
viewwidth = oldwidth;
}
void NewViewSize (int width)
{
CA_UpLevel ();
MM_SortMem ();
viewsize = width;
while (1)
{
if (SetViewSize (width*16,width*16*HEIGHTRATIO))
break;
width--;
};
CA_DownLevel ();
}
//===========================================================================
/*
==========================
=
= Quit
=
==========================
*/
void Quit (char *error,...)
{
unsigned finscreen;
memptr diz;
char far *screen;
unsigned unit,err;
va_list ap;
va_start(ap,error);
MakeDestPath(PLAYTEMP_FILE);
remove(tempPath);
ClearMemory ();
if (!*error)
{
#if GAME_VERSION != SHAREWARE_VERSION
if (gamestate.flags & GS_BAD_DIZ_FILE)
{
char far *end;
CA_CacheGrChunk(DIZ_ERR_TEXT);
diz = grsegs[DIZ_ERR_TEXT];
end=_fstrstr(diz,"^XX");
*end=0;
}
else
if (!IsA386)
{
CA_CacheGrChunk (NO386SCREEN);
screen = MK_FP(grsegs[NO386SCREEN],7);
}
// else
#endif
#if 0
{
CA_CacheGrChunk (ORDERSCREEN);
screen = MK_FP(grsegs[ORDERSCREEN],0);
}
#endif
}
else
{
CA_CacheGrChunk (ERRORSCREEN);
screen = MK_FP(grsegs[ERRORSCREEN],7);
}
WriteConfig ();
ShutdownId ();
if (error && *error)
{
FILE *fp;
unit=va_arg(ap,unsigned);
err=va_arg(ap,unsigned);
// movedata ((unsigned)screen,7,0xb800,0,7*160);
_fmemcpy(MK_FP(0xB800,0), screen, 7*160);
textcolor(14);
textbackground(4);
gotoxy (10,4);
cprintf(error,unit,err);
gotoxy (65-strlen(__VERSION__),2);
cprintf(" Ver:%s ",__VERSION__);
gotoxy (1,8);
MakeDestPath("BS_VSI.ERR");
fp = fopen(tempPath,"wb");
fprintf(fp,"$%02x%02x",unit,err);
if (fp)
fclose(fp);
exit(1);
}
#if 0
if (!error || !(*error))
{
unsigned far *clear = MK_FP(0xb800,23*80*2);
unsigned len = 0;
clrscr();
#if GAME_VERSION != SHAREWARE_VERSION
if (gamestate.flags & GS_BAD_DIZ_FILE)
fprint(diz);
else
#endif
{
// movedata ((unsigned)screen,0,0xb800,0,4000);
_fmemcpy(MK_FP(0xB800,0),screen,4000);
// Far mem set (WORD)! - This is STUPID! Borland SUCKS!
while (len != 80*2)
{
*clear++ = 0x700;
len++;
}
gotoxy (1,24);
}
}
#endif
va_end(ap);
exit(0);
}
//===========================================================================
/*
=====================
=
= DemoLoop
=
=====================
*/
void DemoLoop (void)
{
int i,level;
int LastDemo=0;
boolean breakit;
unsigned old_bufferofs;
while (1)
{
playstate = ex_title;
if (!screenfaded)
VW_FadeOut();
VL_SetPaletteIntensity(0,255,&vgapal,0);
while (!(gamestate.flags & GS_NOWAIT))
{
extern boolean sqActive;
// Start music when coming from menu...
//
if (!sqActive)
{
// Load and start music
//
CA_CacheAudioChunk(STARTMUSIC+TITLE_LOOP_MUSIC);
SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC+TITLE_LOOP_MUSIC]);
}
//
// title page
//
#if !SKIP_TITLE_AND_CREDITS
breakit = false;
CA_CacheScreen(TITLE1PIC);
CA_CacheGrChunk(TITLEPALETTE);
old_bufferofs = bufferofs;
bufferofs=displayofs;
VW_Bar(0,0,320,200,0);
bufferofs=old_bufferofs;
VL_SetPalette (0,256,grsegs[TITLEPALETTE]);
VL_SetPaletteIntensity(0,255,grsegs[TITLEPALETTE],0);
fontnumber = 2;
PrintX = WindowX = 270;
PrintY = WindowY = 179;
WindowW = 29;
WindowH = 8;
VWB_Bar(WindowX,WindowY-1,WindowW,WindowH,VERSION_TEXT_BKCOLOR);
SETFONTCOLOR(VERSION_TEXT_COLOR, VERSION_TEXT_BKCOLOR);
US_Print(__VERSION__);
VW_UpdateScreen();
VL_FadeIn(0,255,grsegs[TITLEPALETTE],30);
UNCACHEGRCHUNK(TITLEPALETTE);
if (IN_UserInput(TickBase*6))
breakit= true;
// Cache screen 2 with Warnings and Copyrights
CA_CacheScreen(TITLE2PIC);
fontnumber = 2;
PrintX = WindowX = 270;
PrintY = WindowY = 179;
WindowW = 29;
WindowH = 8;
VWB_Bar(WindowX,WindowY-1,WindowW,WindowH,VERSION_TEXT_BKCOLOR);
SETFONTCOLOR(VERSION_TEXT_COLOR, VERSION_TEXT_BKCOLOR);
US_Print(__VERSION__);
// Fizzle whole screen incase of any last minute changes needed
// on title intro.
FizzleFade(bufferofs,displayofs,320,200,70,false);
IN_UserInput(TickBase*2);
if (breakit || IN_UserInput(TickBase*6))
break;
VW_FadeOut();
//
// credits page
//
DrawCreditsPage();
VW_UpdateScreen();
VW_FadeIn();
if (IN_UserInput(TickBase*6))
break;
VW_FadeOut();
#endif
//
// demo
//
#if DEMOS_ENABLED
#if IN_DEVELOPMENT
if (!MS_CheckParm("recdemo"))
#endif
PlayDemo(LastDemo++%6);
if (playstate == ex_abort)
break;
else
{
// Start music when coming from menu...
//
if (!sqActive)
// if (!SD_MusicPlaying())
{
// Load and start music
//
CA_CacheAudioChunk(STARTMUSIC+TITLE_LOOP_MUSIC);
SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC+TITLE_LOOP_MUSIC]);
}
}
#endif
//
// high scores
//
#if !SKIP_TITLE_AND_CREDITS
CA_CacheScreen (BACKGROUND_SCREENPIC);
DrawHighScores ();
VW_UpdateScreen ();
VW_FadeIn ();
if (IN_UserInput(TickBase*9))
break;
VW_FadeOut();
#endif
}
if (audiosegs[STARTMUSIC+TITLE_LOOP_MUSIC])
MM_FreePtr((memptr *)&audiosegs[STARTMUSIC+TITLE_LOOP_MUSIC]);
if (!screenfaded)
VW_FadeOut();
#ifdef DEMOS_EXTERN
if (MS_CheckParm("recdemo"))
RecordDemo ();
else
#endif
{
#if IN_DEVELOPMENT || TECH_SUPPORT_VERSION
if (gamestate.flags & GS_QUICKRUN)
{
ReadGameNames();
CA_LoadAllSounds();
NewGame(2,gamestate.episode);
startgame = true;
}
else
#endif
US_ControlPanel (0);
}
if (startgame || loadedgame)
GameLoop ();
}
}
//-------------------------------------------------------------------------
// DrawCreditsPage()
//-------------------------------------------------------------------------
void DrawCreditsPage()
{
PresenterInfo pi;
CA_CacheScreen(BACKGROUND_SCREENPIC);
memset(&pi,0,sizeof(pi));
pi.flags = TPF_CACHE_NO_GFX;
pi.xl=38;
pi.yl=28;
pi.xh=281;
pi.yh=170;
pi.bgcolor = 2;
pi.ltcolor = BORDER_HI_COLOR;
fontcolor = BORDER_TEXT_COLOR;
pi.shcolor = pi.dkcolor = 0;
pi.fontnumber=fontnumber;
#ifdef ID_CACHE_CREDITS
TP_LoadScript(NULL,&pi,CREDITSTEXT);
#else
TP_LoadScript("CREDITS.TXT",&pi,0);
#endif
TP_Presenter(&pi);
}
//===========================================================================
extern void JM_FREE_START();
extern void JM_FREE_END();
/*
==========================
=
= main
=
==========================
*/
//char *nosprtxt[] = {"nospr",nil};
#if IN_DEVELOPMENT || TECH_SUPPORT_VERSION
short starting_episode=0,starting_level=0,starting_difficulty=2;
#endif
short debug_value=0;
void main (void)
{
#if IN_DEVELOPMENT
MakeDestPath(ERROR_LOG);
remove(tempPath);
#endif
MakeDestPath(PLAYTEMP_FILE);
remove(tempPath);
freed_main();
#if FREE_FUNCTIONS
UseFunc((char huge *)JM_FREE_START,(char huge *)JM_FREE_END);
UseFunc((char huge *)JM_FREE_DATA_START,(char huge *)JM_FREE_DATA_END);
#endif
DemoLoop();
Quit(NULL);
}
#if FREE_FUNCTIONS
//-------------------------------------------------------------------------
// UseFunc()
//-------------------------------------------------------------------------
unsigned UseFunc(char huge *first, char huge *next)
{
unsigned start,end;
unsigned pars;
first += 15;
next++;
next--;
start = FP_SEG(first);
end = FP_SEG(next);
if (!FP_OFF(next))
end--;
pars = end - start - 1;
_fmemset(MK_FP(start,0),0,pars*16);
MML_UseSpace(start,pars);
return(pars);
}
#endif
//-------------------------------------------------------------------------
// fprint()
//-------------------------------------------------------------------------
void fprint(char far *text)
{
while (*text)
printf("%c",*text++);
}
//-------------------------------------------------------------------------
// InitDestPath()
//-------------------------------------------------------------------------
void InitDestPath(void)
{
char *ptr;
#pragma warn -pia
if (ptr=getenv("APOGEECD"))
{
struct ffblk ffblk;
short len;
len = _fstrlen(ptr);
if (len > MAX_DEST_PATH_LEN)
{
printf("\nAPOGEECD path too long.\n");
exit(0);
}
_fstrcpy(destPath,ptr);
if (destPath[len-1] == '\\')
destPath[len-1]=0;
if (findfirst(destPath,&ffblk,FA_DIREC) == -1)
{
printf("\nAPOGEECD directory not found.\n");
exit(0);
}
_fstrcat(destPath,"\\");
}
else
_fstrcpy(destPath,"");
#pragma warn +pia
}
//-------------------------------------------------------------------------
// MakeDestPath()
//-------------------------------------------------------------------------
void MakeDestPath(char far *file)
{
_fstrcpy(tempPath,destPath);
_fstrcat(tempPath,file);
}
#if IN_DEVELOPMENT
//-------------------------------------------------------------------------
// ShowMemory()
//-------------------------------------------------------------------------
void ShowMemory(void)
{
long psize,size;
size = MM_TotalFree();
psize = MM_LargestAvail();
mprintf("Mem free: %ld %ld\n",size,psize);
}
#endif