Code Listing
/**********************************************
* RottenApple by Mike Scanlin. Dec 1991.
*
* An INIT that installs a tail patch on GNE so
* that when the user clicks on the apple menu
* the apple icon gets removed via one of
* three animation sequences: BombDisposal,
* PacMan or Tank.
**********************************************/
/* AppleCore is the hit rect the user must
* click in to activate the animation
* (global coordinates) */
#define AppleCoreTop 5
#define AppleCoreLeft 19
#define AppleCoreBottom (AppleCoreTop + 9)
#define AppleCoreRight (AppleCoreLeft + 10)
/* minimum seconds between shows */
#define Frequency 600
/* minimum time between frames (increase this
* number to slow the animation down) */
#define TicksBetweenFrames 3
/* used by the patch installation code */
#define GetNextEventTrap 0xA970
#define JmpInstruction 0x4EF9
#define TabKey 0x09
#define NumSavedRegs 5
/* used to detect bit depth */
#define GetMainDeviceTrap 0xAA2A
#define UnimplementedTrap 0xA89F
void main(void);
int MakeCommonBitMaps(BitMap **theApple,
BitMap **theBackground, BitMap **theOffscreen,
BitMap **theCraneOpen, BitMap **theCraneClosing,
BitMap **theCraneClosed, BitMap *theOldBits,
GrafPtr currentPort);
int MakeExplosionBitMaps(BitMap **theExp1,
BitMap **theExp2, BitMap **theExp3,
BitMap **theExp4, BitMap **theExp5,
BitMap **theExp6);
int DoBombDisposal(void);
int DoPacMan(void);
int DoTank(void);
void EndProc(void);
/**********************************************
* Install GNE patch
*
* This is run at startup time. It gets some
* space in the system heap and sets up a
* patch to GetNextEvent. The patch doesn't
* do anything until the user clicks in the
* middle of the Apple menu title icon. In
* that case they will see a little animation
* sequence. The animation won't be shown more
* than once every 'Frequency' ticks. The patch
* can be disabled at any time by typing
* cmd-shift-opt-tab.
**********************************************/
void
main(void) {
asm {
Move.L D3,-(SP)
/* get the old trap address */
Move #GetNextEventTrap,D0
_GetTrapAddress
/* set the address for the Jmp instruction
* that calls the original trap */
Lea @origTrap,A1
Move.L A0,(A1)
/* get some space in the system heap */
Lea EndProc,A0
Lea @first,A1
Suba.L A1,A0
/* D0 = length of patch */
Move.L A0,D0
/* save for _BlockMove */
Move.L D0,D3
_NewPtr SYS
Cmpi #memFullErr,D0
Beq.S @noPatch
Lea @saveLoc,A1
/* save for removePatch */
Move.L A0,(A1)
/* save for _BlockMove */
Move.L A0,-(SP)
/* set the trap address to the space we
* just got in the system heap. */
Move #GetNextEventTrap,D0
_SetTrapAddress
/* now move our patch into place */
Lea @first,A0
Move.L (SP)+,A1
Move.L D3,D0
_BlockMove
@noPatch
Move.L (SP)+,D3
/* This is the end of the installation part,
* but we can't do an Rts here because Think C
* needs to clean up. So we fall through
* to the end. */
Bra @last
/**********************************************
* GetNextEvent patch
*
* The patch calls the existing GNE and then
* checks if a mouseDown or keyDown event is
* being reported. If not, the event is passed
* to the application unmodified. If we end up
* using the event ourselves, a null event is
* returned to the application.
**********************************************/
@first
/* pop the original return address and save it */
Lea @exitAddress,A0
Move.L (SP)+,(A0)
/* save ptr to event record so we can
* get at it later */
Lea @ eventRecPtr,A0
Move.L (SP),(A0)
/* set the return address to our patch */
Pea @tailPatch
/* the nops get filled with the address of
* the original GetNextEvent */
DC JmpInstruction
@origTrap
Nop
Nop
/* this is where it comes after the normal
* GetNextEvent processing */
@tailPatch
/* change NumSavedRegs if not 5 regs below */
Movem.L A1/D0-D3,-(SP)
/* check if we've been disabled */
Lea @disabled,A0
Tst (A0)
Bne @patchExit
Lea @ eventRecPtr,A0
Move.L (A0),A0
/* check if it's a keydown event that says
* to remove ourself. This is the only keyDown
* that we intercept. */
Move OFFSET(EventRecord,what)(A0),D0
Cmpi #keyDown,D0
Bne.S @noKeyDown
/* the key to remove the patch is cmd-shift-opt-Tab */
Move.L OFFSET(EventRecord,message)(A0),D0
Cmpi.B #TabKey,D0
Bne @patchExit
Move OFFSET(EventRecord,modifiers)(A0),D0
Andi #optionKey+cmdKey+shiftKey+controlKey,D0
Eori #optionKey+cmdKey+shiftKey,D0
Beq @removePatch
@noKeyDown
/* if it's not a mousedown event, then ignore it */
Cmpi #mouseDown,D0
Bne @patchExit
/* did they click in AppleCore? */
Move.L OFFSET(EventRecord,where)(A0),D0
Cmpi #AppleCoreLeft,D0
Blt @patchExit
Cmpi #AppleCoreRight,D0
Bge @patchExit
Swap D0
Cmpi #AppleCoreTop,D0
Blt.S @patchExit
Cmpi #AppleCoreBottom,D0
Bgt.S @patchExit
Move.L Ticks,D0
/* if you hold down cmd-opt when you click in the
* AppleCore rect then you can force the animation
* to happen without the Frequency delay */
Move OFFSET(EventRecord,modifiers)(A0),D1
Andi #optionKey+cmdKey+shiftKey+controlKey,D1
Eori #optionKey+cmdKey,D1
Beq.s @skipTimeCheck
/* don't show the animation more than once every
* Frequency ticks */
Lea @nextTime,A0
Cmp.L (A0),D0
Blt.S @patchExit
@skipTimeCheck
/* pick a show at random, but don't show the one
* that was most recently shown */
Lea @lastShow,A0
Move (A0),D2
Bne.S @lastNotBomb
Btst #0,D0
Bne.S @runPacMan
Bra.S @runTank
@lastNotBomb
Subq #1,D2
Bne.S @lastNotPacMan
Btst #0,D0
Bne.S @runBombDisposal
Bra.S @runTank
@lastNotPacMan
Btst #0,D0
Bne.S @runPacMan
@runBombDisposal
Clr (A0)
Bsr DoBombDisposal
Bra.S @showFinished
@runPacMan
Move #1,(A0)
Bsr DoPacMan
Bra.S @showFinished
@runTank
Move #2,(A0)
Bsr DoTank
@showFinished
Move.L #(long)60*Frequency,D1
Add.L Ticks,D1
Lea @nextTime,A0
Move.L D1,(A0)
/* if no animation was run then don't change
* the event. */
Tst D0
Bne.S @patchExit
@returnNullEvent
/* set the event to null */
Lea @ eventRecPtr,A0
Move.L (A0),A0
Clr OFFSET(EventRecord,what)(A0)
/* change GNE's return value to false. */
Clr (4*NumSavedRegs)(SP)
@patchExit
Movem.L (SP)+,A1/D0-D3
/* JMP to the place that called GetNextEvent */
DC JmpInstruction
@exitAddress
Nop
Nop
/**********************************************
* RemovePatch
*
* Marks the GNE patch as disabled and then
* attempts to remove it. It won't remove it
* if someone else has patched GNE since we
* patched it.
**********************************************/
@removePatch
/* set the disabled flag */
Lea @disabled,A0
St (A0)
/* beep to let them know it has been disabled */
Move #1,-(SP)
_SysBeep
/* check if we are the most recent patch to GNE.
* If we're not, then don't remove. */
Move #GetNextEventTrap,D0
_GetTrapAddress
Lea @first,A1
Cmpa.L A1,A0
Bne.S @returnNullEvent
/* set the trap address back to the original trap */
Lea @origTrap,A0
Move.L (A0),A0
Move #GetNextEventTrap,D0
_SetTrapAddress
/* free up the mem occupied by this patch */
Lea @saveLoc,A0
Move.L (A0),A0
_DisposPtr
Bra.S @returnNullEvent
/* disabled is non-zero if the patch is disabled */
@disabled dc 0
/* eventRecPtr is a copy of the ptr passed to GNE */
@ eventRecPtr dc.l 0
/* lastShow: 0=Bomb Disposal, 1=PacMan, 2=Tank */
@lastShow dc 0
/* minimum value of Ticks before next show begins */
@nextTime dc.l 0
/* address of our patch in the system heap */
@saveLoc dc.l 0
@last
}
}
/**********************************************
* MakeCommonBitMaps
*
* Generates the bitMaps that are common to
* all three animation sequences.
**********************************************/
#define BgLeft 0
#define BgTop 0
#define BgRight 31
#define BgBottom 19
#define BgRowBytes (((BgRight-BgLeft+16) >> 3) & 0xFFFE)
#define BgPixelSize (BgRowBytes * (BgBottom-BgTop+1))
#define BgBitMapSize (sizeof(BitMap) + BgPixelSize)
#define AppleLeft (BgRight-15)
#define AppleRowBytes (((BgRight-AppleLeft+16) >> 3) & 0xFFFE)
#define ApplePixelSize (AppleRowBytes * (BgBottom-BgTop+1))
#define AppleBitMapSize (sizeof(BitMap) + ApplePixelSize)
#define CraneLeft 0
#define CraneTop 2
#define CraneRight 9
#define CraneBottom 18
#define CraneRowBytes (((CraneRight-CraneLeft+16) >> 3) & 0xFFFE)
#define CranePixelSize (CraneRowBytes * (CraneBottom-CraneTop+1))
#define CraneBitMapSize (sizeof(BitMap) + CranePixelSize)
#define CraneArmVLoc (((CraneBottom - CraneTop) >> 1) + CraneTop-1)
int
MakeCommonBitMaps(theApple, theBackground, theOffscreen,
theCraneOpen, theCraneClosing, theCraneClosed,
theOldBits, currentPort)
BitMap **theApple, **theBackground, **theOffscreen,
**theCraneOpen, **theCraneClosing,
**theCraneClosed, *theOldBits;
GrafPtr currentPort;
{
Ptr bitsPtr;
BitMap *p;
p = (*theApple) = (BitMap *)NewPtrSys(AppleBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = AppleRowBytes;
SetRect(&p->bounds, AppleLeft, BgTop, BgRight, BgBottom);
CopyBits(& currentPort->portBits, p,
&p->bounds, &p->bounds, srcCopy, 0L);
p = (*theBackground) = (BitMap *)NewPtrSys(BgBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = BgRowBytes;
SetRect(&p->bounds, BgLeft, BgTop, BgRight, BgBottom);
CopyBits(& currentPort->portBits, p,
&p->bounds, &p->bounds, srcCopy, 0L);
*theOldBits = currentPort->portBits;
SetPortBits(p);
EraseRect(&(*theApple)->bounds);
SetPortBits(theOldBits);
p = (*theOffscreen) = (BitMap *)NewPtrSys(BgBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = BgRowBytes;
p->bounds = (*theBackground)->bounds;
p = (*theCraneOpen) = (BitMap *)NewPtrSysClear(CraneBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = CraneRowBytes;
SetRect(&p->bounds, AppleLeft-CraneRight+6,
CraneTop, AppleLeft+6, CraneBottom);
bitsPtr = p->baseAddr;
bitsPtr[ 0] = 0x0C;
bitsPtr[ 2] = 0x1E;
bitsPtr[ 4] = 0x38;
bitsPtr[ 6] = 0x30;
bitsPtr[ 8] = 0x70;
bitsPtr[10] = 0x60;
bitsPtr[12] = 0xE0;
bitsPtr[14] = 0xC0;
bitsPtr[16] = 0xC0;
bitsPtr[18] = 0xE0;
bitsPtr[20] = 0x60;
bitsPtr[22] = 0x70;
bitsPtr[24] = 0x30;
bitsPtr[26] = 0x38;
bitsPtr[28] = 0x1E;
bitsPtr[30] = 0x0C;
p = (*theCraneClosing) = (BitMap *)NewPtrSysClear(CraneBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = CraneRowBytes;
SetRect(&p->bounds, AppleLeft-CraneRight+6,
CraneTop, AppleLeft+6, CraneBottom);
bitsPtr = p->baseAddr;
bitsPtr[ 2] = 0x06;
bitsPtr[ 4] = 0x0F;
bitsPtr[ 6] = 0x1C;
bitsPtr[ 8] = 0x38;
bitsPtr[10] = 0x70;
bitsPtr[12] = 0xE0;
bitsPtr[14] = 0xC0;
bitsPtr[16] = 0xC0;
bitsPtr[18] = 0xE0;
bitsPtr[20] = 0x70;
bitsPtr[22] = 0x38;
bitsPtr[24] = 0x1C;
bitsPtr[26] = 0x0F;
bitsPtr[28] = 0x06;
p = (*theCraneClosed) = (BitMap *)NewPtrSysClear(CraneBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = CraneRowBytes;
SetRect(&p->bounds, -(CraneRight + 6), CraneTop,
-6, CraneBottom);
bitsPtr = p->baseAddr;
bitsPtr[ 4] = 0x0F;
bitsPtr[ 6] = 0x1F; bitsPtr[ 7] = 0x80;
bitsPtr[ 8] = 0x38;
bitsPtr[10] = 0x70;
bitsPtr[12] = 0xE0;
bitsPtr[14] = 0xC0;
bitsPtr[16] = 0xC0;
bitsPtr[18] = 0xE0;
bitsPtr[20] = 0x70;
bitsPtr[22] = 0x38;
bitsPtr[24] = 0x1F; bitsPtr[25] = 0x80;
bitsPtr[26] = 0x0F;
return(0);
}
/**********************************************
* MakeExplosionBitMaps
*
* Generates the explosion bitmaps that are
* used in some of the animation sequences.
**********************************************/
int
MakeExplosionBitMaps(theExp1, theExp2, theExp3,
theExp4, theExp5, theExp6)
BitMap **theExp1, **theExp2, **theExp3,
**theExp4, **theExp5, **theExp6;
{
Ptr bitsPtr;
int *bitsPtr16;
BitMap *p;
p = (*theExp1) = (BitMap *)NewPtrSysClear(AppleBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = AppleRowBytes;
SetRect(&p->bounds, AppleLeft, BgTop, BgRight, BgBottom);
bitsPtr16 = (int *)p->baseAddr;
bitsPtr16[ 5] = 0x18C0;
bitsPtr16[ 6] = 0x32E0;
bitsPtr16[ 7] = 0x2670;
bitsPtr16[ 8] = 0x2310;
bitsPtr16[ 9] = 0x3760;
bitsPtr16[10] = 0x07E0;
bitsPtr16[11] = 0x70C0;
bitsPtr16[12] = 0x7530;
bitsPtr16[13] = 0x3DE0;
bitsPtr16[14] = 0x01C0;
p = (*theExp2) = (BitMap *)NewPtrSysClear(AppleBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = AppleRowBytes;
SetRect(&p->bounds, AppleLeft, BgTop, BgRight, BgBottom);
bitsPtr16 = (int *)p->baseAddr;
bitsPtr16[ 4] = 0x00C0;
bitsPtr16[ 5] = 0x1D20;
bitsPtr16[ 6] = 0x2220;
bitsPtr16[ 7] = 0x2590;
bitsPtr16[ 8] = 0x4448;
bitsPtr16[ 9] = 0x5650;
bitsPtr16[10] = 0x2890;
bitsPtr16[11] = 0x4428;
bitsPtr16[12] = 0x4148;
bitsPtr16[13] = 0x2610;
bitsPtr16[14] = 0x19E0;
p = (*theExp3) = (BitMap *)NewPtrSysClear(AppleBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = AppleRowBytes;
SetRect(&p->bounds, AppleLeft, BgTop, BgRight, BgBottom);
bitsPtr16 = (int *)p->baseAddr;
bitsPtr16[ 4] = 0x3600;
bitsPtr16[ 5] = 0x49B0;
bitsPtr16[ 6] = 0x4448;
bitsPtr16[ 7] = 0x3288;
bitsPtr16[ 8] = 0x4448;
bitsPtr16[ 9] = 0x5250;
bitsPtr16[10] = 0x2820;
bitsPtr16[11] = 0x2450;
bitsPtr16[12] = 0x2390;
bitsPtr16[13] = 0x1C60;
p = (*theExp4) = (BitMap *)NewPtrSysClear(AppleBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = AppleRowBytes;
SetRect(&p->bounds, AppleLeft, BgTop, BgRight, BgBottom);
bitsPtr16 = (int *)p->baseAddr;
bitsPtr16[ 5] = 0x0660;
bitsPtr16[ 6] = 0x0990;
bitsPtr16[ 7] = 0x1450;
bitsPtr16[ 8] = 0x2320;
bitsPtr16[ 9] = 0x1450;
bitsPtr16[10] = 0x1390;
bitsPtr16[11] = 0x2220;
bitsPtr16[12] = 0x1990;
bitsPtr16[13] = 0x0660;
p = (*theExp5) = (BitMap *)NewPtrSysClear(AppleBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = AppleRowBytes;
SetRect(&p->bounds, AppleLeft, BgTop, BgRight, BgBottom);
bitsPtr16 = (int *)p->baseAddr;
bitsPtr16[ 6] = 0x0700;
bitsPtr16[ 7] = 0x08C0;
bitsPtr16[ 8] = 0x0920;
bitsPtr16[ 9] = 0x14C0;
bitsPtr16[10] = 0x1120;
bitsPtr16[11] = 0x08A0;
bitsPtr16[12] = 0x0740;
p = (*theExp6) = (BitMap *)NewPtrSysClear(AppleBitMapSize);
if (!p) return(1);
p->baseAddr = (Ptr)p + sizeof(BitMap);
p->rowBytes = AppleRowBytes;
SetRect(&p->bounds, AppleLeft, BgTop, BgRight, BgBottom);
bitsPtr = p->baseAddr;
bitsPtr[14] = 0x04;
bitsPtr[16] = 0x01;
bitsPtr[18] = 0x10;
bitsPtr[20] = 0x0A; bitsPtr[21] = 0x40;
bitsPtr[24] = 0x04;
return(0);
}
/**********************************************
* DoBombDisposal
*
* Replace the apple menu with a bomb, explode
* the bomb and then bring on a new apple.
**********************************************/
/* states for BombDisposal sequence */
#define BComeOnScreen 0
#define BStartClosing (BComeOnScreen + AppleLeft + 4)
#define BFinishClosing (BStartClosing + 1)
#define BRemoveApple (BFinishClosing + 1)
#define BBringOnBomb (BRemoveApple + BgRight + 1)
#define BStartOpening (BBringOnBomb + BgRight + 1)
#define BFinishOpening (BStartOpening + 1)
#define BLeaveScreen (BFinishOpening + 1)
#define BBurn1 (BLeaveScreen + 3)
#define BBurn2 (BBurn1 + 3)
#define BBurn3 (BBurn2 + 3)
#define BBurn4 (BBurn3 + 3)
#define BBurn5 (BBurn4 + 3)
#define BBurn6 (BBurn5 + 3)
#define BBurn7 (BBurn6 + 3)
#define BExp1 (BBurn7 + 3)
#define BExp2 (BExp1 + 3)
#define BExp3 (BExp2 + 3)
#define BExp4 (BExp3 + 3)
#define BExp5 (BExp4 + 3)
#define BExp6 (BExp5 + 3)
#define BExp7 (BExp6 + 3)
#define BExp8 (BExp7 + 3)
#define BBringBackApple (BExp8 + 10)
#define BStartOpening2 (BBringBackApple + BgRight + 1)
#define BFinishOpening2 (BStartOpening2 + 1)
#define BLeaveScreen2 (BFinishOpening2 + 1)
#define BAllDone (BLeaveScreen2 + AppleLeft + 5)
int
DoBombDisposal(void) {
int frameNo, craneDirection, objectDirection,
*bitsPtr16, err;
long nextFrame = 0;
Ptr bitsPtr;
GrafPtr oldPort, currentPort;
GDHandle theDevice;
BitMap *background, *offscreen, oldPortBits,
* apple, *bomb, *theObject, *theCrane,
*craneOpen, *craneClosing, *craneClosed,
*exp1, *exp2, *exp3, *exp4, *exp5, *exp6;
if (GetToolTrapAddress(GetMainDeviceTrap) !=
GetToolTrapAddress(UnimplementedTrap)) {
theDevice = GetMainDevice();
if (((**(**theDevice).gdPMap).pixelSize) != 1)
return(1);
}
oldPort = **(GrafPtr **)CurrentA5;
currentPort = WMgrPort;
SetPort( currentPort);
err = MakeCommonBitMaps(& apple, &background,
&offscreen, &craneOpen, &craneClosing,
&craneClosed, &oldPortBits, currentPort);
if (err) return(err);
err = MakeExplosionBitMaps(&exp1, &exp2, &exp3,
&exp4, &exp5, &exp6);
if (err) return(err);
craneOpen->bounds.left = -CraneRight;
craneOpen->bounds.right = 0;
craneClosed->bounds.left = AppleLeft-CraneRight+6;
craneClosed->bounds.right = AppleLeft+6;
bomb = (BitMap *)NewPtrSysClear(AppleBitMapSize);
if (!bomb) return(1);
bomb->baseAddr = (Ptr)bomb + sizeof(BitMap);
bomb->rowBytes = AppleRowBytes;
SetRect(&bomb->bounds, AppleLeft-BgRight,
BgTop, 0, BgBottom);
bitsPtr16 = (int *)bomb->baseAddr;
bitsPtr16[ 2] = 0x3000;
bitsPtr16[ 3] = 0x0C00;
bitsPtr16[ 4] = 0x0200;
bitsPtr16[ 5] = 0x0200;
bitsPtr16[ 6] = 0x0F80;
bitsPtr16[ 7] = 0x1FC0;
bitsPtr16[ 8] = 0x3E60;
bitsPtr16[ 9] = 0x3F60;
bitsPtr16[10] = 0x3FE0;
bitsPtr16[11] = 0x3FE0;
bitsPtr16[12] = 0x1FC0;
bitsPtr16[13] = 0x0F80;
theCrane = craneOpen;
craneDirection = 1;
theObject = apple;
objectDirection = 0;
for (frameNo=BComeOnScreen; frameNo
CopyBits(background, offscreen,
&background->bounds, &background->bounds,
srcCopy, 0L);
theObject->bounds.left += objectDirection;
theObject->bounds.right += objectDirection;
CopyBits(theObject, offscreen,
&theObject->bounds, &theObject->bounds, srcOr, 0L);
theCrane->bounds.left += craneDirection;
theCrane->bounds.right += craneDirection;
if (theCrane->bounds.left > 0) {
SetPortBits(offscreen);
PenSize(2,2);
MoveTo(0, CraneArmVLoc);
LineTo(theCrane->bounds.left, CraneArmVLoc);
PenSize(1,1);
SetPortBits(&oldPortBits);
}
CopyBits(theCrane, offscreen,
&theCrane->bounds, &theCrane->bounds, srcOr, 0L);
while (TickCount() < nextFrame) ;
nextFrame = TickCount() + TicksBetweenFrames;
CopyBits(offscreen, & currentPort->portBits,
&offscreen->bounds, &offscreen->bounds, srcCopy, 0L);
switch (frameNo) {
case BStartClosing:
/* stop the crane from moving and
* start it closing on the apple */
craneDirection = 0;
theCrane = craneClosing;
break;
case BFinishClosing:
/* close it on the apple */
theCrane = craneClosed;
break;
case BRemoveApple:
/* start the apple and the crane
* moving backwards */
craneDirection = -1;
objectDirection = -1;
break;
case BBringOnBomb:
/* start the crane moving forward */
craneDirection = 1;
/* change the object to the bomb and
* start it moving forward */
theObject = bomb;
objectDirection = 1;
break;
case BStartOpening:
case BStartOpening2:
/* stop the crane from moving */
craneDirection = 0;
/* start to open the crane */
theCrane = craneClosing;
/* stop the object from moving */
objectDirection = 0;
break;
case BFinishOpening:
case BFinishOpening2:
/* open the crane */
theCrane = craneOpen;
theCrane->bounds = craneClosing->bounds;
break;
case BLeaveScreen:
case BLeaveScreen2:
/* start the crane moving backwards */
craneDirection = -1;
break;
case BBurn1:
/* change the look of the fuse */
bitsPtr = bomb->baseAddr;
bitsPtr[ 0] = 0x40;
bitsPtr[ 4] = 0x90;
break;
case BBurn2:
/* change the look of the fuse */
bitsPtr = bomb->baseAddr;
bitsPtr[ 0] = 0x00;
bitsPtr[ 2] = 0x14;
bitsPtr[ 4] = 0x00;
bitsPtr[ 6] = 0x2C;
break;
case BBurn3:
/* change the look of the fuse */
bitsPtr = bomb->baseAddr;
bitsPtr[ 2] = 0x00;
bitsPtr[ 4] = 0x11;
bitsPtr[ 6] = 0x04;
bitsPtr[ 8] = 0x12;
break;
case BBurn4:
/* change the look of the fuse */
bitsPtr = bomb->baseAddr;
bitsPtr[ 4] = 0x02;
bitsPtr[ 6] = 0x08; bitsPtr[ 7] = 0x80;
bitsPtr[ 8] = 0x02;
break;
case BBurn5:
/* change the look of the fuse */
bitsPtr = bomb->baseAddr;
bitsPtr[ 4] = 0x00;
bitsPtr[ 6] = 0x04; bitsPtr[ 7] = 0x00;
bitsPtr[ 8] = 0x01;
break;
case BBurn6:
/* change the look of the fuse */
bitsPtr = bomb->baseAddr;
bitsPtr[ 6] = 0x00;
bitsPtr[ 8] = 0x02;
bitsPtr[10] = 0x00;
break;
case BBurn7:
/* change the look of the fuse */
bomb->baseAddr[ 8] = 0x00;
break;
case BExp1:
/* start the explosion sequence */
theObject = exp1;
break;
case BExp2:
theObject = exp2;
break;
case BExp3:
theObject = exp3;
/* now that the crane is off the
* screen, stop it from moving */
craneDirection = 0;
/* change it to the closed crane in
* preparation of brining an apple on */
theCrane = craneClosed;
theCrane->bounds.left = craneOpen->bounds.left-2;
theCrane->bounds.right = craneOpen->bounds.right-2;
break;
case BExp4:
theObject = exp2;
break;
case BExp5:
theObject = exp4;
break;
case BExp6:
theObject = exp5;
break;
case BExp7:
theObject = exp6;
break;
case BExp8:
/* change the last explosion to all white space */
bitsPtr = exp6->baseAddr;
bitsPtr[14] = 0x00;
bitsPtr[16] = 0x00;
bitsPtr[18] = 0x00;
bitsPtr[20] = 0x00; bitsPtr[21] = 0x00;
bitsPtr[24] = 0x00;
break;
case BBringBackApple:
/* start the crane and apple moving forward */
theObject = apple;
objectDirection = 1;
craneDirection = 1;
default:
break;
}
}
SetPort(oldPort);
DisposePtr(background);
DisposePtr(offscreen);
DisposePtr( apple);
DisposePtr(bomb);
DisposePtr(craneOpen);
DisposePtr(craneClosing);
DisposePtr(craneClosed);
DisposePtr(exp1);
DisposePtr(exp2);
DisposePtr(exp3);
DisposePtr(exp4);
DisposePtr(exp5);
DisposePtr(exp6);
return(0);
}
/**********************************************
* DoPacMan
*
* A PacMan-like thing eats the apple and
* then a new apple is brought out.
**********************************************/
#define PacManLeft 0
#define PacManTop 1
#define PacManRight 17
#define PacManBottom 18
#define PacManRowBytes (((PacManRight-PacManLeft+16) >> 3) &
0xFFFE)
#define PacManPixelSize (PacManRowBytes *
(PacManBottom-PacManTop+1))
#define PacManBitMapSize (sizeof(BitMap) + PacManPixelSize)
/* states for PacMan sequence */
#define PComeOnScreen 0
#define PAppleDisappear (PComeOnScreen + AppleLeft + PacManRight -
6)
#define PPMTurnAround (PAppleDisappear + 4)
#define PBringOnApple (PPMTurnAround + AppleLeft + PacManRight)
#define PStartOpening (PBringOnApple + BgRight - 3)
#define PFinishOpening (PStartOpening + 1)
#define PLeaveScreen (PFinishOpening + 1)
#define PAllDone (PLeaveScreen + AppleLeft + 5)
int
DoPacMan(void) {
int i, frameNo, craneDirection, objectDirection,
*bitsPtr16, pacManDirection, pmIndex, err,
pmOldIndex, mouthState, pacManGone;
long nextFrame = 0;
Ptr bitsPtr;
GrafPtr oldPort, currentPort;
GDHandle theDevice;
BitMap *background, *offscreen, oldPortBits,
* apple, *theObject, *theCrane,
*craneOpen, *craneClosing, *craneClosed,
*pacMan[8];
if (GetToolTrapAddress(GetMainDeviceTrap) !=
GetToolTrapAddress(UnimplementedTrap)) {
theDevice = GetMainDevice();
if (((**(**theDevice).gdPMap).pixelSize) != 1)
return(1);
}
oldPort = **(GrafPtr **)CurrentA5;
currentPort = WMgrPort;
SetPort( currentPort);
err = MakeCommonBitMaps(& apple, &background,
&offscreen, &craneOpen, &craneClosing,
&craneClosed, &oldPortBits, currentPort);
if (err) return(err);
pacMan[0] = (BitMap *)NewPtrSysClear(PacManBitMapSize);
if (!pacMan[0]) return(1);
pacMan[0]->baseAddr = (Ptr)pacMan[0] + sizeof(BitMap);
pacMan[0]->rowBytes = PacManRowBytes;
SetRect(&pacMan[0]->bounds, -PacManRight,
PacManTop, 0, PacManBottom);
bitsPtr16 = (int *)pacMan[0]->baseAddr;
bitsPtr16[ 0] = 0x03E0;
bitsPtr16[ 2] = 0x0FF8;
bitsPtr16[ 4] = 0x3FFE;
bitsPtr16[ 6] = 0x3FBE;
bitsPtr16[ 8] = 0x7FFF;
bitsPtr16[10] = 0x7FFF;
bitsPtr16[12] = 0xFFFF; bitsPtr16[13] = 0x8000;
bitsPtr16[14] = 0xFFFF; bitsPtr16[15] = 0x8000;
bitsPtr16[16] = 0xFFFF; bitsPtr16[17] = 0x8000;
bitsPtr16[18] = 0xFFFF; bitsPtr16[19] = 0x8000;
bitsPtr16[20] = 0xFFFF; bitsPtr16[21] = 0x8000;
bitsPtr16[22] = 0x7FFF;
bitsPtr16[24] = 0x7FFF;
bitsPtr16[26] = 0x3FFE;
bitsPtr16[28] = 0x3FFE;
bitsPtr16[30] = 0x0FF8;
bitsPtr16[32] = 0x03E0;
pacMan[1] = (BitMap *)NewPtrSys(PacManBitMapSize);
if (!pacMan[1]) return(1);
BlockMove(pacMan[0], pacMan[1], PacManBitMapSize);
pacMan[1]->baseAddr = (Ptr)pacMan[1] + sizeof(BitMap);
bitsPtr = pacMan[1]->baseAddr;
bitsPtr[21] = 0xFE;
bitsPtr[25] = 0xF8; bitsPtr[26] = 0x00;
bitsPtr[29] = 0xE0; bitsPtr[30] = 0x00;
bitsPtr[33] = 0x80; bitsPtr[34] = 0x00;
bitsPtr[37] = 0xE0; bitsPtr[38] = 0x00;
bitsPtr[41] = 0xF8; bitsPtr[42] = 0x00;
bitsPtr[45] = 0xFE;
/* since PacMans 2 and 3 are similar to 1, we
* calculate them as differences from 1 (saves code) */
for (i = 2; i < 4; i++) {
pacMan[i] = (BitMap *)NewPtrSys(PacManBitMapSize);
if (!pacMan[i]) return(1);
BlockMove(pacMan[1], pacMan[i], PacManBitMapSize);
pacMan[i]->baseAddr = (Ptr)pacMan[i] + sizeof(BitMap);
}
bitsPtr = pacMan[2]->baseAddr;
bitsPtr[ 9] = 0xFC;
bitsPtr[13] = 0xBC;
bitsPtr[17] = 0xF8;
bitsPtr[21] = 0xF0;
bitsPtr[25] = 0xE0;
bitsPtr[29] = 0xC0;
bitsPtr[37] = 0xC0;
bitsPtr[41] = 0xE0;
bitsPtr[45] = 0xF0;
bitsPtr[49] = 0xF8;
bitsPtr[53] = 0xFC;
bitsPtr[57] = 0xFC;
bitsPtr = pacMan[3]->baseAddr;
bitsPtr[ 9] = 0xF8;
bitsPtr[13] = 0xB0;
bitsPtr[17] = 0xE0;
bitsPtr[21] = 0xE0;
bitsPtr[25] = 0xC0;
bitsPtr[29] = 0xC0;
bitsPtr[37] = 0xC0;
bitsPtr[41] = 0xC0;
bitsPtr[45] = 0xE0;
bitsPtr[49] = 0xE0;
bitsPtr[53] = 0xF0;
bitsPtr[57] = 0xF8;
pacMan[4] = (BitMap *)NewPtrSys(PacManBitMapSize);
if (!pacMan[4]) return(1);
BlockMove(pacMan[0], pacMan[4], PacManBitMapSize);
pacMan[4]->baseAddr = (Ptr)pacMan[4] + sizeof(BitMap);
bitsPtr16 = (int *)pacMan[4]->baseAddr;
bitsPtr16[ 6] = 0x3EFE;
/* since PacMans 5, 6 and 7 are similar to 4, we
* calculate them as differences from 4 (saves code) */
for (i = 5; i < 8; i++) {
pacMan[i] = (BitMap *)NewPtrSys(PacManBitMapSize);
if (!pacMan[i]) return(1);
BlockMove(pacMan[4], pacMan[i], PacManBitMapSize);
pacMan[i]->baseAddr = (Ptr)pacMan[i] + sizeof(BitMap);
}
bitsPtr = pacMan[5]->baseAddr;
bitsPtr[20] = 0x3F;
bitsPtr[24] = 0x0F;
bitsPtr[28] = 0x03;
bitsPtr[32] = 0x00;
bitsPtr[36] = 0x03;
bitsPtr[40] = 0x0F;
bitsPtr[44] = 0x3F;
bitsPtr = pacMan[6]->baseAddr;
bitsPtr[ 8] = 0x1F;
bitsPtr[12] = 0x1E;
bitsPtr[16] = 0x0F;
bitsPtr[20] = 0x07;
bitsPtr[24] = 0x03;
bitsPtr[28] = 0x01;
bitsPtr[32] = 0x00;
bitsPtr[36] = 0x01;
bitsPtr[40] = 0x03;
bitsPtr[44] = 0x07;
bitsPtr[48] = 0x0F;
bitsPtr[52] = 0x1F;
bitsPtr[56] = 0x1F;
bitsPtr = pacMan[7]->baseAddr;
bitsPtr[ 8] = 0x0F;
bitsPtr[12] = 0x06;
bitsPtr[16] = 0x03;
bitsPtr[20] = 0x03;
bitsPtr[24] = 0x01;
bitsPtr[28] = 0x01;
bitsPtr[32] = 0x00;
bitsPtr[36] = 0x01;
bitsPtr[40] = 0x01;
bitsPtr[44] = 0x03;
bitsPtr[48] = 0x03;
bitsPtr[52] = 0x07;
bitsPtr[56] = 0x0F;
/* initially, there is no crane */
theCrane = 0;
/* the object is the apple and it's not moving */
theObject = apple;
objectDirection = 0;
/* PacMan starting state so that when he gets
* to the apple his mouth is just beginning to close */
pmIndex = 2;
mouthState = 1;
pacManDirection = 1;
pacManGone = 0;
for (frameNo=PComeOnScreen; frameNo CopyBits(background, offscreen,
&background->bounds, &background->bounds,
srcCopy, 0L);
theObject->bounds.left += objectDirection;
theObject->bounds.right += objectDirection;
CopyBits(theObject, offscreen,
&theObject->bounds, &theObject->bounds, srcOr, 0L);
if (theCrane) {
theCrane->bounds.left += craneDirection;
theCrane->bounds.right += craneDirection;
if (theCrane->bounds.left > 0) {
SetPortBits(offscreen);
PenSize(2,2);
MoveTo(0, CraneArmVLoc);
LineTo(theCrane->bounds.left, CraneArmVLoc);
PenSize(1,1);
SetPortBits(&oldPortBits);
}
CopyBits(theCrane, offscreen,
&theCrane->bounds, &theCrane->bounds, srcOr, 0L);
}
if (!pacManGone) {
pacMan[pmIndex]->bounds.left += pacManDirection;
pacMan[pmIndex]->bounds.right += pacManDirection;
CopyBits(pacMan[pmIndex], offscreen,
&pacMan[pmIndex]->bounds,
&pacMan[pmIndex]->bounds, srcOr, 0L);
/* The indexes of the mouth follow this
* pattern: 0,1,2,3,2,1,0,1,2,... when
* moving to the right and this pattern:
* 4,5,6,7,6,5,4,5,6... when moving to
* the right. The new few lines deal with
* this. */
pmOldIndex = pmIndex;
if (pacManDirection < 0)
pmIndex -= 4;
pmIndex += mouthState;
if (pmIndex > 3) {
pmIndex = 2;
mouthState = -1;
}
else if (pmIndex < 0) {
pmIndex = 1;
mouthState = 1;
}
if (pacManDirection < 0)
pmIndex += 4;
pacMan[pmIndex]->bounds =
pacMan[pmOldIndex]->bounds;
}
while (TickCount() < nextFrame) ;
nextFrame = TickCount() + TicksBetweenFrames;
CopyBits(offscreen, & currentPort->portBits,
&offscreen->bounds, &offscreen->bounds, srcCopy, 0L);
switch (frameNo) {
case PAppleDisappear:
/* when the PacMan gets on top of the apple
* reposition it to be offscreen (where the
* crane will need it to bring it back on) */
theObject->bounds.left -= (BgRight - 3);
theObject->bounds.right -= (BgRight - 3);
break;
case PPMTurnAround:
/* make PacMan move to the left */
pacManDirection = -1;
/* we're dealing with the second set
* of four PacMan BitMaps now */
pmIndex += 4;
pacMan[pmIndex]->bounds =
pacMan[pmIndex-4]->bounds;
break;
case PBringOnApple:
/* now that PacMan is gone, we're finished
* with him */
pacManGone = 1;
/* start the closed crane moving to the
* right */
theCrane = craneClosed;
craneDirection = 1;
/* start the apple moving to the right */
objectDirection = 1;
break;
case PStartOpening:
/* stop the crane and start it opening */
craneDirection = 0;
theCrane = craneClosing;
/* stop the apple */
objectDirection = 0;
break;
case PFinishOpening:
/* open the crane */
theCrane = craneOpen;
break;
case PLeaveScreen:
/* start the crane moving to the left */
craneDirection = -1;
break;
default:
break;
}
}
SetPort(oldPort);
DisposePtr(background);
DisposePtr(offscreen);
DisposePtr( apple);
DisposePtr(craneOpen);
DisposePtr(craneClosing);
DisposePtr(craneClosed);
for (i = 0; i < 8; i++)
DisposePtr(pacMan[i]);
return(0);
}
/**********************************************
* DoTank
*
* A little tank comes out and blows up the
* apple. The tank goes away and a new apple
* is brought out.
**********************************************/
#define TankLeft 0
#define TankTop 10
#define TankRight 11
#define TankBottom 18
#define TankRowBytes (((TankRight-TankLeft+16) >> 3) & 0xFFFE)
#define TankPixelSize (TankRowBytes * (TankBottom-TankTop+1))
#define TankBitMapSize (sizeof(BitMap) + TankPixelSize)
/* states for Tank sequence */
#define TComeOnScreen 0
#define TTankStop (TComeOnScreen + AppleLeft)
#define TRaiseTurret (TTankStop + 10)
#define TAim (TRaiseTurret + 10)
#define TFire (TAim + 3)
#define TRecoil (TFire + 1)
#define TExp2 (TRecoil + 2)
#define TExp3 (TExp2 + 3)
#define TExp4 (TExp3 + 3)
#define TExp5 (TExp4 + 3)
#define TExp6 (TExp5 + 3)
#define TExp7 (TExp6 + 3)
#define TExp8 (TExp7 + 3)
#define TLowerTurret (TExp8 + 10)
#define TTankLeave (TLowerTurret + 10)
#define TBringOnApple (TTankLeave + AppleLeft + 3)
#define TStartOpening (TBringOnApple + BgRight - 3)
#define TFinishOpening (TStartOpening + 1)
#define TLeaveScreen (TFinishOpening + 1)
#define TAllDone (TLeaveScreen + AppleLeft + 5)
int
DoTank(void) {
int i, frameNo, *bitsPtr16, evenTread, tankDone, err,
craneDirection, objectDirection, tankDirection;
long nextFrame = 0;
Ptr bitsPtr;
GrafPtr oldPort, currentPort;
GDHandle theDevice;
BitMap *background, *offscreen, oldPortBits,
* apple, *theObject, *tank, *theCrane,
*craneOpen, *craneClosing, *craneClosed,
*exp1, *exp2, *exp3, *exp4, *exp5, *exp6;
if (GetToolTrapAddress(GetMainDeviceTrap) !=
GetToolTrapAddress(UnimplementedTrap)) {
theDevice = GetMainDevice();
if (((**(**theDevice).gdPMap).pixelSize) != 1)
return(1);
}
oldPort = **(GrafPtr **)CurrentA5;
currentPort = WMgrPort;
SetPort( currentPort);
err = MakeCommonBitMaps(& apple, &background,
&offscreen, &craneOpen, &craneClosing,
&craneClosed, &oldPortBits, currentPort);
if (err) return(err);
err = MakeExplosionBitMaps(&exp1, &exp2, &exp3,
&exp4, &exp5, &exp6);
if (err) return(err);
tank = (BitMap *)NewPtrSysClear(TankBitMapSize);
if (!tank) return(1);
tank->baseAddr = (Ptr)tank + sizeof(BitMap);
tank->rowBytes = TankRowBytes;
SetRect(&tank->bounds, -TankRight,
TankTop, 0, TankBottom);
bitsPtr16 = (int *)tank->baseAddr;
bitsPtr16[ 0] = 0x1C00;
bitsPtr16[ 1] = 0x37E0;
bitsPtr16[ 2] = 0x2200;
bitsPtr16[ 3] = 0x7F80;
bitsPtr16[ 4] = 0xD540;
bitsPtr16[ 5] = 0x80C0;
bitsPtr16[ 6] = 0xD540;
bitsPtr16[ 7] = 0x7F80;
/* initially, there is no crane, the apple
* is stationary and the tank is moving
* forward */
theCrane = 0;
theObject = apple;
objectDirection = 0;
tankDirection = 1;
evenTread = 0;
tankDone = 0;
for (frameNo=TComeOnScreen; frameNo
CopyBits(background, offscreen,
&background->bounds, &background->bounds,
srcCopy, 0L);
theObject->bounds.left += objectDirection;
theObject->bounds.right += objectDirection;
CopyBits(theObject, offscreen,
&theObject->bounds, &theObject->bounds, srcOr, 0L);
if (!tankDone) {
tank->bounds.left += tankDirection;
tank->bounds.right += tankDirection;
if (tankDirection) {
/* since the tank is moving, change
* its treads' appearance */
bitsPtr16 = (int *)tank->baseAddr;
if (evenTread) {
bitsPtr16[ 4] = 0xD540;
bitsPtr16[ 5] = 0x80C0;
bitsPtr16[ 6] = 0xD540;
}
else {
bitsPtr16[ 4] = 0xAAC0;
bitsPtr16[ 5] = 0xC040;
bitsPtr16[ 6] = 0xAAC0;
}
evenTread = ~evenTread;
}
CopyBits(tank, offscreen,
&tank->bounds, &tank->bounds, srcOr, 0L);
}
if (theCrane) {
theCrane->bounds.left += craneDirection;
theCrane->bounds.right += craneDirection;
if (theCrane->bounds.left > 0) {
SetPortBits(offscreen);
PenSize(2,2);
MoveTo(0, CraneArmVLoc);
LineTo(theCrane->bounds.left, CraneArmVLoc);
PenSize(1,1);
SetPortBits(&oldPortBits);
}
CopyBits(theCrane, offscreen,
&theCrane->bounds, &theCrane->bounds, srcOr, 0L);
}
while (TickCount() < nextFrame) ;
nextFrame = TickCount() + TicksBetweenFrames;
CopyBits(offscreen, & currentPort->portBits,
&offscreen->bounds, &offscreen->bounds,
srcCopy, 0L);
switch (frameNo) {
case TTankStop:
/* stop the tank from moving forward */
tankDirection = 0;
break;
case TRaiseTurret:
/* change the BitMap to a raised turret */
bitsPtr16 = (int *)tank->baseAddr;
bitsPtr16[ 0] = 0x1C60;
bitsPtr16[ 1] = 0x3780;
break;
case TFire:
/* move the tank left 1 pixel for recoil */
tank->bounds.left-;
tank->bounds.right-;
/* change the object from the apple to the
* first frame of the explosion */
theObject = exp1;
break;
case TRecoil:
/* move the tank back after the recoil */
tank->bounds.left++;
tank->bounds.right++;
break;
case TExp2:
theObject = exp2;
break;
case TExp3:
theObject = exp3;
break;
case TExp4:
theObject = exp2;
break;
case TExp5:
theObject = exp4;
break;
case TExp6:
theObject = exp5;
break;
case TExp7:
theObject = exp6;
break;
case TExp8:
/* change the last explosion to all white space */
bitsPtr = exp6->baseAddr;
bitsPtr[14] = 0x00;
bitsPtr[16] = 0x00;
bitsPtr[18] = 0x00;
bitsPtr[20] = 0x00; bitsPtr[21] = 0x00;
bitsPtr[24] = 0x00;
break;
case TLowerTurret:
/* change the BitMap to a lowered turret */
bitsPtr16 = (int *)tank->baseAddr;
bitsPtr16[ 0] = 0x1C00;
bitsPtr16[ 1] = 0x37E0;
break;
case TTankLeave:
/* start the tank moving backwards */
tankDirection = -1;
break;
case TBringOnApple:
/* tank is off the screen now */
tankDone = 1;
/* start the closed crane moving foward */
theCrane = craneClosed;
craneDirection = 1;
/* position the apple to be in the crane */
theObject = apple;
theObject->bounds.left -= (BgRight - 3);
theObject->bounds.right -= (BgRight - 3);
objectDirection = 1;
break;
case TStartOpening:
/* stop the crane from moving */
craneDirection = 0;
/* let go of the apple */
theCrane = craneClosing;
/* stop the apple from moving */
objectDirection = 0;
break;
case TFinishOpening:
/* open the crane some more */
theCrane = craneOpen;
break;
case TLeaveScreen:
/* start the crane moving backwards */
craneDirection = -1;
break;
default:
break;
}
}
SetPort(oldPort);
DisposePtr(background);
DisposePtr(offscreen);
DisposePtr( apple);
DisposePtr(craneOpen);
DisposePtr(craneClosing);
DisposePtr(craneClosed);
DisposePtr(exp1);
DisposePtr(exp2);
DisposePtr(exp3);
DisposePtr(exp4);
DisposePtr(exp5);
DisposePtr(exp6);
DisposePtr(tank);
return(0);
}