From 4ff692cf2a71f10cefc467e83c910399890747a4 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 20 Dec 2013 01:25:00 -0500 Subject: [PATCH] The Macintosh Wolfenstein 3D as released. --- Burger.c | 1 + Burger.h | 1 + Data.c | 1 + Doors.c | 1 + EnMove.c | 1 + EnThink.c | 1 + HideMenuBar.c | 1 + HideMenuBar.h | 1 + InterMis.c | 1 + Intro.c | 1 + Level.c | 1 + MWPPCSoundMusicSystem(rev3).lib | Bin 0 -> 79818 bytes MWSoundMusicSystem(rev3).lib | 0 Mac.c | 1 + Missiles.c | 1 + Music.c | 1 + PickAMonitor.c | 1 + PickAMonitor.h | 1 + PlMove.c | 1 + PlStuff.c | 1 + PlThink.c | 1 + Prefs.h | 1 + PrefsFile.c | 1 + PushWall.c | 1 + ReadMe.txt | 1 + RefBsp.c | 1 + RefSprite.c | 1 + Refresh.c | 1 + Refresh2.c | 1 + SetupScalers68k.c | 1 + SetupScalersPPC.c | 1 + Sight.c | 1 + SnesMain.c | 1 + SoundMusicSystem.h | 1 + Sounds.h | 1 + Sprites.h | 1 + StateDef.c | 1 + States.h | 1 + Wolf.68k | 1 + Wolf.h | 1 + Wolf.ppc | 1 + Wolf3D.mcp | Bin 0 -> 204444 bytes WolfIO.c | 1 + WolfMain.c | 1 + wolf.68k.o | Bin 0 -> 396 bytes wolfdef.h | 1 + 46 files changed, 42 insertions(+) create mode 100644 Burger.c create mode 100644 Burger.h create mode 100644 Data.c create mode 100644 Doors.c create mode 100644 EnMove.c create mode 100644 EnThink.c create mode 100644 HideMenuBar.c create mode 100644 HideMenuBar.h create mode 100644 InterMis.c create mode 100644 Intro.c create mode 100644 Level.c create mode 100644 MWPPCSoundMusicSystem(rev3).lib create mode 100644 MWSoundMusicSystem(rev3).lib create mode 100644 Mac.c create mode 100644 Missiles.c create mode 100644 Music.c create mode 100644 PickAMonitor.c create mode 100644 PickAMonitor.h create mode 100644 PlMove.c create mode 100644 PlStuff.c create mode 100644 PlThink.c create mode 100644 Prefs.h create mode 100644 PrefsFile.c create mode 100644 PushWall.c create mode 100644 ReadMe.txt create mode 100644 RefBsp.c create mode 100644 RefSprite.c create mode 100644 Refresh.c create mode 100644 Refresh2.c create mode 100644 SetupScalers68k.c create mode 100644 SetupScalersPPC.c create mode 100644 Sight.c create mode 100644 SnesMain.c create mode 100644 SoundMusicSystem.h create mode 100644 Sounds.h create mode 100644 Sprites.h create mode 100644 StateDef.c create mode 100644 States.h create mode 100644 Wolf.68k create mode 100644 Wolf.h create mode 100644 Wolf.ppc create mode 100644 Wolf3D.mcp create mode 100644 WolfIO.c create mode 100644 WolfMain.c create mode 100644 wolf.68k.o create mode 100644 wolfdef.h 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