home *** CD-ROM | disk | FTP | other *** search
-
- ; This is the crawling insect DA, disassembled and tweaked.
- ; Should work on all kinds of screens now.
- ; Fixed crashes due to calling _Random in VBL with invalid A5.
- ; Added option-open and cmd-opt-open features to kill bugs.
-
- ; E.M.Vishniac
- ; P.O. Box 1357
- ; East Arlington, MA 02174
-
- ; March 7, 1987
-
- ; Thanks to MacNosy for invaluable assistance.
-
- ; When opened, the crawling insect DA starts a bug working its way
- ; up the screen. Opening the DA repeatedly creates more bugs.
- ; Option-opening the DA kills one bug (the youngest).
- ; Command-option-opening the DA kills all the bugs.
-
- ; Though the DA is useless, except for laughs, it is an interesting
- ; example of a VBL task.
-
- ; A lesson:
- ; The original Insect DA crashed at Random times. The
- ; reason was that ResetBug calls _Random, which
- ; uses the quickdraw globals. In a VBL task, A5 may not
- ; be current. To guard against problems, load A5 with
- ; CurrentA5 in the VBL.
- ; Actually, that's not perfect, since CurrentA5 might
- ; not be valid at some times! So, we won't use A5 at
- ; all - we'll use our own Random routine. 5/15/89.
-
- Include Traps.D
- Include SysEquX.D
- Include QuickEquX.D
- Include ToolEqu.D
- Include SysErr.D
-
- macro POP p1 =
- move (A7)+,{P1} |
-
- macro POP.L p1 =
- move.L (A7)+,{P1} |
-
- macro PUSH p1 =
- move {P1},-(a7) |
-
- macro PUSH.L p1 =
- move.L {P1},-(a7) |
-
-
- jHideCursor equ $800 ; address of HideCursor routine
-
- BugInterval equ 7 ; ticks between VBL task runs
- BugHeight equ 16 ; bug is 16 rows high
-
-
- RESOURCE 'DRVR' 31 'Insect' 00
-
- Insect
- DC.W $4F,0,0,0 ; flags, delay, emask, menu
-
- DC.W Open ; open routine
- DC.W Close ; no prime
- DC.W Close ; no control
- DC.W Close ; no status
- DC.W Close ; no close
- ; No name?
-
- ; In case someone gets the DA without source code...
- DC.B ' For source code, send a diskette '
- DC.B 'and a self-addressed, stamped envelope to: '
- DC.B 'Ephraim Vishniac / P.O. Box 1357 '
- DC.B '/ East Arlington, MA 02174. '
- DC.B 'No postage = no reply. '
- .align 2
-
- ; Starting here, the code and data are copied
- ; into the system heap when the DA is opened.
-
- BugBase
- DC.B 'BUG ' ; signature
-
-
- MyVBLTask
- DC.L 0 ; qLink
- DC.W 1 ; qType
- DC.L 0 ; vblAddr
- DC.W BugInterval ; vblCount
- DC.W 0 ; vblPhase
-
-
- oldHide DC.L 0 ; jHideCursor
- oldShow DC.L 0 ; jShowCursor
- oldShield DC.L 0 ; jShieldCursor
-
- ; Here's the local data used by the VBL task.
- LocalData equ *
-
- PaintLoc equ *-LocalData
- DC.L 0 ; [long] address to paint bug
- Generation equ *-LocalData
- DC.W 0 ; [word] bug generation
- Saved equ *-LocalData
- DC.B 0 ; [byte] We've saved the screen data
- DC.B 0 ; [byte] for aligment
- MyScrnBase equ *-LocalData
- DC.L 0 ; [long] start of screen bitmap
- MyScrnRow equ *-LocalData
- DC.W 0 ; [word] size of screen low in bytes
- MyScrnRect equ *-LocalData
- DC.W 0,0,0,0 ; [rect] screen rectangle
-
- ShieldRect equ *-LocalData
- DC.W 0,0,0,0 ; [rect] rectangle for ShieldCursor
- ShieldReturn equ *-LocalData
- DC.L 0 ; [long] return addr from ShieldCursor
- ShieldSR equ *-LocalData
- DC.W 0 ; [word] SR in ShieldCursor
- ScreenData equ *-LocalData
- DCB.W 16,0 ; [16 words] saved screen data
- RandomSeed equ *-LocalData
- DC.L 0 ; [long] seed for random numbers
-
-
- ; This is the main bug task, called every BugInterval clock ticks
- ; by the VBL manager.
-
- MyVBLproc
- Move SR,-(A7) ; save status
- OrI #$100,SR ; mask off some interrupts. needed?
-
- Lea MyVBLTask,A0
- Move #1,vblCount(A0) ; we might have to defer...
- Tst.B CrsrBusy ; Cursor busy?
- Bne @0 ; exit if so
-
- Move #BugInterval,vblCount(A0) ; renew our task
- Bsr Generate ; do our stuff
-
- @0 Move (A7)+,SR ; restore status
- Rts ; and exit
-
-
- ; This routine produces a new generation of the bug.
-
- Generate
- MoveM.L D7/A2-A4,-(A7) ; save registers
-
- Lea LocalData,A4
-
- Move CrsrState,D7 ; D7 = Cursor state
- Tst.L (A4) ; anything doing?
- Beq @3 ; exit if not
-
- Bsr DoOldHide ; hide the cursor
-
- Bsr PaintOverBug ; restore the screen
-
- Move Generation(A4),D0 ; D0.W = bug generation
- AddQ #1,D0 ; increment generation
- CmpI #6,D0 ; there are six generations
- Bne @1 ; skip if not wrapped
- Clr D0 ; else wrap to zero
- @1 Move D0,Generation(A4) ; update generation
-
- Move.L (A4),A0 ; A0 = place to paint
- Sub.W MyScrnRow(A4),A0 ; previous row
- Move.L A0,(A4) ; update
-
- CmpA.L MyScrnBase(A4),A0 ; off top?
- Bge @2 ; skip if not
- Bsr ResetBug ; else pick a new location
-
- @2 Bsr DrawBugPlus ; Draw bug if cursor wasn't obscure
-
- Bsr DoOldShow ; show the cursor
-
- @3 MoveM.L (A7)+,D7/A2-A4 ; restore registers
- MoveQ #0,D0 ; and end update
- Rts
-
-
- ; This substitute for HideCursor makes sure that the bug is hidden
- ; whenever the cursor is hidden.
-
- MyHide
- Move SR,-(A7) ; simulate exception
- OrI #$100,SR ; disable some interrupts
-
- Bsr DoOldHide ; hide the cursor
-
- MoveM.L D0-D1/A0-A4,-(A7) ; save registers
-
- Lea LocalData,A4 ; We hide when the cursor hides
- Tst.L (A4) ; are we active?
- Beq @1 ; exit if not
-
- Bsr PaintOverBug ; restore the screen
-
- @1 MoveM.L (A7)+,D0-D1/A0-A4 ; restore registers
- Move (A7)+,SR ; restore status register
- Rts
-
- DoOldHide
- Push.L oldHide ; run the original HideCursor
- Rts
-
-
- ; This substitute for ShowCursor makes sure that the bug is visible
- ; whenever the cursor is visible.
-
- MyShow
- Move SR,-(A7) ; simulate exception
- OrI #$100,SR ; disable interrupts
-
- MoveM.L D0-D1/A0-A4,-(A7) ; save registers
- Lea LocalData,A4
- Tst.L (A4) ; are we active?
- Beq @2 ; exit if not
- Move CrsrState,D0 ; D0 = Cursor State
- Beq @1 ; branch if State = Visible
- CmpI #-1,D0 ; State = obscure?
- Bne @2 ; exit if not
-
- @1 Bsr DrawBug ; cursor state is Visible or Obscure
-
- @2 MoveM.L (A7)+,D0-D1/A0-A4 ; restore registers
- Bsr DoOldShow ; restore cursor
- Move (A7)+,SR ; restore SR
- Rts
-
- DoOldShow
- Push.L oldShow ; run the original ShowCursor
- Rts
-
-
- ; This substitute for ShieldCursor does for the bug what
- ; ShieldCursor does for the cursor.
-
- vak_1 EQU 4
- param2 EQU 8
- param1 EQU 12
-
- MyShield
- Link A6,#0
- Push.L A4
- Lea LocalData,A4
- Move SR,ShieldSR(A4) ; save SR
- OrI #$100,SR
- Move.L vak_1(A6),ShieldReturn(A4) ; save return address
- Move.L param2(A6),ShieldRect(A4) ; save rectangle
- Move.L param1(A6),ShieldRect+4(A4)
- Pop.L A4 ; end use of local vars
- UnLk A6
-
- AddQ.L #4,A7 ; trash return address so ShieldCursor can work
-
- Bsr DoOldShield ; shield the cursor
-
- MoveM.L D0-D1/A1-A4,-(A7) ; save regs
- Lea LocalData,A4
- Tst.L (A4) ; are we active?
- Beq @2 ; exit if not
-
- Bsr GetBugRect ; get bug rectangle on stack
-
- Move (A7),D0 ; D0 = bug bottom
- Cmp.W ShieldRect+4(A4),D0 ; compare to ShieldRect top
- Ble @1 ; exit if bug's clear above
-
- Move 2(A7),D0 ; D0 = bug right
- Cmp.W ShieldRect+6(A4),D0 ; compare to ShieldRect left
- Ble @1 ; exit if bug's clear left
-
- Move 4(A7),D0 ; D0 = bug top
- Cmp.W ShieldRect(A4),D0 ; compare to ShieldRect bottom
- Bge @1 ; exit if bug's clear below
-
- Move 6(A7),D0 ; D0 = bug left
- Cmp.W ShieldRect+2(A4),D0 ; compare to ShieldRect right
- Bge @1 ; exit if bug's clear right
-
- ; Bug's in the affected rectangle
- Bsr DoOldHide ; hide the cursor
- Bsr PaintOverBug ; restore the screen
- Bsr DoOldShow ; restore the cursor
-
- @1 AddQ.L #8,A7 ; remove rect from stack
- @2 MoveA.L ShieldReturn(A4),A0 ; A0 = return address
- Move ShieldSR(A4),SR ; restore SR
- MoveM.L (A7)+,D0-D1/A1-A4 ; restore registers
- Jmp (A0)
-
- DoOldShield
- Push.L oldShield ; call old ShieldCursor
- Rts
-
-
- ; Construct the Rect for the bug's current location and return it
- ; on the stack, of all places.
-
- GetBugRect
- Pop.L A0 ; A0 = return address
- Move.L (A4),D1 ; D1 = place to paint screen
- Sub.L MyScrnBase(A4),D1 ; D1 = screen offset
- DivU MyScrnRow(A4),D1 ; D1.W = row; high word = column
- Move D1,D0 ; D0.W = row
- Swap D1 ; low word = column byte
- Ext.L D1 ; D1 = left edge, byte offset
- LSL #3,D1 ; D1 = left edge, bit offset
- Push D1 ; push for caller
- AddI #16,D1 ; D1 = right edge, bit offset
-
- Ext.L D0 ; D0 = top edge, row number
- Push D0 ; push for caller
- AddI #16,D0 ; D0.L = bottom edge, row #
- Push D1 ; push right edge
- Push D0 ; push bottom edge
- Jmp (A0) ; return with Rect on stack
-
-
- ; Pick a starting location for the bug and reset the bug generation.
-
- ResetBug
- Clr -(A7) ; for random number
- Bsr MyRandom ; random number generator
- Clr.L D0 ; clear high word
- Pop D0 ; D0.W = random number
- DivU MyScrnRow(A4),D0 ; pick random column
- Swap D0 ; D0.W = some random column
- BClr #0,D0 ; force word alignment
- Ext.L D0
- Add.L MyScrnBase(A4),D0 ; add start of screen
- Move.W MyScrnRect+botRight(A4),D1 ; depth of screen
- Sub.W #16,D1 ; less height of bug
- MulU MyScrnRow(A4),D1 ; offset that many bytes
- Add.L D1,D0 ; screen + lines
- Move.L D0,(A4) ; save as place to paint
- Clr Generation(A4) ; start at first generation
- Rts
-
-
- ; Save the screen image which would be covered by the bug.
-
- SaveUnderBug
- Lea ScreenData(A4),A0 ; A0 = pointer to screen data area
- MoveA.L (A4),A1 ; A1 = place to paint bug
-
- Move #BugHeight-1,D1
- @1 Move (A1),(A0)+ ; save a long
- AddA.W MyScrnRow(A4),A1 ; next row
- DBra D1,@1 ; all the rows
- Rts
-
-
- ; Draw the bug if the cursor is not obscured.
-
- DrawBugPlus
- Tst.B D7 ; cursor obscure? (obscure = -1)
- Bpl DrawBug ; branch if visible or nested
- Rts ; exit if obscure
-
- ; Draw the bug if it's not drawn already.
- ; (Previously saved screen data means the bug is out there.)
-
- DrawBug
- BSet.B #0,Saved(A4) ; saved screen data?
- Bne @2 ; exit if already saved
-
- Bsr SaveUnderBug ; save screen data
-
- Lea BugImages,A0
- Lea BugMasks,A2
- Move Generation(A4),D0 ; D0.W = bug generation
- Ext.L D0 ; D0.L = ditto
- ASL #5,D0 ; generation * 32
- AddA.L D0,A0 ; offset into bug images
- AddA.L D0,A2 ; offset into bug masks
- MoveA.L (A4),A1 ; A1 = place to paint
-
- Move #BugHeight-1,D1
- @1 Move (A2)+,D0 ; fetch mask
- Not D0
- And D0,(A1)
- Move (A0)+,D0 ; fetch image
- Eor D0,(A1)
- AddA.W MyScrnRow(A4),A1 ; next row
- DBra D1,@1
- @2 Rts
-
-
- ; Restore the screen data that the bug stepped on.
-
- PaintOverBug
- BClr.B #0,Saved(A4) ; Screen saved before? (It's not now.)
- Beq @2 ; exit if no screen data
-
- Lea ScreenData(A4),A0 ; A0 = pointer to saved screen data
- MoveA.L (A4),A1 ; A1 = place to start painting on screen
-
- Move #BugHeight-1,D1
- @1 Move (A0)+,(A1) ; copy a word
- AddA.W MyScrnRow(A4),A1 ; skip to next row
- DBra D1,@1 ; and copy them all
- @2 Rts
-
- ; Generate a random number. This is stolen from the Mac Plus ROM code.
- ; Instead of using the QD global seed, it uses one from our local vars.
-
- MyRandom
- Move.W #$41A7,D0
- Move.W D0,D2
- Mulu.W RandomSeed+2(A4),D0
- Move.L D0,D1
- Clr.W D1
- Swap D1
- Mulu.W RandomSeed(A4),D2
- Add.L D1,D2
- Move.L D2,D1
- Add.L D1,D1
- Clr.W D1
- Swap D1
- Andi.L #$FFFF,D0
- Subi.L #$7FFFFFFF,D0
- Andi.L #$7FFF,D2
- Swap D2
- Add.L D1,D2
- Add.L D2,D0
- Bpl.S @0
- Addi.L #$7FFFFFFF,D0
- @0 Move.L D0,RandomSeed(A4)
- Cmpi.W #$8000,D0
- Bne.S @1
- Clr.W D0
- @1 Move.W D0,4(A7)
- Rts
-
- ; Here's the actual bug data.
- ; First are the bug images, then the bug masks.
- ; There are six sets of data for six bug generations.
- BugImages
- DC.L $00102010,$11A00E40,$02400181,$8662781C
- DC.L $08100811,$781E8810,$0810381E,$442183C0
-
- DC.L $20041008,$09900660,$02400180,$0661781E
- DC.L $88108810,$781E0811,$8810781C,$042203C1
-
- DC.L $08000804,$05880270,$02408180,$4660381E
- DC.L $08110811,$781E8810,$0811781E,$842003C0
-
- DC.L $20001000,$09800678,$02440181,$8662781C
- DC.L $08108810,$781E0811,$0810381E,$442183C0
-
- DC.L $00002004,$11880E70,$02400180,$0661781E
- DC.L $88100811,$781E8810,$8810781C,$042203C1
-
- DC.L $00040008,$01901E60,$22408180,$4660381E
- DC.L $08118810,$781E0811,$0811781E,$842003C0
-
- BugMasks
- DC.L $00102010,$11A00FC0,$03C00181,$87E27FFC
- DC.L $0FF00FF1,$7FFE8FF0,$0FF03FFE,$47E183C0
-
- DC.L $20041008,$099007E0,$03C00180,$07E17FFE
- DC.L $8FF08FF0,$7FFE0FF1,$8FF07FFC,$07E203C1
-
- DC.L $08000804,$058803F0,$03C08180,$47E03FFE
- DC.L $0FF10FF1,$7FFE8FF0,$0FF17FFE,$87E003C0
-
- DC.L $20001000,$098007F8,$03C40181,$87E27FFC
- DC.L $0FF08FF0,$7FFE0FF1,$0FF03FFE,$47E183C0
-
- DC.L $00002004,$11880FF0,$03C00180,$07E17FFE
- DC.L $8FF00FF1,$7FFE8FF0,$8FF07FFC,$07E203C1
-
- DC.L $00040008,$01901FE0,$23C08180,$47E03FFE
- DC.L $0FF18FF0,$7FFE0FF1,$0FF17FFE,$87E003C0
-
- StaticSize equ *-MyVBLProc ; size of non-variable stuff
- FullSize equ *-BugBase ; size of everything
-
- ; Open: Install the bug in the system heap, hook it into the cursor
- ; routines, and put it in the VBL queue.
-
- Open MoveM.L A3-A5/D7,-(A7) ; save registers
- Move.L CurrentA5,A5 ; make sure A5 is OK
-
- ; Why are we here?
- Link A6,#-evtBlkSize ; space for event record
- Clr.W -(A7) ; for event-avail result
- Clr.W -(A7) ; we want no events!
- Pea -evtBlkSize(A6) ; our event block
- _EventAvail ; see what's going down
- Tst.W (A7)+ ; toss result
- Move.W evtMeta(A7),D7 ; save modifiers
- UnLk A6 ; discard event record
- BTst.L #optionKey,D7 ; option key down?
- Bne KillBug ; if so, go kill a bug
-
- ; No option key, so it's time to spawn a bug
- ; Get some sysheap space
- Move.L #FullSize,D0 ; stuff to copy into sysheap
- Move.L D0,D4
- _NewPtr ,SYS+CLEAR ; (D0/byteCount:Size):A0\Ptr
- Tst D0 ; got the storage?
- Bmi com_2 ; beep if error
-
- ; A0 = our pointer in SysHeap
- Move.L A0,A3 ; save our pointer
-
- ; save the addresses of the cursor routines
- Lea jHideCursor,A0 ; A0 = addr of jHideCursor
- Lea oldHide,A1 ; our storage for old hooks
- Move.L (A0)+,(A1)+ ; jHideCursor
- Move.L (A0)+,(A1)+ ; jShowCursor
- Move.L (A0),(A1) ; jShieldCursor
-
- ; initialize bug's local data
- Lea LocalData,A4 ; A4 = local data for bug
-
- Move.L Time,RandomSeed(A4) ; seed our number generator
-
- Move.L (A5),A1 ; A1 = qd globals
- Push.L thePort(A1) ; save current port
-
- Link A6,#-GrafSize ; space for a GrafPort
- Push.L A7 ; our GrafPort
- _OpenPort ; get a full-screen port
- Move.L portBits+BaseAddr(A7),MyScrnBase(A4)
- ; start of screen
- Move.W portBits+RowBytes(A7),MyScrnRow(A4)
- ; bytes in row
- Move.L portBits+bounds+topLeft(A7),MyScrnRect(A4)
- Move.L portBits+bounds+botRight(A7),MyScrnRect+4(A4)
- ; the screen's rectangle
- Push.L A7 ; our short-lived GrafPort
- _ClosePort ; say goodbye!
- UnLk A6 ; restore stack
-
- _SetPort ; restore user's port
-
- Jsr ResetBug ; set bug's starting point
-
- ; copy the essential stuff into our sysheap block
- MoveA.L A3,A1 ; A1 = our sysheap pointer
- Lea BugBase,A0
- Move.L D4,D0 ; D0 = our pointer's length
- _BlockMove ; (A0/srcPtr, A1/destPtr:Ptr; D0/byteCount:Size)
-
- ; replace the cursor hooks with our own
- Lea jHideCursor,A0 ; A0 = addr of jHideCursor
- Lea MyHide-BugBase(A3),A1 ; our HideCursor
- Move.L A1,(A0)+ ; replace jHideCursor
- Lea MyShow-BugBase(A3),A1 ; our ShowCursor
- Move.L A1,(A0)+ ; replace jShowCursor
- Lea MyShield-BugBase(A3),A1 ; our ShieldCursor
- Move.L A1,(A0) ; replace jShieldCursor
-
- ; start our VBL task
- Lea MyVBLTask-BugBase(A3),A0 ; A0 = MyVBLTask
- Lea MyVBLproc-BugBase(A3),A1 ; A1 = MyVBLproc
- Move.L A1,vblAddr(A0) ; set VBL procedure
- _VInstall ; (A0/VBLTaskPtr:QElemPtr):D0\OSErr
- Feature
- OpenExit
- MoveM.L (A7)+,A3-A5/D7 ; restore registers
- Move.W #OpenErr,D0 ; return an error (we're not open)
- Rts
-
- ;-refs - Open
-
- com_2 Push #15 ; give a beep!
- _SysBeep ; (duration:INTEGER)
- Bra OpenExit
-
- ; Let's kill a bug!
- KillBug
- Move.L jHideCursor,A3 ; A3 = HideCursor routine
- CmpI.L #'BUG ',BugBase-MyHide(A3) ; check signature
- Bne Feature ; branch if not a bug
-
- Lea MyVBLProc-MyHide(A3),A0 ; start of static stuff
- Lea MyVBLProc,A1 ; compare to our copy
- Move.W #StaticSize-1,D0 ; bytes to check
- @0 CmpM.B (A0)+,(A1)+ ; compare
- Bne Feature ; exit if not our bug
- DBra D0,@0
-
- ; It looks like one of our bugs. Kill it.
- Lea MyVBLTask-MyHide(A3),A0 ; our task pointer
- _VRemove ; stop the bug!
- Bne com_2 ; exit if error
-
- _HideCursor ; Hides bugs too!
-
- ; Restore the old cursor routines
- Lea oldHide-MyHide(A3),A0 ; saved routine pointers
- Lea jHideCursor,A1 ; where they came from
- Move.L (A0)+,(A1)+ ; restore old routines
- Move.L (A0)+,(A1)+
- Move.L (A0),(A1)
-
- ; Release the memory
- Lea BugBase-MyHide(A3),A0 ; start of block
- _DisposPtr
-
- _ShowCursor ; restore cursor state
-
- Push #5 ; give a beep
- _SysBeep ; (duration:INTEGER)
- Move.L #10,A0 ; take a break
- _Delay
-
- BTst.L #cmdKey,D7 ; kill all bugs?
- Bne KillBug ; Yes!
-
- Bra OpenExit ; else exit
-
-
- Close MoveQ #0,D0
- Rts
-