Monday, October 10, 2011

Assembly Is Making Me Miserable (ft. Shaquille O'Neal)

I know talking about school sucks but I'll be back to Sega games no time!!!

I'm so fatigued right now.  I spent almost all week working on my Assembly (programming) homework.  And no, I didn't put this off until late, it was just that aggravating.  Ironing out bugs and whatnot.  This is the final result:


The goal of this assignment is to create a "turret game" that shoots balls at moving targets using a power bar & angle.  Rather than do some mundane 80's arcade game or "space shooter," I decided to make a basketball game.  With Shaquille O'Neal canning 3-pointers at the local playground.  You MUST hit the top of the rim to score points.  The ball will go "swish" and fall through the rim which is super-tight.   Oh and BTW, the rim moves back and forth.  Note that in this screenshot, the square cut-out on the ball is only temporary.

I got carried away and decided to polish the hell out of this.  One reason is because, in class, we're holding a "contest" in that the students who post the best screenshots of their game in action are nominated to win some free prize and get their work published at an end-of-the-year party (score points with potential employers).  Three games were chozen.

How were they chosen?  The teacher brought in two random judges to look at the screenshots (without knowing whose made what game) and pick the three they like the best.  Who were these judges?  Heh...the teacher walked down the hall and hauled in two female art students.

My game didn't get picked purely because it's basketball.  Girls don't like sports.  I lost out to a game with the art teacher's floating head as a destroyable object. I didn't get any such "props" or anything to keep my head held high that day. Oh my, what a horrible day. I got hosed. I'm pissed off and super tired but I'm not going to let that get in my way...we can't grieve forever, gotta get BACK TO BUSINESS!! (the joys of programming...)

So, I'm going to preserve the game & source code for you and me. Take a look and see for yourself how much "fun" this is. I'm not letting this game go to waste (like many programming assignments of the past). If you want to run the game, hit the jump and take a look at the source code.  You need to copy & paste this into an Easy68K Assembler file (click here to get Easy68K).    Then run & compile it.  You must also save the two .bmp files you see to the same directory as your code.

NOTE: Please don't read this code for the sake of criticizing me--my teacher will give me enough of a tongue lashing later on.

Save these .bmp's to the same directory as code, DO NOT CHANGE FILE NAMES.


******************************************************************
*
* Program    : 00000002
* Written by : Eric ______________
* Date       : 10/10/11
* Description: Let's play some Street Hoops big boy!
*
* Controls:
*
* SPACE: Throw Ball
* A: Aim Upwards
* D: Aim Downards
* W: Move Forward
* S: Move Backward
* R: Restart Game (only if 10 shots have been made)
*
* Rules:
*
* You play as Shaquille O'Neal at the local children's playground.
* Sink those free throws and prove your b-ball skills!
* Watch out, the net moves back and forth for no reason,
* probably because Shaq's nerves are getting to him.
*
* Press Space to shoot the ball.
* Depending on how much the red bar is filled, the harder you'll throw the ball.
* Get the ball to land on the top of the rim (don't just "hit" the rim or it won't count).
* Aim and move back & forth to help you get those shots in.
* NOTE: You cannot use the backboard, you can only swish the shots!
*
* Try to score 10 points in 10 shots!  Good luck, playa!!!
*
******************************************************************



******************************************************************
* Constants pertaining to trap codes.
******************************************************************

GET_TIME_CODE                   EQU     8
DRAW_TO_BUFFER_CODE             EQU     17
GET_KEY_INPUT_CODE              EQU     19  
SET_OUTPUT_RESOLUTION_TRAP_CODE EQU     33
PEN_COLOR_TRAP_CODE             EQU     80
FILL_COLOR_TRAP_CODE            EQU     81
DRAW_PIXEL_TRAP_CODE            EQU     82
DRAW_LINE_TRAP_CODE             EQU     84
DRAW_RECTANGLE_TRAP_CODE        EQU     87
DRAW_ELLIPSE_TRAP_CODE          EQU     88
DRAWING_MODE_CODE               EQU     92
SET_PEN_WIDTH_CODE              EQU     93
REPAINT_SCREEN_CODE             EQU     94



******************************************************************
* Game constants that are subject to change.
******************************************************************

SCOREBOX_WIDTH                  EQU     80
SCOREBOX_HEIGHT                 EQU     40
SCOREBOX_BORDER_WIDTH           EQU     4
NUM_DIST_FROM_RIGHT             EQU     80
NUMBER_INCREMENT                EQU     20
PEN_WIDTH                       EQU     3
PLAYER_X_MAX_OFFSET             EQU     150
PLAYER_MOVE_INCREMENT           EQU     15
PLAYER_ANGLE_INCREMENT          EQU     5
ARM_LENGTH                      EQU     40
ARM_HEIGHT_FROM_TOP             EQU     45
ARM_WIDTH_INWARDS               EQU     25
BALL_HALF_WIDTH_HEIGHT          EQU     10
GRAVITY_CONST                   EQU     $200
POWER_BAR_INC_RATE              EQU     6000
POWER_BAR_X_OFFSET              EQU     10
POWER_BAR_Y_OFFSET              EQU     10
POWER_BAR_WIDTH                 EQU     30
POWER_BAR_HEIGHT                EQU     200
POWER_BAR_MAX                   EQU     190
POWER_BAR_BOOST                 EQU     $1000
NET_Y_COORD                     EQU     150
NET_HALF_HEIGHT                 EQU     10
NET_HALF_WIDTH                  EQU     40
NET_HALF_WIDTH_SCORE_SUB        EQU     5
NET_MOVE_RATE                   EQU     $1800
NET_MAX_X                       EQU     595
NET_MIN_X                       EQU     385
OFFSCREEN_BUFFER                EQU     10



******************************************************************
* System variables that shouldn't be changed (unless you have a good reason to do so).
******************************************************************

SCREEN_WIDTH                    EQU     640
SCREEN_HEIGHT                   EQU     480
PLAYER_HEIGHT                   EQU     200
PLAYER_WIDTH                    EQU     179
ASCII_W_KEY                     EQU     $57
ASCII_S_KEY                     EQU     $53
ASCII_A_KEY                     EQU     $41
ASCII_D_KEY                     EQU     $44
ASCII_R_KEY                     EQU     $52
ASCII_SPACE_KEY                 EQU     $20
SEVEN_LINE_LCD                  EQU     7
NUMBER_OF_NUMBERS               EQU     4
TWO_BYTES_MAX                   EQU     255
BLACK                           EQU     $00000000
WHITE                           EQU     $00FFFFFF
RED                             EQU     $000000B0
ORANGE                          EQU     $0000A0FF
YELLOW                          EQU     $0000FFFF
GREEN                           EQU     $0000A000
DARK_BLUE                       EQU     $00A00000
BLUE                            EQU     $00FF0000
TRANSPARENT                     EQU     $00FF00FF



START           ORG     $1000
               
******************************************************************
*
* Begin by changing our screen resolution.  Change to buffer draw mode.  Increase Pen Thickness.
*
******************************************************************
               
                move.l  #SET_OUTPUT_RESOLUTION_TRAP_CODE, d0
                move.w  #SCREEN_WIDTH, d1
                swap.w  d1
                move.w  #SCREEN_HEIGHT, d1
                trap    #15
                move.w  #DRAWING_MODE_CODE, d0
                move.w  #DRAW_TO_BUFFER_CODE, d1
                trap    #15
                move.w  #SET_PEN_WIDTH_CODE, d0
                move.w  #PEN_WIDTH, d1
                trap    #15
               
                clr     d0
                clr     d1
               
               
               
******************************************************************
*
* Before our game loop, print out the background and player.
*
* Since we don't plan on redrawing these two things every single frame, let's draw these two things right now.
*
******************************************************************
               
                lea     BGData, a0
                jsr     DrawPicture
                jsr     DrawPlayer
                jsr     GetTime
               
               
               
******************************************************************
*
* GAME LOOP.
*
* We call the necessary functions here.  We don't draw bitmaps (BG & player) unless they are necessary.
*
******************************************************************
               
GameLoop:       jsr     GetTime
                jsr     GetInput
                jsr     DrawBall
                jsr     DrawNet
                jsr     DrawPowerBar
                jsr     DrawNumberBox

* We use our buffer paint mode to seamlessly move our objects across screen.
               
                move.w  #REPAINT_SCREEN_CODE, d0
                trap    #15
               
                bra     GameLoop
               
               
               
******************************************************************
*
* GET TIME.
*
* Each time this function is called, we compare times (in 1/100th's of seconds),
* and save the time interval in "CurTimeInterval."
*
* That way, we can move objects on a time-basis (not frame-basis), so if the framerate drops,
* the objects move at the same rate regardless.
*
******************************************************************

GetTime:        move.w  #GET_TIME_CODE, d0
                trap    #15
                lea     OldTime, a0
                lea     CurTimeInterval, a1
               
                * Get our OldTime (the last time we called this function)
               
                move.l  (a0), d2
                move.l  d1, (a0)
                sub.l   d2, d1
                move.l  d1, (a1)
               
                * Subtract this time minus our OldTime to get our Current Time Interval
               
                rts
               
               

******************************************************************
*
* GET INPUT.
*
* Space Bar throws bar.  It won't fire if a ball is in play or the shot counter is at 10.
*
* R restarts the game.  This only works when the shot counter is at 10.  It resets the shot counter to 0.
*
* A and D move the pointer "arm" left and right.
*
* W moves the player (Shaq) forward.  S moves the player backwards.
*
*******************************************************************

GetInput:       lea     GameOver, a0
                move.b  (a0), d0
                cmpi.b  #0, d0
                beq     NotGameOver
               
* If GameOver is set to 1, then the game won't receive input.

*******************************************************************
* Restart Key
*******************************************************************

                move.w  #ASCII_R_KEY, d1
                move.w  #GET_KEY_INPUT_CODE, d0
               
                trap    #15
               
* Press R to start game over or else keep game in stasis until then.
               
                cmpi.b  #0, d1
                beq     StuckInGameOver
               
                move.b  #0, (a0)
               
* Once we press R, change the CurrentNumber array so that the score counter displays "0/0".
               
                lea     CurrentNumber, a1
               
                move.b  #10, (a1)+
                move.b  #0, (a1)+
                move.b  #10, (a1)+
                move.b  #0, (a1)
                rts
               
StuckInGameOver:rts

NotGameOver:    lea     BallIsThrown, a0
                move.b  (a0), d0
                cmpi.b  #0, d0
                beq     ContinueInput
                rts
               
* If BallIsThrown is set to 1, then don't receive any input.



*******************************************************************
* Shoot Ball Key
*******************************************************************

ContinueInput:  move.w  #ASCII_SPACE_KEY, d1
                move.w  #GET_KEY_INPUT_CODE, d0
               
                trap    #15
               
                cmpi.b  #0, d1
                beq     NoSpaceInput
               
* Space bar is pressed and a ball is thrown.
* Change BallIsThrown to 1 to signal that ball is in the air.
* Now let us initiate the ball's parameters.
               
                move.b  #1, (a0)
   
   

*******************************************************************          
*
* CurBallCoord is a pair of long values (X, Y0 that denotes where the ball is in the air.
* Three of eight bytes are dedicated to decimal fixed point ($XXXXX.YYY).
* Ball is initially placed in the same location no matter what aim/velocity (on the arm's origin).
*
* Ball Initial X-Pos = PlayerXOffset + Player_Width - Arm_Width_Inwards.
* Ball Initial Y-Pos = Screen_Height - Player_Height + Arm_Height_From_Top.
*
*******************************************************************
               
                lea     CurBallCoord, a0
                lea     PlayerXOffset, a1
                move.w  (a1), d0
                add.w   #PLAYER_WIDTH, d0
                sub.w   #ARM_WIDTH_INWARDS, d0
               
                asl.l   #8, d0
                asl.l   #4, d0
               
                move.l  d0, (a0)+
               
                move.w  #SCREEN_HEIGHT, d1
                sub.w   #PLAYER_HEIGHT, d1
                add.w   #ARM_HEIGHT_FROM_TOP, d1
               
                asl.l   #8, d1
                asl.l   #4, d1
               
                move.l  d1, (a0)
               
* A bunch of variables.
* CurPowerBar is a three-byte fixed-point variable that measures the length of the red bar on the screen.
* CurrentAngle is a byte value between 0-90.  90 is straight up in the air, 0 is parallel with the ground.
* Cosine and Sine are a series of 3-byte decimal words that are referenced to determine the X and Y initial velocities.
* CurBallVelocity is a pair of three-byte fixed-point words that dictates the ball's velocity.
               
                lea     CurPowerBar, a1
                lea     CurrentAngle, a2
                lea     Cosine, a3
                lea     Sine, a4
                lea     CurBallVelocity, a5
               
* Power bar value ranges between $0 to $1FFFF.
* Assume that the bar is always five bytes long.  Shift that value over one byte to the right so we can multiply words, not longs.
               
                move.l  (a1), d0
                asr.l   #4, d0
                move.l  d0, d1
               
* Derive our sine/cosine values by incrementing the address by our angle value.
               
                clr.l   d2
                move.b  (a2), d2
                mulu.w  #2, d2
                add.w   d2, a3
                add.w   d2, a4
                mulu.w  (a3), d0
                mulu.w  (a4), d1
               
* After we derived our x- and y-velocities, shift bytes back to three-byte decimal fixed point.
               
                asr.l   #8, d0
                asr.l   #4, d0
                asr.l   #8, d1
                asr.l   #4, d1
               
* Power_Bar_Boost adds extra velocity to the ball and nothing more.
               
                move.l  d0, (a5)
                add.l   #POWER_BAR_BOOST, (a5)+
                move.l  d1, (a5)
                add.l   #POWER_BAR_BOOST, (a5)
               
                rts
               
               
               
*******************************************************************
* Change Shot Angle Key
*******************************************************************
               
NoSpaceInput:   move.w  #ASCII_A_KEY, d1
                move.w  #GET_KEY_INPUT_CODE, d0
               
                trap    #15
               
                cmpi.b  #0, d1
                beq     NoLeftInput
               
* Press A to increment the yellow arm angle.
* Use sine and cosine chart to pivot this arm around a specific point.
* If angle equals 90 degrees, stop incrementing.
               
                lea     CurrentAngle, a0
                move.b  (a0), d0
                cmp.b   #90, d0
                bge     NoLeftInput
                addq.w  #PLAYER_ANGLE_INCREMENT, d0
                move.b  d0, (a0)

* Once we've changed the current angle, redraw the arm (including the background it is touching).

                jsr     ClearAll
                jsr     DrawArmClear
                jsr     DrawArm
               
               
               
*******************************************************************
* Change Shot Angle Key #2
*******************************************************************
               
NoLeftInput:    move.w  #ASCII_D_KEY, d1
                move.w  #GET_KEY_INPUT_CODE, d0
               
                trap    #15
               
                cmpi.b  #0, d1
                beq     NoRightInput
               
* Press D to decrement the yellow arm angle.
* If angle equals 0 degrees, stop decrementing.
* See A key above, it's the same thing
               
                lea     CurrentAngle, a0
                move.b  (a0), d0
                cmp.b   #0, d0
                ble     NoRightInput
                subq.w  #PLAYER_ANGLE_INCREMENT, d0
                move.b  d0, (a0)
               
                jsr     ClearAll
                jsr     DrawArmClear
                jsr     DrawArm
               
               
               
*******************************************************************
* Move Player Forward (Right) Key
*******************************************************************

NoRightInput:   move.w  #ASCII_W_KEY, d1
                move.w  #GET_KEY_INPUT_CODE, d0
               
                trap    #15
               
                cmpi.b  #0, d1
                beq     NoFrontInput
               
* Get the PlayerXOffset, a word value that denotes the gap between the player and the left-side of the screen
* If player has reached the max offset thresh-hold, don't do anything, just ignore this key.
               
                lea     PlayerXOffset, a0
                move.w  (a0), d0
                move.w  (a0), d1
                cmp.w   #PLAYER_X_MAX_OFFSET, d0
                bge     NoFrontInput
                add.w   #PLAYER_MOVE_INCREMENT, d0
                move.w  d0, (a0)
        
*******************************************************************
*   
* Now our goal is to first redraw the background then the player himself to show our change in position.
*
* See DrawPicture function for what these parameters means.
*
* When drawing our background, OffsetX = ImageXMin and OffsetY = ImageYMin
* Subtract one from ImageXMax and ImageYMax to accomodate for coordinates which begin at 0 (ex. 640 width ranges from 0 to 639)
*
*******************************************************************
               
                lea     OffsetX, a0
                move.w  d1, (a0)
               
                lea     OffsetY, a0
                move.w  #SCREEN_HEIGHT, d4
                sub.w   #PLAYER_HEIGHT, d4
                subq.w  #1, d4
                move.w  d4, (a0)
               
                lea     ImageXMin, a0
                move.w  d1, (a0)
               
                lea     ImageYMin, a0
                move.w  d4, (a0)
               
                lea     ImageXMax, a0
                add.w   #PLAYER_WIDTH, d1
                subq.w  #1, d1
                move.w  d1, (a0)
               
                lea     ImageYMax, a0
                move.w  #SCREEN_HEIGHT, d3
                subq.w  #1, d3
                move.w  d3, (a0)
               
* ClearAll sets all registers and address (except a7) to zero
               
                jsr     ClearAll

* Set pointer a0 to whatever file we want to draw.
* Draw the background, hence use BGData
* Diagonal fix should be set to 1 for BG file, 0 for Player file
               
                lea     BGData, a0
                lea     DiagonalFix, a1
                move.b  #1, (a1)
                jsr     DrawPicture
               
* Once DrawPicture has drawn our BG, call DrawPlayer and go away

                jsr     DrawPlayer
               
               
               
*******************************************************************
* Move Player Backward (Left) Key
*******************************************************************
               
NoFrontInput:   move.w  #ASCII_S_KEY, d1
                move.w  #GET_KEY_INPUT_CODE, d0
               
                trap    #15
               
* See above function for similar method of printing BG then player image
               
                cmpi.b  #0, d1
                beq     NoBackInput
               
                lea     PlayerXOffset, a0
                move.w  (a0), d0
                move.w  (a0), d1
                cmp.w   #0, d0
                ble     NoBackInput
                sub.w   #PLAYER_MOVE_INCREMENT, d0
                move.w  d0, (a0)
               
                add.w   #PLAYER_WIDTH, d1
               
                lea     OffsetX, a0
                move.w  d0, (a0)
               
                lea     OffsetY, a0
                move.w  #SCREEN_HEIGHT, d4
                sub.w   #PLAYER_HEIGHT, d4
                subq.w  #1, d4
                move.w  d4, (a0)
               
                lea     ImageXMin, a0
                move.w  d0, (a0)
               
                lea     ImageYMin, a0
                move.w  d4, (a0)
               
                lea     ImageXMax, a0
                subq.w  #1, d1
                move.w  d1, (a0)
               
                lea     ImageYMax, a0
                move.w  #SCREEN_HEIGHT, d3
                subq.w  #1, d3
                move.w  d3, (a0)
               
                jsr     ClearAll
               
                lea     BGData, a0
                lea     DiagonalFix, a1
                move.b  #1, (a1)
                jsr     DrawPicture
                jsr     DrawPlayer
               
* End our input function.
               
NoBackInput:    rts
               
               
               
*******************************************************************
*
* DRAW PICTURE.
*
* Call this function when we want to draw a bitmap.
*
* You MUST set values to XOffset, YOffset, ImageXMin, ImageYMin, ImageXMax, ImageYMax
* AND set a0 to BMP data file before calling this function.
*
* NOTE: Because drawing large pictures (over 100x100 resolution) can be very laggy,
* don't call this unless we really have to (or we can afford to wait a couple hundred milliseconds.
*
* What the registers do:
*
* d0: Miscellaneous Variables & Traps
* d1: " "
* d2: " "
* d3: " "
* d4: X-Max cutout of bitmap (assuming 0,0 is upper left corner)
* d5: Y-Min cutout of bitmap
* d6: X-Offset
* d7: Y-Offset
* a0: Bitmap Stack Pointer
* a1: Miscellaneous Pointers
* a2: Current X-Coordinate (relative to bitmap ONLY)
* a3: Current Y-Coordinate
* a4: Bitmap Width
* a5: Bitmap Height
* a6: X-Min cutout of bitmap
* a7: N/A
*
* See this link for more info on bitmap file format:
*
* http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
*
******************************************************************
               
DrawPicture:    add.w   #18, a0

* We begin by running through the initial values of a bitmap file.
* Increment to 18 to our image width
               
                move.b  (a0)+, d1
                move.b  (a0), d0
                addq.w  #3, a0

* Do a little endian swap.  Set a4 to bitmap width.

                asl.w   #8, d0
                add.w   d0, d1
                move.w  d1, a4
                clr.w   d0
                clr.w   d1
               
                move.b  (a0)+, d1
                move.b  (a0), d0
                addq.w  #3, a0
               
* Another little endian swap.  Set a5 to bitmap height.
               
                asl.w   #8, d0
                add.w   d0, d1
                move.w  d1, a5
                clr.w   d0
                clr.w   d1
               
* Increment our pointer by 28.  Now we are at our RGB values.
               
                add.w   #28, a0
 
******************************************************************
*
* Before we draw our picture, we need to pick up some parameters.
*
* Parameters that the DrawPicture function uses:
*
* OffsetX: X-offset on our canvas (0 = left)
* OffsetY: Y-offset on our canvas (0 = up)
* ImageXMin: X-offset relative to our image (left-point)
* ImageYMin: Y-offset relative to our image (up-point)
* ImageXMax: X-value where drawing ends
* ImageYMax: Y-value where drawing ends
*
******************************************************************
               
* Set d6 to X-Offset on screen.
               
                lea     OffsetX, a1
               
                move.w  (a1), d6
                addq.w  #1, d6

* Set d7 to Y-Offset on screen.
               
                lea     OffsetY, a1
               
                move.w  (a1), d7
                subq.w  #1, d7
               
* Set d5 to Y-Min cutout of bitmap.
               
                lea     ImageYMin, a1
               
                move.w  (a1), d5
                subq.w  #2, d5
               
* Set d4 to X-Max cutout of bitmap.
               
                lea     ImageXMax, a1
               
                move.w  (a1), d4
               
* Set a2 and a6 to X-min cutout of bitmap.
               
                lea     ImageXMin, a1
                              
                move.w  (a1), a2
                move.w  (a1), a6
               
* Set a3 to Y-min cutout of bitmap.
               
                lea     ImageYMax, a1
               
                move.w  (a1), a3
               
* Skip through our pointer (a0), ignoring all RGB values from Y = ImageHeight to Y = ImageYMax
               
                move.w  #3, d0
                move.w  a3, d1
                addq.w  #1, d1
                move.w  a5, d2
                sub.l   d1, d2
                mulu.w  d2, d0
                move.w  a4, d1
                mulu.w  d1, d0
               
                add.l   d0, a0
               
                clr.l   d0
                clr.l   d1
                clr.l   d2
               
                sub.l   #1, a2
                sub.l   #1, a3
               
* Skip through pointer (a0), ignoring RGB values from X = 0 to X = ImageXMin

DrawSkipX:      move.w  #3, d0
                move.w  a6, d1
                mulu.w  d1, d0
               
                add.l   d0, a0
                clr.l   d0
                clr.l   d1



******************************************************************
*
* DRAW PIXEL.
*
* Take the RGB values and draw the dot in its respective location on screen.
*
* D1 will be our pixel color value
*
******************************************************************
               
DrawPixel:      move.b  (a0)+, d1               * d1: 000000BB
                                               
                swap    d1                      * d1: 00BB0000
                                               
                move.b  (a0)+, d1               * d1: 00BB00GG
               
                asl.w   #8, d1                  * d1: 00BBGG00

                move.b  (a0)+, d1               * d1: 00BBGGRR
               
* If the pixel we derive is $00FF00FF (bright pink), we don't draw that pixel
               
                cmp.l   #TRANSPARENT, d1
                beq     SkipDraw
               
                move.l  #PEN_COLOR_TRAP_CODE, d0
                trap    #15
               
* D0 = Pixel Trap Code
* D1 = X-Value on screen
* D2 = Y-Value on screen
       
                clr.l   d1                             
                move.w  a2, d1
                sub.l   a6, d1
                add.l   d6, d1
                move.w  a3, d2
                sub.l   d5, d2
                add.l   d7, d2
                move.l  #DRAW_PIXEL_TRAP_CODE,d0
                trap    #15         
                clr.l   d0
                clr.l   d1                             
                clr.l   d2
               
* Increment a2, our x-value pointer.
* Once it has reached ImageXMax, then end this row and move to the next one.
               
SkipDraw:       addq.l  #1, a2
               
                cmp     a2, d4  
               
                bne     DrawPixel
               
* Once the x-value has passed the max value, jump our pointer value the distance from X = ImageXMax to X = ImageWidth.
               
                move.w  a6, a2
                subq.w  #1, a2
               
                move.w  a4, d0
                sub.l   d4, d0
               
* DiagonalFix is complicated...if the image you draw is bent over, try enabling/disabling this before you call DrawPicture method.
               
                lea     DiagonalFix, a1
                move.b  (a1), d3
                cmp     #1, d3
               
                bne     CantDoIt
               
                subq.w  #1, d0
CantDoIt:       mulu.w  #3, d0
               
                add.l   d0, a0
                clr     d0
               
* Once the y-value has reached the max value, then we're done drawing the picture.
               
                subq.w  #1, a3
                cmp     a3, d5
               
                bne     DrawSkipX
                jsr     ClearAll
                rts
               


******************************************************************
*
* DRAW NET.
*
* Call this function every single loop.
*
* Draw an oval underneath our backboard.  The net's Y-value is fixed (NET_Y_COORD).
*
* It moves back and forth between two fixed coordinates.
*
* Every time BEFORE we draw an oval, we also have to redraw the background where it once was.
*
* Also, after we've moved the net, we must check that the ball has come in contact with the net (increment score).
*
******************************************************************

DrawNet:        lea     NetXOffset, a0

* Get the net's X and Y values.  Figure out where the net was last frame.
               
                move.l  (a0), d1
                asr.l   #8, d1
                asr.l   #4, d1
                move.l  d1, d3
                add.w   #NET_HALF_WIDTH, d1
                sub.w   #NET_HALF_WIDTH, d3
               
                move.w  #NET_Y_COORD, d2
                move.w  #NET_Y_COORD, d4
                add.w   #NET_HALF_HEIGHT, d2
                sub.w   #NET_HALF_HEIGHT, d4
               
                subq.w  #1, d3
                subq.w  #1, d4
                addq.w  #1, d1
                addq.w  #1, d2
               
* Set our parameters to the DrawPicture function.  Get ready to "blat" out traces of our previous oval.
               
                lea     OffsetX, a3
                move.w  d3, (a3)
               
                lea     OffsetY, a3
                move.w  d4, (a3)
               
                lea     ImageXMin, a3
                move.w  d3, (a3)
               
                lea     ImageYMin, a3
                move.w  d4, (a3)
               
                lea     ImageXMax, a3
                move.w  d1, (a3)
               
                lea     ImageYMax, a3
                move.w  d2, (a3)

* Clear our registers before we draw our picture for good measure.
              
                jsr     ClearAll
               
* Then draw the picture.
               
                lea     BGData, a0
                lea     DiagonalFix, a1
                move.b  #1, (a1)    
               
                jsr     DrawPicture



******************************************************************
*
* Now we've blatted out our previous net's background.
*
* Take the time interval between this frame and the previous one.
*
* Move the net depending on how much time has passed.
*
* NetXOffset is a three-byte fixed-point long that determines the x-coordinate on the screen.
*
******************************************************************
               
                lea     NetXOffset, a0
                lea     CurTimeInterval, a1
                lea     NetMoveBackward, a2
                move.b  (a2), d7
                move.l  (a1), d6
               
                mulu.w  #NET_MOVE_RATE, d6
               
* Check NetMoveBackward bit value.  If it's 0, then our net is supposed to move forward (to the right).
* If not, then move it backwards (to the left).
               
                cmpi.b  #0, d7
                beq     AddNet
                bra     SubNet
               
* Take our distance value derived earlier and either add/subtract the distance traveled.
               
AddNet:         add.l   d6, (a0)
                bra     CheckNetRange
               
SubNet:         sub.l   d6, (a0)
                bra     CheckNetRange
               
* Check and see if the net has reached one of its boundary edges and send it moving backwards
               
CheckNetRange:  move.l  (a0), d0
               
                asr.l   #8, d0
                asr.l   #4, d0
               
* Is the net past its right-most boundary?  Move it back and switch NetMoveBackward to 1.
               
                cmp     #NET_MAX_X, d0
                bls     SkipXMax
               
                move.l  #NET_MAX_X, d1
                asl.l   #8, d1
                asl.l   #4, d1
                move.l  d1, (a0)
                move.b  #1, (a2)
                bra     SkipXMin  
               
* Is the net past its left-most boundary?  Move it forward and switch NetMoveBackward to 0.
               
SkipXMax:       cmp     #NET_MIN_X, d0
                bgt     SkipXMin
               
                move.l  #NET_MIN_X, d1
                asl.l   #8, d1
                asl.l   #4, d1
                move.l  d1, (a0)
                move.b  #0, (a2)
               
* Finally, draw the net on the screen using our new coordinates.
* A white circle with a red border.
               
SkipXMin:       move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #RED, d1
                trap    #15
                move.w  #FILL_COLOR_TRAP_CODE, d0
                move.l  #WHITE, d1
                trap    #15
               
                move.w  #DRAW_ELLIPSE_TRAP_CODE, d0
              
* NetXOffset and NET_Y_COORD denotes the dead center value of the net.
* Use NET_HALF_WIDTH and NET_HALF_HEIGHT to expand the net from this center point.
               
                move.l  (a0), d1
                asr.l   #8, d1
                asr.l   #4, d1
                move.l  d1, d3
                add.w   #NET_HALF_WIDTH, d1
                sub.w   #NET_HALF_WIDTH, d3
               
                move.w  #NET_Y_COORD, d2
                move.w  #NET_Y_COORD, d4
                add.w   #NET_HALF_HEIGHT, d2
                sub.w   #NET_HALF_HEIGHT, d4
               
                trap    #15
               
* Check and see if the ball has come in contact with the net.
* If the ball is not in the air (BallIsThrown is 0), then don't run this check--just return back to the game loop.
               
                lea     BallIsThrown, a0
                move.b  (a0), d7
                cmpi.b  #0, d7
                bne     CheckForScore
                rts
               
******************************************************************
*
* CHECK FOR SCORE.
*
* DrawNet is the only function that calls this.
*
* This is only called if the ball is in the air.
*
* If the ball touches the net, then the ball instantly disappears and no score is added.
*
* HOWEVER, if the ball touches a specific box on the top of the net, then the ball scores a point.
*
* EXAMPLE SCORING BOX, touch the O's to score, touch the X's to fail.
*
*         OOOOOOOO
*         OOOOOOOO
* Net-> XXOOOOOOOOXX
*       XXXXXXXXXXXX
*       XXXXXXXXXXXX
*
******************************************************************

CheckForScore:  lea     CurBallCoord, a0

* Get the ball's coordinates.  Get rid of the decimal bytes (shift right).
               
                move.l  (a0)+, d5
                asr.l   #8, d5
                asr.l   #4, d5
               
                move.l  (a0), d6
               
* Check and see if the ball's Y-coordinate is negative (meaning it's off the screen).
* If this is so, then don't check, it has no way of touching the net.
               
                cmp.l   #0, d6
                bmi     StopChecking
               
                asr.l   #8, d6
                asr.l   #4, d6
               
* The win box is derived using coordinates from our net draw trap box.
*  Save the original coordinates for later--use a1 thru a4 instead.
               
                move.l  d1, a1
                move.l  d2, a2
                move.l  d3, a3
                move.l  d4, a4

                sub.l   #NET_HALF_WIDTH_SCORE_SUB, a1
                add.l   #NET_HALF_WIDTH_SCORE_SUB, a3
                sub.l   #NET_HALF_HEIGHT, a2
                sub.l   #NET_HALF_HEIGHT, a4
                sub.l   #NET_HALF_HEIGHT, a4
               
* Go through the four "if" statements.  If all are true, then our ball is touching the score box.
               
                cmp.l   a1, d5
                bgt     DidntScore
               
                cmp.l   a3, d5
                bls     DidntScore
               
                cmp.l   a2, d6
                bgt     DidntScore
               
                cmp.l   a4, d6
                bls     DidntScore
               
* One more check.  If the ball is not moving down, then don't score.
* This is to prevent players from heaving the ball directly at the rim and scoring because the ball barely grazed the score box.
               
                lea     BallMoveDown, a1
                cmpi.b  #0, (a1)
                beq     DidntScore
               
               

******************************************************************
*
* IT'S GOOD!!!!
*        
* The ball has scored.  The ball comes with its own function called BlotOutBall.
*
* Call this function to erase the ball's previous location and fill it in with the background (like what was done with the net).
*
* Then we change the ball's trajectory--set X-velocity to zero and simulate the "swish" that a nice B-Ball shot does.
*
******************************************************************
               
                jsr     BlotOutBall
               
* Here, increment the score counter to show that we have scored.
               
                lea     CurrentNumber, a1
                lea     CurBallCoord, a2
                lea     CurBallVelocity, a3
                addq.w  #1, a1
                addq.b  #1, (a1)
               
* If the score reaches 10, then the 7-segment LED will have to undergo a special change.
* Set the second number to 0, then the first one to 1 (10).
* Good luck trying to sink all ten shots though!
* FYI, the third and fourth bytes of CurrentNumber denote the total number of shots fired.
               
                cmpi.b  #10, (a1)
                bne     NotMaxScore
               
                move.b  #0, (a1)
                subq.w  #1, a1
                move.b  #1, (a1)
                lea     GameOver, a4
                move.b  #1, (a4)

* Change the ball's trajectory.  Eliminate X-velocity and change its Y-velocity so it's right underneath the net.

NotMaxScore:    move.l  #0, (a3)
                addq.w  #4, a2
                move.l  #NET_Y_COORD, d7
                add.l   #NET_HALF_HEIGHT, d7
                addq.l  #1, d7
                asl.l   #8, d7
                asl.l   #4, d7
                move.l  d7, (a2)

* If the ball has scored, then there's no need to continue checking the ball's coordinates, skip to the end of this function.
               
                bra     StopChecking
               
* If the ball isn't in the score-zone (O's), then check to see if it's in the fail zone (X's).
* The box we use is practically the same as our net trap draw coordinates (we preserved d1 thru d4 for that reason).
               
DidntScore:     cmp.l   d1, d5
                bgt     StopChecking
               
                cmp.l   d3, d5
                bls     StopChecking
               
                cmp.l   d2, d6
                bgt     StopChecking
               
                cmp.l   d4, d6
                bls     StopChecking
               
* If the ball is touching the box, eradicate it (set it back to non-existence).
               
                jsr     EradicateBall
               
* If the ball isn't touching either box, then clear our registers and go away.
               
StopChecking:   jsr     ClearAll
                rts
               
               
               
******************************************************************
*
* DRAW BALL.
*
* Function that is called every game loop.
*
* Draw the ball and change its position & velocity.
*
* Like the net, the previous ball's location must be blotted out with the background.
*
* NOTE: To initiate the ball, see the GetInput code section.
*
******************************************************************

* If the ball isn't in play (BallIsThrown = 0), then go back to the game loop.

DrawBall:       lea     BallIsThrown, a0
                move.b  (a0), d0
                cmp     #0, d0
                bne     MoveBall
                rts
               
* Ball is in the air.  First cover up the previous ball's location and prepare to draw its next location.

MoveBall:       jsr     BlotOutBall



******************************************************************
*
* MOVE BALL.
*
* Get the ball's coordinates & velocity and change both with respect to the time interval in the previous loop.
*
******************************************************************
               
                lea     CurBallCoord, a0
                lea     CurBallVelocity, a1
                lea     BallCheck, a2
                lea     CurTimeInterval, a3
                lea     BallMoveDown, a4
               
* Take our ball velocities.  Multiply by the time interval.
               
                move.l  (a1)+, d0
                move.l  (a1), d1
               
                move.l  (a3), d5
               
                mulu.w  d5, d0
                mulu.w  d5, d1
               
* Apply temporary velocity to our ball's X-position.
               
                add.l   d0, (a0)+
               
                move.l  (a1), d3
                mulu.w  #GRAVITY_CONST, d5
               
******************************************************************
*
* Y-velocity is more difficult to gauge.
* If BallMoveDown is equal to zero, then subtract velocity & position.
* Otherwise, add velocity & position.
* Note that BallMoveDown is always equal to 0 when ball is initiated.
*
******************************************************************
               
                cmpi.b  #1, (a4)
                beq     MoveDown
                bra     MoveUp
               
MoveUp:         sub.l   d1, (a0)

* While BallMoveDown is 0, check and see when Y-velocity equals 0.
* If so, then switch BallMoveDown to 1.

                sub.l   d5, d3
                bpl     BallOkay
               
                move.b  #1, (a4)
                move.l  (a1), d3
               
                bra     BallOkay
               
* If BallMoveDown is 1, then add, not subtract.
               
MoveDown:       add.l   d1, (a0)

                add.l   d5, d3
               
* Apply the changes we've made to the Y-velocity.

BallOkay:       move.l  d3, (a1)



******************************************************************
*
* BALL CHECK.
*
* Call BallCheck, a series of X and Y-planes that, if the ball crosses, eliminates the ball from play.
*
******************************************************************

                move.l  (a2)+, d6
                asl.l   #8, d6
                asl.l   #4, d6

                lea     CurBallCoord, a0
                move.l  (a0), d7
               
                cmp.l   d6, d7
               
* If ball X-coordinate is greater than SCREEN_WIDTH (give-or-take a few), then ball is eradiated from play.
               
                ble     BallCheckX
                jsr     EradicateBall
                rts
               
BallCheckX:     lea     CurBallCoord, a0
                add.l   #4, a0
                clr.l   d7
                move.l  (a0), d7
               
                lea     BallCheck, a2
                addq.l  #4, a2
               
                clr.l   d6
                move.l  (a2), d6
                asl.l   #8, d6
                asl.l   #4, d6

                cmp.l   d6, d7
               
* If ball Y-coordinate is greater than SCREEN_HEIGHT (give-or-take a few), then ball is eradicated from play.
               
                ble     BallCheckY
                jsr     EradicateBall
                rts
               
******************************************************************
*
* ACTUALLY DRAW THE BALL.
*
* Call trap codes and plug in the coordinates to draw the ball.
*
* Ball is orange with a black border.
*
* Ball drawing is centered on the CurBallCord's values (rounded to whole number).
*
******************************************************************
               
BallCheckY:     move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #BLACK, d1
                trap    #15
                move.w  #FILL_COLOR_TRAP_CODE, d0
                move.l  #ORANGE, d1
                trap    #15
               
                move.w  #DRAW_ELLIPSE_TRAP_CODE, d0
               
                lea     CurBallCoord, a0
               
                move.l  (a0), d1
                move.l  (a0)+, d3
                move.l  (a0), d2
                move.l  (a0), d4
               
                asr.l   #8, d1
                asr.l   #4, d1
                asr.l   #8, d2
                asr.l   #4, d2 
                asr.l   #8, d3
                asr.l   #4, d3 
                asr.l   #8, d4
                asr.l   #4, d4
               
                add.w   #BALL_HALF_WIDTH_HEIGHT, d1
                add.w   #BALL_HALF_WIDTH_HEIGHT, d2
                sub.w   #BALL_HALF_WIDTH_HEIGHT, d3
                sub.w   #BALL_HALF_WIDTH_HEIGHT, d4

                trap    #15
               
* Ball is drawn.  Clear registers, return to game loop.
               
                jsr     ClearAll
                rts
               
               
               
******************************************************************
*
* BLOT OUT BALL.
*
* Called frame the ball is in play.
*
* Fills in the ball's most recent location with the background image.
*
* Sets the DrawPicture function's parameters then calls the function.
*
******************************************************************
               
BlotOutBall:    lea     CurBallCoord, a0

* Get the ball's coordinates.  Round to whole numbers.

                move.l  (a0), d1
                move.l  (a0)+, d3
                move.l  (a0), d2
                move.l  (a0), d4
               
                asr.l   #8, d1
                asr.l   #4, d1
                asr.l   #8, d2
                asr.l   #4, d2 
                asr.l   #8, d3
                asr.l   #4, d3 
                asr.l   #8, d4
                asr.l   #4, d4
               
* Create a box that envelopes the ball's location.
               
                add.w   #BALL_HALF_WIDTH_HEIGHT, d1
                add.w   #BALL_HALF_WIDTH_HEIGHT, d2
                sub.w   #BALL_HALF_WIDTH_HEIGHT, d3
                sub.w   #BALL_HALF_WIDTH_HEIGHT, d4
               
* Accomodate for the pen's thickness.  Those increase the ball's dimensions.
               
                addq.w  #PEN_WIDTH, d1
                subq.w  #1, d1
               
                addq.w  #PEN_WIDTH, d2
                subq.w  #1, d2

                subq.w  #PEN_WIDTH, d3
                addq.w  #1, d3

                subq.w  #PEN_WIDTH, d4
                addq.w  #1, d4
               
               
               
******************************************************************
*
* Check to see if the ball's BG redraw zone exceeds the screen.
*
* If it does, change the box coordinates so that they remain within these ranges:
*
* X: 0 to SCREEN_WIDTH-1 (0 to 639)
* Y: 0 to SCREEN_HEIGHT-1 (0 to 479)
*
* If these coordinates spill over, then a glitch will crash the program.
*
* Basically, shift the box over so that it remains in-bounds while retaining one of its coordinates.
*
* The purpose for this is to erase any "residue" that the ball may leave as it is partially off-screen.
*
******************************************************************
               
                move.l  #SCREEN_WIDTH, d6
                subq.l  #1, d6
                cmp.l   d6, d1
                ble     SkipMaxX
               
* If the right-most side of the box is greater than screenwidth, slide box left.
               
                move.l  #SCREEN_WIDTH, d1
                subq.w  #1, d1
                move.l  d1, d3
                sub.l   #BALL_HALF_WIDTH_HEIGHT, d3
                sub.l   #BALL_HALF_WIDTH_HEIGHT, d3
                subq.l  #PEN_WIDTH, d3
               
SkipMaxX:       cmp.l   #0, d4
                bpl     SkipMaxY
               
* If the upper-most side of box is less than zero (above the screen), slide box down.
               
                move.l  0, d4
                move.l  #BALL_HALF_WIDTH_HEIGHT, d2
                add.l   #BALL_HALF_WIDTH_HEIGHT, d2
                addq.l  #PEN_WIDTH, d2
               
SkipMaxY:       move.l  #SCREEN_HEIGHT, d7
                subq.l  #1, d7
                cmp.l   d7, d2
                ble     SkipMinY
               
* If the bottom of the box is greater than SCREEN_HEIGHT (below the screen), slide box up.
               
                move.l  #SCREEN_HEIGHT, d2
                subq.l  #1, d2
                move.l  d2, d4
                sub.l   #BALL_HALF_WIDTH_HEIGHT, d4
                sub.l   #BALL_HALF_WIDTH_HEIGHT, d4
                subq.l  #PEN_WIDTH, d4
               
* Note there is no method to slide the box to the right because,
* in theory, the ball should never touch the left side of the screen!!

SkipMinY:       lea     OffsetX, a0
                move.w  d3, (a0)
               
                lea     OffsetY, a0
                move.w  d4, (a0)
               
                lea     ImageXMin, a0
                move.w  d3, (a0)
               
                lea     ImageYMin, a0
                move.w  d4, (a0)
               
                lea     ImageXMax, a0
                move.w  d1, (a0)
               
                lea     ImageYMax, a0
                move.w  d2, (a0)
               
* Clear registers just to be safe.
               
                jsr     ClearAll
               
* Call Background data, set diagonal fix to 1, draw our picture, and return to loop.
               
                lea     BGData, a0
                lea     DiagonalFix, a1
                move.b  #1, (a1)    
               
                jsr     DrawPicture
                rts
               


******************************************************************
*
* ERADICATE BALL.
*
* Removes the ball from play and increments the shot counter by one.
*
* Called when the ball crosses the BallCheck planes (hits left/bottom of screen)
* or when it hits the "fail zone" part of the net.
*
******************************************************************
               
EradicateBall:  jsr     BlotOutBall

                lea     BallIsThrown, a0
                lea     CurBallVelocity, a1
                lea     BallMoveDown, a2
                lea     CurrentNumber, a3
                lea     CurBallCoord, a5
               
* Set BallIsThrown, BallMoveDown, Velocities, and Coordinates to ZERO.
               
                move.b  #0, (a0)
                move.l  #0, (a1)+
                move.l  #0, (a1)
                move.b  #0, (a2)
                move.l  #0, (a5)+
                move.l  #0, (a5)
               
* Increment the number of total number of thrown balls in our CurrentNumber array of bytes.
               
                addq.w  #3, a3
                move.b  (a3), d0
                addq.w  #1, d0
                move.b  d0, (a3)
               
* Should the number of shots equal ten, change the LED counter to read "10."

                cmpi.b  #10, (a3)
                bne     ContEradication
               
                move.b  #0, (a3)
                subq.w  #1, a3
                move.b  #1, (a3)
                lea     GameOver, a4
                move.b  #1, (a4)
               
* Clear registers, redraw the player, then return to loop.
               
ContEradication:jsr     ClearAll
                jsr     DrawPlayer
                rts



******************************************************************
*
* DRAW PLAYER.
*
* Sets up the parameters for DrawPicture in order to draw our Basketball Player (Shaq).
*
* Is not called every loop iteration.  Called when the player moves forwards, backwards, or when a ball is eradicated.
*
******************************************************************

DrawPlayer:     lea     OffsetX, a0
                lea     OffsetY, a1
                lea     ImageXMin, a2
                lea     ImageYMin, a3
                lea     ImageXMax, a4
                lea     ImageYMax, a5
               
* Call our six vital parameters.
* Get the Player's X-offset.
               
                lea     PlayerXOffset, a6
               
                move.w  (a6), d0
               
                move.w  #SCREEN_HEIGHT, d1
                sub.w   #PLAYER_HEIGHT, d1
                subq.w  #1, d1
               
                move.w  #PLAYER_WIDTH, d2
                subq.w  #1, d2
               
                move.w  #PLAYER_HEIGHT, d3
                subq.w  #1, d3
               
               
               
******************************************************************
*
* The parameters are fairly straightforward.
*
* X-Offset: PlayerXOffset.
* Y-Offset: ScreenHeight - PlayerHeight - 1.
* ImageXMin: 0
* ImageYMin: 0
* ImageXMax: PlayerWidth - 1.
* ImageYMax: PlayerHeight - 1.
*
******************************************************************
               
                move.w  d0, (a0)
                move.w  d1, (a1)
                move.w  #0, (a2)
                move.w  #0, (a3)
                move.w  d2, (a4)
                move.w  d3, (a5)
               
* Clear registers.

                jsr     ClearAll
               
* Set our a0 pointer to PlayerData.  Set DiagonalFix to 0.
               
                lea     PlayerData, a0
                lea     DiagonalFix, a1
                move.b  #0, (a1)
               
* Draw our player on screen.  THEN draw the arm (yellow stick denoting angle).  Return to loop.
               
                jsr     DrawPicture
                jsr     DrawArm
                jsr     ClearAll
                rts
               
               
               
******************************************************************
*
* DRAW ARM.
*
* Draws the yellow line/stick that denotes the ball's throwing angle.
*
* Is only called by the GetInput and DrawPlayer methods.
*
******************************************************************

DrawArm:        move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #YELLOW, d1
                trap    #15
               
                move.w  #DRAW_LINE_TRAP_CODE, d0
               
                lea     PlayerXOffset, a0
                move.w  (a0), d1
                add.w   #PLAYER_WIDTH, d1
               
                move.w  #SCREEN_HEIGHT, d2
                sub.w   #PLAYER_HEIGHT, d2
               
* The line's first coordinate is always relative to the PlayerXOffset.
               
                lea     CurrentAngle, a0
                lea     Cosine, a1
                lea     Sine, a2
               
* Get the CurrentAngle and use it to determine our line's second coordinate.
* Clear registers to pave way for our multiplication.

                clr.l   d3
                clr.l   d4
                clr.l   d5
                clr.l   d6
                clr.l   d7
               
* Add to the pointers to derive the sine/cosine values we need.

                move.b  (a0), d5
                mulu.w  #2, d5
                add.w   d5, a1
                add.w   d5, a2
               
* Multiply the line's width & height to determine the second coordinate position.
               
                move.l  #ARM_LENGTH, d3
                move.w  (a1), d6
                mulu.w  d6, d3
                asr.l   #8, d3
                asr.l   #4, d3
                add.w   d1, d3
               
                move.l  #ARM_LENGTH, d7
                move.w  (a2), d6
                mulu.w  d6, d7
                asr.l   #8, d7
                asr.l   #4, d7
                move.w  d2, d4
                sub.w   d7, d4
               
* Then, shift our coordinates down & to the right right by our player "cannon."
               
                add.w   #ARM_HEIGHT_FROM_TOP, d2
                add.w   #ARM_HEIGHT_FROM_TOP, d4
                sub.w   #ARM_WIDTH_INWARDS, d1
                sub.w   #ARM_WIDTH_INWARDS, d3
               
* Draw line, clear registers, return to loop.
               
                trap    #15
               
                jsr     ClearAll
                rts
               
               
               
******************************************************************
*
* DRAW ARM CLEAR.
*
* Like the ball, net, and player, the arm draws over the background image and needs to be blotted out everytime it moves.
*
* Blot out a rectangle according to the arm's reach.
*
* Called by the GetInput function.
*
******************************************************************

* Get XOffset.  Determine arm's first X-coordinate: PlayerXOffset + Player_Width - Arm_Width_Inwards - 1.

DrawArmClear:   lea     OffsetX, a0
                lea     PlayerXOffset, a1
                move.w  (a1), d0
                add.w   #PLAYER_WIDTH, d0
                sub.w   #ARM_WIDTH_INWARDS, d0
                subq.w  #1, d0
                move.w  d0, (a0)
               
* Get OffsetY.  Determine arm's first Y-coordinate: Screen_Height - Player_Height + Arm_Height_From_Top - 1.
               
                lea     OffsetY, a0
                move.w  #SCREEN_HEIGHT, d1
                sub.w   #PLAYER_HEIGHT, d1
                add.w   #ARM_HEIGHT_FROM_TOP, d1
                move.w  d1, d2
                sub.w   #ARM_LENGTH, d1
                subq.w  #1, d1
                move.w  d1, (a0)
               
* ImageXMin = XOffset.
               
                lea     ImageXMin, a0
                move.w  d0, (a0)
               
* ImageYMin = YOffset.
               
                lea     ImageYMin, a0
                move.w  d1, (a0)
               
* ImageXMax = XOffset + Arm_Length + 1.
* It is necessary to increment ImageXMax and ImageYMax by one to accomodate for pen thickness.
               
                lea     ImageXMax, a0
                add.w   #ARM_LENGTH, d0
                addq.w  #1, d0
                move.w  d0, (a0)
               
* ImageYMax = YOffset + Arm_Length + 1.
               
                lea     ImageYMax, a0
                addq.w  #1, d2
                move.w  d2, (a0)
               
* Clear Registers, draw picture, and return to loop
               
                jsr     ClearAll
                lea     BGData, a0
                lea     DiagonalFix, a1
                move.b  #1, (a1)
               
                jsr     DrawPicture
                rts
               
               

******************************************************************
*
* DRAW POWER BAR.
*
* A black bar on the upper-left side of the screen that contains a pulsating red bar.
*
* Press Space to convey the amount of power in the bar to the ball's initial velocity.
*
* Longer the red bar = faster the ball is thrown.
*
* The bar is updated every frame EXCEPT when the ball is in the air (BallIsThrown = 1).
*
******************************************************************     
         
DrawPowerBar:   lea     BallIsThrown, a0
                move.b  (a0), d0
                cmp     #1, d0
                bne     ContPowerBar
                rts
               
* CurPowerBar is a three-byte fixed-point float that ranges from $0 to $1FFFF.
               
* Get our time interval and Power Bar Inc Rate.  The greater the time interval, the more to raise the power bar meter.

ContPowerBar:   lea     CurPowerBar, a0
                lea     CurTimeInterval, a1
                move.l  (a0), d1
                move.l  (a1), d3
                clr.l   d2
                move.w  #POWER_BAR_INC_RATE, d2
               
* Multiply to determine how much to increment our Power Bar.
               
                mulu.w  d2, d3
                add.l   d3, d1
                move.l  d1, d4
               
* Shift right 3 bytes to accomodate for decimal places.
               
                asr.l   #8, d4
                asr.l   #4, d4
               
* Compare our power bar with the max possible power value.
* If greater than the max, then subtract so that it goes back to zero.
               
                cmp.l   #POWER_BAR_MAX, d4
               
                ble     SkipSetToZero
               
                move.l  #POWER_BAR_MAX, d5
                asl.l   #8, d5
                asl.l   #4, d5
                sub.l   d5, d1
               
* Draw the black box first.
               
SkipSetToZero:  move.l  d1, (a0)

                move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #BLACK, d1
                trap    #15
                move.w  #FILL_COLOR_TRAP_CODE, d0
                trap    #15
               
                clr.l   d1
               
                move.w  #DRAW_RECTANGLE_TRAP_CODE, d0
               
* Length, height, & offsets are determined by constants.
               
                move.w  #POWER_BAR_X_OFFSET, d1
                move.w  #POWER_BAR_X_OFFSET, d3
                move.w  #POWER_BAR_Y_OFFSET, d2
                move.w  #POWER_BAR_Y_OFFSET, d4
               
                add.w   #POWER_BAR_WIDTH, d3
                add.w   #POWER_BAR_HEIGHT, d4
               
                trap    #15
              
* Now draw the red box.

                move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #RED, d1
                trap    #15
                move.w  #FILL_COLOR_TRAP_CODE, d0
                trap    #15
               
                clr.l   d1
                move.w  #POWER_BAR_X_OFFSET, d1
               
                move.w  #DRAW_RECTANGLE_TRAP_CODE, d0
               
* The red bar's length is determined by our CurPowerBar variable.
               
                addq.w  #5, d1
                subq.w  #5, d3
                subq.w  #5, d4
               
                move.l  (a0), d5
                asr.l   #8, d5
                asr.l   #4, d5
               
                move.w  d4, d2
                sub.w   d5, d2
               
                trap    #15
               
* Draw stuff and return as usual.
               
                jsr     ClearAll
                rts
               


******************************************************************
*
* DRAW NUMBER BOX.
*
* First, draws the blue box in the upper right corner.
*
* Then draws the four numbers representing our score (Format: "00/00").
* At least two numbers will be visible at anytime.
*
* Finally draws a white line that represents the slash/fraction sign in between the numbers.
*
******************************************************************  
               
DrawNumberBox:  move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #BLACK, d1
                trap    #15
                move.w  #FILL_COLOR_TRAP_CODE, d0
                trap    #15
               
* Draw the border box.  Use the constants set above.  Very straightforward.

                move.w  #DRAW_RECTANGLE_TRAP_CODE, d0
                move.w  #SCREEN_WIDTH, d1
                move.w  #0, d2
                move.w  #SCREEN_WIDTH, d3
                sub.w   #SCOREBOX_WIDTH, d3
                subq.w  #SCOREBOX_BORDER_WIDTH, d3
                move.w  #SCOREBOX_HEIGHT, d4
                addq.w  #SCOREBOX_BORDER_WIDTH, d4
                trap    #15
               
                move.l  d1, d5
               
* Then draw the actual box itself.
               
                move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #GREEN, d1
                trap    #15
                move.w  #FILL_COLOR_TRAP_CODE, d0
                trap    #15
               
                move.l  d5, d1
               
                move.w  #DRAW_RECTANGLE_TRAP_CODE, d0
               
                subq.w  #SCOREBOX_BORDER_WIDTH, d4
                addq.w  #SCOREBOX_BORDER_WIDTH, d3

                trap    #15
               
* Reference CurrentNumber array.  Then draw our numbers and the number line.

                jsr     ClearAll
               
                lea     CurrentNumber, a6
                jsr     DrawNumbers    
                jsr     DrawNumLine
                jsr     ClearAll
                rts
               
               
               
******************************************************************
*
* DRAW NUMBERS.
*
* Called after the green number box is drawn.
*
* Four numbers drawn LED-style to represent the number of points scored & total shots.
*
* Which numbers to draw are dictated in the four-byte array CurrentNumber.
*
* Get the values from CurrentNumber and draw them.  0 thru 9 draws the cooresponding LED number.  10 means draw nothing.
*
* NumberSwitch is our BitValues we use to draw which number (ex. $7E = 01111110 = "0").
*
* XNum and YNum are arrays that contain the coordinates of lines to draw.
*
* Go through the NumberSwitch value.  Shift right one bit.  If a 1 drops, draw a line.  If a 0 drops, don't draw a line.
*
******************************************************************  
               
DrawNumbers:    lea     NumberSwitch, a0
                lea     XNum, a1
                lea     YNum, a2
                move.b  (a6), d5
                add.l   d5, a0
                move.b  (a0), d5
                move.b  #SEVEN_LINE_LCD, d6               
                addq.w  #1, a6
                addq.w  #1, d7
                jsr     DrawNumberBegin
               
* Each number you draw must be moved over to the right by so much (Number_Increment).
               
                add.w   #NUMBER_INCREMENT, a3
               
* Once we've plowed through our four numbers, exit function.

                cmp     #NUMBER_OF_NUMBERS, d7
               
* Loop DrawNumbers four times (one for each digit).
               
                bne     DrawNumbers
                rts
               


******************************************************************
*
* DRAW NUMBER BEGIN.
*
* Run through this function seven times per number (one for each possible line).
*
* If our shift drops a 1, draw a line.
* Otherwise, don't draw a line.
* Regardless, increment XNum and YNum to get our next line coordinates.
*
******************************************************************

DrawNumberBegin:asr     #1, d5
             
                bcc     DontDrawNumber
                bra     DrawNumber
               
               
               
******************************************************************
*
* Draw          766666665       Byte Format: 0765, 4321
* Order         7       5
*               7       5
*               7       5
*               7       5
*               211111114
*               2       4
*               2       4
*               2       4
*               233333334
*
******************************************************************  
                       
DrawNumber:     move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #WHITE, d1
                trap    #15
               
* Get the coordinates from XNum and YNum.  Then draw the white line.
               
                move.w  #DRAW_LINE_TRAP_CODE, d0
                move.w  (a1)+, d1
                move.w  (a2)+, d2
                move.w  (a1), d3
                move.w  (a2), d4

                add.w   a3, d1
                add.w   a3, d3
               
                trap    #15
               
                subq.b  #1, d6
                cmp     #0, d6
               
                bne     DrawNumberBegin
                rts
               
DontDrawNumber: addq.w  #2, a1
                addq.w  #2, a2
               
* No line to draw but increment the pointers anyway.
               
                subq.b  #1, d6
                cmp     #0, d6
               
                bne     DrawNumberBegin
                rts
               
               
               
******************************************************************
*
* DRAW NUM LINE.
*
* Called after drawing the numbers.  Simply draws the slash between Numbers 2 & 3.
*
******************************************************************  
               
DrawNumLine:    move.w  #PEN_COLOR_TRAP_CODE, d0
                move.l  #WHITE, d1
                trap    #15
               
                move.w  #DRAW_LINE_TRAP_CODE, d0
                move.w  #SCOREBOX_WIDTH, d5
                divu.w  #2, d5
                move.w  d5, d6
                addq.w  #5, d5
                subq.w  #5, d6
                move.w  #SCREEN_WIDTH, d1
                move.w  #SCREEN_WIDTH, d3
                sub.w   d5, d1
                sub.w   d6, d3
                move.w  #35, d2
                move.w  #5, d4
                trap    #15
                rts
               


******************************************************************
*
* CLEAR ALL.
*
* Short function called to set all registers (except a7) to zero.
*
* Spares us the confusions of figuring out which registers must be reset to 0.
*
******************************************************************  
               
ClearAll:       clr.l   d0
                clr.l   d1
                clr.l   d2
                clr.l   d3
                clr.l   d4
                clr.l   d5
                clr.l   d6
                clr.l   d7
                move.l  #0, a0
                move.l  #0, a1
                move.l  #0, a2
                move.l  #0, a3
                move.l  #0, a4
                move.l  #0, a5
                move.l  #0, a6
                rts
               
               
               
******************************************************************
* END OF CODE.
******************************************************************
               
End:            STOP    #$2000



******************************************************************
* Parameters pertaining to DrawPicture.
******************************************************************

OffsetX         dc.w    0
OffsetY         dc.w    0
ImageXMin       dc.w    0
ImageXMax       dc.w    639
ImageYMin       dc.w    0
ImageYMax       dc.w    479



******************************************************************
* Parameter for DrawPlayer.
******************************************************************

PlayerXOffset   dc.w    0



******************************************************************
* Parameters for DrawNet.
******************************************************************

NetXOffset      dc.l    $200000
NetMoveBackward dc.b    1



******************************************************************
* Parameters for GetTime.
******************************************************************

OldTime         dc.l    $0
CurTimeInterval dc.l    $0



******************************************************************
* Parameters pertaining to ball & DrawBall.
******************************************************************

BallIsThrown    dc.b    0
CurBallCoord    dc.l    $8000, $8000
CurBallVelocity dc.l    $0000, $0000
BallMoveDown    dc.b    0



******************************************************************
* Parameters pertaining to DrawPowerBar.
******************************************************************

CurPowerBar     dc.l    $000000



******************************************************************
* Parameter affecting arm angle & ball initial velocty.
******************************************************************

CurrentAngle    dc.b    45



******************************************************************
* Parameter that corrects glitch when drawing Player Picture.
******************************************************************

DiagonalFix     dc.b    1



******************************************************************
* Parameters pertaining to LED/Number drawing.
* NOTE: XNum2 is not directly referred to although its values are.
******************************************************************

CurrentNumber   dc.b    10, 0, 10, 0
NumberSwitch    dc.b    $7E, $18, $37, $3D, $59, $6D, $6F, $38, $7F, $79, $00
XNum            dc.w    (SCREEN_WIDTH-NUM_DIST_FROM_RIGHT+10), (SCREEN_WIDTH-NUM_DIST_FROM_RIGHT), (SCREEN_WIDTH-NUM_DIST_FROM_RIGHT), (SCREEN_WIDTH-NUM_DIST_FROM_RIGHT+10)
XNum2           dc.w    (SCREEN_WIDTH-NUM_DIST_FROM_RIGHT+10), (SCREEN_WIDTH-NUM_DIST_FROM_RIGHT+10), (SCREEN_WIDTH-NUM_DIST_FROM_RIGHT), (SCREEN_WIDTH-NUM_DIST_FROM_RIGHT)
YNum            dc.w    20, 20, 30, 30, 20, 10, 10, 20



******************************************************************
* Parameter denoting game over condition.
******************************************************************

GameOver        dc.b    0



******************************************************************
* Parameter which eradicates ball when crossing certain plane.
******************************************************************

BallCheck       dc.l    (SCREEN_WIDTH+OFFSCREEN_BUFFER), (SCREEN_HEIGHT+OFFSCREEN_BUFFER)
               


******************************************************************
* Sine Chart (it's not a table, I'm sorry).
******************************************************************
               
Sine            dc.w    $000
Sine1           dc.w    $047,     $08E,     $0D6,     $11D,     $164,     $1AC,     $1F3,     $23A,     $280,     $2C7
Sine2           dc.w    $30D,     $353,     $399,     $3DE,     $424,     $469,     $4AD,     $4F1,     $535,     $578
Sine3           dc.w    $5BB,     $5FE,     $640,     $681,     $6C3,     $703,     $743,     $782,     $7C1,     $7FF
Sine4           dc.w    $83D,     $87A,     $8B6,     $8F2,     $92D,     $967,     $9A1,     $9D9,     $A11,     $A48
Sine5           dc.w    $A7F,     $AB4,     $AE9,     $B1D,     $B50,     $B82,     $BB3,     $BE3,     $C13,     $C41
Sine6           dc.w    $C6F,     $C9B,     $CC7,     $CF1,     $D1B,     $D43,     $D6B,     $D91,     $DB6,     $DDB
Sine7           dc.w    $DFE,     $E20,     $E41,     $E61,     $E80,     $E9D,     $EBA,     $ED5,     $EEF,     $F08
Sine8           dc.w    $F20,     $F37,     $F4D,     $F61,     $F74,     $F86,     $F97,     $FA6,     $FB4,     $FC1
Sine9           dc.w    $FCD,     $FD8,     $FE1,     $FE9,     $FF0,     $FF6,     $FFA,     $FFD,     $FFF,     $1000



******************************************************************
* Cosine Chart (not a table).
******************************************************************

Cosine          dc.w    $1000
Cosine1         dc.w    $FFF,     $FFD,     $FFA,     $FF6,     $FF0,     $FE9,     $FE1,     $FD8,     $FCD,     $FC1
Cosine2         dc.w    $FB4,     $FA6,     $F97,     $F86,     $F74,     $F61,     $F4D,     $F37,     $F20,     $F08
Cosine3         dc.w    $EEF,     $ED5,     $EBA,     $E9D,     $E80,     $E61,     $E41,     $E20,     $DFE,     $DDB
Cosine4         dc.w    $DB6,     $D91,     $D6B,     $D43,     $D1B,     $CF1,     $CC7,     $C9B,     $C6F,     $C41
Cosine5         dc.w    $C13,     $BE3,     $BB3,     $B82,     $B50,     $B1D,     $AE9,     $AB4,     $A7F,     $A48
Cosine6         dc.w    $A11,     $9D9,     $9A1,     $967,     $92D,     $8F2,     $8B6,     $87A,     $83D,     $800
Cosine7         dc.w    $7C1,     $782,     $743,     $703,     $6C3,     $681,     $640,     $5FE,     $5BB,     $578
Cosine8         dc.w    $535,     $4F1,     $4AD,     $469,     $424,     $3DE,     $399,     $353,     $30D,     $2C7
Cosine9         dc.w    $280,     $23A,     $1F3,     $1AC,     $164,     $11D,     $0D6,     $08E,     $047,     $000



******************************************************************
* Shaquille O'Neal bitmap data.
******************************************************************

PlayerData      INCBIN  "shaq.bmp"



******************************************************************
* Background B-Ball Court bitmap data.
******************************************************************
               
BGData          INCBIN  "basketballcourt.bmp"



******************************************************************
* The true end, STOP READING NOW.
******************************************************************
               
        END     START  
       
       
       
* ERIC ________________

No comments:

Post a Comment