commit 4ff692cf2a71f10cefc467e83c910399890747a4 Author: Braden Obrzut Date: Fri Dec 20 01:25:00 2013 -0500 The Macintosh Wolfenstein 3D as released. diff --git a/Burger.c b/Burger.c new file mode 100644 index 0000000..96ecd5e --- /dev/null +++ b/Burger.c @@ -0,0 +1 @@ +/********************************** 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 #include #include #include #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 (++xFHeight); 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); } \ No newline at end of file diff --git a/Burger.h b/Burger.h new file mode 100644 index 0000000..4e0d55f --- /dev/null +++ b/Burger.h @@ -0,0 +1 @@ +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); \ No newline at end of file diff --git a/Data.c b/Data.c new file mode 100644 index 0000000..3b2be78 --- /dev/null +++ b/Data.c @@ -0,0 +1 @@ +#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}, }; \ No newline at end of file diff --git a/Doors.c b/Doors.c new file mode 100644 index 0000000..8dd8ece --- /dev/null +++ b/Doors.c @@ -0,0 +1 @@ +#include "Wolfdef.h" #include /********************************** 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? */ } } \ No newline at end of file diff --git a/EnMove.c b/EnMove.c new file mode 100644 index 0000000..c32cd77 --- /dev/null +++ b/EnMove.c @@ -0,0 +1 @@ +/* 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<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 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)distance-= move; /* Remove the distance */ ActorPtr->x = tryx; /* Save the new x,y */ ActorPtr->y = tryy; } \ No newline at end of file diff --git a/EnThink.c b/EnThink.c new file mode 100644 index 0000000..c8929cb --- /dev/null +++ b/EnThink.c @@ -0,0 +1 @@ +#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<y = (y<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