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 ________________
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