home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-04-10 | 40.1 KB | 1,628 lines |
- ;-----------------------------------------------------------------------------
- ; Tetris © Copyright 1990 Software Alchemy of Anselm Hook All Rights Reserved
- ; V1.0 18-jan-89 Code generated by Anselm Hook using CED, Aztek and Transform
- ;-----------------------------------------------------------------------------
-
- include 'tetris.i'
-
- public _main ; workbench support!
- public AmigaJunk
-
- ;***************************************************************************
- ;***************************************************************************
- ;***************************************************************************
- ;***************************************************************************
- ;*
- ;* This Amiga Port of Tetris is a public domain program which I am
- ;* releasing in source code format as a tutorial on assembly
- ;* language programming. It is moderately accurate to the original
- ;* product, featuring multiple players, beveled tiles, different
- ;* levels and audio. Has useful code on a software PAL/NTSC switch,
- ;* interleaved-blitter, coppers, midi based music & raw serial i/o,
- ;* CIAA,CIAB timer control, keyboard handler + extensive greetings also.
- ;* Does 0 Dimensional Tetris, I'm not sure how else to describe it!
- ;* Andy Hook
- ;*
- ;***************************************************************************
-
- ; I use the vertical beam for timing in two places, this will not work if
- ; you have light pen latch set for god knows what reason - Andy.
-
- ; Note that the music score is a direct dump of the Yamaha Demo mode, I
- ; couldn't find any copyright on this data dump, and although the song itself
- ; is uncopyrighted, there might be some cause for concern - Andy.
-
- ; The musical instruments you hear were graciously donated by Kevin Stratton.
- ; Kevin Stratton is the author of the fantastic music and Sound-FX in Vortex.
-
- ; I must also thank Mark Vange for teaching me about MIDI.
-
- ; Software pal switch is poke #32,$dff1dc for those who can't wait.
- ; As shown to me by David Black III coder and integrator extraordinare.
-
- ; Note: I've decided that the technique I used here for multitasking the
- ; players was somewhat inefficient. A better way to do it would be to have
- ; a true interupt driven multitasking exec. Unfortunately that would be
- ; way too slow for this type of application.
-
- SOUND_ROW equ 14*16
- SOUND_LEVEL equ 10*16
- SOUND_PIECE equ 12*16
- SOUND_RAISER equ 9*16
-
- ;
- ; Revision History:
- ; Dec 29 1989 - Played Arcade Game today, made mock outline.
- ; Jan 1 1990 - Wrote MachineTakeover(), ColorFader()
- ; ContinueDraw(), KeyboardInterupt()
- ; SetupVideo(), CopperList:
- ; Jan 2-7 1990 - Fleshed out game logic
- ; Jan 8 1990 - Wrote SoundEngine(); PrintText();
- ; Jan 12 1990 - Revamped block format for PatchCutLine();
- ; Jan 15 1990 - Wrote Multitasking Collapsed Line Flasher.
- ; Jan 16 1990 - Wrote header text, put in AllocMem();
- ; Demonstrated Beta at AMUC General Meeting
- ; Jan 18 1990 - Raisers(); Inter-level-delay
- ; Done.
- ; (but wait...even more goodies ;-)
- ; Jan 29 1990 - Added Simple MusicEngine() + SoundLoader();
- ;
- ; (Bien Gott Mr. Fish is up to #308!!! mama mia)
- ;
- ; Variables is used as an index to Tetris variables, this allows
- ; a pc-relative destination, which the 68000 instruction set doesn't
- ; support naturally. The cost is one permanently allocated register.
- ;
-
-
- Variables ; Variables *must* be first
- Tetris
- bra AmigaJunk
- _main bsr SaveZero
- lea BaseSeed(pc),a0 ; (randomize the seed)
- move.l $dff006,(a0)
- bsr CheckCompilerFailure ; See if Aztek had problems
- bne.s Exit
- bsr AllocatePieces ; get some RAM for graphics
- beq.s Exit
- bsr JustPlayIt ; Start muzak.
- bra TetrisSuccess
-
- TetrisExit
- bsr StopTheMusic
- Exit2 bsr FreePieces
- Exit bsr RestoreZero
- moveq #1,d0
- move.l d0,d1
- rts
-
- TetrisSuccess
- bsr GetTopaz ; Find System Font
- bsr MachineTakeover ; Borrow Amiga for a while
- bsr TetrisSetup ; A5 = Variables, setup view
- bsr MakeMulu110 ; Make Blit Mulu Table
- bsr UnpackPieces ; Colorize Tetris Images
- bsr ResolveDetails ; Make Images look connectable
- bsr DoIntro ; (instructions)
- bsr SayName ; (Whoops Almost forgot!)
- bsr SuperDisplay ; Show all player play fields
-
- ;
- ; Tetris Main Loop, calls all players in turn...
- ; A5 = Pointer to Base of Variables
- ;
- MainLoop ; MAIN LOOP
- bsr WaitFrame ; Syncronize to screen refresh
- bsr WatchInput ; Always watch for input
-
- lea SupervisorPlayerList(pc),a0
- 1$ move.l (a0)+,d0 ; D0 = Next Player or -1
- bmi.s MainLoop
- move.l a0,-(a7) ; (save)
- lea (a5,d0.l),a4 ; A4 = Player One Variables
- bsr PlayPlayer ; Play game with A4 Variables
- move.l (a7)+,a0
- bra.s 1$
-
-
- ;
- ; Setup screen display for all supplied players
- ;
- SuperDisplay
- lea SupervisorPlayerList(pc),a0
- SuperDisplay100
- move.l (a0)+,d0 ; D0 = Next Player or -1
- bmi.s SuperDisplay900
- move.l a0,-(a7)
- lea (a5,d0.l),a4 ; A4 = Player #
- lea PlayFieldOutline(pc),a3 ; A3 = Draws a big empty box
- move.w PlayerArea(a4),d5 ; D5 = Player's area
- bsr RenderLines ; (Draws big empty rectangle)
- bsr DumpScore
- move.l (a7)+,a0
- bra.s SuperDisplay100
- SuperDisplay900
- rts
-
- ;
- ; Find level of any other living players, return such for this player
- ; There may be a problem if all other players are inactive, but
- ; I don't think that should be possible.
- ;
- SuperScan
- moveq #0,d0
- lea SupervisorPlayerList(pc),a0
- 1$ move.l (a0)+,d1 ; D0 = Next Player or -1
- bmi.s 2$
- lea (a5,d1.l),a1 ; A4 = Player #
- cmp.l a1,a4 ; don't scan myself
- beq.s 1$
- tst.w PlayerStats(a1)
- beq.s 1$
- move.b PlayerStats+2(a1),d0 ; use public level
- subq.b #1,d0
- bpl.s 2$
- moveq #0,d0
- 2$ rts
-
- ;
- ; SuperWait Routine is called by a player wishing to advance levels.
- ; Scan for no other active players, when no active players
- ; stop the music, have a delay loop, start the music, continue,
- ; also change the seed at this time.
- ;
- ; You can join in a game at any point, but you can't advance to the
- ; next level till all other players are done.
- ;
- SuperWait
- lea SupervisorPlayerList(pc),a0
- 1$ move.l (a0)+,d1 ; D0 = Next Player or -1
- bmi.s SuperWait200
- lea (a5,d1.l),a1 ; A4 = Player #
- cmp.l a1,a4 ; don't scan myself
- beq.s 1$
- cmp.w #12,PlayerStats(a1) ; If Players Active then fail
- bcs.s 1$
- 2$ moveq #-1,d0 ; failure
- rts
-
- SuperWait200
- bsr MusicEnginePause
-
- move.w #3*60,d0 ; 2 Second Delay at 60 Hz
- 1$ cmp.b #30,$6(a6)
- bne.s 1$
- 2$ cmp.b #20,$6(a6)
- bne.s 2$
- dbf d0,1$
-
- lea speed(pc),a0 ; Allow Speed 24-18
- move.b (a0),d0
- subq.b #1,d0
- cmp.b #24,d0
- bcs.s 3$
- move.b #24,d0
- 3$ cmp.b #18,d0
- bcc.s 4$
- move.b #17,d0
- 4$ move.b d0,(a0)
- bsr MusicEngineUnPause
-
- move.l BaseSeed(pc),d0
- mulu RndSeed(a4),d0
- move.l d0,BaseSeed(a5) ; Randomize the shared seed!
- moveq #1,d0 ; Success
- rts
-
- SuperSearch
- lea SupervisorPlayerList(pc),a0
- 1$ move.l (a0)+,d1 ; D0 = Next Player or -1
- bmi.s 3$
- lea (a5,d1.l),a1 ; A4 = Player #
- cmp.l a1,a4 ; don't scan myself
- beq.s 1$
- tst.w PlayerStats(a1)
- beq.s 1$
- 2$ moveq #-1,d0 ; failure
- rts
- 3$ moveq #1,d0
- rts
-
- ;
- ; If any other players alive then return, else start music for everybody.
- ; Start up any variables too while I'm at it...
- ;
- SuperMusic
- bsr SuperSearch ; -1 = others alive
- bmi.s 1$
- bsr SuperVariables
- move.b speed(pc),d0
- bsr MusicEngineUnPause
- moveq #0,d0
- 1$ rts
-
- ;
- ; If any other players alive return, else stop music for everybody.
- ;
- SuperUnMusic
- bsr SuperSearch ; -1 = others alive
- bmi.s 1$
- bsr MusicEnginePause
- moveq #0,d0
- 1$ rts
-
-
- ;
- ; Setup System Public Variables, start of new game.
- ; Scramble the seed even more!!!! (arg!)
- ;
- SuperVariables
- lea speed(pc),a0
- move.b #24,(a0)
- move.l BaseSeed(pc),d0
- mulu #47,d0
- move.l d0,BaseSeed(a5)
- rts
-
- speed: dc.b 24,0
-
- SupervisorPlayerList
- dc.l PlayerOneStart,PlayerTwoStart,-1
-
- ;-----------------------------------------------------------------------------
-
-
- ;
- ; Support any player whose variable pointer is passed in A4
- ;
- PlayPlayer
- move.w PlayerStats(a4),d0
- jmp PlayArbitration(pc,d0.w)
- nop
- PlayArbitration
- bra.l PlayerDead ; 0 Just plain dead
- bra.l PlayerWaiting ; 4 Wait for others to catch up
- bra.l PlayerNewLevel ; 8 Setting up new level
- bra.l PlayerPlaying ; 12 In process of playing
- bra.l PlayerEndLevel ; 16 Doing end of level
- bra.l PlayerEndGame ; 20 Doing High Score (if any)
- bra.l PlayerCheckLine ; 24
- bra.l PlayerLine ; 28 Special Collapse Line Mode
-
-
-
- return rts
- PlayerDead
- move.w PlayerPort+2(a4),d0 ; Which port?
- move.b $bfe001,d1 ; Amiga port Button Hardware
- and.b d0,d1 ; User Want to play?
- bne.s return
- bsr SuperMusic
- bra PlayerStart ; User selected a game!
- PlayerWaiting
- bsr SuperWait ; Any other players "ingame"
- bmi.s return ; (wait till they aren't)
- move.w #8,PlayerStats(a4) ; Goto New Level Mode
- rts
- PlayerNewLevel
- bsr GenerateLevel ; Setup Next Level
- PlayerPlaying
- bsr Raisers
- bsr BlockHandle ; Get Input, Update Block X,Y
- bra MoveBlock ; Move Block, Handle Hits
- PlayerEndLevel
- move.w #16,PlayerStats(a4) ; (set myself)
- move.w #4,PlayerStats(a4) ; Goto Wait for others mode
- rts
- PlayerEndGame
- move.w #20,PlayerStats(a4) ; (set myself)
- move.w #0,PlayerStats(a4) ; Set "just plain dead" mode
- bra SuperUnMusic
-
- ;
- ; Collapse any finished lines, See if won or died, setup next piece.
- ;
- NextPiece
- move.w PlayerArea2(a4),d0
- add.w #4,d0
- cmp.b BlockPos+6(a4),d0 ; Stopped to High? (Game Over)
- bcc.s PlayerEndGame
-
- move.l PlayerXY(a4),BlockPos(a4) ; Start New Block at Top
- bsr rnd ; D0 = Random(0-55)
- and.w #63-7,d0 ; Get (0-6) (*4*2)
-
- ;
- ; See next piece please
- ;
- move.w d0,-(a7)
- movem.w PlayerArea2(a4),d0/d1 ; d1=x,d0=y
- add.w #2,d1
- subq.w #4,d0
- bsr Erase
- move.l RndSeed(a4),-(a7)
- bsr rnd
- move.l (a7)+,RndSeed(a4)
- and.w #63-7,d0 ; Get (0-6) (*4*2)
- move.w d0,BlockID(a4)
- moveq #0,d0
- move.l d0,d1
- movem.w PlayerArea2(a4),d0/d1 ; d1=x,d0=y
- add.w #2,d1
- subq.w #4,d0
- clr.l BlitRepairAddress(a4) ; (No predecessor)
- bsr DrawBlockAt
- move.w (a7)+,d0
-
- clr.l BlitRepairAddress(a4) ; (No predecessor)
- clr.b RotateFlag(a4) ; No special rotate state
- move.w d0,BlockID(a4) ; Block # of default orient
- ;
- ; Generalized Checkline routine, checks every single
- ; screen line for possible completion.
- ;
- PlayerCheckLine
- lea TetrisByteMap(pc),a3 ; a3 = Player Space
- add.w PlayerArea(a4),a3 ; Where Am I?
- add.w #1,a3 ; Get active region
- move.l a3,a2 ; a2 = Current Line #
- moveq #0,d5
- moveq #RECT_Y-1,d7 ; Check tall
- 3$ moveq #RECT_X-1,d6 ; Check across
- move.l a2,a1 ; a1 = Current Line
- 2$ tst.b (a1)+ ; Any Holes?
- beq.s 4$ ; Empty spot here, skip...
- dbf d6,2$ ; check rest of line
- bra FoundLine
- 4$ add.w #44,a2 ; Next Line
- dbf d7,3$
-
- move.w #12,PlayerStats(a4) ; Return to normal mode
-
- tst.b PlayerStats+3(a4) ; Any rows left to solve?
- bpl.s 5$
- move.w #SOUND_LEVEL,d0 ; End Level triumphant noise
- bsr SoundPlay
- bra PlayerEndLevel ; Oh my God!!! I finished it..
- 5$ rts
-
-
-
-
- ;
- ; Start a brand new player game
- ;
- PlayerStart
- move.l #'0000',d0 ; Wipe Score on New Game
- move.l d0,ScoreText+4(a4)
- move.l d0,ScoreText+8(a4)
- bsr SuperScan ; D1.b = Level to start on
- move.b d0,PlayerStats+2(a4) ; use public level
- move.w #8,PlayerStats(a4) ; Set Generate Mode (no wait)
- rts
-
-
- GenerateLevel
- add.b #1,PlayerStats+2(a4) ; Level += 1;
-
- move.b PlayerStats+2(a4),d0 ; Algorithm for # of Rows req.
- lsl.b #1,d0
- cmp.b #20,d0
- bcs.s 0$
- move.b #20,d0
- 0$ cmp.b #7,d0
- bcc.s 1$
- move.b #7,d0
- 1$ move.b d0,PlayerStats+3(a4)
-
- move.l #$00400020,BlockSpeed(a4)
- move.b PlayerStats+2(a4),d0 ; Algorithm for Speed Per Lev
- cmp.b #15,d0
- bcs.s 2$
- move.b #15,d0
- 2$ lsl.b #3,d0
- add.b #$10,d0
- move.b d0,BlockSpeed+3(a4) ; Speed up per level
-
- move.l #$00000080,Counter(a4)
- lea PlayFieldClear(pc),a3 ; A3 = Draws a big empty box
- move.w PlayerArea(a4),d5 ; D5 = Player's area
- bsr RenderLines ; (Draws big empty rectangle)
- bsr DumpScore
- bsr Difference ; Make Unique Backdrop
- move.w #-1,BlockPos+6(a4) ; Force Very Low First Entry!
- move.l BaseSeed(pc),d0 ; Get shared seed for game
- move.w PlayerStats+2(a4),d1 ; Modify according to level
- mulu d1,d0 ;
- move.l d0,RndSeed(a4) ; My private seed per piece
- bra NextPiece ; Setup Next Piece
-
-
-
- ;
- ; Generate each levels unique backdrop, enemies ect
- ;
-
- Difference
- moveq #0,d0
- move.b PlayerStats+2(a4),d0
- and.b #15,d0 ; 16 different levels...
- lea TetrisLevels(pc),a3
- mulu #5*2,d0
- add.w d0,a3
- move.b 1(a3),CollapseJunk+2(a4) ; (stash mode here)
-
- moveq #0,d4
- move.w PlayerArea(a4),d4 ; D4 = Player's area
- add.l #(RECT_Y-5)*44+1,d4 ; get to bottom
-
- moveq #5,d2
- moveq #5-1,d7
- 0$ move.w (a3)+,d3
- moveq #RECT_X-1,d6
- 1$ add.w d3,d3
- bcc.s 2$
- add.w #8*4,d2
- and.w #8*4*4-1,d2
- bsr PokeScreen
- 2$ add.w #1,d4
- dbf d6,1$
- add.w #44-RECT_X,d4
- dbf d7,0$
- rts
-
- ;
- ; "Physically" Move the Block, and handle any collisions with wall ect.
- ;
- MoveBlock
- bsr GetBlockPos ; D4 = Block Pos
- move.w BlockID(a4),d2 ; D2 = Pointer to Block Image
- bsr TestCollision ; Time to stop?
- bne.s BlockHit
- move.l BlockPos(a4),BlockPos+4(a4) ; Remember Pos for Un-Move
- bra DrawBlock ; Visibly Move Block
-
- BlockHit
- move.b BlockPos+4(a4),d0 ; Detect Sideways Moves
- cmp.b BlockPos(a4),d0 ; Compare Old X to new X
- bne.s MoveItWall ; Moved Sideways? XO != XN
- move.w #SOUND_PIECE,d0 ; Make "Click" Noise
- bsr SoundPlay
- bsr GetBlockOldPos ; Where is block
- move.w BlockID(a4),d2 ; D2 = Block to byte screen
- bsr DrawBlockMem ; Write to byte screen
- bra NextPiece
-
- MoveItWall
- move.w BlockPos+4(a4),BlockPos(a4) ; Discard XNew sideways move
- rts
-
-
-
-
- ;
- ; Handle users input, move block as requested, and also move it down.
- ;
- BlockHandle
-
- move.w BlockSpeed+2(a4),d0 ; Get Suggested Speed Y
- add.w d0,BlockPos+2(a4) ; Add Speed to Position Y
- bsr ReadJoy ; D1 = Joystick %LU------RD
- move.w BlockSpeed+2(a4),d0 ; Get Y Speed
- lsr.w #1,d1 ; D1 = %LU-----R
- bcc.s BlockHandle100
- add.w d0,d0
- add.w d0,BlockPos+2(a4)
- BlockHandle100
- move.b BlockPos+6(a4),d0 ; Disallow Angle Movements
- cmp.b BlockPos+2(a4),d0
- bne.s BlockHandle500
- move.w BlockSpeed(a4),d0 ; Get X Speed
- lsr.w #1,d1 ; D1 = %LU------
- bcs.s BlockHandle400
- add.b d1,d1 ; D1 = %U-------
- bcc.s BlockHandle500
- neg.w d0
- BlockHandle400
- add.w d0,BlockPos(a4)
- BlockHandle500
-
- ;Check for block rotate:
- ; Done after move because when block stops the image is not redrawn
- ; and if block rotated just before stop it would appear in previous
- ; orientation. Wheras rotate never occurs before impending collisions.
-
- move.b $bfe001,d0 ; Test Left Port Button
- move.w PlayerPort+2(a4),d1 ; Get Amiga Hardware Bit #
- and.b d1,d0
- cmp.b LastButton(a4),d0 ; Any change in button state?
- beq.s BlockHandle900
- move.b d0,LastButton(a4) ; Accept only Button Down
- bne.s BlockHandle900
-
- move.w BlockID(a4),d5 ; Attempt Rotation
- move.w d5,d1
- add.w #2,d1 ; Get Next Rotation of Color
- and.w #6,d1 ; Allow rotate only
- and.w #$f8,d5 ; Clean
- or.w d1,d5 ; D5 = New Block Rotation
- bsr GetBlockPos ; D4 = Block ByteMap pos
- move.w d5,d2 ; D2 = Rotation to check out
- bsr TestCollision
- bne.s BlockHandle900 ; 0 = Successful rotation
- move.w d5,BlockID(a4) ; Rotation was possible
- BlockHandle900
- rts
-
-
- dc.b "On dreamless night"
- dc.b "Ere the moon does rise"
- dc.b "Laughlight Shadows"
- dc.b "Across dreamless eyes,"
-
-
- ;
- ; Found Line to Kill!!!
- ;
- FoundLine
- move.w #28,PlayerStats(a4) ; Set Collapse Line Mode!!!
- move.w #$0805,CollapseJunk(a4) ; Some stuff for collapse
- move.l a3,CollapseJunk+4(a4) ; A3 = Top of Field
- move.l a2,CollapseJunk+8(a4) ; A2 = Line Addr to Cut
- sub.w #RECT_Y-1,d7
- neg.w d7
- move.w d7,CollapseJunk+12(a4) ; D7 = Line # to cut
- move.w d7,d0
- subq.w #1,d0
- bsr DrawLine ; (Draw Patch)
- move.w d7,d0
- addq.w #1,d0
- bsr DrawLine ; (Draw Patch if any)
- move.w #SOUND_ROW,d0 ; Make "Line Eat" Noise
- bra SoundPlay
-
-
-
- ;
- ; Separated to be multitasking with other players
- ;
- PlayerLine
- move.l CollapseJunk+4(a4),a3 ; A3 = Top of Field
- move.l CollapseJunk+8(a4),a2 ; A2 = Line to Cut
- move.w CollapseJunk+12(a4),d7 ; D7 = Line # to cut
-
- sub.b #1,CollapseJunk(a4)
- move.b CollapseJunk(a4),d0
- beq.s PlayerLine100
- bsr GargleBlast
- move.w d7,d0 ; D0 = Line to draw
- bra DrawLine
- rts
-
- PlayerLine100
- move.w #24,PlayerStats(a4) ; Be in PlayerLineDone Mode
- bsr CollapseLine ; Kill Line in Byte Map
- sub.b #1,PlayerStats+3(a4) ; Decrement Required Count
- bsr LineScore
- bra RedrawPlayField
- rts
-
- GargleBlast
- move.l a2,a0 ; A2 = Line to flash
- move.b CollapseJunk+3(a4),d0 ; Random # to flash of
- or.b #5,d0 ; (block)
- add.b #8*4,d0
- move.b d0,CollapseJunk+3(a4) ; Random # to flash of
- moveq #RECT_X-1,d6 ; Flash Line Prettily
- 1$ add.b #8*4,d0
- and.b #8*4*4-1,d0
- move.b d0,(a0)+
- dbf d6,1$
- rts
-
-
- ;How to write Collapse Line:
- ; -Collapse line will just set a new mode, that mode will flash the
- ; line and collapse it itself, it will also add the score and count
- ; required, finally it will go back to itself to check for more...
- ; score count, single double triple tetris is computed at this time.
- ;
-
-
- ;
- ; Collapse line on byte map
- ;
- CollapseLine
- bsr PatchCutLine ; Breakup tiles, Pass A2
-
- ; a3 = Top of Field
- ; a2 = Current Line to Kill
- move.l a2,a1 ; A1 = Line to Collapse
- CollapseLine100
- cmp.l a3,a1 ; Is at top?
- beq.s CollapseLine900
- move.w #RECT_X-1,d2 ; Do one Line
- 1$ move.b -44(a1),(a1)+ ; Copy Down one line
- dbf d2,1$
- sub.l #RECT_X+44,a1 ; Goto Previous Line
- bra.s CollapseLine100
- CollapseLine900
- rts
-
-
- PatchCutLine
- ; A2 = Current Line
- lea -44(a2),a1 ; A1 = Do Line above
- move.w #$ff-1,d3 ; D3 = Cut Bottom off
- bsr PatchCut100
- lea 44(a2),a1 ; A1 = Do Line below
- PatchThisLine
- move.w #$ff-4,d3 ; D3 = Cut top off
- PatchCut100
- move.w #RECT_X-1,d2 ; Do one Line
- 1$ move.b (a1),d0 ; READ
- beq.s 2$
- move.b d0,d1 ; (save)
- and.w #31,d0
- move.b UnResolveType(pc,d0.w),d0 ; Get Originator type
- and.b d3,d0 ; Cut one side
- move.b ResolveType2(pc,d0.w),d0 ; Get proper back
- and.b #$e0,d1 ; Mask off old walls info
- or.b d1,d0 ; Insert new walls info
- 2$ move.b d0,(a1)+ ; WRITE
- dbf d2,1$
- rts
-
- ;
- ; Convert back to quirky resolve type format
- ;
- UnResolveType dc.b 15,9, 5,4,13,0,0,0
- dc.b 0,3,10,8,11,0,0,0
- dc.b 0,6, 0,1, 7,0,0,0
- dc.b 0,12,0,2,14,0,0,0
- ;
- ; A handy copy of the ResolveType Table...
- ;
- ResolveType2 dc.b 5,2*8+3,3*8+3,8+1,3,2,2*8+1,2*8+4
- dc.b 8+3,1,8+2,8+4,3*8+1,4,3*8+4,0
-
-
-
- ;
- ; Every x pieces raise up screen one.
- ;
- Raisers
- move.b CollapseJunk+2(a4),d0
- btst #1,d0
- beq.s RaisersStop
- add.w #1,Counter(a4) ; Increment player counter
- move.w Counter(a4),d0
- cmp.w Counter+2(a4),d0
- beq.s RaisersGo
- RaisersStop
- rts
- RaisersGo
- add.w #$200,d0 ; Till next time
- move.w d0,Counter+2(a4)
-
- move.w PlayerArea2(a4),d0 ; Is block below here?
- addq.w #4,d0
- cmp.b BlockPos+6(a4),d0
- bcc.s RaisersStop
-
- move.l d0,-(a7) ; Raiser Noise
- move.l #SOUND_RAISER,d0
- bsr SoundPlay
- move.l (a7)+,d0
-
- sub.b #1,BlockPos+6(a4) ; Move Real Block Up!
- move.b BlockPos+6(a4),BlockPos+2(a4)
-
- bsr RaisersDraw
-
- lea TetrisByteMap(pc),a3
- add.w PlayerArea(a4),a3
- add.w #1,a3 ; A3 = top of player region
- move.l a3,a2
- ; Copy ByteMap up one line
- move.w #RECT_Y-2,d3 ; (don't do last line)
- 0$ move.w #RECT_X-1,d2
- 1$ move.b 44(a2),(a2)+
- dbf d2,1$
- add.w #44-RECT_X,a2
- dbf d3,0$
-
- bsr GargleBlast ; Write random pattern once
-
- move.b BlockPos(a4),d0 ; Force hole in pattern
- sub.b #RECT_X,d0
- neg.b d0
- cmp.b #RECT_X,d0
- bcs.s 3$
- and.w #7,d0
- 3$ and.w #15,d0
- ;eor.b #%111,d0 ; randomize
- move.b #0,(a2,d0.w)
-
- move.l a3,a1 ; Patch top line
- bsr PatchThisLine
-
- moveq #0,d0
- bsr DrawLine ; Draw Top (was patched)
- moveq #RECT_Y-2,d0
- bsr DrawLine ; hack, fix any teat glitch.
- moveq #RECT_Y-1,d0
- bra DrawLine ; Draw Bot (was gargleblasted)
-
-
- RedrawPlayField
- moveq #0,d7
- 1$ move.l d7,d0 ; D0 = Line # to Draw
- bsr DrawLine
- add.w #1,d7
- cmp.w #RECT_Y+1,d7 ; (over-do to get teats)
- bne.s 1$
- rts
-
-
- GetBlockPos
- moveq #0,d4
- move.b BlockPos+2(a4),d4 ; Y byte # pos of block
- mulu #44,d4 ; get raw
- moveq #0,d1
- move.b BlockPos(a4),d1 ; X byte # pos of block
- add.w d1,d4
- rts
-
-
- GetBlockOldPos
- moveq #0,d4
- move.b BlockPos+6(a4),d4 ; Y byte # pos of block
- mulu #44,d4 ; get raw
- moveq #0,d1
- move.b BlockPos+4(a4),d1 ; X byte # pos of block
- add.w d1,d4
- rts
-
-
- TestCollision
- ; D4 = Screen Pos of block
- lea TetrisShapes(pc),a0
- move.w (a0,d2.w),d2 ; D2 = Block Data
- lea TetrisByteMap(pc),a0 ; A0 = Byte Mapped Screen
- add.w d4,a0
- moveq #4-1,d0 ; Examine Each Block Byte
- TestIt200
- moveq #4-1,d1
- TestIt300
- add.w d2,d2 ; (<<BITSHIFT onto Carry Flag)
- bcc.s TestIt500 ; Anything in block here?
- tst.b (a0) ; Coincident with Real World?
- beq.s TestIt500
- moveq #-1,d0 ; Whoops, hit something...
- rts
- TestIt500
- lea 1(a0),a0 ; Next HLine
- dbf d1,TestIt300
- lea 40(a0),a0 ; Next VLine
- dbf d0,TestIt200
- moveq #0,d0
- rts
-
-
-
- DrawBlockMem
- ; D4 = Where to draw
- ; D2 = Block #
- lsl.w #3,d2 ; Get to multiples of 16
- lea TetrisDetails(pc),a1
- lea (a1,d2.w),a1 ; Pointer to Real Block Data
- lea TetrisByteMap(pc),a0 ; A0 = Byte Mapped Screen base
- moveq #4-1,d7 ; Examine Each Block Byte
- 1$ moveq #4-1,d6
- 2$ move.b (a1)+,d2 ; D2 = Data
- beq.s 3$
- move.b d2,(a0,d4.w) ; To Byte Mapped
- 3$ add.w #1,d4 ; Next HLine of render
- dbf d6,2$
- add.w #40,d4 ; Next VLine of render
- dbf d7,1$
- rts
-
-
- ;
- ;
- ; Clear out work area + draw walls ect...
- ; each play zone is 24 deep and 16 wide, centered
- ; ; A3 = Command List
- ;
- RenderLines
- move.w (a3)+,d4 ; D4 = Line Start,End
- bmi RenderLines900 ; Done?
- add.w d5,d4 ; + Offset
- move.w (a3)+,d3 ; D3 = Iterations to perform
- move.w (a3)+,d2 ; D2 = Color (byte graphic #)
- move.b -2(a3),d1 ; D1 = Horiz/Vert/Area?
- bmi.s RenderLinesArea
- beq.s RenderLinesHoriz
- cmp.b #2,d1
- beq.s RenderLinesAngled
- RenderLinesVert
- bsr PokeScreen ; Put D2 at D4 + Show it
- add.w #44,d4
- dbf d3,RenderLinesVert
- bra RenderLines
- RenderLinesAngled
- bsr PokeScreen ; Put D2 at D4 + Show it
- add.w #45,d4
- dbf d3,RenderLinesAngled
- bra RenderLines
- RenderLinesHoriz
- bsr PokeScreen ; Put D2 at A0 + Show it
- addq.w #1,d4
- dbf d3,RenderLinesHoriz
- bra RenderLines
-
- RenderLinesArea
- ; D3 = Horizontal Size to do
- and.b #$7f,d1 ; D1 = Vertical Area to do
- ext.w d1
- move.w d1,d6 ; D6 = Vertical Lines to do
- move.w d3,d7 ; Save Width
- RenderLinesArea100
- bsr PokeScreen
- addq.w #1,d4 ; Next H
- dbf d3,RenderLinesArea100 ; Next H Pos
- move.w d7,d3 ; Reset Horiz Count
- add.w #43,d4 ; Get to next vertical start
- sub.w d3,d4
- dbf d6,RenderLinesArea100
- bra RenderLines
- RenderLines900
- rts
-
- dc.b "A Knight there was"
- dc.b "And that a Noble man"
- dc.b "That fro the time he first bigan"
- dc.b "To Riden out, he loved"
- dc.b "Truthe and Honour"
- dc.b "Justyice and Curteysie."
-
- PokeScreen
- move.w d4,d0 ; Screen Address
- ext.l d0
- divu #44,d0 ; Get vertical lines #
- move.l d0,d1 ; D0 = Vert Byte Pos
- swap d1 ; D1 = Horiz Byte Pos
- bra DrawOne ; Draw one element at D0/D1
-
- EraseByteMap
- lea TetrisByteMap(pc),a0
- move.w #11*29-1,d0 ; Wipe Byte Map
- 1$ clr.l (a0)+
- dbf d0,1$
- rts
-
-
- LineScore
- moveq #5,d2 ; add up new score
- lea ScoreText+4(a4),a0
- moveq #6,d0
- 0$ move.b (a0,d0.w),d1
- add.b d2,d1
- move.b d1,(a0,d0.w)
- cmp.b #$3a,d1
- bcs.s 1$
- sub.b #$39,d1
- and.b #15,d1
- or.b #$30,d1
- move.b d1,(a0,d0.w)
- moveq #1,d2
- dbf d0,0$
- 1$
-
- DumpScore
- lea ScoreText(a4),a0 ; show new score
- move.l GameVideo(pc),a1 ; Dest
- lea 44*4(a1),a1
- bsr PrintText ; Print it!!!
-
- move.b PlayerStats+3(a4),d0
- bpl.s 4$
- moveq #0,d0
- 4$ divu #10,d0 ; Get Decimal...
- or.b #$30,d0
- move.b d0,LayerText+4(a4) ; 10's
- swap d0
- or.b #$30,d0
- move.b d0,LayerText+5(a4) ; 1's
- lea LayerText(a4),a0
- move.l GameVideo(pc),a1
- lea 44(a1),a1
- bsr PrintText
-
- move.b PlayerStats+2(a4),d0
- bpl.s 5$
- moveq #0,d0
- 5$ divu #10,d0 ; Get Decimal...
- or.b #$30,d0
- move.b d0,LevelText+4(a4) ; 10's
- swap d0
- or.b #$30,d0
- move.b d0,LevelText+5(a4) ; 1's
- lea LevelText(a4),a0
- move.l GameVideo(pc),a1
- lea 44*4(a1),a1
- bra PrintText
-
-
- ;---------------------------------------------------------------------
-
- ;
- ; Watch Keyboard, start a player game if requested
- ;
- WatchInput
- moveq #0,d0
- lea KeyEvent(pc),a0 ; Get Key
- move.b (a0),d0
- clr.b (a0) ; Wipe Key from buffer
- cmp.b #'P',d0 ; P to Pause
- beq.s Pause
- cmp.b #$7b,d0 ; ESC == Return to System
- beq MachineReturn
- cmp.b #$11,d0 ; is ESC/F1 or greater?
- bcs.s TetrisHandle900
- cmp.b #$1b,d0 ; is F10 or lesser?
- bcc.s TetrisHandle900
- sub.b #$11,d0
- lsl.b #2,d0 ; Index subroutines
- jmp TetrisInputOptions(pc,d0.w) ; Goto Subroutine
- TetrisHandle900
- rts
-
- Pause lea KeyEvent(pc),a0
- btst #6,$bfe001
- beq.s PauseEnd
- btst #7,$bfe001
- beq.s PauseEnd
- move.b (a0),d0
- cmp.b #$7b,d0 ; ESC == Return to System
- beq MachineReturn
- tst.b d0
- beq.s Pause
- PauseEnd
- clr.b (a0)
- rts
-
- TetrisInputOptions
- bra.l TetrisF1 ; (this wacko thing is
- bra.l TetrisF2 ; due to p c relative code)
- bra.l TetrisF3
- bra.l TetrisF4
- bra.l TetrisF5
- bra.l TetrisF6
- bra.l TetrisF7
- bra.l TetrisF8
- bra.l TetrisF9
- bra.l TetrisFA
- nop ; (stop compiler optimizing)
- TetrisF1
- TetrisF2
- TetrisF3
- TetrisF4
- TetrisF5
- TetrisF6
- TetrisF7
- TetrisF8
- TetrisF9
- TetrisFA
- rts
-
- ;
- ; Generate detailed tile face-pieces for Tetris Objects
- ; The first pass merely sets down used positions, the second
- ; pass actually sets up proper tile faces
- ;
-
- ResolveDetails
- bsr ResolveDetails2
- ResolveDetails2
- lea TetrisShapes(pc),a0 ; A0 = Simple Tile Shape Data
- lea TetrisDetails(pc),a1 ; A1 = Detailed Tiles (to be)
- moveq #0,d7 ; Do 7 Sets of 4 Tiles
- 0$ bsr ResolveSet
- add.w #32,d7 ; Every 4th tile has new color
- cmp.w #32*7,d7 ; End of color spectrum?
- bne.s 0$
- rts
-
-
- ResolveSet
- moveq #4-1,d6 ; Do 4 tiles (1 set of rots)
- 1$ move.w (a0)+,d5 ; D5 = One Tile
- bsr ResolveOne
- dbf d6,1$
- rts
-
-
- ResolveOne
- moveq #16-1,d4 ; Bitscan 16 bits of one tile
- 2$ add.w d5,d5 ; Active bit here?
- bcc.s 3$
- bsr DecideType ; D0 = Decide what connectable
- move.b d0,(a1) ; Store Connection to Detailed
- 3$ lea 1(a1),a1 ; Next Dest
- dbf d4,2$
- rts
-
- DecideType
- move.w d4,d1 ; D1 = Position in array
- sub.w #15,d1
- neg.w d1
- clr.w d0 ; D0 = Faces Active Bits
-
- cmp.b #12,d1 ; On bottom row?
- bpl.s 1$
- tst.b 4(a1) ; Anything below face?
- beq.s 1$
- or.b #1,d0
-
- 1$ cmp.b #4,d1 ; On top row?
- bmi.s 2$
- tst.b -4(a1) ; Above face?
- beq.s 2$
- or.b #4,d0
-
- 2$ bclr #2,d1 ; At Left Edge?
- tst.b d1
- beq.s 3$
- tst.b -1(a1) ; Left of face?
- beq.s 3$
- or.b #2,d0
- ; (no pieces are like x00x)
- 3$ tst.b 1(a1) ; Right of face?
- beq.s 4$
- or.b #8,d0
- 4$
-
- ;
- ; Convert from my random drawn format to logical format also.
- ;
- and.w #$000f,d0
- move.b ResolveType(pc,d0.w),d0
- or.b d7,d0 ; What color is face on?
- 5$ rts
- ; format: something below / to left / to top / to right
-
- ResolveType dc.b 5,2*8+3,3*8+3,8+1,3,2,2*8+1,2*8+4
- dc.b 8+3,1,8+2,8+4,3*8+1,4,3*8+4,0
-
-
- ;*****************************************************************************
- ;*****************************************************************************
- ;
- ; Returns D0 within range of 0-x, This rnd function is from MANX
-
- rnd
- move.l RndSeed(a4),d0
- add.l d0,d0
- bhi.L 3$
- eori.l #$1d872b41,d0
- 3$ move.l d0,RndSeed(a4)
- andi.l #$0000ffff,d0
- divu #7*4*2,d0 ; Range = 0 to 7 ((*4*2)-1)
- swap d0
- rts
-
-
-
- ; soon aztek, soon....
-
- CheckCompilerFailure
- lea Variables(pc),a5 ; A5 = Tetris Variables
- lea TetrisByteMap(a5),a0
- lea TetrisByteMap(pc),a1
- cmp.l a0,a1
- bne.s AztekFailedAsUsual
- lea PlayerTwoStart(a5),a4
- move.l PlayerPort(a4),d0
- cmp.l #$000a0040,d0
- bne.s AztekFailedAsUsual
- moveq #0,d0 ; Compiler managed to compile
- rts
- AztekFailedAsUsual
- moveq #-1,d0
- rts
-
-
-
-
- ;
- ; This is for debugging purposes only.
- ;
- SaveZero
- lea $60,a0 ; save zero page against use
- lea zeropage(pc),a1
- Cheat moveq #12-1,d0
- 1$ move.l (a0)+,(a1)+
- dbf d0,1$
- rts
- RestoreZero
- lea $60,a1 ; restore zero page
- lea zeropage(pc),a0
- bra.s Cheat
- zeropage:dcb.l 12,0
-
-
- ;*****************************************************************************
- ;*****************************************************************************
- ;
- ; Initialize and Enter Tetris
- ;
- TetrisSetup
- lea $dff000,a6 ; A6 = Amiga Hardware
- lea Variables(pc),a5 ; A5 = Tetris Variables
- bsr SetupVideo ; Initialize Video
- bra EraseByteMap ; Erase bytemap
-
-
- ;*****************************************************************************
- ;*****************************************************************************
- ; Amiga Hardware System Specific Support & Resources
-
- SetupVideo
- bsr VideoBitPlanes ; Setup Copper Bitplanes
- bsr VideoClear
-
- lea CopperList(pc),a0 ; (copy list to chip alloced)
- move.l GameCopper(pc),a1
- move.l a1,d1
- move.w #130-1,d0 ; (guestimate)
- 1$ move.l (a0)+,(a1)+
- dbf d0,1$
-
- move.l d1,$80(a6) ; Turn on View
- move.w d1,$88(a6)
- move.w #$87c0,$96(a6) ; All DMA On + Blitter Nasty
- move.w #2,$2e(a6) ; Allow Copper Blits
- rts
-
- VideoClear
- move.l GameVideo(pc),a0
- move.w #11*240-1,d0
- 1$ clr.l (a0)+
- clr.l (a0)+
- clr.l (a0)+
- clr.l (a0)+
- clr.l (a0)+
- dbf d0,1$
- rts
-
- ;
- ; **** note this works only once, afterwards I use a copy of this list
- ;
-
- VideoBitPlanes
- move.l ScreenMem(pc),d0 ; D0 = Address for Screen
- move.l d0,d1
- lsr.l #1,d1
- move.l d1,GameVideo2(a5) ; 1/2 Screen for fast blits
- lea CopperPlanes(pc),a0 ; A0 = Copper Plane Op codes
- move.l d0,GameVideo(a5)
- moveq #5-1,d1 ; Setup plane pointers
- 1$ move.w d0,6(a0)
- swap d0
- move.w d0,2(a0)
- swap d0
- add.w #8,a0 ; Next Copper Poke
- add.l #44,d0 ; Next Interleave Start
- dbf d1,1$
- rts
-
- WaitFrame
- cmp.b #$e0,$dff006 ; Wait till past animations
- bne.s WaitFrame
- 1$ cmp.b #$e2,$dff006
- bne.s 1$
- rts
-
-
- ;*****************************************************************************
- ;*****************************************************************************
- ;
- ; Perform an Ultra smooth and efficient Color Fade in or out
- ; Supply A0 = Destination CopperList (pass it -4)
- ; A1 = Source Color Table
- ;
-
- ColorFader
- moveq #0,d4 ; Start Pass on RED
- move.w #48-1,d5 ; Takes 48 Passes to finish
- 3$ bsr WaitFrame ; Syncronize to frame
-
-
- ; lea CopperColors-4(pc),a0 ; A0 = Copper Color Opcodes-4
-
- ; (lets find the list in chip...yawn)
-
- lea CopperColors(pc),a0
- lea CopperList(pc),a1
- sub.l a1,a0
- add.l GameCopper(pc),a0
- subq.w #4,a0 ; (its wants to be -4 of it)
-
-
- ; **** note: the reason I always sub.w #4,address-register is because
- ; the MC68xxx chips always sign extend to longword internally
- ; and its a moderately faster operation, as well as taking less
- ; memory than the sub.l counterpart (sub.b is not-legal by the way).
-
-
-
- lea ColorTable(pc),a1 ; A1 = Color Table to Seek
-
-
- bsr Col200 ; Perform pass of seek
- dbf d5,3$ ; till done
- rts
- Col200 addq.w #4,a0
- move.w (a0),d0
- cmp.w #$ffff,d0 ; End of Copper List?
- beq.s Col500
- cmp.w #$0180,d0 ; Valid Color?
- bmi.s Col200
- cmp.w #$01c0,d0
- bpl.s Col200
- move.w 2(a0),d1 ; Source Color
- moveq #$f,d0 ; R G or B
- lsl.w d4,d0
- move.w (a1)+,d3 ; D3 = Dest Color
- move.w d1,d2
- and.w d0,d3
- and.w d0,d2 ; Mask out Color
- and.w #$111,d0
- cmp.w d3,d2
- beq.s Col400
- bmi.s Col300
- neg.w d0
- Col300 add.w d0,d1
- Col400 move.w d1,2(a0) ; DEST
- bra.s Col200
- Col500 addq.w #4,d4 ; R G or B?
- cmp.w #12,d4
- bne.s Col600
- moveq #0,d4
- Col600 rts
-
-
- ;*****************************************************************************
- ;*****************************************************************************
-
- AllocMem equ -30-168
- FreeMem equ -30-180
-
- piecessize equ 7*(8*4)*(5*2*8) ; #*pieces*rots * dep*wid*het
- memorysize equ 240*44*5+9000+piecessize ; (scn het*wid*dep+snd+pieces)
- memorysize2 equ memorysize + 80*4 ; (copper list too)
-
-
- AllocatePieces
- move.l #memorysize2,d0
- move.l #2,d1
- move.l 4,a6 ; Exec base
- jsr AllocMem(a6)
- tst.l d0 ; D0 = 0 = Failed
- beq.s AllocateMemory900
-
- ; Divvy up the memory
- lea GameCopper(pc),a0
- move.l d0,(a0)
- add.l #130*4,d0
-
- lea ScreenMem(pc),a0
- move.l d0,(a0)
- add.l #240*44*5,d0
-
- ;lea AudioMem(pc),a0 (used proper loader now jan 29 90)
- ;move.l d0,(a0)
- ;add.l #9000,d0
-
- lea PiecesMem(pc),a0
- move.l d0,(a0)
- ; D0 != 0 = Success
- AllocateMemory900
- rts
-
- FreePieces
- move.l 4,a6
- move.l GameCopper(pc),a1
- move.l #memorysize2,d0
- jmp FreeMem(a6)
-
- ;*****************************************************************************
- ;*****************************************************************************
-
- ReadJoy move.w PlayerPort(a4),d0 ; Read Amiga Port Hardware
- move.w (a6,d0.w),d0 ; Amiga Hardware
- and.w #$0303,d0 ; (see hardware ref manual)
- move.w d0,d1
- lsr.w #1,d1
- eor.w d0,d1 ; D0 = %LU------RD
- rts
-
- ;*****************************************************************************
- ;*****************************************************************************
-
- ; When playing with custom registers be careful about $dff02a, because
- ; you can physically damage the Amiga by de-syncronizing the vertical
- ; framing, the same applies for $dff1dc (PAL/NTSC switch) on FAT AGNES ONLY.
-
- MachineTakeover
- move.b #32,$dff1dc ; Goto PAL Mode
-
- move.l 4,a6 ; Exec
- lea library(pc),a1 ; Find Amiga DosLibrary
- jsr -408(a6) ; D0 = Open Graphics Library
-
- lea MachineVariables(pc),a3 ; a3 = Variable Workspace
- move.l d0,a6 ; GraphicsBase
- move.l 38(a6),-(a3) ; Save System Copper Ptr
-
- move.w #3*60,d1 ; Allow Amiga to Cool off
- 9$ cmp.b #$20,$dff006
- bne.s 9$
- 8$ cmp.b #$22,$dff006
- bne.s 8$
- move.w d1,$dff180
- dbf d1,9$
- ;(can't do this: overrides my music)
- ;move.l 4,a6 ; ExecBase
- ;jsr -120(a6) ; Call Disable();
-
- lea $dff000,a6 ; A6 = Amiga Hardware
- move.w $2(a6),-(a3) ; Save DMA Enabled
- move.w $1c(a6),-(a3) ; Save Interupts Enabled
- move.l $68,-(a3) ; Save System Keyboard Handler
- move.l $c,-(a3) ; Trap Guru Meditations
- move.l $10,-(a3) ;
- lea MachineCrash(pc),a0
- move.l a0,$c
- move.l a0,$10
- ;(i decided to be nicer to the system here)
- ;move.w #$7fff,$9a(a6) ; Freeze Interupts
- ;move.w #$7fff,$96(a6) ; Freeze DMA
-
- lea MachineReturn(pc),a0 ; Trap Gurus to my handler
- move.l a0,$10 ;
- move.l a0,$12 ;
- lea KeyboardInterupt(pc),a0 ; A0 = Interupt Handler
- move.l a0,$68 ; Setup My Keyboard Handler
- move.w #$c008,$9a(a6) ; Enable Keyboard Interupts
- lea oldtrap(pc),a0
- move.l $80,(a0)
- lea Supervisor(pc),a0 ; Enter Supervisor Mode
- move.l a0,$80 ; Setup Trap
- move.l (a7)+,a0 ; A0 = Caller
- move.l a7,-(a3) ; Remember User Stack
- trap #0 ; Goto Hardware Trap
- library dc.b "graphics.library",0,0 ; Dos Library Name
- Supervisor
- move.l a7,-(a3) ; Remember Supervisor Stack
- jmp (a0) ; Return to Caller
- ;-----------------------------------------------------------------------------
-
- MachineCrash
- lea Variables(pc),a0
- move.l a0,$7ff00 ; Store Crash to ABS place
- move.l 2(a7),$7ff04
- move.l 6(a7),$7ff08
- move.l 10(a7),$7ff0c
-
- MachineReturn
- btst #14,$02(a6)
- 1$ btst #14,$02(a6) ; Blitter done?
- bne.s 1$
-
- move.b #2,$1dc(a6) ; Exit PAL, goto NTSC Mode
- ;move.w #$7fff,$96(a6) ; Stop all DMA
- ;move.w #$7fff,$9a(a6) ; Stop all Interupts
-
- lea Supervisor2(pc),a0 ; Goto supervisor (again)
- move.l a0,$80 ; Setup Trap
- trap #0 ; Goto Hardware Trap
- Supervisor2
- move.l oldtrap(pc),$80
-
- lea MachineVariables2(pc),a3 ; a3 = Machine Variables
- move.l (a3)+,a7 ; Restore Supervisor stack
- move.w #0,sr ; Exit Supervisor Mode
- move.l (a3)+,a7 ; Restore User stack
-
- move.l (a3)+,$10 ; Restore Guru ""handlers""
- move.l (a3)+,$c ;
- move.l (a3)+,$68 ; Replace Sys Keyboard Handler
- move.l (a3)+,d1 ; System DMA bits
-
- lea $dff000,a6 ; A6 = Hardware
- move.w #0,$2e(a6) ; Turn Off Copper Blits
- move.l (a3),$80(a6) ; Restore System Copper
- move.w d0,$88(a6) ; Forceload Copper
-
- ; Note the super-fat agnes is using some undefined DMA channels, I
- ; have found that I can no longer safely turn off all the DMA, so I just
- ; try to manage what I can glean.
-
- or.w #$8200,d1 ; Set Enable DMA Bit
- move.w #$1ff,$96(a6)
- move.w d1,$96(a6) ; Reenable System DMA
-
- swap d1 ; System Interupt Bits
- not.w d1 ;
- bclr.l #15,d1 ;
- move.w d1,$9a(a6) ; (verify off non-sys Ints)
- not.w d1 ; (i do this as example only)
- move.w #$7fff,$9c(a6) ; Clear all Interupts Pending
- move.w d1,$9a(a6) ; Reenable System Interupts
-
- ;move.l 4,a6 ; ExecBase
- ;jsr -126(a6) ; Enable();
- bra TetrisExit ; Free system type resources
-
- MachineVariables2 ; (list tail)
- dcb.l 7,0
- MachineVariables
- oldtrap dc.l 0
-
- ;-----------------------------------------------------------------------------
- KeyboardInterupt
- movem.l d0/a0,-(a7) ; Save Registers
- move.b $bfed01,d0 ; Clear Interupt Requests
- ;($bfed01 must be done pronto or next int will be cleared instead)
- btst.l #3,d0 ; Not My Interupt?
- beq.s KeyboardInterupt900
- move.b $bfec01,d0 ; D0 = Read Keyboard
- or.b #64,$bfee01 ; PULSE KDAT LOW FOR 75 usec
- eor.b #254,d0 ; Mask of Hardware Shift
- lsr.b #1,d0 ; Get to Real
- bcc.s KeyboardInterupt500 ; Get Key Down Events Only
- ext.w d0 ; Clean for 68030 indirect
- move.b KeyMap(pc,d0.w),d0 ; Get Real Key
- lea KeyEvent(pc),a0
- move.b d0,(a0) ; Remember Key
- KeyboardInterupt500
- move.w #999,d0 ; >= 75 usec(should be timed)
- 1$ dbf d0,1$
- and.b #$bf,$bfee01 ; UNPULSE KEYBOARD
- KeyboardInterupt900
- movem.l (a7)+,d0/a0 ; Return Registers
- move.w #8,$dff09c ; Clear Interupt Bit
- rte ; Exit
-
- ; (I used this for reference on doing SERIAL input for the MIDI stuff)
-
- KeyMap dc.l $60313233,$34353637,$3839302d,$3d5c0000
- dc.l $51574552,$54595549,$4f505b5d,$00313233
- dc.l $41534446,$47484a4b,$4c3b270d,$00343536
- dc.l $005a5843,$56424e4d,$2c2e2f00,$00373839
- dc.l $200a000d,$0d7b0a00,$00002d00,$1c1d1e1f
- dc.l $11121314,$15161718,$191a0000,$00000000
- dc.l $00000000,$00000000,$00000000,$00000000
- dc.l $00000000,$00000000,$00000000,$00000000
-
-
- ;*****************************************************************************
- ;*****************************************************************************
-
- SayName
- lea Name(pc),a0 ; (whoops, almost forgot)
- move.l GameVideo(pc),a1
- lea 44(a1),a1 ; (change color)
- bra PrintText
- Name: dc.w 14*8,29*8
- dc.b 'An Anselm Hook Game',0
- even
-
- DoIntro
- lea ScrollMessage(pc),a0
- lea ScrollPos(pc),a1
- move.l a0,(a1)
-
- lea IntroText(pc),a0 ; Print Instructions
- move.l GameVideo(pc),a1
- bsr PrintText
- bsr ColorFader ; Bring on view nicely
-
- 1$ lea KeyEvent(pc),a0
- cmp.b #$7b,(a0)
- beq MachineReturn
- bsr DoScrollText
-
- btst #7,$bfe001 ; Wait for User Done
- beq.s 2$ ; Go right into game no pause
- btst #6,$bfe001
- bne.s 1$
- 2$ bra VideoClear
-
- DoScrollText
- lea ScrollPos(pc),a0
- tst.l 4(a0)
- beq.s 2$
- subq.l #1,4(a0)
- bra WaitFrame
- 2$ move.l (a0),a1
- move.b (a1)+,d0 ; D0 = Character #
- bne.s 1$
- lea ScrollMessage(pc),a1
- move.b (a1)+,d0 ; (prefetch!)
- 1$ move.l a1,(a0)
- moveq #7,d1 ; D1 = Horiz Bit Pos #
- 0$ movem.w d0/d1,-(a7)
- bsr PrintColumn
- movem.w (a7)+,d0/d1
- dbf d1,0$
- rts
-
- ScrollPos: dc.l 0,60*5
-
- IntroText:
- dc.w 20,40
- ;0123456789012345678901234567890123456789
- dc.b $84," Amiga Tetris",13
- dc.b 13
- dc.b " Press Escape to Exit to Workbench",13
- dc.b " Press ",$87,"Fire",$80,$82," Button to play",13
- dc.b 13
- dc.b " Move falling pieces with Joystick",13
- dc.b " Rotate pieces with fire button ",13
- dc.b " Interlock pieces to make an unbroken",13
- dc.b " line before pieces overflow playfield ",13
- dc.b " Completed lines are automagically",13
- dc.b " zapped away. Lines required to win",13
- dc.b " level are shown at left of field ",13
- dc.b 13
- dc.b " Amiga Tetris is public domain",13
- dc.b " and is intended primarily as a tutorial",13
- dc.b " on Machine Language programming",13
- dc.b 13
- dc.b " Due to Tetris.s running in PAL Mode you",13
- dc.b " may have to:",13
- dc.b $84," ADJUST VERTICAL HOLD!",13
- dc.b 13
- dc.b 0
-
- ;*****************************************************************************
- ;*****************************************************************************
-
- ;
- ; I reserve some address registers for specific use
- ;
- ; A6 = Amiga Hardware
- ; A5 = Variables, allowing me to do move.w d0,variable(a5)
- ; (which is more flexible than move.w d0,variable(pc))
- ; A4 = Current player vars, allowing infinite # of players.
- ;
-
- ; To Do:
- ; * - pause at level end, with music restart.
- ; * - music 1/2 volume
- ; * - different end of line sound
- ; * - raisers later, and slower
- ; * - (slow music, music speeds up every level)
- ; * - tiles speed up every level
- ; * - instructions
- ; * - turn off sprites
- ; * - make easier, raisers later
- ; * - supervisor multi-player merge/scan
- ; * - sound for end of line + bonuses + randoms + raisers
- ; * - pause
- ; * - less rows at start
- ; * - inc rows, music speed algorithm of level
- ; - single, double, three, tetris bonuses
- ; - statistics on side bar
- ; - support rotate agains right wall
- ; - remove mulus
-
- end
-
- ; end of tetris.s
-