ack3d/fdemo/FDEMO.C
Gered 1b11c42c1d changes from borland sources. including disabling bg music
i'm convinced that the modplayer doesn't work as-is. start/stop of bg
music was commented out in the newer borland sources, and neither the
borland 'nor watcom fdemo executable on the book's cd ever played
bg music for me. enabling it (with the mod file present) causes some
crashes.
2019-11-02 14:52:54 -04:00

2074 lines
41 KiB
C

// Example using Watcom FLAT model Animation Construction Kit
// Started: 01/02/94
// Author: Lary Myers
// Module: FDEMO.C
// (c) CopyRight 1994 All Rights Reserved
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
#include <string.h>
#include <dos.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include "ack3d.h"
#include "ackeng.h"
#include "ackext.h"
#include "kit.h"
#include "modplay.h"
#define DEMO_RESOURCE 69
#define HAND1_RESOURCE 135
#define HAND2_RESOURCE 136
#define KEYBD 0x9 /* INTERRUPT 9 */
#define RIGHT_ARROW_KEY 77
#define UP_ARROW_KEY 72
#define LEFT_ARROW_KEY 75
#define DOWN_ARROW_KEY 80
#define MINUS_KEY 74
#define PLUS_KEY 78
#define NUMBER_5_KEY 76
#define ESCAPE_KEY 1
#define PGUP_KEY 73
#define PGDN_KEY 81
#define B_KEY 48
#define C_KEY 46
#define F_KEY 33
#define I_KEY 23
#define R_KEY 19
#define S_KEY 31
#define W_KEY 17
#define NUM_1_KEY 2
#define NUM_2_KEY 3
#define NUM_3_KEY 4
#define NUM_4_KEY 5
#define NUM_5_KEY 6
#define NUM_6_KEY 7
#define NUM_7_KEY 8
#define NUM_8_KEY 9
#define NUM_9_KEY 10
typedef struct {
int mdx;
int mdy;
int mButtons;
} MOUSE;
#define MAX_AMOUNT 64
#define MAX_MAG_AMOUNT 64
#define MAX_STR_AMOUNT 128
#define MAX_STR_HALF_AMOUNT 64
extern long AckMemUsed; // Running total of memory used
extern short AckDisplayErrors; // 1 = sw to text mode and display error
extern long mFactor;
extern long dFactor;
extern UCHAR colordat[];
ACKENG *ae;
ColorRange ranges[64] = {
16,15,
32,16,
48,16,
64,16,
80,16,
96,8,
104,8,
112,8,
120,8,
128,8,
136,8,
144,8,
152,8,
160,8,
168,8,
176,8,
184,16,
200,16,
216,16,
232,16,
248,16,
0,0
};
int HaveMouse;
short FlashIndex;
short FlashCount;
UCHAR *bmFlash[2];
UCHAR *bmFlash1[2];
char LineBuffer[200];
char *smFont;
UCHAR FontTransparent;
UCHAR FontColor;
UCHAR TextBGcolor;
int Throwing;
int Shooting;
int ShutDownFlag;
short MagAmount;
short StrAmount;
int ShowHitFlag;
int MapResource;
int PalResource;
int ResScreenBack;
int ResScrollBack;
void *BGmusic;
UCHAR *DemoPtr;
short Demoht;
short Demowt;
UCHAR *pHand1;
short Handw1;
short Handh1;
UCHAR *pHand2;
short Handw2;
short Handh2;
long ObjCounter[64];
short LastObjectIndex;
//-----------------------------------------------------------------------------
// Globals used by the frame counting routines
//-----------------------------------------------------------------------------
volatile short framespersec = 0;
volatile short cframes=0, count=0, ticks=0;
char *ErrorMsgs[] = {
"ERR_BADFILE ",
"ERR_BADCOMMAND ",
"ERR_BADOBJNUMBER ",
"ERR_BADSYNTAX ",
"ERR_LOADINGBITMAP",
"ERR_BADDIRECTION ",
"ERR_BADSTARTX ",
"ERR_BADSTARTY ",
"ERR_BADANGLE ",
"ERR_BADMAPFILE ",
"ERR_READINGMAP ",
"ERR_BADPICNAME ",
"ERR_INVALIDFORM ",
"ERR_NOPBM ",
"ERR_BADPICFILE ",
"ERR_NOMEMORY ",
"ERR_BADPALFILE ",
"ERR_BADWINDOWSIZE",
"ERR_TOMANYVIEWS ",
"ERR_BADOBJECTNUM ",
"ERR_BADOBJTYPE "
};
void AckRegisterStructure(ACKENG *ae);
void AckSpeedUp(short);
void AckSlowDown(void);
//=============================================================================
//
//=============================================================================
/* MOD loading routines */
void *MODLoadModule(char *Path)
{
int handle;
unsigned modsize;
void *modfile = NULL;
if ((handle = open(Path,O_RDONLY | O_BINARY)) != -1) {
modsize = lseek(handle,0L,SEEK_END);
lseek(handle,0L,SEEK_SET);
if ((modfile=(void*)AckMalloc(modsize)) != NULL) {
if (read(handle,modfile,modsize) != modsize) {
AckFree(modfile);
modfile = NULL;
}
}
close(handle);
}
return modfile;
}
//=============================================================================
//
//=============================================================================
void MODFreeModule(void *Module)
{
if (Module) AckFree(Module);
}
//=============================================================================
//
//=============================================================================
short StartBGmusic(void)
{
if ((BGmusic = MODLoadModule("SAHARA.MOD")) == NULL)
return(-1);
if (MODPlayModule(BGmusic,5,22000,0x220,5,1))
return(-2);
return(0);
}
//=============================================================================
//
//=============================================================================
void EndBGmusic(void)
{
if (BGmusic == NULL)
return;
MODStopModule();
MODFreeModule(BGmusic);
}
//=============================================================================
//
//=============================================================================
short LoadSmallFont(void)
{
short ht,wt;
int len;
ht = 2;
smFont = AckReadiff((UCHAR *)ht);
if (smFont == NULL)
return(-1);
ht = (*(short *)smFont);
wt = (*(short *)&smFont[2]);
len = ht * wt;
memmove(smFont,&smFont[4],len);
return(0);
}
//=============================================================================
//
//=============================================================================
void smWriteChar(short x,short y,unsigned char ch)
{
int FontOffset,VidOffset;
int row,col;
UCHAR *Video;
VidOffset = (y * 320) + x;
Video = (UCHAR *)0xA0000;
Video += VidOffset;
FontOffset = ((ch-32) * 5);
if (FontTransparent)
Video = ae->ScreenBuffer + VidOffset;
for (row = 0; row < 5; row++)
{
if (!FontTransparent)
{
Video[0] = TextBGcolor;
Video[1] = TextBGcolor;
Video[2] = TextBGcolor;
Video[3] = TextBGcolor;
}
if (smFont[FontOffset])
Video[0] = FontColor;
if (smFont[FontOffset+1])
Video[1] = FontColor;
if (smFont[FontOffset+2])
Video[2] = FontColor;
if (smFont[FontOffset+3])
Video[3] = FontColor;
Video += 320;
FontOffset += 294;
}
}
//=============================================================================
//
//=============================================================================
short smWriteString(short x,short y,char *s)
{
short OrgX;
char ch;
OrgX = x;
while (*s)
{
ch = *s++;
if (ch == 10)
{
x = OrgX;
y += 8;
continue;
}
if (ch < ' ')
continue;
ch = toupper(ch);
smWriteChar(x,y,ch);
x += 5;
}
return(y);
}
//=============================================================================
//
//=============================================================================
void smWriteHUD(short x,short y,UCHAR color,char *s)
{
FontTransparent = 1;
FontColor = color;
smWriteString(x,y,s);
FontTransparent = 0;
FontColor = 15;
}
//=============================================================================
// Checks mouse movement and calculates delta movement in X and Y directions
//=============================================================================
void CheckMouse(MOUSE *m)
{
int dx,dy;
short x,y,buttons;
buttons = ReadMouseCursor(&y,&x);
dx = x - 160;
dy = y - 120;
m->mButtons = buttons;
SetMouseCursor(120,160);
if (abs(dy) > 10 && abs(dx) < 32)
dx >>= 2;
m->mdx = dx;
m->mdy = dy;
}
//=============================================================================
// Reads a text line from the resource file
//=============================================================================
int ReadLine(void)
{
int len;
char ch;
len = 0;
while (len < 200)
{
if (read(rsHandle,&LineBuffer[len],1) != 1)
break;
ch = LineBuffer[len];
if (ch == 10)
continue;
if (ch == 13)
break;
len++;
}
LineBuffer[len] = '\0';
return(len);
}
//=============================================================================
// Skips to the next parameter in a text line
//=============================================================================
char *GetNextParm(char *s)
{
char ch;
while (*s)
{
ch = *s++;
if (ch == ',')
{
while (*s)
{
ch = *s;
if (ch != ',' && ch != ' ' && ch != '\t')
return(s);
s++;
}
return(NULL);
}
}
return(NULL);
}
//=============================================================================
// Loads a wall bitmap specified in info file
//=============================================================================
int LoadWall(void)
{
int wnum,rnum,result;
long pos;
char *lb;
lb = LineBuffer; // Info file buffer
wnum = atoi(lb); // Wall number to load into
lb = GetNextParm(lb);
if (lb == NULL)
return(-1);
rnum = atoi(lb); // Resource number
pos = lseek(rsHandle,0L,SEEK_CUR);
result = AckLoadWall(ae,wnum,(char *)rnum);
lseek(rsHandle,pos,SEEK_SET);
return(result);
}
//=============================================================================
// Loads an object bitmap specified in info file
//=============================================================================
int LoadObject(void)
{
int onum,rnum,result;
long pos;
char *lb;
lb = LineBuffer;
onum = atoi(lb); // Object bitmap number
lb = GetNextParm(lb);
if (lb == NULL)
return(-2);
rnum = atoi(lb); // Resource number
pos = lseek(rsHandle,0L,SEEK_CUR);
result = AckLoadObject(ae,onum,(char *)rnum);
lseek(rsHandle,pos,SEEK_SET);
return(result);
}
//=============================================================================
// Skip any leading spaces in the string
// NOTE: Actually modifies the string passed!
//=============================================================================
char *SkipSpaces(char *s)
{
while (*s == ' ' || *s == '\t' || *s == ',')
strcpy(s,&s[1]);
return(s);
}
//=============================================================================
// Creates and object of the desired style
//=============================================================================
int CreateObject(void)
{
int onum,vnum,speed;
short result,oType;
short NumViews,bmPerView;
UINT flags;
char *lb;
OBJSEQ os;
lb = LineBuffer;
if (!strnicmp(lb,"NUMBER:",7))
{
lb = &lb[7];
onum = atoi(lb);
if (onum < 1 || onum > MAX_OBJECTS)
return(-3);
result = AckCreateObject(ae,onum);
if (result)
return(result);
LastObjectIndex = onum;
lb = GetNextParm(lb);
if (lb == NULL)
return(-4);
ae->ObjList[onum]->Speed = atoi(lb);
return(0);
}
onum = LastObjectIndex; // Object number
oType = 0;
if (!strnicmp(lb,"CREATE:",7))
{
oType = NO_CREATE;
lb = &lb[7];
}
if (!strnicmp(lb,"DESTROY:",8))
{
oType = NO_DESTROY;
lb = &lb[8];
}
if (!strnicmp(lb,"WALK:",5))
{
oType = NO_WALK;
lb = &lb[5];
}
if (!strnicmp(lb,"ATTACK:",7))
{
oType = NO_ATTACK;
lb = &lb[7];
}
if (!strnicmp(lb,"INTERACT:",9))
{
oType = NO_INTERACT;
lb = &lb[9];
}
if (!oType)
return(-5);
lb = SkipSpaces(lb);
if (lb == NULL)
return(-6);
flags = 0;
strupr(lb);
if (strstr(lb,"ANIMATE") != NULL)
flags |= OF_ANIMATE;
if (strstr(lb,"MOVEABLE") != NULL)
flags |= OF_MOVEABLE;
if (strstr(lb,"PASSABLE") != NULL)
flags |= OF_PASSABLE;
if (strstr(lb,"MULTIVIEW") != NULL)
flags |= OF_MULTIVIEW;
if (strstr(lb,"SHOWONCE") != NULL)
flags |= OF_ANIMONCE;
lb = GetNextParm(lb);
if (lb == NULL)
return(-5);
NumViews = atoi(lb);
if (NumViews < 1)
return(-6);
lb = GetNextParm(lb);
if (lb == NULL)
return(-7);
bmPerView = atoi(lb);
if (bmPerView < 1)
return(-7);
vnum = NumViews * bmPerView;
if (vnum > MAX_OBJ_BITMAPS)
return(-8);
lb = GetNextParm(lb);
if (lb == NULL)
return(-9);
vnum = 0;
while (lb != NULL && vnum < MAX_OBJ_BITMAPS)
{
os.bitmaps[vnum++] = atoi(lb);
lb = GetNextParm(lb);
}
os.bmBitmapsPerView = bmPerView;
os.flags = flags;
os.MaxBitmaps = bmPerView;
os.bmSides = NumViews;
result = AckSetupObject(ae,onum,oType,&os);
return(result);
}
//=============================================================================
// Reads the ASCII info file and processes the commands.
//=============================================================================
int ProcessInfoFile(short QuietFlag)
{
int result;
int mode;
long pos;
char *lb;
// Position to start of info file within resource file
lseek(rsHandle,rbaTable[0],SEEK_SET);
mode = result = 0;
while (!result)
{
if (!ReadLine())
continue;
if (*LineBuffer == ';')
continue;
if (!strnicmp(LineBuffer,"END:",4))
break;
if (!QuietFlag)
printf(".");
switch (mode)
{
case 1: // Read walls
if (!strnicmp(LineBuffer,"LOADTYPE:",9))
{
ae->bmLoadType = atoi(&LineBuffer[9]); // Sets for GIF or BBM
break;
}
if (!strnicmp(LineBuffer,"ENDBITMAPS:",11))
mode = 4;
else
result = LoadWall();
break;
case 2: // Object bitmaps
if (!strnicmp(LineBuffer,"LOADTYPE:",9)) // Sets for GIF or BBM
{
ae->bmLoadType = atoi(&LineBuffer[9]);
break;
}
if (!strnicmp(LineBuffer,"ENDBITMAPS:",11))
mode = 5;
else
result = LoadObject();
break;
case 3: // Create Object
if (!strnicmp(LineBuffer,"ENDDESC:",8))
mode = 5;
else
result = CreateObject();
break;
case 4: // Walls topic
if (!strnicmp(LineBuffer,"BITMAPS:",8))
mode = 1;
if (!strnicmp(LineBuffer,"ENDWALLS:",9))
mode = 0;
break;
case 5: // Objects topic
if (!strnicmp(LineBuffer,"BITMAPS:",8))
mode = 2;
if (!strnicmp(LineBuffer,"OBJDESC:",8))
mode = 3;
if (!strnicmp(LineBuffer,"ENDOBJECTS:",11))
mode = 0;
break;
default:
if (!strnicmp(LineBuffer,"WALLS:",6))
{
mode = 4;
break;
}
if (!strnicmp(LineBuffer,"OBJECTS:",8))
{
mode = 5;
break;
}
if (!strnicmp(LineBuffer,"MAPFILE:",8))
{
MapResource = atoi(&LineBuffer[8]);
pos = lseek(rsHandle,0L,SEEK_CUR);
result = AckReadMapFile(ae,(char *)MapResource);
lseek(rsHandle,pos,SEEK_SET);
break;
}
if (!strnicmp(LineBuffer,"PALFILE:",8))
{
PalResource = atoi(&LineBuffer[8]);
break;
}
if (!strnicmp(LineBuffer,"XPLAYER:",8))
{
ae->xPlayer = atoi(&LineBuffer[8]);
break;
}
if (!strnicmp(LineBuffer,"YPLAYER:",8))
{
ae->yPlayer = atoi(&LineBuffer[8]);
break;
}
if (!strnicmp(LineBuffer,"PLAYERANGLE:",12))
{
ae->PlayerAngle = atoi(&LineBuffer[12]);
break;
}
if (!strnicmp(LineBuffer,"SCREENBACK:",11))
{
ResScreenBack = atoi(&LineBuffer[11]);
break;
}
if (!strnicmp(LineBuffer,"SCROLLBACK:",11))
{
ResScrollBack = atoi(&LineBuffer[11]);
break;
}
if (!strnicmp(LineBuffer,"TOPCOLOR:",9))
{
ae->TopColor = atoi(&LineBuffer[9]);
break;
}
if (!strnicmp(LineBuffer,"BOTTOMCOLOR:",12))
{
ae->BottomColor = atoi(&LineBuffer[12]);
break;
}
if (!strnicmp(LineBuffer,"SHADING:",8))
{
strupr(LineBuffer);
if (strstr(&LineBuffer[8],"OFF") != NULL)
ae->LightFlag = SHADING_OFF;
else
ae->LightFlag = SHADING_ON;
break;
}
if (!strnicmp(LineBuffer,"FLOORS:",7))
{
strupr(LineBuffer);
if (strstr(&LineBuffer[7],"OFF") != NULL)
ae->SysFlags |= SYS_SOLID_FLOOR;
else
{
ae->SysFlags &= ~SYS_SOLID_FLOOR;
}
break;
}
if (!strnicmp(LineBuffer,"RESOLUTION:",11))
{
Resolution = atoi(&LineBuffer[11]);
break;
}
if (!strnicmp(LineBuffer,"LOADTYPE:",9))
{
ae->bmLoadType = atoi(&LineBuffer[9]); // Sets for GIF or BBM
break;
}
break;
}
}
if (!result)
{
result = AckCreateObject(ae,0); // Create a dummy object for later
if (!result)
ae->ObjList[0]->Active = 0; // Turn off checking the object
}
if (!QuietFlag)
printf("done\n");
return(result);
}
//=============================================================================
// Quick routine to display a bitmap into the desired buffer. Handles
// transparent colors. Currently used to display the ACK3D Demo bitmap.
//=============================================================================
void ShowBitmap(short x,short y,UCHAR *dst,short ht,short wt,UCHAR *bm)
{
int offset,col;
short endy;
UCHAR ch;
offset = (y*320) + x;
dst += offset;
endy = ae->WinEndY + 2;
while (ht-- > 0 && y++ <= endy)
{
for (col = 0; col < wt; col++)
{
ch = *bm++;
if (ch)
dst[col] = ch;
}
dst += 320;
}
}
//=============================================================================
//
//=============================================================================
void LoadDemoBitmap(void)
{
UCHAR *d;
DemoPtr = AckReadiff((char *)DEMO_RESOURCE);
if (DemoPtr == NULL)
return;
d = DemoPtr;
Demowt = (*(short *)d);
d += 2;
Demoht = (*(short *)d);
pHand1 = AckReadiff((char *)HAND1_RESOURCE);
if (pHand1 == NULL)
return;
d = pHand1;
Handw1 = (*(short *)d);
d += 2;
Handh1 = (*(short *)d);
pHand2 = AckReadiff((char *)HAND2_RESOURCE);
if (pHand2 == NULL)
return;
d = pHand2;
Handw2 = (*(short *)d);
d += 2;
Handh2 = (*(short *)d);
}
//=============================================================================
//
//=============================================================================
short Initialize(short iFlag)
{
short i,bnum;
if (MouseInstalled() != -1)
{
printf("Mouse is required to run.\n");
return(1);
}
ae = AckMalloc(sizeof(ACKENG));
if (ae == NULL)
{
printf("Unable to get required memory.\n");
return(2);
}
memset(ae,0,sizeof(ACKENG));
ae->WinStartX = 20;
ae->WinEndX = 299;
ae->WinStartY = 0;
ae->WinEndY = 156;
// ae->WinStartX = 0;
// ae->WinEndX = 319;
// ae->WinStartY = 0;
// ae->WinEndY = 156;
ae->LightFlag = SHADING_OFF;
ae->xPlayer = 192;
ae->yPlayer = 640;
ae->PlayerAngle = 0;
ae->TopColor = 0;
ae->BottomColor = 24;
ae->DoorSpeed = 6;
ae->NonSecretCode = 1;
ae->SysFlags |= SYS_SOLID_BACK;
if (iFlag & 1)
{
ae->SysFlags |= SYS_SINGLE_BMP;
ae->FloorBitmap = 33;
ae->CeilBitmap = 45;
}
printf("Initializing.\n");
i = AckOpenResource("kit.ovl");
if (i)
{
printf("Unable to open resource KIT.OVL\n");
return(3);
}
i = LoadSmallFont();
if (i)
{
printf("Error loading font BBM.\n");
return(5);
}
i = AckInitialize(ae);
AckCloseResource();
if (i)
{
printf("Error initializing. Error code: %d\n",i);
return(3);
}
printf("Processing DTF file ");
i = AckOpenResource("pics.dtf");
if (i)
{
printf("Unable to open resource PICS.DTF\n");
return(3);
}
i = ProcessInfoFile(0);
if (i)
{
printf("Error reading INF file.\n");
if (i > 100 && i < 121)
printf("Last error was %s\n",ErrorMsgs[i-100]);
else
printf("Error code: %d\n",i);
printf("Line was: \"%s\"\n",LineBuffer);
return(4);
}
bmFlash[0] = ae->bMaps[4];
bmFlash[1] = ae->bMaps[8];
bmFlash1[0] = ae->bMaps[24];
bmFlash1[1] = ae->bMaps[2];
FlashIndex = 0;
LoadDemoBitmap();
return(0);
}
//=============================================================================
// Loads and displays the full screen picture and sets the palette to the one
// loaded with the picture.
//=============================================================================
short LoadAndShow(char *fName)
{
short i,j;
UINT pos,begpos;
UCHAR pMask;
UCHAR *buf,*bPtr;
UCHAR *Video;
buf = AckReadiff(fName);
if (buf == NULL)
return(-1);
Video = (char *)0xA0000;
memmove(Video,&buf[4],64000);
AckSetPalette(colordat);
AckFree(buf);
return(0);
}
//=============================================================================
// Loads a background image (mountains) and processes the image into the
// separate slices for use at display time. Currently a background image
// can be 640 columns wide. This number can be made dynamic if needbe and would
// need to be changed in the routine below and in the DrawBackground routine
// in the ACK engine.
//=============================================================================
int LoadBackDrop(void)
{
int result;
int i,j,pos;
UCHAR *bPtr;
UCHAR *aPtr;
result = 0;
if (ResScrollBack)
{
printf("Loading background image....\n");
bPtr = AckReadiff((char *)ResScrollBack);
printf("Processing background image.\n");
if (bPtr != NULL)
{
for (i = 0; i < 320; i++)
{
pos = i + 4;
aPtr = BackArray[i];
for (j = 0; j < 100; j++)
{
*aPtr++ = bPtr[pos];
pos += 320;
}
}
for (i = 320; i < 640; i++)
{
pos = (i - 320) + 32004;
aPtr = BackArray[i];
for (j = 0; j < 100; j++)
{
*aPtr++ = bPtr[pos];
pos += 320;
}
}
AckFree(bPtr);
}
else
{
printf("Unable to load background image.\n");
result = 8;
}
}
return(result);
}
//=============================================================================
//
//=============================================================================
void ShowHit(void)
{
int x,y,result,wNum;
int flag;
short oNum,mPos;
ae->ObjList[0]->x = ae->xPlayer;
ae->ObjList[0]->y = ae->yPlayer;
wNum = 32;
oNum = 0;
flag = 0;
while (wNum--)
{
result = AckMoveObjectPOV(0,ae->PlayerAngle,12);
if (result == POV_OBJECT)
{
flag = 1;
oNum = AckGetObjectHit();
break;
}
if (result == POV_XWALL)
{
flag = 2;
oNum = ae->xGrid[AckGetWallHit()];
if (oNum & (DOOR_TYPE_SLIDE+DOOR_TYPE_SPLIT))
flag = 4;
oNum &= 0xFF;
break;
}
if (result == POV_YWALL)
{
flag = 3;
oNum = ae->yGrid[AckGetWallHit()];
if (oNum & (DOOR_TYPE_SLIDE+DOOR_TYPE_SPLIT))
flag = 4;
oNum &= 0xFF;
break;
}
}
if (flag)
{
mPos = (ae->ObjList[0]->y & 0xFFC0) + (ae->ObjList[0]->x >> 6);
switch (flag)
{
case 1:
sprintf(LineBuffer,"Object %d hit\nat location %d",oNum,mPos);
break;
case 2:
sprintf(LineBuffer,"Xwall %d hit\nat location %d",oNum,mPos);
break;
case 3:
sprintf(LineBuffer,"Ywall %d hit\nat location %d",oNum,mPos);
break;
case 4:
sprintf(LineBuffer,"Door %d hit\nat location %d",oNum,mPos);
break;
default:
*LineBuffer = '\0';
break;
}
ShowHitFlag = 1;
}
}
//=============================================================================
//
//=============================================================================
void UpdateBlast(void)
{
short j;
if (ae->ObjList[99]->Flags & OF_ANIMDONE &&
ae->ObjList[99]->CurrentType != NO_WALK)
{
AckSetObjectType(ae,99,NO_WALK);
ae->ObjList[99]->Flags &= ~OF_ANIMDONE;
}
j = AckMoveObjectPOV(99,ae->ObjList[99]->Dir,ae->ObjList[99]->Speed);
if (j > 0 && j != POV_PLAYER)
{
if (j != POV_OBJECT)
{
ae->ObjList[99]->Active = 0;
Shooting = 0;
return;
}
j = AckGetObjectHit();
if (j > 4 && j < 13)
{
if (ae->ObjList[j]->CurrentType == NO_WALK)
{
AckSetObjectType(ae,j,NO_INTERACT);
ObjCounter[j] = AckTimerCounter + 18 + (rand() % 120);
}
}
if (j == 51)
ae->ObjList[j]->Active = 0;
ae->ObjList[99]->Active = 0;
Shooting = 0;
}
}
//=============================================================================
//
//=============================================================================
void CheckMonsters(void)
{
int i,tFlag,xp,yp;
int pMap,oMap,oRow,oCol;
int row,col,offset;
long dx,dy,dx2,dy2,dist;
short cType;
UCHAR oFlags;
xp = ae->xPlayer;
yp = ae->yPlayer;
pMap = (yp & 0xFFC0) + (xp >> 6);
i = 5;
//for (i = 5; i < 13; i++)
while (1)
{
if (ae->ObjList[i]->Active)
{
oFlags = ae->ObjList[i]->Flags;
cType = ae->ObjList[i]->CurrentType;
dx = xp - ae->ObjList[i]->x;
dy = yp - ae->ObjList[i]->y;
dx2 = dx * dx;
dy2 = dy * dy;
if ((dx2+dy2) < 128000)
{
ae->ObjList[i]->Dir = AckGetObjectAngle(dx,dy);
if (cType == NO_WALK)
{
ae->ObjList[i]->Flags |= OF_ANIMATE;
oFlags |= OF_ANIMATE;
}
if (cType == NO_CREATE && !(oFlags & OF_ANIMATE))
{
if (i < 50)
{
ae->ObjList[i]->Flags |= OF_ANIMATE;
oFlags |= OF_ANIMATE;
}
else
AckSetObjectType(ae,i,NO_WALK);
}
}
if (cType == NO_WALK && (oFlags & OF_ANIMATE))
{
tFlag = AckMoveObjectPOV(i,ae->ObjList[i]->Dir,8);
oRow = ae->ObjList[i]->Dir / INT_ANGLE_90;
switch (tFlag)
{
case POV_PLAYER:
StrAmount--;
if (StrAmount < 0) StrAmount = 0;
ShowStatus();
break;
case POV_NOTHING:
break;
case POV_SLIDEX:
if (oRow > 1) ae->ObjList[i]->Dir = INT_ANGLE_270;
else ae->ObjList[i]->Dir = INT_ANGLE_90;
break;
case POV_SLIDEY:
if (oRow > 0 && oRow < 3)
ae->ObjList[i]->Dir = INT_ANGLE_180;
else
ae->ObjList[i]->Dir = 0;
break;
case POV_OBJECT:
ae->ObjList[i]->Dir = rand() % INT_ANGLE_360;
break;
default:
if (i < 50)
ae->ObjList[i]->Flags &= ~OF_ANIMATE;
break;
}
}
}
i++;
if (i == 13) i = 51;
if (i == 52) break;
}
}
//=============================================================================
//
//=============================================================================
void ShowStatus(void)
{
UCHAR *Video;
int row,offset,rlen,glen;
offset = (163 * 320) + 34;
glen = MagAmount;
if (glen > MAX_MAG_AMOUNT) glen = MAX_MAG_AMOUNT;
rlen = MAX_MAG_AMOUNT - glen;
Video = (UCHAR *)0xA0000;
Video += offset;
for (row = 0; row < 11; row++)
{
if (glen)
memset(Video,105,glen);
if (rlen)
memset(&Video[glen],39,rlen);
Video += 320;
}
offset = (183 * 320) + 34;
glen = StrAmount >> 1;
if (glen > MAX_STR_HALF_AMOUNT) glen = MAX_STR_HALF_AMOUNT;
rlen = MAX_STR_HALF_AMOUNT - glen;
Video = (UCHAR *)0xA0000;
Video += offset;
for (row = 0; row < 11; row++)
{
if (glen)
memset(Video,105,glen);
if (rlen)
memset(&Video[glen],39,rlen);
Video += 320;
}
}
//=============================================================================
//
//=============================================================================
void DrawBmpBox(int x1,int y1,int x2,int y2,long d1,long d2)
{
long NumCols,DeltaDist;
long htStep,dst;
long ht1,ht2,bmht;
long offset,xpos,ypos,bmPos,yposLow;
long bmCol,bmColStep;
UCHAR *Video,*bmp,*VidOrg,*VidEnd;
UCHAR *vPtr;
dst = d1;
if (d1 > d2) dst = d2;
bmht = 64 * 256;
DeltaDist = labs(d2 - d1);
ht1 = bmht / dst;
NumCols = ht1;
if (DeltaDist)
NumCols = (ht1 * (64 - DeltaDist)) / 64;
if (NumCols < 1) NumCols = 1;
bmColStep = (64*65536) / NumCols;
htStep = (DeltaDist<<16) / NumCols;
if (d2 < d1) htStep = -htStep;
bmp = ae->bMaps[1];
VidOrg = Video = ae->ScreenBuffer;
VidEnd = VidOrg + 64000;
offset = (y1 * 320) + x1;
Video += offset;
bmCol = 0;
d2 = (d1<<16);
for (xpos = 0; xpos < NumCols; xpos++)
{
vPtr = Video;
ypos = 0x1FFF;
yposLow = 0x1F;
bmPos = (bmCol>>16) * 64;
d1 = (d2>>16);
while (yposLow > 0 && vPtr > VidOrg)
{
*vPtr = bmp[bmPos+yposLow];
vPtr -= 320;
ypos -= d1;
yposLow = ypos >> 8;
}
vPtr = Video + 320;
ypos = 0x2000;
yposLow = 0x20;
while (yposLow < 64 && vPtr < VidEnd)
{
*vPtr = bmp[bmPos+yposLow];
vPtr += 320;
ypos += d1;
yposLow = ypos >> 8;
}
d2 += htStep;
bmCol += bmColStep;
Video++;
}
}
//=============================================================================
//
//=============================================================================
void ClsBmpBox(int x1,int y1,int x2,int y2)
{
int offset,wt;
UCHAR *Video;
Video = (UCHAR *)0xA0000;
offset = (y1 * 320) + x1;
wt = (x2 - x1) + 1;
Video += offset;
while (y1++ <= y2)
{
memset(Video,0,wt);
Video += 320;
}
}
typedef struct {
int x1;
int y1;
int x2;
int y2;
int d1;
int d2;
} AWALL;
short near long_sqrt(long v);
//=============================================================================
//
//=============================================================================
short LoadNewLevel(char *LevelName)
{
short i;
i = AckOpenResource(LevelName);
if (i)
return(-1);
for (i = 1; i < MAX_WALLBMPS; i++)
{
if (ae->bMaps[i] != NULL)
{
AckFree(ae->bMaps[i]);
ae->bMaps[i] = NULL;
}
}
for (i = 1; i < MAX_OBJBMPS; i++)
{
if (ae->oMaps[i] != NULL)
{
AckFree(ae->oMaps[i]);
ae->oMaps[i] = NULL;
}
}
for (i = 1; i < ae->MaxObjects; i++)
{
if (ae->ObjList[i] != NULL)
{
AckFree(ae->ObjList[i]);
ae->ObjList[i] = NULL;
}
}
ae->MaxObjects = 0;
for (i = 0; i < (GRID_ARRAY - GRID_WIDTH); i++)
{
if (ae->myGrid[i] != NULL)
AckFree(ae->myGrid[i]);
ae->mxGrid[i] = NULL;
ae->mxGrid[i+1] = NULL;
ae->myGrid[i] = NULL;
ae->myGrid[i+GRID_WIDTH] = NULL;
}
i = ProcessInfoFile(1);
if (i)
return(i);
AckCloseResource();
AckRegisterStructure(ae);
return(0);
}
short LevelFlag;
//=============================================================================
//
//=============================================================================
short main(short argc,char **argv)
{
short i,j,done,fpos;
char ch;
MOUSE mouse;
UCHAR *Video;
int Spin,MoveAmount;
int SpinAngle,MoveAngle;
long TimerEnd;
short DemoFlag;
short lpx,lpy,lpa;
int StartTime,EndTime,InfoFlag;
int CkStart,CkEnd;
int TurnFactor,MoveFactor,MoveHalfFactor;
int HandX,HandY,HandDY;
long x1,y1;
i = 0;
if (argc > 1)
{
for (j = 1; j <= argc; j++)
{
if (!strnicmp(argv[j],"-1",2))
i |= 1;
}
}
if ((done = Initialize(i)) != 0)
return(done);
if ((done = LoadBackDrop()) != 0)
return(done);
// Do some test setup of our GooMonsters
AckSetObjectType(ae,6,NO_WALK);
ae->ObjList[5]->Flags &= ~OF_ANIMATE;
ae->ObjList[7]->Flags &= ~OF_ANIMATE;
ae->ObjList[8]->Flags &= ~OF_ANIMATE;
ae->ObjList[9]->Flags &= ~OF_ANIMATE;
ae->ObjList[10]->Flags &= ~OF_ANIMATE;
ae->ObjList[11]->Flags &= ~OF_ANIMATE;
ae->ObjList[12]->Flags &= ~OF_ANIMATE;
ae->ObjList[99]->Active = 0;
ae->ObjList[99]->Speed = 48;
Shooting = 0;
MagAmount = MAX_MAG_AMOUNT;
StrAmount = MAX_STR_AMOUNT;
AckSetupKeyboard();
AckSetupTimer();
//StartBGmusic();
// Switch to mode 13
AckSetVGAmode();
// Put up the main screen
LoadAndShow((char *)ResScreenBack);
//DoTest();
// Set palette for shading if needed
AckSetupPalRanges(ae,ranges);
ShowStatus();
LevelFlag = 0;
done = 0;
SpinAngle = Spin = MoveAmount = 0;
MouseReleased();
SetMouseCursor(120,160);
fpos = 64;
DemoFlag = 0;
if (DemoPtr != NULL) DemoFlag = 1;
TimerEnd = AckTimerCounter + 18;
// MUST register each ACKENG structure once before use and after AckInitialize
AckRegisterStructure(ae);
StartTime = AckTimerCounter;
AckBuildView();
AckDisplayScreen();
EndTime = AckTimerCounter - StartTime;
if (!EndTime) EndTime = 1;
TurnFactor = INT_ANGLE_1 * EndTime;
MoveFactor = 3 * EndTime;
MoveHalfFactor = MoveFactor >> 1;
StartTime = clock();
EndTime = StartTime;
InfoFlag = 0;
HandX = 134;
HandY = 132;
HandDY = -2;
Throwing = 0;
while (!done)
{
if (SpinAngle)
{
ae->PlayerAngle += SpinAngle;
if (ae->PlayerAngle >= INT_ANGLE_360)
ae->PlayerAngle -= INT_ANGLE_360;
if (ae->PlayerAngle < 0)
ae->PlayerAngle += INT_ANGLE_360;
SpinAngle >>= 3;
if (SpinAngle == -1) SpinAngle = 0;
}
if (MoveAmount)
{
HandY += HandDY;
if (HandY < 125) HandDY = 2;
if (HandY > 132) HandDY = -2;
j = AckMovePOV(MoveAngle,MoveAmount);
AckCheckDoorOpen(ae->xPlayer,ae->yPlayer,MoveAngle);
MoveAmount >>= 1;
if (j == POV_OBJECT)
{
j = AckGetObjectHit();
if (j > 4 && j < 13)
{
StrAmount--;
if (StrAmount < 0)
StrAmount = 0;
ShowStatus();
}
if (j >= 36 && j <= 49)
{
ae->ObjList[j]->Active = 0;
MagAmount += 4;
if (MagAmount > MAX_MAG_AMOUNT)
MagAmount = MAX_MAG_AMOUNT;
ShowStatus();
}
if (j == 50 && ae->ObjList[50]->CurrentType == NO_CREATE)
{
AckSetObjectType(ae,j,NO_WALK);
StrAmount = MAX_STR_AMOUNT;
ShowStatus();
}
}
}
else
{
if (HandY < 132)
HandY++;
}
AckCheckObjectMovement(); // Animate objects if needed
for (j = 5; j < 13; j++)
{
if (ae->ObjList[j]->Flags & OF_ANIMDONE &&
ae->ObjList[j]->CurrentType == NO_DESTROY)
{
AckSetObjectType(ae,j,NO_CREATE);
ae->ObjList[j]->Flags &= ~OF_ANIMDONE;
ae->ObjList[j]->Flags &= ~OF_ANIMATE;
ae->ObjList[j]->Active = 0;
}
if (ae->ObjList[j]->Flags & OF_ANIMDONE &&
ae->ObjList[j]->CurrentType != NO_WALK)
{
AckSetObjectType(ae,j,NO_WALK);
ae->ObjList[j]->Flags &= ~OF_ANIMDONE;
ObjCounter[j] = AckTimerCounter + 18 + (rand() % 20);
}
if (AckTimerCounter > ObjCounter[j])
{
ObjCounter[j] = AckTimerCounter + 18 + (rand() % 18);
if (ae->ObjList[j]->CurrentType == NO_WALK)
AckSetObjectType(ae,j,NO_ATTACK);
else
{
if (ae->ObjList[j]->CurrentType == NO_INTERACT)
AckSetObjectType(ae,j,NO_DESTROY);
}
}
}
if (Shooting)
UpdateBlast();
CheckMonsters();
CkStart = AckTimerCounter;
AckBuildView(); // Build floor, ceiling, and walls into ScrnBuffer
if (DemoFlag)
{
switch (DemoFlag)
{
case 1:
if (AckTimerCounter > TimerEnd)
{
DemoFlag++;
TimerEnd = AckTimerCounter + 54;
}
break;
case 2:
ShowBitmap(130,20,ae->ScreenBuffer,Demoht,Demowt,&DemoPtr[4]);
if (AckTimerCounter > TimerEnd)
{
DemoFlag = 1;
TimerEnd = AckTimerCounter + 216;
}
break;
default:
break;
}
}
switch (Throwing)
{
case 0:
ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh1,Handw1,&pHand1[4]);
break;
case 1:
HandY -= 20;
if (HandY < 97)
{
HandY = 97;
Throwing++;
}
ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh1,Handw1,&pHand1[4]);
break;
case 2:
HandY -= 5;
Throwing++;
ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh2,Handw2,&pHand2[4]);
break;
case 3:
ae->ObjList[99]->Active = 1;
ae->ObjList[99]->x = ae->xPlayer;
ae->ObjList[99]->y = ae->yPlayer;
ae->ObjList[99]->Dir = ae->PlayerAngle;
ae->ObjList[99]->mPos = (ae->yPlayer & 0xFFC0) + ae->xPlayer >> 6;
AckSetObjectType(ae,99,NO_CREATE);
Shooting = 1;
MagAmount--;
ShowStatus();
Throwing++;
ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh2,Handw2,&pHand2[4]);
break;
case 4:
HandY += 5;
Throwing++;
ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh2,Handw2,&pHand2[4]);
break;
case 5:
HandY += 20;
if (HandY > 132)
Throwing = 0;
ShowBitmap(HandX,HandY,ae->ScreenBuffer,Handh1,Handw1,&pHand1[4]);
break;
default:
break;
}
if (InfoFlag)
{
EndTime = clock();
if (EndTime > StartTime+100 )
{
StartTime = EndTime;
cframes = framespersec;
framespersec = 0;
}
sprintf(LineBuffer,"FPS: %6ld,%d,%d,%d",
(long)cframes,ae->xPlayer,ae->yPlayer,ae->PlayerAngle);
smWriteHUD(10,20,32,LineBuffer);
framespersec++;
}
// sprintf(LineBuffer,"MEM: %ld",AckMemUsed);
// smWriteHUD(22,30,32,LineBuffer);
if (ShowHitFlag)
smWriteHUD(10,10,32,LineBuffer);
AckDisplayScreen(); // Copy ScrnBuffer to actual video
CkEnd = AckTimerCounter - CkStart;
if (!CkEnd) CkEnd = 4;
TurnFactor = INT_ANGLE_1 * CkEnd;
MoveFactor = 3 * CkEnd;
MoveHalfFactor = MoveFactor >> 1;
i = (ae->yPlayer & 0xFFC0) + (ae->xPlayer >> 6);
if (FloorMap[i] == 0x28)
{
StrAmount--;
if (StrAmount < 1)
break;
ShowStatus();
}
CheckMouse(&mouse);
if (mouse.mButtons & 1)
{
if (!(ae->ObjList[99]->Active) && MagAmount > 0 && !Throwing)
{
Throwing = 1;
#if 0
ae->ObjList[99]->Active = 1;
ae->ObjList[99]->x = ae->xPlayer;
ae->ObjList[99]->y = ae->yPlayer;
ae->ObjList[99]->Dir = ae->PlayerAngle;
ae->ObjList[99]->mPos = (ae->yPlayer & 0xFFC0) + ae->xPlayer >> 6;
AckSetObjectType(ae,99,NO_CREATE);
Shooting = 1;
MagAmount--;
ShowStatus();
#endif
}
}
if (mouse.mButtons & 2)
{
MoveAmount += MoveFactor; // 16;
if (MoveAmount > MAX_AMOUNT)
MoveAmount = MAX_AMOUNT;
MoveAngle = ae->PlayerAngle;
}
if (mouse.mdx < 0)
{
Spin = -mouse.mdx;
Spin >>= 5;
SpinAngle = -TurnFactor * Spin; // -INT_ANGLE_1 * Spin;
Spin = 1;
}
if (mouse.mdx > 0)
{
Spin = mouse.mdx;
Spin >>= 5;
SpinAngle = TurnFactor * Spin; // INT_ANGLE_1 * Spin;
Spin = 1;
}
if (mouse.mdy < 0)
{
i = -mouse.mdy;
i >>= 2;
i += MoveHalfFactor;
MoveAmount += i;
if (MoveAmount > MAX_AMOUNT)
MoveAmount = MAX_AMOUNT;
MoveAngle = ae->PlayerAngle;
}
if (mouse.mdy > 20)
{
i = mouse.mdy;
i >>= 3;
i += MoveHalfFactor;
j = ae->PlayerAngle + INT_ANGLE_180;
if (j >= INT_ANGLE_360)
j -= INT_ANGLE_360;
MoveAmount += i;
if (MoveAmount > MAX_AMOUNT)
MoveAmount = MAX_AMOUNT;
MoveAngle = j;
}
if (AckKeys[ESCAPE_KEY])
break;
if(AckKeys[RIGHT_ARROW_KEY])
{
Spin += 1;
SpinAngle += TurnFactor; // INT_ANGLE_1 * Spin;
}
if(AckKeys[LEFT_ARROW_KEY])
{
Spin += 1;
SpinAngle -= TurnFactor; // -INT_ANGLE_1 * Spin;
}
if(AckKeys[UP_ARROW_KEY])
{
MoveAmount += (MoveFactor + MoveHalfFactor); // 12;
if (MoveAmount > MAX_AMOUNT)
MoveAmount = MAX_AMOUNT;
MoveAngle = ae->PlayerAngle;
}
if(AckKeys[DOWN_ARROW_KEY])
{
j = ae->PlayerAngle + INT_ANGLE_180;
if (j >= INT_ANGLE_360)
j -= INT_ANGLE_360;
MoveAmount += (MoveFactor + MoveHalfFactor); // 12;
if (MoveAmount > MAX_AMOUNT)
MoveAmount = MAX_AMOUNT;
MoveAngle = j;
}
if (AckKeys[C_KEY])
{
ae->SysFlags ^= SYS_SOLID_CEIL;
ae->SysFlags &= ~SYS_SOLID_BACK;
AckKeys[C_KEY] = 0;
if ((ae->SysFlags & SYS_SOLID_CEIL) && (ResScrollBack != 0))
ae->SysFlags |= SYS_SOLID_BACK;
AckRegisterStructure(ae);
}
if (AckKeys[R_KEY])
{
AckKeys[R_KEY] = 0;
Resolution++;
if (Resolution > 2)
Resolution = 0;
}
if (AckKeys[F_KEY])
{
ae->SysFlags ^= SYS_SOLID_FLOOR;
AckKeys[F_KEY] = 0;
AckRegisterStructure(ae);
}
if (AckKeys[PGUP_KEY] && ViewHeight < 60)
{
ViewHeight++;
CeilingHeight++;
}
if (AckKeys[PGDN_KEY] && ViewHeight > 4)
{
ViewHeight--;
CeilingHeight--;
}
if (AckKeys[NUM_1_KEY])
{
AckKeys[NUM_1_KEY]=0;
dFactor--;
}
if (AckKeys[NUM_2_KEY])
{
AckKeys[NUM_2_KEY]=0;
dFactor++;
}
if (AckKeys[MINUS_KEY])
{
AckKeys[MINUS_KEY]=0;
mFactor--;
}
if (AckKeys[PLUS_KEY])
{
AckKeys[PLUS_KEY]=0;
mFactor++;
}
if (AckKeys[I_KEY])
{
AckKeys[I_KEY] = 0;
InfoFlag ^= 1;
}
if (AckKeys[B_KEY])
{
AckKeys[B_KEY]=0;
// mFactor -= 64;
if (!LevelFlag)
LoadNewLevel("MALL.DTF");
else
{
LoadNewLevel("PICS.DTF");
ae->ObjList[99]->Active = 0;
ae->ObjList[99]->Speed = 48;
}
LevelFlag ^= 1;
}
if (AckKeys[S_KEY])
{
AckKeys[S_KEY] = 0;
mFactor += 64;
}
}
//EndBGmusic();
ShutDownFlag = 1;
AckWrapUp(ae);
AckSetTextmode();
return(0);
}