Vectrex: VPong

vec_vpong

This was my first try to write some code for the vectrex.

It is a very simple rendition of the old Pong game, done in only a few hours. It shows in simple terms how to get a vectrex game running.

Here the full documented source (apart from the include file of OS-Routine names):
(oh well, even with “PRE” tags the source looks rather crappy…)
(BIN: VPONG.BIN)

 

; this game was written on 08.02.1998 by Malban
; it is public domain
;
; comments and vectrex talk are welcome
; my email: xxx@aol.com
;
;
; followin command line was used to assemble:
;
; C:>as09.exe -h0 -l -cti vpong.asm >error
;
; I used the 6809 assembler:
; as09 [1.11].
; Copyright 1990-1994, Frank A. Vorstenbosch, Kingswood Software.
; Available at:
; http://www.falstaff.demon.co.uk/cross.html
;
;
;
; load rom function names...
 INCLUDE "VECTREX.I"
; user variable definitions
;$c890
user_ram EQU $c890
music_active EQU user_ram
paddle_pos EQU music_active + 2
paddle_y EQU paddle_pos
paddle_x EQU paddle_y + 1
paddle_speed_y EQU paddle_x + 1
paddle_speed_x EQU paddle_speed_y + 1

ball_pos EQU paddle_speed_x + 1
ball_y EQU ball_pos
ball_x EQU ball_y + 1
ball_speed_y EQU ball_x + 1
ball_speed_x EQU ball_speed_y + 1             ; speed like $hl, low for every round
ball_speed_y_hi EQU ball_speed_x + 1
ball_speed_x_hi EQU ball_speed_y_hi+ 1
ball_speed_y_reset EQU ball_speed_x_hi + 1
ball_speed_x_reset EQU ball_speed_y_reset+ 1
ball_available EQU ball_speed_x_reset + 1     ; high for when next round

game_level EQU ball_available + 1
paddle_check EQU game_level + 1
paddle_increase EQU paddle_check + 1
court1_scale2 EQU paddle_increase + 1
paddle_intensity EQU court1_scale2 + 1
court1_intensity EQU paddle_intensity + 1
difficult_counter EQU court1_intensity +1
difficulty EQU difficult_counter + 1
game_over_intensity EQU difficulty + 1
game_over_scaley EQU game_over_intensity + 1
game_over_scalex EQU game_over_scaley + 1
game_over_ypos EQU (((game_over_scalex + 2)/2)*2)
game_over_xpos EQU game_over_ypos + 1

tmp EQU game_over_xpos + 1
; see bottom of file for further addresses!

;----------
; user defines
; vectrex coordinates use range from -128 to +127
; these top and bottom values are in scale factor $ff
;----------
FALSE EQU (lo(0))
TRUE EQU (lo(1))
SCREEN_TOP EQU (lo($7f))
SCREEN_BOTTOM EQU (lo(-$80))
SCREEN_LEFT EQU (lo(-$80))
SCREEN_RIGHT EQU (lo($7f))
SCREEN_CENTER EQU (lo(0))

NORMAL_TEXT_SIZE EQU $F160
SCORE_TEXT_SIZE EQU $fb30
LETTER_WIDTH EQU (lo(16))
LETTER_HIGHT EQU (lo(16))

PADDLE_WIDTH EQU (lo(20))
PADDLE_HIGHT EQU (lo(5))

PADDLE_X_RIGHT EQU (lo(SCREEN_RIGHT-PADDLE_WIDTH-$10))
PADDLE_X_LEFT EQU (lo(SCREEN_LEFT+$11))

PADDLE_INIT_XPOS EQU (lo(SCREEN_CENTER-(PADDLE_WIDTH/2))) ; center
PADDLE_INIT_YPOS EQU (lo(SCREEN_BOTTOM+($12))) ; bottom of screen plus court1 modification
PADDLE_INIT_POS EQU (PADDLE_INIT_YPOS*256+PADDLE_INIT_XPOS)
PADDLE_INIT_SPEED EQU (lo(2))
PADDLE_INIT_INCREASE EQU (lo(3))
PADDLE_INTENSITY_INIT EQU (lo($7f))

SIZE_OF_WALL1 EQU (lo($70))
COURT1_XPOS EQU (SCREEN_LEFT+$10)
COURT1_YPOS EQU (SCREEN_BOTTOM+$10)
COURT1_POS EQU (COURT1_YPOS*256+(COURT1_XPOS))
COURT1_COMPENSATE EQU (0*256+(-SIZE_OF_WALL1))
COURT1_INTENSITY_INIT EQU (lo($7f))

BALL_SIZE EQU (lo(5))
BALL_INIT_YPOS EQU (lo($6a))
BALL_X_RIGHT EQU (lo(SCREEN_RIGHT-BALL_SIZE-$10))
BALL_X_LEFT EQU (lo(SCREEN_LEFT+$11))

SCORE_YPOS EQU (SCREEN_TOP-8)
SCORE_XPOS EQU (SCREEN_LEFT+8)
LEVEL_YPOS EQU (SCREEN_TOP-8)
LEVEL_XPOS EQU (lo(0-30))
BALLS_YPOS EQU (SCREEN_TOP-8)
BALLS_XPOS EQU (SCREEN_RIGHT-60)
MAX_SPEED EQU (lo(10))

PADDLE_SCALE_INIT EQU (lo($7f))
COURT1_SCALE_INIT1 EQU (lo($ff))
COURT1_SCALE_INIT2 EQU (lo($7f))
DIFFICULT_THRESHOLD EQU (lo(5))
BALLS_PER_GAME EQU (lo('5'))
;***************************************************************************

 ORG 0
; start of vectrex memory with cartridge name...
 DB "g GCE 1998", $80      ; 'g' is copyright sign
 DW music7                 ; music from the rom
 DB $F8, $50, $20, $C8     ; hight, width, rel x, rel y (from 0,0)
 DB "VECTREX PONG", $80    ; some game information, ending with $80
 DB $F8, $50, -$0, -$70    ; hight, width, rel x, rel y (from 0,0)
 DB "g CHRISTOPHER SALOMON", $80; some game information, ending with $80
 DB 0                      ; end of game header
;***************************************************************************
; here the cartridge program starts off
entry_point:
new_game:
 JSR init_screen           ; startup screen
 JSR init_vars             ; initialize game variables
main_loop:
 JSR do_my_sound           ; do own sound stuff
 JSR Wait_Recal            ; sets dp to d0, and pos at 0, 0
 JSR Do_Sound              ; play sound via rom
 JSR draw_court            ; draw the court
 ; note: the paddle drawing could be optimized,
 ; since the bottom line of the paddle should
 ; have the same y position as there would be
 ; left after drawing the court
 ; for now the pen position is moved back to zero
 ; and the paddle is drawn independently
 JSR draw_paddle
 JSR draw_ball
 JSR draw_strings
 LDA no_balls             ; test for game over
 CMPA #'0'                ; when balls are zero
 BEQ game_lost            ; than game lost
 BRA main_loop            ; start another round
;***************************************************************************
game_lost:
 ; do some extro
 CLRA ; clear A
 STA game_over_intensity  ; and store in intensity
 STA game_over_scalex     ; scale x
 STA game_over_scaley     ; scale y
 STA game_over_ypos       ; pos y
 STA game_over_xpos       ; pos x of game over string
                          ; the next instructions initialize a new sound
 LDA #$01                 ; load #1
 STA Vec_Music_Flag       ; set this as marker for music start
 LDU #musicb              ; load a music structure
 STU music_active         ; and store it to my own music active pointer
                          ; next a do_my_sound and than do sound must be called
game_over_loop1:
 JSR do_my_sound          ; do own sound stuff
 JSR Wait_Recal           ; sets dp to d0, and pos at 0, 0
 JSR Do_Sound             ; do sound stuff
                          ; now print something on screen
 LDA game_over_scaley     ; prepare drawing of game over string
 LDB game_over_scalex     ; load scaling stuff
 STD Vec_Text_HW          ; poke it to ram location
 LDA game_over_intensity  ; load intensity
 JSR Intensity_a          ; set it
 LDA game_over_ypos       ; load position
 LDB game_over_xpos       ; to D (A,B) register
 LDU #game_over_string    ; and the address of the string itself
 JSR Print_Str_d          ; and draw it
                          ; calculate new appearence
 LDA game_over_intensity  ; increase intensity
 ADDA #3                  ; three per step
 STA game_over_intensity  ; store it
 ANDA #$1                 ; every second step increase
 BEQ no_y_scale_now       ; y scale of string
 LDA game_over_scaley     ; load it
 SUBA #1                  ; increase it
 STA game_over_scaley     ; save it
no_y_scale_now:
 LDA game_over_ypos       ; now look at the position of the
 ADDA #2                  ; string, first y pos
 CMPA #$70                ; increase it by two, but not to much
 BLO use_y                ;
 LDA #$70                 ; maximum at $70
use_y:
 STA game_over_ypos       ; store it
 LDA game_over_xpos       ; likewise treat x pos load it
 SUBA #2                  ; decrease it
 CMPA #-$70               ; till -$70
 BGE use_x                ;
 LDA #-$70                ; or use minimum of -$70
use_x:
 STA game_over_xpos       ; store it
 LDA game_over_scalex     ; now do the x scaling
 ADDA #3                  ; every round add 3
 STA game_over_scalex     ; and store it
 LDA game_over_intensity  ; do all this
 CMPA #$7f                ; till intensity is full
 BLO game_over_loop1      ; do the game loop
 JSR Read_Btns            ; get button status once, since only
                          ; differences are noticed
 LDA game_over_scalex     ; now do the x scaling
 SUBA #3                  ; every round add 3
 STA game_over_scalex     ; and store it
game_over_loop2:
 JSR do_my_sound          ; do own sound stuff
 JSR Wait_Recal           ; sets dp to d0, and pos at 0, 0
 JSR Do_Sound             ; do sound stuff
 JSR Intensity_7F         ; draw at full brightness
 LDD #SCORE_TEXT_SIZE
 STD Vec_Text_HW          ; poke it to ram location
 LDA #-$20                ; load position
 LDB #-$30                ; to D (A,B) register
 LDU #score_only_string
 JSR Print_Str_d          ; and draw it
 LDA game_over_scaley     ; prepare drawing of game over string
 LDB game_over_scalex     ; load scaling stuff
 STD Vec_Text_HW          ; poke it to ram location
 LDA game_over_ypos       ; load position
 LDB game_over_xpos       ; to D (A,B) register
 LDU #game_over_string    ; and the address of the string itself
 JSR Print_Str_d          ; and draw it
 JSR Read_Btns            ; get button status
 CMPA #$00                ; is a button pressed?
 BEQ game_over_loop2      ; no, than stay in init_screen_loop
 LDU #Vec_High_Score      ; 'OS' high score
 LDX #no_score_string     ; own last score
 JSR New_High_Score       ; if own was higher, set 'OS' == own
 BRA new_game             ; start a new game
;***************************************************************************
; this routine calculates the new paddle position for only x movement
; expected:dp is allready pointing to d0
; expects coordinates at 0,0
; possibly changes 'paddle_pos'
; nothing is returned
draw_paddle:
 JSR Joy_Digital          ; read joystick positions
 LDB paddle_x             ; load old paddle pos to B
 LDA Vec_Joy_1_X          ; load joystick 1 position X to A
 BEQ no_new_pos           ; no joystick input available
 BMI pos_left             ; joystick moved to left
pos_right:
 CMPB #PADDLE_X_RIGHT     ; is it at maximum right position?
 BEQ no_new_pos           ; if so, do nothing
 ADDB paddle_speed_x      ; increase position with speed faktor
 STB paddle_x             ; and store new position
 CMPB #PADDLE_X_RIGHT     ; compare it again to right border
 BLE new_pos_exit         ; if lower or same (RIGHT) than ok
 LDB #PADDLE_X_RIGHT      ; otherwise use the right
 STB paddle_x             ; border as new position
 BRA new_pos_exit         ; and exit joystick position routine
pos_left:
 CMPB #PADDLE_X_LEFT      ; is it at maximum left position?
 BEQ no_new_pos           ; if so, do nothing
 SUBB paddle_speed_x      ; decrease position with speed faktor
 STB paddle_x             ; and store new position
 CMPB #PADDLE_X_LEFT      ; compare it again to left border
 BGE new_pos_exit         ; if higher or same (LEFT) than ok
 LDB #PADDLE_X_LEFT       ; otherwise use the left
 STB paddle_x             ; border as new position
new_pos_exit:
no_new_pos:
 LDD paddle_pos           ; load current paddle position to D
 JSR Moveto_d             ; move to rel position D
 LDA paddle_intensity     ; load paddle brightness
 JSR Intensity_a          ; switch intensity, Joy_Digital destroys this
 LDX #bottom_paddle       ; address of paddle vector list
 JSR Draw_VLcs            ; Draw vector list
 RTS
;***************************************************************************
; this routine draws the outer court
; expecting dp is allready pointing to d0
; expects coordinates at 0,0
; nothing is returned
draw_court:
 LDA court1_intensity     ; load court1 brightness
 JSR Intensity_a          ; switch intensity
 LDA court1_scale2        ; scale for placing firt point
 STA VIA_t1_cnt_lo        ; move to time 1 lo, this means scaling
 LDD #COURT1_POS          ; first coordinate of COURT 1
 JSR Moveto_d             ; move to rel position D
 LDX #court1              ; address of court vector list
 JSR Draw_VLcs            ; Draw vector list
 LDD #COURT1_COMPENSATE   ; compensates the 'open' court
 JSR Moveto_d             ; move to rel position D
 LDA court1_scale2        ; scale for placing firt point
 STA VIA_t1_cnt_lo        ; move to time 1 lo, this means scaling
 LDB #COURT1_XPOS         ; goes back to
 NEGB                     ; position
 LDA #COURT1_YPOS         ; before court
 NEGA                     ; was drawn
 JSR Moveto_d             ; move to rel position D
 RTS
;***************************************************************************
; this routine moves the ball and draws it
; expecting dp is allready pointing to d0
; expects intensity set to 7f
; nothing is returned
; optimization could easily be done e.g. via direct addressing!
draw_ball:
 LDA ball_available       ; check if there is a ball
 CMPA #FALSE              ; allready in play
 BNE ball_is_available    ; if not
 JSR get_new_ball         ; get a new ball
ball_is_available:        ; now start moving + drawing
                          ; now we change the y position
 LDA ball_speed_y_hi      ; load y speed hi counter
 BEQ no_y_wait            ; if zero, change y pos now
 DECA                     ; decreas high counter
 STA ball_speed_y_hi      ; and store it again
 BRA y_change_done        ; go to where no y change will be done
no_y_wait:
 LDB ball_y               ; change the y position
 ADDB ball_speed_y        ; with the speed factor
 STB ball_y               ; and store it back
 LDA ball_speed_y_reset   ; reset the
 STA ball_speed_y_hi      ; high counter
y_change_done:
                          ; now we change the x position
 LDA ball_speed_x_hi      ; load x speed hi counter
 BEQ no_x_wait            ; if zero, change x pos now
 DECA                     ; decrease high counter
 STA ball_speed_x_hi      ; and store it again
 BRA x_change_done        ; go to where no x change will be done
no_x_wait:
 LDB ball_x               ; change the x position
 ADDB ball_speed_x        ; with the speed factor
 STB ball_x               ; and store it back
 LDA ball_speed_x_reset   ; reset the
 STA ball_speed_x_hi      ; high counter
x_change_done:
                          ; now we check if the ball bounces off a wall
 LDA ball_speed_x         ; in what direction is the ball moving?
 BMI check_left           ; negative, than we check left border
 CMPB #BALL_X_RIGHT       ; ball right out of bounds?
 BLE x_right_ok           ;
 NEG ball_speed_x         ; yes, than change direction
                          ; the next instructions initialize a new sound
 LDA #$01                 ; load #1
 STA Vec_Music_Flag       ; set this as marker for music start
 LDU #PING2               ; load a music structure
 STU music_active         ; and store it to my own music active pointer
                          ; next a do_my_sound and than do sound must be called
check_left:
 CMPB #BALL_X_LEFT        ; ball left out of bounds?
 BGE x_left_ok            ;
 NEG ball_speed_x         ; yes, than change direction
                          ; the next instructions initialize a new sound
 LDA #$01                 ; load #1
 STA Vec_Music_Flag       ; set this as marker for music start
 LDU #PING2               ; load a music structure
 STU music_active         ; and store it to my own music active pointer
                          ; next a do_my_sound and than do sound must be called
x_left_ok:
x_right_ok:               ; x position is OK
 LDA ball_speed_y         ; checking for bottom?
 BPL check_for_upper_border ; or upper border?
                          ; now we check if the ball is hit with paddle (bottom)
 LDB ball_y               ; load y position
 LDA paddle_check         ; is ball allready lost?
 CMPA #FALSE              ; allready lost?
 BEQ allready_lost        ; yep... than don't check again
 SUBB #BALL_SIZE          ; we must look at the bottom edge of the ball
 CMPB #PADDLE_INIT_YPOS   ; compare to paddle y
 BGE nothing_happens      ; if not there, than go on
 LDA paddle_x             ; get the x pos of the paddle
 CMPA ball_x              ; compare to x of ball
 BGE paddle_greater_ball  ; if paddle higher...
paddle_lesser_ball:       ; here paddle smaller than ball
 ADDA #PADDLE_WIDTH       ; check if we have hit the ball
 CMPA ball_x              ; with the body of the paddle
 BLT paddle_not_there     ; no!
 NEG ball_speed_y         ; yep, reflected, change y speed
 BRA ball_reflected       ; and go on
paddle_greater_ball:      ; paddle higher ball
 SUBA #BALL_SIZE          ; take the size of the ball into account
 CMPA ball_x              ; and check again
 BGT paddle_not_there     ; oops, ball seems lost!
 NEG ball_speed_y         ; yep, reflected, change y speed
 BRA ball_reflected       ; and go on
paddle_not_there:
 LDA #FALSE               ; this ball is now lost
 STA paddle_check         ; next time we don't check the paddle
allready_lost:
 CMPB #SCREEN_BOTTOM      ; will ball move off the screen?
 BGT is_roll_over         ; not yet, than go on
get_lost:
 STA ball_available       ; next time a ball is not available
 JSR ball_lost            ; ball is now lost
 RTS                      ; bye!
is_roll_over:
 TSTB                     ; test for
 BMI nothing_happens      ; rollover otherwise do nothing
 BRA get_lost             ; now restart
check_for_upper_border:
                          ; now we check if we are at the upper border
 LDB ball_y               ; load y position
 CMPB #BALL_INIT_YPOS     ; compare upper
 BLE nothing_happens      ; if not there, than go on
 LDA #BALL_INIT_YPOS      ; otherwise use init position
 STA ball_y               ; store it
 NEG ball_speed_y         ; and reflect, using opposite y speed
                          ; the next instructions initialize a new sound
 LDA #$01                 ; load #1
 STA Vec_Music_Flag       ; set this as marker for music start
 LDU #PING2               ; load a music structure
 STU music_active         ; and store it to my own music active pointer
                          ; next a do_my_sound and than do sound must be called
nothing_happens:
draw_ball_on_screen:
 JSR Reset0Ref            ; reset screen position
 LDD ball_pos             ; load position of ball
 JSR Moveto_d_7F          ; move to rel position D and scale factor 7F
 LDX #ball                ; address of ball vector list
 JSR Draw_VLc             ; Draw vector list
 RTS
ball_reflected:
 LDB ball_x               ; load x position of ball again!
 ADDB #(BALL_SIZE/2)      ; and get the center of it
 LDA paddle_x             ; load x position of paddle
 ADDA #(PADDLE_WIDTH/2)   ; and get the center of it
 STA tmp                  ; store ball center
 SUBB tmp                 ; in A now the offset of the
                          ; ball center to the center of
                          ; the paddle
                          ; should be abs(10)
 ASRB                     ; only a quarter should remain
 ASRB                     ;
 LDA difficulty           ; load difficulty setting
 MUL                      ; multiply A*B
 ADDB ball_speed_x        ; and modify the x speed accordingly
 STB ball_speed_x         ; store it
 LDA #1                   ; score 1 for reflecting
 LDX #no_score_string     ; load score address
 JSR Add_Score_a          ; add to score
 LDA #1                   ; score 1 for reflecting
 LDX #no_level_string     ; load level address
 JSR Add_Score_a          ; add to level
 INC game_level           ; add to level
                          ; let's see if we can make it a bit more difficult!
 INC difficult_counter    ; increase counter
 LDA difficult_counter    ; load it
 CMPA #DIFFICULT_THRESHOLD ; and check if new difficult level is reached
 BNE no_difficult_change  ; no, not yet
 INC difficulty           ; difficulty + 1
 CLRA                     ; difficult_counter to zero
 STA difficult_counter    ; store it
 INC ball_speed_y         ; y speed one up :-)
 LDA ball_speed_y         ; load speed to A
 CMPA #MAX_SPEED          ; check if not too fast
 BLE no_speed_overflow    ; do nothing
 LDA #MAX_SPEED           ; store MAX_SPEED
 STA ball_speed_y         ; to ball y speed
no_speed_overflow:
no_difficult_change:
 LDA ball_speed_x         ; load x speed
 CMPA #0                  ; check for 0 speed
 BNE no_x_zero_speed      ; if none zero do nothing
 JSR Random               ; get random
 TFR A,B                  ; copy to B
 ANDB #$1                 ; look at first bit
 CMPB #0                  ; test for zero
 BEQ no_x_speed_change    ; do nothing if zero
 TSTA                     ; positive or negative random?
 BPL change_to_plus1      ; or plus
 LDA #-1                  ; -1
 STA ball_speed_x         ; store x speed
 BRA done_speed_change    ;
change_to_plus1:
 LDA #1                   ; 1
 STA ball_speed_x         ; store x speed
no_x_speed_change:
no_x_zero_speed:
done_speed_change:
 LDA ball_speed_y         ; load y speed of ball
 CMPA paddle_increase     ; and see if paddle should be faster
 BLT no_paddle_speed_change ; no, not yet
 INC paddle_speed_x       ; go faster in x
 LDA paddle_increase      ; and new increase threshold
 ADDA #2                  ; old plus 2
 STA paddle_increase      ; and store
no_paddle_speed_change:
                          ; the next instructions initialize a new sound
 LDA #$01                 ; load #1
 STA Vec_Music_Flag       ; set this as marker for music start
 LDU #PING1               ; load a music structure
 STU music_active         ; and store it to my own music active pointer
                          ; next a do_my_sound and than do sound must be called
 BRA draw_ball_on_screen
;***************************************************************************
; this routine initiates a new ball
; not finnished yet
; nothing is returned
get_new_ball:
 LDA #TRUE                ; next time a ball is
 STA ball_available       ; available
 STA paddle_check         ; next time we check the paddle
 CLRA                     ; start in the middle of screen
 STA ball_x               ; this is the next x position
 LDA #BALL_INIT_YPOS      ; start at top of screen
 STA ball_y               ; this is the next y position
 LDA #-1 ; ball y speed   ; allway negativ, since ball must
                          ; move down!
 STA ball_speed_y         ; not randomized yet
 LDA #0                   ; hi value for y speed for now
 STA ball_speed_y_hi      ; allways zero
 STA ball_speed_y_reset   ; as is the reset value
 JSR Random               ; get random number to A
 ANDA #($3)               ; only the 2 lower bits are needed
 TFR A,B                  ; copy it to A
 JSR Random               ; get random number to A
 TSTA                     ; is it positive?
 BPL positiv_x            ; if so use positiv x speed
 NEGB                     ; else negative
positiv_x:
 STB ball_speed_x         ; now store the speed
 LDA #0                   ; hi value for x speed for now
 STA ball_speed_x_hi      ; allways zero
 STA ball_speed_x_reset   ; as is the reset value
 RTS
;***************************************************************************
ball_lost:
                          ; the next instructions initialize a new sound
 LDA #$01                 ; load #1
 STA Vec_Music_Flag       ; set this as marker for music start
 LDU #ball_lost_sound     ; load a music structure
 STU music_active         ; and store it to my own music active pointer
                          ; next a do_my_sound and than do sound must be called
 LDA court1_scale1        ; just for the loop, might do a bra as a jump into the loop
lost_loop:
 STA court1_scale1        ; store the last changed court 1 scale factor
 JSR do_my_sound          ; do own sound stuff
 JSR Wait_Recal           ; sets dp to d0, and pos at 0, 0
 JSR Do_Sound             ; play sound via rom
 JSR draw_court           ; draw the court
 JSR draw_paddle          ; draw paddle
 JSR draw_strings         ; draw strings (not scaled, should I?)
 LDA court1_scale2        ; load scale value2 of court (for positioning)
 SUBA #3                  ; decrease it
 STA court1_scale2        ; and write it back
 LDA bottom_paddle_scale  ; load scale value of paddle
 SUBA #3                  ; decrease it
 STA bottom_paddle_scale  ; and write it back
 LDA court1_intensity     ; load intensity of court
 SUBA #3                  ; decrease it
 STA court1_intensity     ; and write it back
 LDA paddle_intensity     ; load intensity of paddle
 SUBA #3                  ; decrease it
 STA paddle_intensity     ; and write it back
 LDA court1_scale1        ; load scale value1 of court (for sizing)
 SUBA #6                  ; decrease it
 BCC lost_loop            ; and write it back
 DEC no_balls             ; one ball less
 JSR init_new_ball_vars   ; and reinit all destroyed variables
 RTS
;***************************************************************************
; this routine initializes the game variables
; nothing is expected and nothing is returned
init_vars:
 JSR Init_OS              ; init OS, should allready been done...
 LDU #_copy_start         ; my 'ram' address (source)
 LDX #copy_start          ; copy my 'ram' to vectrex ram (destination)
 LDA #(_copy_end-_copy_start) ; number of bytes to be copied, must be less than $81
 JSR Move_Mem_a           ; and copy...
 LDA #FALSE               ; no ball availabel
 STA ball_available       ; upon startup
 LDA #1                   ; initial game level
 STA game_level           ; upon startup
 LDX #no_score_string     ; get the address of score string
 JSR Clear_Score          ; clear score
 LDA #BALLS_PER_GAME      ; balls 5
 STA no_balls             ; and store five balls
 LDD #PADDLE_INIT_POS     ; load init values
 STD paddle_pos           ; and store them...
init_new_ball_vars:
 LDX #no_level_string     ; get level string
 JSR Clear_Score          ; clear level string
 CLRA                     ; clear level number
 LDA #PADDLE_INIT_SPEED   ; initial paddle speed x
 STA paddle_speed_x       ; and store it
 LDA #PADDLE_INIT_SPEED   ; initial paddle speed y
 STA paddle_speed_y       ; and store it
 LDA #PADDLE_INIT_INCREASE ; set paddle increase
 STA paddle_increase      ; and store
 LDA #COURT1_SCALE_INIT1  ; init value for court scale 1
 STA court1_scale1        ; scale for placing first point
 LDA #COURT1_SCALE_INIT2  ; init value for court scale 2
 STA court1_scale2        ; scale for court size
 LDA #PADDLE_SCALE_INIT   ; init value for paddle size
 STA bottom_paddle_scale  ; paddle scale value
 LDA #PADDLE_INTENSITY_INIT ; set the brightness
 STA paddle_intensity     ; of the paddle
 LDA #COURT1_INTENSITY_INIT ; set the brightness
 STA court1_intensity     ; of the court
 CLRA                     ; difficult to zero
 STA difficult_counter    ; store it
 INCA                     ; difficulty to 1
 STA difficulty           ; store it
 RTS
;***************************************************************************
; this routine draws the initial screen
; with information about the game
; nothing is expected and nothing is returned
init_screen:
 JSR Read_Btns            ; get button status once, since only
                          ; differences are noticed
 LDD #NORMAL_TEXT_SIZE    ; load default text height & width
 STD Vec_Text_HW          ; poke it to ram location
 JSR Intensity_7F         ; draw at full brightness
                          ; the next 5 instructions initialize a new sound
 JSR DP_to_C8             ; set DP...
 LDA #$01                 ; load #1
 STA Vec_Music_Flag       ; set this as marker for music start
 LDU #music4              ; load a music structure
 STU music_active         ; and store it to my own music active pointer
                          ; next a do_my_sound and than do sound must be called
init_screen_loop:
 JSR do_my_sound          ; do own sound stuff
 JSR Wait_Recal           ; sets dp to d0, and pos at 0, 0
 JSR Do_Sound             ; do sound stuff
 LDU #game_name           ; load text start to U
                          ; Get A=Y, B=X (D=AB) coordinate
 LDA #(LETTER_HIGHT/2)    ; Center Text Y
 LDB #(-(LETTER_WIDTH*11)/2) ; Center Text X
 JSR Print_Str_d          ; Print the string
 JSR Read_Btns            ; get button status
 CMPA #$00                ; is a button pressed?
 BEQ init_screen_loop     ; no, than stay in init_screen_loop
exit_init_screen:         ; otherwise proceed
 RTS
;***************************************************************************
; expecting dp is allready pointing to d0
; prints 'score', 'hits' and 'balls'
draw_strings:
 JSR Intensity_7F         ; draw at full brightness
 JSR Reset0Ref            ; reset screen position
 LDU #score_string        ; load text start to U
                          ; Get A=Y, B=X (D=AB) coordinate
 JSR Print_List_hw        ; Print the string
 RTS
;***************************************************************************
; leaves with DP set to C8
; expects music to be initialized
; and pointer in music_active
do_my_sound:
 JSR DP_to_C8             ; set DP to C8
 LDU music_active         ; get active music
 JSR Init_Music_chk       ; and init new notes
 RTS
;***************************************************************************
game_name:
 DB "VECTREX PONG", $80
game_over_string:
 DB "GAME OVER", $80
;***************************************************************************
ball:
 DB 3 ; 4 vectors are drawn
 DB 0, BALL_SIZE         ; next point relativ (y,x)
 DB BALL_SIZE, 0         ; next point relativ (y,x)
 DB 0, -BALL_SIZE        ; next point relativ (y,x)
 DB -BALL_SIZE, 0        ; next point relativ (y,x)
;***************************************************************************
; note: PING1 and PING2 stolen from patriots, hope you don't mind John!
PING1:
 FDB $FD69
 FDB $FD79
 FCB $20,$0A
 FCB 0, $80
;***************************************************************************
PING2:
 FDB $FD69
 FDB $FD79
 FCB $0A,$0A
 FCB 0, $80
;***************************************************************************
ball_lost_sound:
 FDB $FE66,$FEB6
 FCB $07, $12
 FCB $07, $06
 FCB $00, $3C
 FCB $18, $80
;***************************************************************************
; entries following must be copied to vectrex ram...
; start of 'my ram'
_copy_start:
;***************************************************************************
_score_string:
 DB hi(SCORE_TEXT_SIZE)
 DB lo(SCORE_TEXT_SIZE)
 DB SCORE_YPOS, SCORE_XPOS
_score_only_string:
 DB "SCORE:"
_no_score_string:
 DB "000000", $80
_level_string:
 DB hi(SCORE_TEXT_SIZE)
 DB lo(SCORE_TEXT_SIZE)
 DB LEVEL_YPOS, LEVEL_XPOS
 DB "HITS:"
_no_level_string:
 DB "000000", $80
_balls_string:
 DB hi(SCORE_TEXT_SIZE)
 DB lo(SCORE_TEXT_SIZE)
 DB BALLS_YPOS, BALLS_XPOS
 DB "BALLS:"
_no_balls:
 DB BALLS_PER_GAME,$80
_string_list_end:
 DB 0
;***************************************************************************
_bottom_paddle:
 DB 3 ; 4 vectors are drawn
_bottom_paddle_scale:
 DB PADDLE_SCALE_INIT    ; 4 size of paddle
 DB 0, PADDLE_WIDTH      ; next point relativ (y,x)
 DB PADDLE_HIGHT, 0      ; next point relativ (y,x)
 DB 0, -PADDLE_WIDTH     ; next point relativ (y,x)
 DB -PADDLE_HIGHT, 0     ; next point relativ (y,x)
;***************************************************************************
_court1:
 DB 2 ; 3 vectors are drawn
_court1_scale1:
 DB COURT1_SCALE_INIT2   ; size of court
 DB SIZE_OF_WALL1, 0     ; next point relativ (y,x)
 DB 0, SIZE_OF_WALL1     ; next point relativ (y,x)
 DB -SIZE_OF_WALL1, 0    ; next point relativ (y,x)
;***************************************************************************
_copy_end:
;***************************************************************************
; stupid assembler, these defines must be made after the above
; labels
copy_start EQU ((tmp/2)*2 + 100)
score_string EQU (copy_start)
score_only_string EQU (copy_start+(_score_only_string-_copy_start))
no_score_string EQU (copy_start+(_no_score_string-_copy_start))
level_string EQU (copy_start+(_level_string-_copy_start))
no_level_string EQU (copy_start+(_no_level_string-_copy_start))
balls_string EQU (copy_start+(_balls_string-_copy_start))
no_balls EQU (copy_start+(_no_balls-_copy_start))
bottom_paddle EQU (copy_start+(_bottom_paddle-_copy_start))
bottom_paddle_scale EQU (copy_start+(_bottom_paddle_scale-_copy_start))
court1 EQU (copy_start+(_court1-_copy_start))
court1_scale1 EQU (copy_start+(_court1_scale1-_copy_start))
;***************************************************************************
 END entry_point
;***************************************************************************

Leave a Reply

Your email address will not be published. Required fields are marked *