mirror of
https://github.com/Blzut3/Wolf3D-Mac.git
synced 2024-09-12 17:54:31 +00:00
1 line
61 KiB
C
1 line
61 KiB
C
/*********************
|
||
|
||
Main Macintosh code
|
||
|
||
*********************/
|
||
|
||
#include "Wolfdef.h" /* All the game equates */
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include <setjmp.h>
|
||
#include <palettes.h>
|
||
#include <qdoffscreen.h>
|
||
#include <Gestalt.h>
|
||
#include "SoundMusicSystem.h"
|
||
#include "PickAMonitor.h"
|
||
#include "Hidemenubar.h"
|
||
#include "Prefs.h"
|
||
#include <AppleEvents.h>
|
||
|
||
static Word DoMyAlert(Word AlertNum);
|
||
static void CenterSFWindow(Point *MyPoint,Word x,Word y);
|
||
static void CenterAWindow(WindowPtr MyWindow);
|
||
static void FixPauseMenu(void);
|
||
Boolean LoadGame(void);
|
||
pascal Boolean StandardModalFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *itemHit);
|
||
Word ChooseGameDiff(void);
|
||
Word DoEvent(EventRecord *event);
|
||
void DoUpdate(WindowPtr window);
|
||
void DrawWindow(WindowPtr window);
|
||
void AdjustMenus(void);
|
||
void DoMenuCommand(LongWord menuResult);
|
||
Boolean DoCloseWindow(WindowPtr window);
|
||
void InitTools(void);
|
||
void SaveGame(void);
|
||
void LoadPrefs(void);
|
||
void SavePrefs(void);
|
||
Boolean ChooseLoadGame(void);
|
||
Boolean ChooseSaveGame(void);
|
||
OSErr MyEventHandler(AppleEvent *MyAppleEvent,AppleEvent *AppleReply,long MyRefCon);
|
||
|
||
Boolean MouseHit; /* True if a mouse was pressed */
|
||
static MenuHandle PauseMenu;
|
||
static Boolean WaitNextOK; /* True if WaitNextEvent is present */
|
||
static Boolean LowOnMem; /* True if sound is disabled for low memory */
|
||
static Boolean OpenPending; /* True if a load game apple event occured */
|
||
static Byte *SaveFileName; /* Pointer to the save file name */
|
||
static short SaveFileVol; /* Directory referance for save file name */
|
||
static long SaveFileParID; /* Parent directory id of save-game file */
|
||
static Boolean ValidRects; /* Are there blank rects in the window? */
|
||
static RgnHandle BlackRgn; /* Blank region for window blanking */
|
||
static Rect QDGameRect; /* Rect of the game playing area */
|
||
static Rect GameRect = {0,0,200,320}; /* Size of the playfield */
|
||
static Rect BlackRect = {0,0,480,640}; /* Rect for the Black Window (Set to main window size) */
|
||
static Rect BlackRect2 = {0,0,480,640}; /* True rect for the Black window (Global) */
|
||
static Word OldPixDepth; /* Previous pixel depth of screen */
|
||
Word MacWidth; /* Width of play screen (Same as GameRect.right) */
|
||
Word MacHeight; /* Height of play screen (Same as GameRect.bottom) */
|
||
Word MacViewHeight; /* Height of 3d screen (Bottom of 3D view */
|
||
static Word MonitorWidth=640; /* Width of the monitor in pixels */
|
||
static Word MonitorHeight=480; /* Height of the monitor in pixels */
|
||
Word QuitFlag; /* I quit if true */
|
||
Word TrueVideoWidth; /* Width of video monitor in bytes */
|
||
Byte *TrueVideoPointer; /* Pointer to the video monitor memory */
|
||
Byte *GameVideoPointer; /* Pointer to start of 3D view on monitor memory (Used by BlastScreen) */
|
||
Boolean DoQuickDraw = TRUE; /* Use quickdraw for updates? */
|
||
static Boolean DimQD; /* Force QuickDraw forever! */
|
||
Word IgnoreMessage; /* Variable set by prefs to ignore messages */
|
||
static CursHandle WatchHandle; /* Handle to a watch cursor */
|
||
#define RectX ((MonitorWidth-MacWidth)/2)
|
||
#define RectY ((MonitorHeight-MacHeight)/2)
|
||
Word VidXs[] = {320,512,640,640}; /* Screen sizes to play with */
|
||
Word VidYs[] = {200,384,400,480};
|
||
Word VidVs[] = {160,320,320,400};
|
||
Word VidPics[] = {rFaceShapes,rFace512,rFace640,rFace640}; /* Resource #'s for art */
|
||
static Word MouseBaseX;
|
||
static Word MouseBaseY;
|
||
static Boolean InPause; /* Pause active? */
|
||
|
||
extern jmp_buf ResetJmp;
|
||
extern Boolean JumpOK;
|
||
extern CWindowPtr GameWindow; /* Pointer to main game window */
|
||
extern CGrafPtr GameGWorld; /* Grafport to offscreen buffer */
|
||
GDHandle gMainGDH; /* Main graphics handle */
|
||
CTabHandle MainColorHandle; /* Main color table handle */
|
||
|
||
static void WaitCursor(void);
|
||
static void ResetPalette(void);
|
||
static void DoBackground(EventRecord *event);
|
||
static void InitAEStuff(void);
|
||
static void FixTheCursor(void);
|
||
|
||
/***************************
|
||
|
||
Dialog filter for 68020/30 version speed warning
|
||
|
||
***************************/
|
||
|
||
#ifndef __powerc
|
||
static pascal Boolean InitFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
|
||
{
|
||
char theChar;
|
||
Handle theHandle;
|
||
short theType;
|
||
Rect theRect;
|
||
|
||
switch (theEvent->what) {
|
||
case keyDown:
|
||
theChar = theEvent->message & charCodeMask;
|
||
switch (theChar) {
|
||
case 0x0D: /* Return */
|
||
case 0x03: /* Enter */
|
||
*itemHit = 1;
|
||
return (TRUE);
|
||
}
|
||
|
||
case updateEvt:
|
||
GetDialogItem(theDialog,1, &theType, &theHandle, &theRect);
|
||
InsetRect(&theRect, -4, -4);
|
||
PenSize(3,3);
|
||
FrameRoundRect(&theRect, 16, 16);
|
||
}
|
||
return (FALSE); /* Tells dialog manager to handle the event */
|
||
}
|
||
#endif
|
||
|
||
/***************************
|
||
|
||
Init the Macintosh and all the
|
||
system tools
|
||
|
||
***************************/
|
||
|
||
void InitTools(void)
|
||
{
|
||
Handle menuBar; /* Handle to menu bar record */
|
||
Word i; /* Temp */
|
||
long Feature; /* Gestalt return value */
|
||
short int *SoundListPtr; /* Pointer to sound list for Halestorm driver */
|
||
|
||
MaxApplZone(); /* Expand the heap so code segments load at the top */
|
||
InitGraf((Ptr) &qd.thePort); /* Init the graphics system */
|
||
InitFonts(); /* Init the font manager */
|
||
InitWindows(); /* Init the window manager */
|
||
InitMenus(); /* Init the menu manager */
|
||
TEInit(); /* Init text edit */
|
||
InitDialogs(nil); /* Init the dialog manager */
|
||
i = 16; /* Make 64*16 handle records */
|
||
do {
|
||
MoreMasters(); /* Create a BUNCH of new handles */
|
||
} while (--i);
|
||
#ifdef __powerc
|
||
WaitNextOK = TRUE;
|
||
#else
|
||
if (NGetTrapAddress(0xA860,1) != (void *)0xa89F) {
|
||
WaitNextOK = TRUE;
|
||
}
|
||
#endif
|
||
|
||
InitAEStuff(); /* Apple events shit */
|
||
InitCursor(); /* Reset the cursor */
|
||
WatchHandle = GetCursor(watchCursor); /* Get the watch cursor */
|
||
HLock((Handle)WatchHandle); /* Lock it down */
|
||
WaitCursor(); /* Set the watch cursor */
|
||
LoadPrefs(); /* Load the prefs file */
|
||
|
||
/* Now that the mac is started up, let's make sure I can run on this particular mac */
|
||
|
||
#ifndef __powerc /* Power macs REQUIRE 7.1 to run so don't even check on power macs */
|
||
|
||
if (Gestalt(gestaltVersion,&Feature)) { /* Is gestalt working? */
|
||
goto Not607; /* Oh oh... */
|
||
}
|
||
|
||
/* Check for System 6.0.7 or later */
|
||
|
||
if (Gestalt(gestaltSystemVersion, &Feature) ||
|
||
(short)Feature < 0x0607) { /* Is it 6.0.7 or later? */
|
||
goto Not607;
|
||
}
|
||
|
||
#endif
|
||
|
||
/* Check for Color QuickDraw. If there's no color, quit. Below, we check for
|
||
32-bit color QuickDraw. */
|
||
|
||
if (Gestalt(gestaltQuickdrawVersion, &Feature)) {
|
||
Not607:
|
||
DoMyAlert(Not607Win); /* Alert the user */
|
||
GoodBye(); /* Exit now */
|
||
}
|
||
|
||
/* Check for 32-bit Color QuickDraw */
|
||
|
||
if( (Feature & 0x0000ffff) < 0x0200) { /* Not 32 bit? */
|
||
DoMyAlert(Not32QDWin); /* I need 32 bit quickdraw! */
|
||
GoodBye(); /* Exit */
|
||
}
|
||
|
||
/* Check the Mac's processor. If it's a 68030 or earlier, warn the user it
|
||
might be slow, and note the best ways to speed it up. */
|
||
|
||
#ifndef __powerc /* Power macs don't need this message */
|
||
Gestalt(gestaltProcessorType,&Feature);
|
||
i = 0;
|
||
switch(Feature) {
|
||
case gestalt68000:
|
||
++i;
|
||
ParamText("\p68000","\p","\p","\p");
|
||
break;
|
||
case gestalt68020:
|
||
++i;
|
||
ParamText("\p68020","\p","\p","\p");
|
||
break;
|
||
case gestalt68030:
|
||
++i;
|
||
ParamText("\p68030","\p","\p","\p");
|
||
break;
|
||
}
|
||
|
||
if (i && !IgnoreMessage) {
|
||
short theValue,itemHit,iType;
|
||
Handle iHndl;
|
||
Rect iRect;
|
||
DialogPtr MyDialog;
|
||
ModalFilterUPP theDialogFilter;
|
||
|
||
theDialogFilter = NewModalFilterProc(InitFilter); /* Create a code pointer */
|
||
MyDialog = GetNewDialog(SlowWarnWin,0L,(WindowPtr)-1); /* Load my dialog from disk */
|
||
CenterAWindow(MyDialog);
|
||
ShowWindow(MyDialog); /* Display with OK button framed */
|
||
SetPort((WindowPtr) MyDialog);
|
||
InitCursor(); /* Init the cursor */
|
||
do {
|
||
ModalDialog(theDialogFilter,&itemHit); /* Handle the dialog */
|
||
if (itemHit==2) { /* The checkbox */
|
||
GetDialogItem(MyDialog,2, &iType, &iHndl, &iRect);
|
||
theValue = GetControlValue((ControlHandle)iHndl);
|
||
SetControlValue( (ControlHandle) iHndl, !theValue );
|
||
}
|
||
} while (itemHit!=1);
|
||
GetDialogItem(MyDialog,2, &iType, &iHndl, &iRect); /* Get the check box state */
|
||
IgnoreMessage = GetControlValue((ControlHandle)iHndl);
|
||
if (IgnoreMessage) { /* If I should ignore... */
|
||
SavePrefs(); /* Save the prefs file */
|
||
}
|
||
DisposeDialog(MyDialog); /* Release the dialog memory */
|
||
}
|
||
#endif
|
||
|
||
/* Let's set up the environment... */
|
||
|
||
InitSoundMusicSystem(8,8,5,jxLowQuality);
|
||
PurgeSongs(TRUE); /* Allow songs to stay in memory */
|
||
SoundListPtr = (short int *) LoadAResource(MySoundList); /* Get the list of sounds */
|
||
RegisterSounds(SoundListPtr,FALSE);
|
||
ReleaseAResource(MySoundList); /* Release the sound list */
|
||
|
||
GetTableMemory(); /* Get memory for far tables math tables */
|
||
MapListPtr = (maplist_t *) LoadAResource(rMapList); /* Get the map list */
|
||
SongListPtr = (unsigned short *) LoadAResource(rSongList);
|
||
WallListPtr = (unsigned short *) LoadAResource(MyWallList);
|
||
|
||
/* Alert the user that you MUST pay! */
|
||
|
||
if (MapListPtr->MaxMap==3) { /* Shareware version? */
|
||
DoMyAlert(ShareWareWin); /* Show the shareware message */
|
||
}
|
||
if (FreeMem() < 3000000L) { /* Are you low on memory? */
|
||
DoMyAlert(LowMemWin);
|
||
SystemState = 0; /* Turn off music and sound (Just in case) */
|
||
LowOnMem = TRUE;
|
||
}
|
||
ShowCursor(); /* Make sure the cursor is ok */
|
||
WaitCursor(); /* Restore the watch cursor */
|
||
|
||
/* Try to set up 8-bit color mode */
|
||
|
||
gMainGDH = PickAMonitor(8,TRUE,512,384); /* Pick a monitor to play on */
|
||
if (!gMainGDH) { /* No macs that can display or canceled */
|
||
GoodBye(); /* Exit */
|
||
}
|
||
OldPixDepth = (**(**gMainGDH).gdPMap).pixelSize; /* Get the previous mode */
|
||
if (OldPixDepth != 8) { /* Was it 8 bit already? */
|
||
if (SetDepth(gMainGDH,8, 1 << gdDevType,1)) { /* Set to 8 bit */
|
||
BailOut(); /* Oh oh... */
|
||
}
|
||
}
|
||
MainColorHandle = (*(*gMainGDH)->gdPMap)->pmTable; /* Get my main device's color handle */
|
||
BlackRect2 = (**gMainGDH).gdRect; /* Init the black rect */
|
||
LockPixels((**gMainGDH).gdPMap); /* Lock down the memory FOREVER! */
|
||
TrueVideoPointer = (Byte *) GetPixBaseAddr((**gMainGDH).gdPMap); /* Get pointer to screen mem */
|
||
TrueVideoWidth = (Word) ((**(**gMainGDH).gdPMap).rowBytes & 0x3FFF); /* Get width of screen mem */
|
||
|
||
if (!TrueVideoPointer || !TrueVideoWidth) {
|
||
DimQD = TRUE; /* Don't allow offscreen drawing */
|
||
DoQuickDraw = TRUE; /* Force QD */
|
||
}
|
||
MonitorHeight = BlackRect2.bottom - BlackRect2.top; /* Get the size of the video screen */
|
||
MonitorWidth = BlackRect2.right - BlackRect2.left;
|
||
MouseBaseX = BlackRect2.left+256;
|
||
MouseBaseY = BlackRect2.top+192;
|
||
|
||
menuBar = GetNewMBar(MyMenuBar); /* read menus into menu bar */
|
||
if (!menuBar) {
|
||
BailOut(); /* Menu bar error */
|
||
}
|
||
SetMenuBar(menuBar); /* install menus */
|
||
DisposeHandle(menuBar); /* Release the menu bar */
|
||
AppendResMenu(GetMenuHandle(mApple),'DRVR'); /* add DA names to Apple menu */
|
||
DrawMenuBar(); /* Show the menu bar */
|
||
HideMenuBar(); /* Hide the menu bar */
|
||
|
||
GameWindow = (CWindowPtr)NewCWindow(nil,&BlackRect2, "\p",TRUE, plainDBox, (WindowPtr) -1L, FALSE, 0);
|
||
if (!GameWindow) { /* No background window? */
|
||
BailOut();
|
||
}
|
||
BlackRgn = NewRgn(); /* Make a region for the black area */
|
||
SetPort((WindowPtr)GameWindow); /* Use this grafport */
|
||
ActivatePalette((WindowPtr)GameWindow);
|
||
BlackRect.top = 0; /* Init the main rect */
|
||
BlackRect.left = 0;
|
||
BlackRect.bottom = MonitorHeight;
|
||
BlackRect.right = MonitorWidth;
|
||
FillRect(&BlackRect,&qd.black); /* Erase the screen to black */
|
||
NewGameWindow(1); /* Create a game window at 512x384 */
|
||
ClearTheScreen(BLACK); /* Force the offscreen memory blank */
|
||
BlastScreen();
|
||
FixTheCursor(); /* Fix the cursor */
|
||
}
|
||
|
||
/************************************
|
||
|
||
Set the hardware palette to match my window palette for high speed
|
||
copybits operation
|
||
|
||
************************************/
|
||
|
||
extern Byte CurrentPal[768]; /* Last palette the game was set to */
|
||
|
||
static void ResetPalette(void)
|
||
{
|
||
SetPort((WindowPtr) GameWindow); /* Reset the game window */
|
||
if ((**(**gMainGDH).gdPMap).pixelSize != 8) { /* Get the previous mode */
|
||
SetDepth(gMainGDH,8, 1 << gdDevType,1); /* Set to 8 bit color */
|
||
}
|
||
SetAPalettePtr(CurrentPal); /* Restore the palette */
|
||
}
|
||
|
||
/************************************
|
||
|
||
Process the suspend/resume events
|
||
|
||
************************************/
|
||
|
||
static void DoBackground(EventRecord *event)
|
||
{
|
||
EventRecord PauseEvent;
|
||
|
||
if ((event->message & 0xff000000) ==0x01000000) { /* Suspend/Resume events */
|
||
if (!(event->message & resumeFlag)) { /* Suspend event? */
|
||
if (!InPause) {
|
||
PauseSoundMusicSystem(); /* Stop the music */
|
||
ShowMenuBar(); /* Display the menu bar */
|
||
}
|
||
InitCursor(); /* Restore the arrow cursor */
|
||
|
||
/* Call a new event loop while in background to let us know when we've returned. */
|
||
|
||
do {
|
||
WaitNextEvent2(everyEvent, &PauseEvent, 0xFF, nil);
|
||
if (PauseEvent.what==updateEvt) { /* Time for update? */
|
||
DoUpdate((WindowPtr) PauseEvent.message); /* Redraw the window */
|
||
}
|
||
} while (PauseEvent.what!=mouseDown && PauseEvent.what!=activateEvt && PauseEvent.what!=app4Evt);
|
||
|
||
/* Turn the main game window back on and update its contents. */
|
||
|
||
ResetPalette(); /* Reset the game palette */
|
||
FixTheCursor(); /* Make it disappear for game if needed */
|
||
if (!InPause) {
|
||
HideMenuBar(); /* Make the menu bar disappear */
|
||
ResumeSoundMusicSystem(); /* Restart the music */
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/************************************
|
||
|
||
Call Wait next event if present
|
||
|
||
************************************/
|
||
|
||
Boolean WaitNextEvent2(short EventMask,EventRecord *theEvent,long sleep,RgnHandle mouseRgn)
|
||
{
|
||
if (WaitNextOK) {
|
||
return WaitNextEvent(EventMask,theEvent,sleep,mouseRgn);
|
||
}
|
||
SystemTask();
|
||
return GetNextEvent(EventMask,theEvent);
|
||
}
|
||
|
||
/************************************
|
||
|
||
Execute the apple event
|
||
|
||
************************************/
|
||
|
||
static void HandleHighLevelEvent(EventRecord *event)
|
||
{
|
||
AEProcessAppleEvent(event);
|
||
if (QuitFlag) {
|
||
GoodBye();
|
||
}
|
||
}
|
||
|
||
/************************************
|
||
|
||
Do the right thing for an event. Determine what kind of
|
||
event it is, and call the appropriate routines.
|
||
This is like TaskMaster for the IIgs
|
||
|
||
************************************/
|
||
|
||
Word DoEvent(EventRecord *event)
|
||
{
|
||
Word part;
|
||
WindowPtr window;
|
||
Word key;
|
||
Point aPoint;
|
||
|
||
switch (event->what) { /* Process the event */
|
||
case kHighLevelEvent: /* Apple events? */
|
||
HandleHighLevelEvent(event); /* Pass it on... */
|
||
break;
|
||
|
||
case mouseDown: /* Pressed the mouse? */
|
||
FixMHeight(); /* Allow menu bar clicks */
|
||
part = FindWindow(event->where, &window); /* Choose the hit */
|
||
ZapMHeight(); /* Don't click anymore */
|
||
switch (part) {
|
||
case inMenuBar: /* process a mouse menu command (if any) */
|
||
AdjustMenus(); /* Enable/disable menu items */
|
||
ShowMenuBar(); /* Display the menu bar */
|
||
DoMenuCommand(MenuSelect(event->where)); /* Handle the command */
|
||
if (!InPause) {
|
||
HideMenuBar(); /* Hide the menu bar */
|
||
}
|
||
break;
|
||
case inSysWindow: /* let the system handle the mouseDown */
|
||
SystemClick(event, window); /* Pass on the event */
|
||
break;
|
||
case inContent:
|
||
if (window != FrontWindow() ) {
|
||
SelectWindow(window); /* Make it the front window */
|
||
}
|
||
if (window == (WindowPtr)GameWindow) {
|
||
MouseHit = TRUE;
|
||
}
|
||
break;
|
||
case inDrag: /* pass screenBits.bounds to get all gDevices */
|
||
DragWindow(window, event->where, &qd.screenBits.bounds);
|
||
break;
|
||
case inGoAway:
|
||
if (TrackGoAway(window,event->where)) { /* Handle the close box */
|
||
DoCloseWindow(window); /* Close my window */
|
||
}
|
||
break;
|
||
case inZoomIn:
|
||
case inZoomOut:
|
||
if (TrackBox(window, event->where, part)) { /* Track the zoom box */
|
||
SetPort(window); /* the window must be the current port... */
|
||
EraseRect(&window->portRect); /* because of a bug in ZoomWindow */
|
||
ZoomWindow(window,part,TRUE); /* note that we invalidate and erase... */
|
||
InvalRect(&window->portRect); /* to make things look better on-screen */
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
case keyDown:
|
||
case autoKey: /* check for menukey equivalents */
|
||
key = event->message & charCodeMask;
|
||
if (event->modifiers & cmdKey) { /* Command key down */
|
||
if (event->what == keyDown) {
|
||
AdjustMenus(); /* enable/disable/check menu items properly */
|
||
DoMenuCommand(MenuKey(key)); /* Process the key */
|
||
}
|
||
return 0; /* Ignore the event */
|
||
}
|
||
return key; /* Return the key pressed */
|
||
case updateEvt:
|
||
DoUpdate((WindowPtr) event->message); /* Force redraw of my window */
|
||
break;
|
||
case diskEvt:
|
||
if ((event->message>>16) != noErr ) { /* Was there an error? */
|
||
SetPt(&aPoint, kDILeft, kDITop);
|
||
DIBadMount(aPoint, event->message); /* Format the disk? */
|
||
}
|
||
break;
|
||
case activateEvt:
|
||
if (event->modifiers & 1) {
|
||
FixTheCursor(); /* Reset the cursor to the hidden state */
|
||
SetPort((WindowPtr)GameWindow);
|
||
ResetPalette(); /* Set my system palette */
|
||
}
|
||
break;
|
||
case osEvt:
|
||
DoBackground(event); /* Process suspend / resume */
|
||
break;
|
||
}
|
||
if (OpenPending && JumpOK) {
|
||
OpenPending=FALSE; /* Ack the event */
|
||
if (LoadGame()) { /* Load the game into memory */
|
||
longjmp(ResetJmp,EX_LOADGAME); /* Restart a loaded game */
|
||
}
|
||
}
|
||
if (!InPause) {
|
||
HideMenuBar(); /* Make SURE the menu bar is gone! */
|
||
}
|
||
return 0; /* No event processed */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Call this when I receive an update event
|
||
|
||
**********************************/
|
||
|
||
void DoUpdate(WindowPtr window)
|
||
{
|
||
if (((WindowPeek) window)->windowKind >=0) { /* Is this my window? */
|
||
BeginUpdate(window); /* this sets up the visRgn */
|
||
DrawWindow(window); /* Draw the game window */
|
||
EndUpdate(window); /* Fix the visRgn */
|
||
}
|
||
}
|
||
|
||
/************************
|
||
|
||
Update the contents of the window
|
||
|
||
************************/
|
||
|
||
void DrawWindow(WindowPtr window)
|
||
{
|
||
Word OldQuick; /* Previous state of the quickdraw flag */
|
||
if (window == (WindowPtr) GameWindow) { /* Is it my window? */
|
||
SetPort((WindowPtr)GameWindow);
|
||
OldQuick = DoQuickDraw; /* Save the quickdraw flag */
|
||
DoQuickDraw = TRUE; /* Force quickdraw */
|
||
BlastScreen(); /* Update the screen */
|
||
DoQuickDraw = OldQuick; /* Restore quickdraw flag */
|
||
if (ValidRects) { /* Black region valid? */
|
||
FillRgn(BlackRgn,&qd.black); /* Fill the black region */
|
||
}
|
||
}
|
||
}
|
||
|
||
/****************************
|
||
|
||
Set an item's mark with a check mark
|
||
|
||
****************************/
|
||
|
||
static void SetAMark(MenuHandle MyHand,Word Which,Word Var)
|
||
{
|
||
Var = (Var) ? 0x12 : 0;
|
||
SetItemMark(MyHand,Which,Var);
|
||
}
|
||
|
||
/****************************
|
||
|
||
Enable and disable menu items
|
||
|
||
****************************/
|
||
|
||
void AdjustMenus(void)
|
||
{
|
||
WindowPtr window;
|
||
MenuHandle FileMenu,EditMenu,OptionMenu;
|
||
|
||
window = FrontWindow(); /* Which window is in front */
|
||
FileMenu = GetMenuHandle(mFile); /* Get the file menu handle */
|
||
EditMenu = GetMenuHandle(mEdit); /* Get the edit menu handle */
|
||
OptionMenu = GetMenuHandle(mOptions);
|
||
if (window!=(WindowPtr)GameWindow) { /* Enable if there is a window */
|
||
EnableItem(FileMenu,iClose);
|
||
EnableItem(EditMenu,0);
|
||
} else {
|
||
DisableItem(FileMenu,iClose);
|
||
DisableItem(EditMenu,0);
|
||
}
|
||
if (playstate == EX_STILLPLAYING) { /* Game is in progress */
|
||
EnableItem(FileMenu,iSaveAs); /* Save the game */
|
||
EnableItem(FileMenu,iSave); /* Quicksave the game */
|
||
} else {
|
||
DisableItem(FileMenu,iSaveAs); /* Can't save game when isn't in the mode */
|
||
DisableItem(FileMenu,iSave);
|
||
}
|
||
if (LowOnMem) {
|
||
DisableItem(OptionMenu,iSound);
|
||
DisableItem(OptionMenu,iMusic);
|
||
}
|
||
if (DimQD) {
|
||
DisableItem(OptionMenu,iUseQuickDraw);
|
||
}
|
||
if (playstate==EX_AUTOMAP || playstate==EX_DIED) {
|
||
DisableItem(OptionMenu,iScreenSize);
|
||
} else {
|
||
EnableItem(OptionMenu,iScreenSize);
|
||
}
|
||
SetAMark(OptionMenu,iSound,SystemState&SfxActive); /* Check the sound menu */
|
||
SetAMark(OptionMenu,iMusic,SystemState&MusicActive); /* Check the music menu */
|
||
SetAMark(OptionMenu,iGovenor,SlowDown); /* Check the Speed goveror */
|
||
SetAMark(OptionMenu,iMouseControl,MouseEnabled); /* Check the mouse flag */
|
||
SetAMark(OptionMenu,iUseQuickDraw,DoQuickDraw); /* Check the mouse flag */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Process a menu bar event
|
||
|
||
**********************************/
|
||
|
||
void DoMenuCommand(LongWord menuResult)
|
||
{
|
||
Word menuID; /* the resource ID of the selected menu */
|
||
Word menuItem; /* the item number of the selected menu */
|
||
Str255 daName; /* Name of desk acc */
|
||
Word i; /* Temp */
|
||
|
||
menuID = menuResult>>16;
|
||
menuItem = menuResult&0xffff; /* get menu item number and menu number */
|
||
switch (menuID) {
|
||
case mApple: /* Apple menu */
|
||
switch (menuItem) {
|
||
case iAbout: /* Bring up alert for About */
|
||
PlaySound(SND_MENU);
|
||
DoMyAlert(rAboutAlert); /* Show the credits */
|
||
PlaySound(SND_OK);
|
||
break;
|
||
case iSpeedHint:
|
||
PlaySound(SND_MENU);
|
||
DoMyAlert(SpeedTipsWin); /* Show the hints for speed */
|
||
PlaySound(SND_OK);
|
||
break;
|
||
case iShareWare:
|
||
PlaySound(SND_MENU);
|
||
DoMyAlert(ShareWareWin); /* Ask about $$$ */
|
||
PlaySound(SND_OK);
|
||
break;
|
||
default: /* all non-About items in this menu are DAs */
|
||
GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
|
||
OpenDeskAcc(daName);
|
||
break;
|
||
}
|
||
break;
|
||
case mFile: /* File menu */
|
||
switch (menuItem) {
|
||
case iNew:
|
||
if (ChooseGameDiff()) { /* Choose level of difficulty */
|
||
HiliteMenu(0);
|
||
FixPauseMenu();
|
||
SaveFileName = 0; /* Zap the save game name */
|
||
longjmp(ResetJmp,EX_NEWGAME);
|
||
}
|
||
break;
|
||
case iClose:
|
||
DoCloseWindow(FrontWindow());
|
||
break;
|
||
case iOpen:
|
||
if (ChooseLoadGame()) { /* Choose a game to load */
|
||
if (LoadGame()) { /* Load the game into memory */
|
||
HiliteMenu(0);
|
||
FixPauseMenu();
|
||
longjmp(ResetJmp,EX_LOADGAME); /* Restart a loaded game */
|
||
}
|
||
}
|
||
break;
|
||
case iSave:
|
||
if (SaveFileName) { /* Save the file automatically? */
|
||
SaveGame(); /* Save it */
|
||
break;
|
||
}
|
||
case iSaveAs:
|
||
if (ChooseSaveGame()) { /* Select a save game name */
|
||
SaveGame(); /* Save it */
|
||
}
|
||
break;
|
||
case iQuit:
|
||
GoodBye(); /* Try to quit */
|
||
break;
|
||
}
|
||
break;
|
||
case mEdit: /* call SystemEdit for DA editing & MultiFinder */
|
||
SystemEdit(menuItem-1); /* since we don't do any Editing */
|
||
break;
|
||
case mOptions:
|
||
switch (menuItem) {
|
||
case iSound:
|
||
SystemState^=SfxActive; /* Sound on/off flags */
|
||
if (!(SystemState&SfxActive)) {
|
||
if (InPause) {
|
||
ResumeSoundMusicSystem();
|
||
}
|
||
PlaySound(0); /* Turn off all existing sounds */
|
||
if (InPause) {
|
||
PauseSoundMusicSystem();
|
||
}
|
||
}
|
||
break;
|
||
case iMusic:
|
||
SystemState^=MusicActive; /* Music on/off flags */
|
||
if (InPause) {
|
||
ResumeSoundMusicSystem();
|
||
}
|
||
if (SystemState&MusicActive) {
|
||
PlaySong(KilledSong); /* Restart the music */
|
||
} else {
|
||
PlaySong(0); /* Shut down the music */
|
||
}
|
||
if (InPause) {
|
||
PauseSoundMusicSystem();
|
||
}
|
||
break;
|
||
case iScreenSize:
|
||
i = DoMyAlert(AskSizeWin); /* Should I change the size? */
|
||
if (i && i<5) {
|
||
--i;
|
||
if (GameViewSize!=i) { /* Did you change the size? */
|
||
if (!InPause) {
|
||
HideMenuBar();
|
||
}
|
||
MouseHit = TRUE; /* Get out of pause mode */
|
||
GameViewSize = i; /* Set the new size */
|
||
if (playstate==EX_STILLPLAYING || playstate==EX_AUTOMAP) {
|
||
TryIt:
|
||
GameViewSize = NewGameWindow(GameViewSize); /* Make a new window */
|
||
if (!StartupRendering(GameViewSize)) { /* Set the size of the game screen */
|
||
ReleaseScalers();
|
||
if (!GameViewSize) {
|
||
BailOut();
|
||
}
|
||
--GameViewSize;
|
||
goto TryIt;
|
||
}
|
||
if (playstate==EX_STILLPLAYING) {
|
||
RedrawStatusBar(); /* Redraw the lower area */
|
||
}
|
||
playstate=EX_STILLPLAYING;
|
||
SetAPalette(rGamePal); /* Reset the game palette */
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case iGovenor:
|
||
SlowDown^=1; /* Toggle the slow down flag */
|
||
break;
|
||
case iMouseControl:
|
||
MouseEnabled = (!MouseEnabled); /* Toggle the cursor */
|
||
FixTheCursor();
|
||
if (MouseEnabled) {
|
||
ReadSystemJoystick();
|
||
mousex = 0;
|
||
mousey = 0;
|
||
mouseturn=0;
|
||
ReadSystemJoystick();
|
||
mousex =0; /* Discard the results */
|
||
mousey =0;
|
||
mouseturn=0;
|
||
}
|
||
break;
|
||
case iUseQuickDraw:
|
||
DoQuickDraw^=TRUE; /* Toggle the quickdraw flag */
|
||
break;
|
||
}
|
||
SavePrefs();
|
||
break;
|
||
}
|
||
HiliteMenu(0); /* unhighlight what MenuSelect (or MenuKey) hilited */
|
||
}
|
||
|
||
/*********************************
|
||
|
||
Close a window, return TRUE if successful
|
||
|
||
*********************************/
|
||
|
||
Boolean DoCloseWindow(WindowPtr window)
|
||
{
|
||
int Kind;
|
||
|
||
if (window) { /* Valid pointer? */
|
||
Kind = ((WindowPeek) window)->windowKind; /* Get the kind */
|
||
if (Kind<0) {
|
||
CloseDeskAcc(Kind);
|
||
}
|
||
}
|
||
return TRUE; /* I closed it! */
|
||
}
|
||
|
||
/***************************
|
||
|
||
I can't load! Bail out now!
|
||
|
||
****************************/
|
||
|
||
void BailOut(void)
|
||
{
|
||
DoMyAlert(rUserAlert); /* Show the alert window */
|
||
GoodBye(); /* Bail out! */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Update the wolf screen as fast as possible
|
||
|
||
Make sure that ForeColor = BLACK and Color = WHITE,
|
||
ROWBYTES should be long aligned (4,8,12,16...)
|
||
Source and dest should be EXACTLY the same bit depth
|
||
ctSeed should match the WINDOW's color seed
|
||
Both rects should be multiples of 4 to make long word transfers only
|
||
|
||
**********************************/
|
||
|
||
void BlastScreen2(Rect *BlastRect)
|
||
{
|
||
Rect QDRect;
|
||
CTabHandle ColorHandle,ColorHandle2;
|
||
|
||
QDRect = *BlastRect;
|
||
OffsetRect(&QDRect,QDGameRect.left,QDGameRect.top);
|
||
SetPort((WindowPtr) GameWindow); /* Make sure the port is set */
|
||
ColorHandle = (**(*GameGWorld).portPixMap).pmTable; /* Get the color table */
|
||
ColorHandle2 = (**(*GameWindow).portPixMap).pmTable; /* Get the color table */
|
||
PtrToXHand(*MainColorHandle,(Handle)ColorHandle,8+8*256);
|
||
PtrToXHand(*MainColorHandle,(Handle)ColorHandle2,8+8*256);
|
||
CopyBits((BitMap *) *((*GameGWorld).portPixMap),(BitMap *) *((*GameWindow).portPixMap),
|
||
BlastRect,&QDRect,srcCopy,NULL);
|
||
|
||
}
|
||
|
||
void BlastScreen(void)
|
||
{
|
||
Word i,j,k,m;
|
||
Byte *Screenad;
|
||
LongWord *Dest;
|
||
union {
|
||
LongWord * L;
|
||
Byte *B;
|
||
} Src;
|
||
Point MyPoint;
|
||
|
||
MyPoint.h = BlackRect2.left;
|
||
MyPoint.v = BlackRect2.top;
|
||
ShieldCursor(&GameRect,MyPoint);
|
||
if (!DoQuickDraw) {
|
||
i = MacHeight;
|
||
k = MacWidth/64;
|
||
m = VideoWidth - MacWidth;
|
||
Src.B = VideoPointer; /* Pointer to video */
|
||
Screenad = GameVideoPointer; /* Get dest video address */
|
||
do {
|
||
j = k; /* Init width (In Longs) */
|
||
Dest = (LongWord *) Screenad; /* Reset the dest pointer */
|
||
do {
|
||
Dest[0] = Src.L[0];
|
||
Dest[1] = Src.L[1];
|
||
Dest[2] = Src.L[2];
|
||
Dest[3] = Src.L[3];
|
||
Dest[4] = Src.L[4];
|
||
Dest[5] = Src.L[5];
|
||
Dest[6] = Src.L[6];
|
||
Dest[7] = Src.L[7];
|
||
Dest[8] = Src.L[8];
|
||
Dest[9] = Src.L[9];
|
||
Dest[10] = Src.L[10];
|
||
Dest[11] = Src.L[11];
|
||
Dest[12] = Src.L[12];
|
||
Dest[13] = Src.L[13];
|
||
Dest[14] = Src.L[14];
|
||
Dest[15] = Src.L[15];
|
||
Dest+=16;
|
||
Src.L+=16;
|
||
} while (--j);
|
||
Src.B += m;
|
||
Screenad+=TrueVideoWidth;
|
||
} while (--i);
|
||
} else {
|
||
BlastScreen2(&GameRect);
|
||
}
|
||
ShowCursor();
|
||
if (!InPause) {
|
||
ObscureCursor();
|
||
}
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Create a new game window
|
||
|
||
**********************************/
|
||
|
||
Word NewGameWindow(Word NewVidSize)
|
||
{
|
||
Byte *DestPtr;
|
||
LongWord *LongPtr;
|
||
Word i,j;
|
||
Boolean Pass2;
|
||
RgnHandle TempRgn;
|
||
|
||
Pass2 = FALSE; /* Assume memory is OK */
|
||
|
||
/* First, kill ALL previous permenant records */
|
||
|
||
if (NewVidSize>=2) { /* Is this 640 mode? */
|
||
if (MonitorWidth<640) { /* Can I show 640 mode? */
|
||
NewVidSize=1; /* Reduce to 512 mode */
|
||
} else {
|
||
if (MonitorHeight<480) { /* Can I display 480 lines? */
|
||
NewVidSize=2; /* Show 400 instead */
|
||
}
|
||
}
|
||
}
|
||
if (NewVidSize==MacVidSize) { /* Same size being displayed? */
|
||
return MacVidSize; /* Exit then... */
|
||
}
|
||
SetPort((WindowPtr)GameWindow); /* Blank out the screen! */
|
||
ForeColor(blackColor); /* Make sure the colors are set */
|
||
BackColor(whiteColor);
|
||
FillRect(&BlackRect,&qd.black); /* Blank it out! */
|
||
|
||
TryAgain:
|
||
if (GameGWorld) {
|
||
DisposeGWorld(GameGWorld); /* Release the old GWorld */
|
||
GameGWorld=0;
|
||
}
|
||
if (GameShapes) {
|
||
FreeSomeMem(GameShapes); /* All the permanent game shapes */
|
||
GameShapes=0;
|
||
}
|
||
MacVidSize = NewVidSize; /* Set the new data size */
|
||
MacWidth = VidXs[NewVidSize];
|
||
MacHeight = VidYs[NewVidSize];
|
||
MacViewHeight = VidVs[NewVidSize];
|
||
|
||
GameRect.bottom = MacHeight; /* Set new video height */
|
||
GameRect.right = MacWidth; /* Set new video width */
|
||
QDGameRect.top = RectY;
|
||
QDGameRect.left = RectX;
|
||
QDGameRect.bottom = RectY+MacHeight;
|
||
QDGameRect.right = RectX+MacWidth;
|
||
|
||
if (MacHeight==MonitorHeight && MacWidth==MonitorWidth) {
|
||
ValidRects = FALSE;
|
||
} else {
|
||
ValidRects = TRUE; /* The 4 bar rects are valid */
|
||
RectRgn(BlackRgn,&BlackRect);
|
||
TempRgn = NewRgn();
|
||
RectRgn(TempRgn,&QDGameRect);
|
||
DiffRgn(BlackRgn,TempRgn,BlackRgn);
|
||
DisposeRgn(TempRgn);
|
||
}
|
||
|
||
GameVideoPointer = &TrueVideoPointer[(LongWord)QDGameRect.top*TrueVideoWidth+QDGameRect.left];
|
||
if (NewGWorld(&GameGWorld,8,&GameRect,nil,nil,0)) {
|
||
goto OhShit;
|
||
}
|
||
LockPixels(GameGWorld->portPixMap); /* Lock down the memory FOREVER! */
|
||
VideoPointer = (Byte *)GetPixBaseAddr(GameGWorld->portPixMap); /* Get the video pointer */
|
||
VideoWidth = (Word) (**(*GameGWorld).portPixMap).rowBytes & 0x3FFF;
|
||
InitYTable(); /* Init the game's YTable */
|
||
SetAPalette(rBlackPal); /* Set the video palette */
|
||
ClearTheScreen(BLACK); /* Set the screen to black */
|
||
BlastScreen();
|
||
|
||
LongPtr = (LongWord *) LoadAResource(VidPics[MacVidSize]);
|
||
if (!LongPtr) {
|
||
goto OhShit;
|
||
}
|
||
GameShapes = (Byte **) AllocSomeMem(LongPtr[0]); /* All the permanent game shapes */
|
||
if (!GameShapes) { /* Can't load in the shapes */
|
||
ReleaseAResource(VidPics[MacVidSize]); /* Release it NOW! */
|
||
goto OhShit;
|
||
}
|
||
DLZSS((Byte *)GameShapes,(Byte *) &LongPtr[1],LongPtr[0]);
|
||
ReleaseAResource(VidPics[MacVidSize]);
|
||
i = 0;
|
||
j = (MacVidSize==1) ? 47+10 : 47; /* 512 mode has 10 shapes more */
|
||
DestPtr = (Byte *) GameShapes;
|
||
LongPtr = (LongWord *) GameShapes;
|
||
do {
|
||
GameShapes[i] = DestPtr+LongPtr[i];
|
||
} while (++i<j);
|
||
if (Pass2) { /* Low memory? */
|
||
if (!StartupRendering(NewVidSize)) { /* Reset the scalers... */
|
||
ReleaseScalers();
|
||
goto OhShit;
|
||
}
|
||
}
|
||
return MacVidSize;
|
||
|
||
OhShit: /* Oh oh.... */
|
||
if (Pass2) {
|
||
if (!NewVidSize) { /* At the smallest screen size? */
|
||
BailOut();
|
||
}
|
||
--NewVidSize; /* Smaller size */
|
||
} else {
|
||
PlaySong(0); /* Release song memory */
|
||
ReleaseScalers(); /* Release the compiled scalers */
|
||
PurgeAllSounds(1000000); /* Force sounds to be purged */
|
||
Pass2 = TRUE;
|
||
}
|
||
goto TryAgain; /* Let's try again */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Scale the system X coord
|
||
|
||
**********************************/
|
||
|
||
Word ScaleX(Word x)
|
||
{
|
||
switch(MacVidSize) {
|
||
case 1:
|
||
return x*8/5;
|
||
case 2:
|
||
case 3:
|
||
return x*2;
|
||
}
|
||
return x;
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Scale the system Y coord
|
||
|
||
**********************************/
|
||
|
||
Word ScaleY(Word y)
|
||
{
|
||
switch(MacVidSize) {
|
||
case 1: /* 512 resolution */
|
||
y = (y*8/5)+64;
|
||
if (y==217) { /* This hack will line up the gun on 512 mode */
|
||
++y;
|
||
}
|
||
return y;
|
||
case 2: /* 640 x 400 */
|
||
return y*2;
|
||
case 3: /* 640 x 480 */
|
||
return y*2+80;
|
||
}
|
||
return y; /* 320 resolution */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Shut down and exit
|
||
|
||
**********************************/
|
||
|
||
void GoodBye(void)
|
||
{
|
||
ShowMenuBar(); /* Restore the menu bar */
|
||
ReleaseScalers(); /* Release all my memory */
|
||
FinisSoundMusicSystem(); /* Shut down the Halestorm driver */
|
||
if (gMainGDH && OldPixDepth) { /* Old pixel depth */
|
||
SetDepth(gMainGDH,OldPixDepth, 1 << gdDevType,1); /* Restore the depth */
|
||
}
|
||
InitCursor();
|
||
ExitToShell(); /* Exit to System 7 */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Read from the Mac's keyboard/mouse system
|
||
|
||
**********************************/
|
||
|
||
Word MyKey;
|
||
|
||
typedef struct MacKeys2Joy {
|
||
Word Index;
|
||
Word BitField;
|
||
Word JoyValue;
|
||
} MacKeys2Joy;
|
||
|
||
MacKeys2Joy KeyMatrix[] = {
|
||
{11,1<<1,JOYPAD_LFT|JOYPAD_UP}, /* Keypad 7 */
|
||
{10,1<<6,JOYPAD_LFT}, /* Keypad 4 */
|
||
{10,1<<3,JOYPAD_LFT|JOYPAD_DN}, /* Keypad 1 */
|
||
{11,1<<3,JOYPAD_UP}, /* Keypad 8 */
|
||
{10,1<<7,JOYPAD_DN}, /* Keypad 5 */
|
||
{10,1<<4,JOYPAD_DN}, /* Keypad 2 */
|
||
{11,1<<4,JOYPAD_RGT|JOYPAD_UP}, /* Keypad 9 */
|
||
{11,1<<0,JOYPAD_RGT}, /* Keypad 6 */
|
||
{10,1<<5,JOYPAD_RGT|JOYPAD_DN}, /* Keypad 3 */
|
||
{15,1<<6,JOYPAD_UP}, /* Arrow up */
|
||
{15,1<<5,JOYPAD_DN}, /* Arrow down */
|
||
{15,1<<3,JOYPAD_LFT}, /* Arrow Left */
|
||
{15,1<<4,JOYPAD_RGT}, /* Arrow Right */
|
||
{ 1,1<<5,JOYPAD_UP}, /* W */
|
||
{ 0,1<<0,JOYPAD_LFT}, /* A */
|
||
{ 0,1<<1,JOYPAD_DN}, /* S */
|
||
{ 0,1<<2,JOYPAD_RGT}, /* D */
|
||
{ 4,1<<2,JOYPAD_UP}, /* I */
|
||
{ 4,1<<6,JOYPAD_LFT}, /* J */
|
||
{ 5,1<<0,JOYPAD_DN}, /* K */
|
||
{ 4,1<<5,JOYPAD_RGT}, /* L */
|
||
{ 6,1<<1,JOYPAD_A}, /* Space */
|
||
{ 4,1<<4,JOYPAD_A}, /* Return */
|
||
{10,1<<2,JOYPAD_A}, /* Keypad 0 */
|
||
{ 9,1<<4,JOYPAD_A}, /* keypad enter */
|
||
{ 7,1<<7,JOYPAD_TR}, /* Option */
|
||
{ 7,1<<2,JOYPAD_TR}, /* Option */
|
||
{ 7,1<<0,JOYPAD_X}, /* Shift L */
|
||
{ 7,1<<1,JOYPAD_X}, /* Caps Lock */
|
||
{ 7,1<<4,JOYPAD_X}, /* Shift R */
|
||
{ 6,1<<0,JOYPAD_SELECT}, /* Tab */
|
||
{ 7,1<<3,JOYPAD_B}, /* Ctrl */
|
||
{ 7,1<<6,JOYPAD_B} /* Ctrl */
|
||
};
|
||
|
||
static char *CheatPtr[] = { /* Cheat strings */
|
||
"XUSCNIELPPA",
|
||
"IDDQD",
|
||
"BURGER",
|
||
"WOWZERS",
|
||
"LEDOUX",
|
||
"SEGER",
|
||
"MCCALL",
|
||
"APPLEIIGS"
|
||
};
|
||
static Word Cheat; /* Which cheat is active */
|
||
static Word CheatIndex; /* Index to the cheat string */
|
||
|
||
static void FixPauseMenu(void)
|
||
{
|
||
if (PauseMenu) { /* Is there a pause menu? */
|
||
InPause = FALSE;
|
||
DeleteMenu(55); /* Remove it from the menu bar */
|
||
DrawMenuBar(); /* Redraw the menu bar */
|
||
HideMenuBar(); /* Hide the menu bar */
|
||
DisposeMenu(PauseMenu); /* Free the memory */
|
||
PauseMenu = 0; /* Ack the flag */
|
||
ResumeSoundMusicSystem(); /* Restart the music */
|
||
}
|
||
}
|
||
|
||
void ReadSystemJoystick(void)
|
||
{
|
||
Word i;
|
||
Word Index;
|
||
|
||
MacKeys2Joy *MacPtr;
|
||
Point MyPoint;
|
||
union {
|
||
unsigned char Keys[16];
|
||
KeyMap Macy;
|
||
} Keys;
|
||
|
||
joystick1 = 0; /* Assume that joystick not moved */
|
||
|
||
i = GetAKey(); /* Allow menu events */
|
||
if (i==0x1b) { /* Pause key? */
|
||
ShowMenuBar();
|
||
InitCursor();
|
||
PauseMenu = NewMenu(55,"\p<< Game is Paused! >>");
|
||
InsertMenu(PauseMenu,0);
|
||
DrawMenuBar();
|
||
PauseSoundMusicSystem(); /* Pause the music */
|
||
InPause = TRUE; /* Hack to prevent the menu bar from disappearing */
|
||
WaitTicksEvent(0);
|
||
LastTicCount = ReadTick(); /* Reset the timer for the pause key */
|
||
FixPauseMenu(); /* Exit pause */
|
||
FixTheCursor();
|
||
}
|
||
|
||
/* Switch weapons like in DOOM! */
|
||
|
||
if (i) { /* Was a key hit? */
|
||
i = toupper(i); /* Force UPPER case */
|
||
if (CheatIndex) { /* Cheat in progress */
|
||
if (CheatPtr[Cheat][CheatIndex]==i) { /* Match the current string? */
|
||
++CheatIndex; /* Next char */
|
||
if (!CheatPtr[Cheat][CheatIndex]) { /* End of the string? */
|
||
PlaySound(SND_BONUS); /* I got a bonus! */
|
||
switch (Cheat) { /* Execute the cheat */
|
||
case 1:
|
||
gamestate.godmode^=TRUE; /* I am invincible! */
|
||
break;
|
||
case 5:
|
||
GiveKey(0);
|
||
GiveKey(1); /* Award the keys */
|
||
break;
|
||
case 6:
|
||
playstate=EX_WARPED; /* Force a jump to the next level */
|
||
nextmap = gamestate.mapon+1; /* Next level */
|
||
if (MapListPtr->MaxMap<=nextmap) { /* Too high? */
|
||
nextmap = 0; /* Reset to zero */
|
||
}
|
||
break;
|
||
case 7:
|
||
ShowPush ^= TRUE;
|
||
break;
|
||
case 0:
|
||
case 4:
|
||
GiveKey(0); /* Award the keys */
|
||
GiveKey(1);
|
||
gamestate.godmode = TRUE; /* I am a god */
|
||
case 2:
|
||
gamestate.machinegun = TRUE;
|
||
gamestate.chaingun = TRUE;
|
||
gamestate.flamethrower = TRUE;
|
||
gamestate.missile = TRUE;
|
||
GiveAmmo(gamestate.maxammo);
|
||
GiveGas(99);
|
||
GiveMissile(99);
|
||
break;
|
||
case 3:
|
||
gamestate.maxammo = 999;
|
||
GiveAmmo(999);
|
||
}
|
||
}
|
||
} else {
|
||
CheatIndex = 0;
|
||
goto TryFirst;
|
||
}
|
||
} else {
|
||
TryFirst:
|
||
Index = 0; /* Init the scan routine */
|
||
do {
|
||
if (CheatPtr[Index][0] == i) {
|
||
Cheat = Index; /* This is my current cheat I am scanning */
|
||
CheatIndex = 1; /* Index to the second char */
|
||
break; /* Exit */
|
||
}
|
||
} while (++Index<8); /* All words scanned? */
|
||
}
|
||
switch (ScanCode) { /* Use the SCAN code to make sure I hit the right key! */
|
||
case 0x12 : /* 1 */
|
||
gamestate.pendingweapon = WP_KNIFE;
|
||
break;
|
||
case 0x13 : /* 2 */
|
||
if (gamestate.ammo) {
|
||
gamestate.pendingweapon = WP_PISTOL;
|
||
}
|
||
break;
|
||
case 0x14 : /* 3 */
|
||
if (gamestate.ammo && gamestate.machinegun) {
|
||
gamestate.pendingweapon = WP_MACHINEGUN;
|
||
}
|
||
break;
|
||
case 0x15 : /* 4 */
|
||
if (gamestate.ammo && gamestate.chaingun) {
|
||
gamestate.pendingweapon = WP_CHAINGUN;
|
||
}
|
||
break;
|
||
case 0x17 : /* 5 */
|
||
if (gamestate.gas && gamestate.flamethrower) {
|
||
gamestate.pendingweapon = WP_FLAMETHROWER;
|
||
}
|
||
break;
|
||
case 0x16 : /* 6 */
|
||
if (gamestate.missiles && gamestate.missile) {
|
||
gamestate.pendingweapon = WP_MISSILE;
|
||
}
|
||
break;
|
||
case 0x41: /* Keypad Period */
|
||
case 0x2C: /* Slash */
|
||
joystick1 = JOYPAD_START;
|
||
}
|
||
}
|
||
|
||
GetKeys(Keys.Macy); /* Get the keyboard from the mac */
|
||
|
||
i = 0; /* Init the count */
|
||
MacPtr = KeyMatrix;
|
||
do {
|
||
Index = MacPtr->Index; /* Get the byte index */
|
||
if (Keys.Keys[Index] & MacPtr->BitField) {
|
||
joystick1 |= MacPtr->JoyValue; /* Set the joystick value */
|
||
}
|
||
MacPtr++; /* Next index */
|
||
} while (++i<33); /* All done? */
|
||
|
||
if (MouseEnabled) { /* Mouse control turned on? */
|
||
if (Button()) { /* Get the mouse button */
|
||
joystick1 |= JOYPAD_B; /* Mouse button */
|
||
}
|
||
GetMouse(&MyPoint); /* Get the mouse location */
|
||
LocalToGlobal(&MyPoint); /* Convert mouse to global coordinate system */
|
||
if (joystick1&JOYPAD_TR) { /* Strafing? */
|
||
mousex += (MyPoint.h-MouseBaseX); /* Move horizontally for strafe */
|
||
} else {
|
||
mouseturn += (MouseBaseX-MyPoint.h); /* Turn left or right */
|
||
}
|
||
mousey += (MyPoint.v-MouseBaseY); /* Forward motion */
|
||
(*(unsigned short *) 0x082C) = MouseBaseY; /* Set RawMouse */
|
||
(*(unsigned short *) 0x082E) = MouseBaseX;
|
||
(*(unsigned short *) 0x0828) = MouseBaseY; /* MTemp */
|
||
(*(unsigned short *) 0x082A) = MouseBaseX;
|
||
(*(Byte *) 0x08CE) = 255; /* CrsrNew */
|
||
(*(Byte *) 0x08CF) = 255; /* CrsrCouple */
|
||
}
|
||
|
||
if (joystick1 & JOYPAD_TR) { /* Handle the side scroll (Special case) */
|
||
if (joystick1&JOYPAD_LFT) {
|
||
joystick1 = (joystick1 & ~(JOYPAD_TR|JOYPAD_LFT)) | JOYPAD_TL;
|
||
} else if (joystick1&JOYPAD_RGT) {
|
||
joystick1 = joystick1 & ~JOYPAD_RGT;
|
||
} else {
|
||
joystick1 &= ~JOYPAD_TR;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Handle GET PSYCHED!
|
||
|
||
**********************************/
|
||
|
||
static Rect PsychedRect;
|
||
static Word LeftMargin;
|
||
#define PSYCHEDWIDE 184
|
||
#define PSYCHEDHIGH 5
|
||
#define PSYCHEDX 20
|
||
#define PSYCHEDY 46
|
||
#define MAXINDEX (66+S_LASTONE)
|
||
|
||
/**********************************
|
||
|
||
Draw the initial shape
|
||
|
||
**********************************/
|
||
|
||
void ShowGetPsyched(void)
|
||
{
|
||
LongWord *PackPtr;
|
||
Byte *ShapePtr;
|
||
LongWord PackLength;
|
||
Word X,Y;
|
||
|
||
SetPort((WindowPtr)GameWindow);
|
||
ClearTheScreen(BLACK);
|
||
BlastScreen();
|
||
PackPtr = LoadAResource(rGetPsychPic);
|
||
PackLength = PackPtr[0];
|
||
ShapePtr = AllocSomeMem(PackLength);
|
||
DLZSS(ShapePtr,(Byte *) &PackPtr[1],PackLength);
|
||
X = (MacWidth-224)/2;
|
||
Y = (MacViewHeight-56)/2;
|
||
DrawShape(X,Y,ShapePtr);
|
||
FreeSomeMem(ShapePtr);
|
||
ReleaseAResource(rGetPsychPic);
|
||
BlastScreen();
|
||
SetAPalette(rGamePal);
|
||
SetPort((WindowPtr)GameWindow);
|
||
ForeColor(redColor);
|
||
PsychedRect.top = Y + PSYCHEDY + QDGameRect.top;
|
||
PsychedRect.bottom = PsychedRect.top + PSYCHEDHIGH;
|
||
PsychedRect.left = X + PSYCHEDX + QDGameRect.left;
|
||
PsychedRect.right = PsychedRect.left;
|
||
LeftMargin = PsychedRect.left;
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Update the thermomitor
|
||
|
||
**********************************/
|
||
|
||
void DrawPsyched(Word Index)
|
||
{
|
||
Word Factor;
|
||
|
||
Factor = Index * PSYCHEDWIDE; /* Calc the relative X pixel factor */
|
||
Factor = Factor / MAXINDEX;
|
||
PsychedRect.left = PsychedRect.right; /* Adjust the left pixel */
|
||
PsychedRect.right = Factor+LeftMargin;
|
||
PaintRect(&PsychedRect); /* Draw the pixel in the bar */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Erase the Get Psyched screen
|
||
|
||
**********************************/
|
||
|
||
void EndGetPsyched(void)
|
||
{
|
||
ForeColor(blackColor); /* Reset the color to black for high speed */
|
||
SetAPalette(rBlackPal); /* Zap the palette */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Choose the game difficulty
|
||
|
||
**********************************/
|
||
|
||
static void DrawNewRect(DialogPtr theDialog,Word Item,Word Color)
|
||
{
|
||
short iType;
|
||
Handle iHndl;
|
||
Rect iRect;
|
||
|
||
ForeColor(Color);
|
||
GetDialogItem(theDialog,Item, &iType, &iHndl, &iRect);
|
||
InsetRect(&iRect,-4,-4);
|
||
PenSize(3,3); /* Nice thick line */
|
||
FrameRect(&iRect);
|
||
PenNormal();
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Choose the game difficulty
|
||
|
||
**********************************/
|
||
|
||
static Word OldVal; /* Make semi-global so the filter can use it as input */
|
||
|
||
Word ChooseGameDiff(void)
|
||
{
|
||
ModalFilterUPP theDialogFilter;
|
||
DialogPtr MyDialog;
|
||
short itemHit;
|
||
Word donewithdialog;
|
||
Word RetVal;
|
||
Word OldTick;
|
||
unsigned short DblClick;
|
||
Byte OldPal[768];
|
||
|
||
memcpy(OldPal,CurrentPal,768);
|
||
SetPort((WindowPtr)GameWindow);
|
||
FillRect(&BlackRect,&qd.black);
|
||
SetAPalette(rGamePal);
|
||
MyDialog = GetNewDialog(NewGameWin,0L,(WindowPtr)-1); /* Open the dialog window */
|
||
OldVal = difficulty+1; /* Save the current difficulty */
|
||
PlaySound(SND_MENU);
|
||
CenterAWindow(MyDialog);
|
||
ShowWindow(MyDialog); /* Display with OK button framed */
|
||
InitCursor();
|
||
SetPort((WindowPtr) MyDialog);
|
||
DrawNewRect(MyDialog,OldVal,blackColor);
|
||
DblClick = 0;
|
||
donewithdialog = FALSE;
|
||
RetVal = TRUE; /* Assume ok */
|
||
|
||
theDialogFilter = NewModalFilterProc(StandardModalFilterProc);
|
||
|
||
do {
|
||
ModalDialog(theDialogFilter, &itemHit);
|
||
switch (itemHit) {
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
case 4: /* The checkbox */
|
||
if (OldVal!=itemHit) {
|
||
DrawNewRect(MyDialog,OldVal,whiteColor); /* Erase the old rect */
|
||
DrawNewRect(MyDialog,itemHit,blackColor);
|
||
OldVal = itemHit;
|
||
}
|
||
PlaySound(SND_GUNSHT); /* Gun shot */
|
||
if (DblClick==itemHit) { /* Hit the same item? */
|
||
if (((Word)ReadTick()-OldTick)<(Word)15) { /* Double click time? */
|
||
donewithdialog = TRUE;
|
||
difficulty = OldVal-1;
|
||
break; /* Ok! */
|
||
}
|
||
}
|
||
OldTick=ReadTick(); /* Save the tick mark */
|
||
DblClick=itemHit; /* Save the last item hit */
|
||
break;
|
||
case 5:
|
||
RetVal = FALSE;
|
||
donewithdialog = TRUE;
|
||
PlaySound(SND_OK);
|
||
break;
|
||
case 6: /* OK Button */
|
||
donewithdialog = TRUE;
|
||
difficulty = OldVal-1;
|
||
PlaySound(SND_OK);
|
||
break;
|
||
}
|
||
} while (!donewithdialog);
|
||
DisposeRoutineDescriptor(theDialogFilter);
|
||
DisposeDialog(MyDialog);
|
||
SetAPalettePtr(OldPal); /* Restore the palette */
|
||
SetPort((WindowPtr) GameWindow);
|
||
DrawWindow((WindowPtr)GameWindow); /* Draw it NOW! */
|
||
FixTheCursor();
|
||
return RetVal;
|
||
}
|
||
|
||
static Byte BoxUp[] = {3,4,1,2}; /* Up/Down */
|
||
static Byte BoxLeft[] = {2,1,4,3}; /* Left/Right */
|
||
static Byte TabLeft[] = {2,3,4,1}; /* Tab */
|
||
|
||
pascal Boolean StandardModalFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
|
||
{
|
||
char theChar;
|
||
Handle theHandle;
|
||
short theType;
|
||
Rect theRect;
|
||
|
||
switch (theEvent->what) {
|
||
case keyDown:
|
||
theChar = toupper(theEvent->message & charCodeMask);
|
||
switch (theChar) {
|
||
|
||
case '8': /* Up */
|
||
case 0x1E: /* Up */
|
||
case '5': /* Down */
|
||
case '2': /* Down */
|
||
case 0x1F: /* Down */
|
||
case 'W':
|
||
case 'S':
|
||
case 'I':
|
||
case 'K':
|
||
*itemHit = BoxUp[OldVal-1];
|
||
return TRUE;
|
||
|
||
case '4': /* Left */
|
||
case '6': /* Right */
|
||
case 0x1C: /* Left */
|
||
case 0x1D: /* Right */
|
||
case 'A':
|
||
case 'D':
|
||
case 'J':
|
||
case 'L':
|
||
*itemHit = BoxLeft[OldVal-1];
|
||
return TRUE;
|
||
|
||
case 9:
|
||
*itemHit = TabLeft[OldVal-1];
|
||
return TRUE;
|
||
|
||
case 0x0D: /* Return */
|
||
case 0x03: /* Enter */
|
||
*itemHit = 6;
|
||
return (TRUE);
|
||
|
||
case 'Q': /* Cmd-Q */
|
||
case '.': /* Cmd-Period */
|
||
if (theEvent->modifiers & cmdKey) {
|
||
case 0x1b: /* Esc */
|
||
*itemHit = 5;
|
||
return (TRUE);
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
case updateEvt:
|
||
GetDialogItem(theDialog, 6, &theType, &theHandle, &theRect);
|
||
InsetRect(&theRect, -4, -4);
|
||
PenSize(3, 3);
|
||
FrameRoundRect(&theRect, 16, 16);
|
||
}
|
||
return (FALSE); //<2F> Tells dialog manager to handle the event
|
||
}
|
||
|
||
|
||
/**********************************
|
||
|
||
Load the prefs file into memory and use defaults
|
||
for ANY errors that could occur
|
||
|
||
**********************************/
|
||
|
||
typedef struct { /* Save game data field */
|
||
unsigned short State; /* Game state flags */
|
||
unsigned short Mouse; /* Mouse control */
|
||
unsigned short QuickDraw; /* Quickdraw for updates */
|
||
unsigned short Goveror; /* Speed governor */
|
||
unsigned short ViewSize; /* Game screen size */
|
||
unsigned short Difficulty; /* Game difficulty */
|
||
unsigned short Ignore; /* Ignore message flag */
|
||
} Prefs_t;
|
||
|
||
void LoadPrefs(void)
|
||
{
|
||
Prefs_t Prefs;
|
||
|
||
Prefs.State = 3; /* Assume sound & music enabled */
|
||
Prefs.Mouse = FALSE; /* Mouse control shut off */
|
||
Prefs.QuickDraw = TRUE; /* Use quickdraw for screen updates */
|
||
Prefs.Goveror = TRUE; /* Enable speed governor */
|
||
Prefs.ViewSize = 0; /* 320 mode screen */
|
||
Prefs.Difficulty = 2; /* Medium difficulty */
|
||
Prefs.Ignore = FALSE; /* Enable message */
|
||
|
||
InitPrefsFile('WOLF',(Byte *)"Wolfenstein 3D Prefs"); /* Create the prefs file (If it doesn't exist) */
|
||
LoadPrefsFile((Byte *)&Prefs,sizeof(Prefs)); /* Load in the prefs (Assume it may NOT!) */
|
||
SystemState = Prefs.State; /* Store the defaults from either the presets or the file */
|
||
MouseEnabled = Prefs.Mouse;
|
||
DoQuickDraw = Prefs.QuickDraw;
|
||
SlowDown = Prefs.Goveror;
|
||
GameViewSize = Prefs.ViewSize;
|
||
difficulty = Prefs.Difficulty;
|
||
IgnoreMessage = Prefs.Ignore;
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Save the prefs file to disk but ignore any errors
|
||
|
||
**********************************/
|
||
|
||
void SavePrefs(void)
|
||
{
|
||
Prefs_t Prefs; /* Structure to save to disk */
|
||
Prefs.State = SystemState; /* Init the prefs structure */
|
||
Prefs.Mouse = MouseEnabled;
|
||
Prefs.QuickDraw = DoQuickDraw;
|
||
Prefs.Goveror = SlowDown;
|
||
Prefs.ViewSize = GameViewSize;
|
||
Prefs.Difficulty = difficulty;
|
||
Prefs.Ignore = IgnoreMessage;
|
||
SavePrefsFile((Byte *)&Prefs,sizeof(Prefs)); /* Save the prefs file */
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Save the game
|
||
|
||
**********************************/
|
||
|
||
#ifdef __powerc
|
||
Byte MachType[4] = "PPC3";
|
||
#else
|
||
Byte MachType[4] = "68K3";
|
||
#endif
|
||
|
||
void SaveGame(void)
|
||
{
|
||
short FileRef;
|
||
long Count;
|
||
Word PWallWord;
|
||
|
||
HCreate(SaveFileVol,SaveFileParID,SaveFileName,'WOLF','SAVE'); /* Create the save game file */
|
||
if (HOpen(SaveFileVol,SaveFileParID,SaveFileName,fsWrPerm,&FileRef)) { /* Can I open it? */
|
||
return; /* Abort! */
|
||
}
|
||
|
||
Count = 4; /* Default length */
|
||
FSWrite(FileRef,&Count,&MachType); /* Save a machine type ID */
|
||
Count = sizeof(unsigned short);
|
||
FSWrite(FileRef,&Count,&MapListPtr->MaxMap); /* Number of maps (ID) */
|
||
Count = sizeof(gamestate);
|
||
FSWrite(FileRef,&Count,&gamestate); /* Save the game stats */
|
||
Count = sizeof(PushWallRec);
|
||
FSWrite(FileRef,&Count,&PushWallRec); /* Save the pushwall stats */
|
||
|
||
Count = sizeof(nummissiles);
|
||
FSWrite(FileRef,&Count,&nummissiles); /* Save missiles in motion */
|
||
if (nummissiles) {
|
||
Count = nummissiles*sizeof(missile_t);
|
||
FSWrite(FileRef,&Count,&missiles[0]);
|
||
}
|
||
Count = sizeof(numactors);
|
||
FSWrite(FileRef,&Count,&numactors); /* Save actors */
|
||
if (numactors) {
|
||
Count = numactors*sizeof(actor_t);
|
||
FSWrite(FileRef,&Count,&actors[0]);
|
||
}
|
||
Count = sizeof(numdoors);
|
||
FSWrite(FileRef,&Count,&numdoors); /* Save doors */
|
||
if (numdoors) {
|
||
Count = numdoors*sizeof(door_t);
|
||
FSWrite(FileRef,&Count,&doors[0]);
|
||
}
|
||
Count = sizeof(numstatics);
|
||
FSWrite(FileRef,&Count,&numstatics);
|
||
if (numstatics) {
|
||
Count = numstatics*sizeof(static_t);
|
||
FSWrite(FileRef,&Count,&statics[0]);
|
||
}
|
||
Count = 64*64;
|
||
FSWrite(FileRef,&Count,MapPtr);
|
||
Count = sizeof(tilemap); /* Tile map */
|
||
FSWrite(FileRef,&Count,&tilemap);
|
||
|
||
Count = sizeof(ConnectCount);
|
||
FSWrite(FileRef,&Count,&ConnectCount);
|
||
if (ConnectCount) {
|
||
Count = ConnectCount * sizeof(connect_t);
|
||
FSWrite(FileRef,&Count,&areaconnect[0]);
|
||
}
|
||
Count = sizeof(areabyplayer);
|
||
FSWrite(FileRef,&Count,&areabyplayer[0]);
|
||
Count = (128+5)*64;
|
||
FSWrite(FileRef,&Count,&textures[0]);
|
||
Count = sizeof(Word);
|
||
PWallWord = 0; /* Assume no pushwall pointer in progress */
|
||
if (pwallseg) {
|
||
PWallWord = (pwallseg-(saveseg_t*)nodes)+1; /* Convert to number offset */
|
||
}
|
||
FSWrite(FileRef,&Count,&PWallWord);
|
||
Count = MapPtr->numnodes*sizeof(savenode_t); /* How large is the BSP tree? */
|
||
FSWrite(FileRef,&Count,nodes); /* Save it to disk */
|
||
FSClose(FileRef); /* Close the file */
|
||
PlaySound(SND_BONUS);
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Load the game
|
||
|
||
**********************************/
|
||
|
||
void *SaveRecord;
|
||
void *SaveRecordMem;
|
||
|
||
Boolean LoadGame(void)
|
||
{
|
||
LongWord FileSize;
|
||
union {
|
||
Byte *B;
|
||
unsigned short *S;
|
||
Word *W;
|
||
LongWord *L;
|
||
} FilePtr;
|
||
void *TheMem;
|
||
short FileRef;
|
||
|
||
if (HOpen(SaveFileVol, SaveFileParID, SaveFileName, fsRdPerm, &FileRef)) {
|
||
return FALSE;
|
||
}
|
||
GetEOF(FileRef,(long*)&FileSize); /* Get the size of the file */
|
||
FilePtr.B = TheMem = AllocSomeMem(FileSize); /* Get memory for the file */
|
||
if (!FilePtr.B) { /* No memory! */
|
||
return FALSE;
|
||
}
|
||
FSRead(FileRef,(long*)&FileSize,(Ptr)FilePtr.B); /* Open the file */
|
||
FSClose(FileRef); /* Close the file */
|
||
if (memcmp(MachType,FilePtr.B,4)) { /* Is this the proper machine type? */
|
||
goto Bogus;
|
||
}
|
||
FilePtr.B+=4; /* Index past signature */
|
||
if (MapListPtr->MaxMap!=*FilePtr.S) { /* Map count the same? */
|
||
goto Bogus; /* Must be differant game */
|
||
}
|
||
++FilePtr.S; /* Index past count */
|
||
memcpy(&gamestate,FilePtr.B,sizeof(gamestate)); /* Reset the game state */
|
||
SaveRecord = FilePtr.B;
|
||
SaveRecordMem = TheMem;
|
||
return TRUE;
|
||
|
||
Bogus:
|
||
FreeSomeMem(TheMem);
|
||
return FALSE;
|
||
}
|
||
|
||
void FinishLoadGame(void)
|
||
{
|
||
union {
|
||
Byte *B;
|
||
unsigned short *S;
|
||
Word *W;
|
||
LongWord *L;
|
||
} FilePtr;
|
||
|
||
FilePtr.B = SaveRecord;
|
||
|
||
memcpy(&gamestate,FilePtr.B,sizeof(gamestate)); /* Reset the game state */
|
||
FilePtr.B+=sizeof(gamestate);
|
||
|
||
memcpy(&PushWallRec,FilePtr.B,sizeof(PushWallRec)); /* Record for the single pushwall in progress */
|
||
FilePtr.B+=sizeof(PushWallRec);
|
||
|
||
nummissiles = *FilePtr.W;
|
||
++FilePtr.W;
|
||
if (nummissiles) {
|
||
memcpy(&missiles[0],FilePtr.B,sizeof(missile_t)*nummissiles);
|
||
FilePtr.B += sizeof(missile_t)*nummissiles;
|
||
}
|
||
|
||
numactors = *FilePtr.W;
|
||
++FilePtr.W;
|
||
if (numactors) {
|
||
memcpy(&actors[0],FilePtr.B,sizeof(actor_t)*numactors);
|
||
FilePtr.B += sizeof(actor_t)*numactors;
|
||
}
|
||
|
||
numdoors = *FilePtr.W;
|
||
++FilePtr.W;
|
||
if (numdoors) {
|
||
memcpy(&doors[0],FilePtr.B,sizeof(door_t)*numdoors);
|
||
FilePtr.B += sizeof(door_t)*numdoors;
|
||
}
|
||
|
||
numstatics = *FilePtr.W;
|
||
++FilePtr.W;
|
||
if (numstatics) {
|
||
memcpy(&statics[0],FilePtr.B,sizeof(static_t)*numstatics);
|
||
FilePtr.B += sizeof(static_t)*numstatics;
|
||
}
|
||
memcpy(MapPtr,FilePtr.B,64*64);
|
||
FilePtr.B += 64*64;
|
||
memcpy(&tilemap,FilePtr.B,sizeof(tilemap)); /* Tile map */
|
||
FilePtr.B += sizeof(tilemap); /* Index past data */
|
||
|
||
ConnectCount = *FilePtr.W; /* Number of valid interconnects */
|
||
FilePtr.W++;
|
||
if (ConnectCount) {
|
||
memcpy(areaconnect,FilePtr.B,sizeof(connect_t)*ConnectCount); /* Is this area mated with another? */
|
||
FilePtr.B+= sizeof(connect_t)*ConnectCount;
|
||
}
|
||
memcpy(areabyplayer,FilePtr.B,sizeof(areabyplayer));
|
||
FilePtr.B+=sizeof(areabyplayer); /* Which areas can I see into? */
|
||
|
||
memcpy(&textures[0],FilePtr.B,(128+5)*64);
|
||
FilePtr.B+=((128+5)*64); /* Texture array for pushwalls */
|
||
|
||
pwallseg = 0; /* Assume bogus */
|
||
if (*FilePtr.W) {
|
||
pwallseg = (saveseg_t *)nodes;
|
||
pwallseg = &pwallseg[*FilePtr.W-1];
|
||
}
|
||
++FilePtr.W;
|
||
memcpy(nodes,FilePtr.B,MapPtr->numnodes*sizeof(savenode_t));
|
||
/* FilePtr.B+=(MapPtr->numnodes*sizeof(savenode_t)); /* Next entry */
|
||
|
||
FreeSomeMem(SaveRecordMem);
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Process an alert and center it on my game monitor
|
||
Note : I am cheating like a son of a bitch by modifing the
|
||
resources directly!
|
||
|
||
**********************************/
|
||
|
||
static Word DoMyAlert(Word AlertNum)
|
||
{
|
||
Word Val;
|
||
Rect **AlertRect; /* Handle to the alert rect */
|
||
Rect MyRect;
|
||
|
||
InitCursor(); /* Fix the cursor */
|
||
AlertRect = (Rect **)GetResource('ALRT',AlertNum); /* Load in the template */
|
||
MyRect = **AlertRect; /* Copy the rect */
|
||
MyRect.right -= MyRect.left; /* Get the width */
|
||
MyRect.bottom -= MyRect.top; /* Get the height */
|
||
CenterSFWindow((Point *)&MyRect,MyRect.right,MyRect.bottom); /* Center the window */
|
||
MyRect.right += MyRect.left; /* Fix the rect */
|
||
MyRect.bottom += MyRect.top;
|
||
**AlertRect = MyRect;
|
||
ChangedResource((Handle)AlertRect);
|
||
Val = Alert(AlertNum,nil);
|
||
if (!InPause) { /* If paused then don't fix the cursor */
|
||
FixTheCursor();
|
||
}
|
||
return Val;
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Beg for $$$ at the end of the shareware version
|
||
|
||
**********************************/
|
||
|
||
void ShareWareEnd(void)
|
||
{
|
||
SetAPalette(rGamePal);
|
||
DoMyAlert(EndGameWin);
|
||
SetAPalette(rBlackPal);
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Show the standard file dialog
|
||
for opening a new game
|
||
|
||
**********************************/
|
||
|
||
SFTypeList MyList = {'SAVE'};
|
||
SFReply Reply;
|
||
|
||
static void CenterSFWindow(Point *MyPoint,Word Width,Word Height)
|
||
{
|
||
GDHandle MainDevice;
|
||
Rect TheRect;
|
||
Word H,W; /* Device width of main device */
|
||
|
||
if (gMainGDH) { /* Has the video device been selected? */
|
||
MyPoint->v = ((MonitorHeight-Height)/3)+BlackRect2.top; /* Center the window then */
|
||
MyPoint->h = ((MonitorWidth-Width)/2)+BlackRect2.left;
|
||
return;
|
||
}
|
||
MainDevice = GetMainDevice(); /* Get the default device */
|
||
TheRect = (**MainDevice).gdRect; /* Get the rect of the device */
|
||
H = TheRect.bottom - TheRect.top; /* Get the size of the video screen */
|
||
W = TheRect.right - TheRect.left;
|
||
MyPoint->v = ((H-Height)/3)+TheRect.top; /* Center the window */
|
||
MyPoint->h = ((W-Width)/2)+TheRect.left;
|
||
}
|
||
|
||
static void CenterAWindow(WindowPtr MyWindow)
|
||
{
|
||
Rect MyRect;
|
||
Point MyPoint;
|
||
|
||
MyRect = ((WindowPeek)MyWindow)->port.portRect;
|
||
CenterSFWindow(&MyPoint,MyRect.right-MyRect.left,MyRect.bottom-MyRect.top);
|
||
MoveWindow(MyWindow,MyPoint.h,MyPoint.v,FALSE);
|
||
}
|
||
|
||
|
||
Boolean ChooseLoadGame(void)
|
||
{
|
||
long ProcID;
|
||
Point MyPoint;
|
||
|
||
InitCursor();
|
||
CenterSFWindow(&MyPoint,348,136);
|
||
SFGetFile(MyPoint,0,0,1,MyList,0,&Reply);
|
||
FixTheCursor();
|
||
if (!Reply.good) { /* Pressed cancel? */
|
||
return FALSE;
|
||
}
|
||
SaveFileName = (Byte *)&Reply.fName;
|
||
SaveFileVol = Reply.vRefNum;
|
||
GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&ProcID);
|
||
return TRUE;
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Show the standard file dialog
|
||
for saving a new game
|
||
|
||
**********************************/
|
||
|
||
Boolean ChooseSaveGame(void)
|
||
{
|
||
Byte *SaveTemp;
|
||
Point MyPoint;
|
||
long ProcID;
|
||
|
||
InitCursor();
|
||
SaveTemp = SaveFileName;
|
||
if (!SaveTemp) {
|
||
SaveTemp = "\pUntitled";
|
||
}
|
||
CenterSFWindow(&MyPoint,304,104);
|
||
SFPutFile(MyPoint,"\pSave your game as:",SaveTemp,0,&Reply);
|
||
FixTheCursor();
|
||
if (!Reply.good) {
|
||
return FALSE;
|
||
}
|
||
SaveFileName = (Byte *)&Reply.fName;
|
||
SaveFileVol = Reply.vRefNum;
|
||
GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&ProcID);
|
||
return TRUE;
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Process Apple Events
|
||
|
||
**********************************/
|
||
#if 1
|
||
struct AEinstalls {
|
||
AEEventClass theClass;
|
||
AEEventID theEvent;
|
||
void *Code;
|
||
AEEventHandlerUPP theProc;
|
||
};
|
||
typedef struct AEinstalls AEinstalls;
|
||
|
||
|
||
static OSErr GotRequiredParams(AppleEvent *theAppleEvent)
|
||
{
|
||
DescType returnedType;
|
||
Size actualSize;
|
||
OSErr theErr;
|
||
|
||
theErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr,
|
||
typeWildCard, &returnedType, nil, 0, &actualSize);
|
||
if (theErr == errAEDescNotFound)
|
||
return noErr;
|
||
if (!theErr)
|
||
return errAEParamMissed;
|
||
return theErr;
|
||
}
|
||
|
||
/* This is the standard Open Application event. */
|
||
static pascal OSErr AEOpenHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refIn)
|
||
{
|
||
OSErr theErr;
|
||
|
||
// This event occurs when the application is opened. In most cases
|
||
// nothing needs to be done, but we must make sure that we received
|
||
// no parameters, since none are supposed to be received.
|
||
|
||
theErr = GotRequiredParams(theAppleEvent);
|
||
if (theErr)
|
||
return theErr;
|
||
|
||
// do whatever is needed (e.g., open new untitled document)
|
||
|
||
return noErr;
|
||
}
|
||
|
||
/* Open Doc, opens our documents. Remember, this can happen at application start AND */
|
||
/* anytime else. If your app is up and running and the user goes to the desktop, hilites one */
|
||
/* of your files, and double-clicks or selects Open from the finder File menu this event */
|
||
/* handler will get called. Which means you don't do any initialization of globals here, or */
|
||
/* anything else except open then doc. */
|
||
/* SO-- Do NOT assume that you are at app start time in this */
|
||
/* routine, or bad things will surely happen to you. */
|
||
|
||
static pascal OSErr AEOpenDocHandler(AppleEvent *theAppleEvent, AppleEvent reply, long refCon)
|
||
{
|
||
AEDescList docList;
|
||
OSErr theErr;
|
||
long index, itemsInList;
|
||
Size actualSize;
|
||
AEKeyword keywd;
|
||
DescType returnedType;
|
||
FSSpec theFSS;
|
||
|
||
// In response to this event, we must open all documents specified in
|
||
// the Apple Event.
|
||
|
||
AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
|
||
|
||
// check for missing required parameters
|
||
theErr = GotRequiredParams(theAppleEvent);
|
||
if (theErr != noErr)
|
||
return AEDisposeDesc(&docList);
|
||
|
||
// count the number of descriptor records in the list
|
||
theErr = AECountItems(&docList, &itemsInList);
|
||
|
||
// get each descriptor record from the list, coerce the returned
|
||
// data to an FSSpec record, and open the associated file
|
||
index = 1;
|
||
if (index <= itemsInList) {
|
||
AEGetNthPtr(&docList, index, typeFSS, &keywd, &returnedType,
|
||
(Ptr)&theFSS, sizeof(theFSS), &actualSize);
|
||
// open FSSpec
|
||
OpenPending = TRUE;
|
||
SaveFileVol = theFSS.vRefNum;
|
||
SaveFileParID = theFSS.parID;
|
||
SaveFileName = (Byte *)&Reply.fName;
|
||
memcpy(&Reply.fName,&theFSS.name,*theFSS.name+1);
|
||
}
|
||
|
||
AEDisposeDesc(&docList);
|
||
|
||
return noErr;
|
||
}
|
||
|
||
|
||
static pascal OSErr AEPrintHandler(AppleEvent *theAppleEvent, AppleEvent reply, long refCon)
|
||
{
|
||
AEDescList docList;
|
||
OSErr theErr;
|
||
long index, itemsInList;
|
||
Size actualSize;
|
||
AEKeyword keywd;
|
||
DescType returnedType;
|
||
FSSpec theFSS;
|
||
|
||
// In response to this event, we must print all documents specified in
|
||
// the Apple Event.
|
||
|
||
theErr = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
|
||
|
||
// check for missing required parameters
|
||
theErr = GotRequiredParams(theAppleEvent);
|
||
if (theErr != noErr)
|
||
return AEDisposeDesc(&docList);
|
||
|
||
// count the number of descriptor records in the list
|
||
theErr = AECountItems(&docList, &itemsInList);
|
||
|
||
// get each descriptor record from the list, coerce the returned
|
||
// data to an FSSpec record, and open the associated file
|
||
for (index = 1; index <= itemsInList; index++)
|
||
{
|
||
theErr = AEGetNthPtr(&docList, index, typeFSS, &keywd, &returnedType,
|
||
(Ptr)&theFSS, sizeof(theFSS), &actualSize);
|
||
// print FSSpec <no printing in this application>
|
||
}
|
||
|
||
AEDisposeDesc(&docList);
|
||
|
||
return noErr;
|
||
}
|
||
|
||
/* Standard Quit event handler, to handle a Quit event from the Finder, for example.
|
||
Note that we may not exit from the AppleEvent handler! We have to set a flag,
|
||
and exit from within the normal application code. */
|
||
|
||
static pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
|
||
{
|
||
QuitFlag = 1; /* I quit! */
|
||
return noErr;
|
||
}
|
||
|
||
/* InitAEStuff installs my appleevent handlers */
|
||
void InitAEStuff(void);
|
||
|
||
static AEinstalls HandlersToInstall[] = {
|
||
{kCoreEventClass, kAEOpenApplication,AEOpenHandler,0},
|
||
{kCoreEventClass, kAEOpenDocuments, AEOpenDocHandler,0},
|
||
{kCoreEventClass, kAEQuitApplication, AEQuitHandler,0},
|
||
{kCoreEventClass, kAEPrintDocuments, AEPrintHandler,0}
|
||
};
|
||
|
||
void InitAEStuff(void)
|
||
{
|
||
|
||
Word i;
|
||
|
||
/* Check this machine for AppleEvents. If they are not here (ie not 7.0)
|
||
* then we return. */
|
||
|
||
#ifndef __powerc
|
||
long aLong;
|
||
short Code,Count;
|
||
short Index;
|
||
AppFile Stuff;
|
||
|
||
/* This is for the WONDERFUL system 6.0.7 filenames */
|
||
/* Only execute on 680x0 macs */
|
||
|
||
CountAppFiles(&Code,&Count);
|
||
for (Index=1;Index<=Count;++Count) {
|
||
GetAppFiles(Index,&Stuff);
|
||
if (Index==1) {
|
||
OpenPending = TRUE;
|
||
SaveFileVol = Stuff.vRefNum;
|
||
SaveFileName = (Byte *)&Reply.fName;
|
||
memcpy(&Reply.fName,&Stuff.fName,*Stuff.fName+1);
|
||
GetWDInfo(SaveFileVol,&SaveFileVol,&SaveFileParID,&aLong);
|
||
}
|
||
ClrAppFiles(Index);
|
||
}
|
||
if (Gestalt(gestaltAppleEventsAttr, &aLong)) { /* Are Apple events present? */
|
||
return;
|
||
}
|
||
if (!(aLong & (1<<gestaltAppleEventsPresent))) {
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
/* The following series of calls installs all our AppleEvent Handlers.
|
||
* These handlers are added to the application event handler list that
|
||
* the AppleEvent manager maintains. So, whenever an AppleEvent happens
|
||
* and we call AEProcessEvent, the AppleEvent manager will check our
|
||
* list of handlers and dispatch to it if there is one.
|
||
*/
|
||
i = 0;
|
||
do {
|
||
HandlersToInstall[i].theProc = NewAEEventHandlerProc(HandlersToInstall[i].Code);
|
||
AEInstallEventHandler(HandlersToInstall[i].theClass, HandlersToInstall[i].theEvent,
|
||
HandlersToInstall[i].theProc,0,FALSE);
|
||
} while (++i<4);
|
||
}
|
||
#endif
|
||
|
||
/**********************************
|
||
|
||
Make the cursor disappear if needed
|
||
|
||
**********************************/
|
||
|
||
static void FixTheCursor(void)
|
||
{
|
||
InitCursor();
|
||
if (MouseEnabled && !InPause) {
|
||
HideCursor();
|
||
}
|
||
}
|
||
|
||
/**********************************
|
||
|
||
Show a watch cursor
|
||
|
||
**********************************/
|
||
|
||
static void WaitCursor(void)
|
||
{
|
||
SetCursor(*WatchHandle);
|
||
}
|