Commit 2fa9feb4 authored by Steven Fuller's avatar Steven Fuller

Added Mac Wolf3D to CVS

parent 7af3c59d
/**********************************
Burger library for the Macintosh.
Use Think.c or Code Warrior to compile.
Use SMART linking to link in just what you need
**********************************/
#include "WolfDef.h" /* Get the prototypes */
#include <string.h>
#include <sound.h>
#include <stdio.h>
#include <palettes.h>
#include "SoundMusicSystem.h"
#include "PickAMonitor.h"
/**********************************
Variables used by my global library
**********************************/
Word DoEvent(EventRecord *event);
void DoMacEvents(void);
void BlastScreen(void);
static Word FreeStage(Word Stage,LongWord Size);
extern Boolean MouseHit; /* True if a mouse down event occured */
Word NoSystemMem;
unsigned char *VideoPointer; /* Pointer to video memory */
extern Word QuitFlag; /* Did the application quit? */
Word VideoWidth; /* Width to each video scan line */
Word SystemState=3; /* Sound on/off flags */
Word KilledSong; /* Song that's currently playing */
Word KeyModifiers; /* Keyboard modifier flags */
LongWord LastTick; /* Last system tick (60hz) */
Word FontX; /* X Coord of font */
Word FontY; /* Y Coord of font */
unsigned char *FontPtr; /* Pointer to font image data */
unsigned char *FontWidths; /* Pointer to font width table */
Word FontHeight; /* Point size of current font */
Word FontLast; /* Number of font entries */
Word FontFirst; /* ASCII value of first char */
Word FontLoaded; /* Rez number of loaded font (0 if none) */
Word FontInvisible; /* Allow masking? */
unsigned char FontOrMask[16]; /* Colors for font */
LongWord YTable[480]; /* Offsets to the screen */
SndChannelPtr myPaddleSndChan; /* Sound channel */
Word ScanCode;
CWindowPtr GameWindow;
CGrafPtr GameGWorld;
extern GDHandle gMainGDH;
extern CTabHandle MainColorHandle;
extern Boolean DoQuickDraw;
/**********************************
Wait a single system tick
**********************************/
static Word QuickTicker;
void DoMacEvents(void)
{
EventRecord MyEvent;
if (!DoQuickDraw) {
if ((ReadTick() - QuickTicker) < 30) {
return;
}
QuickTicker = ReadTick();
}
PurgeAllSounds(85000); /* Try to keep some memory free */
if (WaitNextEvent2(updateMask|diskMask|driverMask|networkMask|activMask|app4Mask,&MyEvent,0,0)) {
DoEvent(&MyEvent);
}
}
/**********************************
Wait a single system tick
**********************************/
void WaitTick(void)
{
do {
DoMacEvents(); /* Allow backgrounding */
} while (ReadTick()==LastTick); /* Tick changed? */
LastTick=ReadTick(); /* Save it */
}
/**********************************
Wait a specific number of system ticks
from a time mark before you get control
**********************************/
void WaitTicks(Word Count)
{
LongWord TickMark; /* Temp tick mark */
do {
DoMacEvents(); /* Allow other tasks to execute */
TickMark = ReadTick(); /* Get the mark */
} while ((TickMark-LastTick)<=Count); /* Time up? */
LastTick = TickMark; /* Save the new time mark */
}
/**********************************
Get the current system tick
**********************************/
LongWord ReadTick(void)
{
return(TickCount()); /* Just get it from the Mac OS */
}
/**********************************
Wait for a mouse/keyboard event
**********************************/
Word WaitEvent(void)
{
Word Temp;
do {
Temp = WaitTicksEvent(6000); /* Wait 10 minutes */
} while (!Temp); /* No event? */
return Temp; /* Return the event code */
}
/**********************************
Wait for an event or a timeout
**********************************/
Word WaitTicksEvent(Word Time)
{
LongWord TickMark;
LongWord NewMark;
Word RetVal;
MouseHit = FALSE;
TickMark = ReadTick(); /* Get the initial time mark */
for (;;) {
DoMacEvents(); /* Allow other tasks a shot! */
NewMark = ReadTick(); /* Get the new time mark */
if (Time) {
if ((NewMark-TickMark)>=Time) { /* Time up? */
RetVal = 0; /* Return timeout */
break;
}
}
RetVal = GetAKey();
if (RetVal) {
break;
}
if (MouseHit) {
RetVal = 1; /* Hit the mouse */
break;
}
}
LastTick = NewMark;
return RetVal;
}
/**********************************
Get a key from the keyboard
**********************************/
Word GetAKey(void)
{
EventRecord MyRecord;
if (WaitNextEvent2(everyEvent,&MyRecord,0,0)) {
if (!DoEvent(&MyRecord)) {
KeyModifiers = MyRecord.modifiers;
return 0;
}
return FixMacKey(&MyRecord);
}
return 0;
}
/**********************************
Check if all keys are released
**********************************/
Word WaitKey(void)
{
Word Key;
do {
Key = GetAKey();
} while (!Key);
return (Key);
}
/**********************************
Check if all keys are released
**********************************/
Word AllKeysUp(void)
{
KeyMap KeyArray;
GetKeys(KeyArray);
if (KeyArray[0] || KeyArray[1] || KeyArray[2] || KeyArray[3]) {
return 0;
}
return 1;
}
Word FixMacKey(EventRecord *Event)
{
Word NewKey;
NewKey = Event->message & 0xff;
ScanCode = (Event->message>>8) & 0xff;
switch (NewKey) {
case 0x1c :
NewKey = 0x08;
break;
case 0x1d :
NewKey = 0x15;
break;
case 0x1e :
NewKey = 0x0b;
break;
case 0x1f :
NewKey = 0x0a;
break;
}
KeyModifiers = Event->modifiers;
if (NewKey == 'Q' || NewKey == 'q') {
if (KeyModifiers & cmdKey) {
QuitFlag = 1;
}
}
return NewKey;
}
/**********************************
Flush out the keyboard buffer
**********************************/
void FlushKeys(void)
{
while (GetAKey()) {}
}
/**********************************
Convert a long value into a ascii string
**********************************/
static LongWord Tens[] = {
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000};
void ultoa(LongWord Val,char *Text)
{
Word Index; /* Index to Tens table */
Word Hit; /* Printing? */
Word Letter; /* Letter to print */
LongWord LongVal; /* Tens value */
Index = 9; /* Start at the millions */
Hit = 0; /* Didn't print anything yet! */
do {
Letter = '0'; /* Init the char */
LongVal = Tens[Index]; /* Init the value into a local */
while (Val >= LongVal) { /* Is the number in question larger? */
Val -= LongVal; /* Sub the tens value */
++Letter; /* Inc the char */
Hit=1; /* I must draw! */
}
if (Hit) { /* Remove the leading zeros */
Text[0] = Letter; /* Save char in the string */
++Text; /* Inc dest */
}
} while (--Index); /* All the tens done? */
Text[0] = Val + '0'; /* Must print FINAL digit */
Text[1] = 0; /* End the string */
}
/**********************************
Sound sub-system
**********************************/
/**********************************
Shut down the sound
**********************************/
void SoundOff(void)
{
PlaySound(0);
}
/**********************************
Play a sound resource
**********************************/
void PlaySound(Word SoundNum)
{
if (SoundNum && (SystemState&SfxActive)) {
SoundNum+=127;
if (SoundNum&0x8000) { /* Mono sound */
EndSound(SoundNum&0x7fff);
}
BeginSound(SoundNum&0x7fff,11127<<17L);
} else {
EndAllSound();
}
}
/**********************************
Stop playing a sound resource
**********************************/
void StopSound(Word SoundNum)
{
EndSound(SoundNum+127);
}
static Word LastSong = -1;
void PlaySong(Word Song)
{
if (Song) {
KilledSong = Song;
if (SystemState&MusicActive) {
if (Song!=LastSong) {
BeginSongLooped(Song);
LastSong = Song;
}
return;
}
}
EndSong();
LastSong = -1;
}
/**********************************
Graphics subsystem
**********************************/
/**********************************
Draw a masked shape
**********************************/
void InitYTable(void)
{
Word i;
LongWord Offset;
i = 0;
Offset = 0;
do {
YTable[i] = Offset;
Offset+=VideoWidth;
} while (++i<480);
}
/**********************************
Draw a shape
**********************************/
void DrawShape(Word x,Word y,void *ShapePtr)
{
unsigned char *ScreenPtr;
unsigned char *Screenad;
unsigned char *ShapePtr2;
unsigned short *ShapePtr3;
Word Width;
Word Height;
Word Width2;
ShapePtr3 = ShapePtr;
Width = ShapePtr3[0]; /* 16 bit width */
Height = ShapePtr3[1]; /* 16 bit height */
ShapePtr2 = (unsigned char *) &ShapePtr3[2];
ScreenPtr = (unsigned char *) &VideoPointer[YTable[y]+x];
do {
Width2 = Width;
Screenad = ScreenPtr;
do {
*Screenad++ = *ShapePtr2++;
} while (--Width2);
ScreenPtr +=VideoWidth;
} while (--Height);
}
/**********************************
Draw a masked shape
**********************************/
void DrawMShape(Word x,Word y,void *ShapePtr)
{
unsigned char *ScreenPtr;
unsigned char *Screenad;
unsigned char *MaskPtr;
unsigned char *ShapePtr2;
Word Width;
Word Height;
Word Width2;
ShapePtr2 = ShapePtr;
Width = ShapePtr2[1];
Height = ShapePtr2[3];
ShapePtr2 +=4;
MaskPtr = &ShapePtr2[Width*Height];
ScreenPtr = (unsigned char *) &VideoPointer[YTable[y]+x];
do {
Width2 = Width;
Screenad = ScreenPtr;
do {
*Screenad = (*Screenad & *MaskPtr++) | *ShapePtr2++;
++Screenad;
} while (--Width2);
ScreenPtr +=VideoWidth;
} while (--Height);
}
/**********************************
Draw a masked shape with an offset
**********************************/
void DrawXMShape(Word x,Word y,void *ShapePtr)
{
unsigned short *ShapePtr2;
ShapePtr2 = ShapePtr;
x += ShapePtr2[0];
y += ShapePtr2[1];
DrawMShape(x,y,&ShapePtr2[2]);
}
/**********************************
Erase a masked shape
**********************************/
void EraseMBShape(Word x,Word y, void *ShapePtr, void *BackPtr)
{
unsigned char *ScreenPtr;
unsigned char *Screenad;
unsigned char *Backad;
unsigned char *BackPtr2;
unsigned char *MaskPtr;
Word Width;
Word Height;
Word Width2;
MaskPtr = ShapePtr; /* Get the pointer to the mask */
Width = MaskPtr[1]; /* Get the width of the shape */
Height = MaskPtr[3]; /* Get the height of the shape */
MaskPtr = &MaskPtr[(Width*Height)+4]; /* Index to the mask */
/* Point to the screen */
ScreenPtr = (unsigned char *) &VideoPointer[YTable[y]+x];
BackPtr2 = BackPtr;
BackPtr2 = &BackPtr2[(y*SCREENWIDTH)+x]; /* Index to the erase buffer */
do {
Width2 = Width; /* Init width count */
Screenad = ScreenPtr;
Backad = BackPtr2;
do {
if (!*MaskPtr++) {
*Screenad = *Backad;
}
++Screenad;
++Backad;
} while (--Width2);
ScreenPtr +=VideoWidth;
BackPtr2 += SCREENWIDTH;
} while (--Height);
}
/**********************************
Test for a shape collision
**********************************/
Word TestMShape(Word x,Word y,void *ShapePtr)
{
unsigned char *ScreenPtr;
unsigned char *Screenad;
unsigned char *MaskPtr;
unsigned char *ShapePtr2;
Word Width;
Word Height;
Word Width2;
ShapePtr2 = ShapePtr;
Width = ShapePtr2[0];
Height = ShapePtr2[1];
ShapePtr2 +=2;
MaskPtr = &ShapePtr2[Width*Height];
ScreenPtr = (unsigned char *) &VideoPointer[YTable[y]+x];
do {
Width2 = Width;
Screenad = ScreenPtr;
do {
if (!*MaskPtr++) {
if (*Screenad != *ShapePtr2) {
return 1;
}
}
++ShapePtr2;
++Screenad;
} while (--Width2);
ScreenPtr +=VideoWidth;
} while (--Height);
return 0;
}
/**********************************
Test for a masked shape collision
**********************************/
Word TestMBShape(Word x,Word y,void *ShapePtr,void *BackPtr)
{
unsigned char *ScreenPtr;
unsigned char *Screenad;
unsigned char *Backad;
unsigned char *BackPtr2;
unsigned char *MaskPtr;
Word Width;
Word Height;
Word Width2;
MaskPtr = ShapePtr; /* Get the pointer to the mask */
Width = MaskPtr[0]; /* Get the width of the shape */
Height = MaskPtr[1]; /* Get the height of the shape */
MaskPtr = &MaskPtr[(Width*Height)+2]; /* Index to the mask */
/* Point to the screen */
ScreenPtr = (unsigned char *) &VideoPointer[YTable[y]+x];
BackPtr2 = BackPtr;
BackPtr2 = &BackPtr2[(y*SCREENWIDTH)+x]; /* Index to the erase buffer */
do {
Width2 = Width; /* Init width count */
Screenad = ScreenPtr;
Backad = BackPtr2;
do {
if (!*MaskPtr++) {
if (*Screenad != *Backad) {
return 1;
}
}
++Screenad;
++Backad;
} while (--Width2);
ScreenPtr +=VideoWidth;
BackPtr2 += SCREENWIDTH;
} while (--Height);
return 0;
}
/**********************************
Show a full screen picture
**********************************/
void ShowPic(Word PicNum)
{
DrawShape(0,0,LoadAResource(PicNum)); /* Load the resource and show it */
ReleaseAResource(PicNum); /* Release it */
BlastScreen();
}
/**********************************
Clear the screen to a specific color
**********************************/
void ClearTheScreen(Word Color)
{
Word x,y;
unsigned char *TempPtr;
TempPtr = VideoPointer;
y = SCREENHEIGHT; /* 200 lines high */
do {
x = 0;
do {
TempPtr[x] = Color; /* Fill color */
} while (++x<SCREENWIDTH);
TempPtr += VideoWidth; /* Next line down */
} while (--y);
}
/**********************************
Draw a text string
**********************************/
void DrawAString(char *TextPtr)
{
while (TextPtr[0]) { /* At the end of the string? */
DrawAChar(TextPtr[0]); /* Draw the char */
++TextPtr; /* Continue */
}
}
/**********************************
Set the X/Y to the font system
**********************************/
void SetFontXY (Word x,Word y)
{
FontX = x;
FontY = y;
}
/**********************************
Make color zero invisible
**********************************/
void FontUseMask(void)
{
FontInvisible = 0;
FontSetColor(0,0);
}
/**********************************
Make color zero a valid color
**********************************/
void FontUseZero(void)
{
FontInvisible = -1;
FontSetColor(0,BLACK);
}
/**********************************
Set the color entry for the font
**********************************/
void FontSetColor(Word Num,Word Color)
{
FontOrMask[Num] = Color;
}
/**********************************
Install a font into memory
**********************************/
typedef struct FontStruct {
unsigned short FHeight;
unsigned short FLast;
unsigned short FFirst;
unsigned char FData;
} FontStruct;
void InstallAFont(Word FontNum)
{
FontStruct *FPtr;
if (FontLoaded) {
if (FontLoaded == FontNum) {
return;
}
ReleaseAResource(FontLoaded);
}
FontLoaded = FontNum;
FPtr = LoadAResource(FontNum);
FontHeight = SwapUShort(FPtr->FHeight);
FontLast = SwapUShort(FPtr->FLast);
FontFirst = SwapUShort(FPtr->FFirst);
FontWidths = &FPtr->FData;
FontPtr = &FontWidths[FontLast];
}
/**********************************
Draw a char to the screen
**********************************/
void DrawAChar(Word Letter)
{
Word XWidth;
Word Offset;
Word Width;
Word Height;
int Width2;
unsigned char *Font;
unsigned char *ScreenPtr;
unsigned char *Screenad;
unsigned char *FontOr;
Word Temp;
Word Temp2;
Letter -= FontFirst; /* Offset from the first entry */
if (Letter>=FontLast) { /* In the font? */
return; /* Exit then! */
}
XWidth = FontWidths[Letter]; /* Get the pixel width of the entry */
Width = (XWidth-1)/2;
Font = &FontPtr[Letter*2];
Offset = (Font[1]*256) + Font[0];
Font = &FontPtr[Offset];
ScreenPtr = (unsigned char *) &VideoPointer[YTable[FontY]+FontX];
FontX+=XWidth;
Height = FontHeight;
FontOr = &FontOrMask[0];
do {
Screenad = ScreenPtr;
Width2 = Width;
do {
Temp = *Font++;
Temp2 = Temp>>4;
if (Temp2 != FontInvisible) {
Screenad[0] = FontOr[Temp2];
}
Temp &= 0x0f;
if (Temp != FontInvisible) {
Screenad[1] = FontOr[Temp];
}
Screenad+=2; /* Next address */
} while(--Width2>=0);
ScreenPtr += VideoWidth;
} while (--Height);
}
/**********************************
Palette Manager
**********************************/
/**********************************
Load and set a palette resource
**********************************/
void SetAPalette(Word PalNum)
{
SetAPalettePtr(LoadAResource(PalNum)); /* Set the current palette */
ReleaseAResource(PalNum); /* Release the resource */
}
/**********************************
Load and set a palette from a pointer
**********************************/
Byte CurrentPal[768];
void SetAPalettePtr(unsigned char *PalPtr)
{
CTabHandle ColorHandle; /* Handle to the main palette */
Handle PalHand; /* Handle to palette */
Word i; /* Temp */
CSpecArray *Colors; /* Pointer to color array */
GDHandle OldDevice;
memcpy(CurrentPal,PalPtr,768);
ColorHandle = MainColorHandle;
HLock((Handle) ColorHandle);
Colors = &(*ColorHandle)->ctTable;
++Colors; /* Go to color #0 */
i = 1; /* Skip color #0 */
PalPtr+=3;
do { /* Fill in all the color entries */
Colors[0]->rgb.red = (Word) (PalPtr[0]<<8) | PalPtr[0];
Colors[0]->rgb.green = (Word) (PalPtr[1]<<8) | PalPtr[1];
Colors[0]->rgb.blue = (Word) (PalPtr[2]<<8) | PalPtr[2];
if (!Colors[0]->rgb.blue) {
Colors[0]->rgb.blue = 0x0101;
}
PalPtr+=3;
++Colors;
} while (++i<255); /* All done? */
OldDevice = GetGDevice();
SetGDevice(gMainGDH);
SetEntries(0,255-1,(*ColorHandle)->ctTable); /* Set the color entries */
PalHand = (Handle) (**(*GameGWorld).portPixMap).pmTable;
PtrToXHand(*ColorHandle,PalHand,8+(8*256));
PalHand = (Handle) (**(*GameWindow).portPixMap).pmTable;
PtrToXHand(*ColorHandle,PalHand,8+(8*256));
HUnlock((Handle)ColorHandle); /* Release the main handle */
MakeITable(0,0,0); /* Create the proper color table */
SetGDevice(OldDevice);
}
/**********************************
Fade the screen to black
**********************************/
void FadeToBlack(void)
{
unsigned char MyPal[768];
memset(MyPal,0,sizeof(MyPal)); /* Fill with black */
MyPal[0] = MyPal[1] = MyPal[2] = 255;
FadeToPtr(MyPal);
}
/**********************************
Fade the screen to a palette
**********************************/
void FadeTo(Word RezNum)
{
FadeToPtr(LoadAResource(RezNum));
ReleaseAResource(RezNum);
}
/**********************************
Fade the palette
**********************************/
void FadeToPtr(unsigned char *PalPtr)
{
int DestPalette[768]; /* Dest offsets */
Byte WorkPalette[768]; /* Palette to draw */
Byte SrcPal[768];
Word Count;
Word i;
if (!memcmp(PalPtr,&CurrentPal,768)) { /* Same palette? */
return;
}
memcpy(SrcPal,CurrentPal,768);
i = 0;
do { /* Convert the source palette to ints */
DestPalette[i] = PalPtr[i];
} while (++i<768);
i = 0;
do {
DestPalette[i] -= SrcPal[i]; /* Convert to delta's */
} while (++i<768);
Count = 1;
do {
i = 0;
do {
WorkPalette[i] = ((DestPalette[i] * (int)(Count)) / 16) + SrcPal[i];
} while (++i<768);
SetAPalettePtr(WorkPalette);
WaitTicks(1);
} while (++Count<17);
}
/**********************************
Resource manager subsystem
**********************************/
/**********************************
Load a personal resource
**********************************/
void *LoadAResource(Word RezNum)
{
return(LoadAResource2(RezNum,'BRGR'));
}
/**********************************
Load a global resource
**********************************/
Handle RezHandle;
void *LoadAResource2(Word RezNum,LongWord Type)
{
Handle MyHand;
Word Stage;
Stage = 0;
do {
Stage = FreeStage(Stage,128000);
MyHand = GetResource(Type,RezNum);
if (MyHand) {
RezHandle = MyHand;
HLock(MyHand);
return *MyHand;
}
} while (Stage);
return 0;
}
/**********************************
Allow a resource to be purged
**********************************/
void ReleaseAResource(Word RezNum)
{
ReleaseAResource2(RezNum,'BRGR');
}
/**********************************
Release a global resource
**********************************/
void ReleaseAResource2(Word RezNum,LongWord Type)
{
Handle MyHand;
MyHand = GetResource(Type,RezNum); /* Get the resource if available */
HUnlock(MyHand);
HPurge(MyHand); /* Mark handle as purgeable */
}
/**********************************
Force a resource to be destroyed
**********************************/
void KillAResource(Word RezNum)
{
KillAResource2(RezNum,'BRGR');
}
/**********************************
Kill a global resource
**********************************/
void KillAResource2(Word RezNum,LongWord Type)
{
Handle MyHand;
MyHand = GetResource(Type,RezNum); /* Get the resource if available */
ReleaseResource(MyHand);
}
void SaveJunk(void *AckPtr,Word Length)
{
static Word Count=1;
FILE *fp;
char SaveName[40];
sprintf(SaveName,"SprRec%d",Count);
fp = fopen(SaveName,"wb");
fwrite(AckPtr,1,Length,fp);
fclose(fp);
++Count;
}
/**********************************
Kill a global resource
**********************************/
unsigned short SwapUShort(unsigned short Val)
{
return ((Val<<8) | (Val>>8));
}
/**********************************
Decompress using LZSS
**********************************/
#if 1
void DLZSS(Byte *Dest,Byte *Src,LongWord Length)
{
Word BitBucket;
Word RunCount;
Word Fun;
Byte *BackPtr;
if (!Length) {
return;
}
BitBucket = (Word) Src[0] | 0x100;
++Src;
do {
if (BitBucket&1) {
Dest[0] = Src[0];
++Src;
++Dest;
--Length;
} else {
RunCount = (Word) Src[0] | ((Word) Src[1]<<8);
Fun = 0x1000-(RunCount&0xfff);
BackPtr = Dest-Fun;
RunCount = ((RunCount>>12) & 0x0f) + 3;
if (Length >= RunCount) {
Length -= RunCount;
} else {
Length = 0;
}
do {
*Dest++ = *BackPtr++;
} while (--RunCount);
Src+=2;
}
BitBucket>>=1;
if (BitBucket==1) {
BitBucket = (Word)Src[0] | 0x100;
++Src;
}
} while (Length);
}
#endif
/**********************************
Allocate some memory
**********************************/
void *AllocSomeMem(LongWord Size)
{
void *MemPtr;
Word Stage;
Stage = 0;
do {
Stage = FreeStage(Stage,Size);
MemPtr = NewPtr(Size); /* Get some memory */
if (MemPtr) {
return MemPtr; /* Return it */
}
} while (Stage);
if (!NoSystemMem) {
MemPtr = NewPtrSys(Size);
}
return MemPtr;
}
/**********************************
Allocate some memory
**********************************/
static Word FreeStage(Word Stage,LongWord Size)
{
switch (Stage) {
case 1:
PurgeAllSounds(Size); /* Kill off sounds until I can get memory */
break;
case 2:
PlaySound(0); /* Shut down all sounds... */
PurgeAllSounds(Size); /* Purge them */
break;
case 3:
PlaySong(0); /* Kill music */
FreeSong(); /* Purge it */
PurgeAllSounds(Size); /* Make SURE it's gone! */
break;
case 4:
return 0;
}
return Stage+1;
}
/**********************************
Release some memory
**********************************/
void FreeSomeMem(void *MemPtr)
{
DisposePtr(MemPtr);
}
typedef unsigned int Word;
typedef unsigned long LongWord;
#ifndef __MACTYPES__
typedef unsigned char Byte;
typedef unsigned char Boolean;
#endif
#define BLACK 255
#define DARKGREY 250
#define BROWN 101
#define PURPLE 133
#define BLUE 210
#define DARKGREEN 229
#define ORANGE 23
#define RED 216
#define BEIGE 14
#define YELLOW 5
#define GREEN 225
#define LIGHTBLUE 150
#define LILAC 48
#define PERIWINKLE 120
#define LIGHTGREY 43
#define WHITE 0
#define __MAC__
#define __BIGENDIAN__
#define SfxActive 1
#define MusicActive 2
#define VideoSize 64000
#define SetAuxType(x,y)
#define SetFileType(x,y)
extern unsigned char *VideoPointer;
extern Word KeyModifiers;
extern Word ScanCode;
extern Word KilledSong;
extern Word SystemState;
extern Word VideoWidth;
extern LongWord LastTick;
extern LongWord YTable[480];
extern Handle RezHandle;
void DLZSS(Byte *Dest, Byte *Src,LongWord Length);
void DLZB(Byte *Dest, Byte *Src,LongWord Length);
LongWord SwapLong(LongWord Val);
unsigned short SwapUShort(unsigned short Val);
short SwapShort(short Val);
void WaitTick(void);
void WaitTicks(Word TickCount);
Word WaitTicksEvent(Word TickCount);
Word WaitEvent(void);
LongWord ReadTick(void);
void *AllocSomeMem(LongWord Size);
void FreeSomeMem(void *MemPtr);
Word GetAKey(void);
Word AllKeysUp(void);
Word WaitKey(void);
void FlushKeys(void);
Word FixMacKey(EventRecord *MyRecord);
void SoundOff(void);
void PlaySound(Word SndNum);
void StopSound(Word SndNum);
void PlaySong(Word SongNum);
void ClearTheScreen(Word Color);
void ShowPic(Word PicNum);
void InitYTable(void);
void InstallAFont(Word FontNum);
void FontUseMask(void);
void FontUseZero(void);
void SetFontXY(Word x,Word y);
void FontSetColor(Word Index,Word Color);
void DrawAString(char *TextPtr);
void DrawAChar(Word Letter);
void ultoa(LongWord Val,char *TextPtr);
Word GetRandom(Word Range);
void Randomize(void);
void DrawShape(Word x,Word y,void *ShapePtr);
void DrawXMShape(Word x,Word y,void *ShapePtr);
void DrawMShape(Word x,Word y,void *ShapePtr);
void EraseMBShape(Word x,Word y, void *ShapePtr,void *BackPtr);
Word TestMShape(Word x,Word y,void *ShapePtr);
Word TestMBShape(Word x,Word y,void *ShapePtr,void *BackPtr);
void SetAPalette(Word PalNum);
void SetAPalettePtr(unsigned char *PalPtr);
void FadeTo(Word PalNum);
void FadeToBlack(void);
void FadeToPtr(unsigned char *PalPtr);
void *LoadAResource(Word RezNum);
void ReleaseAResource(Word RezNum);
void KillAResource(Word RezNum);
void *LoadAResource2(Word RezNum,LongWord Type);
void ReleaseAResource2(Word RezNum,LongWord Type);
void KillAResource2(Word RezNum,LongWord Type);
void SaveJunk(void *AckPtr,Word Length);
#include "wolfdef.h"
/**********************************
Global data used by Wolfenstein 3-D
**********************************/
Word tilemap[MAPSIZE][MAPSIZE]; /* Main tile map */
Word ConnectCount; /* Number of valid interconnects */
connect_t areaconnect[MAXDOORS]; /* Is this area mated with another? */
Boolean areabyplayer[MAXAREAS]; /* Which areas can I see into? */
Word numstatics; /* Number of active static objects */
static_t statics[MAXSTATICS]; /* Data for the static items */
Word numdoors; /* Number of active door objects */
door_t doors[MAXDOORS]; /* Data for the door items */
Word nummissiles; /* Number of active missiles */
missile_t missiles[MAXMISSILES]; /* Data for the missile items */
Word numactors; /* Number of active actors */
actor_t actors[MAXACTORS]; /* Data for the actors */
unsigned char **GameShapes; /* Pointer to the game shape array */
Word difficulty; /* 0 = easy, 1= normal, 2=hard*/
gametype_t gamestate; /* Status of the game (Save game) */
exit_t playstate; /* Current status of the game */
Word killx,killy; /* X,Y of the thing that killed you! */
Boolean madenoise; /* True when shooting or screaming*/
Boolean playermoving; /* Is the player in motion? */
Boolean useheld; /* Holding down the use key? */
Boolean selectheld; /* Weapon select held down? */
Boolean attackheld; /* Attack button held down? */
Boolean buttonstate[NUMBUTTONS]; /* Current input */
Word joystick1; /* Joystick value */
int mousex; /* Mouse x movement */
int mousey; /* Mouse y movement */
int mouseturn; /* Mouse turn movement */
Word nextmap; /* Next map to warp to */
Word facecount; /* Time to show a specific head */
Word faceframe; /* Head pic to show */
Word elevatorx,elevatory; /* x,y of the elevator */
Word firstframe; /* if non 0, the screen is still faded out */
Word OldMapNum; /* Currently loaded map # */
loadmap_t *MapPtr; /* Pointer to current loaded map */
int clipshortangle; /* Angle for the left edge of the screen */
int clipshortangle2; /* clipshortangle * 2 */
Word viewx; /* X coord of camera */
Word viewy; /* Y coord of camera */
fixed_t viewsin; /* Base sine for viewing angle */
fixed_t viewcos; /* Base cosine for viewing angle */
Word normalangle; /* Normalized angle for view (NSEW) */
Word centerangle; /* viewangle in fineangles*/
Word centershort; /* viewangle in 64k angles*/
Word topspritescale; /* Scale of topmost sprite */
Word topspritenum; /* Shape of topmost sprite */
Word xscale[1024]; /* Scale factor for width of the screen */
Word numvisspr; /* Number of valid visible sprites */
vissprite_t vissprites[MAXVISSPRITES]; /* Buffer for sprite records */
Word xevents[MAXVISSPRITES]; /* Scale events for sprite sort */
Word sortbuffer[MAXVISSPRITES]; /* mergesort requires an extra buffer*/
Word *firstevent; /* First event in sorted list */
Boolean areavis[MAXAREAS]; /* Area visible */
Word bspcoord[4]; /* Rect for the BSP search */
Word TicCount; /* Ticks since last screen draw */
Word LastTicCount; /* Tick value at start of render */
Boolean IntermissionHack; /* Hack for preventing double score drawing during intermission */
Word rw_maxtex;
Word rw_mintex;
LongWord rw_scalestep;
Word rw_midpoint;
Boolean rw_downside;
int rw_centerangle;
Byte *rw_texture;
LongWord rw_scale;
Byte *ArtData[64];
void *SpriteArray[S_LASTONE];
Word MacVidSize = -1;
Word SlowDown = 1; /* Force the game to 15 hz */
Word MouseEnabled = 0; /* Allow mouse control */
Word GameViewSize = 0; /* Size of the game screen */
Word NoWeaponDraw=1; /* Flag to not draw the weapon on the screen */
maplist_t *MapListPtr; /* Pointer to map info record */
unsigned short *SongListPtr; /* Pointer to song list record */
unsigned short *WallListPtr; /* Pointer to wall list record */
Word MaxScaler = 1; /* Maximum number of VALID scalers */
Boolean ShowPush; /* Cheat for pushwalls */
Byte textures[MAPSIZE*2+5][MAPSIZE]; /* Texture indexes */
Word NaziSound[] = {SND_ESEE,SND_ESEE2,SND_ESEE3,SND_ESEE4};
classinfo_t classinfo[] = { /* Info for all the bad guys */
{SND_ESEE,SND_EDIE, /* Nazi */
ST_GRD_WLK1, ST_GRD_STND, ST_GRD_ATK1,ST_GRD_PAIN,ST_GRD_DIE,
100, 5, 0x0F, 6},
{SND_ESEE,SND_EDIE, /* Blue guard */
ST_OFC_WLK1, ST_OFC_STND, ST_OFC_ATK1,ST_OFC_PAIN,ST_OFC_DIE,
400, 10, 0x01, 12},
{SND_ESEE,SND_EDIE, /* White officer */
ST_SS_WLK1, ST_SS_STND, ST_SS_ATK1,ST_SS_PAIN,ST_SS_DIE,
500, 6, 0x07, 25},
{SND_DOGBARK,SND_DOGDIE, /* Dog */
ST_DOG_WLK1,ST_DOG_STND,ST_DOG_ATK1,ST_DOG_WLK1,ST_DOG_DIE,
200, 9, 0x07, 1},
{SND_NOSOUND,SND_EDIE, /* Mutant */
ST_MUTANT_WLK1, ST_MUTANT_STND, ST_MUTANT_ATK1,ST_MUTANT_PAIN,ST_MUTANT_DIE,
400, 7, 0x01, 18},
{SND_GUTEN,SND_EDIE, /* Hans */
ST_HANS_WLK1, ST_HANS_STND, ST_HANS_ATK1,ST_GRD_STND,ST_HANS_DIE,
5000,7, 0x01, 250},
{SND_SHITHEAD,SND_EDIE, /* Dr. Schabbs */
ST_SCHABBS_WLK1, ST_SCHABBS_STND, ST_SCHABBS_ATK1,ST_GRD_STND,ST_SCHABBS_DIE,
5000, 5,0x01, 350},
{SND_GUTEN,SND_EDIE, /* Trans */
ST_TRANS_WLK1, ST_TRANS_STND, ST_TRANS_ATK1,ST_GRD_STND,ST_TRANS_DIE,
5000, 7,0x01, 300},
{SND_DOGBARK,SND_EDIE, /* Uber knight */
ST_UBER_WLK1, ST_UBER_STND, ST_UBER_ATK1,ST_GRD_STND,ST_UBER_DIE,
5000, 8,0x01, 400},
{SND_COMEHERE,SND_EDIE, /* Dark knight */
ST_DKNIGHT_WLK1, ST_DKNIGHT_STND, ST_DKNIGHT_ATK1,ST_GRD_STND,ST_DKNIGHT_DIE,
5000, 7,0x01, 450},
{SND_SHIT,SND_EDIE, /* Mechahitler */
ST_MHITLER_WLK1, ST_MHITLER_STND, ST_MHITLER_ATK1,ST_GRD_STND, ST_HITLER_DIE,
5000, 7,0x01, 500},
{SND_HITLERSEE,SND_EDIE, /* Hitler */
ST_HITLER_WLK1, ST_MHITLER_STND, ST_HITLER_ATK1,ST_GRD_STND,ST_HITLER_DIE,
5000, 8,0x01, 500},
};
#include "Wolfdef.h"
#include <string.h>
/**********************************
Rules for door operation
door->position holds the amount the door is open, ranging from 0 to TILEGLOBAL-1
The number of doors is limited to 64 because various fields are only 6 bits
Open doors conect two areas, so sounds will travel between them and sight
will be checked when the player is in a connected area.
areaconnect has a list of connected area #'s, used to create the table areabyplayer
Every time a door opens or closes the areabyplayer matrix gets recalculated.
An area is True if it connects with the player's current spor.
**********************************/
/**********************************
Insert a connection between two rooms
Note: I can have MORE than one connection between rooms
so it is VALID to have duplicate entries (1,6) & (1,6)
Each call to AddConnection must be balanced with a call to RemoveConnection
**********************************/
void AddConnection(Word Area1,Word Area2)
{
connect_t *DestPtr;
DestPtr = &areaconnect[ConnectCount]; /* Make pointer to the last record */
DestPtr->Area1 = Area1; /* Init the struct */
DestPtr->Area2 = Area2;
++ConnectCount; /* Add 1 to the valid list */
}
/**********************************
Remove a connection between two rooms
Note: I can have MORE than one connection between rooms
so it is VALID to have duplicate entries (1,6) & (1,6)
**********************************/
void RemoveConnection(Word Area1,Word Area2)
{
Word i;
connect_t *DestPtr;
DestPtr = &areaconnect[0]; /* Init the scan pointer */
i = ConnectCount; /* Init the count */
if (!i) {
return;
}
do {
if (DestPtr->Area1 == Area1 && /* Match? */
DestPtr->Area2 == Area2) {
--ConnectCount; /* Remove the count */
DestPtr[0] = areaconnect[ConnectCount]; /* Copy last to current */
break; /* I'm done! */
}
++DestPtr; /* Next entry to scan */
} while (--i); /* Should NEVER fall out! */
}
/**********************************
Recursive routine to properly set the areabyplayer array by
using the contents of the areaconnect array.
Scans outward from playerarea, marking all connected areas.
**********************************/
void RecursiveConnect(Word areanumber)
{
Word i;
Word j;
connect_t *AreaPtr;
areabyplayer[areanumber] = TRUE; /* Mark this spot (Prevent overflow) */
i = ConnectCount; /* Init index */
if (i) { /* No doors available? */
AreaPtr = &areaconnect[0]; /* Get a local pointer */
do {
if (AreaPtr->Area1 == areanumber) { /* Am I in this pair? */
j = AreaPtr->Area2; /* Follow this path */
goto TryIt;
}
if (AreaPtr->Area2 == areanumber) { /* The other side? */
j = AreaPtr->Area1; /* Follow this side */
TryIt:
if (!areabyplayer[j]) { /* Already been here? */
RecursiveConnect(j); /* Link it in... */
}
}
++AreaPtr; /* Next entry */
} while (--i); /* All done? */
}
}
/**********************************
Properly set the areabyplayer record
**********************************/
void ConnectAreas(void)
{
memset(areabyplayer,0,sizeof(areabyplayer)); /* Zap the memory */
RecursiveConnect(MapPtr->areasoundnum[actors[0].areanumber]); /* Start here */
}
/**********************************
Start a door opening
**********************************/
void OpenDoor(door_t *door)
{
if (door->action == DR_OPEN) { /* Already open? */
door->ticcount = 0; /* Reset open time (Keep open) */
} else {
door->action = DR_OPENING; /* start it opening*/
} /* The door will be made passable when it is totally open */
}
/**********************************
Start a door closing
**********************************/
void CloseDoor(door_t *door)
{
Word tile,tilex,tiley;
Word *TilePtr;
int delta;
/* don't close on anything solid */
tilex = door->tilex; /* Get the current tile */
tiley = door->tiley;
TilePtr = &tilemap[tiley][tilex]; /* Get pointer to tile map */
if (door->action != DR_OPENING) { /* In the middle of opening? */
/* don't close on an actor or bonus item */
tile = TilePtr[0]; /* What's the tile? */
if (tile & TI_BODY) {
door->action = DR_WEDGEDOPEN; /* bodies never go away */
return;
}
if (tile & (TI_ACTOR | TI_GETABLE) ) { /* Removable? */
door->ticcount = 60; /* wait a while before trying to close again */
return;
}
/* Don't close on the player */
delta = actors[0].x - ((tilex<<8)|0x80);
if (w_abs(delta) <= (0x82+PLAYERSIZE)) {
delta = actors[0].y - ((tiley<<8)|0x80);
if (w_abs(delta) <= (0x82+PLAYERSIZE)) {
return; /* It's touching the player! */
}
}
}
door->action = DR_CLOSING; /* Close the door */
TilePtr[0] |= (TI_BLOCKMOVE|TI_BLOCKSIGHT); /* make the door space a solid tile*/
}
/**********************************
Open or Close a door (Press space at a door)
**********************************/
void OperateDoor(Word dooron)
{
Word type;
door_t *door;
door = &doors[dooron]; /* Which door? */
type = door->info>>1; /* Get the door type */
if ( (type==1 && !(gamestate.keys&1)) || (type==2 && !(gamestate.keys&2)) ) {
PlaySound(SND_LOCKEDDOOR); /* The door is locked */
return;
}
switch (door->action) {
case DR_CLOSED:
case DR_CLOSING:
OpenDoor(door); /* Open the door */
break;
case DR_OPEN:
case DR_OPENING:
CloseDoor(door); /* Close the door */
}
}
/**********************************
Close the door after a few seconds
**********************************/
void DoorOpen(door_t *door)
{
door->ticcount+=TicCount; /* Inc the tic value */
if (door->ticcount >= OPENTICS) { /* Time up? */
door->ticcount = OPENTICS-1; /* So if the door can't close it will keep trying*/
CloseDoor(door); /* Try to close the door */
}
}
/**********************************
Step the door animation for open, mark as DR_OPEN if all the way open
**********************************/
void DoorOpening(door_t *door)
{
Word position;
Word area1,area2;
Byte *SoundNumPtr;
position = door->position; /* Get the pixel position */
if (!position) { /* Fully closed? */
/* door is just starting to open, so connect the areas*/
SoundNumPtr = MapPtr->areasoundnum;
area1 = SoundNumPtr[door->area1];
area2 = SoundNumPtr[door->area2];
AddConnection(area1,area2); /* Link the two together */
ConnectAreas(); /* Link the map */
if (areabyplayer[area1] || areabyplayer[area2]) { /* Can I hear it? */
PlaySound(SND_OPENDOOR); /* Play the door sound */
}
}
/* slide the door open a bit */
position += DOORSPEED*TicCount; /* Move the door a bit */
if (position >= TILEGLOBAL-1) { /* Fully open? */
/* Door is all the way open */
position = TILEGLOBAL-1; /* Set to maximum */
door->ticcount = 0; /* Reset the timer for closing */
door->action = DR_OPEN; /* Mark as open */
tilemap[door->tiley][door->tilex] &= ~(TI_BLOCKMOVE|TI_BLOCKSIGHT); /* Mark as enterable */
}
door->position = position; /* Set the new position */
}
/**********************************
Step the door animation for close,
mark as DR_CLOSED if all the way closed
**********************************/
void DoorClosing(door_t *door)
{
int position;
Byte *SoundNumPtr;
position = door->position-(DOORSPEED*TicCount); /* Close a little more */
if (position <= 0) { /* Will I close now? */
/* door is closed all the way, so disconnect the areas*/
SoundNumPtr = MapPtr->areasoundnum; /* Unlink the sound areas */
RemoveConnection(SoundNumPtr[door->area1],SoundNumPtr[door->area2]);
ConnectAreas(); /* Reset areabyplayer */
door->action = DR_CLOSED; /* It's closed */
position = 0; /* Mark as closed */
}
door->position = position; /* Set the new position */
}
/**********************************
Process all the doors each game loop
**********************************/
void MoveDoors(void)
{
Word dooron; /* Which door am I on? */
door_t *door; /* Pointer to current door */
dooron = numdoors; /* How many doors to scan? */
if (dooron) { /* Any doors at all? */
door = doors; /* Pointer to the first door */
do {
switch (door->action) { /* Call the action code */
case DR_OPEN:
DoorOpen(door); /* Check to close the door */
break;
case DR_OPENING: /* Continue the door opening */
DoorOpening(door);
break;
case DR_CLOSING: /* Close the door */
DoorClosing(door);
}
++door; /* Next pointer */
} while (--dooron); /* All doors done? */
}
}
/* enmove.c*/
#include "wolfdef.h"
dirtype opposite[9] =
{west,southwest,south,southeast,east,northeast,north,northwest,nodir};
dirtype diagonal[9][9] = {
/* east */ {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir},
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},
/* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir},
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},
/* west */ {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir},
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},
/* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir},
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir},
{nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}
};
/**********************************
Changes actor to a new state, setting ticcount to the max for that state
**********************************/
void NewState(actor_t *ActorPtr,stateindex_t state)
{
state_t *StatePtr;
StatePtr = &states[state]; /* Get the state record pointer */
ActorPtr->state = state; /* Set the actor's state */
ActorPtr->ticcount = StatePtr->tictime; /* Set the initial tick value */
ActorPtr->pic = StatePtr->shapenum; /* Set the current shape number */
}
/**********************************
Attempts to move actor in its current (ActorPtr->dir) direction.
If blocked by either a wall or an actor returns FALSE
If move is either clear or blocked only by a door, returns TRUE and sets
ActorPtr->tilex = new destination
ActorPtr->tiley
ActorPtr->areanumber = the floor tile number (0-(MAXAREAS-1)) of destination
ActorPtr->distance = TILEGLOBAL, or doornumber if a door is blocking the way
If a door is in the way, an OpenDoor call is made to start it opening.
The actor code should wait until
doorobjlist[ActorPtr->distance].action = dr_open, meaning the door has been
fully opened
**********************************/
/**********************************
Check if I can move in a diagonal direction
**********************************/
Boolean CheckDiag(Word x,Word y)
{
/* anything blocking stops diagonal move*/
if (tilemap[y][x]&(TI_BLOCKMOVE|TI_ACTOR)) {
return FALSE; /* It's blocked */
}
return TRUE; /* It's open! */
}
/**********************************
Check if I can move in a sideways direction
also do the code for an actor to open a door
return 0 if blocked, 1 if open, 2 if I need to open a door
**********************************/
Word CheckSide(Word x,Word y,actor_t *ActorPtr)
{
Word temp;
temp=tilemap[y][x]; /* Get the tile */
if (temp & TI_DOOR) { /* Door? */
if (!(temp&TI_BLOCKMOVE)) { /* Not blocked? */
return 1; /* door is open*/
}
if (ActorPtr->class == CL_DOG) {
return 0; /* dogs can't open doors */
}
return 2; /* I have to open the door */
}
if (temp&(TI_BLOCKMOVE|TI_ACTOR)) { /* Normally blocked? */
return 0; /* Can't go this way */
}
return 1; /* I can go! */
}
/**********************************
Try to move the actor around
**********************************/
Boolean TryWalk (actor_t *ActorPtr)
{
Word x,y;
Word Temp;
Word *TileMapPtr;
Word tile;
x = ActorPtr->goalx; /* Where is my goal x,y? */
y = ActorPtr->goaly;
switch (ActorPtr->dir) { /* Go in my direction */
case north: /* Go n,s,e,w */
--y;
goto DoSide;
case east:
++x;
goto DoSide;
case south:
++y;
goto DoSide;
case west:
--x;
DoSide:
Temp = CheckSide(x,y,ActorPtr); /* See if I can move this way */
if (!Temp) { /* Not this way? */
return FALSE; /* Exit */
}
if (Temp==2) { /* Door? */
OpenDoor(&doors[tilemap[y][x]&TI_NUMMASK]); /* Open the door */
ActorPtr->flags |= (FL_WAITDOOR|FL_NOTMOVING); /* Force the actor to pause */
return TRUE; /* I'm ok! */
}
break; /* Continue */
case northeast:
if (!CheckDiag(x+1,y)) {
return FALSE;
}
y--;
goto FixEast;
case southeast:
if (!CheckDiag(x+1,y)) {
return FALSE;
}
y++;
FixEast:
if (!CheckDiag(x,y)) {
return FALSE;
}
x++;
if (!CheckDiag(x,y)) {
return FALSE;
}
break;
case southwest:
if (!CheckDiag(x-1,y)) {
return FALSE;
}
y++;
goto FixWest;
case northwest:
if (!CheckDiag(x-1,y)) {
return FALSE;
}
y--;
FixWest:
if (!CheckDiag(x,y)) {
return FALSE;
}
x--;
if (!CheckDiag(x,y)) {
return FALSE;
}
}
/* invalidate the move if moving onto the player */
if (areabyplayer[MapPtr->areasoundnum[ActorPtr->areanumber]]) {
if (w_abs(((x<<FRACBITS)|0x80) - actors[0].x) < MINACTORDIST
&& w_abs(((y<<FRACBITS)|0x80) - actors[0].y) < MINACTORDIST) {
return FALSE;
}
}
/* remove old actor marker*/
tilemap[ActorPtr->goaly][ActorPtr->goalx] &= ~TI_ACTOR;
/* place new actor marker*/
TileMapPtr = &tilemap[y][x]; /* Get pointer to cell */
tile = TileMapPtr[0]; /* Get the cell */
TileMapPtr[0] = tile | TI_ACTOR; /* Mark with an actor */
Temp = ActorPtr - &actors[0];
MapPtr->tilemap[y][x] = Temp; /* Save the current actor # */
ActorPtr->goalx = x;
ActorPtr->goaly = y;
if (!(tile&TI_DOOR) ) { /* doorways are not areas*/
ActorPtr->areanumber = tile&TI_NUMMASK;
}
ActorPtr->distance = TILEGLOBAL; /* Move across 1 whole tile */
ActorPtr->flags &= ~(FL_WAITDOOR|FL_NOTMOVING); /* I'm not waiting and I'm moving */
return TRUE; /* It's ok! */
}
/**********************************
Attempts to choose and initiate a movement for actor that sends it towards
the player while dodging
**********************************/
void SelectDodgeDir(actor_t *ActorPtr)
{
int deltax,deltay;
Word i;
Word absdx,absdy;
dirtype dirtry[5];
dirtype turnaround,tdir;
turnaround=opposite[ActorPtr->dir];
deltax = actors[0].x - ActorPtr->x;
deltay = actors[0].y - ActorPtr->y;
/* arange 5 direction choices in order of preference*/
/* the four cardinal directions plus the diagonal straight towards*/
/* the player*/
if (deltax>0) {
dirtry[1]= east;
dirtry[3]= west;
} else {
dirtry[1]= west;
dirtry[3]= east;
}
if (deltay>0) {
dirtry[2]= south;
dirtry[4]= north;
} else {
dirtry[2]= north;
dirtry[4]= south;
}
/* randomize a bit for dodging*/
absdx = w_abs(deltax);
absdy = w_abs(deltay);
if (absdx > absdy) {
tdir = dirtry[1];
dirtry[1] = dirtry[2];
dirtry[2] = tdir;
tdir = dirtry[3];
dirtry[3] = dirtry[4];
dirtry[4] = tdir;
}
if (w_rnd() & 1) {
tdir = dirtry[1];
dirtry[1] = dirtry[2];
dirtry[2] = tdir;
tdir = dirtry[3];
dirtry[3] = dirtry[4];
dirtry[4] = tdir;
}
dirtry[0] = diagonal[dirtry[1]][dirtry[2]];
/* try the directions until one works*/
i = 0;
do {
tdir = dirtry[i];
if (tdir != nodir && tdir != turnaround) {
ActorPtr->dir = tdir;
if (TryWalk(ActorPtr)) { /* Can I go this way? */
return; /* Yep! */
}
}
} while(++i<5); /* All tries done? */
/* turn around only as a last resort*/
if (turnaround != nodir) {
ActorPtr->dir = turnaround;
if (TryWalk(ActorPtr)) {
return;
}
}
ActorPtr->dir = nodir; /* Stop the motion */
ActorPtr->flags |= FL_NOTMOVING; /* Kill the logic! */
}
/**********************************
Attempts to choose and initiate a movement for actor that sends it towards
the player but doesn't try to dodge
**********************************/
void SelectChaseDir(actor_t *ActorPtr)
{
int deltax,deltay;
dirtype d[3];
dirtype tdir, olddir, turnaround;
olddir = (dirtype) ActorPtr->dir; /* Save the current direction */
turnaround=opposite[olddir]; /* What's the opposite direction */
deltax = actors[0].x - ActorPtr->x; /* Which way to travel? */
deltay = actors[0].y - ActorPtr->y;
if (deltax>0) {
d[1]= east;
} else if (!deltax) {
d[1]= nodir;
} else {
d[1]= west;
}
if (deltay>0) {
d[2]=south;
} else if (!deltay) {
d[2]=nodir;
} else {
d[2]=north;
}
if (w_abs(deltay)>w_abs(deltax)) { /* Swap if Y is greater */
tdir=d[1];
d[1]=d[2];
d[2]=tdir;
}
if (d[1]==turnaround) { /* Try not to turn around */
d[1]=nodir;
}
if (d[2]==turnaround) { /* Try not to turn around */
d[2]=nodir;
}
if (d[1]!=nodir) { /* East/West movement? */
ActorPtr->dir = d[1]; /* Try to move */
if (TryWalk(ActorPtr)) {
return; /*either moved forward or attacked*/
}
}
if (d[2]!=nodir) { /* North/South movement? */
ActorPtr->dir =d[2];
if (TryWalk(ActorPtr)) {
return;
}
}
/* there is no direct path to the player, so pick another direction */
if (olddir!=nodir) {
ActorPtr->dir =olddir; /* Continue in the old direction */
if (TryWalk(ActorPtr)) {
return;
}
}
if (w_rnd()&1) { /*randomly determine direction of search*/
tdir = north;
do {
if (tdir!=turnaround) {
ActorPtr->dir =tdir;
if (TryWalk(ActorPtr)) {
return;
}
}
} while(++tdir<(west+1));
} else {
tdir = west;
do {
if (tdir!=turnaround) {
ActorPtr->dir =tdir;
if ( TryWalk(ActorPtr)) {
return;
}
}
} while(--tdir>=north);
}
if (turnaround != nodir) { /* Alright, try backwards now */
ActorPtr->dir =turnaround;
if ( TryWalk(ActorPtr) ) {
return;
}
}
ActorPtr->dir = nodir; /* Can't move, I give up */
ActorPtr->flags |= FL_NOTMOVING;
}
/**********************************
Moves actor <move> global units in actor->dir direction
Actors are not allowed to move inside the player
Does NOT check to see if the move is tile map valid
**********************************/
void MoveActor(actor_t *ActorPtr,Word move)
{
Word tryx,tryy;
tryx = ActorPtr->x; /* Get the x and y */
tryy = ActorPtr->y;
switch (ActorPtr->dir) {;
case northeast: /* Move to the new x,y */
tryx += move;
case north:
tryy -= move;
break;
case southeast:
tryy += move;
case east:
tryx += move;
break;
case southwest:
tryx -= move;
case south:
tryy += move;
break;
case northwest:
tryy -= move;
case west:
tryx -= move;
}
/* check to make sure it's not moving on top of player*/
if (areabyplayer[MapPtr->areasoundnum[ActorPtr->areanumber]]) {
if (w_abs(tryx - actors[0].x)<MINACTORDIST) {
if (w_abs(tryy - actors[0].y)<MINACTORDIST) {
return;
}
}
}
ActorPtr->distance-= move; /* Remove the distance */
ActorPtr->x = tryx; /* Save the new x,y */
ActorPtr->y = tryy;
}
#include "wolfdef.h"
/**********************************
Drops a bonus item at the x,y of the actor
If there are no free item spots, nothing is done.
**********************************/
void PlaceItemType(Word shape,actor_t *ActorPtr)
{
Word tile;
Word x,y;
static_t *StaticPtr;
if (numstatics>=MAXSTATICS) { /* Already full? */
return; /* Get out! */
}
StaticPtr = &statics[numstatics]; /* Get pointer to the record */
/* drop bonus items on closest tile, rather than goal tile (unless it is a closing door) */
x = ActorPtr->x >> FRACBITS;
y = ActorPtr->y >> FRACBITS;
tile = tilemap[y][x];
if ( (tile&TI_BLOCKMOVE) && !(tile &TI_ACTOR) ) {
x = ActorPtr->goalx;
y = ActorPtr->goaly;
}
StaticPtr->pic = shape;
StaticPtr->x = (x<<FRACBITS)|0x80;
StaticPtr->y = (y<<FRACBITS)|0x80;
StaticPtr->areanumber = ActorPtr->areanumber;
tilemap[y][x] |= TI_GETABLE; /* Mark as getable */
++numstatics; /* A new static */
}
/**********************************
Kill an actor
Also drop off any items you can get from a dead guy.
**********************************/
void KillActor(actor_t *ActorPtr)
{
Word x,y;
GivePoints(classinfo[ActorPtr->class].points); /* Award the score */
switch(ActorPtr->class) { /* Drop anything special? */
case CL_SS:
PlaceItemType(S_MACHINEGUN,ActorPtr); /* Give a gun */
break;
case CL_OFFICER:
case CL_MUTANT:
case CL_GUARD:
PlaceItemType(S_AMMO,ActorPtr); /* Drop some ammo */
break;
case CL_HANS:
case CL_SCHABBS:
case CL_TRANS:
case CL_UBER:
case CL_DKNIGHT:
PlaceItemType(S_G_KEY,ActorPtr); /* Drop a key */
break;
}
++gamestate.killcount; /* I killed someone! */
ActorPtr->flags = FL_DEAD; /* remove old actor marker*/
tilemap[ActorPtr->goaly][ActorPtr->goalx] &= ~TI_ACTOR;
x = ActorPtr->x >> FRACBITS;
y = ActorPtr->y >> FRACBITS;
tilemap[y][x] |= TI_BODY; /* body flag on most apparant, no matter what */
NewState(ActorPtr,classinfo[ActorPtr->class].deathstate); /* start the death animation */
}
/**********************************
Does damage points to enemy actor, either putting it into a stun frame or
killing it.
Called when an enemy is hit.
**********************************/
static Word PainTick;
void DamageActor(Word damage,actor_t *ActorPtr)
{
stateindex_t pain;
madenoise = TRUE; /* You made some noise! */
/* do double damage if shooting a non attack mode actor*/
if ( !(ActorPtr->flags & FL_ACTIVE) ) {
if (difficulty<3) { /* Death incarnate? */
damage <<= 1;
}
FirstSighting(ActorPtr); /* Put into combat mode*/
}
if (damage >= ActorPtr->hitpoints) { /* Did I kill it? */
KillActor(ActorPtr); /* Die!! */
return;
}
ActorPtr->hitpoints -= damage; /* Remove the damage */
if (ActorPtr->class == CL_MECHAHITLER && ActorPtr->hitpoints <= 250 && ActorPtr->hitpoints+damage > 250) {
/* hitler losing armor */
PlaySound(SND_SHIT); /* Remove armor */
pain = ST_MHITLER_DIE1;
} else {
if ((ReadTick() - PainTick) >= 30) {
PainTick = ReadTick();
PlaySound(SND_PAIN); /* Ow!! */
}
pain = classinfo[ActorPtr->class].painstate; /* Do pain */
}
if (pain) { /* some classes don't have pain frames */
if (ActorPtr->state != pain) { /* Already in pain? */
NewState(ActorPtr,pain);
}
}
}
/**********************************
Throw a Missile at the player
**********************************/
void A_Throw(actor_t *ActorPtr)
{
Word angle;
int speed;
missile_t *MissilePtr;
PlaySound(SND_ROCKET|0x8000);
MissilePtr = GetNewMissile(); /* Create a missile */
MissilePtr->x = ActorPtr->x;
MissilePtr->y = ActorPtr->y;
MissilePtr->areanumber = ActorPtr->areanumber;
/* get direction from enemy to player */
angle = PointToAngle(ActorPtr->x,ActorPtr->y);
angle >>= SHORTTOANGLESHIFT;
speed = costable[angle];
speed = speed/5;
MissilePtr->xspeed = -speed;
speed = sintable[angle];
speed = speed/5;
MissilePtr->yspeed = speed;
MissilePtr->pic = S_NEEDLE; /* Hurl a needle */
MissilePtr->flags = MF_HITPLAYER | MF_HITSTATICS; /* Can hit the player */
MissilePtr->type = MI_NEEDLE; /* Needle missile */
}
/**********************************
Launch a rocket at the player
**********************************/
void A_Launch(actor_t *ActorPtr)
{
Word angle;
int speed;
missile_t *MissilePtr;
PlaySound(SND_ROCKET|0x8000);
MissilePtr = GetNewMissile();
MissilePtr->x = ActorPtr->x;
MissilePtr->y = ActorPtr->y;
MissilePtr->areanumber = ActorPtr->areanumber;
/* get direction from player to boss*/
angle = PointToAngle (ActorPtr->x,ActorPtr->y);
angle >>= SHORTTOANGLESHIFT;
speed = costable[angle];
speed = speed/5;
MissilePtr->xspeed = -speed;
speed = sintable[angle];
speed = speed/5;
MissilePtr->yspeed = speed;
MissilePtr->pic = S_ENMISSILE; /* Rocket */
MissilePtr->flags = MF_HITPLAYER | MF_HITSTATICS;
MissilePtr->type = MI_EMISSILE;
A_Shoot(ActorPtr); /* also shoot a bullet */
}
/**********************************
Scream a death sound
**********************************/
void A_Scream(actor_t *ActorPtr)
{
Word Sound,i;
Sound = classinfo[ActorPtr->class].deathsound; /* Get the sound # */
if (Sound==SND_EDIE) { /* Normal death sound? */
if (w_rnd()&1) { /* Play one randomly */
++Sound;
}
i = 0;
do {
StopSound(NaziSound[i]); /* Kill all Nazi voices */
} while (++i<4);
}
PlaySound(Sound); /* Play the sound */
}
/**********************************
Body hitting the ground
**********************************/
void A_Thud(actor_t *ActorPtr)
{
PlaySound(SND_BODYFALL);
}
/**********************************
You win the game!
**********************************/
void A_Victory(actor_t *ActorPtr)
{
playstate = EX_COMPLETED;
}
/**********************************
Drop Hitler's armor and let hitler run around
**********************************/
void A_HitlerMorph(actor_t *ActorPtr)
{
missile_t *MissilePtr;
/* Use an inert missile for the armor remnants */
MissilePtr = GetNewMissile();
MissilePtr->x = ActorPtr->x; /* Pass the armor x,y */
MissilePtr->y = ActorPtr->y;
MissilePtr->areanumber = ActorPtr->areanumber;
MissilePtr->xspeed = 0; /* No motion */
MissilePtr->yspeed = 0;
MissilePtr->flags = 0;
MissilePtr->type = -1; /* Maximum time */
MissilePtr->pic = S_MHITLER_DIE4; /* Set the picture */
ActorPtr->class = CL_HITLER; /* Convert to true hitler */
ActorPtr->speed = 40/4; /* faster without armor*/
}
/**********************************
Try to damage the player, based on skill level and player's speed
**********************************/
void A_Shoot(actor_t *ActorPtr)
{
Word damage; /* Damage to inflict */
Word distance;
if (!areabyplayer[MapPtr->areasoundnum[ActorPtr->areanumber]]) { /* In the same area? */
return;
}
madenoise = TRUE; /* I made a sound! */
if (ActorPtr->class >= CL_HANS) { /* Boss? */
PlaySound(SND_BIGGUN|0x8000); /* Boom! */
} else {
PlaySound(SND_GUNSHT|0x8000); /* Bang! */
}
if (!CheckLine(ActorPtr)) { /* Player is behind a wall*/
return; /* Can't shoot! */
}
distance = CalcDistance(ActorPtr); /* How far? (0-4095 range) */
if (distance >= TILEGLOBAL*16) { /* Too far away? */
return;
}
if (ActorPtr->class == CL_OFFICER || ActorPtr->class >= CL_HANS) { /* better shots */
if (distance < (16*16)) {
distance = 0; /* Zap the distance */
} else {
distance -= (16*16);
}
}
if (playermoving) { /* harder to hit when moving*/
if (distance >= (224*16)) {
return;
}
distance += (32*16);
}
/* see if the shot was a hit*/
if ((w_rnd()*16)>distance) {
switch(difficulty) {
case 0:
damage = (w_rnd()&3)+1;
break;
case 1:
damage = (w_rnd()&7)+1;
break;
default:
damage = (w_rnd()&7)+3;
}
if (distance<(32*16)) {
damage <<= 2;
} else if (distance<(64*16)) {
damage <<= 1;
}
TakeDamage(damage,ActorPtr->x,ActorPtr->y); /* Hit the player (Pass the killer's x,y) */
}
}
/**********************************
Bite the player
**********************************/
void A_Bite(actor_t *ActorPtr)
{
Word dmg;
PlaySound(SND_DOGBARK); /* Take a bite! */
if (CalcDistance(ActorPtr)<=BITERANGE) { /* In range? */
switch (difficulty) {
case 0:
dmg = (w_rnd()&3)+3; /* Small bite */
break;
case 1:
dmg = (w_rnd()&7)+3; /* Medium bite */
break;
default:
dmg = (w_rnd()&15)+4; /* BIG bite */
}
TakeDamage(dmg,ActorPtr->x,ActorPtr->y); /* Pass along the damage */
}
}
/**********************************
Return the distance between the player and this actor
**********************************/
Word CalcDistance(actor_t *ActorPtr)
{
Word absdx;
Word absdy;
absdx = w_abs(ActorPtr->x - actors[0].x);
absdy = w_abs(ActorPtr->y - actors[0].y);
return (absdx > absdy) ? absdx : absdy; /* Return the larger */
}
/**********************************
Called every few frames to check for sighting and attacking the player
**********************************/
Word shootchance[8] = {256,64,32,24,20,16,12,8};
void A_Target(actor_t *ActorPtr)
{
Word chance; /* % chance of hit */
Word distance; /* Distance of critters */
if (!areabyplayer[MapPtr->areasoundnum[ActorPtr->areanumber]] || !CheckLine(ActorPtr)) {
ActorPtr->flags &= ~FL_SEEPLAYER; /* Can't see you */
return;
}
ActorPtr->flags |= FL_SEEPLAYER; /* I see you */
distance = CalcDistance(ActorPtr); /* Get the distance */
if (distance < BITERANGE) { /* always attack when this close */
goto attack;
}
if (ActorPtr->class == CL_DOG) { /* Dogs can only bite */
return;
}
if (ActorPtr->class == CL_SCHABBS && distance <= TILEGLOBAL*4) {
goto attack; /* Dr. schabbs always attacks */
}
if (distance >= TILEGLOBAL*8) { /* Too far? */
return;
}
chance = shootchance[distance>>FRACBITS]; /* Get the base chance */
if (difficulty >= 2) {
chance <<= 1; /* Increase chance */
}
if (w_rnd() < chance) {
attack: /* go into attack frame*/
NewState(ActorPtr,classinfo[ActorPtr->class].attackstate);
}
}
/**********************************
MechaHitler takes a step
**********************************/
void A_MechStep(actor_t *ActorPtr)
{
PlaySound(SND_MECHSTEP|0x8000); /* Step sound */
A_Target(ActorPtr); /* Shoot player */
}
/**********************************
Chase the player
**********************************/
void T_Chase(actor_t *ActorPtr)
{
Word move;
/* if still centered in a tile, try to find a move */
if (ActorPtr->flags & FL_NOTMOVING) {
if (ActorPtr->flags & FL_WAITDOOR) {
TryWalk(ActorPtr); /* Waiting for a door to open*/
} else if (ActorPtr->flags & FL_SEEPLAYER) {
SelectDodgeDir(ActorPtr); /* Dodge the player's bullets */
} else {
SelectChaseDir(ActorPtr); /* Directly chase the player */
}
if (ActorPtr->flags & FL_NOTMOVING) {
return; /* Still blocked in */
}
}
/* OPTIMIZE: integral steps / tile movement */
/* cover some distance*/
move = ActorPtr->speed*TicCount; /* this could be put in the class info array*/
while (move) {
if (move < ActorPtr->distance) {
MoveActor(ActorPtr,move); /* Move one step */
return;
}
/* reached goal tile, so select another one*/
move -= ActorPtr->distance;
MoveActor(ActorPtr,ActorPtr->distance); /* move the last 1 to center*/
if (ActorPtr->flags & FL_SEEPLAYER) {
SelectDodgeDir(ActorPtr); /* Dodge the player */
} else {
SelectChaseDir(ActorPtr); /* Directly chase the player */
}
if (ActorPtr->flags & FL_NOTMOVING) {
return; /* object is blocked in*/
}
}
}
/**********************************
Move all actors for a single frame
Actions are performed as the state is entered
**********************************/
typedef void (*call_t)(actor_t *ActorPtr);
static void A_Nothing(actor_t *ActorPtr) {}
call_t thinkcalls[] = {
A_Nothing, /* No action */
T_Stand, /* Stand at attention */
T_Chase /* Chase the player */
};
call_t actioncalls[] = {
A_Nothing,
A_Target,
A_Shoot,
A_Bite,
A_Throw,
A_Launch,
A_HitlerMorph,
A_MechStep,
A_Victory,
A_Scream,
A_Thud
};
void MoveActors(void)
{
Word i; /* Index */
state_t *StatePtr; /* Pointer to state logic */
actor_t *ActorPtr; /* Pointer to Actor code */
if (numactors<2) { /* No actors to check? */
return;
}
i = 1; /* Init index */
ActorPtr = &actors[1]; /* Init the pointer to the actors */
do {
if (!(ActorPtr->flags&FL_ACTIVE) /* Is this actor in view? */
&& !areabyplayer[MapPtr->areasoundnum[ActorPtr->areanumber]]) {
goto Skip;
}
StatePtr = &states[ActorPtr->state]; /* Get the current state */
if (ActorPtr->ticcount>TicCount) { /* Count down the time */
ActorPtr->ticcount-=TicCount;
} else { /* change state if time's up */
ActorPtr->state = StatePtr->next; /* Set the next state */
StatePtr = &states[ActorPtr->state]; /* Get the new state ptr */
ActorPtr->ticcount = StatePtr->tictime; /* Reset the time */
ActorPtr->pic = StatePtr->shapenum; /* Set the new picture # */
/* action think */
actioncalls[StatePtr->action](ActorPtr); /* Call the code */
}
thinkcalls[StatePtr->think](ActorPtr); /* Perform the action */
Skip: /* Next entry */
++ActorPtr;
} while (++i<numactors);
}
#include "hidemenubar.h"
static Boolean MenuBarHidden = FALSE; /* Current state of the menu bar. */
static Rect OldeMBarRect; /* Saves rectangle enclosing real menu bar. */
static RgnHandle OldeGrayRgn; /* Saves the region defining the desktop */
static short OldMBarHeight; /* Previous menu bar height */
extern GDHandle gMainGDH;
/********************************
Hide the menu bar (If visible)
********************************/
void HideMenuBar(void)
{
RgnHandle menuRgn;
WindowPeek theWindow;
GDHandle TempHand;
TempHand = GetMainDevice();
if (TempHand!=gMainGDH) { /* Main graphics handle */
return;
}
if (!MenuBarHidden) { /* Already hidden? */
OldMBarHeight = LMGetMBarHeight(); /* Get the height in pixels */
OldeGrayRgn = NewRgn(); /* Make a new region */
CopyRgn(GetGrayRgn(), OldeGrayRgn); /* Copy the background region */
OldeMBarRect = qd.screenBits.bounds; /* Make a region from the rect or the monitor width */
OldeMBarRect.bottom = OldeMBarRect.top + OldMBarHeight; /* Top to bottom of menu */
menuRgn = NewRgn(); /* Convert to region */
RectRgn(menuRgn, &OldeMBarRect);
UnionRgn(GetGrayRgn(), menuRgn, GetGrayRgn()); /* Add the menu area to background */
theWindow = (WindowPeek)FrontWindow();
PaintOne((WindowPtr)theWindow, menuRgn); /* Redraw the front window */
PaintBehind((WindowPtr)theWindow, menuRgn); /* Redraw all other windows */
CalcVis((WindowPtr)theWindow); /* Resize the visible region */
CalcVisBehind((WindowPtr)theWindow, menuRgn); /* Resize the visible regions for all others */
DisposeRgn(menuRgn); /* Release the menu region */
MenuBarHidden = TRUE; /* It is now hidden */
ZapMHeight(); /* Zap the height */
}
}
/********************************
Show the menu bar (If hidden)
********************************/
void ShowMenuBar(void)
{
WindowPeek theWindow;
if (MenuBarHidden) { /* Hidden? */
FixMHeight();
MenuBarHidden = FALSE; /* The bar is here */
CopyRgn(OldeGrayRgn, GetGrayRgn()); /* Get the region */
RectRgn(OldeGrayRgn, &OldeMBarRect); /* Convert menu rect to region */
theWindow = (WindowPeek)FrontWindow(); /* Get the front window */
CalcVis((WindowPtr)theWindow); /* Reset the visible region */
CalcVisBehind((WindowPtr)theWindow,OldeGrayRgn); /* Remove the menu bar from windows */
DisposeRgn(OldeGrayRgn); /* Bye bye region */
OldeGrayRgn = 0; /* Zap the handle */
HiliteMenu(0); /* Don't hilite any menu options */
DrawMenuBar(); /* Redraw the menu bar */
}
}
/********************************
Restore the menu bar height so that
the OS can handle menu bar events
********************************/
void FixMHeight(void)
{
if (MenuBarHidden) { /* Hidden? */
LMSetMBarHeight(OldMBarHeight); /* Reset the height */
}
}
/********************************
Zap the menu bar height so that things
like MenuClock won't draw
********************************/
void ZapMHeight(void)
{
if (MenuBarHidden) { /* Hidden? */
LMSetMBarHeight(0); /* Zap the height */
}
}
extern void HideMenuBar(void);
extern void ShowMenuBar(void);
extern void FixMHeight(void);
extern void ZapMHeight(void);
\ No newline at end of file
#include "WolfDef.h"
#include <string.h>
#include <stdlib.h>
extern Word NumberIndex; /* Hack for drawing numbers */
static LongWord BJTime; /* Time to draw BJ? */
static Word WhichBJ; /* Which BJ to show */
static LongWord Indexs[3]; /* Offsets to BJ's true shapes */
static Byte *BJPtr; /* Pointer to BJ's shapes */
static Word ParTime; /* Par time for level */
static LongWord BonusScore; /* Additional points */
#define BONUSX 353
#define BONUSY 103
#define TIMEX 353
#define TIMEWIDTH 36
#define TIMEY 140
#define TIMEY2 180
#define SCOREX 353
#define SCOREY 332
#define RATIOX 353
#define RATIOY 217
#define RATIOY2 253
#define RATIOY3 291
/**********************************
Draw BJ if needed
**********************************/
static Rect BJRect = {48,73,48+142,73+131}; /* Rect for BJ's picture */
static void ShowBJ(void)
{
if ((ReadTick()-BJTime) >= 20) { /* Time to draw a BJ? */
BJTime = ReadTick(); /* Set the new time */
if (WhichBJ!=2) { /* Thumbs up? */
WhichBJ ^= 1; /* Nope, toggle breathing */
}
DrawShape(73,48,&BJPtr[Indexs[WhichBJ]]); /* Draw BJ */
BlastScreen2(&BJRect); /* Update video */
}
}
/**********************************
Have BJ Breath for a while
**********************************/
static void BJBreath(Word Delay)
{
do {
ShowBJ();
if (WaitTicksEvent(1)) {
break;
}
} while (--Delay);
}
/**********************************
Draw the score
**********************************/
static Rect ScoreRect = {SCOREY,SCOREX,SCOREY+22,SCOREX+(12*7)};
static void DrawIScore(void)
{
SetNumber(gamestate.score,SCOREX,SCOREY,7); /* Draw the game score */
BlastScreen2(&ScoreRect);
}
/**********************************
Draw the earned bonus
**********************************/
static Rect BonusRect = {BONUSY,BONUSX,BONUSY+22,BONUSX+(12*7)};
static void DrawIBonus(void)
{
SetNumber(BonusScore,BONUSX,BONUSY,7);
BlastScreen2(&BonusRect);
}
/**********************************
Draw a time value at the given coords
**********************************/
static void DrawTime(Word x,Word y,Word time)
{
Word minutes,seconds;
Rect TimeRect;
TimeRect.left = x;
TimeRect.right = x+((12*4)+TIMEWIDTH);
TimeRect.top = y;
TimeRect.bottom = y+22;
minutes = time/60;
seconds = time%60;
SetNumber(minutes,x,y,2);
x+=TIMEWIDTH;
SetNumber(seconds,x,y,2);
BlastScreen2(&TimeRect);
}
/**********************************
Draws a ratio value at the given coords.
**********************************/
static void DrawRatio(Word x,Word y,Word theRatio)
{
Rect RatioRect;
RatioRect.top = y;
RatioRect.left = x;
RatioRect.bottom = y+22;
RatioRect.right = x+(3*12);
SetNumber(theRatio,x,y,3);
BlastScreen2(&RatioRect);
}
/**********************************
RollScore
Do a Bill-Budgey roll of the old score to the new score,
not bothering with the lower digit, as you never get less
than ten for anything.
**********************************/
static void RollScore(void)
{
Word i;
do {
if (BonusScore>1000) {
i = 1000;
} else {
i = BonusScore;
}
BonusScore-=i;
GivePoints(i);
ShowBJ();
DrawIScore();
DrawIBonus();
PlaySound(SND_MGUN|0x8000);
if (WaitTicksEvent(6)) {
GivePoints(BonusScore); /* Add the final bonus */
BonusScore=0;
DrawIScore();
DrawIBonus();
break;
}
} while (BonusScore);
}
/**********************************
RollRatio
Do a Bill-Budgey roll of the ratio.
**********************************/
static void RollRatio(Word x,Word y,Word ratio)
{
Word i;
Word NoDelay;
i = 0;
NoDelay = 0;
while (i<ratio) {
DrawRatio(x,y,i);
PlaySound(SND_MGUN|0x8000);
ShowBJ();
if (WaitTicksEvent(6)) {
NoDelay = 1;
break;
}
i+=10;
}
DrawRatio(x,y,ratio);
/* make ding sound */
if (ratio==100) {
if (!NoDelay) {
PlaySound(SND_EXTRA);
WaitTicks(30);
}
BonusScore += 10000;
DrawIBonus();
if (!NoDelay) {
BJBreath(60); /* Breath a little */
}
}
}
/**********************************
Let's show 'em how they did!
**********************************/
void LevelCompleted (void)
{
Word k;
LongWord *PackPtr;
Byte *ShapePtr;
LongWord PackLength;
/* setup */
ParTime = MapListPtr->InfoArray[gamestate.mapon].ParTime;
BonusScore = 0; /* Init the bonus */
IntermissionHack = TRUE; /* Hack to keep score from drawing twice */
NumberIndex = 47; /* Hack to draw score using an alternate number set */
NewGameWindow(1); /* Force 512 mode screen */
PackPtr = LoadAResource(rIntermission);
PackLength = PackPtr[0];
ShapePtr = (Byte *) AllocSomeMem(PackLength);
DLZSS(ShapePtr,(Byte *) &PackPtr[1],PackLength);
DrawShape(0,0,ShapePtr);
FreeSomeMem(ShapePtr);
ReleaseAResource(rIntermission);
PackPtr = LoadAResource(rInterPics);
PackLength = PackPtr[0];
BJPtr = (Byte *)AllocSomeMem(PackLength);
DLZSS(BJPtr,(Byte *) &PackPtr[1],PackLength);
ReleaseAResource(rInterPics);
memcpy(Indexs,BJPtr,12); /* Copy the index table */
WhichBJ = 0; /* Init BJ */
BJTime = ReadTick()-50; /* Force a redraw */
BlastScreen(); /* Draw the screen */
ShowBJ(); /* Draw BJ */
StartSong(SongListPtr[1]); /* Play the intermission song */
SetAPalette(rInterPal); /* Set the palette */
DrawIScore(); /* Draw the current score */
FlushKeys(); /* Flush the keyboard buffer */
/* First an initial pause */
BJBreath(60);
/* Display Par Time, Player's Time, and show bonus if any. */
if (gamestate.playtime>=(100*60*60UL)) {
k =(99*60)+59;
} else {
k = gamestate.playtime/60;
}
DrawTime(TIMEX,TIMEY,k); /* How much time has elapsed? */
DrawTime(TIMEX,TIMEY2,ParTime);
if (k < ParTime) {
k = (ParTime-k) * 50; /* 50 points per second */
BonusScore += k; /* Add to the bonus */
DrawIBonus(); /* Draw the bonus */
PlaySound(SND_EXTRA);
BJBreath(60); /* Breath a little */
}
/* Show ratios for "terminations", treasure, and secret stuff. */
/* If 100% on all counts, Perfect Bonus! */
k=0; /* Not perfect (Yet) */
RollRatio(RATIOX,RATIOY,(gamestate.treasurecount*100)/gamestate.treasuretotal);
if (gamestate.treasurecount == gamestate.treasuretotal) {
k++; /* Perfect treasure */
}
RollRatio(RATIOX,RATIOY2,(gamestate.killcount*100)/gamestate.killtotal);
if (gamestate.killcount == gamestate.killtotal) {
k++; /* Perfect kills */
}
RollRatio(RATIOX,RATIOY3,(gamestate.secretcount*100)/gamestate.secrettotal);
if (gamestate.secretcount == gamestate.secrettotal) {
k++; /* Perfect secret */
}
if (BonusScore) { /* Did you get a bonus? */
RollScore();
BJBreath(60);
}
if (k==3) {
WhichBJ = 2; /* Draw thumbs up for BJ */
PlaySound(SND_THUMBSUP);
}
do {
ShowBJ(); /* Animate BJ */
} while (!WaitTicksEvent(1)); /* Wait for a keypress */
FreeSomeMem(BJPtr); /* Release BJ's shapes */
FadeToBlack(); /* Fade away */
IntermissionHack = FALSE; /* Release the hack */
NumberIndex = 36; /* Restore the index */
}
/**********************************
Handle the intermission screen
**********************************/
void Intermission (void)
{
FadeToBlack();
LevelCompleted(); /* Show the data (Init ParTime) */
gamestate.globaltime += gamestate.playtime; /* Add in the playtime */
gamestate.globaltimetotal += ParTime; /* Get the par */
gamestate.globalsecret += gamestate.secretcount; /* Secrets found */
gamestate.globaltreasure += gamestate.treasurecount; /* Treasures found */
gamestate.globalkill += gamestate.killcount; /* Number killed */
gamestate.globalsecrettotal += gamestate.secrettotal; /* Total secrets */
gamestate.globaltreasuretotal += gamestate.treasuretotal; /* Total treasures */
gamestate.globalkilltotal += gamestate.killtotal; /* Total kills */
SetupPlayScreen(); /* Reset the game screen */
}
/**********************************
Okay, let's face it: they won the game.
**********************************/
void VictoryIntermission (void)
{
FadeToBlack();
LevelCompleted();
}
/**********************************
Show player the game characters
**********************************/
#define NUMCAST 12
Word caststate[NUMCAST] = {
ST_GRD_WLK1, ST_OFC_WLK1, ST_SS_WLK1,ST_MUTANT_WLK1,
ST_DOG_WLK1, ST_HANS_WLK1, ST_SCHABBS_WLK1, ST_TRANS_WLK1,
ST_UBER_WLK1, ST_DKNIGHT_WLK1,ST_MHITLER_WLK1, ST_HITLER_WLK1};
#if 0
char *casttext[NUMCAST] = { /* 28 chars max */
"GUARD",
"OFFICER",
"ELITE GUARD",
"MUTANT",
"MUTANT RAT",
"HANS GROSSE",
"DR. SCHABBS",
"TRANS GROSSE",
"UBERMUTANT",
"DEATH KNIGHT",
"MECHAMEISTER",
"STAATMEISTER"
};
#endif
void CharacterCast(void)
{
Word Enemy,count, cycle;
Word up;
state_t *StatePtr;
/* reload level and set things up */
gamestate.mapon = 0; /* First level again */
PrepPlayLoop(); /* Prepare the system */
viewx = actors[0].x; /* Mark the starting x,y */
viewy = actors[0].y;
topspritescale = 32*2;
/* go through the cast */
Enemy = 0;
cycle = 0;
do {
StatePtr = &states[caststate[Enemy]]; /* Init the state pointer */
count = 1; /* Force a fall through on first pass */
up = FALSE;
for (;;) {
if (++cycle>=60*4) { /* Time up? */
cycle = 0; /* Reset the clock */
if (++Enemy>=NUMCAST) { /* Next bad guy */
Enemy = 0; /* Reset the bad guy */
}
break;
}
if (!--count) {
count = StatePtr->tictime;
StatePtr = &states[StatePtr->next];
}
topspritenum = StatePtr->shapenum; /* Set the formost shape # */
RenderView(); /* Show the 3d view */
WaitTicks(1); /* Limit to 15 frames a second */
ReadSystemJoystick(); /* Read the joystick */
if (!joystick1 && !up) {
up = TRUE;
continue;
}
if (!up) {
continue;
}
if (!joystick1) {
continue;
}
if (joystick1 & (JOYPAD_START|JOYPAD_A|JOYPAD_B|JOYPAD_X|JOYPAD_Y)) {
Enemy = NUMCAST;
break;
}
if ( (joystick1 & (JOYPAD_TL|JOYPAD_LFT)) && Enemy >0) {
Enemy--;
break;
}
if ( (joystick1 & (JOYPAD_TR|JOYPAD_RGT)) && Enemy <NUMCAST-1) {
Enemy++;
break;
}
}
} while (Enemy < NUMCAST); /* Still able to show */
StopSong(); /* Stop the music */
FadeToBlack(); /* Fade out */
}
#include "wolfdef.h"
#include <ctype.h>
#include <stdlib.h>
/**********************************
Main game introduction
**********************************/
void Intro(void)
{
LongWord *PackPtr;
LongWord PackLength;
Byte *ShapePtr;
NewGameWindow(1); /* Set to 512 mode */
FadeToBlack(); /* Fade out the video */
PackPtr = LoadAResource(rMacPlayPic);
PackLength = PackPtr[0];
ShapePtr = AllocSomeMem(PackLength);
DLZSS(ShapePtr,(Byte *) &PackPtr[1],PackLength);
DrawShape(0,0,ShapePtr);
FreeSomeMem(ShapePtr);
ReleaseAResource(rMacPlayPic);
BlastScreen();
StartSong(SongListPtr[0]); /* Play the song */
FadeTo(rMacPlayPal); /* Fade in the picture */
WaitTicksEvent(240); /* Wait for event */
FadeTo(rIdLogoPal);
if (toupper(WaitTicksEvent(240))=='B') { /* Wait for event */
FadeToBlack();
ClearTheScreen(BLACK);
BlastScreen();
PackPtr = LoadAResource(rYummyPic);
PackLength = PackPtr[0];
ShapePtr = AllocSomeMem(PackLength);
DLZSS(ShapePtr,(Byte *) &PackPtr[1],PackLength);
DrawShape((SCREENWIDTH-320)/2,(SCREENHEIGHT-200)/2,ShapePtr);
FreeSomeMem(ShapePtr);
ReleaseAResource(rYummyPic);
BlastScreen();
FadeTo(rYummyPal);
WaitTicksEvent(600);
}
}
#include "wolfdef.h"
#include <string.h>
/* static object info*/
/* List of bad guy sprites */
static Word DKnightSprs[] = {
S_DKNIGHT_ATK1,
S_DKNIGHT_ATK2,
S_DKNIGHT_ATK3,
S_DKNIGHT_ATK4,
S_DKNIGHT_WLK1,
S_DKNIGHT_WLK2,
S_DKNIGHT_WLK3,
S_DKNIGHT_WLK4,
S_DKNIGHT_DTH1,
S_DKNIGHT_DTH2,
S_DKNIGHT_DTH3,S_G_KEY,0};
static Word DogSprs[] = {
S_DOG_ATK1,
S_DOG_ATK2,
S_DOG_ATK3,
S_DOG_WLK1,
S_DOG_WLK2,
S_DOG_WLK3,
S_DOG_WLK4,
S_DOG_DTH1,
S_DOG_DTH2,
S_DOG_DTH3,0};
static Word NaziSprs[] = {
S_GUARD_ATK1,
S_GUARD_ATK2,
S_GUARD_ATK3,
S_GUARD_WLK1,
S_GUARD_WLK2,
S_GUARD_WLK3,
S_GUARD_WLK4,
S_GUARD_PAIN,
S_GUARD_DTH1,
S_GUARD_DTH2,
S_GUARD_DTH3,S_AMMO,0};
static Word HansSprs[] = {
S_HANS_ATK1,
S_HANS_ATK2,
S_HANS_ATK3,
S_HANS_WLK1,
S_HANS_WLK2,
S_HANS_WLK3,
S_HANS_WLK4,
S_HANS_DTH1,
S_HANS_DTH2,
S_HANS_DTH3,S_G_KEY,0};
static Word HitlerSprs[] = {
S_HITLER_ATK1,
S_HITLER_ATK2,
S_HITLER_ATK3,
S_HITLER_WLK1,
S_HITLER_WLK2,
S_HITLER_WLK3,
S_HITLER_WLK4,
S_HITLER_DTH1,
S_HITLER_DTH2,
S_HITLER_DTH3,
S_MHITLER_ATK1,
S_MHITLER_ATK2,
S_MHITLER_ATK3,
S_MHITLER_DIE1,
S_MHITLER_DIE2,
S_MHITLER_DIE3,
S_MHITLER_DIE4,
S_MHITLER_WLK1,
S_MHITLER_WLK2,
S_MHITLER_WLK3,
S_MHITLER_WLK4,0};
static Word UberSprs[] = {
S_UBER_ATK1,
S_UBER_ATK2,
S_UBER_ATK3,
S_UBER_ATK4,
S_UBER_WLK1,
S_UBER_WLK2,
S_UBER_WLK3,
S_UBER_WLK4,
S_UBER_DTH1,
S_UBER_DTH2,
S_UBER_DTH3,S_G_KEY,0};
static Word MutantSprs[] = {
S_MUTANT_ATK1,
S_MUTANT_ATK2,
S_MUTANT_ATK3,
S_MUTANT_WLK1,
S_MUTANT_WLK2,
S_MUTANT_WLK3,
S_MUTANT_WLK4,
S_MUTANT_PAIN,
S_MUTANT_DTH1,
S_MUTANT_DTH2,
S_MUTANT_DTH3,S_AMMO,0};
static Word OfficerSprs[] = {
S_OFFICER_ATK1,
S_OFFICER_ATK2,
S_OFFICER_ATK3,
S_OFFICER_WLK1,
S_OFFICER_WLK2,
S_OFFICER_WLK3,
S_OFFICER_WLK4,
S_OFFICER_PAIN,
S_OFFICER_DTH1,
S_OFFICER_DTH2,
S_OFFICER_DTH3,S_AMMO,0};
static Word SchabbsSpr[] = {
S_SCHABBS_ATK1,
S_SCHABBS_ATK2,
S_SCHABBS_WLK1,
S_SCHABBS_WLK2,
S_SCHABBS_WLK3,
S_SCHABBS_WLK4,
S_SCHABBS_DTH1,
S_SCHABBS_DTH2,
S_SCHABBS_DTH3,S_G_KEY,0};
static Word SSSprs[] = {
S_SS_ATK1,
S_SS_ATK2,
S_SS_ATK3,
S_SS_WLK1,
S_SS_WLK2,
S_SS_WLK3,
S_SS_WLK4,
S_SS_PAIN,
S_SS_DTH1,
S_SS_DTH2,
S_SS_DTH3,S_MACHINEGUN,S_AMMO,0};
static Word TransSprs[] = {
S_TRANS_ATK1,
S_TRANS_ATK2,
S_TRANS_ATK3,
S_TRANS_WLK1,
S_TRANS_WLK2,
S_TRANS_WLK3,
S_TRANS_WLK4,
S_TRANS_DTH1,
S_TRANS_DTH2,
S_TRANS_DTH3,S_G_KEY,0};
static Byte EnemyHits[16];
static Word *EnemySprs[] = { /* This list MUST match class_t! */
NaziSprs,
OfficerSprs,
SSSprs,
DogSprs,
MutantSprs,
HansSprs,
SchabbsSpr,
TransSprs,
UberSprs,
DKnightSprs,
HitlerSprs,
HitlerSprs
};
static Byte WallHits[256];
Word staticflags[] = {
0, /*S_WATER_PUDDLE,*/
TI_BLOCKMOVE, /*S_GREEN_BARREL,*/
TI_BLOCKMOVE, /*S_CHAIR_TABLE,*/
TI_BLOCKMOVE, /*S_FLOOR_LAMP,*/
0, /*S_CHANDELIER,*/
TI_GETABLE, /*S_DOG_FOOD,*/
TI_BLOCKMOVE, /*S_COLUMN,*/
TI_BLOCKMOVE, /*S_POTTED_TREE,*/
TI_BLOCKMOVE, /*S_FLAG,*/
TI_BLOCKMOVE, /*S_POTTED_PLANT,*/
TI_BLOCKMOVE, /*S_BLUE_POT,*/
0, /*S_DEBRIS1,*/
0, /*S_LIGHT,*/
0, /*S_BUCKET,*/
TI_BLOCKMOVE, /*S_ARMOUR,*/
TI_BLOCKMOVE, /*S_CAGE,*/
TI_GETABLE, /*S_G_KEY,*/
TI_GETABLE, /*S_S_KEY,*/
TI_GETABLE, /*S_BANDOLIER*/
TI_GETABLE, /*S_AMMOCASE,*/
TI_GETABLE, /*S_FOOD,*/
TI_GETABLE, /*S_HEALTH,*/
TI_GETABLE, /*S_AMMO,*/
TI_GETABLE, /*S_MACHINEGUN,*/
TI_GETABLE, /*S_CHAINGUN,*/
TI_GETABLE, /*S_CROSS,*/
TI_GETABLE, /*S_CHALICE,*/
TI_GETABLE, /*S_CHEST,*/
TI_GETABLE, /*S_CROWN,*/
TI_GETABLE, /*S_ONEUP,*/
TI_BLOCKMOVE, /*S_WOOD_BARREL,*/
TI_BLOCKMOVE, /*S_WATER_WELL,*/
TI_GETABLE, /*S_FLAMETHROWER */
TI_GETABLE, /*S_GASCAN */
TI_GETABLE, /*S_LAUNCHER */
TI_GETABLE /*S_MISSILES */
};
/**********************************
Spawn a static object at x,y
**********************************/
void SpawnStatic(Word x,Word y,Word shape)
{
Word *TilePtr;
static_t *StatPtr;
if (numstatics>=MAXSTATICS) {
return; /* Oh oh!! */
}
TilePtr = &tilemap[y][x]; /* Precalc tile pointer */
StatPtr = &statics[numstatics];
StatPtr->x = (x<<FRACBITS)+0x80; /* Set the pixel X */
StatPtr->y = (y<<FRACBITS)+0x80; /* Set the pixel Y */
StatPtr->areanumber = TilePtr[0] & TI_NUMMASK; /* Mask off the area number */
TilePtr[0] |= staticflags[shape];
shape += S_WATER_PUDDLE; /* Init the shape number */
WallHits[shape] = 1; /* Load in this shape */
StatPtr->pic = shape; /* Set the object's shape */
switch (shape) {
case S_CROSS:
case S_CHALICE:
case S_CHEST:
case S_CROWN:
case S_ONEUP:
++gamestate.treasuretotal; /* Mark this as treasure */
}
++numstatics; /* I have one more item */
}
/**********************************
Spawn the player at x,y
**********************************/
void SpawnPlayer(Word x,Word y,Word dir)
{
gamestate.viewangle = (1-dir)*ANGLES/4; /* Get the basic viewing angle */
actors[0].x = (x<<FRACBITS)+0x80; /* Save the X coord */
actors[0].y = (y<<FRACBITS)+0x80; /* Save the Y coord */
actors[0].class = CL_PLAYER; /* This is the player */
actors[0].areanumber = tilemap[y][x]&TI_NUMMASK; /* Which area? */
ConnectCount = 0; /* Zap the interconnects */
ConnectAreas(); /* Init the area table */
}
/**********************************
Spawn an actor at a specific x,y
**********************************/
void SpawnStand(Word x,Word y,class_t which)
{
stateindex_t state;
classinfo_t *info;
actor_t *ActorPtr;
Word *TilePtr;
Word tile;
if (numactors==MAXACTORS) { /* Too many actors already? */
return; /* Exit */
}
EnemyHits[which] = 1;
info = &classinfo[which]; /* Get the pointer to the basic info */
state = info->standstate; /* Get the state logic value */
ActorPtr = &actors[numactors]; /* Get the pointer to the new actor entry */
TilePtr = &tilemap[y][x]; /* Pointer to the current tile */
tile = TilePtr[0]; /* What's in the tile? */
ActorPtr->x = (x<<FRACBITS)+0x80; /* Init the x and y */
ActorPtr->y = (y<<FRACBITS)+0x80;
ActorPtr->pic = states[state].shapenum; /* What picture to display? */
ActorPtr->ticcount = states[state].tictime; /* Initial tick count */
ActorPtr->state = state;
ActorPtr->flags = FL_SHOOTABLE | FL_NOTMOVING; /* You can shoot it */
ActorPtr->distance = 0; /* No distance to travel */
ActorPtr->dir = nodir; /* No direction of travel */
ActorPtr->areanumber = tile&TI_NUMMASK; /* Area in */
ActorPtr->reacttime = 0; /* Reaction time */
TilePtr[0] = tile | TI_ACTOR; /* Mark as a bad guy */
MapPtr->tilemap[y][x] = numactors; /* Save the actor # */
ActorPtr->goalx = x; /* Don't travel anywhere */
ActorPtr->goaly = y;
ActorPtr->class = which; /* Actor type */
ActorPtr->speed = info->speed; /* Basic speed */
ActorPtr->hitpoints = info->hitpoints; /* Starting hit points */
++numactors; /* I now add one more actor to the list */
++gamestate.killtotal; /* Another critter must die! */
}
/**********************************
Spawn an actor at a specific x,y and ALSO set the ambush flag
**********************************/
void SpawnAmbush(Word x,Word y,class_t which)
{
actor_t *ActorPtr;
ActorPtr = &actors[numactors]; /* Get the pointer to the new actor entry */
SpawnStand(x,y,which); /* Fill in all the entries */
ActorPtr->flags |= FL_AMBUSH; /* Set the ambush flag */
}
/**********************************
Spawn a door at the specified x,y
**********************************/
void SpawnDoor(Word x,Word y,Word type)
{
door_t *door;
Word *TilePtr;
if (numdoors==MAXDOORS) {
return;
}
TilePtr = &tilemap[y-1][x]; /* Pointer to the tile (-1 y) for door->area index */
door = &doors[numdoors]; /* Pointer to the door record */
door->position = 0; /* doors start out fully closed*/
door->tilex = x;
door->tiley = y;
door->info = type-90; /* Set the door type */
door->action = DR_CLOSED; /* Mark as closed */
TilePtr[MAPSIZE] = (TI_DOOR|TI_BLOCKMOVE|TI_BLOCKSIGHT)| numdoors;
if (type & 1) { /* horizontal*/
door->area1 = TilePtr[MAPSIZE*2] & TI_NUMMASK; /* One cell below */
door->area2 = TilePtr[0] & TI_NUMMASK; /* One cell above */
} else {
door->area1 = TilePtr[MAPSIZE-1] & TI_NUMMASK; /* One cell left */
door->area2 = TilePtr[MAPSIZE+1] & TI_NUMMASK; /* One cell right */
}
++numdoors;
}
/**********************************
Spawn a pushwall track at the specified x,y
**********************************/
void AddPWallTrack(Word x,Word y,Word tile)
{
Byte *TextPtr;
if (x>=MAPSIZE || y>=MAPSIZE) {
return; /* pushwall is off the edge of a map*/
}
TextPtr = &textures[MAPSIZE+x][y];
if (TextPtr[0] != 0xff) { /* Already marked? */
return; /* solid wall*/
}
TextPtr[0] = tile + 1; /* Save the tile # */
textures[y][x] = tile; /* Mark the texture index */
}
/**********************************
Spawn a pushwall at the specified x,y
**********************************/
void SpawnPushwall(Word x,Word y,Word tile)
{
++gamestate.secrettotal; /* Secret area! */
tilemap[y][x] |= (TI_BLOCKMOVE | TI_BLOCKSIGHT | TI_PUSHWALL);
/* directly set texture values for rendering*/
tile = (tile-1)<<1;
AddPWallTrack(x, y, tile);
AddPWallTrack(x-1, y, tile);
AddPWallTrack(x-2, y, tile);
AddPWallTrack(x+1, y, tile);
AddPWallTrack(x+2, y, tile);
AddPWallTrack(x, y-1, tile);
AddPWallTrack(x, y-2, tile);
AddPWallTrack(x, y+1, tile);
AddPWallTrack(x, y+2, tile);
}
/**********************************
Spawn an elevator at the specified x,y
**********************************/
void SpawnElevator(Word x,Word y)
{
elevatorx = x; /* for easy mode cheating*/
elevatory = y;
tilemap[y][x] |= TI_BLOCKMOVE | TI_SWITCH;
}
/**********************************
Spawn the outside at the specified x,y
**********************************/
void SpawnOut(Word x,Word y)
{
/*tilemap[y][x] |= TI_BLOCKMOVE | TI_SWITCH;*/
}
/**********************************
Spawn a secret item at the specified x,y
**********************************/
void SpawnSecret(Word x,Word y)
{
tilemap[y][x] |= TI_BLOCKMOVE | TI_SECRET;
}
/**********************************
Spawn all actors and mark down special places
A spawn record is (x,y,type)
**********************************/
void SpawnThings(void)
{
Word x,y; /* Temp x,y */
Word type; /* Item to spawn */
Byte *spawn_p;
Word Count; /* Number of items to create */
Word *EnemyPtr;
memset(EnemyHits,0,sizeof(EnemyHits));
spawn_p = (Byte *)MapPtr+MapPtr->spawnlistofs; /* Point to the spawn table */
Count = MapPtr->numspawn; /* How many items to spawn? */
if (!Count) {
return;
}
do {
x = spawn_p[0]; /* Get the X */
y = spawn_p[1]; /* Get the y */
type = spawn_p[2]; /* Get the type */
spawn_p+=3; /* Index past the record */
if (type<19) {
continue;
} else if (type<23) { /* 19-22 */
SpawnPlayer(x,y,type-19);
} else if (type<59) { /* 23-58 */
SpawnStatic(x,y,type-23);
} else if (type<90) { /* 59-89 */
continue;
} else if (type<98) { /* 90-97 */
SpawnDoor(x,y,type);
} else if (type == 98) { /* 98 */
SpawnPushwall(x,y,spawn_p[0]);
++spawn_p;
} else if (type == 99) { /* 99 */
SpawnOut(x,y);
} else if (type == 100) { /* 100 */
SpawnElevator(x,y);
} else if (type == 101) { /* 101 */
SpawnSecret(x,y);
} else if (type<108) { /* 102-107 */
continue;
} else if (type<123) { /* 108-122 */
SpawnStand(x,y,(class_t) (type-108));
} else if (type<126) { /* 123-125 */
continue;
} else if (type<140) { /* 126-139 */
SpawnAmbush(x,y,(class_t) (type-126));
}
} while (--Count);
Count = 0;
do {
if (EnemyHits[Count]) {
x = 0;
EnemyPtr = EnemySprs[Count];
do {
WallHits[EnemyPtr[x]] = 1;
++x;
} while (EnemyPtr[x]);
}
} while (++Count<16);
}
/**********************************
Release the map data
**********************************/
void ReleaseMap(void)
{
Word i;
if (OldMapNum) {
KillAResource(OldMapNum); /* Make SURE it's purged! */
OldMapNum = 0; /* Nothing loaded */
MapPtr = 0; /* No data available */
}
i = 0;
do {
if (ArtData[i]) {
FreeSomeMem(ArtData[i]); /* Release the wall art */
ArtData[i] = 0;
}
} while (++i<64); /* All walls done? */
i = 1;
do {
if (SpriteArray[i]) { /* Is this sprite loaded? */
FreeSomeMem(SpriteArray[i]); /* Release the memory */
SpriteArray[i] = 0;
}
} while (++i<S_LASTONE); /* All done? */
}
/**********************************
Load and initialize everything for current game level
Spawnlist 0-(numusable-1) are the usable (door/pushwall) spawn objects
Polysegs 0-(numpushwalls-1) are four sided pushwall segs
**********************************/
Boolean SetupGameLevel(void)
{
Byte *src;
Word *dest;
Word tile;
Word Count;
/* clear counts*/
gamestate.secrettotal=0; /* No secret items found */
gamestate.killtotal=0; /* Noone killed */
gamestate.treasuretotal=0; /* No treasure found */
gamestate.secretcount=0; /* No secret areas found */
gamestate.killcount=0; /* Noone to kill on this level */
gamestate.treasurecount = 0; /* No treasures laid */
/* Load a level */
ReleaseMap(); /* Free up any previous map */
OldMapNum = (MapListPtr->MapRezNum)+gamestate.mapon; /* Which map to load */
MapPtr = LoadAResource(OldMapNum); /* Load in the map */
if (!MapPtr) {
return FALSE; /* Uh.. yeah... */
}
DrawPsyched(1); /* First stage done */
#ifdef __BIGENDIAN__
MapPtr->numspawn = SwapUShort(MapPtr->numspawn); /* Fix for 68000 machines */
MapPtr->spawnlistofs = SwapUShort(MapPtr->spawnlistofs);
MapPtr->numnodes = SwapUShort(MapPtr->numnodes);
MapPtr->nodelistofs = SwapUShort(MapPtr->nodelistofs);
#endif
numstatics = 0; /* Clear out the static array */
numdoors = 0; /* Clear out the door array */
numactors = 1; /* player has spot 0*/
nummissiles = 0; /* Clear out the missile array */
/* expand the byte width map to word width*/
memset(WallHits,0,sizeof(WallHits));
src = &MapPtr->tilemap[0][0];
dest = &tilemap[0][0];
Count = 0;
do {
tile = src[Count]; /* Get the byte tile */
if (tile & TI_BLOCKMOVE) {
tile |= TI_BLOCKSIGHT; /* Mark as blocking my sight */
WallHits[(tile-1)&0x1F]=1;
}
dest[Count] = tile; /* Save the new tile */
} while (++Count<MAPSIZE*MAPSIZE);
/* let the rendering engine know about the new map*/
NewMap(); /* Set the variables */
DrawPsyched(2); /* Second stage */
if (!LoadWallArt()) { /* Get the wall shapes */
return FALSE;
}
/* map.tilemap is now used to hold actor numbers if the TI_ACTOR bit is set in
the word tilemap*/
memset(WallHits,0,sizeof(WallHits)); /* Init the wall table */
Count = 1;
do {
WallHits[Count] = 1; /* Force the permanent sprites to load */
} while (++Count<S_VICTORY+1);
SpawnThings(); /* Create all the characters in the game level */
return LoadSpriteArt(); /* Load in the sprite art */
}
/************************************
Load in a single wall shape
************************************/
static Boolean LoadWallShape(Word Index,Byte *DarkPtr)
{
Byte *WallPtr;
Byte *Buffer;
Word WallVal;
Word j;
Buffer = AllocSomeMem(0x4000); /* Get memory for wall */
if (!Buffer) {
return FALSE;
}
WallVal = WallListPtr[Index+1]; /* Which resource is it? */
WallPtr = LoadAResource(WallVal&0x3fff); /* Load the shape */
if (!WallPtr) {
FreeSomeMem(Buffer);
return FALSE;
}
DLZSS(Buffer,WallPtr,0x4000); /* Decompress it */
if (WallVal & 0x8000) { /* Do I need to darken it? */
j = 0;
do {
Buffer[j] = DarkPtr[Buffer[j]]; /* Use a lookup table to darken it */
} while (++j<0x4000);
}
ArtData[Index] = Buffer; /* Save the pointer */
ReleaseAResource(WallVal&0x3fff); /* Purge the data */
return TRUE;
}
/************************************
Load in all the wall art
************************************/
Word LoadWallArt(void)
{
Word i;
Word j;
Word RetVal;
Byte *DarkPtr;
RetVal = FALSE;
DarkPtr = LoadAResource(MyDarkData); /* Get my darken table */
i = 0;
do {
if (WallHits[i]) {
j = i*2;
if (!LoadWallShape(j,DarkPtr) ||
!LoadWallShape(j+1,DarkPtr) ) {
goto Abort;
}
DrawPsyched(j+2);
}
} while (++i<29);
i = 59;
do {
if (!LoadWallShape(i,DarkPtr)) {
goto Abort;
}
DrawPsyched(i+2);
} while (++i<64);
RetVal = TRUE;
Abort:
ReleaseAResource(MyDarkData);
return RetVal; /* No errors */
}
/***************************
Load in all the sprites
***************************/
Word LoadSpriteArt(void)
{
Word i;
Word Length;
Byte *MyPtr;
Byte *MyNewPtr;
i=1;
do {
if (WallHits[i]) {
MyPtr = LoadAResource(i+(428-1)); /* Get the packed file */
if (!MyPtr) {
return FALSE;
}
Length = MyPtr[0]; /* Get the length unpacked */
Length |= MyPtr[1]<<8;
MyNewPtr = (Byte *)AllocSomeMem(Length); /* Get memory for the sprite */
if (!MyNewPtr) {
ReleaseAResource(i+(428-1));
return FALSE;
}
DLZSS(MyNewPtr,&MyPtr[2],Length); /* Unpack it */
SpriteArray[i] = MyNewPtr; /* Save the pointer */
ReleaseAResource(i+(428-1)); /* Release the resource */
DrawPsyched(i+66);
}
} while (++i<S_LASTONE);
DrawPsyched(66+S_LASTONE);
return TRUE;
}
/*********************
Main Macintosh code
*********************/
#include "Wolfdef.h" /* All the game equates */
#include <string.h>
#include <ctype.h>
#include <setjmp.h>
#include <palettes.h>
#include <qdoffscreen.h>
#include <Gestalt.h>
#include "SoundMusicSystem.h"
#include "PickAMonitor.h"
#include "Hidemenubar.h"
#include "Prefs.h"
#include <AppleEvents.h>
static Word DoMyAlert(Word AlertNum);
static void CenterSFWindow(Point *MyPoint,Word x,Word y);
static void CenterAWindow(WindowPtr MyWindow);
static void FixPauseMenu(void);
Boolean LoadGame(void);
pascal Boolean StandardModalFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *itemHit);
Word ChooseGameDiff(void);
Word DoEvent(EventRecord *event);
void DoUpdate(WindowPtr window);
void DrawWindow(WindowPtr window);
void AdjustMenus(void);
void DoMenuCommand(LongWord menuResult);
Boolean DoCloseWindow(WindowPtr window);
void InitTools(void);
void SaveGame(void);
void LoadPrefs(void);
void SavePrefs(void);
Boolean ChooseLoadGame(void);
Boolean ChooseSaveGame(void);
OSErr MyEventHandler(AppleEvent *MyAppleEvent,AppleEvent *AppleReply,long MyRefCon);
Boolean MouseHit; /* True if a mouse was pressed */
static MenuHandle PauseMenu;
static Boolean WaitNextOK; /* True if WaitNextEvent is present */
static Boolean LowOnMem; /* True if sound is disabled for low memory */
static Boolean OpenPending; /* True if a load game apple event occured */
static Byte *SaveFileName; /* Pointer to the save file name */
static short SaveFileVol; /* Directory referance for save file name */
static long SaveFileParID; /* Parent directory id of save-game file */
static Boolean ValidRects; /* Are there blank rects in the window? */
static RgnHandle BlackRgn; /* Blank region for window blanking */
static Rect QDGameRect; /* Rect of the game playing area */
static Rect GameRect = {0,0,200,320}; /* Size of the playfield */
static Rect BlackRect = {0,0,480,640}; /* Rect for the Black Window (Set to main window size) */
static Rect BlackRect2 = {0,0,480,640}; /* True rect for the Black window (Global) */
static Word OldPixDepth; /* Previous pixel depth of screen */
Word MacWidth; /* Width of play screen (Same as GameRect.right) */
Word MacHeight; /* Height of play screen (Same as GameRect.bottom) */
Word MacViewHeight; /* Height of 3d screen (Bottom of 3D view */
static Word MonitorWidth=640; /* Width of the monitor in pixels */
static Word MonitorHeight=480; /* Height of the monitor in pixels */
Word QuitFlag; /* I quit if true */
Word TrueVideoWidth; /* Width of video monitor in bytes */
Byte *TrueVideoPointer; /* Pointer to the video monitor memory */
Byte *GameVideoPointer; /* Pointer to start of 3D view on monitor memory (Used by BlastScreen) */
Boolean DoQuickDraw = TRUE; /* Use quickdraw for updates? */
static Boolean DimQD; /* Force QuickDraw forever! */
Word IgnoreMessage; /* Variable set by prefs to ignore messages */
static CursHandle WatchHandle; /* Handle to a watch cursor */
#define RectX ((MonitorWidth-MacWidth)/2)
#define RectY ((MonitorHeight-MacHeight)/2)
Word VidXs[] = {320,512,640,640}; /* Screen sizes to play with */
Word VidYs[] = {200,384,400,480};
Word VidVs[] = {160,320,320,400};
Word VidPics[] = {rFaceShapes,rFace512,rFace640,rFace640}; /* Resource #'s for art */
static Word MouseBaseX;
static Word MouseBaseY;
static Boolean InPause; /* Pause active? */
extern jmp_buf ResetJmp;
extern Boolean JumpOK;
extern CWindowPtr GameWindow; /* Pointer to main game window */
extern CGrafPtr GameGWorld; /* Grafport to offscreen buffer */
GDHandle gMainGDH; /* Main graphics handle */
CTabHandle MainColorHandle; /* Main color table handle */
static void WaitCursor(void);
static void ResetPalette(void);
static void DoBackground(EventRecord *event);
static void InitAEStuff(void);
static void FixTheCursor(void);
/***************************
Dialog filter for 68020/30 version speed warning
***************************/
#ifndef __powerc
static pascal Boolean InitFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
{
char theChar;
Handle theHandle;
short theType;
Rect theRect;
switch (theEvent->what) {
case keyDown:
theChar = theEvent->message & charCodeMask;
switch (theChar) {
case 0x0D: /* Return */
case 0x03: /* Enter */
*itemHit = 1;
return (TRUE);
}
case updateEvt:
GetDialogItem(theDialog,1, &theType, &theHandle, &theRect);
InsetRect(&theRect, -4, -4);
PenSize(3,3);
FrameRoundRect(&theRect, 16, 16);
}
return (FALSE); /* Tells dialog manager to handle the event */
}
#endif
/***************************
Init the Macintosh and all the
system tools
***************************/
void InitTools(void)
{
Handle menuBar; /* Handle to menu bar record */
Word i; /* Temp */
long Feature; /* Gestalt return value */
short int *SoundListPtr; /* Pointer to sound list for Halestorm driver */
MaxApplZone(); /* Expand the heap so code segments load at the top */
InitGraf((Ptr) &qd.thePort); /* Init the graphics system */
InitFonts(); /* Init the font manager */
InitWindows(); /* Init the window manager */
InitMenus(); /* Init the menu manager */
TEInit(); /* Init text edit */
InitDialogs(nil); /* Init the dialog manager */
i = 16; /* Make 64*16 handle records */
do {
MoreMasters(); /* Create a BUNCH of new handles */
} while (--i);
#ifdef __powerc
WaitNextOK = TRUE;
#else
if (NGetTrapAddress(0xA860,1) != (void *)0xa89F) {
WaitNextOK = TRUE;
}
#endif
InitAEStuff(); /* Apple events shit */
InitCursor(); /* Reset the cursor */
WatchHandle = GetCursor(watchCursor); /* Get the watch cursor */
HLock((Handle)WatchHandle); /* Lock it down */
WaitCursor(); /* Set the watch cursor */
LoadPrefs(); /* Load the prefs file */
/* Now that the mac is started up, let's make sure I can run on this particular mac */
#ifndef __powerc /* Power macs REQUIRE 7.1 to run so don't even check on power macs */
if (Gestalt(gestaltVersion,&Feature)) { /* Is gestalt working? */
goto Not607; /* Oh oh... */
}
/* Check for System 6.0.7 or later */
if (Gestalt(gestaltSystemVersion, &Feature) ||
(short)Feature < 0x0607) { /* Is it 6.0.7 or later? */
goto Not607;
}
#endif
/* Check for Color QuickDraw. If there's no color, quit. Below, we check for
32-bit color QuickDraw. */
if (Gestalt(gestaltQuickdrawVersion, &Feature)) {
Not607:
DoMyAlert(Not607Win); /* Alert the user */
GoodBye(); /* Exit now */
}
/* Check for 32-bit Color QuickDraw */
if( (Feature & 0x0000ffff) < 0x0200) { /* Not 32 bit? */
DoMyAlert(Not32QDWin); /* I need 32 bit quickdraw! */
GoodBye(); /* Exit */
}
/* Check the Mac's processor. If it's a 68030 or earlier, warn the user it
might be slow, and note the best ways to speed it up. */
#ifndef __powerc /* Power macs don't need this message */
Gestalt(gestaltProcessorType,&Feature);
i = 0;
switch(Feature) {
case gestalt68000:
++i;
ParamText("\p68000","\p","\p","\p");
break;
case gestalt68020:
++i;
ParamText("\p68020","\p","\p","\p");
break;
case gestalt68030:
++i;
ParamText("\p68030","\p","\p","\p");
break;
}
if (i && !IgnoreMessage) {
short theValue,itemHit,iType;
Handle iHndl;
Rect iRect;
DialogPtr MyDialog;
ModalFilterUPP theDialogFilter;
theDialogFilter = NewModalFilterProc(InitFilter); /* Create a code pointer */
MyDialog = GetNewDialog(SlowWarnWin,0L,(WindowPtr)-1); /* Load my dialog from disk */
CenterAWindow(MyDialog);
ShowWindow(MyDialog); /* Display with OK button framed */
SetPort((WindowPtr) MyDialog);
InitCursor(); /* Init the cursor */
do {
ModalDialog(theDialogFilter,&itemHit); /* Handle the dialog */
if (itemHit==2) { /* The checkbox */
GetDialogItem(MyDialog,2, &iType, &iHndl, &iRect);
theValue = GetControlValue((ControlHandle)iHndl);
SetControlValue( (ControlHandle) iHndl, !theValue );
}
} while (itemHit!=1);
GetDialogItem(MyDialog,2, &iType, &iHndl, &iRect); /* Get the check box state */
IgnoreMessage = GetControlValue((ControlHandle)iHndl);
if (IgnoreMessage) { /* If I should ignore... */
SavePrefs(); /* Save the prefs file */
}
DisposeDialog(MyDialog); /* Release the dialog memory */
}
#endif
/* Let's set up the environment... */
InitSoundMusicSystem(8,8,5,jxLowQuality);
PurgeSongs(TRUE); /* Allow songs to stay in memory */
SoundListPtr = (short int *) LoadAResource(MySoundList); /* Get the list of sounds */
RegisterSounds(SoundListPtr,FALSE);
ReleaseAResource(MySoundList); /* Release the sound list */
GetTableMemory(); /* Get memory for far tables math tables */
MapListPtr = (maplist_t *) LoadAResource(rMapList); /* Get the map list */
SongListPtr = (unsigned short *) LoadAResource(rSongList);
WallListPtr = (unsigned short *) LoadAResource(MyWallList);
/* Alert the user that you MUST pay! */
if (MapListPtr->MaxMap==3) { /* Shareware version? */
DoMyAlert(ShareWareWin); /* Show the shareware message */
}
if (FreeMem() < 3000000L) { /* Are you low on memory? */
DoMyAlert(LowMemWin);
SystemState = 0; /* Turn off music and sound (Just in case) */
LowOnMem = TRUE;
}
ShowCursor(); /* Make sure the cursor is ok */
WaitCursor(); /* Restore the watch cursor */
/* Try to set up 8-bit color mode */
gMainGDH = PickAMonitor(8,TRUE,512,384); /* Pick a monitor to play on */
if (!gMainGDH) { /* No macs that can display or canceled */
GoodBye(); /* Exit */
}
OldPixDepth = (**(**gMainGDH).gdPMap).pixelSize; /* Get the previous mode */
if (OldPixDepth != 8) { /* Was it 8 bit already? */
if (SetDepth(gMainGDH,8, 1 << gdDevType,1)) { /* Set to 8 bit */
BailOut(); /* Oh oh... */
}
}
MainColorHandle = (*(*gMainGDH)->gdPMap)->pmTable; /* Get my main device's color handle */
BlackRect2 = (**gMainGDH).gdRect; /* Init the black rect */
LockPixels((**gMainGDH).gdPMap); /* Lock down the memory FOREVER! */
TrueVideoPointer = (Byte *) GetPixBaseAddr((**gMainGDH).gdPMap); /* Get pointer to screen mem */
TrueVideoWidth = (Word) ((**(**gMainGDH).gdPMap).rowBytes & 0x3FFF); /* Get width of screen mem */
if (!TrueVideoPointer || !TrueVideoWidth) {
DimQD = TRUE; /* Don't allow offscreen drawing */
DoQuickDraw = TRUE; /* Force QD */
}
MonitorHeight = BlackRect2.bottom - BlackRect2.top; /* Get the size of the video screen */
MonitorWidth = BlackRect2.right - BlackRect2.left;
MouseBaseX = BlackRect2.left+256;
MouseBaseY = BlackRect2.top+192;
menuBar = GetNewMBar(MyMenuBar); /* read menus into menu bar */
if (!menuBar) {
BailOut(); /* Menu bar error */
}
SetMenuBar(menuBar); /* install menus */
DisposeHandle(menuBar); /* Release the menu bar */
AppendResMenu(GetMenuHandle(mApple),'DRVR'); /* add DA names to Apple menu */
DrawMenuBar(); /* Show the menu bar */
HideMenuBar(); /* Hide the menu bar */
GameWindow = (CWindowPtr)NewCWindow(nil,&BlackRect2, "\p",TRUE, plainDBox, (WindowPtr) -1L, FALSE, 0);
if (!GameWindow) { /* No background window? */
BailOut();
}
BlackRgn = NewRgn(); /* Make a region for the black area */
SetPort((WindowPtr)GameWindow); /* Use this grafport */
ActivatePalette((WindowPtr)GameWindow);
BlackRect.top = 0; /* Init the main rect */
BlackRect.left = 0;
BlackRect.bottom = MonitorHeight;
BlackRect.right = MonitorWidth;
FillRect(&BlackRect,&qd.black); /* Erase the screen to black */
NewGameWindow(1); /* Create a game window at 512x384 */
ClearTheScreen(BLACK); /* Force the offscreen memory blank */
BlastScreen();
FixTheCursor(); /* Fix the cursor */
}
/************************************
Set the hardware palette to match my window palette for high speed
copybits operation
************************************/
extern Byte CurrentPal[768]; /* Last palette the game was set to */
static void ResetPalette(void)
{
SetPort((WindowPtr) GameWindow); /* Reset the game window */
if ((**(**gMainGDH).gdPMap).pixelSize != 8) { /* Get the previous mode */
SetDepth(gMainGDH,8, 1 << gdDevType,1); /* Set to 8 bit color */
}
SetAPalettePtr(CurrentPal); /* Restore the palette */
}
/************************************
Process the suspend/resume events
************************************/
static void DoBackground(EventRecord *event)
{
EventRecord PauseEvent;
if ((event->message & 0xff000000) ==0x01000000) { /* Suspend/Resume events */
if (!(event->message & resumeFlag)) { /* Suspend event? */
if (!InPause) {
PauseSoundMusicSystem(); /* Stop the music */
ShowMenuBar(); /* Display the menu bar */
}
InitCursor(); /* Restore the arrow cursor */
/* Call a new event loop while in background to let us know when we've returned. */
do {
WaitNextEvent2(everyEvent, &PauseEvent, 0xFF, nil);
if (PauseEvent.what==updateEvt) { /* Time for update? */
DoUpdate((WindowPtr) PauseEvent.message); /* Redraw the window */
}
} while (PauseEvent.what!=mouseDown && PauseEvent.what!=activateEvt && PauseEvent.what!=app4Evt);
/* Turn the main game window back on and update its contents. */
ResetPalette(); /* Reset the game palette */
FixTheCursor(); /* Make it disappear for game if needed */
if (!InPause) {
HideMenuBar(); /* Make the menu bar disappear */
ResumeSoundMusicSystem(); /* Restart the music */
}
}
}
}
/************************************
Call Wait next event if present
************************************/
Boolean WaitNextEvent2(short EventMask,EventRecord *theEvent,long sleep,RgnHandle mouseRgn)
{
if (WaitNextOK) {
return WaitNextEvent(EventMask,theEvent,sleep,mouseRgn);
}
SystemTask();
return GetNextEvent(EventMask,theEvent);
}
/************************************
Execute the apple event
************************************/
static void HandleHighLevelEvent(EventRecord *event)
{
AEProcessAppleEvent(event);
if (QuitFlag) {
GoodBye();
}
}
/************************************
Do the right thing for an event. Determine what kind of
event it is, and call the appropriate routines.
This is like TaskMaster for the IIgs
************************************/
Word DoEvent(EventRecord *event)
{
Word part;
WindowPtr window;
Word key;
Point aPoint;
switch (event->what) { /* Process the event */
case kHighLevelEvent: /* Apple events? */
HandleHighLevelEvent(event); /* Pass it on... */
break;
case mouseDown: /* Pressed the mouse? */
FixMHeight(); /* Allow menu bar clicks */
part = FindWindow(event->where, &window); /* Choose the hit */
ZapMHeight(); /* Don't click anymore */
switch (part) {
case inMenuBar: /* process a mouse menu command (if any) */
AdjustMenus(); /* Enable/disable menu items */
ShowMenuBar(); /* Display the menu bar */
DoMenuCommand(MenuSelect(event->where)); /* Handle the command */
if (!InPause) {
HideMenuBar(); /* Hide the menu bar */
}
break;
case inSysWindow: /* let the system handle the mouseDown */
SystemClick(event, window); /* Pass on the event */
break;
case inContent:
if (window != FrontWindow() ) {
SelectWindow(window); /* Make it the front window */
}
if (window == (WindowPtr)GameWindow) {
MouseHit = TRUE;
}
break;
case inDrag: /* pass screenBits.bounds to get all gDevices */
DragWindow(window, event->where, &qd.screenBits.bounds);
break;
case inGoAway:
if (TrackGoAway(window,event->where)) { /* Handle the close box */
DoCloseWindow(window); /* Close my window */
}
break;
case inZoomIn:
case inZoomOut:
if (TrackBox(window, event->where, part)) { /* Track the zoom box */
SetPort(window); /* the window must be the current port... */
EraseRect(&window->portRect); /* because of a bug in ZoomWindow */
ZoomWindow(window,part,TRUE); /* note that we invalidate and erase... */
InvalRect(&window->portRect); /* to make things look better on-screen */
}
break;
}
break;
case keyDown:
case autoKey: /* check for menukey equivalents */
key = event->message & charCodeMask;
if (event->modifiers & cmdKey) { /* Command key down */
if (event->what == keyDown) {
AdjustMenus(); /* enable/disable/check menu items properly */
DoMenuCommand(MenuKey(key)); /* Process the key */
}
return 0; /* Ignore the event */
}
return key; /* Return the key pressed */
case updateEvt:
DoUpdate((WindowPtr) event->message); /* Force redraw of my window */
break;
case diskEvt:
if ((event->message>>16) != noErr ) { /* Was there an error? */
SetPt(&aPoint, kDILeft, kDITop);
DIBadMount(aPoint, event->message); /* Format the disk? */
}
break;
case activateEvt:
if (event->modifiers & 1) {
FixTheCursor(); /* Reset the cursor to the hidden state */
SetPort((WindowPtr)GameWindow);
ResetPalette(); /* Set my system palette */
}
break;
case osEvt:
DoBackground(event); /* Process suspend / resume */
break;
}
if (OpenPending && JumpOK) {
OpenPending=FALSE; /* Ack the event */
if (LoadGame()) { /* Load the game into memory */
longjmp(ResetJmp,EX_LOADGAME); /* Restart a loaded game */
}
}
if (!InPause) {
HideMenuBar(); /* Make SURE the menu bar is gone! */
}
return 0; /* No event processed */
}
/**********************************
Call this when I receive an update event
**********************************/
void DoUpdate(WindowPtr window)
{
if (((WindowPeek) window)->windowKind >=0) { /* Is this my window? */
BeginUpdate(window); /* this sets up the visRgn */
DrawWindow(window); /* Draw the game window */
EndUpdate(window); /* Fix the visRgn */
}
}
/************************
Update the contents of the window
************************/
void DrawWindow(WindowPtr window)
{
Word OldQuick; /* Previous state of the quickdraw flag */
if (window == (WindowPtr) GameWindow) { /* Is it my window? */
SetPort((WindowPtr)GameWindow);
OldQuick = DoQuickDraw; /* Save the quickdraw flag */
DoQuickDraw = TRUE; /* Force quickdraw */
BlastScreen(); /* Update the screen */
DoQuickDraw = OldQuick; /* Restore quickdraw flag */
if (ValidRects) { /* Black region valid? */
FillRgn(BlackRgn,&qd.black); /* Fill the black region */
}
}
}
/****************************
Set an item's mark with a check mark
****************************/
static void SetAMark(MenuHandle MyHand,Word Which,Word Var)
{
Var = (Var) ? 0x12 : 0;
SetItemMark(MyHand,Which,Var);
}
/****************************
Enable and disable menu items
****************************/
void AdjustMenus(void)
{
WindowPtr window;
MenuHandle FileMenu,EditMenu,OptionMenu;
window = FrontWindow(); /* Which window is in front */
FileMenu = GetMenuHandle(mFile); /* Get the file menu handle */
EditMenu = GetMenuHandle(mEdit); /* Get the edit menu handle */
OptionMenu = GetMenuHandle(mOptions);
if (window!=(WindowPtr)GameWindow) { /* Enable if there is a window */
EnableItem(FileMenu,iClose);
EnableItem(EditMenu,0);
} else {
DisableItem(FileMenu,iClose);
DisableItem(EditMenu,0);
}
if (playstate == EX_STILLPLAYING) { /* Game is in progress */
EnableItem(FileMenu,iSaveAs); /* Save the game */
EnableItem(FileMenu,iSave); /* Quicksave the game */
} else {
DisableItem(FileMenu,iSaveAs); /* Can't save game when isn't in the mode */
DisableItem(FileMenu,iSave);
}
if (LowOnMem) {
DisableItem(OptionMenu,iSound);
DisableItem(OptionMenu,iMusic);
}
if (DimQD) {
DisableItem(OptionMenu,iUseQuickDraw);
}
if (playstate==EX_AUTOMAP || playstate==EX_DIED) {
DisableItem(OptionMenu,iScreenSize);
} else {
EnableItem(OptionMenu,iScreenSize);
}
SetAMark(OptionMenu,iSound,SystemState&SfxActive); /* Check the sound menu */
SetAMark(OptionMenu,iMusic,SystemState&MusicActive); /* Check the music menu */
SetAMark(OptionMenu,iGovenor,SlowDown); /* Check the Speed goveror */
SetAMark(OptionMenu,iMouseControl,MouseEnabled); /* Check the mouse flag */
SetAMark(OptionMenu,iUseQuickDraw,DoQuickDraw); /* Check the mouse flag */
}
/**********************************
Process a menu bar event
**********************************/
void DoMenuCommand(LongWord menuResult)
{
Word menuID; /* the resource ID of the selected menu */
Word menuItem; /* the item number of the selected menu */
Str255 daName; /* Name of desk acc */
Word i; /* Temp */
menuID = menuResult>>16;
menuItem = menuResult&0xffff; /* get menu item number and menu number */
switch (menuID) {
case mApple: /* Apple menu */
switch (menuItem) {
case iAbout: /* Bring up alert for About */
PlaySound(SND_MENU);
DoMyAlert(rAboutAlert); /* Show the credits */
PlaySound(SND_OK);
break;
case iSpeedHint:
PlaySound(SND_MENU);
DoMyAlert(SpeedTipsWin); /* Show the hints for speed */
PlaySound(SND_OK);
break;
case iShareWare:
PlaySound(SND_MENU);
DoMyAlert(ShareWareWin); /* Ask about $$$ */
PlaySound(SND_OK);
break;
default: /* all non-About items in this menu are DAs */
GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
OpenDeskAcc(daName);
break;
}
break;
case mFile: /* File menu */
switch (menuItem) {
case iNew:
if (ChooseGameDiff()) { /* Choose level of difficulty */
HiliteMenu(0);
FixPauseMenu();
SaveFileName = 0; /* Zap the save game name */
longjmp(ResetJmp,EX_NEWGAME);
}
break;
case iClose:
DoCloseWindow(FrontWindow());
break;
case iOpen:
if (ChooseLoadGame()) { /* Choose a game to load */
if (LoadGame()) { /* Load the game into memory */
HiliteMenu(0);
FixPauseMenu();
longjmp(ResetJmp,EX_LOADGAME); /* Restart a loaded game */
}
}
break;
case iSave:
if (SaveFileName) { /* Save the file automatically? */
SaveGame(); /* Save it */
break;
}
case iSaveAs:
if (ChooseSaveGame()) { /* Select a save game name */
SaveGame(); /* Save it */
}
break;
case iQuit:
GoodBye(); /* Try to quit */
break;
}
break;
case mEdit: /* call SystemEdit for DA editing & MultiFinder */
SystemEdit(menuItem-1); /* since we don't do any Editing */
break;
case mOptions:
switch (menuItem) {
case iSound:
SystemState^=SfxActive; /* Sound on/off flags */
if (!(SystemState&SfxActive)) {
if (InPause) {
ResumeSoundMusicSystem();
}
PlaySound(0); /* Turn off all existing sounds */
if (InPause) {
PauseSoundMusicSystem();
}
}
break;
case iMusic:
SystemState^=MusicActive; /* Music on/off flags */
if (InPause) {
ResumeSoundMusicSystem();
}
if (SystemState&MusicActive) {
PlaySong(KilledSong); /* Restart the music */
} else {
PlaySong(0); /* Shut down the music */
}
if (InPause) {
PauseSoundMusicSystem();
}
break;
case iScreenSize:
i = DoMyAlert(AskSizeWin); /* Should I change the size? */
if (i && i<5) {
--i;
if (GameViewSize!=i) { /* Did you change the size? */
if (!InPause) {
HideMenuBar();
}
MouseHit = TRUE; /* Get out of pause mode */
GameViewSize = i; /* Set the new size */
if (playstate==EX_STILLPLAYING || playstate==EX_AUTOMAP) {
TryIt:
GameViewSize = NewGameWindow(GameViewSize); /* Make a new window */
if (!StartupRendering(GameViewSize)) { /* Set the size of the game screen */
ReleaseScalers();
if (!GameViewSize) {
BailOut();
}
--GameViewSize;
goto TryIt;
}
if (playstate==EX_STILLPLAYING) {
RedrawStatusBar(); /* Redraw the lower area */
}
playstate=EX_STILLPLAYING;
SetAPalette(rGamePal); /* Reset the game palette */
}
}
}
break;
case iGovenor:
SlowDown^=1; /* Toggle the slow down flag */
break;
case iMouseControl:
MouseEnabled = (!MouseEnabled); /* Toggle the cursor */
FixTheCursor();
if (MouseEnabled) {
ReadSystemJoystick();
mousex = 0;
mousey = 0;
mouseturn=0;
ReadSystemJoystick();
mousex =0; /* Discard the results */
mousey =0;
mouseturn=0;
}
break;
case iUseQuickDraw:
DoQuickDraw^=TRUE; /* Toggle the quickdraw flag */
break;
}
SavePrefs();
break;
}
HiliteMenu(0); /* unhighlight what MenuSelect (or MenuKey) hilited */
}
/*********************************
Close a window, return TRUE if successful
*********************************/
Boolean DoCloseWindow(WindowPtr window)
{
int Kind;
if (window) { /* Valid pointer? */
Kind = ((WindowPeek) window)->windowKind; /* Get the kind */
if (Kind<0) {
CloseDeskAcc(Kind);
}
}
return TRUE; /* I closed it! */
}
/***************************
I can't load! Bail out now!
****************************/
void BailOut(void)
{
DoMyAlert(rUserAlert); /* Show the alert window */
GoodBye(); /* Bail out! */
}
/**********************************
Update the wolf screen as fast as possible
Make sure that ForeColor = BLACK and Color = WHITE,
ROWBYTES should be long aligned (4,8,12,16...)
Source and dest should be EXACTLY the same bit depth
ctSeed should match the WINDOW's color seed
Both rects should be multiples of 4 to make long word transfers only
**********************************/
void BlastScreen2(Rect *BlastRect)
{
Rect QDRect;
CTabHandle ColorHandle,ColorHandle2;
QDRect = *BlastRect;
OffsetRect(&QDRect,QDGameRect.left,QDGameRect.top);
SetPort((WindowPtr) GameWindow); /* Make sure the port is set */
ColorHandle = (**(*GameGWorld).portPixMap).pmTable; /* Get the color table */
ColorHandle2 = (**(*GameWindow).portPixMap).pmTable; /* Get the color table */
PtrToXHand(*MainColorHandle,(Handle)ColorHandle,8+8*256);
PtrToXHand(*MainColorHandle,(Handle)ColorHandle2,8+8*256);
CopyBits((BitMap *) *((*GameGWorld).portPixMap),(BitMap *) *((*GameWindow).portPixMap),
BlastRect,&QDRect,srcCopy,NULL);
}
void BlastScreen(void)
{
Word i,j,k,m;
Byte *Screenad;
LongWord *Dest;
union {
LongWord * L;
Byte *B;
} Src;
Point MyPoint;
MyPoint.h = BlackRect2.left;
MyPoint.v = BlackRect2.top;
ShieldCursor(&GameRect,MyPoint);
if (!DoQuickDraw) {
i = MacHeight;
k = MacWidth/64;
m = VideoWidth - MacWidth;
Src.B = VideoPointer; /* Pointer to video */
Screenad = GameVideoPointer; /* Get dest video address */
do {
j = k; /* Init width (In Longs) */
Dest = (LongWord *) Screenad; /* Reset the dest pointer */
do {
Dest[0] = Src.L[0];
Dest[1] = Src.L[1];
Dest[2] = Src.L[2];
Dest[3] = Src.L[3];
Dest[4] = Src.L[4];
Dest[5] = Src.L[5];
Dest[6] = Src.L[6];
Dest[7] = Src.L[7];
Dest[8] = Src.L[8];
Dest[9] = Src.L[9];
Dest[10] = Src.L[10];
Dest[11] = Src.L[11];
Dest[12] = Src.L[12];
Dest[13] = Src.L[13];
Dest[14] = Src.L[14];
Dest[15] = Src.L[15];
Dest+=16;
Src.L+=16;
} while (--j);
Src.B += m;
Screenad+=TrueVideoWidth;
} while (--i);
} else {
BlastScreen2(&GameRect);
}
ShowCursor();
if (!InPause) {
ObscureCursor();
}
}
/**********************************
Create a new game window
**********************************/
Word NewGameWindow(Word NewVidSize)
{
Byte *DestPtr;
LongWord *LongPtr;
Word i,j;
Boolean Pass2;
RgnHandle TempRgn;
Pass2 = FALSE; /* Assume memory is OK */
/* First, kill ALL previous permenant records */
if (NewVidSize>=2) { /* Is this 640 mode? */
if (MonitorWidth<640) { /* Can I show 640 mode? */
NewVidSize=1; /* Reduce to 512 mode */
} else {
if (MonitorHeight<480) { /* Can I display 480 lines? */
NewVidSize=2; /* Show 400 instead */
}
}
}
if (NewVidSize==MacVidSize) { /* Same size being displayed? */
return MacVidSize; /* Exit then... */
}
SetPort((WindowPtr)GameWindow); /* Blank out the screen! */
ForeColor(blackColor); /* Make sure the colors are set */
BackColor(whiteColor);
FillRect(&BlackRect,&qd.black); /* Blank it out! */
TryAgain:
if (GameGWorld) {
DisposeGWorld(GameGWorld); /* Release the old GWorld */
GameGWorld=0;
}
if (GameShapes) {
FreeSomeMem(GameShapes); /* All the permanent game shapes */
GameShapes=0;
}
MacVidSize = NewVidSize; /* Set the new data size */
MacWidth = VidXs[NewVidSize];
MacHeight = VidYs[NewVidSize];
MacViewHeight = VidVs[NewVidSize];
GameRect.bottom = MacHeight; /* Set new video height */
GameRect.right = MacWidth; /* Set new video width */
QDGameRect.top = RectY;
QDGameRect.left = RectX;
QDGameRect.bottom = RectY+MacHeight;
QDGameRect.right = RectX+MacWidth;
if (MacHeight==MonitorHeight && MacWidth==MonitorWidth) {
ValidRects = FALSE;
} else {
ValidRects = TRUE; /* The 4 bar rects are valid */
RectRgn(BlackRgn,&BlackRect);
TempRgn = NewRgn();
RectRgn(TempRgn,&QDGameRect);
DiffRgn(BlackRgn,TempRgn,BlackRgn);
DisposeRgn(TempRgn);
}
GameVideoPointer = &TrueVideoPointer[(LongWord)QDGameRect.top*TrueVideoWidth+QDGameRect.left];
if (NewGWorld(&GameGWorld,8,&GameRect,nil,nil,0)) {
goto OhShit;
}
LockPixels(GameGWorld->portPixMap); /* Lock down the memory FOREVER! */
VideoPointer = (Byte *)GetPixBaseAddr(GameGWorld->portPixMap); /* Get the video pointer */
VideoWidth = (Word) (**(*GameGWorld).portPixMap).rowBytes & 0x3FFF;
InitYTable(); /* Init the game's YTable */
SetAPalette(rBlackPal); /* Set the video palette */
ClearTheScreen(BLACK); /* Set the screen to black */
BlastScreen();
LongPtr = (LongWord *) LoadAResource(VidPics[MacVidSize]);
if (!LongPtr) {
goto OhShit;
}
GameShapes = (Byte **) AllocSomeMem(LongPtr[0]); /* All the permanent game shapes */
if (!GameShapes) { /* Can't load in the shapes */
ReleaseAResource(VidPics[MacVidSize]); /* Release it NOW! */
goto OhShit;
}
DLZSS((Byte *)GameShapes,(Byte *) &LongPtr[1],LongPtr[0]);
ReleaseAResource(VidPics[MacVidSize]);
i = 0;
j = (MacVidSize==1) ? 47+10 : 47; /* 512 mode has 10 shapes more */
DestPtr = (Byte *) GameShapes;
LongPtr = (LongWord *) GameShapes;
do {
GameShapes[i] = DestPtr+LongPtr[i];
} while (++i<j);
if (Pass2) { /* Low memory? */
if (!StartupRendering(NewVidSize)) { /* Reset the scalers... */
ReleaseScalers();
goto OhShit;
}
}
return MacVidSize;
OhShit: /* Oh oh.... */
if (Pass2) {
if (!NewVidSize) { /* At the smallest screen size? */
BailOut();
}
--NewVidSize; /* Smaller size */
} else {
PlaySong(0); /* Release song memory */
ReleaseScalers(); /* Release the compiled scalers */
PurgeAllSounds(1000000); /* Force sounds to be purged */
Pass2 = TRUE;
}
goto TryAgain; /* Let's try again */
}
/**********************************
Scale the system X coord
**********************************/
Word ScaleX(Word x)
{
switch(MacVidSize) {
case 1:
return x*8/5;
case 2:
case 3:
return x*2;
}
return x;
}
/**********************************
Scale the system Y coord
**********************************/
Word ScaleY(Word y)
{
switch(MacVidSize) {
case 1: /* 512 resolution */
y = (y*8/5)+64;
if (y==217) { /* This hack will line up the gun on 512 mode */
++y;
}
return y;
case 2: /* 640 x 400 */
return y*2;
case 3: /* 640 x 480 */
return y*2+80;
}
return y; /* 320 resolution */
}
/**********************************
Shut down and exit
**********************************/
void GoodBye(void)
{
ShowMenuBar(); /* Restore the menu bar */
ReleaseScalers(); /* Release all my memory */
FinisSoundMusicSystem(); /* Shut down the Halestorm driver */
if (gMainGDH && OldPixDepth) { /* Old pixel depth */
SetDepth(gMainGDH,OldPixDepth, 1 << gdDevType,1); /* Restore the depth */
}
InitCursor();
ExitToShell(); /* Exit to System 7 */
}
/**********************************
Read from the Mac's keyboard/mouse system
**********************************/
Word MyKey;
typedef struct MacKeys2Joy {
Word Index;
Word BitField;
Word JoyValue;
} MacKeys2Joy;
MacKeys2Joy KeyMatrix[] = {
{11,1<<1,JOYPAD_LFT|JOYPAD_UP}, /* Keypad 7 */
{10,1<<6,JOYPAD_LFT}, /* Keypad 4 */
{10,1<<3,JOYPAD_LFT|JOYPAD_DN}, /* Keypad 1 */
{11,1<<3,JOYPAD_UP}, /* Keypad 8 */
{10,1<<7,JOYPAD_DN}, /* Keypad 5 */
{10,1<<4,JOYPAD_DN}, /* Keypad 2 */
{11,1<<4,JOYPAD_RGT|JOYPAD_UP}, /* Keypad 9 */
{11,1<<0,JOYPAD_RGT}, /* Keypad 6 */
{10,1<<5,JOYPAD_RGT|JOYPAD_DN}, /* Keypad 3 */
{15,1<<6,JOYPAD_UP}, /* Arrow up */
{15,1<<5,JOYPAD_DN}, /* Arrow down */
{15,1<<3,JOYPAD_LFT}, /* Arrow Left */
{15,1<<4,JOYPAD_RGT}, /* Arrow Right */
{ 1,1<<5,JOYPAD_UP}, /* W */
{ 0,1<<0,JOYPAD_LFT}, /* A */
{ 0,1<<1,JOYPAD_DN}, /* S */
{ 0,1<<2,JOYPAD_RGT}, /* D */
{ 4,1<<2,JOYPAD_UP}, /* I */
{ 4,1<<6,JOYPAD_LFT}, /* J */
{ 5,1<<0,JOYPAD_DN}, /* K */
{ 4,1<<5,JOYPAD_RGT}, /* L */
{ 6,1<<1,JOYPAD_A}, /* Space */
{ 4,1<<4,JOYPAD_A}, /* Return */
{10,1<<2,JOYPAD_A}, /* Keypad 0 */
{ 9,1<<4,JOYPAD_A}, /* keypad enter */
{ 7,1<<7,JOYPAD_TR}, /* Option */
{ 7,1<<2,JOYPAD_TR}, /* Option */
{ 7,1<<0,JOYPAD_X}, /* Shift L */
{ 7,1<<1,JOYPAD_X}, /* Caps Lock */
{ 7,1<<4,JOYPAD_X}, /* Shift R */
{ 6,1<<0,JOYPAD_SELECT}, /* Tab */
{ 7,1<<3,JOYPAD_B}, /* Ctrl */
{ 7,1<<6,JOYPAD_B} /* Ctrl */
};
static char *CheatPtr[] = { /* Cheat strings */
"XUSCNIELPPA",
"IDDQD",
"BURGER",
"WOWZERS",
"LEDOUX",
"SEGER",
"MCCALL",
"APPLEIIGS"
};
static Word Cheat; /* Which cheat is active */
static Word CheatIndex; /* Index to the cheat string */
static void FixPauseMenu(void)
{
if (PauseMenu) { /* Is there a pause menu? */
InPause = FALSE;
DeleteMenu(55); /* Remove it from the menu bar */
DrawMenuBar(); /* Redraw the menu bar */
HideMenuBar(); /* Hide the menu bar */
DisposeMenu(PauseMenu); /* Free the memory */
PauseMenu = 0; /* Ack the flag */
ResumeSoundMusicSystem(); /* Restart the music */
}
}
void ReadSystemJoystick(void)
{
Word i;
Word Index;
MacKeys2Joy *MacPtr;
Point MyPoint;
union {
unsigned char Keys[16];
KeyMap Macy;
} Keys;
joystick1 = 0; /* Assume that joystick not moved */
i = GetAKey(); /* Allow menu events */
if (i==0x1b) { /* Pause key? */
ShowMenuBar();
InitCursor();
PauseMenu = NewMenu(55,"\p<< Game is Paused! >>");
InsertMenu(PauseMenu,0);
DrawMenuBar();
PauseSoundMusicSystem(); /* Pause the music */
InPause = TRUE; /* Hack to prevent the menu bar from disappearing */
WaitTicksEvent(0);
LastTicCount = ReadTick(); /* Reset the timer for the pause key */
FixPauseMenu(); /* Exit pause */
FixTheCursor();
}
/* Switch weapons like in DOOM! */
if (i) { /* Was a key hit? */
i = toupper(i); /* Force UPPER case */
if (CheatIndex) { /* Cheat in progress */
if (CheatPtr[Cheat][CheatIndex]==i) { /* Match the current string? */
++CheatIndex; /* Next char */
if (!CheatPtr[Cheat][CheatIndex]) { /* End of the string? */
PlaySound(SND_BONUS); /* I got a bonus! */
switch (Cheat) { /* Execute the cheat */
case 1:
gamestate.godmode^=TRUE; /* I am invincible! */
break;
case 5:
GiveKey(0);
GiveKey(1); /* Award the keys */
break;
case 6:
playstate=EX_WARPED; /* Force a jump to the next level */
nextmap = gamestate.mapon+1; /* Next level */
if (MapListPtr->MaxMap<=nextmap) { /* Too high? */
nextmap = 0; /* Reset to zero */
}
break;
case 7:
ShowPush ^= TRUE;
break;
case 0:
case 4:
GiveKey(0); /* Award the keys */
GiveKey(1);
gamestate.godmode = TRUE; /* I am a god */
case 2:
gamestate.machinegun = TRUE;
gamestate.chaingun = TRUE;
gamestate.flamethrower = TRUE;
gamestate.missile = TRUE;
GiveAmmo(gamestate.maxammo);
GiveGas(99);
GiveMissile(99);
break;
case 3:
gamestate.maxammo = 999;
GiveAmmo(999);
}
}
} else {
CheatIndex = 0;
goto TryFirst;
}
} else {
TryFirst:
Index = 0; /* Init the scan routine */
do {
if (CheatPtr[Index][0] == i) {
Cheat = Index; /* This is my current cheat I am scanning */
CheatIndex = 1; /* Index to the second char */
break; /* Exit */
}
} while (++Index<8); /* All words scanned? */
}
switch (ScanCode) { /* Use the SCAN code to make sure I hit the right key! */
case 0x12 : /* 1 */
gamestate.pendingweapon = WP_KNIFE;
break;
case 0x13 : /* 2 */
if (gamestate.ammo) {
gamestate.pendingweapon = WP_PISTOL;
}
break;
case 0x14 : /* 3 */
if (gamestate.ammo && gamestate.machinegun) {
gamestate.pendingweapon = WP_MACHINEGUN;
}
break;
case 0x15 : /* 4 */
if (gamestate.ammo && gamestate.chaingun) {
gamestate.pendingweapon = WP_CHAINGUN;
}
break;
case 0x17 : /* 5 */
if (gamestate.gas && gamestate.flamethrower) {
gamestate.pendingweapon = WP_FLAMETHROWER;
}
break;
case 0x16 : /* 6 */
if (gamestate.missiles && gamestate.missile) {
gamestate.pendingweapon = WP_MISSILE;
}
break;
case 0x41: /* Keypad Period */
case 0x2C: /* Slash */
joystick1 = JOYPAD_START;
}
}
GetKeys(Keys.Macy); /* Get the keyboard from the mac */
i = 0; /* Init the count */
MacPtr = KeyMatrix;
do {
Index = MacPtr->Index; /* Get the byte index */
if (Keys.Keys[Index] & MacPtr->BitField) {
joystick1 |= MacPtr->JoyValue; /* Set the joystick value */
}
MacPtr++; /* Next index */
} while (++i<33); /* All done? */
if (MouseEnabled) { /* Mouse control turned on? */
if (Button()) { /* Get the mouse button */
joystick1 |= JOYPAD_B; /* Mouse button */
}
GetMouse(&MyPoint); /* Get the mouse location */
LocalToGlobal(&MyPoint); /* Convert mouse to global coordinate system */
if (joystick1&JOYPAD_TR) { /* Strafing? */
mousex += (MyPoint.h-MouseBaseX); /* Move horizontally for strafe */
} else {
mouseturn += (MouseBaseX-MyPoint.h); /* Turn left or right */
}
mousey += (MyPoint.v-MouseBaseY); /* Forward motion */
(*(unsigned short *) 0x082C) = MouseBaseY; /* Set RawMouse */
(*(unsigned short *) 0x082E) = MouseBaseX;
(*(unsigned short *) 0x0828) = MouseBaseY; /* MTemp */
(*(unsigned short *) 0x082A) = MouseBaseX;
(*(Byte *) 0x08CE) = 255; /* CrsrNew */
(*(Byte *) 0x08CF) = 255; /* CrsrCouple */
}
if (joystick1 & JOYPAD_TR) { /* Handle the side scroll (Special case) */
if (joystick1&JOYPAD_LFT) {
joystick1 = (joystick1 & ~(JOYPAD_TR|JOYPAD_LFT)) | JOYPAD_TL;
} else if (joystick1&JOYPAD_RGT) {
joystick1 = joystick1 & ~JOYPAD_RGT;
} else {
joystick1 &= ~JOYPAD_TR;
}
}
}
/**********************************
Handle GET PSYCHED!
**********************************/
static Rect PsychedRect;
static Word LeftMargin;
#define PSYCHEDWIDE 184
#define PSYCHEDHIGH 5
#define PSYCHEDX 20
#define PSYCHEDY 46
#define MAXINDEX (66+S_LASTONE)
/**********************************
Draw the initial shape
**********************************/
void ShowGetPsyched(void)
{
LongWord *PackPtr;
Byte *ShapePtr;
LongWord PackLength;
Word X,Y;
SetPort((WindowPtr)GameWindow);
ClearTheScreen(BLACK);
BlastScreen();
PackPtr = LoadAResource(rGetPsychPic);
PackLength = PackPtr[0];
ShapePtr = AllocSomeMem(PackLength);
DLZSS(ShapePtr,(Byte *) &PackPtr[1],PackLength);
X = (MacWidth-224)/2;
Y = (MacViewHeight-56)/2;
DrawShape(X,Y,ShapePtr);
FreeSomeMem(ShapePtr);
ReleaseAResource(rGetPsychPic);
BlastScreen();
SetAPalette(rGamePal);
SetPort((WindowPtr)GameWindow);
ForeColor(redColor);
PsychedRect.top = Y + PSYCHEDY + QDGameRect.top;
PsychedRect.bottom = PsychedRect.top + PSYCHEDHIGH;
PsychedRect.left = X + PSYCHEDX + QDGameRect.left;
PsychedRect.right = PsychedRect.left;
LeftMargin = PsychedRect.left;
}
/**********************************
Update the thermomitor
**********************************/
void DrawPsyched(Word Index)
{
Word Factor;
Factor = Index * PSYCHEDWIDE; /* Calc the relative X pixel factor */
Factor = Factor / MAXINDEX;
PsychedRect.left = PsychedRect.right; /* Adjust the left pixel */
PsychedRect.right = Factor+LeftMargin;
PaintRect(&PsychedRect); /* Draw the pixel in the bar */
}
/**********************************
Erase the Get Psyched screen
**********************************/
void EndGetPsyched(void)
{
ForeColor(blackColor); /* Reset the color to black for high speed */
SetAPalette(rBlackPal); /* Zap the palette */
}
/**********************************
Choose the game difficulty
**********************************/
static void DrawNewRect(DialogPtr theDialog,Word Item,Word Color)
{
short iType;
Handle iHndl;
Rect iRect;
ForeColor(Color);
GetDialogItem(theDialog,Item, &iType, &iHndl, &iRect);
InsetRect(&iRect,-4,-4);
PenSize(3,3); /* Nice thick line */
FrameRect(&iRect);
PenNormal();
}
/**********************************
Choose the game difficulty
**********************************/
static Word OldVal; /* Make semi-global so the filter can use it as input */
Word ChooseGameDiff(void)
{
ModalFilterUPP theDialogFilter;
DialogPtr MyDialog;
short itemHit;
Word donewithdialog;
Word RetVal;
Word OldTick;
unsigned short DblClick;
Byte OldPal[768];
memcpy(OldPal,CurrentPal,768);
SetPort((WindowPtr)GameWindow);
FillRect(&BlackRect,&qd.black);
SetAPalette(rGamePal);
MyDialog = GetNewDialog(NewGameWin,0L,(WindowPtr)-1); /* Open the dialog window */
OldVal = difficulty+1; /* Save the current difficulty */
PlaySound(SND_MENU);
CenterAWindow(MyDialog);
ShowWindow(MyDialog); /* Display with OK button framed */
InitCursor();
SetPort((WindowPtr) MyDialog);
DrawNewRect(MyDialog,OldVal,blackColor);
DblClick = 0;
donewithdialog = FALSE;
RetVal = TRUE; /* Assume ok */
theDialogFilter = NewModalFilterProc(StandardModalFilterProc);
do {
ModalDialog(theDialogFilter, &itemHit);
switch (itemHit) {
case 1:
case 2:
case 3:
case 4: /* The checkbox */
if (OldVal!=itemHit) {
DrawNewRect(MyDialog,OldVal,whiteColor); /* Erase the old rect */
DrawNewRect(MyDialog,itemHit,blackColor);
OldVal = itemHit;
}
PlaySound(SND_GUNSHT); /* Gun shot */
if (DblClick==itemHit) { /* Hit the same item? */
if (((Word)ReadTick()-OldTick)<(Word)15) { /* Double click time? */
donewithdialog = TRUE;
difficulty = OldVal-1;
break; /* Ok! */
}
}
OldTick=ReadTick(); /* Save the tick mark */
DblClick=itemHit; /* Save the last item hit */
break;
case 5:
RetVal = FALSE;
donewithdialog = TRUE;
PlaySound(SND_OK);
break;
case 6: /* OK Button */
donewithdialog = TRUE;
difficulty = OldVal-1;
PlaySound(SND_OK);
break;
}
} while (!donewithdialog);
DisposeRoutineDescriptor(theDialogFilter);
DisposeDialog(MyDialog);
SetAPalettePtr(OldPal); /* Restore the palette */
SetPort((WindowPtr) GameWindow);
DrawWindow((WindowPtr)GameWindow); /* Draw it NOW! */
FixTheCursor();
return RetVal;
}
static Byte BoxUp[] = {3,4,1,2}; /* Up/Down */
static Byte BoxLeft[] = {2,1,4,3}; /* Left/Right */
static Byte TabLeft[] = {2,3,4,1}; /* Tab */
pascal Boolean StandardModalFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
{
char theChar;
Handle theHandle;
short theType;
Rect theRect;
switch (theEvent->what) {
case keyDown:
theChar = toupper(theEvent->message & charCodeMask);
switch (theChar) {
case '8': /* Up */
case 0x1E: /* Up */
case '5': /* Down */
case '2': /* Down */
case 0x1F: /* Down */
case 'W':
case 'S':
case 'I':
case 'K':
*itemHit = BoxUp[OldVal-1];
return TRUE;
case '4': /* Left */
case '6': /* Right */
case 0x1C: /* Left */
case 0x1D: /* Right */
case 'A':
case 'D':
case 'J':
case 'L':
*itemHit = BoxLeft[OldVal-1];
return TRUE;
case 9:
*itemHit = TabLeft[OldVal-1];
return TRUE;
case 0x0D: /* Return */
case 0x03: /* Enter */
*itemHit = 6;
return (TRUE);
case 'Q': /* Cmd-Q */
case '.': /* Cmd-Period */
if (theEvent->modifiers & cmdKey) {
case 0x1b: /* Esc */
*itemHit = 5;
return (TRUE);
}
break;
}
break;
case updateEvt:
GetDialogItem(theDialog, 6, &theType, &theHandle, &theRect);
InsetRect(&theRect, -4, -4);
PenSize(3, 3);
FrameRoundRect(&theRect, 16, 16);
}
return (FALSE); // Tells dialog manager to handle the event
}
/**********************************
Load the prefs file into memory and use defaults
for ANY errors that could occur
**********************************/
typedef struct { /* Save game data field */
unsigned short State; /* Game state flags */
unsigned short Mouse; /* Mouse control */
unsigned short QuickDraw; /* Quickdraw for updates */
unsigned short Goveror; /* Speed governor */
unsigned short ViewSize; /* Game screen size */
unsigned short Difficulty; /* Game difficulty */
unsigned short Ignore; /* Ignore message flag */
} Prefs_t;
void LoadPrefs(void)
{
Prefs_t Prefs;
Prefs.State = 3; /* Assume sound & music enabled */
Prefs.Mouse = FALSE; /* Mouse control shut off */
Prefs.QuickDraw = TRUE; /* Use quickdraw for screen updates */
Prefs.Goveror = TRUE; /* Enable speed governor */
Prefs.ViewSize = 0; /* 320 mode screen */
Prefs.Difficulty = 2; /* Medium difficulty */
Prefs.Ignore = FALSE; /* Enable message */
InitPrefsFile('WOLF',(Byte *)"Wolfenstein 3D Prefs"); /* Create the prefs file (If it doesn't exist) */
LoadPrefsFile((Byte *)&Prefs,sizeof(Prefs)); /* Load in the prefs (Assume it may NOT!) */
SystemState = Prefs.State; /* Store the defaults from either the presets or the file */
MouseEnabled = Prefs.Mouse;
DoQuickDraw = Prefs.QuickDraw;
SlowDown = Prefs.Goveror;
GameViewSize = Prefs.ViewSize;
difficulty = Prefs.Difficulty;
IgnoreMessage = Prefs.Ignore;
}
/**********************************
Save the prefs file to disk but ignore any errors
**********************************/
void SavePrefs(void)
{
Prefs_t Prefs; /* Structure to save to disk */
Prefs.State = SystemState; /* Init the prefs structure */
Prefs.Mouse = MouseEnabled;
Prefs.QuickDraw = DoQuickDraw;
Prefs.Goveror = SlowDown;
Prefs.ViewSize = GameViewSize;
Prefs.Difficulty = difficulty;
Prefs.Ignore = IgnoreMessage;
SavePrefsFile((Byte *)&Prefs,sizeof(Prefs)); /* Save the prefs file */
}
/**********************************
Save the game
**********************************/
#ifdef __powerc
Byte MachType[4] = "PPC3";
#else
Byte MachType[4] = "68K3";
#endif
void SaveGame(void)
{
short FileRef;
long Count;
Word PWallWord;
HCreate(SaveFileVol,SaveFileParID,SaveFileName,'WOLF','SAVE'); /* Create the save game file */
if (HOpen(SaveFileVol,SaveFileParID,SaveFileName,fsWrPerm,&FileRef)) { /* Can I open it? */
return; /* Abort! */
}
Count = 4; /* Default length */
FSWrite(FileRef,&Count,&MachType); /* Save a machine type ID */
Count = sizeof(unsigned short);
FSWrite(FileRef,&Count,&MapListPtr->MaxMap); /* Number of maps (ID) */
Count = sizeof(gamestate);
FSWrite(FileRef,&Count,&gamestate); /* Save the game stats */
Count = sizeof(PushWallRec);
FSWrite(FileRef,&Count,&PushWallRec); /* Save the pushwall stats */
Count = sizeof(nummissiles);
FSWrite(FileRef,&Count,&nummissiles); /* Save missiles in motion */
if (nummissiles) {
Count = nummissiles*sizeof(missile_t);
FSWrite(FileRef,&Count,&missiles[0]);
}
Count = sizeof(numactors);
FSWrite(FileRef,&Count,&numactors); /* Save actors */
if (numactors) {
Count = numactors*sizeof(actor_t);
FSWrite(FileRef,&Count,&actors[0]);
}
Count = sizeof(numdoors);
FSWrite(FileRef,&Count,&numdoors); /* Save doors */
if (numdoors) {
Count = numdoors*sizeof(door_t);
FSWrite(FileRef,&Count,&doors[0]);
}
Count = sizeof(numstatics);
FSWrite(FileRef,&Count,&numstatics);
if (numstatics) {
Count = numstatics*sizeof(static_t);
FSWrite(FileRef,&Count,&statics[0]);
}
Count = 64*64;
FSWrite(FileRef,&Count,MapPtr);
Count = sizeof(tilemap); /* Tile map */
FSWrite(FileRef,&Count,&tilemap);
Count = sizeof(ConnectCount);
FSWrite(FileRef,&Count,&ConnectCount);
if (ConnectCount) {
Count = ConnectCount * sizeof(connect_t);
FSWrite(FileRef,&Count,&areaconnect[0]);
}
Count = sizeof(areabyplayer);
FSWrite(FileRef,&Count,&areabyplayer[0]);
Count = (128+5)*64;
FSWrite(FileRef,&Count,&textures[0]);
Count = sizeof(Word);
PWallWord = 0; /* Assume no pushwall pointer in progress */
if (pwallseg) {
PWallWord = (pwallseg-(saveseg_t*)nodes)+1; /* Convert to number offset */
}
FSWrite(FileRef,&Count,&PWallWord);
Count = MapPtr->numnodes*sizeof(savenode_t); /* How large is the BSP tree? */
FSWrite(FileRef,&Count,nodes); /* Save it to disk */
FSClose(FileRef); /* Close the file */
PlaySound(SND_BONUS);
}
/**********************************
Load the game
**********************************/
void *SaveRecord;
void *SaveRecordMem;
Boolean LoadGame(void)
{
LongWord FileSize;
union {
Byte *B;
unsigned short *S;
Word *W;
LongWord *L;
} FilePtr;
void *TheMem;
short FileRef;
if (HOpen(SaveFileVol, SaveFileParID, SaveFileName, fsRdPerm, &FileRef)) {
return FALSE;
}
GetEOF(FileRef,(long*)&FileSize); /* Get the size of the file */
FilePtr.B = TheMem = AllocSomeMem(FileSize); /* Get memory for the file */
if (!FilePtr.B) { /* No memory! */
return FALSE;
}
FSRead(FileRef,(long*)&FileSize,(Ptr)FilePtr.B); /* Open the file */
FSClose(FileRef); /* Close the file */
if (memcmp(MachType,FilePtr.B,4)) { /* Is this the proper machine type? */
goto Bogus;
}
FilePtr.B+=4; /* Index past signature */
if (MapListPtr->MaxMap!=*FilePtr.S) { /* Map count the same? */
goto Bogus; /* Must be differant game */
}
++FilePtr.S; /* Index past count */
memcpy(&gamestate,FilePtr.B,sizeof(gamestate)); /* Reset the game state */
SaveRecord = FilePtr.B;
SaveRecordMem = TheMem;
return TRUE;
Bogus:
FreeSomeMem(TheMem);
return FALSE;
}
void FinishLoadGame(void)
{
union {
Byte *B;
unsigned short *S;
Word *W;
LongWord *L;
} FilePtr;
FilePtr.B = SaveRecord;
memcpy(&gamestate,FilePtr.B,sizeof(gamestate)); /* Reset the game state */
FilePtr.B+=sizeof(gamestate);
memcpy(&PushWallRec,FilePtr.B,sizeof(PushWallRec)); /* Record for the single pushwall in progress */
FilePtr.B+=sizeof(PushWallRec);
nummissiles = *FilePtr.W;
++FilePtr.W;
if (nummissiles) {
memcpy(&missiles[0],FilePtr.B,sizeof(missile_t)*nummissiles);
FilePtr.B += sizeof(missile_t)*nummissiles;
}
numactors = *FilePtr.W;
++FilePtr.W;
if (numactors) {
memcpy(&actors[0],FilePtr.B,sizeof(actor_t)*numactors);
FilePtr.B += sizeof(actor_t)*numactors;
}
numdoors = *FilePtr.W;
++FilePtr.W;
if (numdoors) {
memcpy(&doors[0],FilePtr.B,sizeof(door_t)*numdoors);
FilePtr.B += sizeof(door_t)*numdoors;
}
numstatics = *FilePtr.W;
++FilePtr.W;
if (numstatics) {
memcpy(&statics[0],FilePtr.B,sizeof(static_t)*numstatics);
FilePtr.B += sizeof(static_t)*numstatics;
}
memcpy(MapPtr,FilePtr.B,64*64);
FilePtr.B += 64*64;
memcpy(&tilemap,FilePtr.B,sizeof(tilemap)); /* Tile map */
FilePtr.B += sizeof(tilemap); /* Index past data */
ConnectCount = *FilePtr.W; /* Number of valid interconnects */
FilePtr.W++;
if (ConnectCount) {
memcpy(areaconnect,FilePtr.B,sizeof(connect_t)*ConnectCount); /* Is this area mated with another? */
FilePtr.B+= sizeof(connect_t)*ConnectCount;
}
memcpy(areabyplayer,FilePtr.B,sizeof(areabyplayer));
FilePtr.B+=sizeof(areabyplayer); /* Which areas can I see into? */
memcpy(&textures[0],FilePtr.B,(128+5)*64);
FilePtr.B+=((128+5)*64); /* Texture array for pushwalls */
pwallseg = 0; /* Assume bogus */
if (*FilePtr.W) {
pwallseg = (saveseg_t *)nodes;
pwallseg = &pwallseg[*FilePtr.W-1];
}
++FilePtr.W;
memcpy(nodes,FilePtr.B,MapPtr->numnodes*sizeof(savenode_t));
/* FilePtr.B+=(MapPtr->numnodes*sizeof(savenode_t)); /* Next entry */
FreeSomeMem(SaveRecordMem);
}
/**********************************
Process an alert and center it on my game monitor
Note : I am cheating like a son of a bitch by modifing the
resources directly!
**********************************/
static Word DoMyAlert(Word AlertNum)
{
Word Val;
Rect **AlertRect; /* Handle to the alert rect */
Rect MyRect;
InitCursor(); /* Fix the cursor */
AlertRect = (Rect **)GetResource('ALRT',AlertNum); /* Load in the template */
MyRect = **AlertRect; /* Copy the rect */
MyRect.right -= MyRect.left; /* Get the width */
MyRect.bottom -= MyRect.top; /* Get the height */
CenterSFWindow((Point *)&MyRect,MyRect.right,MyRect.bottom); /* Center the window */
MyRect.right += MyRect.left; /* Fix the rect */
MyRect.bottom += MyRect.top;
**AlertRect = MyRect;
ChangedResource((Handle)AlertRect);
Val = Alert(AlertNum,nil);
if (!InPause) { /* If paused then don't fix the cursor */
FixTheCursor();
}
return Val;
}
/**********************************
Beg for $$$ at the end of the shareware version
**********************************/
void ShareWareEnd(void)
{
SetAPalette(rGamePal);
DoMyAlert(EndGameWin);
SetAPalette(rBlackPal);
}
/**********************************
Show the standard file dialog
for opening a new game
**********************************/
SFTypeList MyList = {'SAVE'};
SFReply Reply;
static void CenterSFWindow(Point *MyPoint,Word Width,Word Height)
{
GDHandle MainDevice;
Rect TheRect;
Word H,W; /* Device width of main device */
if (gMainGDH) { /* Has the video device been selected? */
MyPoint->v = ((MonitorHeight-Height)/3)+BlackRect2.top; /* Center the window then */
MyPoint->h = ((MonitorWidth-Width)/2)+BlackRect2.left;
return;
}
MainDevice = GetMainDevice(); /* Get the default device */
TheRect = (**MainDevice).gdRect; /* Get the rect of the device */
H = TheRect.bottom - TheRect.top; /* Get the size of the video screen */
W = TheRect.right - TheRect.left;
MyPoint->v = ((H-Height)/3)+TheRect.top; /* Center the window */
MyPoint->h = ((W-Width)/2)+TheRect.left;
}
static void CenterAWindow(WindowPtr MyWindow)
{
Rect MyRect;
Point MyPoint;
MyRect = ((WindowPeek)MyWindow)->port.portRect;
CenterSFWindow(&MyPoint,MyRect.right-MyRect.left,MyRect.bottom-MyRect.top);
MoveWindow(MyWindow,MyPoint.h,MyPoint.v,FALSE);
}
Boolean ChooseLoadGame(void)
{
long ProcID;
Point MyPoint;
InitCursor();
CenterSFWindow(&MyPoint,348,136);
SFGetFile(MyPoint,0,0,1,MyList,0,&Reply);
FixTheCursor();
if (!Reply.good) { /* Pressed cancel? */
return FALSE;
}
SaveFileName = (Byte *)&Reply.fName;
SaveFileVol = Reply.vRefNum;
GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&ProcID);
return TRUE;
}
/**********************************
Show the standard file dialog
for saving a new game
**********************************/
Boolean ChooseSaveGame(void)
{
Byte *SaveTemp;
Point MyPoint;
long ProcID;
InitCursor();
SaveTemp = SaveFileName;
if (!SaveTemp) {
SaveTemp = "\pUntitled";
}
CenterSFWindow(&MyPoint,304,104);
SFPutFile(MyPoint,"\pSave your game as:",SaveTemp,0,&Reply);
FixTheCursor();
if (!Reply.good) {
return FALSE;
}
SaveFileName = (Byte *)&Reply.fName;
SaveFileVol = Reply.vRefNum;
GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&ProcID);
return TRUE;
}
/**********************************
Process Apple Events
**********************************/
#if 1
struct AEinstalls {
AEEventClass theClass;
AEEventID theEvent;
void *Code;
AEEventHandlerUPP theProc;
};
typedef struct AEinstalls AEinstalls;
static OSErr GotRequiredParams(AppleEvent *theAppleEvent)
{
DescType returnedType;
Size actualSize;
OSErr theErr;
theErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr,
typeWildCard, &returnedType, nil, 0, &actualSize);
if (theErr == errAEDescNotFound)
return noErr;
if (!theErr)
return errAEParamMissed;
return theErr;
}
/* This is the standard Open Application event. */
static pascal OSErr AEOpenHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refIn)
{
OSErr theErr;
// This event occurs when the application is opened. In most cases
// nothing needs to be done, but we must make sure that we received
// no parameters, since none are supposed to be received.
theErr = GotRequiredParams(theAppleEvent);
if (theErr)
return theErr;
// do whatever is needed (e.g., open new untitled document)
return noErr;
}
/* Open Doc, opens our documents. Remember, this can happen at application start AND */
/* anytime else. If your app is up and running and the user goes to the desktop, hilites one */
/* of your files, and double-clicks or selects Open from the finder File menu this event */
/* handler will get called. Which means you don't do any initialization of globals here, or */
/* anything else except open then doc. */
/* SO-- Do NOT assume that you are at app start time in this */
/* routine, or bad things will surely happen to you. */
static pascal OSErr AEOpenDocHandler(AppleEvent *theAppleEvent, AppleEvent reply, long refCon)
{
AEDescList docList;
OSErr theErr;
long index, itemsInList;
Size actualSize;
AEKeyword keywd;
DescType returnedType;
FSSpec theFSS;
// In response to this event, we must open all documents specified in
// the Apple Event.
AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
// check for missing required parameters
theErr = GotRequiredParams(theAppleEvent);
if (theErr != noErr)
return AEDisposeDesc(&docList);
// count the number of descriptor records in the list
theErr = AECountItems(&docList, &itemsInList);
// get each descriptor record from the list, coerce the returned
// data to an FSSpec record, and open the associated file
index = 1;
if (index <= itemsInList) {
AEGetNthPtr(&docList, index, typeFSS, &keywd, &returnedType,
(Ptr)&theFSS, sizeof(theFSS), &actualSize);
// open FSSpec
OpenPending = TRUE;
SaveFileVol = theFSS.vRefNum;
SaveFileParID = theFSS.parID;
SaveFileName = (Byte *)&Reply.fName;
memcpy(&Reply.fName,&theFSS.name,*theFSS.name+1);
}
AEDisposeDesc(&docList);
return noErr;
}
static pascal OSErr AEPrintHandler(AppleEvent *theAppleEvent, AppleEvent reply, long refCon)
{
AEDescList docList;
OSErr theErr;
long index, itemsInList;
Size actualSize;
AEKeyword keywd;
DescType returnedType;
FSSpec theFSS;
// In response to this event, we must print all documents specified in
// the Apple Event.
theErr = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
// check for missing required parameters
theErr = GotRequiredParams(theAppleEvent);
if (theErr != noErr)
return AEDisposeDesc(&docList);
// count the number of descriptor records in the list
theErr = AECountItems(&docList, &itemsInList);
// get each descriptor record from the list, coerce the returned
// data to an FSSpec record, and open the associated file
for (index = 1; index <= itemsInList; index++)
{
theErr = AEGetNthPtr(&docList, index, typeFSS, &keywd, &returnedType,
(Ptr)&theFSS, sizeof(theFSS), &actualSize);
// print FSSpec <no printing in this application>
}
AEDisposeDesc(&docList);
return noErr;
}
/* Standard Quit event handler, to handle a Quit event from the Finder, for example.
Note that we may not exit from the AppleEvent handler! We have to set a flag,
and exit from within the normal application code. */
static pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
{
QuitFlag = 1; /* I quit! */
return noErr;
}
/* InitAEStuff installs my appleevent handlers */
void InitAEStuff(void);
static AEinstalls HandlersToInstall[] = {
{kCoreEventClass, kAEOpenApplication,AEOpenHandler,0},
{kCoreEventClass, kAEOpenDocuments, AEOpenDocHandler,0},
{kCoreEventClass, kAEQuitApplication, AEQuitHandler,0},
{kCoreEventClass, kAEPrintDocuments, AEPrintHandler,0}
};
void InitAEStuff(void)
{
Word i;
/* Check this machine for AppleEvents. If they are not here (ie not 7.0)
* then we return. */
#ifndef __powerc
long aLong;
short Code,Count;
short Index;
AppFile Stuff;
/* This is for the WONDERFUL system 6.0.7 filenames */
/* Only execute on 680x0 macs */
CountAppFiles(&Code,&Count);
for (Index=1;Index<=Count;++Count) {
GetAppFiles(Index,&Stuff);
if (Index==1) {
OpenPending = TRUE;
SaveFileVol = Stuff.vRefNum;
SaveFileName = (Byte *)&Reply.fName;
memcpy(&Reply.fName,&Stuff.fName,*Stuff.fName+1);
GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&aLong);
}
ClrAppFiles(Index);
}
if (Gestalt(gestaltAppleEventsAttr, &aLong)) { /* Are Apple events present? */
return;
}
if (!(aLong & (1<<gestaltAppleEventsPresent))) {
return;
}
#endif
/* The following series of calls installs all our AppleEvent Handlers.
* These handlers are added to the application event handler list that
* the AppleEvent manager maintains. So, whenever an AppleEvent happens
* and we call AEProcessEvent, the AppleEvent manager will check our
* list of handlers and dispatch to it if there is one.
*/
i = 0;
do {
HandlersToInstall[i].theProc = NewAEEventHandlerProc(HandlersToInstall[i].Code);
AEInstallEventHandler(HandlersToInstall[i].theClass, HandlersToInstall[i].theEvent,
HandlersToInstall[i].theProc,0,FALSE);
} while (++i<4);
}
#endif
/**********************************
Make the cursor disappear if needed
**********************************/
static void FixTheCursor(void)
{
InitCursor();
if (MouseEnabled && !InPause) {
HideCursor();
}
}
/**********************************
Show a watch cursor
**********************************/
static void WaitCursor(void)
{
SetCursor(*WatchHandle);
}
#include "wolfdef.h"
/**********************************
Returns a pointer to an empty missile record
**********************************/
missile_t *GetNewMissile(void)
{
Word Count;
Count = nummissiles;
if (Count < MAXMISSILES) { /* Already full? */
++Count; /* Next entry */
nummissiles = Count; /* Save the new missile count */
}
return &missiles[Count-1]; /* Get pointer to empty missile */
}
/**********************************
Explode a missile
**********************************/
void ExplodeMissile(missile_t *MissilePtr)
{
MissilePtr->flags = 0; /* Can't harm anyone! */
if (MissilePtr->type == MI_PMISSILE) {
MissilePtr->pic = S_MISSBOOM; /* Rocket explosion */
MissilePtr->type = 16; /* Tics to stay in explosion*/
} else {
MissilePtr->pic = S_FIREBOOM; /* Fire explosion */
MissilePtr->type = 8; /* Tics to stay in explosion*/
}
PlaySound(SND_BOOM|0x8000); /* BOOM! */
MissilePtr->x -= MissilePtr->xspeed; /* Undo the last motion */
MissilePtr->y -= MissilePtr->yspeed;
MissilePtr->xspeed = 0; /* Don't move anymore */
MissilePtr->yspeed = 0;
}
/**********************************
Take damage from the player
Damage is 8,16...64, pass the x,y for a kill x,y
**********************************/
void MissileHitPlayer(missile_t *MissilePtr)
{
TakeDamage((w_rnd()&0x38)+8,MissilePtr->x,MissilePtr->y); /* Inflict damage */
}
/**********************************
Take damage from the enemy
Detonate if not killed (return True)
**********************************/
Boolean MissileHitEnemy(missile_t *MissilePtr, actor_t *ActorPtr)
{
Word Damage;
if (MissilePtr->type == MI_PMISSILE) { /* Rocket? */
Damage = (w_rnd()&0x30)+16; /* Hit'm hard! */
} else {
Damage = (w_rnd()&0x0f)+1; /* Burn a little */
}
DamageActor(Damage,ActorPtr); /* Hit'em! */
return !(ActorPtr->flags & FL_DEAD); /* Not dead? */
}
/**********************************
Did the missile impact on an actor
**********************************/
Boolean CheckMissileActorHits(missile_t *MissilePtr)
{
Word xl,xh,yh;
Word x,y;
Word Bang;
Word tile;
actor_t *ActorPtr;
Bang = 0; /* Assume the missile is OK */
xl = (MissilePtr->x>>FRACBITS)-1; /* Create the kill rect */
xh = xl+3;
y = (MissilePtr->y>>FRACBITS)-1;
yh = y+3;
if (xl>=MAPSIZE) { /* Clip the attack rect to STAY on the map! */
xl = 0;
}
if (y>=MAPSIZE) {
y = 0;
}
if (xh>=MAPSIZE) {
xh = MAPSIZE;
}
if (yh>=MAPSIZE) {
yh = MAPSIZE;
}
do {
x = xl; /* Begin the X scan */
do {
tile = tilemap[y][x]; /* Actor here? */
if (tile&TI_ACTOR) {
ActorPtr = &actors[MapPtr->tilemap[y][x]]; /* Check for impact */
if ( (w_abs(ActorPtr->x - MissilePtr->x) < MISSILEHITDIST) &&
(w_abs(ActorPtr->y - MissilePtr->y) < MISSILEHITDIST)) {
Bang |= MissileHitEnemy(MissilePtr,ActorPtr); /* Detonate? */
}
}
} while (++x<xh); /* Scan the x's */
} while (++y<yh); /* Scan the y's */
return Bang; /* Return detonation value */
}
/**********************************
Move the missiles each game frame
**********************************/
void MoveMissiles(void)
{
Word Count; /* Current missile # */
missile_t *MissilePtr; /* Pointer to missile record */
Word i,x,y,tile; /* Tile position */
Count = nummissiles; /* How many active missiles? */
if (!Count || !TicCount) { /* No missiles? (Or elapsed time?) */
return; /* Exit now */
}
MissilePtr = &missiles[0]; /* Init pointer to the first missile */
do {
if (!MissilePtr->flags) { /* inert explosion*/
if (MissilePtr->type>TicCount) { /* Time up? */
MissilePtr->type-=TicCount; /* Remove some time */
++MissilePtr; /* Go to the next entry */
} else {
--nummissiles; /* Remove this missile */
MissilePtr[0] = missiles[nummissiles]; /* Copy the FINAL record here */
}
continue; /* Next! */
}
/* move position*/
i = TicCount; /* How many times to try this? */
do {
MissilePtr->x += MissilePtr->xspeed;
MissilePtr->y += MissilePtr->yspeed;
/* check for contact with player*/
if (MissilePtr->flags & MF_HITPLAYER) {
if (w_abs(MissilePtr->x - actors[0].x) < MISSILEHITDIST
&& w_abs(MissilePtr->y - actors[0].y) < MISSILEHITDIST) {
MissileHitPlayer(MissilePtr); /* Take damage */
goto BOOM; /* Boom! */
}
}
/* check for contact with actors*/
if (MissilePtr->flags & MF_HITENEMIES) {
if (CheckMissileActorHits(MissilePtr)) { /* Did it detonate? */
goto BOOM; /* Boom! */
}
}
/* check for contact with walls and get new area */
x = MissilePtr->x >> FRACBITS;
y = MissilePtr->y >> FRACBITS;
tile = tilemap[y][x];
if (tile & TI_BLOCKMOVE) { /* Can be a solid static or a wall*/
BOOM:
ExplodeMissile(MissilePtr); /* Detonate a missile */
break;
}
if (!(tile&TI_DOOR) ) { /* doorways don't have real area numbers*/
MissilePtr->areanumber = tile&TI_NUMMASK;
}
} while (--i);
++MissilePtr; /* Pointer to the next entry */
} while (--Count); /* No more entries? */
}
#include "Wolfdef.h"
/**********************************
Stop the current song from playing
**********************************/
void StopSong(void)
{
PlaySong(0);
}
/**********************************
Play a new song
**********************************/
void StartSong(Word songnum)
{
PlaySong(songnum); /* Stop the previous song (If any) */
}
#include "WolfDef.h"
#include <Palettes.h>
#include <gestalt.h>
#include "PickAMonitor.h"
#define PAMStrings 2001
#define NoColorString 1
#define NoDepthString 2
#define NoSizeString 3
#define NoProblemString 4
void CheckMonitor(DialogPtr theWindow, int bitDepth, Boolean colorRequired, short minWidth, short minHeight);
void OutlineOK(DialogPtr theDialog, Boolean enabled);
/**********************************
Take a window pointer and center it onto the
current video device
**********************************/
void CenterWindowOnMonitor(WindowPtr theWindow, GDHandle theMonitor)
{
short newH, newV;
Rect mRect;
mRect = (**theMonitor).gdRect; /* Get the rect of the monitor */
/* Find the difference between the two monitors' sizes */
newH = (mRect.right - mRect.left) - (theWindow->portRect.right - theWindow->portRect.left);
newV = (mRect.bottom - mRect.top) - (theWindow->portRect.bottom - theWindow->portRect.top);
/* Half the difference so that it's centered top-to-bottom and left-to-right */
/* Add that offset to the upper-left of the monitor */
MoveWindow(theWindow,(newH>>1)+mRect.left,(newV>>1)+mRect.top,TRUE); /* Move and bring to front */
}
/**********************************
Returns true if the device supports color
**********************************/
Boolean SupportsColor(GDHandle theMonitor)
{
return TestDeviceAttribute(theMonitor,gdDevType); /* Is it color? */
}
/**********************************
Returns true if the device supports a specific color depth
**********************************/
short SupportsDepth(GDHandle theMonitor, int theDepth, Boolean needsColor)
{
return HasDepth(theMonitor,theDepth,1<<gdDevType,needsColor);
}
/**********************************
Returns true if the device supports a specific video size
**********************************/
Boolean SupportsSize(GDHandle theMonitor, short theWidth, short theHeight)
{
Rect theRect;
/* Grab the dimensions of the monitor */
theRect = (**theMonitor).gdRect;
/* Offset it to (0, 0) references */
OffsetRect(&theRect, -theRect.left, -theRect.top);
/* Check the dimensions to see if they are large enough */
if ((theRect.right < theWidth) || (theRect.bottom < theHeight)) {
return FALSE; /* No good! */
}
return TRUE;
}
/**********************************
Return the GDevice from a specific quickdraw point
**********************************/
GDHandle MonitorFromPoint(Point *thePoint)
{
GDHandle theMonitor;
/* Loop through the list of monitors to see one encompasses the point */
theMonitor = GetDeviceList(); /* Get the first monitor */
do {
if (PtInRect(*thePoint,&(**theMonitor).gdRect)) { /* Is this it? */
break; /* Exit now */
}
theMonitor = GetNextDevice(theMonitor); /* Get the next device in list */
} while (theMonitor); /* All done now? */
/* Just in case some weird evil happened, return a fail value (THEORETICALLY can't happen) */
return theMonitor;
}
// ---------------------------------------- PickAMonitor
GDHandle PickAMonitor(int theDepth, Boolean colorRequired, short minWidth, short minHeight)
{
GDHandle theMonitor;
GDHandle tempMonitor;
Point thePoint;
EventRecord theEvent;
DialogPtr theDialog;
short itemHit;
char theChar;
Word validCount;
GrafPtr savedPort;
/* Loop through the monitor list once to make sure there is at least one good monitor */
theMonitor = GetDeviceList(); /* Get the first monitor */
tempMonitor = 0; /* No monitor found */
validCount = 0; /* None found */
do {
if (colorRequired && !SupportsColor(theMonitor)) { /* Check for color? */
continue;
}
if (!SupportsDepth(theMonitor, theDepth, colorRequired)) { /* Check for bit depth */
continue;
}
if (!SupportsSize(theMonitor, minWidth, minHeight)) { /* Check for monitor size */
continue;
}
tempMonitor = theMonitor; /* Save the valid record */
++validCount; /* Inc the count */
} while ((theMonitor = GetNextDevice(theMonitor)) != 0);
/* If there was only one valid monitor, goodMonitor will be referencing it. Return it immediately. */
if (validCount == 1) {
return (tempMonitor); /* Exit now */
}
/* If there are no valid monitors then put up a dialog saying so. Then return nil. */
if (!validCount) {
StopAlert(2001, nil);
return 0;
}
// Start an event loop going. Rather than using modalDialog with a gnarly filter, we'll just display the dialog
// then use a gnarly event loop to accommodate it. This will go on until the user selects either "This Monitor"
// (ok) or "Quit" (cancel).
theDialog = GetNewDialog(2000, nil, (WindowPtr) -1L);
CenterWindowOnMonitor((WindowPtr) theDialog, GetMainDevice());
InitCursor();
GetPort(&savedPort);
SetPort(theDialog);
ShowWindow(theDialog);
CheckMonitor(theDialog, theDepth, colorRequired, minWidth, minHeight);
do {
itemHit = 0;
/* Get next event from the event queue */
if (WaitNextEvent2(everyEvent&(~highLevelEventMask), &theEvent, 30, nil)) {
switch (theEvent.what) {
case keyDown:
theChar = theEvent.message & charCodeMask;
if ((theEvent.modifiers & cmdKey) && ((theChar == '.') || (theChar == 'q') || (theChar == 'Q'))) {
itemHit = cancel;
break;
}
if (theChar == 0x1B) {
itemHit = cancel;
break;
}
if ((theChar == 0x0D) || (theChar == 0x03)) {
itemHit = ok;
break;
}
break;
// Did we mouse-down in the dialogs drag-bar?
case mouseDown:
if (FindWindow(theEvent.where, (WindowPtr *) &theDialog) == inDrag)
{
DragWindow((WindowPtr) theDialog, theEvent.where, &qd.screenBits.bounds);
GetMouse(&thePoint);
LocalToGlobal(&thePoint);
tempMonitor = MonitorFromPoint(&thePoint);
CenterWindowOnMonitor((WindowPtr) theDialog, tempMonitor);
CheckMonitor(theDialog, theDepth, colorRequired, minWidth, minHeight);
break;
}
default:
// If not, perform regular dialog event processing
DialogSelect(&theEvent, &theDialog, &itemHit);
}
}
} while ((itemHit != ok) && (itemHit != cancel));
// Ok, the dialog is still the active grafport so all coordinates are in its local system. If I define a point
// as (0, 0) now it will be the upper left corner of the dialog's drawing area. I then turn this to a global screen
// coordinate and call GetMonitorFromPoint.
SetPt(&thePoint, 0, 0);
LocalToGlobal(&thePoint);
theMonitor = MonitorFromPoint(&thePoint);
// Restore our current graphics environment and return the monitor reference.
SetPort(savedPort);
DisposeDialog(theDialog);
if (itemHit == ok) {
return (theMonitor);
}
return (nil);
}
// ---------------------------------------- CheckMonitor
void CheckMonitor(DialogPtr theDialog, int bitDepth, Boolean colorRequired, short minWidth, short minHeight)
{
GDHandle theMonitor;
Point thePoint;
short theType;
Handle theHandle;
Rect theRect;
Str255 message;
Boolean badMonitor = FALSE;
GrafPtr savedPort;
GetPort(&savedPort);
SetPort((WindowPtr) theDialog);
SetPt(&thePoint, 0, 0);
LocalToGlobal(&thePoint);
theMonitor = MonitorFromPoint(&thePoint);
GetDialogItem(theDialog, 4, &theType, &theHandle, &theRect);
if (colorRequired && ! SupportsColor(theMonitor)) {
GetIndString(message, PAMStrings, NoColorString);
SetDialogItemText(theHandle, message);
badMonitor = TRUE;
}
if (!SupportsDepth(theMonitor, bitDepth, colorRequired)) {
GetIndString(message, PAMStrings, NoDepthString);
SetDialogItemText(theHandle, message);
badMonitor = TRUE;
}
if (! SupportsSize(theMonitor, minWidth, minHeight)) {
GetIndString(message, PAMStrings, NoDepthString);
SetDialogItemText(theHandle, message);
badMonitor = TRUE;
}
SetPort(savedPort);
if (badMonitor) {
// Gray-out the "This Monitor" button
GetDialogItem(theDialog, ok, &theType, &theHandle, &theRect);
HiliteControl((ControlHandle) theHandle, 255);
OutlineOK(theDialog, FALSE);
BeginUpdate((WindowPtr) theDialog);
UpdateDialog(theDialog, theDialog->visRgn);
EndUpdate((WindowPtr) theDialog);
return;
}
// Activate the "This Monitor" button and put up the no problem text.
GetIndString(message, PAMStrings, NoProblemString);
SetDialogItemText(theHandle, message);
GetDialogItem(theDialog, ok, &theType, &theHandle, &theRect);
HiliteControl((ControlHandle) theHandle, 0);
OutlineOK(theDialog, TRUE);
BeginUpdate((WindowPtr) theDialog);
UpdateDialog(theDialog, theDialog->visRgn);
EndUpdate((WindowPtr) theDialog);
}
// ---------------------------------------- OutlineOK
void OutlineOK(DialogPtr theDialog, Boolean enabled)
{
GrafPtr savedPort;
ColorSpec saveColor;
PenState savedState;
short theType;
Handle theHandle;
Rect theRect;
GetPenState(&savedState);
PenMode(patCopy);
PenSize(2, 2);
SaveFore(&saveColor);
ForeColor(blackColor);
GetPort(&savedPort);
SetPort((WindowPtr) theDialog);
GetDialogItem(theDialog, ok, &theType, &theHandle, &theRect);
InsetRect(&theRect, -4, -4);
if (enabled)
PenPat(&qd.black);
else
PenPat(&qd.gray);
FrameRoundRect(&theRect, 16, 16);
SetPort(savedPort);
RestoreFore(&saveColor);
SetPenState(&savedState);
}
extern void CenterWindowOnMonitor(WindowPtr theWindow, GDHandle theMonitor);
extern Boolean SupportsColor(GDHandle theMonitor);
extern short SupportsDepth(GDHandle theMonitor, int theDepth, Boolean needsColor);
extern Boolean SupportsSize(GDHandle theMonitor, short theWidth, short theHeight);
extern GDHandle MonitorFromPoint(Point *thePoint);
extern GDHandle PickAMonitor(int bitDepth, Boolean colorRequired, short minWidth, short minHeight);
extern Boolean WaitNextEvent2(short EventMask,EventRecord *theEvent,long sleep,RgnHandle mouseRgn);
\ No newline at end of file
#include "wolfdef.h"
/**********************************
See if players current position is ok
returns True if move ok
All coordinates are stored in 8.8 fractions (8 bits integer, 8 bits fraction)
**********************************/
static Boolean TryMove(Word Checkx,Word Checky)
{
actor_t *ActorPtr; /* Pointer to actor record */
Word xl,yl,xh,yh; /* Rect to scan */
Word tile; /* Tile being tested */
Word x,y; /* Working x,y */
xl = (Checkx - PLAYERSIZE)>>FRACBITS; /* Make the rect for the player in tiles */
xh = ((Checkx + PLAYERSIZE)>>FRACBITS)+1;
yl = (Checky - PLAYERSIZE)>>FRACBITS;
yh = ((Checky + PLAYERSIZE)>>FRACBITS)+1;
/* check for solid walls*/
y = yl;
do {
x=xl;
do {
tile = tilemap[y][x]; /* Test the tile */
if (tile & TI_GETABLE) { /* Can I get this? */
GetBonus(x,y); /* Get the item */
}
if (tile & TI_BLOCKMOVE) { /* Motion blocked */
return FALSE; /* Can't go this way! */
}
} while (++x<xh); /* Scan the x */
} while (++y<yh); /* Scan the y */
/* check for actors */
yl--; /* Increase the rect for actor hits */
yh++;
xl--;
xh++;
y = yl;
do {
x = xl;
do {
tile = tilemap[y][x]; /* Get the tile */
if (tile&TI_ACTOR) { /* Actor here? */
ActorPtr = &actors[MapPtr->tilemap[y][x]];
if (w_abs(ActorPtr->x - Checkx) < MINACTORDIST) {
if (w_abs(ActorPtr->y - Checky) < MINACTORDIST)
return FALSE; /* I hit the actor! */
}
}
} while (++x<xh); /* Scan the x */
} while (++y<yh); /* Scan the y */
playermoving = TRUE; /* I am moving (Harder to hit) */
return TRUE; /* Way is clear */
}
/**********************************
Clip the player's motion
I will also try to use as much motion as I have
**********************************/
static void ClipMove(int xmove,int ymove)
{
int Checkx,Checky;
/* Try complete move */
Checkx = xmove; /* Save the current motion offset */
Checky = ymove;
do {
if (TryMove(actors[0].x+Checkx,actors[0].y+Checky)) { /* Can I move here? */
actors[0].x += Checkx; /* Save it */
actors[0].y += Checky;
if (Checkx==xmove) { /* Use all the motion? */
return; /* Exit now! */
}
xmove-=Checkx; /* Remove the used motion */
ymove-=Checky;
break; /* Exit now */
}
if (Checkx==-1) { /* Minimum motion */
Checkx = 0;
}
Checkx>>=1; /* Reduce the amount of motion */
if (Checky==-1) { /* Minimum motion */
Checky=0;
}
Checky>>=1;
} while (Checkx || Checky); /* Is there ANY motion? */
/* Try horizontal motion */
Checkx = actors[0].x + xmove;
if (TryMove(Checkx,actors[0].y)) {
actors[0].x = Checkx; /* Set new x */
return;
}
/* try just vertical*/
Checky = actors[0].y + ymove;
if (TryMove(actors[0].x,Checky)) {
actors[0].y = Checky; /* Set new y */
}
}
/**********************************
Adds movement to xmove & ymove
**********************************/
static void Thrust(Word angle,Word speed,Word *xmove, Word *ymove)
{
angle &= ANGLES-1; /* Mask the angle range */
if (speed >= TILEGLOBAL) {
speed = TILEGLOBAL-1; /* Force maximum speed */
}
*xmove += FixedByFrac(speed,costable[angle]); /* Add x motion */
*ymove -= FixedByFrac(speed,sintable[angle]); /* Add y motion */
}
/**********************************
Changes the player's angle and position
**********************************/
#define TURNSPEED 4 /* Turning while moving */
#define FASTTURN 6 /* Turning in place */
#define WALKSPEED 25
#define RUNSPEED 45
void ControlMovement(void)
{
Word turn,total;
Word tile;
Word xmove,ymove;
Word move;
playermoving = FALSE; /* No motion (Yet) */
xmove = 0; /* Init my deltas */
ymove = 0;
if (buttonstate[bt_run]) {
turn = FASTTURN*TicCount; /* Really fast turn */
move = RUNSPEED*TicCount;
} else {
turn = TURNSPEED*TicCount; /* Moderate speed turn */
move = WALKSPEED*TicCount;
}
/* turning */
gamestate.viewangle += mouseturn; /* Add in the mouse movement verbatim */
if (buttonstate[bt_east]) {
gamestate.viewangle -= turn; /* Turn right */
}
if (buttonstate[bt_west]) {
gamestate.viewangle += turn; /* Turn left */
}
gamestate.viewangle &= (ANGLES-1); /* Fix the viewing angle */
/* Handle all strafe motion */
if (mousex) { /* Side to side motion (Strafe mode) */
mousex<<=3;
if (mousex>0) {
Thrust(gamestate.viewangle - ANGLES/4,mousex,&xmove,&ymove);
} else {
Thrust(gamestate.viewangle + ANGLES/4,-mousex,&xmove,&ymove);
}
}
if (buttonstate[bt_right]) { /* Slide right keyboard */
Thrust(gamestate.viewangle - ANGLES/4, move>>1,&xmove,&ymove);
}
if (buttonstate[bt_left]) { /* Slide left keyboard */
Thrust(gamestate.viewangle + ANGLES/4, move>>1,&xmove,&ymove);
}
/* Handle all forward motion */
total = buttonstate[bt_north] ? move : 0; /* Move ahead? */
if (mousey < 0) { /* Moved the mouse ahead? */
total -= mousey<<3; /* Add it in */
}
if (total) {
Thrust(gamestate.viewangle, total,&xmove,&ymove); /* Move ahead */
}
total = buttonstate[bt_south] ? move : 0; /* Reverse direction */
if (mousey > 0) {
total += mousey<<3;
}
if (total) {
Thrust(gamestate.viewangle+ANGLES/2, total,&xmove,&ymove);
}
mousex = 0;
mousey = 0; /* Reset the mouse motion */
mouseturn = 0;
if (xmove || ymove) { /* Any motion? */
ClipMove(xmove,ymove); /* Move ahead (Clipped) */
tile = tilemap[actors[0].y>>FRACBITS][actors[0].x>>FRACBITS];
if (!(tile&TI_DOOR) ) { /* Normal tile? */
actors[0].areanumber = tile & TI_NUMMASK; /* Set my new area */
}
}
}
#include "wolfdef.h"
/**********************************
Do damage to the player and show the killer
if you die.
**********************************/
void TakeDamage(Word points,Word x,Word y)
{
int angle;
if (gamestate.godmode) { /* Don't do anything else if a god */
return;
}
if (gamestate.health <= points) { /* Died? */
playstate = EX_DIED; /* Kill off the player */
gamestate.health = 0; /* No health */
killx = x; /* Mark the x,y of the killer */
killy = y;
} else {
PlaySound((w_rnd()&1)+SND_OUCH1); /* Ouch! */
gamestate.health -= points; /* Remove the hit points */
}
IO_DrawHealth(gamestate.health); /* Draw the health */
/* change face to look at attacker */
angle = PointToAngle(x,y) - (gamestate.viewangle<<SHORTTOANGLESHIFT);
if (angle > 0) {
if (angle > 0x2000) {
faceframe = 3;
} else {
faceframe = 1;
}
} else {
if (angle < -0x2000) {
faceframe = 2;
} else {
faceframe = 0;
}
}
if (gamestate.health <= 25) { /* Feel'n pretty bad? */
faceframe += 5; /* use beat up frames*/
}
IO_DrawFace(faceframe); /* Draw the face */
facecount = 120; /* Hold for 2 seconds */
}
/**********************************
Heal the player
**********************************/
void HealSelf(Word points)
{
gamestate.health += points; /* Add in the health */
if (gamestate.health>100) {
gamestate.health = 100; /* Maximum */
}
IO_DrawHealth(gamestate.health); /* Draw the health */
if (gamestate.health <= 25) { /* Feel'n good? */
faceframe = 5; /* Use beat up frames*/
} else {
faceframe = 0;
}
IO_DrawFace(faceframe); /* Redraw the face */
}
/**********************************
Award a free life
**********************************/
void GiveExtraMan(void)
{
if (gamestate.lives<10) { /* Too many already? */
++gamestate.lives; /* +1 life */
IO_DrawLives(gamestate.lives); /* Redraw the lives */
}
PlaySound(SND_EXTRA); /* Play a sound */
}
/**********************************
Award some score to the player and give
free lives if enough points have been accumulated
**********************************/
void GivePoints(LongWord points)
{
gamestate.score += points; /* Add to the score */
while (gamestate.score >= gamestate.nextextra) {
gamestate.nextextra += EXTRAPOINTS; /* New free man score */
GiveExtraMan(); /* Give a free man */
}
IO_DrawScore(gamestate.score); /* Draw the new score */
}
/**********************************
Award some score to the player and give
free lives if enough points have been accumulated
**********************************/
void GiveTreasure(void)
{
++gamestate.treasure; /* Add the value of the treasure */
while (gamestate.treasure >= 50) {
gamestate.treasure -= 50; /* Give a free man for 50 treasures */
GiveExtraMan();
}
IO_DrawTreasure(gamestate.treasure); /* Draw the treasure amount */
}
/**********************************
Award a new weapon, use it if better than what
the player already has.
**********************************/
void GiveWeapon(weapontype weapon)
{
if (gamestate.pendingweapon < weapon) { /* Better? */
gamestate.pendingweapon = weapon; /* Use it! */
}
}
/**********************************
Award some ammo, rearm weapon if knife was the current weapon
**********************************/
void GiveAmmo(Word ammo)
{
gamestate.ammo += ammo; /* Add the ammo */
if (gamestate.ammo > gamestate.maxammo) {
gamestate.ammo = gamestate.maxammo; /* Force maximum */
}
switch(gamestate.weapon) {
case WP_PISTOL:
case WP_MACHINEGUN:
case WP_CHAINGUN:
IO_DrawAmmo(gamestate.ammo); /* Draw the ammo */
break;
case WP_KNIFE: /* Was it the knife? */
if (gamestate.ammo == ammo) { /* Only equip if I had NO ammo */
gamestate.pendingweapon = WP_PISTOL;
if (gamestate.machinegun) {
gamestate.pendingweapon = WP_MACHINEGUN;
}
if (gamestate.chaingun) { /* Use the best weapon */
gamestate.pendingweapon = WP_CHAINGUN;
}
}
}
}
/**********************************
Award some gasoline, rearm flamethrower if knife was the current weapon
**********************************/
void GiveGas(Word ammo)
{
gamestate.gas += ammo; /* Add the gasoline */
if (gamestate.gas > 99) {
gamestate.gas = 99; /* Maximum gas */
}
if (gamestate.weapon == WP_FLAMETHROWER) { /* Flamethrower active? */
IO_DrawAmmo(gamestate.gas); /* Draw the gas */
}
}
/**********************************
Award some rockets, rearm missile launcher if knife was the current weapon
**********************************/
void GiveMissile(Word ammo)
{
gamestate.missiles += ammo; /* Add in the missiles */
if (gamestate.missiles > 99) {
gamestate.missiles = 99; /* Maximum missiles */
}
if (gamestate.weapon == WP_MISSILE) {
IO_DrawAmmo(gamestate.missiles); /* Draw the missile count */
}
}
/**********************************
Award a key
**********************************/
void GiveKey(Word key)
{
gamestate.keys |= (1<<key); /* Add in the key mask */
IO_DrawKeys(gamestate.keys); /* Draw the keys */
}
/**********************************
Play a sound for a bonus item
**********************************/
void BonusSound(void)
{
PlaySound(SND_BONUS);
}
/**********************************
Play a sound for getting a weapon
**********************************/
void WeaponSound(void)
{
PlaySound(SND_GETAMMO|0x8000);
}
/**********************************
Play a sound for getting more health
**********************************/
void HealthSound(void)
{
PlaySound(SND_HEAL|0x8000);
}
/**********************************
Play a sound for getting a key
**********************************/
void KeySound(void)
{
PlaySound(SND_GETKEY);
}
/**********************************
Picks up the bonus item at mapx,mapy. It is possible to
have multiple items in a single tile, and they may
not all get picked up (maxed out)
**********************************/
void GetBonus(Word x,Word y)
{
static_t *StaticPtr; /* Pointer to static item */
Word Count; /* Static count */
Word touched; /* Number of items touched */
Word got; /* Number of items taken */
Word Truex,Truey; /* x,y in pixels */
Count = numstatics;/* Init the count */
if (!Count) { /* No items at all? */
goto EndNow; /* Leave NOW! */
}
touched = 0; /* No items are marked */
got = 0; /* No items found */
StaticPtr = statics; /* Init the main index */
Truex=x<<FRACBITS; /* Convert x,y to pixel offsets */
Truey=y<<FRACBITS;
do {
if (((StaticPtr->x&0xff00) != Truex) || ((StaticPtr->y&0xff00) != Truey)) {
goto NextOne; /* Not a tile match, skip it */
}
++touched; /* Found one! */
++got; /* Assume I picked it up */
switch (StaticPtr->pic) { /* Do the proper action */
case S_HEALTH:
if (!gamestate.godmode && gamestate.health == 100) {
goto KillGot; /* No good */
}
HealthSound(); /* Add health */
HealSelf(25); /* 25 HP's better */
break;
case S_G_KEY:
case S_S_KEY:
GiveKey(StaticPtr->pic - S_G_KEY); /* Award the key */
KeySound(); /* Key sound */
break;
case S_CROSS:
case S_CHALICE:
case S_CHEST:
case S_CROWN:
BonusSound(); /* Goodie sound */
GiveTreasure(); /* Award treasure points */
++gamestate.treasurecount; /* +1 treasure found */
break;
case S_AMMO:
if (!gamestate.godmode && gamestate.ammo == gamestate.maxammo) { /* Ammo full? */
goto KillGot; /* Abort */
}
WeaponSound(); /* Tah dah! */
GiveAmmo(5); /* 5 bullets */
break;
case S_MISSILES:
if (!gamestate.godmode && gamestate.missiles == 99) { /* Missiles full? */
goto KillGot; /* Abort */
}
WeaponSound(); /* Get ammo sound */
GiveMissile(5); /* Award 5 missiles */
break;
case S_GASCAN:
if (!gamestate.godmode && gamestate.gas == 99) { /* Gas full? */
goto KillGot; /* Abort */
}
WeaponSound(); /* Get ammo sound */
GiveGas(14); /* 14 gallons of pure death */
break;
case S_AMMOCASE:
if (!gamestate.godmode && gamestate.ammo == gamestate.maxammo) { /* Ammo full */
goto KillGot; /* Abort */
}
WeaponSound(); /* Award the bonus */
GiveAmmo(25); /* Give 25 bullets */
break;
case S_MACHINEGUN:
if (!gamestate.godmode && gamestate.machinegun && gamestate.ammo == gamestate.maxammo) {
goto KillGot;
}
GiveAmmo(6); /* Award bullets */
if (!gamestate.machinegun) {
gamestate.machinegun = TRUE; /* Make it permanent */
GiveWeapon(WP_MACHINEGUN); /* Arm if better */
}
WeaponSound(); /* Got a gun! */
break;
case S_CHAINGUN:
GiveAmmo(20);
if (!gamestate.chaingun) {
gamestate.chaingun = TRUE; /* Make the gun permanent */
GiveWeapon(WP_CHAINGUN); /* Award the chain gun */
}
IAmSoHappy:
PlaySound(SND_THUMBSUP); /* Got a gun! */
IO_DrawFace(4); /* Make a happy face! */
facecount = 120; /* Hold for 2 seconds */
break;
case S_FLAMETHROWER:
if (!gamestate.flamethrower) {
gamestate.flamethrower = TRUE; /* Make flame thrower permanent */
GiveWeapon(WP_FLAMETHROWER); /* Award the flame thrower */
}
GiveGas(20); /* Start with 20 gallons */
goto IAmSoHappy; /* Yeah! */
case S_LAUNCHER:
if (!gamestate.missile) {
gamestate.missile = TRUE; /* Make missile launcher permanent */
GiveWeapon(WP_MISSILE); /* Award the missile launcher */
}
GiveMissile(5); /* Start with 5 missiles */
goto IAmSoHappy; /* He he he */
case S_ONEUP:
HealSelf(99); /* Fully heal */
GiveExtraMan(); /* Give a free man */
++gamestate.treasurecount; /* I got a treasure */
break;
case S_FOOD:
if (!gamestate.godmode && gamestate.health == 100) { /* Full health? */
goto KillGot; /* Don't get it */
}
HealthSound(); /* Feel's good! */
HealSelf(10); /* Add 10 points */
break;
case S_DOG_FOOD:
if (!gamestate.godmode && gamestate.health == 100) { /* Full health? */
goto KillGot; /* Abort */
}
PlaySound(SND_DOGBARK); /* Get a bonus */
HealSelf(4); /* Not much extra health */
break;
case S_BANDOLIER:
if (gamestate.maxammo < 299) { /* Maximum ammo */
gamestate.maxammo += 100; /* More ammo! */
}
WeaponSound(); /* Get a bonus */
GiveAmmo(20); /* Award ammo */
GiveGas(2);
GiveMissile(5);
break;
default:
touched--; /* Huh? */
goto KillGot; /* Can happen if a bonus item is dropped on a scenery pic */
}
/* remove the static object */
--numstatics; /* One less item */
StaticPtr[0] = statics[numstatics]; /* Copy the last item */
goto SkipInc; /* Process this entry again! */
KillGot:
--got; /* Invalidate the touch */
NextOne:
++StaticPtr; /* Next pointer */
SkipInc:;
} while (--Count);
if (touched == got) { /* All items taken? */
EndNow:
tilemap[y][x] &= ~TI_GETABLE; /* No more getable items */
}
}
#include "wolfdef.h"
#define SHOTRATE 6
/**********************************
Change my weapon to the biggest one I got
**********************************/
static void OutOfAmmo(void)
{
if (gamestate.missile && gamestate.missiles) {
gamestate.pendingweapon = WP_MISSILE;
return; /* Launcher & missiles */
}
if (gamestate.flamethrower && gamestate.gas) {
gamestate.pendingweapon = WP_FLAMETHROWER;
return; /* Flames and gas */
}
if (gamestate.ammo) {
if (gamestate.chaingun) {
gamestate.pendingweapon = WP_CHAINGUN;
return;
}
if (gamestate.machinegun) {
gamestate.pendingweapon = WP_MACHINEGUN;
return;
}
gamestate.pendingweapon = WP_PISTOL;
return;
}
gamestate.pendingweapon = WP_KNIFE;
}
/**********************************
Draw the ammo for the new weapon
**********************************/
void ChangeWeapon (void)
{
switch(gamestate.weapon) { /* Which weapon */
case WP_PISTOL:
case WP_MACHINEGUN:
case WP_CHAINGUN:
IO_DrawAmmo(gamestate.ammo); /* Draw bullets */
break;
case WP_FLAMETHROWER:
IO_DrawAmmo(gamestate.gas); /* Draw gasoline */
break;
case WP_MISSILE:
IO_DrawAmmo(gamestate.missiles); /* Draw missiles */
}
}
/**********************************
Fire my weapon, change to knife if no more ammo
**********************************/
void Cmd_Fire(void)
{
switch(gamestate.weapon) {
case WP_CHAINGUN:
case WP_MACHINEGUN:
case WP_PISTOL:
if (!gamestate.ammo) { /* Do I have ammo? */
OutOfAmmo(); /* Change the weapon */
}
break;
case WP_FLAMETHROWER:
if (!gamestate.gas) {
OutOfAmmo(); /* Change the weapon */
}
break;
case WP_MISSILE:
if (!gamestate.missiles) {
OutOfAmmo(); /* Change the weapon */
}
}
gamestate.attackframe = 1; /* Begin the attack */
gamestate.attackcount = SHOTRATE; /* Time before next action */
}
/**********************************
Try to use a switch, door or pushwall...
**********************************/
void Cmd_Use(void)
{
Word dir; /* Direction facing */
Word tile; /* Tile tested */
Word x,y; /* x,y of the tile to test */
/* Find which cardinal direction the player is facing */
x = actors[0].x >> FRACBITS; /* Get the x,y in tiles */
y = actors[0].y >> FRACBITS;
dir = ((gamestate.viewangle+ANGLES/8)&(ANGLES-1)) >> 7; /* Force into a cardinal direction */
switch (dir) {
case 0:
x++;
dir = CD_EAST; /* East */
break;
case 1:
y--;
dir = CD_NORTH; /* North */
break;
case 2:
x--;
dir = CD_WEST; /* West */
break;
case 3:
y++;
dir = CD_SOUTH; /* South */
}
tile = tilemap[y][x]; /* Get the tile data */
if (tile & TI_DOOR) { /* Is this a door? */
OperateDoor(tile&TI_NUMMASK); /* Door # to operate */
return;
}
if (!PushWallRec.pwallcount && (tile&TI_PUSHWALL)) { /* Push wall? */
PushWall(x,y,dir); /* Note: Only 1 pushwall at a time! */
return;
}
if (tile & TI_SWITCH) { /* Elevator switch? */
PlaySound(SND_THROWSWITCH|0x8000);
playstate = EX_COMPLETED;
return;
}
if (tile & TI_SECRET) { /* Secret level? */
PlaySound(SND_THROWSWITCH|0x8000);
playstate = EX_SECRET;
return;
}
if (tile & TI_BLOCKSIGHT) {
PlaySound(SND_HITWALL|0x8000); /* Oof! */
}
}
/**********************************
Change my weapon
**********************************/
void Cmd_ChangeWeapon(void)
{
for (;;) {
++gamestate.pendingweapon; /* Next weapon */
switch(gamestate.pendingweapon) {
case WP_PISTOL:
if (gamestate.ammo) { /* Do I have ammo ? */
return; /* Use it! */
}
break;
case WP_MACHINEGUN:
if (gamestate.machinegun && gamestate.ammo) {
return; /* Machine gun & ammo! */
}
break;
case WP_CHAINGUN:
if (gamestate.chaingun && gamestate.ammo) {
return; /* Chain gun & ammo! */
}
break;
case WP_FLAMETHROWER:
if (gamestate.flamethrower && gamestate.gas) {
return; /* Flames and gas */
}
break;
case WP_MISSILE:
if (gamestate.missile && gamestate.missiles) {
return; /* Launcher & missiles */
}
break;
default:
gamestate.pendingweapon = WP_KNIFE; /* Force as the knife */
return;
}
}
}
/**********************************
Sets actor to the closest enemy in the line of fire, or 0
if there is no valid target
**********************************/
actor_t *TargetEnemy (void)
{
Word *xe;
Word i;
vissprite_t *dseg;
actor_t *ActorPtr;
/* look at the drawn sprites from closest to farthest*/
i = numvisspr;
if (i) { /* Any drawn? */
xe = &firstevent[i-1]; /* Index to the CLOSEST sprite */
do {
dseg = &vissprites[xe[0]&(MAXVISSPRITES-1)];
if (dseg->actornum) { /* static sprite or missile */
if (xscale[CENTERX] <= dseg->clipscale) { /* Not obscured by a wall*/
if (dseg->x1 <= CENTERX+8 && dseg->x2 >= CENTERX-8) {
ActorPtr = &actors[dseg->actornum]; /* Get pointer to the actor */
if (!(ActorPtr->flags & FL_DEAD)) { /* Dead already? */
return ActorPtr; /* Shoot me! */
}
}
}
}
--xe;
} while (--i);
}
return 0; /* No actor in range */
}
/**********************************
Attack with a knife
**********************************/
void KnifeAttack(void)
{
actor_t *ActorPtr;
ActorPtr = TargetEnemy(); /* Who to hit? */
if (ActorPtr) { /* Got someone? */
if (CalcDistance(ActorPtr) <= KNIFEDIST) { /* In range? */
DamageActor(w_rnd()&15,ActorPtr); /* Hit him! */
PlaySound(SND_KNIFE|0x8000);
return;
}
}
PlaySound(SND_KNIFEMISS|0x8000); /* Swish the knife */
}
/**********************************
Attack with a pistol, machine gun, chain gun
**********************************/
void GunAttack(void)
{
Word Damage;
actor_t *ActorPtr;
if (gamestate.weapon == WP_CHAINGUN ) {
Damage = SND_CHAIN|0x8000; /* Bang! */
} else if (gamestate.weapon == WP_MACHINEGUN) {
Damage = SND_MGUN|0x8000;
} else {
Damage = SND_GUNSHT|0x8000;
}
PlaySound(Damage); /* Play the gun shot sound */
madenoise = TRUE; /* I made some noise */
if (!gamestate.godmode) {
--gamestate.ammo; /* Remove a bullet */
}
IO_DrawAmmo(gamestate.ammo); /* Redraw the ammo */
ActorPtr = TargetEnemy(); /* Anyone to hit? */
if (ActorPtr) { /* Found one? */
if (CalcDistance(ActorPtr) < 2*TILEGLOBAL) { /* Close range? */
Damage = w_rnd()&15; /* More damage */
} else {
Damage = w_rnd()&7;
}
DamageActor(Damage,ActorPtr); /* Shoot! */
}
}
/**********************************
Attack with a flame thrower
**********************************/
void FlameAttack(void)
{
int x; /* Sine,cos value */
missile_t *MissilePtr; /* Pointer to new missile record */
madenoise = TRUE;
PlaySound(SND_FTHROW|0x8000); /* Burn! */
if (!gamestate.godmode) {
--gamestate.gas; /* Use a gallon of gas */
}
IO_DrawAmmo(gamestate.gas); /* Draw the gas value */
/* flame sprite*/
MissilePtr = GetNewMissile(); /* Get a missile record */
MissilePtr->areanumber = actors[0].areanumber; /* Start where I am */
x = costable[gamestate.viewangle]; /* Set the x velocity */
MissilePtr->xspeed = x/5; /* Set the speed */
MissilePtr->x = (x/4) + actors[0].x;
x = -sintable[gamestate.viewangle]; /* Set the y velocity */
MissilePtr->yspeed = x/5; /* Set the speed */
MissilePtr->y = (x/4) + actors[0].y;
MissilePtr->pic = S_FIREBALL; /* Use the fireball pic */
MissilePtr->flags = MF_HITENEMIES | MF_HITSTATICS;
MissilePtr->type = MI_PFLAME;
}
/**********************************
Attack with a missile
**********************************/
void MissileAttack(void)
{
int x; /* Sine,Cos value */
missile_t *MissilePtr; /* Pointer to new missile record */
PlaySound(SND_ROCKET|0x8000); /* Fire! */
madenoise = TRUE; /* Made a racket */
if (!gamestate.godmode) {
--gamestate.missiles;
}
IO_DrawAmmo(gamestate.missiles); /* Draw the missile count */
MissilePtr = GetNewMissile(); /* missile sprite */
MissilePtr->areanumber = actors[0].areanumber;
x = costable[gamestate.viewangle];
MissilePtr->x = (x/4) + actors[0].x; /* Must be visible for screen! */
MissilePtr->xspeed = (x/5);
x = -sintable[gamestate.viewangle];
MissilePtr->y = (x/4) + actors[0].y;
MissilePtr->yspeed = (x/5);
MissilePtr->pic = S_MISSILE;
MissilePtr->flags = MF_HITENEMIES | MF_HITSTATICS;
MissilePtr->type = MI_PMISSILE;
}
/**********************************
Move the player (Called every tic)
**********************************/
void MovePlayer(void)
{
ControlMovement(); /* Read the controller */
/* check for use*/
if (buttonstate[bt_use]) { /* Pressed use? */
if (!useheld) {
useheld = TRUE; /* Only once... */
Cmd_Use();
}
} else {
useheld = FALSE; /* It's released */
}
/* check for weapon select */
if (buttonstate[bt_select]) {
if (!selectheld) {
selectheld = TRUE; /* Only once */
Cmd_ChangeWeapon(); /* Change the weapon */
}
} else {
selectheld = FALSE; /* It's released */
}
/* check for starting an attack */
if (buttonstate[bt_attack]) {
if (!attackheld && !gamestate.attackframe) {
attackheld = TRUE; /* Held down */
Cmd_Fire(); /* Initiate firing my weapon */
}
} else {
attackheld = FALSE; /* It's released */
}
/* advance attacking action */
if (!gamestate.attackframe) { /* Not in the middle of firing the weapon? */
if (gamestate.pendingweapon != gamestate.weapon) { /* New weapon? */
gamestate.weapon = gamestate.pendingweapon; /* Set the weapon */
ChangeWeapon(); /* Redraw the ammo */
}
return; /* Exit now */
}
/* I am in an attack, time yet? */
if (gamestate.attackcount>TicCount) { /* Wait to attack! */
gamestate.attackcount-=TicCount; /* Wait a bit */
return;
}
/* change frame */
if (TicCount<SHOTRATE) {
gamestate.attackcount += (SHOTRATE-TicCount); /* Carry over the time */
}
++gamestate.attackframe; /* Next animation frame */
/* frame 2: attack frame */
if (gamestate.attackframe == 2) {
switch (gamestate.weapon) {
case WP_KNIFE:
KnifeAttack(); /* Knife 'em */
break;
case WP_PISTOL:
if (!gamestate.ammo) {
gamestate.attackframe = 4;
return;
}
GunAttack(); /* One shot */
break;
case WP_MACHINEGUN:
if (!gamestate.ammo) {
gamestate.attackframe = 4;
return;
}
GunAttack(); /* First shot */
break;
case WP_CHAINGUN:
if (!gamestate.ammo) {
gamestate.attackframe = 4;
return;
}
GunAttack(); /* First of many shots */
break;
case WP_FLAMETHROWER:
if (!gamestate.gas) {
gamestate.attackframe = 4;
return;
}
FlameAttack(); /* Shoot a flame */
break;
case WP_MISSILE:
if (!gamestate.missiles) {
gamestate.attackframe = 4;
return;
}
MissileAttack(); /* Shoot the missile */
}
}
/* frame 3: second shot for chaingun and flamethrower */
if (gamestate.attackframe == 3) {
if (gamestate.weapon == WP_CHAINGUN ) {
if (!gamestate.ammo) {
++gamestate.attackframe;
} else {
GunAttack(); /* Shoot! */
}
} else if (gamestate.weapon == WP_FLAMETHROWER ) {
if (!gamestate.gas) {
++gamestate.attackframe;
} else {
FlameAttack(); /* Flame on! */
}
}
return;
}
/* frame 4: possible auto fire */
if (gamestate.attackframe == 4) {
if (buttonstate[bt_attack]) { /* Held down? */
if ( (gamestate.weapon == WP_MACHINEGUN
|| gamestate.weapon == WP_CHAINGUN) && gamestate.ammo) {
gamestate.attackframe = 2; /* Fire again */
GunAttack(); /* Shoot */
}
if (gamestate.weapon == WP_FLAMETHROWER && gamestate.gas) {
gamestate.attackframe=2;
FlameAttack(); /* Flame again */
}
}
return;
}
if (gamestate.attackframe == 5) { /* End the attack */
switch (gamestate.weapon) {
case WP_CHAINGUN:
case WP_MACHINEGUN:
case WP_PISTOL:
if (!gamestate.ammo) {
OutOfAmmo(); /* Switch weapons */
} else if (gamestate.weapon == WP_PISTOL && buttonstate[bt_attack]
&& !attackheld) {
attackheld = TRUE;
gamestate.attackframe = 1; /* Fire again the pistol */
return;
}
break;
case WP_FLAMETHROWER:
if (!gamestate.gas) { /* Out of gas? */
OutOfAmmo(); /* Change weapons */
}
break;
case WP_MISSILE:
if (!gamestate.missiles) { /* Out of missiles? */
OutOfAmmo(); /* Switch weapons */
}
}
gamestate.attackcount = 0; /* Shut down the attack */
gamestate.attackframe = 0;
}
}
void InitPrefsFile(OSType creator,Byte *PrefsName);
OSErr LoadPrefsFile(Byte *PrefsPtr,Word PrefsLen);
OSErr SavePrefsFile(Byte *PrefsPtr,Word PrefsLen);
#include <Folders.h>
#include <Gestalt.h>
#include <Processes.h>
#include "Wolfdef.h"
#include <String.h>
#include "prefs.h"
typedef struct {
Byte fileName[34]; /* Enough space for filename */
OSType creator; /* Creator TYPE */
OSType fileType; /* File type */
OSType resType; /* Resource type */
short resID; /* Open resource file ID */
} PrefsInfo;
static PrefsInfo prefsInfo; /* My internal prefs record */
static Boolean prefsInited = FALSE; /* Is the struct valid? */
/**********************************
I miss the Apple IIgs where all you need to set the prefs directory
was to pass a filename of "@:Prefs file" and it will automatically place
the prefs file in either the proper Network folder or system prefs folder...
Instead I have to do this bullshit to scan the volumes to find the prefs
folder and volume...
If the file was not found, then create it.
return TRUE if the file was found and could not be created
**********************************/
static Boolean FindPrefsFile(short *prefVRefNum, long *prefDirID)
{
OSErr theErr;
long response;
CInfoPBRec infoPB;
if (!prefsInited) { /* Only look if the prefs structure is valid */
return FALSE; /* Exit NOW! */
}
/* First, try it the easy way... */
if ( !Gestalt(gestaltFindFolderAttr, &response) && /* Is the easy way available? */
( (1<<gestaltFindFolderPresent) & response)) {
/* Call the OS to do the dirty work */
theErr = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
prefVRefNum, prefDirID);
/* OK, try it the hard way... :( */
} else {
SysEnvRec theSysEnv;
StringPtr prefFolderName = "\pPreferences";
/* yeachh -- we have to do it all by hand! */
if (SysEnvirons(1, &theSysEnv)) { /* Is the system disk present? */
return FALSE; /* Forget it! */
}
*prefVRefNum = theSysEnv.sysVRefNum; /* Save off the boot volume ID */
/* check whether Preferences folder already exists */
infoPB.hFileInfo.ioCompletion = 0; /* Wait for completion */
infoPB.hFileInfo.ioNamePtr = prefFolderName; /* Get folder name */
infoPB.hFileInfo.ioVRefNum = *prefVRefNum; /* Pass the volume # */
infoPB.hFileInfo.ioFDirIndex = 0; /* Scan directories */
infoPB.hFileInfo.ioDirID = 0; /* Init dir id */
theErr = PBGetCatInfo(&infoPB, FALSE); /* Get the catalog info */
if (!theErr) {
*prefDirID = infoPB.hFileInfo.ioDirID; /* Return the folder id */
} else if (theErr == fnfErr) { /* Preferences doesn't already exist */
HParamBlockRec dirPB;
/* create "Preferences" folder */
dirPB.fileParam.ioCompletion = 0;
dirPB.fileParam.ioVRefNum = *prefVRefNum;
dirPB.fileParam.ioNamePtr = prefFolderName;
dirPB.fileParam.ioDirID = 0;
theErr = PBDirCreate(&dirPB, FALSE); /* Create the folder */
if (!theErr) {
*prefDirID = dirPB.fileParam.ioDirID; /* Save the ID */
}
}
}
/* if we make it here OK, create Preferences file if necessary */
if (!theErr) {
infoPB.hFileInfo.ioCompletion = 0;
infoPB.hFileInfo.ioNamePtr = prefsInfo.fileName;
infoPB.hFileInfo.ioVRefNum = *prefVRefNum;
infoPB.hFileInfo.ioFDirIndex = 0;
infoPB.hFileInfo.ioDirID = *prefDirID;
theErr = PBGetCatInfo(&infoPB, FALSE); /* Get the file info */
if (theErr == fnfErr) { /* Not present? */
theErr = HCreate(*prefVRefNum, *prefDirID, prefsInfo.fileName,
prefsInfo.creator, prefsInfo.fileType);
if (!theErr) {
HCreateResFile(*prefVRefNum, *prefDirID, prefsInfo.fileName);
theErr = ResError(); /* Was there an error? */
}
}
}
return (!theErr);
}
/**********************************
Init the record for the "Prefs" file
All this does is preset the prefsfile structure
for the filename of the prefs file.
**********************************/
void InitPrefsFile(OSType creator,Byte *PrefsName)
{
Word FLen;
FLen = strlen((char *)PrefsName); /* How long is the string? */
prefsInfo.fileName[0] = FLen; /* Make a PASCAL string */
BlockMove(PrefsName,&prefsInfo.fileName[1],FLen); /* Copy the bulk */
prefsInfo.creator = creator; /* 4 Letter creator filetype */
prefsInfo.fileType = 'PREF'; /* Pref's filetype */
prefsInfo.resType = 'PREF'; /* Pref's resource */
prefsInfo.resID = 0; /* No resource ID assigned yet */
prefsInited = TRUE; /* All numbers are set... */
}
/**********************************
Load in a prefs file and store it
into a passed pointer IF the file was
loaded properly.
Return any error codes.
**********************************/
OSErr LoadPrefsFile(Byte *PrefsPtr,Word PrefsLen)
{
short prefVRefNum, prefRefNum;
long prefDirID;
Handle origHdl;
LongWord origSize;
if (!FindPrefsFile(&prefVRefNum, &prefDirID)) { /* Search for the file */
return fnfErr; /* File was NOT found error */
}
prefRefNum = HOpenResFile(prefVRefNum, prefDirID, prefsInfo.fileName, fsRdWrPerm);
if (prefRefNum == -1) { /* Resource error? */
return ResError(); /* Return the resource manager error */
}
/* Not finding the resource is not an error -- caller will use default data */
origHdl = Get1Resource(prefsInfo.resType, prefsInfo.resID);
if (origHdl) { /* Valid handle? */
origSize = GetHandleSize(origHdl); /* How much data is here? */
if (origSize < PrefsLen) { /* Less data than expected? */
PrefsLen = origSize; /* Use the smaller size */
}
BlockMove(*origHdl,PrefsPtr,PrefsLen); /* Copy the NEW prefs data */
ReleaseResource(origHdl); /* Release the data */
}
CloseResFile(prefRefNum); /* Close the resource file */
return ResError(); /* Return any errors */
}
/**********************************
Save data for a new prefs file
**********************************/
OSErr SavePrefsFile(Byte *PrefsPtr,Word PrefsLen)
{
short prefVRefNum, prefRefNum;
long prefDirID;
Handle origHdl;
LongWord origSize;
OSErr theErr = noErr;
if (!FindPrefsFile(&prefVRefNum, &prefDirID)) { /* File not present? */
return fnfErr; /* File not found error */
}
prefRefNum = HOpenResFile(prefVRefNum, prefDirID, prefsInfo.fileName, fsRdWrPerm);
if (prefRefNum == -1) { /* Bad resource fork? */
return ResError(); /* Return the error */
}
origHdl = Get1Resource(prefsInfo.resType, prefsInfo.resID); /* Get the resource */
if (origHdl) { /* Overwrite the existing resource */
origSize = GetHandleSize(origHdl); /* How large is it? */
if (PrefsLen != origSize) { /* Different size? */
SetHandleSize(origHdl, PrefsLen); /* Set the new size */
}
BlockMove(PrefsPtr,*origHdl,PrefsLen); /* Copy the data */
ChangedResource(origHdl); /* Mark as changed */
WriteResource(origHdl); /* Save to disk */
ReleaseResource(origHdl); /* Release it */
} else {
/* store specified preferences for the first time */
origHdl = NewHandle(PrefsLen); /* Make some temp memory */
if (origHdl) {
BlockMove(PrefsPtr,*origHdl,PrefsLen);
AddResource(origHdl, prefsInfo.resType, prefsInfo.resID, "\p");
WriteResource(origHdl); /* Write to disk */
ReleaseResource(origHdl); /* Release it */
}
}
CloseResFile(prefRefNum); /* Close the resource file */
if (!theErr) { /* No errors? */
return ResError(); /* Return any resource error */
}
return theErr; /* Return the last error */
}
#include "wolfdef.h"
#define PWALLSPEED 4 /* Micropixels per 60th of a second */
pushwall_t PushWallRec; /* Record for the single pushwall in progress */
/**********************************
Set pwallychange and pwallxchange
Uses pwallpos,pwalldir
**********************************/
void SetPWallChange(void)
{
Word pos;
pos = PushWallRec.pwallpos&(FRACUNIT-1); /* Get the pixel fraction */
PushWallRec.pwallxchange = 0; /* No motion yet */
PushWallRec.pwallychange = 0;
switch (PushWallRec.pwalldir) { /* Which way? */
case CD_NORTH:
PushWallRec.pwallychange = -pos; /* Y motion */
return;
case CD_EAST:
PushWallRec.pwallxchange = pos; /* X motion */
return;
case CD_SOUTH:
PushWallRec.pwallychange = pos; /* Y motion */
return;
case CD_WEST:
PushWallRec.pwallxchange = -pos; /* X motion */
}
}
/**********************************
Marks the dest tile as blocked and begins a push wall sequence
Uses pwallx,pwally,pwalldir
**********************************/
void PushWallOne(void)
{
PushWallRec.pwallcheckx = PushWallRec.pwallx;
PushWallRec.pwallchecky = PushWallRec.pwally;
switch (PushWallRec.pwalldir) {
case CD_NORTH:
PushWallRec.pwallchecky--;
break;
case CD_EAST:
PushWallRec.pwallcheckx++;
break;
case CD_SOUTH:
PushWallRec.pwallchecky++;
break;
case CD_WEST:
PushWallRec.pwallcheckx--;
}
tilemap[PushWallRec.pwallchecky][PushWallRec.pwallcheckx] |= TI_BLOCKMOVE | TI_BLOCKSIGHT;
StartPushWall(); /* let the refresh do some junk*/
}
/**********************************
Initiate a pushwall sequence
Call with x,y,dir of wall to push
**********************************/
void PushWall(Word x,Word y,Word dir)
{
PlaySound(SND_PWALL); /* Play the wall sound */
PushWallRec.pwallx = x; /* Save the x,y in my globals */
PushWallRec.pwally = y;
PushWallRec.pwalldir = dir; /* Save the wall direction */
PushWallOne(); /* Initiate the animation */
PushWallRec.pwallcount = 2; /* Move two cells */
++gamestate.secretcount; /* Secret area found */
PushWallRec.pwallpos = PWALLSPEED/2; /* Begin the move */
/* mark the segs that are being moved */
tilemap[y][x] &= ~TI_PUSHWALL; /* Clear the pushwall bit */
SetPWallChange(); /* Set pwallchange */
}
/**********************************
Continue any pushwall animations, called by the main loop
**********************************/
void MovePWalls (void)
{
if (!PushWallRec.pwallcount) { /* Any walls to push? */
return; /* Nope, get out */
}
PushWallRec.pwallpos += PWALLSPEED*TicCount; /* Move the wall a little */
SetPWallChange(); /* Set the wall for the renderer */
if (PushWallRec.pwallpos<256) { /* Crossed a tile yet? */
return; /* Exit now */
}
PushWallRec.pwallpos -= 256; /* Mark as crossed */
/* the tile can now be walked into */
tilemap[PushWallRec.pwally][PushWallRec.pwallx] &= ~TI_BLOCKMOVE; /* The movable block is gone */
AdvancePushWall(); /* Remove the bsp seg */
if (!--PushWallRec.pwallcount) { /* Been pushed 2 blocks?*/
StopSound(SND_PWALL); /* Play the wall sound */
PlaySound(SND_PWALL2); /* Play the wall stop sound */
return; /* Don't do this anymore! */
}
PushWallRec.pwallx = PushWallRec.pwallcheckx; /* Set the tile to the next cell */
PushWallRec.pwally = PushWallRec.pwallchecky;
PushWallOne(); /* Push one more record */
}
#include "WolfDef.h"
static Word checkcoord[11][4] = { /* Indexs to the bspcoord table */
{3,0,2,1},
{3,0,2,0},
{3,1,2,0},
{0,0,0,0},
{2,0,2,1},
{0,0,0,0}, /* Not valid */
{3,1,3,0},
{0,0,0,0},
{2,0,3,1},
{2,1,3,1},
{2,1,3,0}};
/**********************************
Draw a 3-D textured polygon, must be done FAST!
**********************************/
void RenderWallLoop(Word x1,Word x2,Word distance)
{
fixed_t texturecolumn;
Word tile,scaler, angle;
/* calculate and draw each column */
if (rw_downside) {
while (x1 < x2) { /* Time to draw? */
scaler = rw_scale >> FRACBITS; /* Get the draw scale */
xscale[x1] = scaler; /* Save the scale factor */
angle = xtoviewangle[x1]+rw_centerangle;
texturecolumn = rw_midpoint - SUFixedMul(finetangent[angle],distance); /* Which texture to use? */
if ((Word)texturecolumn < rw_mintex) {
texturecolumn = rw_mintex;
} else if ((Word)texturecolumn >= rw_maxtex) {
texturecolumn = rw_maxtex-1;
}
tile = rw_texture[texturecolumn>>8]; /* Get the tile to use */
IO_ScaleWallColumn(x1,scaler,tile,(texturecolumn>>1)&127); /* Draw the line */
++x1; /* Next x */
rw_scale+=rw_scalestep; /* Step the scale factor for the wall */
}
return;
}
while (x1 < x2) { /* Time to draw? */
scaler = rw_scale >> FRACBITS; /* Get the draw scale */
xscale[x1] = scaler; /* Save the scale factor */
angle = xtoviewangle[x1]+rw_centerangle;
texturecolumn = SUFixedMul(finetangent[angle],distance)+rw_midpoint; /* Which texture to use? */
if ((Word)texturecolumn < rw_mintex) {
texturecolumn = rw_mintex;
} else if ((Word)texturecolumn >= rw_maxtex) {
texturecolumn = rw_maxtex-1;
}
tile = rw_texture[texturecolumn>>8]; /* Get the tile to use */
if (!(WallListPtr[tile+1] & 0x4000)) {
texturecolumn^=0xff; /* Reverse the tile for N,W walls */
}
IO_ScaleWallColumn(x1,scaler,tile,(texturecolumn>>1)&127); /* Draw the line */
++x1; /* Next x */
rw_scale+=rw_scalestep; /* Step the scale factor for the wall */
}
}
/*
=====================
=
= RenderWallRange
=
= Draw a wall segment between start and stop angles (inclusive) (short angles)
= No clipping is needed
=
======================
*/
void RenderWallRange (Word start,Word stop,saveseg_t *seg,Word distance)
{
LongWord scale2;
Word vangle;
Word x1,x2;
/* mark the segment as visible for auto map*/
seg->dir |= DIR_SEENFLAG; /* for automap*/
areavis[seg->area] = 1; /* for sprite drawing*/
start -= ANGLE180; /* Adjust the start angle */
stop -= ANGLE180; /* Adjust the stop angle */
vangle = (Word)(start+ANGLE90)>>ANGLETOFINESHIFT;
x1 = viewangletox[vangle];
vangle = (Word)(stop+ANGLE90-1)>>ANGLETOFINESHIFT; /* make non inclusive*/
x2 = viewangletox[vangle];
if (x2 == x1) {
return; /* less than one column wide*/
}
rw_scale = (long) ScaleFromGlobalAngle(start+centershort,distance)<<FRACBITS;
if (x2>x1+1) {
scale2 = (long) ScaleFromGlobalAngle(stop+centershort,distance)<<FRACBITS;
rw_scalestep = (long)(scale2-rw_scale)/(long)(x2-x1);
}
RenderWallLoop(x1,x2,distance);
}
/*
===============================================================================
=
= ClipWallSegment
=
= Clips the given screenpost and includes it in newcolumn
===============================================================================
*/
/* a screenpost_t is a solid range of visangles, used to clip and detect*/
/* span exposures / hidings*/
typedef struct {
Word top, bottom;
} screenpost_t;
#define MAXSEGS 16
screenpost_t solidsegs[MAXSEGS], *newend; /* newend is one past the last valid seg */
void ClipWallSegment(Word top,Word bottom,saveseg_t *seg,Word distance)
{
screenpost_t *next, *start;
/* find the first clippost that touches the source post (adjacent pixels are touching)*/
start = solidsegs;
while (start->bottom > top+1) {
start++;
}
if (top > start->top) {
if (bottom > start->top+1) { /* post is entirely visible (above start), so insert a new clippost*/
RenderWallRange(top, bottom,seg,distance);
next = newend;
newend++;
while (next != start) {
*next = *(next-1);
next--;
}
next->top = top;
next->bottom = bottom;
return;
}
/* there is a fragment above *start*/
RenderWallRange (top, start->top + 1,seg,distance);
start->top = top; /* adjust the clip size*/
}
if (bottom >= start->bottom)
return; /* bottom contained in start*/
next = start;
while (bottom <= (next+1)->top+1) {
/* there is a fragment between two posts*/
RenderWallRange (next->bottom - 1, (next+1)->top + 1,seg,distance);
next++;
if (bottom >= next->bottom) { /* bottom is contained in next*/
start->bottom = next->bottom; /* adjust the clip size*/
goto crunch;
}
}
/* there is a fragment after *next*/
RenderWallRange (next->bottom - 1, bottom,seg,distance);
start->bottom = bottom; /* adjust the clip size*/
/* remove start+1 to next from the clip list, because start now covers their area*/
crunch:
if (next == start) {
return; /* post just extended past the bottom of one post*/
}
while (next++ != newend) /* remove a post*/
*++start = *next;
newend = start+1;
}
/**********************************
Clear out the edge segments for the ray cast
(Assume full viewing angle)
**********************************/
void ClearClipSegs(void)
{
solidsegs[0].top = -1; /* Maximum angle */
solidsegs[0].bottom = ANGLE180 + clipshortangle; /* First edge */
solidsegs[1].top = ANGLE180 - clipshortangle; /* Left edge */
solidsegs[1].bottom = 0; /* Minimum angle */
newend = solidsegs+2;
}
/**********************************
Clip and draw a given wall segment
**********************************/
void P_DrawSeg (saveseg_t *seg)
{
Word segplane;
Word door;
door_t *door_p;
unsigned short span, tspan;
unsigned short angle1, angle2;
int texslide;
int distance;
if (seg->dir & DIR_DISABLEDFLAG) { /* Segment shut down? */
return; /* pushwall part*/
}
segplane = (Word)seg->plane << 7;
rw_mintex = (Word)seg->min << 7;
rw_maxtex = (Word)seg->max << 7;
/* adjust pushwall segs */
if (seg == pwallseg) { /* Is this the active pushwall? */
if (seg->dir&1) { /* east/west*/
segplane += PushWallRec.pwallychange;
} else { /* north/south*/
segplane += PushWallRec.pwallxchange;
}
}
/* get texture*/
if (seg->texture >= 129) { /* segment is a door */
door = seg->texture - 129; /* Which door is this? */
door_p = &doors[door];
rw_texture = &textures[129 + (door_p->info>>1)][0];
texslide = door_p->position;
rw_mintex += texslide;
} else {
texslide = 0;
rw_texture = &textures[seg->texture][0];
}
switch (seg->dir&3) { /* mask off the flags*/
case di_north:
distance = viewx - segplane;
if (distance <= 0) {
return; /* back side*/
}
rw_downside = FALSE;
rw_midpoint = viewy;
normalangle = 2*FINEANGLES/4;
angle1 = PointToAngle(segplane,rw_maxtex);
angle2 = PointToAngle(segplane,rw_mintex);
break;
case di_south:
distance = segplane - viewx;
if (distance <= 0) {
return; /* back side*/
}
rw_downside = TRUE;
rw_midpoint = viewy;
normalangle = 0*FINEANGLES/4;
angle1 = PointToAngle(segplane,rw_mintex);
angle2 = PointToAngle(segplane,rw_maxtex);
break;
case di_east:
distance = viewy - segplane;
if (distance <= 0) {
return; /* back side*/
}
rw_downside = TRUE;
rw_midpoint = viewx;
normalangle = 1*FINEANGLES/4;
angle1 = PointToAngle(rw_mintex,segplane);
angle2 = PointToAngle(rw_maxtex,segplane);
break;
case di_west:
distance = segplane - viewy;
if (distance <= 0) {
return; /* back side*/
}
rw_downside = FALSE;
rw_midpoint = viewx;
normalangle = 3*FINEANGLES/4;
angle1 = PointToAngle(rw_maxtex,segplane);
angle2 = PointToAngle(rw_mintex,segplane);
break;
}
/* clip to view edges*/
span = angle1 - angle2;
if (span >= 0x8000) { /* Test for negative (32 bit clean) */
return;
}
angle1 -= centershort;
angle2 -= centershort;
++angle2; /* make angle 2 non inclusive*/
tspan = angle1 + clipshortangle;
if (tspan > clipshortangle2) {
tspan -= clipshortangle2;
if (tspan >= span) {
return; /* totally off the left edge*/
}
angle1 = clipshortangle;
}
tspan = clipshortangle - angle2;
if (tspan > clipshortangle2) {
tspan -= clipshortangle2;
if (tspan >= span) {
return; /* totally off the left edge*/
}
angle2 = -clipshortangle;
}
/* calc center angle for texture mapping*/
rw_centerangle = (centerangle-normalangle)&FINEMASK;
if (rw_centerangle > FINEANGLES/2) {
rw_centerangle -= FINEANGLES;
}
rw_centerangle += FINEANGLES/4;
rw_midpoint -= texslide;
rw_mintex -= texslide;
angle1 += ANGLE180; /* adjust so angles are unsigned*/
angle2 += ANGLE180;
ClipWallSegment(angle1, angle2,seg,distance);
}
/**********************************
Returns True if some part of the BSP dividing line might be visible
**********************************/
Boolean CheckBSPNode(Word boxpos)
{
short angle1, angle2;
unsigned short span, tspan;
unsigned short uangle1, uangle2;
screenpost_t *start;
Word *PosPtr;
int x1,y1,x2,y2;
PosPtr = &checkcoord[boxpos][0];
x1 = bspcoord[PosPtr[0]];
y1 = bspcoord[PosPtr[1]];
x2 = bspcoord[PosPtr[2]];
y2 = bspcoord[PosPtr[3]];
angle1 = PointToAngle(x1,y1) - centershort;
angle2 = PointToAngle(x2,y2) - centershort;
/* check clip list for an open space */
span = angle1 - angle2;
if (span >= 0x8000) {
return TRUE; /* sitting on a line*/
}
tspan = angle1 + clipshortangle;
if (tspan > clipshortangle2) {
tspan -= clipshortangle2;
if (tspan >= span) {
return FALSE; /* totally off the left edge*/
}
angle1 = clipshortangle;
}
tspan = clipshortangle - angle2;
if (tspan > clipshortangle2) {
tspan -= clipshortangle2;
if (tspan >= span) {
return FALSE; /* totally off the left edge*/
}
angle2 = -clipshortangle;
}
/* find the first clippost that touches the source post (adjacent pixels are touching)*/
uangle1 = angle1 + ANGLE180;
uangle2 = angle2 + ANGLE180;
start = solidsegs;
while (start->bottom > uangle1+1) {
++start;
}
if (uangle1 <= start->top && uangle2 >= start->bottom) {
return FALSE; /* the clippost contains the new span*/
}
return TRUE;
}
/**********************************
Draw one or more wall segments
**********************************/
void TerminalNode (saveseg_t *seg)
{
for (;;) { /* Forever? */
P_DrawSeg(seg); /* Draw the wall segment (If visible) */
if (seg->dir & DIR_LASTSEGFLAG) { /* Last segment in list? */
return; /* Exit now */
}
++seg; /* Index to the next wall segment */
}
}
/**********************************
Render the 3D view by recursivly following the BSP tree
**********************************/
void RenderBSPNode(Word bspnum)
{
savenode_t *bsp; /* Pointer to the current BSP node */
Word side; /* decision line */
Word coordinate; /* Current coord */
Word savednum; /* Save index */
Word savedcoordinate; /* Save value */
Word boxpos; /* Index to the coord table */
bsp = &nodes[bspnum]; /* Get pointer to the current tree node */
if (bsp->dir & DIR_SEGFLAG) { /* There is a segment here... */
TerminalNode((saveseg_t *)bsp); /* Render it */
return; /* Exit */
}
/* decision node */
coordinate = bsp->plane<<7; /* stored as half tiles*/
if (bsp->dir) { /* True for vertical tiles */
side = viewx > coordinate; /* vertical decision line*/
savednum = BSPLEFT + (side^1); /* Left or right */
} else {
side = viewy > coordinate; /* horizontal decision line*/
savednum = BSPTOP + (side^1); /* Top or bottom */
}
savedcoordinate = bspcoord[savednum]; /* Save this coord */
bspcoord[savednum] = coordinate; /* Set my new coord boundary */
RenderBSPNode(bsp->children[side^1]); /* recursively divide front space*/
bspcoord[savednum] = savedcoordinate; /* Restore the coord */
savednum ^= 1; /* Negate the index */
savedcoordinate = bspcoord[savednum]; /* Save the other side */
bspcoord[savednum] = coordinate; /* Set the new side */
/* if the back side node is a single seg, don't bother explicitly checking visibility */
if ( ! ( nodes[bsp->children[side]].dir & DIR_LASTSEGFLAG ) ) {
/* don't flow into the back space if it is not going to be visible */
if (viewx <= bspcoord[BSPLEFT]) {
boxpos = 0;
} else if (viewx < bspcoord[BSPRIGHT]) {
boxpos = 1;
} else {
boxpos = 2;
}
if (viewy > bspcoord[BSPTOP]) {
if (viewy < bspcoord[BSPBOTTOM]) {
boxpos += 4;
} else {
boxpos += 8;
}
}
if (!CheckBSPNode(boxpos)) { /* Intersect possible? */
goto skipback; /* Exit now then */
}
}
RenderBSPNode(bsp->children[side]); /* recursively divide back space */
skipback:
bspcoord[savednum] = savedcoordinate;
}
#include "WolfDef.h"
#include <string.h>
Word *src1,*src2,*dest; /* Used by the sort */
/**********************************
Merges src1/size1 and src2/size2 to dest
Both Size1 and Size2 MUST be non-zero
**********************************/
void Merge(Word Size1, Word Size2)
{
Word *XDest,*XSrc1,*XSrc2;
/* merge two parts of the unsorted array to the sorted array */
XDest = dest;
dest = &XDest[Size1+Size2];
XSrc1 = src1;
src1 = &XSrc1[Size1];
XSrc2 = src2;
src2 = &XSrc2[Size2];
if (XSrc1[0] < XSrc2[0]) { /* Which sort to use? */
mergefrom1:
do {
XDest[0] = XSrc1[0]; /* Copy one entry */
++XDest;
++XSrc1;
if (!--Size1) { /* Any more? */
do { /* Dump the rest */
XDest[0] = XSrc2[0]; /* Copy the rest of data */
++XDest;
++XSrc2;
} while (--Size2);
return;
}
} while (XSrc1[0] < XSrc2[0]);
}
do {
XDest[0] = XSrc2[0];
++XDest;
++XSrc2;
if (!--Size2) {
do {
XDest[0] = XSrc1[0];
++XDest;
++XSrc1;
} while (--Size1);
return;
}
} while (XSrc1[0] >= XSrc2[0]);
goto mergefrom1;
}
/**********************************
Sorts the events from xevents[0] to xevent_p
firstevent will be set to the first sorted event (either xevents[0] or sortbuffer[0])
**********************************/
void SortEvents(void)
{
Word count; /* Number of members to sort */
Word size; /* Entry size to sort with */
Word sort; /* Sort count */
Word remaining; /* Temp merge count */
Word *sorted,*unsorted,*temp;
count = numvisspr; /* How many entries are there? */
if (count<2) {
firstevent = xevents; /* Just return the 0 or 1 entries */
return; /* Leave now */
}
size = 1; /* source size (<<1 / loop)*/
sort = 1; /* iteration number (+1 / loop)*/
sorted = xevents;
unsorted = sortbuffer;
do {
remaining = count>>sort; /* How many times to try */
/* pointers incremented by the merge */
src1 = sorted; /* Sorted array */
src2 = &sorted[remaining<<(sort-1)]; /* Half point */
dest = unsorted; /* Dest array */
/* merge paired blocks*/
if (remaining) { /* Any to sort? */
do {
Merge(size,size); /* All groups equal size */
} while (--remaining);
}
/* copy or merge the leftovers */
remaining = count&((size<<1)-1); /* Create mask (1 bit higher) */
if (remaining > size) { /* one complete block and one fragment */
src1 = &src2[size];
Merge(remaining-size,size);
} else if (remaining) { /* just a single sorted fragment */
memcpy(dest,src2,remaining*sizeof(Word)); /* Copy it */
}
/* get ready to sort back to the other array */
size <<= 1; /* Double the entry size */
++sort; /* Increase the shift size */
temp = sorted; /* Swap the pointers */
sorted = unsorted;
unsorted = temp;
} while (size<count);
firstevent = sorted;
}
/**********************************
Draw a single scaled sprite
x1 = Left edge, x2 = Right edge, rs_vseg = record for sprite
**********************************/
void RenderSprite(Word x1,Word x2,vissprite_t *VisPtr)
{
Word column;
Word scaler;
scaler = VisPtr->clipscale; /* Get the size of the sprite */
column = 0; /* Start at the first column */
if ((int) x1 > VisPtr->x1) { /* Clip the left? */
column = (x1-VisPtr->x1)*VisPtr->columnstep; /* Start here instead */
}
/* calculate and draw each column */
do {
if (xscale[x1] <= scaler) { /* Visible? */
IO_ScaleMaskedColumn(x1,scaler,VisPtr->pos,column>>FRACBITS);
}
column+=VisPtr->columnstep; /* Next column (Fraction) */
} while (++x1<=x2);
}
/**********************************
Add a sprite entry to the render list
**********************************/
void AddSprite (thing_t *thing,Word actornum)
{
fixed_t tx; /* New X coord */
fixed_t tz; /* New z coord (Size) */
Word scale; /* Scaled size */
int px; /* Center X coord */
unsigned short *patch; /* Pointer to sprite data */
int x1, x2; /* Left,Right x */
Word width; /* Width of sprite */
fixed_t trx,try; /* x,y from the camera */
vissprite_t *VisPtr; /* Local pointer to visible sprite record */
/* transform the origin point */
if (numvisspr>=(MAXVISSPRITES-1)) {
return;
}
trx = thing->x - viewx; /* Adjust from the camera view */
try = viewy - thing->y; /* Adjust from the camera view */
tz = R_TransformZ(trx,try); /* Get the distance */
if (tz < MINZ) { /* Too close? */
return;
}
if (tz>=MAXZ) { /* Force smallest */
tz = MAXZ-1;
}
scale = scaleatzptr[tz]; /* Get the scale at the z coord */
tx = R_TransformX(trx,try); /* Get the screen x coord */
px = ((tx*(long)scale)>>7) + CENTERX; /* Use 32 bit precision! */
/* calculate edges of the shape */
patch = SpriteArray[thing->sprite]; /* Pointer to the sprite info */
width =((LongWord)patch[0]*scale)>>6; /* Get the width of the shape */
if (!width) {
return; /* too far away*/
}
x1 = px - (width>>1); /* Get the left edge */
if (x1 >= (int) SCREENWIDTH) {
return; /* off the right side */
}
x2 = x1 + width - 1; /* Get the right edge */
if (x2 < 0) {
return; /* off the left side*/
}
VisPtr = &vissprites[numvisspr];
VisPtr->pos = &patch[0]; /* Sprite info offset */
VisPtr->x1 = x1; /* Min x */
VisPtr->x2 = x2; /* Max x */
VisPtr->clipscale = scale; /* Size to draw */
VisPtr->columnstep = (patch[0]<<8)/width; /* Step for width scale */
VisPtr->actornum = actornum; /* Actor who this is (0 for static) */
/* pack the vissprite number into the low 6 bits of the scale for sorting */
xevents[numvisspr] = (scale<<6) | numvisspr; /* Pass the scale in the upper 10 bits */
++numvisspr; /* 1 more valid record */
}
/**********************************
Draw a scaling game over sprite on top of everything
**********************************/
void DrawTopSprite(void)
{
unsigned short *patch;
int x1, x2;
Word width;
vissprite_t VisRecord;
if (topspritescale) { /* Is there a top sprite? */
/* calculate edges of the shape */
patch = SpriteArray[topspritenum]; /* Get the info on the shape */
width = (patch[0]*topspritescale)>>7; /* Adjust the width */
if (!width) {
return; /* Too far away */
}
x1 = CENTERX - (width>>1); /* Use the center to get the left edge */
if (x1 >= SCREENWIDTH) {
return; /* off the right side*/
}
x2 = x1 + width - 1; /* Get the right edge */
if (x2 < 0) {
return; /* off the left side*/
}
VisRecord.pos = patch; /* Index to the shape record */
VisRecord.x1 = x1; /* Left edge */
VisRecord.x2 = x2; /* Right edge */
VisRecord.clipscale = topspritescale; /* Size */
VisRecord.columnstep = (patch[0]<<8)/(x2-x1+1); /* Width step */
/* Make sure it is sorted to be drawn last */
memset(xscale,0,sizeof(xscale)); /* don't clip behind anything */
if (x1<0) {
x1 = 0; /* Clip the left */
}
if (x2>=SCREENWIDTH) {
x2 = SCREENWIDTH-1; /* Clip the right */
}
RenderSprite(x1,x2,&VisRecord); /* Draw the sprite */
}
}
/**********************************
Draw all the character sprites
**********************************/
void DrawSprites(void)
{
vissprite_t *dseg; /* Pointer to visible sprite record */
int x1,x2; /* Left x, Right x */
Word i; /* Index */
static_t *stat; /* Pointer to static sprite record */
actor_t *actor; /* Pointer to active actor record */
missile_t *MissilePtr; /* Pointer to active missile record */
Word *xe; /* Pointer to sort value */
numvisspr = 0; /* Init the sprite count */
/* add all sprites in visareas*/
if (numstatics) { /* Any statics? */
i = numstatics;
stat = statics; /* Init my pointer */
do {
if (areavis[stat->areanumber]) { /* Is it in a visible area? */
AddSprite((thing_t *) stat,0); /* Add to my list */
}
++stat; /* Next index */
} while (--i); /* Count down */
}
if (numactors>1) { /* Any actors? */
i = 1; /* Index to the first NON-PLAYER actor */
actor = &actors[1]; /* Init pointer */
do {
if (areavis[actor->areanumber]) { /* Visible? */
AddSprite ((thing_t *)actor, i); /* Add it */
}
++actor; /* Next actor */
} while (++i<numactors); /* Count up */
}
if (nummissiles) { /* Any missiles? */
i = nummissiles; /* Get the missile count */
MissilePtr = missiles; /* Get the pointer to the first missile */
do {
if (areavis[MissilePtr->areanumber]) { /* Visible? */
AddSprite((thing_t *)MissilePtr,0); /* Show it */
}
++MissilePtr; /* Next missile */
} while (--i); /* Count down */
}
i = numvisspr;
if (i) { /* Any sprites? */
/* sort sprites from back to front*/
SortEvents();
/* draw from smallest scale to largest */
xe=firstevent;
do {
dseg = &vissprites[xe[0]&(MAXVISSPRITES-1)]; /* Which one? */
x1 = dseg->x1;
if (x1<0) { /* Clip the left? */
x1 = 0;
}
x2 = dseg->x2;
if (x2>= (int)SCREENWIDTH) { /* Clip the right? */
x2 = SCREENWIDTH-1;
}
RenderSprite(x1,x2,dseg); /* Draw the sprite */
++xe;
} while (--i);
}
}
#include "WolfDef.h"
#include <string.h>
#include <math.h>
#define DOORPIC 59
/* Scale ranges from 0xffff (one tile == 512 pixels high) down to 0x100 (one tile == 2 pixels) */
savenode_t *nodes;
saveseg_t *pwallseg; /* pushwall in motion*/
/*
================================================
MATH ROUTINES
================================================
*/
/* -8.8 * -0.8 = -8.8*/
fixed_t FixedByFrac (fixed_t a, fixed_t b)
{
fixed_t c;
c = ((long)a * (long)b)>>FRACBITS;
return c;
}
/* -8.8 * -0.8 = -8.8*/
fixed_t SUFixedMul (fixed_t a, ufixed_t b)
{
fixed_t c;
c = ((long)a * (long)b)>>FRACBITS;
return c;
}
/* -8.8 / -8.8 = -8.8*/
fixed_t FixedDiv (fixed_t a, fixed_t b)
{
a = (long)(((long)a<<FRACBITS) / (long)b);
return a;
}
/**********************************
Return the x coord for a sprite
**********************************/
fixed_t R_TransformX(fixed_t x,fixed_t y)
{
fixed_t gxt,gyt;
gxt = FixedByFrac(x,viewsin);
gyt = FixedByFrac(y,viewcos);
return gxt-gyt;
}
/**********************************
Return the scale factor for a sprite
**********************************/
fixed_t R_TransformZ(fixed_t x,fixed_t y)
{
fixed_t gxt,gyt;
gxt = FixedByFrac(x,viewcos);
gyt = FixedByFrac(y,viewsin);
return gxt+gyt;
}
/**********************************
Return the scale factor from a 64k range angle
**********************************/
Word ScaleFromGlobalAngle(int visangle,int distance)
{
fixed_t tz;
Word anglea, angleb;
Word sinea, sineb;
visangle >>= ANGLETOFINESHIFT;
anglea = (FINEANGLES/4 + (visangle-centerangle))&(FINEANGLES/2-1);
angleb = (FINEANGLES/4 + (visangle-normalangle))&(FINEANGLES/2-1);
sinea = finesine[anglea]; /* bothe sines are always positive*/
sineb = finesine[angleb];
tz = ((long)distance * sinea) / sineb;
if (tz>=MAXZ) { /* Make sure it's not too big... */
tz = MAXZ-1;
}
return scaleatzptr[tz]; /* Return the size */
}
/**********************************
The automap has to be done in quadrants for various reasons
**********************************/
void DrawAutomap(Word tx,Word ty)
{
Word i, tile;
saveseg_t *seg;
Word x,y,xstep,ystep,count;
Word min,max;
Word maxtx, maxty;
Word NodeCount;
NodeCount = MapPtr->numnodes;
maxtx = tx+(SCREENWIDTH/16);
maxty = ty+(SCREENHEIGHT/16);
seg = (saveseg_t *)nodes;
i = 0;
do {
if ( (seg->dir & (DIR_SEGFLAG|DIR_SEENFLAG)) == (DIR_SEGFLAG|DIR_SEENFLAG) ) {
min = (seg->min-1)>>1;
max = (seg->max+3)>>1;
switch (seg->dir&3) {
case di_north:
x = (seg->plane-1)>>1;
y = min;
xstep = 0;
ystep = 1;
break;
case di_south:
x = seg->plane>>1;
y = min;
xstep = 0;
ystep = 1;
break;
case di_east:
y = (seg->plane-1)>>1;
x = min;
xstep = 1;
ystep = 0;
break;
case di_west:
y = seg->plane>>1;
x = min;
xstep = 1;
ystep = 0;
break;
}
for (count=max-min ; count ; --count,x+=xstep,y+=ystep) {
if (x < tx || x >= maxtx || y < ty || y>=maxty) {
continue;
}
tile = tilemap[y][x];
if (tile & TI_DOOR) {
tile = 59 /*(seg->dir&1) + 30*/;
} else if (tile & TI_PUSHWALL) {
if (ShowPush) {
tile = 64;
} else {
tile = textures[y][x];
}
} else {
tile = MapPtr->tilemap[y][x];
if (! (tile&0x80) ) {
continue; /* not a solid tile*/
}
tile = textures[y][x];
}
DrawSmall(x-tx,y-ty,tile); /* Draw the tile on the screen */
}
}
++seg;
} while (++i<NodeCount);
x = viewx>>8;
y = viewy>>8;
if (x >= tx && x < maxtx && y >= ty && y<maxty) {
DrawSmall(x-tx,y-ty,64); /* Draw BJ's face here */
}
BlastScreen();
}
/**********************************
Init my math tables for the current view
**********************************/
#define PI 3.141592657
Boolean StartupRendering(Word NewSize)
{
#ifdef __MAC__
int i;
Word minz;
int x;
float a, fv;
long t;
LongWord focallength;
Word j;
Word *ScalePtr;
#endif
if (NewSize == MathSize) { /* Already loaded? */
return TRUE;
}
#ifdef __MAC__ /* Only the mac version will calculate the tables */
/* generate scaleatz*/
ScalePtr = scaleatzptr;
minz = PROJECTIONSCALE/MAXFRAC; /* What's the largest index */
for (j=0;j<=minz;j++) {
ScalePtr[j] = MAXFRAC; /* Fill in the overflow area (No longs) */
}
do { /* Calculate the rest */
ScalePtr[j] = PROJECTIONSCALE/j; /* Create whole numbers */
} while (++j<MAXZ);
/* viewangle tangent table*/
if (MathSize==-1) { /* Only needs to be done once */
i = 0;
do {
a = (i-FINEANGLES/4+0.1)*PI*2/FINEANGLES;
fv = 256*tan(a);
if (fv>0x7fff) {
t = 0x7fff;
} else if (fv<-0x7fff) {
t = -0x7fff;
} else {
t = fv;
}
finetangent[i] = t;
} while (++i<FINEANGLES/2);
/* finesine table*/
i = 0;
do {
a = (i+0.0)*PI*2/FINEANGLES;
t = 256*sin(a);
if (t>255) {
t = 255;
}
if (t<1) {
t = 1;
}
finesine[i] = t;
} while (++i<FINEANGLES/2);
}
/* use tangent table to generate viewangletox*/
/* calc focallength so FIELDOFVIEW angles covers SCREENWIDTH */
focallength = (SCREENWIDTH/2)<<FRACBITS/finetangent[FINEANGLES/4+FIELDOFVIEW/2];
i = 0;
do {
t = ((long) finetangent[i]*(long)focallength)>>FRACBITS;
t = (int)SCREENWIDTH/2 - t;
if (t < -1) {
t = -1;
} else if (t>(int)SCREENWIDTH+1) {
t = SCREENWIDTH+1;
}
viewangletox[i] = t;
} while (++i<FINEANGLES/2);
/* scan viewangletox[] to generate xtoviewangle[]*/
x = 0;
do {
i = 0;
while (viewangletox[i]>=x) {
i++;
}
xtoviewangle[x] = i-FINEANGLES/4-1;
} while (++x<=SCREENWIDTH);
/* take out the fencepost cases from viewangletox*/
for (i=0 ; i<FINEANGLES/2 ; i++) {
t = SUFixedMul (finetangent[i], focallength);
t = (int)SCREENWIDTH/2 - t;
if (viewangletox[i] == -1) {
viewangletox[i] = 0;
} else if (viewangletox[i] == SCREENWIDTH+1) {
viewangletox[i] = SCREENWIDTH;
}
}
#if 0 /* Should I save these tables? */
if (!NewSize) {
SaveJunk(scaleatzptr,sizeof(Word)*MAXZ);
SaveJunk(finetangent,sizeof(short)*FINEANGLES/2);
SaveJunk(finesine,sizeof(short)*FINEANGLES/2);
SaveJunk(viewangletox,sizeof(short)*FINEANGLES/2);
SaveJunk(xtoviewangle,sizeof(short)*(SCREENWIDTH+1));
GoodBye();
}
#endif
#else
/* All other versions load the tables from disk (MUCH FASTER!!) */
if (MathSize==-1) {
finetangent = LoadAResource(rFineTangent);
finesine = LoadAResource(rFineSine);
}
scaleatzptr = LoadAResource(rScaleAtZ);
viewangletox = LoadAResource(rViewAngleToX);
xtoviewangle = LoadAResource(rXToViewAngle);
#endif
clipshortangle = xtoviewangle[0]<<ANGLETOFINESHIFT; /* Save leftmost angle for view */
clipshortangle2 = clipshortangle*2; /* Double the angle for constant */
/* textures for doors stay the same across maps*/
memset(textures[128],DOORPIC+4,MAPSIZE); /* door side*/
memset(textures[129],DOORPIC+0,MAPSIZE); /* regular door*/
memset(textures[130],DOORPIC+1,MAPSIZE); /* lock 1*/
memset(textures[131],DOORPIC+2,MAPSIZE); /* lock 2*/
memset(textures[132],DOORPIC+3,MAPSIZE); /* elevator*/
ReleaseScalers(); /* Release any compiled scalers */
if (!SetupScalers()) { /* Redo any scalers */
return FALSE;
}
MathSize = NewSize;
return TRUE;
}
/**********************************
Alert the rendering engine about a new map
**********************************/
void NewMap(void)
{
Word x,y, tile;
Byte *src;
#ifdef __BIGENDIAN__
savenode_t *FixPtr;
#endif
memset(textures,0xff,128*64); /* clear array so pushwall spawning can insert*/
/* texture numbers in empty spots*/
src = &MapPtr->tilemap[0][0];
y = 0;
do {
x = 0;
do {
tile = *src++;
if (tile&TI_BLOCKMOVE) { /* blocking?*/
tile = ((tile&0x3f)-1)*2;
textures[MAPSIZE+x][y] = tile + 1; /* Use the dark shape */
textures[y][x] = tile; /* Use the light shape */
}
} while (++x<MAPSIZE);
} while (++y<MAPSIZE);
nodes = (savenode_t *)((Byte *)MapPtr + MapPtr->nodelistofs);
#ifdef __BIGENDIAN__
y = MapPtr->numnodes;
FixPtr = nodes;
while (y) {
FixPtr->children[0] = SwapUShort(FixPtr->children[0]); /* Swap endian on all offsets */
FixPtr->children[1] = SwapUShort(FixPtr->children[1]);
++FixPtr;
--y;
}
#endif
pwallseg = 0; /* No pushwalls in progress */
}
/**********************************
Set up my pushwall record so the BSP records will follow
**********************************/
void StartPushWall(void)
{
Word i;
Word segdir,segplane,segmin;
saveseg_t *SavePtr; /* Temp pointer */
pwallseg = 0; /* No pushwalls in progress */
switch (PushWallRec.pwalldir) { /* Which direction? */
case CD_NORTH:
segmin = PushWallRec.pwallx<<1; /* Minimum segment */
segplane = (PushWallRec.pwally+1)<<1; /* y facing plane */
segdir = di_east; /* Point east */
break;
case CD_EAST:
segplane = PushWallRec.pwallx<<1; /* Minimum segment */
segmin = PushWallRec.pwally<<1;
segdir = di_south; /* Point south */
break;
case CD_SOUTH:
segmin = PushWallRec.pwallx<<1;
segplane = PushWallRec.pwally<<1;
segdir = di_west; /* Point west */
break;
case CD_WEST:
segplane = (PushWallRec.pwallx+1)<<1;
segmin = PushWallRec.pwally<<1;
segdir = di_north; /* Point north */
}
SavePtr = (saveseg_t *)nodes; /* Init pointer to the nodes */
i = MapPtr->numnodes; /* Get the node count */
if (i) { /* Maps MUST have nodes */
do {
if ((SavePtr->dir & DIR_SEGFLAG) && /* Segmented? */
((SavePtr->dir & 3) == segdir) && /* Proper side? */
(SavePtr->plane == segplane) && /* Proper plane? */
(SavePtr->min == segmin) ) { /* Proper segment */
pwallseg = SavePtr; /* Save the segment */
return; /* Exit */
}
++SavePtr; /* Next index */
} while (--i); /* Count down */
}
}
/**********************************
Mark a pushwall BSP segment as disabled
**********************************/
void AdvancePushWall(void)
{
if (pwallseg) { /* Failsafe */
pwallseg->dir |= DIR_DISABLEDFLAG; /* Mark the pushwall as disabled */
}
}
/**********************************
Render the entire 3-D view
**********************************/
void RenderView(void)
{
Word frame;
centerangle = gamestate.viewangle<<GAMEANGLETOFINE; /* 512 to 2048 */
centershort = centerangle<<ANGLETOFINESHIFT; /* 2048 to 64k */
viewsin = sintable[gamestate.viewangle]; /* Get the basic sine */
viewcos = costable[gamestate.viewangle]; /* Get the basic cosine */
memset(areavis, 0, sizeof(areavis)); /* No areas are visible */
ClearClipSegs(); /* Clip first seg only to sides of screen */
IO_ClearViewBuffer(); /* Erase to ceiling / floor colors*/
bspcoord[BSPTOP] = 0; /* The map is 64*64 */
bspcoord[BSPBOTTOM] = 64*FRACUNIT;
bspcoord[BSPLEFT] = 0;
bspcoord[BSPRIGHT] = 64*FRACUNIT;
RenderBSPNode(0); /* traverse the BSP tree from the root */
DrawSprites(); /* sort all the sprites in any of the rendered areas*/
DrawTopSprite(); /* draw game over sprite on top of everything*/
if (!NoWeaponDraw) { /* Don't draw the weapon? */
frame = gamestate.attackframe;
if (frame == 4) {
frame = 1; /* drop back frame*/
}
IO_AttackShape(gamestate.weapon*4 + frame); /* Draw the gun shape */
}
IO_DisplayViewBuffer(); /* blit to screen */
}
#include "WolfDef.h"
#include <stdlib.h>
Word MathSize; /* What size of math data is calculated? */
Word *scaleatzptr; /* Pointer to the scale table for z projection */
short *xtoviewangle; /* Screen x to view angle */
short *viewangletox; /* View angle to screen x */
short *finetangent; /* Fine tangent table */
short *finesine; /* Fine sine table */
fixed_t sintable[ANGLES] = {
0,3,6,9,13,16,19,22,25,28,31,34,37,41,44,47,
50,53,56,59,62,65,68,71,74,77,80,83,86,89,92,95,
98,100,103,106,109,112,115,117,120,123,126,128,131,134,136,139,
142,144,147,149,152,154,157,159,162,164,167,169,171,174,176,178,
180,183,185,187,189,191,193,195,197,199,201,203,205,207,208,210,
212,214,215,217,219,220,222,223,225,226,228,229,231,232,233,234,
236,237,238,239,240,241,242,243,244,245,246,247,247,248,249,249,
250,251,251,252,252,253,253,253,254,254,254,255,255,255,255,255,
255,255,255,255,255,255,254,254,254,253,253,253,252,252,251,251,
250,249,249,248,247,247,246,245,244,243,242,241,240,239,238,237,
236,234,233,232,231,229,228,226,225,223,222,220,219,217,215,214,
212,210,208,207,205,203,201,199,197,195,193,191,189,187,185,183,
180,178,176,174,171,169,167,164,162,159,157,154,152,149,147,144,
142,139,136,134,131,128,126,123,120,117,115,112,109,106,103,100,
98,95,92,89,86,83,80,77,74,71,68,65,62,59,56,53,
50,47,44,41,37,34,31,28,25,22,19,16,13,9,6,3,
0,-3,-6,-9,-13,-16,-19,-22,-25,-28,-31,-34,-37,-41,-44,-47,
-50,-53,-56,-59,-62,-65,-68,-71,-74,-77,-80,-83,-86,-89,-92,-95,
-98,-100,-103,-106,-109,-112,-115,-117,-120,-123,-126,-128,-131,-134,-136,-139,
-142,-144,-147,-149,-152,-154,-157,-159,-162,-164,-167,-169,-171,-174,-176,-178,
-180,-183,-185,-187,-189,-191,-193,-195,-197,-199,-201,-203,-205,-207,-208,-210,
-212,-214,-215,-217,-219,-220,-222,-223,-225,-226,-228,-229,-231,-232,-233,-234,
-236,-237,-238,-239,-240,-241,-242,-243,-244,-245,-246,-247,-247,-248,-249,-249,
-250,-251,-251,-252,-252,-253,-253,-253,-254,-254,-254,-255,-255,-255,-255,-255,
-255,-255,-255,-255,-255,-255,-254,-254,-254,-253,-253,-253,-252,-252,-251,-251,
-250,-249,-249,-248,-247,-247,-246,-245,-244,-243,-242,-241,-240,-239,-238,-237,
-236,-234,-233,-232,-231,-229,-228,-226,-225,-223,-222,-220,-219,-217,-215,-214,
-212,-210,-208,-207,-205,-203,-201,-199,-197,-195,-193,-191,-189,-187,-185,-183,
-180,-178,-176,-174,-171,-169,-167,-164,-162,-159,-157,-154,-152,-149,-147,-144,
-142,-139,-136,-134,-131,-128,-126,-123,-120,-117,-115,-112,-109,-106,-103,-100,
-98,-95,-92,-89,-86,-83,-80,-77,-74,-71,-68,-65,-62,-59,-56,-53,
-50,-47,-44,-41,-37,-34,-31,-28,-25,-22,-19,-16,-13,-9,-6,-3
};
fixed_t costable[ANGLES] = {
255,255,255,255,255,255,254,254,254,253,253,253,252,252,251,251,
250,249,249,248,247,247,246,245,244,243,242,241,240,239,238,237,
236,234,233,232,231,229,228,226,225,223,222,220,219,217,215,214,
212,210,208,207,205,203,201,199,197,195,193,191,189,187,185,183,
180,178,176,174,171,169,167,164,162,159,157,154,152,149,147,144,
142,139,136,134,131,128,126,123,120,117,115,112,109,106,103,100,
98,95,92,89,86,83,80,77,74,71,68,65,62,59,56,53,
50,47,44,41,37,34,31,28,25,22,19,16,13,9,6,3,
0,-3,-6,-9,-13,-16,-19,-22,-25,-28,-31,-34,-37,-41,-44,-47,
-50,-53,-56,-59,-62,-65,-68,-71,-74,-77,-80,-83,-86,-89,-92,-95,
-98,-100,-103,-106,-109,-112,-115,-117,-120,-123,-126,-128,-131,-134,-136,-139,
-142,-144,-147,-149,-152,-154,-157,-159,-162,-164,-167,-169,-171,-174,-176,-178,
-180,-183,-185,-187,-189,-191,-193,-195,-197,-199,-201,-203,-205,-207,-208,-210,
-212,-214,-215,-217,-219,-220,-222,-223,-225,-226,-228,-229,-231,-232,-233,-234,
-236,-237,-238,-239,-240,-241,-242,-243,-244,-245,-246,-247,-247,-248,-249,-249,
-250,-251,-251,-252,-252,-253,-253,-253,-254,-254,-254,-255,-255,-255,-255,-255,
-255,-255,-255,-255,-255,-255,-254,-254,-254,-253,-253,-253,-252,-252,-251,-251,
-250,-249,-249,-248,-247,-247,-246,-245,-244,-243,-242,-241,-240,-239,-238,-237,
-236,-234,-233,-232,-231,-229,-228,-226,-225,-223,-222,-220,-219,-217,-215,-214,
-212,-210,-208,-207,-205,-203,-201,-199,-197,-195,-193,-191,-189,-187,-185,-183,
-180,-178,-176,-174,-171,-169,-167,-164,-162,-159,-157,-154,-152,-149,-147,-144,
-142,-139,-136,-134,-131,-128,-126,-123,-120,-117,-115,-112,-109,-106,-103,-100,
-98,-95,-92,-89,-86,-83,-80,-77,-74,-71,-68,-65,-62,-59,-56,-53,
-50,-47,-44,-41,-37,-34,-31,-28,-25,-22,-19,-16,-13,-9,-6,-3,
0,3,6,9,13,16,19,22,25,28,31,34,37,41,44,47,
50,53,56,59,62,65,68,71,74,77,80,83,86,89,92,95,
98,100,103,106,109,112,115,117,120,123,126,128,131,134,136,139,
142,144,147,149,152,154,157,159,162,164,167,169,171,174,176,178,
180,183,185,187,189,191,193,195,197,199,201,203,205,207,208,210,
212,214,215,217,219,220,222,223,225,226,228,229,231,232,233,234,
236,237,238,239,240,241,242,243,244,245,246,247,247,248,249,249,
250,251,251,252,252,253,253,253,254,254,254,255,255,255,255,255
};
Word tantoangle[513] = {
0,20,40,61,81,101,122,142,162,183,203,224,244,264,285,305,
325,346,366,386,407,427,447,468,488,508,529,549,569,590,610,630,
651,671,691,711,732,752,772,792,813,833,853,873,894,914,934,954,
974,995,1015,1035,1055,1075,1096,1116,1136,1156,1176,1196,1216,1236,1256,1277,
1297,1317,1337,1357,1377,1397,1417,1437,1457,1477,1497,1517,1537,1556,1576,1596,
1616,1636,1656,1676,1696,1715,1735,1755,1775,1795,1814,1834,1854,1874,1893,1913,
1933,1952,1972,1992,2011,2031,2051,2070,2090,2109,2129,2148,2168,2187,2207,2226,
2246,2265,2285,2304,2323,2343,2362,2381,2401,2420,2439,2459,2478,2497,2516,2536,
2555,2574,2593,2612,2631,2650,2669,2688,2708,2727,2746,2765,2784,2802,2821,2840,
2859,2878,2897,2916,2935,2953,2972,2991,3010,3028,3047,3066,3084,3103,3122,3140,
3159,3177,3196,3214,3233,3251,3270,3288,3307,3325,3343,3362,3380,3398,3416,3435,
3453,3471,3489,3508,3526,3544,3562,3580,3598,3616,3634,3652,3670,3688,3706,3724,
3742,3759,3777,3795,3813,3831,3848,3866,3884,3901,3919,3937,3954,3972,3989,4007,
4024,4042,4059,4077,4094,4112,4129,4146,4164,4181,4198,4215,4233,4250,4267,4284,
4301,4318,4335,4352,4369,4386,4403,4420,4437,4454,4471,4488,4505,4521,4538,4555,
4572,4588,4605,4622,4638,4655,4671,4688,4704,4721,4737,4754,4770,4787,4803,4819,
4836,4852,4868,4884,4901,4917,4933,4949,4965,4981,4997,5013,5029,5045,5061,5077,
5093,5109,5125,5141,5156,5172,5188,5204,5219,5235,5251,5266,5282,5297,5313,5328,
5344,5359,5375,5390,5406,5421,5436,5452,5467,5482,5497,5513,5528,5543,5558,5573,
5588,5603,5618,5633,5648,5663,5678,5693,5708,5723,5738,5752,5767,5782,5797,5811,
5826,5841,5855,5870,5884,5899,5913,5928,5942,5957,5971,5985,6000,6014,6028,6043,
6057,6071,6085,6100,6114,6128,6142,6156,6170,6184,6198,6212,6226,6240,6254,6268,
6282,6295,6309,6323,6337,6350,6364,6378,6391,6405,6419,6432,6446,6459,6473,6486,
6500,6513,6527,6540,6553,6567,6580,6593,6606,6620,6633,6646,6659,6672,6685,6698,
6711,6724,6737,6750,6763,6776,6789,6802,6815,6828,6841,6853,6866,6879,6892,6904,
6917,6930,6942,6955,6967,6980,6992,7005,7017,7030,7042,7055,7067,7079,7092,7104,
7116,7129,7141,7153,7165,7177,7190,7202,7214,7226,7238,7250,7262,7274,7286,7298,
7310,7322,7333,7345,7357,7369,7381,7392,7404,7416,7428,7439,7451,7462,7474,7486,
7497,7509,7520,7532,7543,7555,7566,7577,7589,7600,7611,7623,7634,7645,7657,7668,
7679,7690,7701,7712,7724,7735,7746,7757,7768,7779,7790,7801,7812,7823,7833,7844,
7855,7866,7877,7888,7898,7909,7920,7931,7941,7952,7963,7973,7984,7994,8005,8015,
8026,8036,8047,8057,8068,8078,8089,8099,8109,8120,8130,8140,8151,8161,8171,8181,
8192};
/**********************************
Get the memory for the scale tables
**********************************/
void GetTableMemory(void)
{
#ifdef __MAC__ /* Only the mac version will calculate the tables */
/* All other versions will load precalc'd tables from disk */
scaleatzptr = (Word *)AllocSomeMem(sizeof(Word)*MAXZ);
viewangletox = (short *)AllocSomeMem(sizeof(short)*FINEANGLES/2);
xtoviewangle = (short *)AllocSomeMem(sizeof(short)*(1024+1));
finetangent = (short *)AllocSomeMem(sizeof(short)*FINEANGLES/2);
finesine = (short *) AllocSomeMem(sizeof(short)*FINEANGLES/2);
#endif
MathSize = -1; /* No math data is loaded... */
}
#include "WolfDef.h"
#include <string.h>
#include <stdlib.h>
LongWord ScaleDiv[2048];
/**********************************
Create the compiled scalers
**********************************/
Boolean SetupScalers(void)
{
Word i;
if (!ScaleDiv[1]) { /* Divide table inited already? */
i = 1;
do {
ScaleDiv[i] = 0x400000UL/(LongWord)i; /* Get the recipocal for the scaler */
} while (++i<2048);
}
MaxScaler = 2048;
return TRUE;
}
void ReleaseScalers(void)
{
}
/**********************************
Draw a vertical line with a scaler
(Used for WALL drawing)
**********************************/
void ScaleGlue(void *a,LongWord scale,void *c,LongWord d,LongWord e,LongWord f,LongWord g);
#if 0
void IO_ScaleWallColumn(Word x,Word scale,LongWord column)
{
LongWord TheFrac;
LongWord TheInt;
LongWord y;
Byte *ArtStart;
if (scale) { /* Uhh.. Don't bother */
TheFrac = ScaleDiv[scale];
scale*=2;
ArtStart = &ArtData[(column>>7)&0x3f][(column&127)<<7];
if (scale<VIEWHEIGHT) {
y = (VIEWHEIGHT-scale)/2;
TheInt = TheFrac>>24;
TheFrac <<= 8;
ScaleGlue(ArtStart,scale,
&VideoPointer[(y*VideoWidth)+x],
TheFrac,
TheInt,
VideoWidth,
0
);
return;
}
y = (scale-VIEWHEIGHT)/2; /* How manu lines to remove */
y = y*TheFrac;
TheInt = TheFrac>>24;
TheFrac <<= 8L;
ScaleGlue(&ArtStart[y>>24L],VIEWHEIGHT,
&VideoPointer[x],
TheFrac,
TheInt,
VideoWidth,
y<<8L
);
}
}
#endif
/**********************************
Draw a vertical line with a masked scaler
(Used for SPRITE drawing)
**********************************/
typedef struct {
unsigned short Topy;
unsigned short Boty;
unsigned short Shape;
} SpriteRun;
void SpriteGlue(Byte *a,LongWord b,Byte *c,Word d,Word e);
/*
SGArtStart EQU A0 ;Pointer to the 6 byte run structure
SGFrac EQU D2 ;Pointer to the scaler
SGInteger EQU D3 ;Pointer to the video
SGScreenPtr EQU A1 ;Pointer to the run base address
SGCount EQU D6
SGDelta EQU D4
*/
void IO_ScaleMaskedColumn(Word x,Word scale,unsigned short *CharPtr,Word column)
{
Byte * CharPtr2;
int Y1,Y2;
Byte *Screenad;
SpriteRun *RunPtr;
LongWord TheFrac;
Word RunCount;
Word TopY;
Word Index;
LongWord Delta;
if (!scale) {
return;
}
CharPtr2 = (Byte *) CharPtr;
TheFrac = ScaleDiv[scale]; /* Get the scale fraction */
RunPtr = (SpriteRun *) &CharPtr[CharPtr[column+1]/2]; /* Get the offset to the RunPtr data */
Screenad = &VideoPointer[x]; /* Set the base screen address */;
TopY = (VIEWHEIGHT/2)-scale; /* Number of pixels for 128 pixel shape */
while (RunPtr->Topy != (unsigned short) -1) { /* Not end of record? */
Y1 = (LongWord)scale*RunPtr->Topy/128+TopY;
if (Y1<(int)VIEWHEIGHT) { /* Clip top? */
Y2 = (LongWord)scale*RunPtr->Boty/128+TopY;
if (Y2>0) {
if (Y2>(int)VIEWHEIGHT) {
Y2 = VIEWHEIGHT;
}
Index = RunPtr->Shape+(RunPtr->Topy/2);
Delta = 0;
if (Y1<0) {
Delta = (LongWord)(0-Y1)*TheFrac;
Index += (Delta>>16);
Y1 = 0;
}
RunCount = Y2-Y1; /* How many lines to draw?*/
if (RunCount) {
SpriteGlue(
&CharPtr2[Index], /* Pointer to art data */
TheFrac, /* Fixed point fractional value */
&Screenad[YTable[Y1]], /* Pointer to screen */
RunCount, /* Number of lines to draw */
Delta /* Delta value */
);
}
}
}
RunPtr++; /* Next record */
}
}
/**********************************
Draw an automap tile
**********************************/
Byte *SmallFontPtr;
void DrawSmall(Word x,Word y,Word tile)
{
Byte *Screenad;
Byte *ArtStart;
Word Width,Height;
if (!SmallFontPtr) {
return;
}
x*=16;
y*=16;
Screenad = &VideoPointer[YTable[y]+x];
ArtStart = &SmallFontPtr[tile*(16*16)];
Height = 0;
do {
Width = 16;
do {
Screenad[0] = ArtStart[0];
++Screenad;
++ArtStart;
} while (--Width);
Screenad+=VideoWidth-16;
} while (++Height<16);
}
void MakeSmallFont(void)
{
Word i,j,Width,Height;
Byte *DestPtr,*ArtStart;
Byte *TempPtr;
SmallFontPtr = AllocSomeMem(16*16*65);
if (!SmallFontPtr) {
return;
}
memset(SmallFontPtr,0,16*16*65); /* Erase the font */
i = 0;
DestPtr = SmallFontPtr;
do {
ArtStart = &ArtData[i][0];
if (!ArtStart) {
DestPtr+=(16*16);
} else {
Height = 0;
do {
Width = 16;
j = Height*8;
do {
DestPtr[0] = ArtStart[j];
++DestPtr;
j+=(WALLHEIGHT*8);
} while (--Width);
} while (++Height<16);
}
} while (++i<64);
TempPtr = LoadAResource(MyBJFace);
memcpy(DestPtr,TempPtr,16*16);
ReleaseAResource(MyBJFace);
}
void KillSmallFont(void)
{
if (SmallFontPtr) {
FreeSomeMem(SmallFontPtr);
SmallFontPtr=0;
}
}
#include "WolfDef.h"
#include <string.h>
#include "SoundMusicSystem.h"
#include "mixedmode.h"
Word ScaleDiv[2048]; /* Divide table for scalers */
/**********************************
Create the compiled scalers
**********************************/
Boolean SetupScalers(void)
{
Word i;
if (!ScaleDiv[1]) { /* Divide table inited already? */
i = 1;
do {
ScaleDiv[i] = 0x40000000/i; /* Get the recipocal for the scaler */
} while (++i<2048);
}
MaxScaler = 2048; /* Init the highest scaler value */
return TRUE; /* No errors possible */
}
/**********************************
Release the memory from the scalers
**********************************/
void ReleaseScalers(void)
{
}
/**********************************
Draw a vertical line with a scaler
(Used for WALL drawing)
This is now in assembly language
**********************************/
/* void ScaleGlue(void *a,t_compscale *b,void *c); */
void ScaleGlue(void *a,Word b,void *c,Word d,Word e,Word f,Word g);
/*
; R3 = ArtPtr
; R4 = Maxlines
; R5 = ScreenPtr
; R6 = Frac
; R7 = Integer
; R8 = VideoWidth
; R9 = Delta
*/
#if 0
void IO_ScaleWallColumn(Word x,Word scale,LongWord column)
{
Word TheFrac;
Word TheInt;
Word y;
Byte *ArtStart;
if (scale) { /* Uhh.. Don't bother */
scale*=2;
TheFrac = 0x80000000UL / scale;
ArtStart = &ArtData[(column>>7)&0x3f][(column&127)<<7];
if (scale<VIEWHEIGHT) {
y = (VIEWHEIGHT-scale)/2;
TheInt = TheFrac>>24;
TheFrac <<= 8;
ScaleGlue(ArtStart,scale,
&VideoPointer[(y*VideoWidth)+x],
TheFrac,
TheInt,
VideoWidth,
0
);
return;
}
y = (scale-VIEWHEIGHT)/2; /* How manu lines to remove */
y = y*TheFrac;
TheInt = TheFrac>>24;
TheFrac <<= 8;
ScaleGlue(&ArtStart[y>>24],VIEWHEIGHT,
&VideoPointer[x],
TheFrac,
TheInt,
VideoWidth,
y<<8
);
}
}
#endif
/**********************************
Draw a vertical line with a masked scaler
(Used for SPRITE drawing)
**********************************/
typedef struct {
unsigned short Topy;
unsigned short Boty;
unsigned short Shape;
} SpriteRun;
void SpriteGlue(Byte *a,Word b,Word c,Byte *d,Word e,Word f);
/*
SGArtStart EQU R3 ;Pointer to the 6 byte run structure
SGFrac EQU R4 ;Pointer to the scaler
SGInteger EQU R5 ;Pointer to the video
SGScreenPtr EQU R6 ;Pointer to the run base address
SGCount EQU R7
SGDelta EQU R8
*/
void IO_ScaleMaskedColumn(Word x,Word scale,unsigned short *CharPtr,Word column)
{
Byte * CharPtr2;
int Y1,Y2;
Byte *Screenad;
SpriteRun *RunPtr;
Word TheFrac;
Word TFrac;
Word TInt;
Word RunCount;
int TopY;
Word Index;
Word Delta;
if (!scale) {
return;
}
CharPtr2 = (Byte *) CharPtr;
TheFrac = ScaleDiv[scale]; /* Get the scale fraction */
RunPtr = (SpriteRun *) &CharPtr[CharPtr[column+1]/2]; /* Get the offset to the RunPtr data */
Screenad = &VideoPointer[x]; /* Set the base screen address */
TFrac = TheFrac<<8;
TInt = TheFrac>>24;
TopY = (VIEWHEIGHT/2)-scale; /* Number of pixels for 128 pixel shape */
while (RunPtr->Topy != (unsigned short) -1) { /* Not end of record? */
Y1 = scale*(LongWord)RunPtr->Topy/128+TopY;
if (Y1<(int)VIEWHEIGHT) { /* Clip top? */
Y2 = scale*(LongWord)RunPtr->Boty/128+TopY;
if (Y2>0) {
if (Y2>(int)VIEWHEIGHT) {
Y2 = VIEWHEIGHT;
}
Index = RunPtr->Shape+(RunPtr->Topy/2);
Delta = 0;
if (Y1<0) {
Delta = (0-(Word)Y1)*TheFrac;
Index += (Delta>>24);
Delta <<= 8;
Y1 = 0;
}
RunCount = Y2-Y1;
if (RunCount) {
SpriteGlue(
&CharPtr2[Index], /* Pointer to art data */
TFrac, /* Fractional value */
TInt, /* Integer value */
&Screenad[Y1*VideoWidth], /* Pointer to screen */
RunCount, /* Number of lines to draw */
Delta /* Delta value */
);
}
}
}
RunPtr++; /* Next record */
}
}
/**********************************
Draw an automap tile
**********************************/
Byte *SmallFontPtr;
void DrawSmall(Word x,Word y,Word tile)
{
Byte *Screenad;
Byte *ArtStart;
Word Width,Height;
if (!SmallFontPtr) {
return;
}
x*=16;
y*=16;
Screenad = &VideoPointer[YTable[y]+x];
ArtStart = &SmallFontPtr[tile*(16*16)];
Height = 0;
do {
Width = 16;
do {
Screenad[0] = ArtStart[0];
++Screenad;
++ArtStart;
} while (--Width);
Screenad+=VideoWidth-16;
} while (++Height<16);
}
void MakeSmallFont(void)
{
Word i,j,Width,Height;
Byte *DestPtr,*ArtStart;
Byte *TempPtr;
SmallFontPtr = AllocSomeMem(16*16*65);
if (!SmallFontPtr) {
return;
}
memset(SmallFontPtr,0,16*16*65); /* Erase the font */
i = 0;
DestPtr = SmallFontPtr;
do {
ArtStart = &ArtData[i][0];
if (!ArtStart) {
DestPtr+=(16*16);
} else {
Height = 0;
do {
Width = 16;
j = Height*8;
do {
DestPtr[0] = ArtStart[j];
++DestPtr;
j+=(WALLHEIGHT*8);
} while (--Width);
} while (++Height<16);
}
} while (++i<64);
TempPtr = LoadAResource(MyBJFace);
memcpy(DestPtr,TempPtr,16*16);
ReleaseAResource(MyBJFace);
#if 0
TempPtr = AllocSomeMem(16*16*128);
memset(TempPtr,-1,16*16*128);
i = 0;
do {
memcpy(&TempPtr[(i+1)*256],&SmallFontPtr[(i*2)*256],256);
} while (++i<29);
i = 0;
do {
memcpy(&TempPtr[((i*2)+90)*256],&SmallFontPtr[(i+59)*256],256);
memcpy(&TempPtr[((i*2)+91)*256],&SmallFontPtr[(i+59)*256],256);
} while (++i<4);
SaveJunk(TempPtr,256*128);
FreeSomeMem(TempPtr);
#endif
}
void KillSmallFont(void)
{
if (SmallFontPtr) {
FreeSomeMem(SmallFontPtr);
SmallFontPtr=0;
}
}
#include "wolfdef.h"
/**********************************
Returns True if a straight line between the player and actor is unobstructed
**********************************/
Boolean CheckLine(actor_t *ActorPtr)
{
Word actorx,actory,actortx,actorty; /* Current actor's coords */
Word playerx,playery,playertx,playerty; /* Player's coords */
Word xl,xh,yl,yh; /* Min x,y Max x,y for test */
int delta; /* Pixel differance to calc Step and Frac */
int Step; /* Step value for each whole xy */
Word Frac; /* Fractional xy stepper */
Word deltafrac; /* True distance for whole numbers */
Word intercept; /* Temp for door code */
Word tile; /* Temp for tile check */
Byte partial; /* Fraction to force whole numbers */
actorx = ActorPtr->x; /* Get the actor's x,y */
actortx = actorx>>FRACBITS; /* Get the actor's tile x,y */
actory = ActorPtr->y;
actorty = actory>>FRACBITS;
playerx = actors[0].x; /* Get the player's x,y */
playertx = playerx>>FRACBITS; /* Get the player's tile x,y */
playery = actors[0].y;
playerty = playery>>FRACBITS;
/* The actor COULD be standing on a blocked tile (On a CLOSING door tile) */
#if 0
if (tilemap[actorty][actortx] & TI_BLOCKSIGHT) { /* Is the actor IN a wall? */
return FALSE; /* This could happen on a closing door */
}
#endif
/* check for solid tiles at x crossings */
if (playertx!=actortx) { /* Scan in the x direction? */
if (actortx<playertx) {
partial = -actorx; /* Isolate the fraction */
xl = actortx-1; /* Actor is on the left side */
xh = playertx-1;
yl = actory;
yh = playery;
deltafrac = playerx-actorx; /* Distance in pixels */
} else {
partial = -playerx;
xl = playertx; /* Player is on the left side */
xh = actortx;
yl = playery;
yh = actory;
deltafrac = actorx-playerx; /* Distance in pixels */
}
delta = yh-yl; /* Y adjust (Signed) */
if (w_abs(delta) >= (16*FRACUNIT) || deltafrac >= (16*FRACUNIT)) { /* Farther than 16 tiles? */
return FALSE;
}
Step = FixedDiv(delta,deltafrac); /* How much to y step */
Frac = FixedByFrac(Step,partial)+yl; /* Init the Y coord */
do {
++xl;
tile = tilemap[Frac>>FRACBITS][xl]; /* Get the current tile */
if (tile & TI_BLOCKSIGHT) {
return FALSE; /* Can't see! */
}
if (tile & TI_DOOR) { /* see if the door is open enough*/
intercept = ((Step/2)+Frac)&0xff;
if (intercept > doors[tile&TI_NUMMASK].position) {
return FALSE; /* Can't see! */
}
}
Frac += Step;
} while (xl<xh);
}
/* check for solid tiles at y crossings */
if (playerty!=actorty) {
if (actorty<playerty) {
partial = -actory;
xl = actorx;
xh = playerx;
yl = actorty-1;
yh = playerty-1;
deltafrac = playery-actory;
} else {
partial = -playery;
xl = playerx;
xh = actorx;
yl = playerty;
yh = actorty;
deltafrac = actory-playery;
}
delta = xh-xl; /* Number of tiles to scan */
if (w_abs(delta) >= 16*FRACUNIT || deltafrac >= 16*FRACUNIT) {
return FALSE;
}
Step = FixedDiv(delta,deltafrac);
Frac = FixedByFrac(Step,partial)+xl;
do {
++yl;
tile = tilemap[yl][Frac>>FRACBITS];
if (tile & TI_BLOCKSIGHT) {
return FALSE;
}
if (tile & TI_DOOR) { /* see if the door is open enough*/
intercept = ((Step/2)+Frac)&0xff;
if (intercept > doors[tile&TI_NUMMASK].position) {
return FALSE; /* Can't see! */
}
}
Frac += Step;
} while (yl<yh);
}
return TRUE; /* You are visible */
}
/**********************************
Puts actor into attack mode, either after reaction time or being shot
**********************************/
void FirstSighting(actor_t *ActorPtr)
{
classinfo_t *info;
Word sound;
info = &classinfo[ActorPtr->class]; /* Get pointer to info record */
sound = info->sightsound; /* Get the requested sound */
if (sound == SND_ESEE) { /* make random human sound*/
sound = NaziSound[w_rnd()&3]; /* Make a differant sound */
}
PlaySound(sound|0x8000); /* Play the sight sound */
NewState(ActorPtr,info->sightstate); /* Set the next state */
ActorPtr->flags |= FL_ACTIVE; /* Make it active */
}
/**********************************
Called by actors that ARE NOT chasing the player. If the player
is detected (by sight, noise, or proximity), the actor is put into
it's combat frame.
Incorporates a random reaction delay.
**********************************/
void T_Stand(actor_t *ActorPtr)
{
if (ActorPtr->reacttime) { /* Waiting to react? */
if (ActorPtr->reacttime>TicCount) { /* Still waiting? */
ActorPtr->reacttime-=TicCount; /* Count down */
return;
}
if (ActorPtr->flags&FL_AMBUSH ) { /* Ambush actor? */
if (!CheckLine(ActorPtr)) { /* Can I see you? */
ActorPtr->reacttime=1; /* be very ready, but*/
return; /* don't attack yet*/
}
ActorPtr->flags &= ~FL_AMBUSH; /* Clear the ambush flag */
}
FirstSighting(ActorPtr); /* Attack the player! */
ActorPtr->reacttime=0;
}
/* Haven't seen player yet*/
if (madenoise || CheckLine(ActorPtr)) { /* Made a gun shot? Seen? */
ActorPtr->reacttime = (w_rnd() & classinfo[ActorPtr->class].reactionmask)*4+1;
}
}
#include "WolfDef.h"
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <ctype.h>
/**********************************
Prepare the screen for game
**********************************/
void SetupPlayScreen (void)
{
SetAPalette(rBlackPal); /* Force black palette */
ClearTheScreen(BLACK); /* Clear the screen to black */
BlastScreen();
firstframe = 1; /* fade in after drawing first frame */
GameViewSize = NewGameWindow(GameViewSize);
}
/**********************************
Display the automap
**********************************/
void RunAutoMap(void)
{
Word vx,vy;
Word Width,Height;
Word CenterX,CenterY;
Word oldjoy,newjoy;
MakeSmallFont(); /* Make the tiny font */
playstate = EX_AUTOMAP;
vx = viewx>>8; /* Get my center x,y */
vy = viewy>>8;
Width = (SCREENWIDTH/16); /* Width of map in tiles */
Height = (VIEWHEIGHT/16); /* Height of map in tiles */
CenterX = Width/2;
CenterY = Height/2;
if (vx>=CenterX) {
vx -= CenterX;
} else {
vx = 0;
}
if (vy>=CenterY) {
vy -= CenterY;
} else {
vy = 0;
}
oldjoy = joystick1;
do {
ClearTheScreen(BLACK);
DrawAutomap(vx,vy);
do {
ReadSystemJoystick();
} while (joystick1==oldjoy);
oldjoy &= joystick1;
newjoy = joystick1 ^ oldjoy;
if (newjoy & (JOYPAD_START|JOYPAD_SELECT|JOYPAD_A|JOYPAD_B|JOYPAD_X|JOYPAD_Y)) {
playstate = EX_STILLPLAYING;
}
if (newjoy & JOYPAD_UP && vy) {
--vy;
}
if (newjoy & JOYPAD_LFT && vx) {
--vx;
}
if (newjoy & JOYPAD_RGT && vx<(MAPSIZE-1)) {
++vx;
}
if (newjoy & JOYPAD_DN && vy <(MAPSIZE-1)) {
++vy;
}
} while (playstate==EX_AUTOMAP);
playstate = EX_STILLPLAYING;
/* let the player scroll around until the start button is pressed again */
KillSmallFont(); /* Release the tiny font */
RedrawStatusBar();
ReadSystemJoystick();
mousex = 0;
mousey = 0;
mouseturn = 0;
}
/**********************************
Begin a new game
**********************************/
void StartGame(void)
{
if (playstate!=EX_LOADGAME) { /* Variables already preset */
NewGame(); /* init basic game stuff */
}
SetupPlayScreen();
GameLoop(); /* Play the game */
StopSong(); /* Make SURE music is off */
}
/**********************************
Show the game logo
**********************************/
Boolean TitleScreen (void)
{
Word RetVal; /* Value to return */
LongWord PackLen;
LongWord *PackPtr;
Byte *ShapePtr;
playstate = EX_LIMBO; /* Game is not in progress */
NewGameWindow(1); /* Set to 512 mode */
FadeToBlack(); /* Fade out the video */
PackPtr = LoadAResource(rTitlePic);
PackLen = PackPtr[0];
ShapePtr = (Byte *)AllocSomeMem(PackLen);
DLZSS(ShapePtr,(Byte *) &PackPtr[1],PackLen);
DrawShape(0,0,ShapePtr);
ReleaseAResource(rTitlePic);
FreeSomeMem(ShapePtr);
BlastScreen();
StartSong(SongListPtr[0]);
FadeTo(rTitlePal); /* Fade in the picture */
BlastScreen();
RetVal = WaitTicksEvent(0); /* Wait for event */
playstate = EX_COMPLETED;
return TRUE; /* Return True if canceled */
}
/**********************************
Main entry point for the game (Called after InitTools)
**********************************/
jmp_buf ResetJmp;
Boolean JumpOK;
extern Word NumberIndex;
void main(void)
{
InitTools(); /* Init the system environment */
WaitTick(); /* Wait for a system tick to go by */
playstate = (exit_t)setjmp(ResetJmp);
NumberIndex = 36; /* Force the score to redraw properly */
IntermissionHack = FALSE;
if (playstate) {
goto DoGame; /* Begin a new game or saved game */
}
JumpOK = TRUE; /* Jump vector is VALID */
FlushKeys(); /* Allow a system event */
Intro(); /* Do the game intro */
for (;;) {
if (TitleScreen()) { /* Show the game logo */
StartSong(SongListPtr[0]);
ClearTheScreen(BLACK); /* Blank out the title page */
BlastScreen();
SetAPalette(rBlackPal);
if (ChooseGameDiff()) { /* Choose your difficulty */
playstate = EX_NEWGAME; /* Start a new game */
DoGame:
FadeToBlack(); /* Fade the screen */
StartGame(); /* Play the game */
}
}
}
}
/* generated by sndlink.exe */
enum {
SND_NOSOUND,
SND_THROWSWITCH, /* Throw end level switch */
SND_GETKEY, /* Pick up a key */
SND_BONUS, /* Score ding */
SND_OPENDOOR, /* Open a door */
SND_DOGBARK, /* Dog bite */
SND_DOGDIE, /* Dog die */
SND_ESEE, /* Ahtung! */
SND_ESEE2, /* Halt! */
SND_EDIE, /* Nazi died */
SND_EDIE2, /* Nazi died 2 */
SND_BODYFALL, /* Body hit the ground */
SND_PAIN, /* Hit bad guy */
SND_GETAMMO, /* Pick up ammo */
SND_KNIFE, /* Knife attack */
SND_GUNSHT, /* 45 Shoot */
SND_MGUN, /* Sub machine gun */
SND_CHAIN, /* Chain gun */
SND_FTHROW, /* Flame thrower */
SND_ROCKET, /* Rocket launcher */
SND_PWALL, /* Start pushwall */
SND_PWALL2, /* Stop pushwall */
SND_GUTEN, /* Guten tag */
SND_SHIT, /* Shit! */
SND_HEAL, /* Healed a bit */
SND_THUMBSUP, /* You stud you! */
SND_EXTRA, /* Extra guy */
SND_OUCH1, /* BJ has beed injured */
SND_OUCH2, /* Second sound */
SND_PDIE, /* BJ has died */
SND_HITWALL, /* Tried to open a wall */
SND_KNIFEMISS, /* Knife missed */
SND_BIGGUN, /* Boss's gun */
SND_COMEHERE, /* Come here! */
SND_ESEE3, /* Nazi sees you */
SND_ESEE4, /* Nazi sees you */
SND_OK, /* Hit start game */
SND_MENU, /* New game menu */
SND_HITLERSEE, /* Hitler sees you */
SND_SHITHEAD, /* Big boss sees you */
SND_BOOM, /* Explosion */
SND_LOCKEDDOOR, /* Locked door */
SND_MECHSTEP, /* Mech step */
NUMSOUNDS };
/* generated by sprgrab */
enum {
S_NONE,
S_MISSILE,
S_MISSBOOM,
S_GAMEOVER,
S_ENMISSILE,
S_FIREBALL,
S_FIREBOOM,
S_NEEDLE,
S_VICTORY,
S_DKNIGHT_ATK1,
S_DKNIGHT_ATK2,
S_DKNIGHT_ATK3,
S_DKNIGHT_ATK4,
S_DKNIGHT_WLK1,
S_DKNIGHT_WLK2,
S_DKNIGHT_WLK3,
S_DKNIGHT_WLK4,
S_DKNIGHT_DTH1,
S_DKNIGHT_DTH2,
S_DKNIGHT_DTH3,
S_DOG_ATK1,
S_DOG_ATK2,
S_DOG_ATK3,
S_DOG_WLK1,
S_DOG_WLK2,
S_DOG_WLK3,
S_DOG_WLK4,
S_DOG_DTH1,
S_DOG_DTH2,
S_DOG_DTH3,
S_GUARD_ATK1,
S_GUARD_ATK2,
S_GUARD_ATK3,
S_GUARD_WLK1,
S_GUARD_WLK2,
S_GUARD_WLK3,
S_GUARD_WLK4,
S_GUARD_PAIN,
S_GUARD_DTH1,
S_GUARD_DTH2,
S_GUARD_DTH3,
S_HANS_ATK1,
S_HANS_ATK2,
S_HANS_ATK3,
S_HANS_WLK1,
S_HANS_WLK2,
S_HANS_WLK3,
S_HANS_WLK4,
S_HANS_DTH1,
S_HANS_DTH2,
S_HANS_DTH3,
S_HITLER_ATK1,
S_HITLER_ATK2,
S_HITLER_ATK3,
S_HITLER_WLK1,
S_HITLER_WLK2,
S_HITLER_WLK3,
S_HITLER_WLK4,
S_HITLER_DTH1,
S_HITLER_DTH2,
S_HITLER_DTH3,
S_UBER_ATK1,
S_UBER_ATK2,
S_UBER_ATK3,
S_UBER_ATK4,
S_UBER_WLK1,
S_UBER_WLK2,
S_UBER_WLK3,
S_UBER_WLK4,
S_UBER_DTH1,
S_UBER_DTH2,
S_UBER_DTH3,
S_MHITLER_ATK1,
S_MHITLER_ATK2,
S_MHITLER_ATK3,
S_MHITLER_DIE1,
S_MHITLER_DIE2,
S_MHITLER_DIE3,
S_MHITLER_DIE4,
S_MHITLER_WLK1,
S_MHITLER_WLK2,
S_MHITLER_WLK3,
S_MHITLER_WLK4,
S_MUTANT_ATK1,
S_MUTANT_ATK2,
S_MUTANT_ATK3,
S_MUTANT_WLK1,
S_MUTANT_WLK2,
S_MUTANT_WLK3,
S_MUTANT_WLK4,
S_MUTANT_PAIN,
S_MUTANT_DTH1,
S_MUTANT_DTH2,
S_MUTANT_DTH3,
S_OFFICER_ATK1,
S_OFFICER_ATK2,
S_OFFICER_ATK3,
S_OFFICER_WLK1,
S_OFFICER_WLK2,
S_OFFICER_WLK3,
S_OFFICER_WLK4,
S_OFFICER_PAIN,
S_OFFICER_DTH1,
S_OFFICER_DTH2,
S_OFFICER_DTH3,
S_SCHABBS_ATK1,
S_SCHABBS_ATK2,
S_SCHABBS_WLK1,
S_SCHABBS_WLK2,
S_SCHABBS_WLK3,
S_SCHABBS_WLK4,
S_SCHABBS_DTH1,
S_SCHABBS_DTH2,
S_SCHABBS_DTH3,
S_SS_ATK1,
S_SS_ATK2,
S_SS_ATK3,
S_SS_WLK1,
S_SS_WLK2,
S_SS_WLK3,
S_SS_WLK4,
S_SS_PAIN,
S_SS_DTH1,
S_SS_DTH2,
S_SS_DTH3,
S_TRANS_ATK1,
S_TRANS_ATK2,
S_TRANS_ATK3,
S_TRANS_WLK1,
S_TRANS_WLK2,
S_TRANS_WLK3,
S_TRANS_WLK4,
S_TRANS_DTH1,
S_TRANS_DTH2,
S_TRANS_DTH3,
S_WATER_PUDDLE,
S_GREEN_BARREL,
S_CHAIR_TABLE,
S_FLOOR_LAMP,
S_CHANDELIER,
S_DOG_FOOD,
S_COLLUMN,
S_POTTED_TREE,
S_FLAG,
S_POTTED_PLANT,
S_BLUE_POT,
S_DEBRIS1,
S_LIGHT,
S_BUCKET,
S_ARMOUR,
S_CAGE,
S_G_KEY,
S_S_KEY,
S_BANDOLIER,
S_AMMOCASE,
S_FOOD,
S_HEALTH,
S_AMMO,
S_MACHINEGUN,
S_CHAINGUN,
S_CROSS,
S_CHALICE,
S_CHEST,
S_CROWN,
S_ONEUP,
S_WOOD_BARREL,
S_WATER_WELL,
S_FLAMETHROWER,
S_GASCAN,
S_LAUNCHER,
S_MISSILES,
S_LASTONE
};
#include "wolfdef.h"
state_t states[NUMSTATES] = {
{S_GUARD_WLK4, 0, T_STAND, A_NULL, ST_GRD_STND},
{S_GUARD_WLK1,12, T_CHASE, A_TARGET, ST_GRD_WLK2},
{S_GUARD_WLK2,12, T_CHASE, A_TARGET, ST_GRD_WLK3},
{S_GUARD_WLK3,12, T_CHASE, A_TARGET, ST_GRD_WLK4},
{S_GUARD_WLK4,12, T_CHASE, A_TARGET, ST_GRD_WLK1},
{S_GUARD_ATK1,16, T_NULL, A_NULL, ST_GRD_ATK2},
{S_GUARD_ATK2,16, T_NULL, A_NULL, ST_GRD_ATK3},
{S_GUARD_ATK3,16, T_NULL, A_SHOOT, ST_GRD_WLK1},
{S_GUARD_PAIN,12, T_NULL, A_NULL, ST_GRD_WLK1},
{S_GUARD_PAIN, 8, T_NULL, A_NULL, ST_GRD_DTH1},
{S_GUARD_DTH1, 8, T_NULL, A_SCREAM, ST_GRD_DTH2},
{S_GUARD_DTH2, 8, T_NULL, A_THUD, ST_GRD_DTH3},
{S_GUARD_DTH3, 0, T_NULL, A_NULL, ST_GRD_DTH3},
{S_DOG_WLK4, 0, T_STAND, A_NULL, ST_DOG_STND},
{S_DOG_WLK1, 8, T_CHASE, A_TARGET, ST_DOG_WLK2},
{S_DOG_WLK2, 8, T_CHASE, A_TARGET, ST_DOG_WLK3},
{S_DOG_WLK3, 8, T_CHASE, A_TARGET, ST_DOG_WLK4},
{S_DOG_WLK4, 8, T_CHASE, A_TARGET, ST_DOG_WLK1},
{S_DOG_ATK1, 8, T_NULL, A_NULL, ST_DOG_ATK2},
{S_DOG_ATK2, 8, T_NULL, A_NULL, ST_DOG_ATK3},
{S_DOG_ATK3,20, T_NULL, A_BITE, ST_DOG_ATK4},
{S_DOG_WLK1, 8, T_NULL, A_NULL, ST_DOG_WLK1},
{S_DOG_DTH1, 8, T_NULL, A_NULL, ST_DOG_DTH2},
{S_DOG_DTH2, 8, T_NULL, A_SCREAM, ST_DOG_DTH3},
{S_DOG_DTH3, 8, T_NULL, A_THUD, ST_DOG_DTH4},
{S_DOG_DTH3, 0, T_NULL, A_NULL, ST_DOG_DTH4},
{S_SS_WLK4, 0, T_STAND, A_NULL, ST_SS_STND},
{S_SS_WLK1,20, T_CHASE, A_TARGET, ST_SS_WLK2},
{S_SS_WLK2,20, T_CHASE, A_TARGET, ST_SS_WLK3},
{S_SS_WLK3,20, T_CHASE, A_TARGET, ST_SS_WLK4},
{S_SS_WLK4,20, T_CHASE, A_TARGET, ST_SS_WLK1},
{S_SS_ATK1,20, T_NULL, A_NULL, ST_SS_ATK2},
{S_SS_ATK2,20, T_NULL, A_NULL, ST_SS_ATK3},
{S_SS_ATK3, 8, T_NULL, A_SHOOT, ST_SS_ATK4},
{S_SS_ATK2, 8, T_NULL, A_NULL, ST_SS_ATK5},
{S_SS_ATK3, 8, T_NULL, A_SHOOT, ST_SS_ATK6},
{S_SS_ATK2, 8, T_NULL, A_NULL, ST_SS_ATK7},
{S_SS_ATK3, 8, T_NULL, A_SHOOT, ST_SS_ATK8},
{S_SS_ATK2, 8, T_NULL, A_NULL, ST_SS_ATK9},
{S_SS_ATK3, 8, T_NULL, A_SHOOT, ST_SS_WLK1},
{S_SS_PAIN, 8, T_NULL, A_NULL, ST_SS_WLK1},
{S_SS_PAIN, 8, T_NULL, A_NULL, ST_SS_DTH1},
{S_SS_DTH1, 8, T_NULL, A_SCREAM, ST_SS_DTH2},
{S_SS_DTH2, 8, T_NULL, A_THUD, ST_SS_DTH3},
{S_SS_DTH3, 0, T_NULL, A_NULL, ST_SS_DTH3},
{S_OFFICER_WLK4, 0, T_STAND, A_NULL, ST_OFC_STND},
{S_OFFICER_WLK1,12, T_CHASE, A_TARGET, ST_OFC_WLK2},
{S_OFFICER_WLK2, 8, T_CHASE, A_TARGET, ST_OFC_WLK3},
{S_OFFICER_WLK3,12, T_CHASE, A_TARGET, ST_OFC_WLK4},
{S_OFFICER_WLK4, 8, T_CHASE, A_TARGET, ST_OFC_WLK1},
{S_OFFICER_ATK1, 8, T_NULL, A_NULL, ST_OFC_ATK2},
{S_OFFICER_ATK2, 8, T_NULL, A_NULL, ST_OFC_ATK3},
{S_OFFICER_ATK3,16, T_NULL, A_SHOOT, ST_OFC_WLK1},
{S_OFFICER_PAIN, 8, T_NULL, A_NULL, ST_OFC_WLK1},
{S_OFFICER_PAIN, 8, T_NULL, A_NULL, ST_OFC_DTH1},
{S_OFFICER_DTH1, 8, T_NULL, A_SCREAM, ST_OFC_DTH2},
{S_OFFICER_DTH2, 8, T_NULL, A_THUD, ST_OFC_DTH3},
{S_OFFICER_DTH3, 0, T_NULL, A_NULL, ST_OFC_DTH3},
{S_MUTANT_WLK4, 0, T_STAND, A_NULL, ST_MUTANT_STND},
{S_MUTANT_WLK1,16, T_CHASE, A_TARGET, ST_MUTANT_WLK2},
{S_MUTANT_WLK2,16, T_CHASE, A_TARGET, ST_MUTANT_WLK3},
{S_MUTANT_WLK3,16, T_CHASE, A_TARGET, ST_MUTANT_WLK4},
{S_MUTANT_WLK4,16, T_CHASE, A_TARGET, ST_MUTANT_WLK1},
{S_MUTANT_ATK1, 8, T_NULL, A_NULL, ST_MUTANT_ATK2},
{S_MUTANT_ATK2,20, T_NULL, A_SHOOT, ST_MUTANT_ATK3},
{S_MUTANT_ATK1, 8, T_NULL, A_NULL, ST_MUTANT_ATK4},
{S_MUTANT_ATK3,20, T_NULL, A_SHOOT, ST_MUTANT_WLK1},
{S_MUTANT_PAIN, 8, T_NULL, A_NULL, ST_MUTANT_WLK1},
{S_MUTANT_PAIN, 8, T_NULL, A_NULL, ST_MUTANT_DTH1},
{S_MUTANT_DTH1, 8, T_NULL, A_SCREAM, ST_MUTANT_DTH2},
{S_MUTANT_DTH2, 8, T_NULL, A_THUD, ST_MUTANT_DTH3},
{S_MUTANT_DTH3, 0, T_NULL, A_NULL, ST_MUTANT_DTH3},
{S_HANS_WLK4, 0, T_STAND, A_NULL, ST_HANS_STND},
{S_HANS_WLK1,20, T_CHASE, A_TARGET, ST_HANS_WLK2},
{S_HANS_WLK2,20, T_CHASE, A_TARGET, ST_HANS_WLK3},
{S_HANS_WLK3,20, T_CHASE, A_TARGET, ST_HANS_WLK4},
{S_HANS_WLK4,20, T_CHASE, A_TARGET, ST_HANS_WLK1},
{S_HANS_ATK1,40, T_NULL, A_NULL, ST_HANS_ATK2},
{S_HANS_ATK2,12, T_NULL, A_SHOOT, ST_HANS_ATK3},
{S_HANS_ATK3,12, T_NULL, A_SHOOT, ST_HANS_ATK4},
{S_HANS_ATK2,12, T_NULL, A_SHOOT, ST_HANS_ATK5},
{S_HANS_ATK3,12, T_NULL, A_SHOOT, ST_HANS_ATK6},
{S_HANS_ATK2,12, T_NULL, A_SHOOT, ST_HANS_ATK7},
{S_HANS_ATK3,12, T_NULL, A_SHOOT, ST_HANS_WLK1},
{S_HANS_DTH1,16, T_NULL, A_SCREAM, ST_HANS_DTH2},
{S_HANS_DTH2,16, T_NULL, A_THUD, ST_HANS_DTH3},
{S_HANS_DTH3, 0, T_NULL, A_NULL, ST_HANS_DTH3},
{S_SCHABBS_WLK4, 0, T_STAND, A_NULL, ST_SCHABBS_STND},
{S_SCHABBS_WLK1,20, T_CHASE, A_TARGET, ST_SCHABBS_WLK2},
{S_SCHABBS_WLK2,20, T_CHASE, A_TARGET, ST_SCHABBS_WLK3},
{S_SCHABBS_WLK3,20, T_CHASE, A_TARGET, ST_SCHABBS_WLK4},
{S_SCHABBS_WLK4,20, T_CHASE, A_TARGET, ST_SCHABBS_WLK1},
{S_SCHABBS_ATK1,28, T_NULL, A_NULL, ST_SCHABBS_ATK2},
{S_SCHABBS_ATK2,12, T_NULL, A_THROW, ST_SCHABBS_WLK1},
{S_SCHABBS_DTH1,16, T_NULL, A_SCREAM, ST_SCHABBS_DTH2},
{S_SCHABBS_DTH2,16, T_NULL, A_THUD, ST_SCHABBS_DTH3},
{S_SCHABBS_DTH3, 0, T_NULL, A_NULL, ST_SCHABBS_DTH3},
{S_TRANS_WLK4, 0, T_STAND, A_NULL, ST_TRANS_STND},
{S_TRANS_WLK1,20, T_CHASE, A_TARGET, ST_TRANS_WLK2},
{S_TRANS_WLK2,20, T_CHASE, A_TARGET, ST_TRANS_WLK3},
{S_TRANS_WLK3,20, T_CHASE, A_TARGET, ST_TRANS_WLK4},
{S_TRANS_WLK4,20, T_CHASE, A_TARGET, ST_TRANS_WLK1},
{S_TRANS_ATK1,48, T_NULL, A_NULL, ST_TRANS_ATK2},
{S_TRANS_ATK2,12, T_NULL, A_SHOOT, ST_TRANS_ATK3},
{S_TRANS_ATK3,12, T_NULL, A_SHOOT, ST_TRANS_ATK4},
{S_TRANS_ATK2,12, T_NULL, A_SHOOT, ST_TRANS_ATK5},
{S_TRANS_ATK3,12, T_NULL, A_SHOOT, ST_TRANS_ATK6},
{S_TRANS_ATK2,12, T_NULL, A_SHOOT, ST_TRANS_ATK7},
{S_TRANS_ATK3,12, T_NULL, A_SHOOT, ST_TRANS_WLK1},
{S_TRANS_DTH1,16, T_NULL, A_SCREAM, ST_TRANS_DTH2},
{S_TRANS_DTH2,16, T_NULL, A_THUD, ST_TRANS_DTH3},
{S_TRANS_DTH3, 0, T_NULL, A_NULL, ST_TRANS_DTH3},
{S_UBER_WLK4, 0, T_STAND, A_NULL, ST_UBER_STND},
{S_UBER_WLK1,12, T_CHASE, A_TARGET, ST_UBER_WLK2},
{S_UBER_WLK2,12, T_CHASE, A_TARGET, ST_UBER_WLK3},
{S_UBER_WLK3,12, T_CHASE, A_TARGET, ST_UBER_WLK4},
{S_UBER_WLK4,12, T_CHASE, A_TARGET, ST_UBER_WLK1},
{S_UBER_ATK1,40, T_NULL, A_NULL, ST_UBER_ATK2},
{S_UBER_ATK2, 8, T_NULL, A_SHOOT, ST_UBER_ATK3},
{S_UBER_ATK3, 8, T_NULL, A_SHOOT, ST_UBER_ATK4},
{S_UBER_ATK2, 8, T_NULL, A_SHOOT, ST_UBER_ATK5},
{S_UBER_ATK3, 8, T_NULL, A_SHOOT, ST_UBER_ATK6},
{S_UBER_ATK2, 8, T_NULL, A_SHOOT, ST_UBER_ATK7},
{S_UBER_ATK3, 8, T_NULL, A_SHOOT, ST_UBER_WLK1},
{S_UBER_DTH1,16, T_NULL, A_SCREAM, ST_UBER_DTH2},
{S_UBER_DTH2,16, T_NULL, A_THUD, ST_UBER_DTH3},
{S_UBER_DTH3, 0, T_NULL, A_NULL, ST_UBER_DTH3},
{S_DKNIGHT_WLK4, 0, T_STAND, A_NULL, ST_DKNIGHT_STND},
{S_DKNIGHT_WLK1,20, T_CHASE, A_TARGET, ST_DKNIGHT_WLK2},
{S_DKNIGHT_WLK2,20, T_CHASE, A_TARGET, ST_DKNIGHT_WLK3},
{S_DKNIGHT_WLK3,20, T_CHASE, A_TARGET, ST_DKNIGHT_WLK4},
{S_DKNIGHT_WLK4,20, T_CHASE, A_TARGET, ST_DKNIGHT_WLK1},
{S_DKNIGHT_ATK1,28, T_NULL, A_NULL, ST_DKNIGHT_ATK2},
{S_DKNIGHT_ATK2,12, T_NULL, A_LAUNCH, ST_DKNIGHT_ATK3},
{S_DKNIGHT_ATK4,12, T_NULL, A_SHOOT, ST_DKNIGHT_ATK4},
{S_DKNIGHT_ATK3,12, T_NULL, A_LAUNCH, ST_DKNIGHT_ATK5},
{S_DKNIGHT_ATK4,12, T_NULL, A_SHOOT, ST_DKNIGHT_WLK1},
{S_DKNIGHT_DTH1,16, T_NULL, A_SCREAM, ST_DKNIGHT_DTH2},
{S_DKNIGHT_DTH2,16, T_NULL, A_THUD, ST_DKNIGHT_DTH3},
{S_DKNIGHT_DTH3, 0, T_NULL, A_NULL, ST_DKNIGHT_DTH3},
{S_MHITLER_WLK4, 0, T_STAND, A_NULL, ST_MHITLER_STND},
{S_MHITLER_WLK1,20, T_CHASE, A_MECHSTEP, ST_MHITLER_WLK2},
{S_MHITLER_WLK2,20, T_CHASE, A_TARGET, ST_MHITLER_WLK3},
{S_MHITLER_WLK3,20, T_CHASE, A_MECHSTEP, ST_MHITLER_WLK4},
{S_MHITLER_WLK4,20, T_CHASE, A_TARGET, ST_MHITLER_WLK1},
{S_MHITLER_ATK1,28, T_NULL, A_NULL, ST_MHITLER_ATK2},
{S_MHITLER_ATK2, 8, T_NULL, A_SHOOT, ST_MHITLER_ATK3},
{S_MHITLER_ATK3, 8, T_NULL, A_SHOOT, ST_MHITLER_ATK4},
{S_MHITLER_ATK2, 8, T_NULL, A_SHOOT, ST_MHITLER_ATK5},
{S_MHITLER_ATK3, 8, T_NULL, A_SHOOT, ST_MHITLER_ATK6},
{S_MHITLER_ATK2, 8, T_NULL, A_SHOOT, ST_MHITLER_ATK7},
{S_MHITLER_ATK3, 8, T_NULL, A_SHOOT, ST_MHITLER_WLK1},
{S_MHITLER_DIE1,12, T_NULL, A_NULL, ST_MHITLER_DIE2},
{S_MHITLER_DIE2,12, T_NULL, A_NULL, ST_MHITLER_DIE3},
{S_MHITLER_DIE3,12, T_NULL, A_NULL, ST_MHITLER_DIE4},
{S_HITLER_WLK4, 8, T_NULL, A_HITLERMORPH, ST_HITLER_WLK1},
{S_HITLER_WLK1,12, T_CHASE, A_TARGET, ST_HITLER_WLK2},
{S_HITLER_WLK2, 8, T_CHASE, A_TARGET, ST_HITLER_WLK3},
{S_HITLER_WLK3,12, T_CHASE, A_TARGET, ST_HITLER_WLK4},
{S_HITLER_WLK4, 8, T_CHASE, A_TARGET, ST_HITLER_WLK1},
{S_HITLER_ATK1,28, T_NULL, A_NULL, ST_HITLER_ATK2},
{S_HITLER_ATK2, 8, T_NULL, A_SHOOT, ST_HITLER_ATK3},
{S_HITLER_ATK3, 8, T_NULL, A_SHOOT, ST_HITLER_ATK4},
{S_HITLER_ATK2, 8, T_NULL, A_SHOOT, ST_HITLER_ATK5},
{S_HITLER_ATK3, 8, T_NULL, A_SHOOT, ST_HITLER_WLK1},
{S_HITLER_DTH1,16, T_NULL, A_SCREAM, ST_HITLER_DTH2},
{S_HITLER_DTH2,16, T_NULL, A_NULL, ST_HITLER_DTH3},
{S_HITLER_DTH3,120,T_NULL, A_THUD, ST_HITLER_DTH4},
{S_HITLER_DTH3, 0, T_NULL, A_VICTORY, ST_HITLER_DTH4}
};
/* generated by statescr*/
typedef enum {
ST_GRD_STND,
ST_GRD_WLK1,
ST_GRD_WLK2,
ST_GRD_WLK3,
ST_GRD_WLK4,
ST_GRD_ATK1,
ST_GRD_ATK2,
ST_GRD_ATK3,
ST_GRD_PAIN,
ST_GRD_DIE,
ST_GRD_DTH1,
ST_GRD_DTH2,
ST_GRD_DTH3,
ST_DOG_STND,
ST_DOG_WLK1,
ST_DOG_WLK2,
ST_DOG_WLK3,
ST_DOG_WLK4,
ST_DOG_ATK1,
ST_DOG_ATK2,
ST_DOG_ATK3,
ST_DOG_ATK4,
ST_DOG_DIE,
ST_DOG_DTH2,
ST_DOG_DTH3,
ST_DOG_DTH4,
ST_SS_STND,
ST_SS_WLK1,
ST_SS_WLK2,
ST_SS_WLK3,
ST_SS_WLK4,
ST_SS_ATK1,
ST_SS_ATK2,
ST_SS_ATK3,
ST_SS_ATK4,
ST_SS_ATK5,
ST_SS_ATK6,
ST_SS_ATK7,
ST_SS_ATK8,
ST_SS_ATK9,
ST_SS_PAIN,
ST_SS_DIE,
ST_SS_DTH1,
ST_SS_DTH2,
ST_SS_DTH3,
ST_OFC_STND,
ST_OFC_WLK1,
ST_OFC_WLK2,
ST_OFC_WLK3,
ST_OFC_WLK4,
ST_OFC_ATK1,
ST_OFC_ATK2,
ST_OFC_ATK3,
ST_OFC_PAIN,
ST_OFC_DIE,
ST_OFC_DTH1,
ST_OFC_DTH2,
ST_OFC_DTH3,
ST_MUTANT_STND,
ST_MUTANT_WLK1,
ST_MUTANT_WLK2,
ST_MUTANT_WLK3,
ST_MUTANT_WLK4,
ST_MUTANT_ATK1,
ST_MUTANT_ATK2,
ST_MUTANT_ATK3,
ST_MUTANT_ATK4,
ST_MUTANT_PAIN,
ST_MUTANT_DIE,
ST_MUTANT_DTH1,
ST_MUTANT_DTH2,
ST_MUTANT_DTH3,
ST_HANS_STND,
ST_HANS_WLK1,
ST_HANS_WLK2,
ST_HANS_WLK3,
ST_HANS_WLK4,
ST_HANS_ATK1,
ST_HANS_ATK2,
ST_HANS_ATK3,
ST_HANS_ATK4,
ST_HANS_ATK5,
ST_HANS_ATK6,
ST_HANS_ATK7,
ST_HANS_DIE,
ST_HANS_DTH2,
ST_HANS_DTH3,
ST_SCHABBS_STND,
ST_SCHABBS_WLK1,
ST_SCHABBS_WLK2,
ST_SCHABBS_WLK3,
ST_SCHABBS_WLK4,
ST_SCHABBS_ATK1,
ST_SCHABBS_ATK2,
ST_SCHABBS_DIE,
ST_SCHABBS_DTH2,
ST_SCHABBS_DTH3,
ST_TRANS_STND,
ST_TRANS_WLK1,
ST_TRANS_WLK2,
ST_TRANS_WLK3,
ST_TRANS_WLK4,
ST_TRANS_ATK1,
ST_TRANS_ATK2,
ST_TRANS_ATK3,
ST_TRANS_ATK4,
ST_TRANS_ATK5,
ST_TRANS_ATK6,
ST_TRANS_ATK7,
ST_TRANS_DIE,
ST_TRANS_DTH2,
ST_TRANS_DTH3,
ST_UBER_STND,
ST_UBER_WLK1,
ST_UBER_WLK2,
ST_UBER_WLK3,
ST_UBER_WLK4,
ST_UBER_ATK1,
ST_UBER_ATK2,
ST_UBER_ATK3,
ST_UBER_ATK4,
ST_UBER_ATK5,
ST_UBER_ATK6,
ST_UBER_ATK7,
ST_UBER_DIE,
ST_UBER_DTH2,
ST_UBER_DTH3,
ST_DKNIGHT_STND,
ST_DKNIGHT_WLK1,
ST_DKNIGHT_WLK2,
ST_DKNIGHT_WLK3,
ST_DKNIGHT_WLK4,
ST_DKNIGHT_ATK1,
ST_DKNIGHT_ATK2,
ST_DKNIGHT_ATK3,
ST_DKNIGHT_ATK4,
ST_DKNIGHT_ATK5,
ST_DKNIGHT_DIE,
ST_DKNIGHT_DTH2,
ST_DKNIGHT_DTH3,
ST_MHITLER_STND,
ST_MHITLER_WLK1,
ST_MHITLER_WLK2,
ST_MHITLER_WLK3,
ST_MHITLER_WLK4,
ST_MHITLER_ATK1,
ST_MHITLER_ATK2,
ST_MHITLER_ATK3,
ST_MHITLER_ATK4,
ST_MHITLER_ATK5,
ST_MHITLER_ATK6,
ST_MHITLER_ATK7,
ST_MHITLER_DIE1,
ST_MHITLER_DIE2,
ST_MHITLER_DIE3,
ST_MHITLER_DIE4,
ST_HITLER_WLK1,
ST_HITLER_WLK2,
ST_HITLER_WLK3,
ST_HITLER_WLK4,
ST_HITLER_ATK1,
ST_HITLER_ATK2,
ST_HITLER_ATK3,
ST_HITLER_ATK4,
ST_HITLER_ATK5,
ST_HITLER_DIE,
ST_HITLER_DTH2,
ST_HITLER_DTH3,
ST_HITLER_DTH4,
NUMSTATES
} stateindex_t;
;
; Assembly language functions for wolf 3-D
; By Bill Heineman
; 9-12-94 (Rev to use tight loop for scale code)
;
; Call the compiled scaler
; void ScaleGlue(void *TextPtr,t_compscale *CodePtr);
;
CASE ON
WALLHEIGHT EQU 128+1
EXPORT IO_ScaleWallColumn
EXPORT SpriteGlue
IMPORT VideoPointer:DATA
IMPORT VideoWidth:DATA
IMPORT ScaleDiv:DATA
IMPORT ArtData:DATA
IMPORT MacViewHeight:DATA
IO_ScaleWallColumn PROC
Adder1 EQU 20
ParmX EQU 4+Adder1
ParmScale EQU 6+Adder1
ParmTile EQU 8+Adder1
ParmColumn EQU 10+Adder1
;
; D0 = Temp, A0 = Temp
;
RegScrn EQU A0 ;Pointer to the screen
RegArt2 EQU A1 ;True pointer to art
RegArt EQU D1 ;Offset into the shape
RegDelta EQU D2 ;Delta counter
RegFrac EQU D3 ;Fixed point fraction
RegInt EQU D4 ;Fixed point integer
RegVidWidth EQU D5 ;Width of the screen in bytes
RegScale EQU D6 ;Scale factor
MOVEM.L D2-D6,-(A7) ;Save my registers
MOVE.L #0,RegScale ;Force scale to a long value
MOVE.W ParmScale(A7),RegScale ;Preload the scale factor
CMP.W #0,RegScale ;Scale of zero?
BEQ.S ByeBye ;Exit now! (Can't draw zero height)
MOVE.W ParmX(A7),D0 ;Get the X coord
MOVE.L VideoPointer,RegScrn ;Init the screen pointer
ADD.W D0,RegScrn ;Add the X coord
MOVE.W VideoWidth,RegVidWidth ;Init the video width
LEA ScaleDiv,RegArt2 ;Get pointer to the scaler recipocal table
MOVE.W RegScale,D0 ;Place scale value in temp
LSL.W #2,D0 ;Mul by 4 for longword index
MOVE.L (RegArt2,D0.W),RegFrac ;Get the precalced fraction
ADD.W RegScale,RegScale ;Convert scale to pixel value
MOVE.W ParmColumn(A7),RegArt ;Get the column index to the art
LSL.W #7,RegArt ;I have the pixel index
MOVE.W ParmTile(A7),D0
LSL.W #2,D0 ;Shift down 7 up 2
LEA ArtData,RegArt2 ;Get pointer to my shape ptr array
MOVE.L (RegArt2,D0.W),RegArt2 ;Get the base pointer to the art in A2
MOVE.W MacViewHeight,D0 ;Get the height
CMP.W D0,RegScale ;Clipping needed?
BCC.S ClipTop ;Do the clipped version
SUB.W RegScale,D0 ;How many line are clear?
LSR.W #1,D0 ;Number of lines to jump DOWN (Center it)
MULU.W RegVidWidth,D0 ;Mul by bytes per line
ADD.L D0,RegScrn ;Add to the screen pointer
MOVE.L RegFrac,RegInt ;Copy the full fixed point number
SWAP RegInt ;Isolate the integer
MOVE.W #0,RegDelta ;Zap the delta
SUB.W #1,RegScale ;-1 from the count for DBF
;
; This is the tight loop that draws the scaled line
; RegArt2/RegArt = Source ptr
; RegScrn = Video pointer
; RegFrac = Scale fraction
; RegInt = Scale integer
; RegDelta = Scale delta
; RegScale = Pixel count (Max MacViewHeight)
;
Loopy
MOVE.B (RegArt2,RegArt.W),D0 ;Move shape byte
MOVE.B D0,(RegScrn)
ADD.W RegFrac,RegDelta ;Adjust the delta
ADDX.W RegInt,RegArt ;Adjust the source byte offset
ADD.W RegVidWidth,RegScrn ;Next dest scan line
DBF RegScale,Loopy ;Still more?
ByeBye ;Exit
MOVEM.L (A7)+,D2-D6
RTS
ClipTop
SUB.W D0,RegScale ;Number of lines clipped
LSR.W #1,RegScale ;True number of lines skipped from top
MOVE.W RegFrac,RegDelta ;Init the delta for the mul
MULU.W RegScale,RegDelta ;Make the new delta for skipped lines
MOVE.L RegDelta,D0 ;Copy the delta
SWAP D0 ;Isolate the integer
ADD.W D0,RegArt ;Skip the hidden lines
MOVE.L RegFrac,D0
SWAP D0
MULU.W RegScale,D0
ADD.W D0,RegArt
MOVE.L RegFrac,RegInt ;Copy the full fixed point number
SWAP RegInt ;Isolate the integer
MOVE.W MacViewHeight,RegScale ;Use maximum height
SUB.W #1,RegScale ;Adjust for DBF
JMP Loopy
;
; Call the compiled scaler to draw a run of the line
;
;void SpriteGlue(Byte *a,LongWord b,Byte *c,Word d,Word e);
SpriteGlue PROC
Off EQU 20
ParmSGArt EQU 4+Off ;Pointer to the 6 byte run structure
ParmTFrac EQU 8+Off ;Pointer to the scaler
ParmScrn EQU 12+Off ;Pointer to the run base address
ParmCnt EQU 16+Off ;Line count
ParmDelta EQU 18+Off ;Initial delta
SGArt2 EQU A0 ;Pointer to the 6 byte run structure
SGScrn EQU A1 ;Pointer to the run base address
SGArt EQU D1
SGFrac EQU D2 ;Pointer to the scaler
SGInt EQU D3 ;Pointer to the video
SGCount EQU D6
SGDelta EQU D4
SGVidWidth EQU D5
MOVEM.L D2-D6,-(A7)
MOVE.L ParmSGArt(A7),SGArt2
MOVE.L ParmScrn(A7),SGScrn
MOVE.L ParmTFrac(A7),SGFrac ;Get pointer to the run structure
MOVE.L SGFrac,SGInt
SWAP SGInt
MOVE.W ParmCnt(A7),SGCount
MOVE.W ParmDelta(A7),SGDelta
MOVE.W VideoWidth,SGVidWidth ;Init the video width
MOVE.L #0,SGArt
SUB.W #1,SGCount ;Adjust for count used in DBF
Loopy2
MOVE.B (SGArt2,SGArt.W),D0 ;Get shape byte
MOVE.B D0,(SGScrn)
ADD.W SGFrac,SGDelta ;Adjust the delta
ADDX.W SGInt,SGArt ;Adjust the source byte offset
ADD.W SGVidWidth,SGScrn ;Next dest scan line
DBF SGCount,Loopy2 ;Still more?
MOVEM.L (A7)+,D2-D6
RTS
END
#define MyMenuBar 128 /* application's menu bar */
#define rAboutAlert 128 /* about alert */
#define rUserAlert 129 /* error user alert */
#define AskSizeWin 130 /* Ask for screen size window */
#define NewGameWin 131 /* Choose difficulty */
#define Not607Win 132 /* Not system 6.0.7 or later */
#define NotColorWin 133 /* No color */
#define Not32QDWin 134 /* Not Quickdraw 32 */
#define SlowWarnWin 135 /* Your machine is slow */
#define SpeedTipsWin 136 /* Hints on speed */
#define ShareWareWin 137 /* Pay us $$$ */
#define GoSlowWin 138 /* You are not in 8 bit color mode */
#define EndGameWin 139 /* You won the shareware version */
#define LowMemWin 140 /* You are dangerously low on memory */
/* kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the
SysEnvRec we understand. */
#define kSysEnvironsVersion 1
/* kOSEvent is the event number of the suspend/resume and mouse-moved events sent
by MultiFinder. Once we determine that an event is an osEvent, we look at the
high byte of the message sent to determine which kind it is. To differentiate
suspend and resume events we check the resumeMask bit. */
#define kOSEvent app4Evt /* event used by MultiFinder */
#define kSuspendResumeMessage 1 /* high byte of suspend/resume event message */
#define kResumeMask 1 /* bit of message field for resume vs. suspend */
#define kMouseMovedMessage 0xFA /* high byte of mouse-moved event message */
#define kNoEvents 0 /* no events mask */
/* The following constants are used to identify menus and their items. The menu IDs
have an "m" prefix and the item numbers within each menu have an "i" prefix. */
#define mApple 128 /* Apple menu */
#define iAbout 1
#define iSpeedHint 2
#define iShareWare 3
#define mFile 129 /* File menu */
#define iNew 1
#define iOpen 2
#define iClose 4
#define iSave 5
#define iSaveAs 6
#define iQuit 8
#define mEdit 130 /* Edit menu */
#define iUndo 1
#define iCut 3
#define iCopy 4
#define iPaste 5
#define iClear 6
#define mOptions 131 /* Game menu */
#define iSound 1
#define iMusic 2
#define iScreenSize 3
#define iGovenor 4
#define iMouseControl 5
#define iUseQuickDraw 6
/* 1.01 - kTopLeft - This is for positioning the Disk Initialization dialogs. */
#define kDITop 0x0050
#define kDILeft 0x0070
/* kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions. */
#define kExtremeNeg -32768
#define kExtremePos 32767 - 1 /* required to address an old region bug */
/* these #defines are used to set enable/disable flags of a menu */
#define AllItems 0b1111111111111111111111111111111 /* 31 flags */
#define NoItems 0b0000000000000000000000000000000
#define MenuItem1 0b0000000000000000000000000000001
#define MenuItem2 0b0000000000000000000000000000010
#define MenuItem3 0b0000000000000000000000000000100
#define MenuItem4 0b0000000000000000000000000001000
#define MenuItem5 0b0000000000000000000000000010000
#define MenuItem6 0b0000000000000000000000000100000
#define MenuItem7 0b0000000000000000000000001000000
#define MenuItem8 0b0000000000000000000000010000000
#define MenuItem9 0b0000000000000000000000100000000
#define MenuItem10 0b0000000000000000000001000000000
#define MenuItem11 0b0000000000000000000010000000000
#define MenuItem12 0b0000000000000000000100000000000
/* Burger resources */
#define rIdLogoPic 128 /* Id Logo for 3do version */
#define rMacPlayPic 129 /* Mac play logo */
#define rMacPlayPal 130
#define rIdLogoPal 131
#define rBlackPal 132
#define rTitlePic 133 /* Title screen picture */
#define rTitlePal 134 /* Title screen palette */
#define MySoundList 135 /* List of sound effects to log */
#define MyDarkData 136 /* 256 byte table to darken walls */
#define MyWallList 137 /* All wall shapes */
#define MyBJFace 138 /* BJ's face for automap */
#define rIntermission 139 /* Intermission background */
#define rInterPal 140
#define rInterPics 141 /* BJ's intermission pictures */
#define rFaceShapes 142 /* All the permanent game shapes */
#define rFace512 143 /* All game sprites */
#define rFace640 144
#define rGamePal 145 /* Game Palette */
#define rMapList 146 /* Map info data */
#define rSongList 147 /* Music list data */
#define rGetPsychPic 148
#define rYummyPic 149
#define rYummyPal 150
#define rFineTangent 151 /* High detail tangent table */
#define rFineSine 152 /* High detail sine table */
#define rScaleAtZ 153 /* High detail scale table */
#define rViewAngleToX 154 /* Angle to X coord */
#define rXToViewAngle 155 /* X to angle */
;
; Assembly language functions for wolf 3-D PPC version
; Written by Bill Heineman
; 9-12-94 (Rev for removing scalers and using direct code)
;
;
; Bullshit to make the PPC Mac environment know I'm here
;
import VideoWidth ; global variable from C program
import MacViewHeight
import ArtData
import VideoPointer
import ScaleDiv
toc
tc VideoWidth[TC],VideoWidth
tc MacViewHeight[TC],MacViewHeight
tc ArtData[TC],ArtData
tc VideoPointer[TC],VideoPointer
tc ScaleDiv[TC],ScaleDiv
export IO_ScaleWallColumn[DS]
export .IO_ScaleWallColumn[PR]
export SpriteGlue[DS]
export .SpriteGlue[PR]
toc ;Table of contents for the subroutines
tc IO_ScaleWallColumn[TC], IO_ScaleWallColumn[DS]
tc SpriteGlue[TC], SpriteGlue[DS]
csect IO_ScaleWallColumn[DS]
dc.l .IO_ScaleWallColumn[PR]
dc.l TOC[tc0]
csect SpriteGlue[DS]
dc.l .SpriteGlue[PR]
dc.l TOC[tc0]
;
; This routine will draw a scaled wall column.
;
; void IO_ScaleWallColumn(Word x,Word scale,LongWord column)
;
WALLHEIGHT EQU 128+1
; Passed from "C"
X equ R3 ;X coord
Scale equ R4 ;Scale factor
Tile equ R5 ;Tile to draw
Column equ R6 ;Packed wall column #
; Locals
ArtStart EQU R7 ;Pointer to wall art
ScreenPtr EQU R8 ;Pointer to screen memory column
Frac EQU R9 ;Fractional scaler
Integer EQU R10 ;Fractional integer
VWidth EQU R11 ;Video of the video screen in bytes
Delta EQU R6 ;Delta factor and temp
VHeight EQU R12 ;Height of mac screen
Temp EQU R3 ;Temp (Use AFTER X is added)
csect .IO_ScaleWallColumn[PR]
CMPLWI Scale,0 ;Is the scale factor zero?
BEQLR ;Exit NOW!
LWZ ScreenPtr,VideoPointer[TC](RTOC) ;Get handle to video
LWZ ArtStart,ArtData[TC](RTOC) ;Get handle to art data list
LWZ VWidth,VideoWidth[TC](RTOC) ;Get handle to video width
LWZ Frac,ScaleDiv[TC](RTOC)
LWZ VHeight,MacViewHeight[TC](RTOC) ;Get pointer to view height
LWZ ScreenPtr,0(ScreenPtr) ;I have the base pointer
LWZ VWidth,0(VWidth) ;Init video width
LWZ VHeight,0(VHeight) ;Get the number of lines visible
SLWI Scale,Scale,1 ;Mul scale by 2 (Get true pixel value
ADD ScreenPtr,ScreenPtr,X ;Add the X coord (Frees Temp)
SLWI Temp,Scale,1 ;Get low word index
SLWI Tile,Tile,2 ;Get the wall shape pointer
LWZX Frac,Frac,Temp ;Get the scale factor
SLWI Column,Column,7 ;Mul by 128 pixels
LWZX ArtStart,ArtStart,Tile ;Get pointer to the shape
ADD ArtStart,ArtStart,Column ;I have the shape ptr
CMPLW Scale,VHeight ;Too big?
BGE ClipTop ;Clip the top
;
; No clipping needed!
; Adjust the dest screen for the starting Y coord
;
MTCTR Scale ;Init counter
SUB Temp,VHeight,Scale ;How many lines to jump down?
LI Delta,0 ;Init the delta factor
SRWI Temp,Temp,1 ;Divide by to center vertically
SRWI Integer,Frac,24 ;Isolate the integer
MULLW Temp,VWidth,Temp ;Adjust the Y coord
SLWI Frac,Frac,8 ;Isolate the fraction
ADD ScreenPtr,ScreenPtr,Temp ;Create the dest screen pointer
;
; Tight loop
; Grab byte, adjust fractional scaler values and store to screen
;
More:
LBZ R0,0(ArtStart) ;Fetch a shape byte
ADDC. Delta,Delta,Frac ;Add the scaler fractional
STB R0,0(ScreenPtr) ;Store on the screen
ADDE ArtStart,ArtStart,Integer ;Add the constant
ADD ScreenPtr,ScreenPtr,VWidth ;Go down a line
BDNZ More ;All lines done?
BLR ;Exit routine
;
; Clip the top and bottom
; Calc the number of lost lines by clipping and "Fake"
; the numbers as if I processed those missing lines
;
ClipTop:
MTCTR VHeight ;I will draw a screen line full
SUB Temp,Scale,VHeight ;How many lines to jump down?
SRWI Integer,Frac,24 ;Isolate the integer
SRWI Temp,Temp,1 ;Divide by to center vertically
MULLW Temp,Frac,Temp ;Adjust the scaler by lost lines
SRWI Delta,Temp,24 ;How many bytes are lost?
ADD ArtStart,ArtStart,Delta ;Create the SOURCE art pointer
SLWI Frac,Frac,8 ;Isolate the fraction
SLWI Delta,Temp,8 ;Init the adjusted delta
B More ;Jump to the code
;
; Call the compiled scaler to draw a run of the line
;
csect .SpriteGlue[PR]
SGArtStart EQU R3 ;Pointer to the 6 byte run structure
SGFrac EQU R4 ;Pointer to the scaler
SGInteger EQU R5 ;Pointer to the video
SGScreenPtr EQU R6 ;Pointer to the run base address
SGCount EQU R7
SGDelta EQU R8
SGVWidth EQU R9
LWZ SGVWidth,VideoWidth[TC](RTOC)
LWZ SGVWidth,0(SGVWidth)
MTCTR SGCount
SMore:
LBZ R0,0(SGArtStart) ;Fetch a shape byte
ADDC. SGDelta,SGDelta,SGFrac ;Add the scaler fractional
STB R0,0(SGScreenPtr) ;Store on the screen
ADDE SGArtStart,SGArtStart,SGInteger ;Add the constant
ADD SGScreenPtr,SGScreenPtr,SGVWidth ;Go down a line
BDNZ SMore ;All lines done?
BLR ;Exit routine
#include "WolfDef.h"
#include <string.h>
/**********************************
Draw a space padded list of numbers
for the score
**********************************/
LongWord pow10[] = {1,10,100,1000,10000,100000,1000000};
Word NumberIndex = 36; /* First number in the shape list... */
void SetNumber(LongWord number,Word x,Word y,Word digits)
{
LongWord val;
Word count;
Word empty;
empty = 1; /* No char's drawn yet */
while (digits) { /* Any digits left? */
count = 0; /* No value yet */
val = pow10[digits-1]; /* Get the power of 10 */
while (number >= val) { /* Any value here? */
count++; /* +1 to the count */
number -= val; /* Remove the value */
}
if (empty && !count && digits!=1) { /* pad on left with blanks rather than 0 */
DrawShape(x,y,GameShapes[NumberIndex]);
} else {
empty = 0; /* I have drawn... */
DrawShape(x,y,GameShapes[count+NumberIndex]); /* Draw the digit */
}
x+=ScaleX(8);
digits--; /* Count down */
}
}
/**********************************
Read from the Mac's keyboard/mouse system
**********************************/
void IO_CheckInput(void)
{
ReadSystemJoystick(); /* Set the variable "joystick1" */
/* check for auto map */
if (joystick1 & JOYPAD_START) {
RunAutoMap(); /* Do the auto map */
}
/*
** get game control flags from joypad
*/
memset(buttonstate,0,sizeof(buttonstate)); /* Zap the buttonstates */
if (joystick1 & JOYPAD_UP)
buttonstate[bt_north] = 1;
if (joystick1 & JOYPAD_DN)
buttonstate[bt_south] = 1;
if (joystick1 & JOYPAD_LFT)
buttonstate[bt_west] = 1;
if (joystick1 & JOYPAD_RGT)
buttonstate[bt_east] = 1;
if (joystick1 & JOYPAD_TL)
buttonstate[bt_left] = 1;
if (joystick1 & JOYPAD_TR)
buttonstate[bt_right] = 1;
if (joystick1 & JOYPAD_B)
buttonstate[bt_attack] = 1;
if (joystick1 & (JOYPAD_Y|JOYPAD_X) )
buttonstate[bt_run] = 1;
if (joystick1 & JOYPAD_A)
buttonstate[bt_use] = 1;
if (joystick1 & JOYPAD_SELECT) {
buttonstate[bt_select] = 1;
}
}
/**********************************
Draw the floor and castle #
**********************************/
void IO_DrawFloor(Word floor)
{
SetNumber(MapListPtr->InfoArray[floor].ScenarioNum,ScaleX(8),ScaleY(176),1);
SetNumber(MapListPtr->InfoArray[floor].FloorNum,ScaleX(32),ScaleY(176),1);
}
/**********************************
Draw the score
**********************************/
void IO_DrawScore(LongWord score)
{
if (!IntermissionHack) { /* Don't draw during intermission! */
SetNumber(score,ScaleX(56),ScaleY(176),7);
}
}
/**********************************
Draw the number of live remaining
**********************************/
void IO_DrawLives(Word lives)
{
if (!IntermissionHack) { /* Don't draw during intermission! */
--lives; /* Adjust for zero start value */
if (lives > 9) {
lives = 9; /* Failsafe */
}
SetNumber(lives,ScaleX(188),ScaleY(176),1); /* Draw the lives count */
}
}
/**********************************
Draw the health
**********************************/
void IO_DrawHealth(Word health)
{
SetNumber(health,ScaleX(210),ScaleY(176),3);
}
/**********************************
Draw the ammo remaining
**********************************/
void IO_DrawAmmo(Word ammo)
{
SetNumber(ammo,ScaleX(268),ScaleY(176),3);
}
/**********************************
Draw the treasure score
**********************************/
void IO_DrawTreasure(Word treasure)
{
SetNumber(treasure,ScaleX(128),ScaleY(176),2);
}
/**********************************
Draw the keys held
**********************************/
void IO_DrawKeys(Word keys)
{
if (keys&1) {
DrawShape(ScaleX(310),ScaleY(164),GameShapes[10]);
}
if (keys&2) {
DrawShape(ScaleX(310),ScaleY(184),GameShapes[11]);
}
}
/**********************************
Draw the gun in the foreground
**********************************/
void IO_AttackShape(Word shape)
{
DrawXMShape(ScaleX(128),ScaleY(96),GameShapes[shape+12]);
}
/**********************************
Draw the BJ's face
**********************************/
void IO_DrawFace(Word face)
{
DrawShape(ScaleX(160),ScaleY(164),GameShapes[face]); /* Draw the face */
}
/**********************************
Redraw the main status bar
**********************************/
void IO_DrawStatusBar(void)
{
DrawShape(ScaleX(0),ScaleY(160),GameShapes[46]);
}
/**********************************
Erase the floor and ceiling
**********************************/
#ifndef __APPLEIIGS__ /* Done in assembly on the IIgs version */
#ifndef __3DO__
void IO_ClearViewBuffer(void)
{
unsigned char *Screenad;
Word Count,WCount;
LongWord *LScreenad;
LongWord Fill;
Screenad = VideoPointer;
Count = VIEWHEIGHT/2;
Fill = 0x2f2f2f2f;
do {
WCount = SCREENWIDTH/4;
LScreenad = (LongWord *) Screenad;
do {
*LScreenad++ = Fill; /* 004 */
} while (--WCount);
Screenad+=VideoWidth;
} while (--Count);
Count = VIEWHEIGHT/2;
Fill = 0x2A2A2A2A;
do {
WCount = SCREENWIDTH/4;
LScreenad = (LongWord *) Screenad;
do {
*LScreenad++ = Fill;
} while (--WCount);
Screenad+=VideoWidth;
} while (--Count);
}
#endif
#endif
/**********************************
Copy the 3-D screen to display memory
**********************************/
void IO_DisplayViewBuffer (void)
{
BlastScreen();
/* if this is the first frame rendered, upload everything and fade in */
if (firstframe) {
FadeTo(rGamePal);
firstframe = 0;
}
}
#include "wolfdef.h"
#include <string.h>
/**********************************
Return the absolute value
**********************************/
Word w_abs(int val)
{
return val>=0 ? val : -val;
}
/**********************************
Return a seeded random number
**********************************/
Byte rndtable[256] = {
0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66,
74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36,
95,110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188,
52,140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224,
149,104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242,
145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0,
175,143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235,
25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113,
94,161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75,
136,156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196,
135,106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113,
80,250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241,
24,223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224,
145,224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95,
28,139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226,
71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36,
17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106,
197,242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136,
120,163, 236, 249
};
Word rndindex = 0;
Word w_rnd(void)
{
rndindex = (rndindex+1)&0xff; /* Next index */
return rndtable[rndindex]; /* Return the number */
}
/**********************************
Return an angle value based on a slope.
Assume that x is >= to y.
**********************************/
Word AngleFromSlope2(Word y,Word x)
{
return tantoangle[((LongWord)y<<SLOPEBITS)/x];
}
/**********************************
Convert an arbitrary point from the viewxy into an angle.
To get a global angle from cartesian coordinates, the coordinates are flipped until
they are in the first octant of the coordinate system, then the y (<=x) is scaled and
divided by x to get a tangent (slope) value which is looked up in the tantoangle[] table.
The +1 size is to handle the case when x==y without additional checking.
**********************************/
#define ANG90 0x4000
#define ANG180 0x8000
#define ANG270 0xc000
angle_t PointToAngle(fixed_t x, fixed_t y)
{
x -= viewx; /* Adjust the x and y based on the camera */
y = viewy - y;
if (x>=0) { /* x is positive? */
if (y>=0) { /* y is positive? */
if (x>y) {
return AngleFromSlope2(y,x); /* octant 0*/
} else {
return ANG90-1-AngleFromSlope2(x,y); /* octant 1 */
}
} else { /* y<0 */
y = -y; /* Negate y (Make positive) */
if (x>y) {
return -AngleFromSlope2(y,x); /* octant 8 */
} else {
return ANG270+AngleFromSlope2 (x,y); /* octant 7 */
}
}
} else { /* x<0*/
x = -x; /* Force x positive */
if (y>= 0) { /* Is y positive? */
if (x>y) {
return ANG180-1-AngleFromSlope2(y,x); /* octant 3 */
} else {
return ANG90+AngleFromSlope2(x,y); /* octant 2 */
}
} else { /* y<0*/
y = -y; /* Force y positive also */
if (x>y) {
return ANG180+AngleFromSlope2 (y,x); /* octant 4 */
}
}
}
return ANG270-1-AngleFromSlope2(x,y); /* octant 5 */
}
/**********************************
Died() has already spun the view toward the killer
GameOver() scales the "game over" sprite in and pulses it until an event
**********************************/
void GameOver(void)
{
topspritenum = S_GAMEOVER; /* Game over words */
topspritescale = 8; /* Start the scale factor */
do {
RenderView(); /* Draw the 3-d view */
topspritescale+=8;
} while (topspritescale<120);
for (;;) { /* Stay here forever */
do {
if (WaitTicksEvent(1)) { /* Canceled? */
return;
}
RenderView(); /* Show the 3-D view */
topspritescale-=2; /* Make smaller */
} while(topspritescale>100); /* Not too small... */
do {
if (WaitTicksEvent(1)) { /* Canceled? */
return;
}
RenderView(); /* Show the 3-D view */
topspritescale+=2; /* Make bigger */
} while (topspritescale<120); /* Not too big... */
}
}
/**********************************
Show the word "Victory" scaling in...
**********************************/
void VictoryScale(void)
{
topspritenum = S_VICTORY;
topspritescale = 16;
do {
RenderView();
topspritescale += 16;
} while (topspritescale<240);
for (;;) {
do {
if (WaitTicksEvent(1)) {
return;
}
RenderView();
topspritescale-=4;
} while (topspritescale>200);
do {
if (WaitTicksEvent(1)) {
return;
}
RenderView();
topspritescale+=4;
} while (topspritescale<240);
}
}
/**********************************
You died...
**********************************/
void Died (void)
{
Word Timer; /* Time mark */
Word Adds; /* Number of tics elapsed */
Word Total;
angle_t SrcAngle; /* Angle of view */
angle_t DestAngle; /* Angle of death */
fixed_t Motion; /* Motion constant */
gamestate.attackframe = 0; /* Remove the gun shape */
NoWeaponDraw = TRUE; /* The weapon is not drawn */
PlaySound(SND_PDIE); /* ARRRGGGHHHH!! */
IO_DrawFace(9); /* Show the dead face */
/* find angle to face attacker */
SrcAngle = gamestate.viewangle<<SHORTTOANGLESHIFT; /* Get the fine current angle */
DestAngle = PointToAngle(killx,killy)&(-1<<SHORTTOANGLESHIFT); /* What's the direction of the kill angle */
/* rotate to attacker */
if (SrcAngle!=DestAngle) { /* Do I need to rotate? */
Motion = (fixed_t)(DestAngle-SrcAngle)/ (fixed_t)30; /* Differance in fine angles */
LastTicCount = ReadTick();
Total = 30; /* Number of tics to elapse */
for (;;) { /* There yet? */
Timer = ReadTick(); /* How much time has elapsed */
Adds = Timer-LastTicCount; /* Save the time */
LastTicCount = Timer; /* Mark the new time */
if (Adds>=Total) { /* Too much time? */
break; /* Get out now! */
}
Total-=Adds; /* Remove elapsed time */
SrcAngle += Motion*Adds; /* Spin */
gamestate.viewangle = SrcAngle>>SHORTTOANGLESHIFT; /* Set the new view angle */
RenderView(); /* Show the view */
}
gamestate.viewangle = DestAngle>>SHORTTOANGLESHIFT; /* Finish the motion */
RenderView(); /* Draw the screen */
}
/* done */
if (!gamestate.lives) {
GameOver(); /* Show Game over... */
} else {
WaitEvent(); /* Wait for an event */
gamestate.health = 100; /* Restore health */
if (difficulty) { /* Remove weapons if difficult */
gamestate.weapon = gamestate.pendingweapon = WP_PISTOL;
gamestate.machinegun = FALSE;
gamestate.chaingun = FALSE;
gamestate.missile = FALSE;
gamestate.flamethrower = FALSE;
gamestate.ammo = STARTAMMO;
gamestate.missiles = 0;
gamestate.gas = 0;
gamestate.maxammo = 99;
gamestate.keys = 0;
} else {
if (gamestate.ammo < STARTAMMO*2) { /* If easy, then reload... */
gamestate.ammo = STARTAMMO*2;
}
}
gamestate.attackframe = 0; /* Reset the attack frame */
gamestate.attackcount = 0;
}
FadeToBlack(); /* Fade the screen to black */
}
/**********************************
Calls draw face if time to change
**********************************/
void UpdateFace(void)
{
Word Base;
if (facecount>TicCount) { /* Time to change the face? */
facecount-=TicCount; /* Wait a bit */
} else {
Base = (gamestate.health <= 25) ? 5 : 0;
if (faceframe==Base) { /* Normal frame? */
++Base; /* Use alternate */
}
faceframe=Base; /* Set the new face */
facecount = (w_rnd ()&31)+4; /* Random time */
IO_DrawFace(faceframe); /* Draw the face */
}
}
/**********************************
Prepare for a game loop
**********************************/
void PrepPlayLoop (void)
{
StartSong(SongListPtr[gamestate.mapon+2]); /* start music */
if (!SetupGameLevel()) { /* Load the game map */
ReleaseMap(); /* Release map memory */
ReleaseScalers(); /* Release the compiled scalers */
PlaySong(0);
while (!SetupGameLevel()) { /* Try loading it again */
Again:
ReleaseMap(); /* Oh oh... */
if (!GameViewSize) { /* Smallest screen? */
BailOut(); /* Leave... */
}
--GameViewSize; /* Smaller screen size */
GameViewSize = NewGameWindow(GameViewSize);
}
}
if (!StartupRendering(GameViewSize)) {
ReleaseScalers();
goto Again;
}
topspritescale = 0; /* No overlay sprite */
faceframe = 1; /* First face */
facecount = 1; /* change face next tic */
firstframe = 1; /* Force a fade in */
NoWeaponDraw = 0; /* Allow drawing of weapon */
memset(buttonstate,0,sizeof(buttonstate)); /* Kill the mouse system */
if (playstate!=EX_LOADGAME) {
PushWallRec.pwallcount = 0; /* No pushwalls */
gamestate.playtime = 0; /* Game has started */
} else {
FinishLoadGame(); /* Finish the load game code */
}
RedrawStatusBar(); /* Redraw the main bar */
mousey = 0; /* Reset the mouse y */
playstate = EX_STILLPLAYING; /* Game is in progress */
}
/**********************************
Play the game
**********************************/
void PlayLoop(void)
{
LongWord Timer;
LastTicCount = ReadTick();
do {
Timer = ReadTick(); /* How much time has elapsed */
TicCount = (Timer-LastTicCount);
gamestate.playtime += TicCount; /* Add the physical time to the elapsed time */
LastTicCount=Timer;
if (!SlowDown) {
TicCount = 4; /* Adjust from 4 */
}
if (TicCount>=5) {
TicCount = 4;
}
IO_CheckInput(); /* Read the controls from the system */
madenoise = FALSE; /* No noise made (Yet) */
MoveDoors(); /* Open and close all doors */
MovePWalls(); /* Move all push walls */
MovePlayer(); /* Move the player */
MoveActors(); /* Move all the bad guys */
MoveMissiles(); /* Move all projectiles */
UpdateFace(); /* Draw BJ's face and animate it */
viewx = actors[0].x; /* Where is the camera? */
viewy = actors[0].y;
RenderView(); /* Draw the 3D view */
} while (playstate==EX_STILLPLAYING);
StopSong();
}
/**********************************
Set up new game to start from the beginning
**********************************/
void NewGame(void)
{
nextmap = 0; /* No next map inited */
memset(&gamestate,0,sizeof(gamestate)); /* Zap the game variables */
gamestate.weapon = gamestate.pendingweapon = WP_PISTOL; /* Set the pistol */
gamestate.health = 100; /* Reset the health */
gamestate.ammo = STARTAMMO; /* Reset the ammo */
if (!difficulty) {
gamestate.ammo += STARTAMMO; /* Double the ammo if easy */
}
gamestate.maxammo = 99; /* Refill the ammo */
gamestate.lives = 3; /* 3 lives */
gamestate.nextextra = EXTRAPOINTS; /* Next free life score needed */
gamestate.godmode = 0; /* Force god mode off */
}
/**********************************
Redraw the main status bar at the bottom
**********************************/
void RedrawStatusBar(void)
{
IO_DrawStatusBar(); /* Draw the status bar */
IO_DrawFloor(gamestate.mapon); /* Draw the current floor # */
IO_DrawScore(gamestate.score); /* Draw the current score */
IO_DrawTreasure(gamestate.treasure); /* Draw the treasure score */
IO_DrawLives(gamestate.lives); /* Draw the life count */
IO_DrawHealth(gamestate.health); /* Draw the health */
switch (gamestate.weapon) { /* Draw the proper ammo */
case WP_FLAMETHROWER:
IO_DrawAmmo(gamestate.gas);
break;
case WP_MISSILE:
IO_DrawAmmo(gamestate.missiles);
break;
default:
IO_DrawAmmo(gamestate.ammo);
break;
}
IO_DrawKeys(gamestate.keys); /* Draw the keys held */
IO_DrawFace(faceframe); /* Draw BJ's face */
}
/**********************************
Play the game!
**********************************/
void GameLoop (void)
{
for(;;) {
skipbrief:
ShowGetPsyched();
PrepPlayLoop(); /* Init internal variables */
EndGetPsyched();
PlayLoop(); /* Play the game */
if (playstate == EX_DIED) { /* Did you die? */
--gamestate.lives; /* Remove a life */
Died(); /* Run the death code */
if (!gamestate.lives) { /* No more lives? */
return; /* Exit then */
}
goto skipbrief; /* Try again */
}
if (playstate == EX_SECRET) { /* Going to the secret level? */
nextmap = MapListPtr->InfoArray[gamestate.mapon].SecretLevel;
} else if (playstate != EX_WARPED) {
nextmap = MapListPtr->InfoArray[gamestate.mapon].NextLevel; /* Normal warp? */
} /* If warped, then nextmap is preset */
if (nextmap == 0xffff) { /* Last level? */
VictoryScale(); /* You win!! */
ReleaseMap(); /* Unload the map */
Intermission(); /* Display the wrapup... */
ShareWareEnd(); /* End the game for the shareware version */
/* VictoryIntermission(); /* Wrapup for victory! */
return;
}
ReleaseMap(); /* Unload the game map */
gamestate.keys = 0; /* Zap the keys */
WaitTicks(1); /* Flush the ticker */
WaitTicks(30); /* Wait for the sound to finish */
if (playstate != EX_WARPED) { /* No bonus for warping! */
Intermission(); /* Show the wrap up... */
}
gamestate.mapon = nextmap; /* Next level */
}
}
History of Wolfenstein 3D: First & Second Encounter
Programming and Project Lead: Bill Heineman
Additional programming: Chris DeSalvo
Producer: Bill Dugan
Wolfenstein 3D for MacOS was released on October 1st, 1994 by Interplay Productions under license from id software. The code was based not on the PC version but of a Super NES version that was done at id software. This version of the game differs greatly from the PC version since it used BSP trees to help determine which walls were to be drawn instead of the ray-casting method.
The fixed point number system was 8.8 format so that it could fit in a 65816 register for the SNES and Apple IIgs version of Wolf 3D. (8 bits of integer and 8 bits of fraction)
The mac version also has two modes of drawing. In the 68000 version, 68000 code is generated at runtime to draw the vertical lines very quickly. The source file SetupScalers68k.c creates the 68000 code and then issues calls to it via a little 68000 assembly glue code. This is how the game got its speed. The powerpc version originally had this method as well but the performance sucked. So it was changed to a simple assembly loop and the game ran fine. This is why there is SetupScalersPPC.c and SetupScalers68k.c.
I took the code from Codewarrion DR/4 which was the development system at the time and updated the project to Codewarrior PRO 5 (Which is what I use today). I've compiled, tested and ran the game and the code runs fine. The sound code is copyright Steve Hales and Jim Nitchals. You cannot use the music driver in your own programs unless you get a license from Steve Hales. (Jim Nitchals sadly has passed on, may he rest in peace).
Yes, there is a level editor that I wrote. It sucks. I suggest you get WolfEdit that is available on the web from WolfAddict software instead. It doesn't suck.
Here it is 1/21/2000. Over 5 years since I did the mac version of Wolf 3D. Seems like yesterday. I hope you enjoy looking over this code and making little changes for your own pleasure and learning. If someone makes any improvements to this code like adding Sprocket support or GL support, please send me the new source. I can be found at burger@logicware.com
I want to thank those who helped make this project a reality. John Carmack, Jay Wilbur, John Romero, Brian Luzietti and my wife Lorenza.
Bill Heineman
Logicware Inc.
20628 E. Arrow Hwy. #6
burger@logicware.com
\ No newline at end of file
#ifndef __WOLFDEF__
#define __WOLFDEF__
#define DEMO /* Define if this is the lame demo for dealers */
/* japversion has mission pics instead */
/* #define JAPVERSION */
/* If code is compiled on a IIgs, pass the compiler presets... */
#ifdef __ORCAC__
#pragma optimize 15 /* Normal optimization */
#pragma memorymodel 0 /* Force small memory model */
#pragma noroot /* No root files */
#pragma lint -1 /* Full error checking */
segment "Wolf3d"; /* Code segment */
#endif
/* an angle_t occupies an entire 16 bits so wraparound is automatically handled */
#define SHORTTOANGLESHIFT 7 /* 0x10000 to ANGLES */
#define SLOPEBITS 9 /* Used in AngleFromSlope2 */
typedef unsigned short angle_t; /* Must be short to allow wraparound */
typedef short fixed_t; /* 8.8 fixed point number */
typedef unsigned short ufixed_t; /* 8.8 unsigned fixed point number */
#include <burger.h> /* My standard system equates */
#include "States.h" /* Think state equates */
#include "Sounds.h" /* Sound equates */
#include "Sprites.h" /* Sprite indexs */
#include "Wolf.h" /* Resource maps */
/**********************************
Game constants and equates
The game uses a tile map of 64X64 tiles and uses a 16 bit fixed
point number to record the placement of any object in the game. The
upper 8 bits are the tile with the lower 8 bits being which fraction into the
tile the player is standing on.
To adjust the screen size, modify SCREENWIDTH,SCREENHEIGHT,VIEWHEIGHT,ScaleX,ScaleY
**********************************/
#define MAXVISSPRITES 64 /* Maximum number of sprites to display (Must be a power of 2!) */
#define MAXACTORS 128 /* max number of nazis, etc / map */
#define MAXSTATICS 200 /* max number of lamps, bonus, etc */
#define MAXMISSILES 32 /* max missiles, flames, smokes, etc */
#define MAXDOORS 64 /* max number of sliding doors (64<=) */
#define MAXAREAS 64 /* max number of bsp areas */
#define NUMBUTTONS 10 /* Number of control buttons */
#define WALLHEIGHT 128 /* Height,width of walls */
#define SPRITEHEIGHT 64 /* Height,width of a sprite */
#define MAXSCALER 960 /* Number of scalers to create */
#define PLAYERSIZE 88 /* radius of player in 8.8 fixed point */
#define PROJECTIONSCALE (SCREENWIDTH/2)*0x90l
#define FIELDOFVIEW 364*4 /* fineangles in the SCREENWIDTH wide window*/
#define MINZ 62 /* PLAYERSIZE/sqrt(2) rounded down*/
#define MAXZ (32*FRACUNIT) /* Farthest thing away */
#define FINEANGLES 0x2000 /* Power of 2 */
#define FINEMASK (FINEANGLES-1)
#define ANGLETOFINESHIFT 3 /* 0x10000 >> 0x2000*/
#define GAMEANGLETOFINE 4 /* 512 << 0x2000 */
#define ANGLE90 0x4000 /* Use a 0x10000 angle range */
#define ANGLE180 0x8000 /* Use a 0x10000 angle range */
#ifdef __MAC__
#define SCREENWIDTH MacWidth /* Size of the offscreen buffer */
#define SCREENHEIGHT MacHeight /* Height of the offscreen buffer */
#define VIEWHEIGHT MacViewHeight /* Height of the viewing area */
Word ScaleX(Word x); /* Scale factor for 320 mode points projected to SCREEN */
Word ScaleY(Word y);
extern Word MacWidth;
extern Word MacHeight;
extern Word MacViewHeight;
#else
#define SCREENWIDTH 320 /* Size of the offscreen buffer */
#define SCREENHEIGHT 200 /* Height of the offscreen buffer */
#define VIEWHEIGHT 160 /* Height of the viewing area */
#define ScaleX(x) x /* Scale factor for 320 mode points projected to SCREEN */
#define ScaleY(y) y
#endif
#define CENTERY (VIEWHEIGHT/2) /* Center of the viewing area */
#define CENTERX (SCREENWIDTH/2) /* Center of the viewing area */
#define ANGLES 512 /* Number of angles for camera */
#define FRACBITS 8 /* Number of bits of fraction */
#define FRACUNIT (1<<FRACBITS) /* Shift count for fraction conversion */
#define MAXFRAC 0x7fff /* Largest fraction constant */
#define MAXUFRAC 0xffff /* Largest unsigned fraction constant */
#define MAXDAMAGECOLOR 32 /* Number of shades of red to use for damage */
#define MAXBONUSCOLOR 8 /* Number of shades of gold to use for damage */
#define EXTRAPOINTS 20000 /* Points for a free man */
#define STARTAMMO 16 /* Ammo to begin the game with */
#define TILEGLOBAL 256 /* Pixels per tile */
#define MINACTORDIST 192 /* minimum dist from player center*/
/* to any actor center*/
#define KNIFEDIST 480 /* max dist for a knife hit (fixed_t) */
#define BITERANGE 350 /* max dist for a bite hit (fixed_t) */
#define MISSILEHITDIST 120 /* max dist for a missile impact (fixed_t) */
#define MAPSIZE 64 /* Size of a map in tiles */
/* joypad masks */
#define JOYPAD_B 0x8000
#define JOYPAD_Y 0x4000
#define JOYPAD_SELECT 0x2000
#define JOYPAD_START 0x1000
#define JOYPAD_UP 0x800
#define JOYPAD_DN 0x400
#define JOYPAD_LFT 0x200
#define JOYPAD_RGT 0x100
#define JOYPAD_A 0x80
#define JOYPAD_X 0x40
#define JOYPAD_TL 0x20
#define JOYPAD_TR 0x10
/**********************************
Game enums and record lists
**********************************/
typedef enum { /* Think logic states (MUST match thinkcalls in EnThink.c) */
T_NULL, /* No action */
T_STAND, /* Watch for player */
T_CHASE /* Chase player */
} thinklogic_t;
typedef enum { /* Action logic states (MUST match actioncalls in EnThink.c */
A_NULL, /* No action */
A_TARGET, /* Target the player */
A_SHOOT, /* Shoot the player */
A_BITE, /* Bite the player */
A_THROW, /* Throw a syringe */
A_LAUNCH, /* Launch a missile */
A_HITLERMORPH, /* Remove the mechhitler's armor */
A_MECHSTEP, /* Mechahitler step sound */
A_VICTORY, /* You win */
A_SCREAM, /* Actor screams */
A_THUD /* Hit the ground */
} actionlogic_t;
typedef enum { /* Index to the button array */
bt_north, /* North pressed */
bt_east, /* Turn East pressed */
bt_south, /* South pressed */
bt_west, /* Turn West pressed */
bt_left, /* Move left */
bt_right, /* Move right */
bt_attack, /* Fire */
bt_use, /* Open door, use switch */
bt_run, /* Move faster */
bt_select /* Change weapons */
} buttonname_t;
typedef enum { /* Used by spawning and wall pushing */
CD_NORTH, /* Face north */
CD_EAST, /* Face east */
CD_SOUTH,
CD_WEST
} cardinaldir_t;
typedef enum { /* Used by actor's motion */
east,
northeast,
north,
northwest,
west,
southwest,
south,
southeast,
nodir
} dirtype;
typedef enum { /* Weapons used by the player */
WP_KNIFE,
WP_PISTOL,
WP_MACHINEGUN,
WP_CHAINGUN,
WP_FLAMETHROWER,
WP_MISSILE,
NUMWEAPONS
} weapontype;
typedef enum { /* State of the game */
EX_LIMBO, /* Currently in limbo */
EX_STILLPLAYING,
EX_COMPLETED,
EX_SECRET,
EX_WARPED,
EX_DIED,
EX_NEWGAME,
EX_LOADGAME,
EX_AUTOMAP
} exit_t;
typedef enum { /* actor class info*/
CL_GUARD,
CL_OFFICER,
CL_SS,
CL_DOG,
CL_MUTANT,
CL_HANS,
CL_SCHABBS,
CL_TRANS,
CL_UBER,
CL_DKNIGHT,
CL_MECHAHITLER,
CL_HITLER,
CL_PLAYER
} class_t;
enum {BSPTOP,BSPBOTTOM,BSPLEFT,BSPRIGHT}; /* BSP quadrants */
/**********************************
Compiled scaler
**********************************/
typedef struct {
unsigned short codeofs[WALLHEIGHT+1]; /* Entry to the code for sprites */
#ifndef __APPLEIIGS__
Byte FixA1[WALLHEIGHT+1]; /* A1 adjust for the screen */
Byte Pad[1]; /* Long word align it... */
#endif
Byte code[1]; /* Scaler code */
} t_compscale;
/**********************************
Status of the game (Save game record)
**********************************/
typedef struct {
LongWord score; /* Current score */
LongWord nextextra; /* Points to next free man */
LongWord globaltime, globaltimetotal;
LongWord playtime; /* Time for the current game (In ticks) */
Word mapon; /* Current map */
Word treasure; /* Treasures picked up */
Word lives; /* Lives remaining */
Word health; /* Hit points */
Word ammo; /* Current bullets */
Word maxammo; /* Maximum bullets */
Word gas; /* Flame thrower ammo */
Word missiles; /* Missile launcher ammo */
Word keys; /* Keys obtained */
Boolean machinegun,chaingun,missile,flamethrower;
weapontype weapon,pendingweapon;
Word attackframe,attackcount;
Word secretcount,treasurecount,killcount;
Word secrettotal,treasuretotal,killtotal;
Word globalsecret, globaltreasure, globalkill;
Word globalsecrettotal, globaltreasuretotal, globalkilltotal;
Word viewangle; /* Angle of camera */
Boolean godmode; /* You are invincible */
} gametype_t;
/**********************************
Map data record (Stored maps)
**********************************/
typedef struct {
Byte tilemap[64][64];
Byte areasoundnum[64];
unsigned short numspawn; /* Must be short */
unsigned short spawnlistofs; /* Must be short */
unsigned short numnodes; /* Must be short */
unsigned short nodelistofs; /* Must be short */
Byte data[1]; /* nodes, and spawn list */
} loadmap_t;
typedef struct {
unsigned short NextLevel; /* Normal warp level */
unsigned short SecretLevel; /* Secret level */
unsigned short ParTime; /* Time for par */
unsigned short ScenarioNum; /* Scenario number */
unsigned short FloorNum; /* Floor number */
} MapInfo_t;
typedef struct {
unsigned short MaxMap; /* Maximum number of maps */
unsigned short MapRezNum; /* Basic resource # */
MapInfo_t InfoArray[1]; /* Next map to jump to */
} maplist_t;
/**********************************
Static data for each sprite state
**********************************/
typedef struct {
Word sightsound; /* Sound at the sight of you */
Word deathsound; /* Sound at the death of the actor */
stateindex_t sightstate; /* State when you are sighted */
stateindex_t standstate; /* State when at rest */
stateindex_t attackstate; /* State when attacking you */
stateindex_t painstate; /* State when hit */
stateindex_t deathstate; /* State when dead */
Word points; /* Points for death */
Word speed; /* Speed of actor */
Word reactionmask; /* reaction time = 1 + w_rnd()&reactionmask*/
Word hitpoints; /* Hit points */
} classinfo_t;
enum {di_north, di_east, di_south, di_west}; /* BSP base directions */
/**********************************
The saved data structures are held in a single list, with segs being differentiated from
nodes by the presence of DIR_SEGFLAG in the dir field
Note... saveseg_t and savenode_t share the same memory
**********************************/
#define DIR_SEGFLAG 0x80 /* Use segment value */
#define DIR_LASTSEGFLAG 0x40 /* Last segment in list */
#define DIR_DISABLEDFLAG 0x20 /* Shut down (Pushwall) */
#define DIR_SEENFLAG 0x10 /* For automapping*/
typedef struct {
Byte plane;
Byte dir;
unsigned short children[2];
} savenode_t;
#ifndef __BIGENDIAN__
typedef struct {
Byte plane; /* in half tiles*/
Byte dir;
Byte min,max; /* in half tiles*/
Byte texture;
Byte area;
} saveseg_t;
#else
typedef struct {
Byte plane; /* in half tiles*/
Byte dir;
Byte max,min; /* in half tiles*/
Byte area;
Byte texture;
} saveseg_t;
#endif
/**********************************
Static object struct
(Bullets,food,gold)
**********************************/
/* Used by the renderer, must match the header of static_t, actor_t, missile_t */
typedef struct {
int x,y; /* Item's x,y */
Word sprite; /* Item's shape */
Word areanumber; /* Item's visible area */
} thing_t;
typedef struct { /* Must match thing_t */
Word x,y; /* Item's x,y */
Word pic; /* Picture of item */
Word areanumber; /* Which room is it in (Rendering) */
} static_t;
/**********************************
Static door struct
**********************************/
typedef enum {
DR_OPEN, /* Door is fully open */
DR_CLOSED, /* Door is fully closed */
DR_OPENING, /* Door is opening */
DR_CLOSING, /* Door is closing */
DR_WEDGEDOPEN /* Door is permenantly open */
} dooraction_t;
#define OPENTICS 120 /* Time to wait before closing a door (In Ticks) */
#define DOORSPEED (TILEGLOBAL/64) /* Time to close a door (32 ticks) */
typedef struct {
Word tilex; /* X coord of door */
Word tiley; /* Y coord of door */
Word action; /* Action code (See above) for door */
Word position; /* Pixel position of door (0=Closed) */
Word info; /* Texture of the door (Steel,Elevator) */
Word ticcount; /* Time delay before automatic closing */
Word area1; /* Area # on one side of the door */
Word area2; /* Area # on the other side of the door */
} door_t;
typedef struct {
Boolean Area1; /* First area */
Boolean Area2; /* Second area */
} connect_t;
/**********************************
Pushwall state struct
**********************************/
typedef struct {
Word pwallcount; /* Blocks still to move (Distance) */
Word pwallpos; /* Amount a pushable wall has been moved in it's tile */
Word pwallx,pwally; /* the tile the pushwall edge is in now*/
Word pwallcheckx,pwallchecky; /* the tile it will be in next*/
Word pwalldir;
int pwallxchange, pwallychange; /* adjust coordinates this much*/
} pushwall_t;
/**********************************
Sprite state struct
**********************************/
typedef struct {
Word shapenum; /* Shape to display */
Word tictime; /* Time before next state */
thinklogic_t think; /* Think logic index */
actionlogic_t action; /* Action code */
stateindex_t next; /* Next state */
} state_t;
/**********************************
Visible sprite struct (Used to render the sprites)
**********************************/
typedef struct {
void *pos; /* position of sprite info */
ufixed_t columnstep; /* Step factor for width scale */
int x1,x2; /* Left x, Right x */
Word actornum; /* 0 if a static sprite / missile*/
Word clipscale; /* Size of sprite (Scale number) */
} vissprite_t;
/**********************************
Data struct for thinking actor
**********************************/
/* Actor flags */
#define FL_SHOOTABLE 1
#define FL_ACTIVE 2
#define FL_SEEPLAYER 4 /* if True, dodge instead of moving straight forward*/
#define FL_AMBUSH 16
#define FL_WAITDOOR 32 /* if set, ac_dir points at a door*/
#define FL_NOTMOVING 64 /* still centered in dest tile*/
#define FL_DEAD 128 /* if set, don't shoot this anymore (death explosion)*/
typedef struct { /* Must match thing_t */
Word x,y;
Word pic;
Word areanumber;
Word ticcount; /* Time before motion */
class_t class; /* Actor's class */
stateindex_t state; /* State index */
Word flags; /* State flags (See above) */
Word distance; /* Distance to travel before change */
Word dir; /* 9 directions for motion */
Word hitpoints; /* Hit points before death */
Word speed; /* Speed of motion */
Word goalx; /* tile x,y for movement goal */
Word goaly;
Word reacttime; /* Time to react to the player */
} actor_t;
/**********************************
Missile struct
(Rockets, flames)
**********************************/
typedef enum { /* Flame type */
MI_PMISSILE, /* Player's missile */
MI_PFLAME, /* Player's flame */
MI_EMISSILE,
MI_NEEDLE
} mtype_t;
#define MF_HITPLAYER 1 /* Can it hit the player? */
#define MF_HITENEMIES 2 /* Can it hit an enemy? */
#define MF_HITSTATICS 4 /* Can it hit a static item? */
typedef struct { /* Must match thing_t */
Word x,y; /* Position of the missile */
Word pic; /* Picture of missile */
Word areanumber; /* Area missile is in */
Word type; /* Also used as a ticcount for explosions */
Word flags; /* Who can I hit? (If zero then explosion) */
int xspeed,yspeed; /* Direction of travel */
} missile_t;
/**********************************
Flags used by tilemap, NOTE: this allows only 128 unique tiles
**********************************/
#define TI_SECRET 0x8000 /* Secret level switch */
#define TI_BODY 0x4000 /* Dead body here */
#define TI_BLOCKSIGHT 0x2000 /* Sight is blocked */
#define TI_GETABLE 0x1000 /* Getable item here */
#define TI_ACTOR 0x800 /* Actor here */
#define TI_DOOR 0x400 /* Door here */
#define TI_PUSHWALL 0x200 /* Pushwall here */
#define TI_SWITCH 0x100 /* Exit switch here */
#define TI_BLOCKMOVE 0x80 /* Block in motion here */
#define TI_NUMMASK 0x7f /* Can be an area, door number, or pwall number */
extern LongWord rw_scale;
extern LongWord rw_scalestep;
extern Word rw_midpoint;
extern Word rw_mintex;
extern Word rw_maxtex;
extern Byte *rw_texture;
extern int rw_centerangle;
extern Boolean rw_downside; /* True for dir_east and dir_south*/
extern Byte *ArtData[64];
extern Byte textures[MAPSIZE*2+5][MAPSIZE]; /* 0-63 is horizontal, 64-127 is vertical*/
/* 128 - 132 are doors*/
/* In Mac.c, 3DO.c, AppleIIgs.c */
extern void InitTools(void);
extern void BlastScreen(void);
extern void BlastScreen2(Rect *BlastRect);
extern void DoMacEvents(void);
extern void BailOut(void);
extern void GoodBye(void);
extern void ReadSystemJoystick(void);
extern Word NewGameWindow(Word NewVidSize);
extern void ShowGetPsyched(void);
extern void DrawPsyched(Word Index);
extern void EndGetPsyched(void);
extern Word ChooseGameDiff(void);
extern void ShareWareEnd(void);
extern void FinishLoadGame(void);
/* In StateDef.c */
extern state_t states[NUMSTATES]; /* Actor states */
/* In Doors.c */
extern void AddConnection(Word Area1,Word Area2);
extern void RemoveConnection(Word Area1,Word Area2);
extern void RecursiveConnect(Word areanumber);
extern void ConnectAreas(void);
extern void OpenDoor(door_t *door);
extern void CloseDoor(door_t *door);
extern void OperateDoor(Word dooron);
extern void DoorOpen(door_t *door);
extern void DoorOpening(door_t *door);
extern void DoorClosing(door_t *door);
extern void MoveDoors(void);
/* Missiles.c */
extern missile_t *GetNewMissile(void);
extern void ExplodeMissile(missile_t *MissilePtr);
extern void MissileHitPlayer(missile_t *MissilePtr);
extern Boolean MissileHitEnemy(missile_t *MissilePtr,actor_t *ActorPtr);
extern Boolean CheckMissileActorHits(missile_t *MissilePtr);
extern void MoveMissiles(void);
/* In Level.c */
extern void SpawnStatic(Word x,Word y,Word shape);
extern void SpawnPlayer(Word x,Word y,Word dir);
extern void SpawnStand(Word x,Word y,class_t which);
extern void SpawnAmbush(Word x,Word y,class_t which);
extern void SpawnDoor(Word x,Word y,Word type);
extern void AddPWallTrack(Word x,Word y,Word tile);
extern void SpawnPushwall(Word x,Word y,Word tile);
extern void SpawnElevator(Word x,Word y);
extern void SpawnOut(Word x,Word y);
extern void SpawnSecret(Word x,Word y);
extern void SpawnThings(void);
extern void ReleaseMap(void);
extern Boolean SetupGameLevel(void);
extern Word LoadWallArt(void);
extern Word LoadSpriteArt(void);
/* In Sight.c */
extern Boolean CheckLine(actor_t *ActorPtr);
extern void FirstSighting(actor_t *ActorPtr);
extern void T_Stand(actor_t *ActorPtr);
/* In Enmove.c */
extern dirtype opposite[9];
extern dirtype diagonal[9][9];
extern void NewState(actor_t *ActorPtr,stateindex_t state);
extern Boolean CheckDiag(Word x,Word y);
extern Word CheckSide(Word x,Word y,actor_t *ActorPtr);
extern Boolean TryWalk(actor_t *ActorPtr);
extern void SelectDodgeDir(actor_t *ActorPtr);
extern void SelectChaseDir(actor_t *ActorPtr);
extern void MoveActor(actor_t *ActorPtr,Word move);
/* In EnThink.c */
void PlaceItemType(Word shape,actor_t *ActorPtr);
extern void KillActor(actor_t *ActorPtr);
extern void DamageActor(Word damage,actor_t *ActorPtr);
extern void A_Throw(actor_t *ActorPtr);
extern void A_Launch(actor_t *ActorPtr);
extern void A_Scream(actor_t *ActorPtr);
extern void A_Thud(actor_t *ActorPtr);
extern void A_Victory(actor_t *ActorPtr);
extern void A_HitlerMorph(actor_t *ActorPtr);
extern void A_Shoot(actor_t *ActorPtr);
extern void A_Bite(actor_t *ActorPtr);
extern Word CalcDistance(actor_t *ActorPtr);
extern void A_Target(actor_t *ActorPtr);
extern void A_MechStep(actor_t *ActorPtr);
extern void T_Chase(actor_t *ActorPtr);
extern void MoveActors(void);
/* In PlStuff.c */
extern void TakeDamage(Word points,Word x,Word y);
extern void HealSelf(Word points);
extern void GiveExtraMan(void);
extern void GivePoints(LongWord points);
extern void GiveTreasure(void);
extern void GiveWeapon(weapontype weapon);
extern void GiveAmmo(Word ammo);
extern void GiveGas(Word ammo);
extern void GiveMissile(Word ammo);
extern void GiveKey(Word key);
extern void BonusSound(void);
extern void WeaponSound(void);
extern void HealthSound(void);
extern void KeySound(void);
extern void GetBonus(Word x,Word y);
/* In PlThink.c */
extern void ChangeWeapon(void);
extern void Cmd_Fire(void);
extern void Cmd_Use(void);
extern void Cmd_ChangeWeapon(void);
extern actor_t *TargetEnemy(void);
extern void KnifeAttack(void);
extern void GunAttack(void);
extern void FlameAttack(void);
extern void MissileAttack(void);
extern void MovePlayer(void);
/* In PlMove.c */
extern void ControlMovement(void);
/* In PushWall.c */
extern pushwall_t PushWallRec; /* Record for the single pushwall in progress */
extern void SetPWallChange(void);
extern void PushWallOne(void);
extern void PushWall(Word x,Word y,Word dir);
extern void MovePWalls(void);
/* In WolfIO.c */
extern void SetNumber(LongWord number,Word x,Word y,Word digits);
extern void IO_CheckInput(void);
extern void IO_DrawFloor(Word floor);
extern void IO_DrawScore(LongWord score);
extern void IO_DrawLives(Word lives);
extern void IO_DrawHealth(Word health);
extern void IO_DrawAmmo(Word ammo);
extern void IO_DrawTreasure(Word treasure);
extern void IO_DrawKeys(Word keys);
extern void IO_AttackShape(Word shape);
extern void IO_DrawFace(Word face);
extern void IO_DrawStatusBar(void);
extern void IO_ClearViewBuffer(void);
extern void IO_ScaleWallColumn(Word x,Word scale,Word tile,Word column);
extern void IO_DisplayViewBuffer(void);
/* In SetupScalers.c */
extern Boolean BuildCompScale (Word height, void **finalspot,Byte *WorkPtr);
extern Boolean SetupScalers(void);
extern void ReleaseScalers(void);
extern void IO_ScaleMaskedColumn(Word x,Word scale,unsigned short *sprite,Word column);
extern void DrawSmall(Word x,Word y,Word tile);
extern void MakeSmallFont(void);
extern void KillSmallFont(void);
/* In Intro.c */
extern void Intro(void);
/* In Music.c */
extern void StopSong(void);
extern void StartSong(Word songnum);
/* In WolfMain.c */
extern Word w_abs(int v);
extern Byte rndtable[256];
extern Word rndindex;
extern Word w_rnd(void);
extern Word AngleFromSlope2(Word y,Word x);
extern angle_t PointToAngle(fixed_t x,fixed_t y);
extern void GameOver(void);
extern void VictoryScale(void);
extern void Died(void);
extern void UpdateFace(void);
extern void PrepPlayLoop(void);
extern void PlayLoop(void);
extern void NewGame(void);
extern void RedrawStatusBar(void);
extern void GameLoop(void);
/* In RefSprite.c */
extern void Merge(Word Size1,Word Size2);
extern void SortEvents(void);
extern void RenderSprite(Word x1,Word x2,vissprite_t *rs_seg);
extern void AddSprite(thing_t *thing,Word actornum);
extern void DrawTopSprite(void);
extern void DrawSprites(void);
/* In Refresh.c */
extern savenode_t *nodes;
extern saveseg_t *pwallseg;
extern fixed_t FixedByFrac(fixed_t a, fixed_t b);
extern fixed_t SUFixedMul(fixed_t a, ufixed_t b);
extern fixed_t FixedDiv(fixed_t a, fixed_t b);
extern fixed_t R_TransformX(fixed_t x,fixed_t y);
extern fixed_t R_TransformZ(fixed_t x,fixed_t y);
extern Word ScaleFromGlobalAngle(int visangle,int distance);
extern void DrawAutomap(Word tx,Word ty);
extern Boolean StartupRendering(Word NewSize);
extern void NewMap(void);
extern void StartPushWall(void);
extern void AdvancePushWall(void);
extern void RenderView(void);
/* In Refresh2.c */
extern Word MathSize; /* The current size of the math tables */
extern Word *scaleatzptr; /* Pointer to the scale table for z projection */
extern short *xtoviewangle; /* Screen x to view angle */
extern short *viewangletox; /* View angle to screen x */
extern short *finetangent; /* Fine tangent table */
extern short *finesine; /* Fine sine table */
extern fixed_t sintable[ANGLES]; /* Course sine table */
extern fixed_t costable[ANGLES]; /* Course cosine table */
extern Word tantoangle[513]; /* Course tangent to angle table */
extern void GetTableMemory(void);
/* In RefBsp.c */
extern void RenderWallLoop(Word x1,Word x2,Word distance);
extern void RenderWallRange(Word start,Word stop,saveseg_t *seg,Word distance);
extern void ClipWallSegment(Word top,Word bottom,saveseg_t *seg,Word distance);
extern void ClearClipSegs(void);
extern void P_DrawSeg(saveseg_t *seg);
extern Boolean CheckBSPNode(Word boxpos);
extern void TerminalNode(saveseg_t *seg);
extern void RenderBSPNode(Word bspnum);
/* In SnesMain.c */
extern void SetupPlayScreen(void);
extern void RunAutoMap(void);
extern void StartGame(void);
extern Boolean TitleScreen(void);
extern void WolfMain(void);
/* In Intermis.c */
extern void LevelCompleted(void);
extern void Intermission(void);
extern void VictoryIntermission(void);
extern void CharacterCast(void);
/* In Data.c */
extern void *SpriteArray[S_LASTONE]; /* Pointers to all the sprites */
extern Word tilemap[MAPSIZE][MAPSIZE]; /* Main tile map */
extern Word ConnectCount; /* Number of valid interconnects */
extern connect_t areaconnect[MAXDOORS]; /* Is this area mated with another? */
extern Boolean areabyplayer[MAXAREAS]; /* Which areas can I see into? */
extern Word numstatics; /* Number of active static objects */
extern static_t statics[MAXSTATICS]; /* Data for the static items */
extern Word numdoors; /* Number of active door objects */
extern door_t doors[MAXDOORS]; /* Data for the door items */
extern Word nummissiles; /* Number of active missiles */
extern missile_t missiles[MAXMISSILES]; /* Data for the missile items */
extern Word numactors; /* Number of active actors */
extern actor_t actors[MAXACTORS]; /* Data for the actors */
extern t_compscale *AllScalers[MAXSCALER]; /* Pointers to all the compiled scalers */
extern Byte **GameShapes; /* Pointer to the game shape array */
extern Word difficulty; /* 0 = easy, 1= normal, 2=hard*/
extern gametype_t gamestate; /* Status of the game (Save game) */
extern exit_t playstate; /* Current status of the game */
extern Word killx,killy; /* X,Y of the thing that killed you! */
extern Boolean madenoise; /* True when shooting or screaming*/
extern Boolean playermoving; /* Is the player in motion? */
extern Boolean useheld; /* Holding down the use key? */
extern Boolean selectheld; /* Weapon select held down */
extern Boolean attackheld; /* Attack button held down? */
extern Boolean buttonstate[NUMBUTTONS]; /* Current input */
extern Word joystick1; /* Joystick value */
extern int mousex; /* Mouse x movement */
extern int mousey; /* Mouse y movement */
extern int mouseturn; /* Mouse turn factor */
extern Word nextmap; /* Next map to warp to */
extern Word facecount; /* Time to show a specific head */
extern Word faceframe; /* Head pic to show */
extern Word elevatorx,elevatory; /* x,y of the elevator */
extern Word firstframe; /* if non 0, the screen is still faded out */
extern Word OldMapNum; /* Currently loaded map # */
extern loadmap_t *MapPtr; /* Pointer to current loaded map */
extern int clipshortangle; /* Angle for the left edge of the screen */
extern int clipshortangle2; /* clipshortangle * 2 */
extern classinfo_t classinfo[]; /* Class information for all bad guys */
extern Word viewx; /* X coord of camera */
extern Word viewy; /* Y coord of camera */
extern fixed_t viewsin; /* Base sine for viewing angle */
extern fixed_t viewcos; /* Base cosine for viewing angle */
extern Word normalangle; /* Normalized angle for view (NSEW) */
extern Word centerangle; /* viewangle in fineangles*/
extern Word centershort; /* viewangle in 64k angles*/
extern Word topspritescale; /* Scale of topmost sprite */
extern Word topspritenum; /* Shape of topmost sprite */
extern Word xscale[1024]; /* Scale factor for width of the screen */
extern Word numvisspr; /* Number of valid visible sprites */
extern vissprite_t vissprites[MAXVISSPRITES]; /* Buffer for sprite records */
extern Word xevents[MAXVISSPRITES]; /* Scale events for sprite sort */
extern Word sortbuffer[MAXVISSPRITES]; /* mergesort requires an extra buffer*/
extern Word *firstevent; /* First event in sorted list */
extern Boolean areavis[MAXAREAS]; /* Area visible */
extern Word bspcoord[4]; /* Rect for the BSP search */
extern Word TicCount; /* Ticks since last screen draw */
extern Word LastTicCount; /* Tick value at start of render */
extern Word MacVidSize; /* Current 0 = 320, 1 = 512, 2 = 640 */
extern Word SlowDown; /* If true, then limit game to 30hz */
extern Word MouseEnabled; /* Allow mouse control */
extern Word GameViewSize; /* Size of the game screen */
extern Boolean IntermissionHack; /* Hack for preventing double score drawing during intermission */
extern Word NoWeaponDraw; /* Flag to not draw the weapon on the screen */
extern maplist_t *MapListPtr; /* Pointer to map info record */
extern unsigned short *SongListPtr; /* Pointer to song list record */
extern unsigned short *WallListPtr; /* Pointer to wall list record */
extern Word MaxScaler; /* Maximum number of VALID scalers */
extern Word NaziSound[]; /* Sounds for nazis starting */
extern Boolean ShowPush; /* Cheat for showing pushwalls on automap */
#endif /* __WOLFDEF__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment