home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
BEEHIVE
/
GAMES
/
CRAM36.ARC
/
CRAM.MAC
< prev
Wrap
Text File
|
1990-07-21
|
24KB
|
932 lines
TITLE'CRAM vs 3.6'
;***********************************************************
;* *
;* PROGRAM NAME: CRAM.MAC *
;* *
;* VERSION : 3.6 08/05/87 *
;* *
;* FUNCTION : Graphics Demonstration Game *
;* *
;***********************************************************
.Z80
ASEG
.SALL
; CP/M FUNCTIONS AND ADDRESSES
BDOS EQU 5 ; SYSTEM CALL ENTRY
WCONF EQU 2 ; WRITE (A) TO CON:
DCON EQU 6 ; DIRECT CONSOLE I/O
CONMOD EQU 06DH ; SET CONSOLE MODE
OPENF EQU 15 ; OPEN A FILE
CLOSF EQU 16 ; CLOSE A FILE AFTER WRITE
WRITF EQU 21 ; WRITE ONE RECORD TO FILE
SETDMA EQU 26 ; SET DMA ADDRESS
SETMSC EQU 44 ; SET MULTI-SECTOR COUNT
TFCB EQU 5CH ; TRANSIENT FCB
FCBCR EQU TFCB+32 ; CURRENT RECORD IN TFCB
VIDEO EQU 0F800H ; START OF VIDEO RAM
POSXY MACRO X,Y ; MACRO FOR DIRECT CURSOR
DB 1BH,3DH ; POSITIONING
DB Y+20H ; 0<=X<=79
DB X+20H ; 0<=Y<=24
ENDM ;
ORG 100H ; TRANSIENT PROGRAM AREA
DBUFF EQU $ ; HIGH SCORE BUFFER
BEGIN: JP INIT ; JUMP OVER HIGH SCORE AREA
REPT 9 ; HIGH SCORE TABLE
DEFB 0,0,' '
ENDM
VOL: DEFB 5 ; VOLUME CONTROL
INIT: LD (CPMSP),SP ; SAVE CP/M STACK
LD SP,STAK ; SET UP LOCAL STACK
LD C,20H ; TURN OFF BONDWELL CURSOR
CALL CURSOR
LD A,R ; SEED RANDOM NUMBER ROUTINE
LD (SEED),A
LD A,R
LD (SEED+1),A
LD C,CONMOD ; SET CONSOLE MODE TO
LD DE,00000010B ; DISABLE ^S
CALL BDOS
; ***** MAIN PROGRAM LOOP *********************************
START: CALL TITLE ; TITLE ROUTINE
CALL SETUP ; SETUP GAME BOARD
CALL PLAY ; PLAY GAME
CALL END ; END OF GAME ROUTINE
JR START ; LOOP BACK
; ***** HIGH LEVEL SUBROUTINES ****************************
TITLE: CALL CLS ; CLEAR SCREEN
CALL PTITLE ; PRINT TITLE
CALL SHWSCR ; AND PREVIOUS SCORE
TITL10: CALL FLASH ; FLASH SCREEN
CALL TONE ; PLAY TONE
LD BC,2800H ; DELAY VALUE
CALL DELAY ; WAIT A BIT
CALL GETENT ; CHECK FOR <RETURN>
JR Z,TITL10 ; LOOP IF NOT PRESSED
CALL GETDIF ; GET DIFFICULTY LEVEL
RET
SETUP: CALL GRPHCL ; CLEAR SCREEN
CALL FRAME ; FRAME SCREEN
LD A,(MODBUF) ; GET MODE
CP 1 ; ? MODE 1
CALL Z,BLOCK ; SETUP OBSTICLES FOR MODE 1
CALL SETCRS ; SET CURSOR AND COUNTER
CALL SET ; DISPLAY STARTING POS.
CALL GAMMSG ; SHOW GAME MESSAGE
SETUP10:
CALL GARR20 ; GET KEYSTROKE
JR Z,SETUP10 ; LOOP UNTIL KEYSTROKE
CALL FRAME ; COMPLETE FRAME AGAIN
RET
PLAY: CALL GETARR ; GET ARROWS PRESSED
CALL FPOSN ; FIND NEW POSITION
CALL POINT ; CHECK IF GAME OVER
RET NZ ; RET TO DRIVE IF IT IS
CALL SET ; DISPLAY NEW POSITION
LD A,(MODBUF) ; CHECK FOR MODE 2
CP 2
CALL Z,BL40 ; SET BLOCK IF IT IS
CALL SCORE ; UPDATE SCORE
CALL SHWSCR ; DISPLAY SCORE
CALL PAUSE ; PAUSE BETWEEN MOVES
JR PLAY ; LOOP BACK AND START OVER
END: LD B,35 ; COUNTER FOR FLASHES
END10: PUSH BC ; SAVE COUNTER
CALL FLASH ; FLASH SCREEN
CALL NOISE ; FUNNY SOUND
POP BC ; GET END COUNTER
DJNZ END10 ; REPEAT 35 TIMES
CALL CLKEY ; CLEAR KEY BUFFER
CALL HSCORE ; CHECK FOR HIGH SCORE
RET
; ***** LOW LEVEL SUBROUTINES *****************************
; MESSAGE POINTED TO BY STACK OUT TO CONSOLE
SPMSG: EX (SP),HL ; GET RETURN ADDRESS TO HL
LD A,(HL) ; GET ONE MESSAGE CHARACTER
OR A ; ?0 END OF STRING
INC HL ; POINT TO NEXT
EX (SP),HL ; RESTORE STACK FOR
RET Z ; RETURN IF DONE
CALL CO ; ELSE DISPLAY CHARACTER
JR SPMSG ; AND DO ANOTHER
; SEND THE CONTENTS OF A TO THE CP/M CON: DEVICE
CO: PUSH BC ; SAVE REGISTERS
PUSH DE
PUSH HL
LD C,WCONF ; SELECT FUNCTION
LD E,A ; CHARACTER TO E
CALL BDOS ; OUTPUT BY CP/M
POP HL
POP DE
POP BC
RET
CLS: CALL SPMSG ; USES CP/M BIOS ROUTINES
DEFB 1BH,2AH,00H ; TO CLEAR THE SCREEN
RET
DELAY: DEC BC
LD A,B ; TEST FOR 0
OR C
JR NZ,DELAY
RET
GRPHCL: LD HL,VIDEO ; BEGINNING OF SCREEN
LD DE,VIDEO+1 ; NEXT SPACE
LD BC,1999 ; # POSITIONS - 1
LD (HL),00 ; SET FIRST POSITION
LDIR ; AND COPY IT
RET
PTITLE: CALL SPMSG ;PRINT TITLE
.XLIST
;1ST LINE OF GRAPHIC "CRAM"
POSXY 20,2
DEFB 32,80H,80H,80H,80H,80H,' ',80H,80H,80H,80H,80H,80H
DEFB ' ',80H,80H,80H,' ',80H,80H,' ',80H,80H
;2ND LINE
POSXY 20,3
DEFB 80H,' ',80H,' ',80H,' ',80H,' ',80H,' '
DEFB 80H,' ',80H,32,80H,' ',80H,32,80H
;3RD LINE
POSXY 20,4
DEFB 80H,' ',80H,' ',80H,' ',80H,' ',80H
DEFB ' ',80H,' ',80H,32,80H,' ',80H
;4TH LINE
POSXY 20,5
DEFB 80H,' ',80H,80H,80H,80H,80H,80H,' ',80H,80H
DEFB 80H,80H,80H,80H,80H,' ',80H,' ',80H,' ',80H
;5TH LINE
POSXY 20,6
DEFB 80H,' ',80H,' ',80H,' ',80H,' ',80H
DEFB ' ',80H,' ',80H,' ',80H
;6TH LINE
POSXY 20,7
DEFB 80H,' ',80H,' ',80H,' ',80H,' ',80H,' '
DEFB 80H,' ',80H,' ',80H,' ',80H
;7TH LINE
POSXY 20,8
DEFB 32,80H,80H,80H,80H,80H,' ',80H,' ',80H,' ',80H
DEFB ' ',80H,' ',80H,' ',80H,' ',80H
;
POSXY 13,10
DEFM 'Version 3.6 for Bondwell 14 by Robert Johanson, 1987'
POSXY 11,11
DEFM 'Originally written by Hardin Brothers (80 Micro 2/84:108)'
POSXY 59,13
DEFM '<RETURN> to play'
POSXY 59,14
DEFM '<ARROWS> for volume'
POSXY 59,15
DEFM ' or <^C> to quit'
POSXY 25,13
DEFM '==>> Previous High Scores <<=='
POSXY 25,14
DEFM 'Level Score Name '
POSXY 25,15
DEFM '=============================='
DEFB 0
.LIST
HSCR: LD B,0 ; PRINT HIGH SCORE TABLE
LD HL,0F800H+1307 ; START OF HIGH SCORE TABLE ON SCREEN
HSC10: PUSH BC
PUSH HL
LD A,B
CALL GD40 ; GET LEVEL OFFSET IN DBUFF
POP HL
POP BC
LD A,B
ADD A,31H ; CONVERT TO ASCII DIFF LEVEL
LD (HL),A ; (1 - 9)
PUSH HL ; SAVE ADDRESS
PUSH BC ; AND LEVEL #
LD DE,08 ; MOVE TO START OF SCORE
ADD HL,DE
PUSH HL ; SAVE ADDRESS OF SCREEN (+10 TO NAME)
PUSH HL
POP IX ; IX POINTS TO RESULT BUFFER
LD IY,PWRTAB ; IY POWER TABLE
LD D,0
LD A,(OFFSET) ; OFFSET FOR CURRENT LEVEL
LD E,A
LD HL,DBUFF
ADD HL,DE ; HL POINTS TO SCORE POSITION IN FILE BUFFER
PUSH HL ; SAVE ADDRESS (+2 TO NAME)
LD E,(HL)
INC HL
LD D,(HL)
EX DE,HL
CALL XLA10 ; TRANSLATE SCORE TO ASCII
POP BC
INC BC
INC BC
LD HL,10
POP DE
ADD HL,DE
EX DE,HL
PUSH BC
POP HL
LD BC,26
LDIR
POP BC ; LEVEL # IN B:
POP HL ; READY FOR NEXT ADDRESS
INC B ; NEXT LEVEL
LD A,9
CP B
RET Z ; IF B=9 THEN FINISHED
LD DE,80 ; OTHERWISE POINT TO NEXT
ADD HL,DE
JR HSC10 ; AND GO AGAIN
HSCORE: LD DE,DBUFF ; CHECK SCORE AGAINST HIGH SCORE
LD H,0
LD A,(OFFSET) ; FOR THAT LEVEL
LD L,A
ADD HL,DE ; ADDRESS OF HIGH SCORE
PUSH HL
LD E,(HL) ; DE = HIGH SCORE
INC HL
LD D,(HL)
EX DE,HL ; NOW HL
LD BC,(SCRBUF) ; SCORE IN BC
OR A ; CLEAR CARRY
SBC HL,BC ; COMPARE NEW WITH OLD
POP HL ; ADDRESS OF HIGH SCORE
RET NC ; NOT HIGHER - RETURN
LD (HL),C ; SAVE NEW SCORE IN DBUFF
INC HL
LD (HL),B
INC HL ; HL->ADDRESS OF NAME IN DBUFF
PUSH HL ; SAVE ON STACK
LD A,0FFH ; SET HSCORE CHANGED FLAG
LD (SCRFLAG),A
CALL CLS ; CLEAR SCREEN
CALL SPMSG ; PRINT MESSAGE
.XLIST
POSXY 6,5
DEFM 'Congratulations.... You have just become a World'
DEFM ' Champion CRAMMER !!!'
POSXY 16,7
DEFM 'Enter your name for the Official Hall of Fame :'
POSXY 27,9
DEFM '=========================='
POSXY 22,10
DEFM '(max 26 characters, CP/M 3 editing)',0DH,0AH
POSXY 25,8
DEFM '->',0
.LIST
LD C,60H ; TURN ON CURSOR FOR INPUT
CALL CURSOR
LD DE,CONBUFF ; GET NAME USING
LD C,0AH ; READ CONSOLE BUFFER FUNCTION
CALL BDOS
LD C,20H ; TURN CURSOR OFF AGAIN
CALL CURSOR
POP DE ; ADDRESS IN DBUFF FOR NAME
LD HL,CONBUFF+2 ; CONBUFF INPUT
LD B,0
LD A,(CONBUFF+1) ; GET # CHARACTERS INPUT
LD C,A ; INTO BC
OR A ; ? 0 CHARACTERS (LDIR DOESN'T LIKE
JR Z,HS05 ; BC OF 0). JUST PAD WITH SPACES
PUSH BC ; SAVE FOR RON
LDIR ; MOVE TO DBUFF POSITION
POP BC
HS05: LD A,26 ; MAX NUMBER IN NAME
SUB C ; GET NUMBER TO FILL
RET Z ; C=26, NO NEED TO FILL
LD B,A
LD A,32
HS10: LD (DE),A ; FILL WITH SPACES
INC DE
DJNZ HS10 ; GO UNTIL B=0
RET ; THEN RETURN
CLKEY: CALL GETKEY
JR NZ,CLKEY
CLK01: LD C,11 ; CLEAR ANY LEFT OVER ARROW KEYS
CALL BDOS
OR A
RET Z ; NO MORE KEYS - RETURN
LD C,01 ; KEY STILL THERE - GET IT
CALL BDOS
JR CLK01 ; CHECK FOR ANY MORE
FLASH: LD BC,2000 ; # CHARS ON SCREEN
LD HL,VIDEO ; HL = BEGINNING OF SCREEN
FL10: LD A,(HL) ; GET CHAR FROM SCREEN
BIT 7,A ; IS IT HIGH OR LOW
JR Z,FL20 ; LOW ==> HIGH
RES 7,A ; HIGH ==> LOW
JR FL30
FL20: SET 7,A
FL30: LD (HL),A
INC HL ; STORE INVERTED CHAR
DEC BC ; TEST FOR END OF SCREEN
LD A,B
OR C
RET Z
JR FL10
TONE: LD IX,(TONPTR) ; IX==>NEXT TONE VALUE
LD A,(IX) ; GET VALUE
OR A ; SET FLAGS
JR NZ,TONE10 ; GO IF NOT ZERO
LD IX,TONTOP ; ELSE = TOP OF LIST
TONE10: CALL MAKTON ; MAKE THE TONE
INC IX ; BUMP POINTER
INC IX ; TWICE
LD (TONPTR),IX ; AND SAVE IT
RET ; RET TO CALLER
MAKTON: DI ; TURN OFF INTERRUPTS
LD C,(IX) ; DURATION IN C
MAK10: LD B,(IX+1) ; GET FREQ VALUE
LD A,(VOL) ; VARIABLE VOLUME
OUT (50H),A ; AUDIO REGISTER
MAK20: DJNZ MAK20 ; DELAY FOR 1/2 CYCLE
LD B,(IX+1) ; FREQ. VALUE AGAIN
XOR A
OUT (50H),A
MAK30: DJNZ MAK30
DEC C ; DROP DURATION
JR NZ,MAK10 ; LOOP UNTIL C=0
EI ; INTERRUPTS BACK ON
RET ; AND RETURN
NOISE: LD B,10 ; NO TO REPEAT
LD IX,NOTE ; POINT TO DATA AREA
LD (IX),10 ; DURATION OF RANDOM NOTE
NOIS10: PUSH BC ; SAVE ON STACK
LD A,R ; GET RANDOM NUMBER (0-127)
LD (IX+1),A ; FREQ OF RANDOM NOTE
CALL MAKTON
POP BC ; GO 10 TIMES
DJNZ NOIS10
RET
; GETENT CHECKS FOR <RETURN> - RETURNS NZ IF <RETURN> IS PRESSED
; OTHERWISE, Z.
; VS 3.0 ^C WILL ABORT AND RETURN TO CP/M
; VS 3.5 CHECKS FOR DIFF LEVELS AND BY-PASSES CALL GETDIF
; (IE WILL SAVE A KEY-STROKE FOR EXPERIENCED PLAYERS)
; VS 3.6 CHECKS FOR UP OR DOWN ARROWS TO VARY SOUND VOLUME
GETENT: CALL GETKEY ; DIRECT CONSOLE I/O
RET Z
CP 0DH ; ?<RETURN> (CR)
JR NZ,GET10
OR A ; SET NZ FOR CR
RET
GET10: CP 03H ; ?^C FOR FINISH
JP Z,DONE ; BACK TO CP/M
CP '1' ; IS IT A KEY 1 - 9
JR C,GET20
CP '9'+1
JR NC,GET20
POP HL ; WASTE RETURN ADDRESS SO
JP GD15 ; NEXT RET WILL BE TO MAIN
; PROGRAM LOOP
GET20: CP 05H ; ? UP ARROW
JR Z,GET30
CP 18H ; ? DOWN ARROW
JR Z,GET40
GET25: XOR A ; NOT A VALID KEY - SET Z
RET ; AND RETURN
GET30: LD A,(VOL) ; INCREASE VOLUME
CP 0FFH ; ?ALREADY MAX VOLUME
RET Z ; YES - RETURN
INC A ; NO - INCREASE IT
JR GET50
GET40: LD A,(VOL) ; DECREASE VOLUME
OR A ; CHECK FOR ZERO
RET Z ; YES - RETURN
DEC A ; NO - DECREASE IT
GET50: LD (VOL),A
LD A,0FFH ; SET CHANGE FLAG
LD (SCRFLAG),A
XOR A ; AND RETURN WITH Z
RET
GETDIF: CALL CLS
CALL SPMSG
.XLIST
DEFM 'Select Difficulty Level'
DEFW 0D0AH
DEFW 0A0AH
DEFM ' 1 (Very Easy) to 9 (Very Difficult)'
DEFM ' ..... '
DEFB 0
.LIST
GD10: LD C,DCON ; GET KEY INPUT
LD E,0FDH ; RETURN WHEN KEY IS PRESSED
CALL BDOS ; WITH VALUE IN A
CP '1'
JR C,GD10
CP '9'+1
JR NC,GD10
GD15: SUB 31H ; PUT IN 0 - 8 RANGE
LD (DIFBUF),A ; STORE DIFFICULTY
PUSH AF ; AND PUT ON STACK
LD B,3
LD C,0
GD20: SUB B ; FIND MODE AND SPEED
JR C,GD30
INC C ; COUNT DIVISION
JR GD20
GD30: ADD A,B ; GET REMAINDER
LD (MODBUF),A ; STORE MODE (0,1,2)
LD HL,DTABLE ; ADDRESS OF DELAY TABLE
LD D,0 ; C IS SPEED (0,1,2)
LD E,C ; DE IS TABLE OFFSET
ADD HL,DE
LD A,(HL) ; A HAS DELAY VALUE
LD (SPDBUF),A ; STORE IN SPDBUF
LD HL,BLKTAB ; ADDRESS OF BLOCK TABLE
ADD HL,DE ; DE IS TABLE OFFSET
LD A,(HL) ; A HAS # BLOCKS * 6
LD (BLKBUF),A ; STORE IN BLKBUF
POP AF ; A IS DIFF 0-8
GD40: LD D,0 ; JOIN HERE FOR PTITLE CODE
LD E,A
LD HL,OSTAB ; ADDRESS OF OFFSET TABLE
ADD HL,DE
LD A,(HL) ; A HAS CURRENT OFFSET
LD (OFFSET),A ; PUT IN OFFSET BUFFER
RET
FRAME: LD HL,VIDEO-1 ; HL->SCREEN TOP-1
LD B,81 ; TOP POSITIONS +1
LD A,80H ; FULL GRAPHICS CHARACTER
FR10: INC HL ; POINT TO NEXT POSITION
LD (HL),A ; SET GRAPHICS BLOCK
DJNZ FR10 ; REPEAT FOR TOP LINE + 1
LD B,23 ; B=# OF LINES
LD DE,79 ; OFFSET FOR EACH LINE
FR20: ADD HL,DE ; SKIP MIDDLE OF SCREEN
LD (HL),A ; SET BLOCK
INC HL
LD (HL),A
DJNZ FR20
LD B,79 ; SPACES ON BOTTOM LINE - 1
FR30: INC HL
LD (HL),A
DJNZ FR30 ; REPEAT FOR BOTTOM
RET ; AND RETURN
SETCRS: LD HL,6000 ; HL->MIDDLE OF SCREEN
LD (CRSPOS),HL ; SET CURSOR POSITION
XOR A
LD (SCRBUF),A ; ZERO CURRENT SCORE
LD (SCRBUF+1),A
LD A,13H ; SET STARTING DIRECTION
LD (SAVARR),A
LD HL,TONTOP ; SET TO TOP OF TONE TABLE
LD (TONPTR),HL
RET ; AND RETURN
GAMMSG: CALL SPMSG
.XLIST
POSXY 28,24 ; PRINT GAME MESSAGE
DEFM ' USE ARROW KEYS TO MOVE '
DEFB 00H
.LIST
RET ; AND RETURN
GETKEY: LD C,DCON ; STOBE KEYBOARD - RETURNS
LD E,0FFH ; VALUE OF KEY, OR Z IF NO
CALL BDOS ; KEY PRESSED
OR A ; SET FLAGS
RET
GETARR: CALL GETKEY ; ? ARROWS PRESSED
RET Z ; NO - RETURN
CP 05H
JR Z,GARR10
CP 18H
JR Z,GARR10
CP 13H
JR Z,GARR10
CP 04H
JR Z,GARR10
XOR A
RET
GARR10: LD (SAVARR),A ; SAVE ARROW KEY
OR A ; RESET Z
RET
GARR20: CALL GETKEY ; THIS IS SIMILAR TO
RET Z ; GETARR, HOWEVER
CP 05H ; RETURNS Z IF NO KEY
JR Z,GARR10 ; PRESSED, NZ IF ANY KEY
CP 18H ; PRESSED, AND UPDATES
JR Z,GARR10 ; SAVARR IF THE KEY
CP 13H ; HAPPENED TO BE AN
JR Z,GARR10 ; ARROW
CP 04H
JR Z,GARR10
RET
FPOSN: LD HL,(CRSPOS) ; CURRENT SCREEN POSITION
LD DE,160 ; OFFSET BETWEEN LINES
LD A,(SAVARR) ; GET ARROW DIRECTION
CP 05H ; CHECK FOR UP ARROW
JR NZ,FPO10 ; GO IF NOT
SBC HL,DE ; ELSE MOVE UP ONE LINE
FPO10: CP 18H ; CHECK FOR DOWN ARROW
JR NZ,FPO20 ; GO IF NOT
ADD HL,DE ; MOVE DOWN A LINE
FPO20: CP 13H ; CHECK FOR LEFT ARROW
JR NZ,FPO30 ; GO IF NOT
DEC HL ; MOVE LEFT ONE SPACE
FPO30: CP 04H ; CHECK FOR RIGHT ARROW
JR NZ,FPO40 ; GO IF NOT
INC HL ; MOVE RIGHT ONE SPACE
FPO40: LD (CRSPOS),HL ; SAVE NEW POSITION
RET ; AND RETURN
SCORE: LD HL,(SCRBUF) ; GET CURRENT SCORE
INC HL ; ADD ONE
LD (SCRBUF),HL ; PUT IT BACK
RET ; AND RETURN
SHWSCR: CALL XLATE ; TRANSLATE BIN -> ASCII
CALL SPMSG
POSXY 36,0
DEFB ' '
ASCORE: DEFB '00000 ',0
RET
XLATE: LD HL,(SCRBUF) ; GET BIN SCORE FROM BUFF
LD IY,PWRTAB ; IY->POWERS OF TEN
LD IX,ASCORE ; IX->ASCII SCORE BUFFER
XLA10: LD E,(IY+0) ; GET LSB OF POWER
LD D,(IY+1) ; GET MSB OF POWER
XOR A
XLA20: OR A ; RESET CARRY
SBC HL,DE ; SUBTRACT CURRENT POWER
JR C,XLA30 ; GO IF CARRY
INC A ; ELSE INCREMENT COUNTER
JR XLA20 ; AND DO AGAIN
XLA30: ADD HL,DE ; HL=VALUE BEFORE CARRY
ADD A,30H ; CHANGE TO ASCII
LD (IX),A ; SAVE ASCII VALUE
LD A,E ; GET LSB OF POWER
CP 1 ; IS IT 1?
RET Z ; IF SO, RETURN
INC IX ; ELSE IX->NEXT CHAR
INC IY ; IY->NEXT POWER
INC IY
JR XLA10 ; AND GO AGAIN
BLOCK: LD A,(BLKBUF) ; # OF BLOCKS TO SET IN A
LD B,A ; THEN INTO B
BL20: PUSH BC
CALL RAND ; GET RANDOM NUMBER
CALL SCALE ; CHECK IF IN RANGE
JR Z,BL30 ; JUMP IF OUT OF RANGE
LD BC,(CRSPOS) ; SAVE GAME CRSPOS
PUSH BC
LD (CRSPOS),HL ; SAVE IN CRSPOS
CALL SET ; AND TURN ON PIXEL
POP BC ; GET GAME CRSPOS
LD (CRSPOS),BC ; AND PUT IT BACK
BL30: POP BC
DJNZ BL20 ; DO UNTIL B=0
RET
BL40: LD B,1 ; SET ONE BLOCK (MODE 2)
JR BL20 ; JOIN MODE 1 BLOCK ROUTINE
PAUSE: LD A,(SPDBUF) ; GET DIFFICULTY VALUE
LD B,A ; INTO B
PAUS10: PUSH BC ; SAVE VALUE
LD BC,050H ; DELAY VALUE
CALL DELAY ; WAIT A BIT
CALL GETARR ; GET ARROW KEYS
POP BC ; RECOVER VALUE
DJNZ PAUS10 ; REPEAT UNTIL ZERO
RET ; THEN RETURN
CURSOR: LD A,0AH ; CONTROL BONDWELL CURSOR
OUT (10H),A ; THROUGH 6845 REGISTERS
LD A,C ; C=20H FOR NO CURSOR
OUT (11H),A ; C=60H FOR SLOW BLINK
RET
; ***** 16-BIT PSEUDO-RANDOM NUMBER GENERATOR ******************
; FROM APC SUBSET FEB 83:50
RAND: LD HL,(SEED) ; GET SEED (OR LAST NUMBER)
LD D,H
LD E,L ; DE<-HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL ; HL<-HL*16
PUSH HL
ADD HL,HL ; HL<-HL*32
EX (SP),HL
OR A ; CLEAR CARRY
SBC HL,DE ; HL<-HL*15
POP BC ; BC<-HL*32
ADD HL,BC ; HL<-HL*(32+15)
ADD HL,HL
ADD HL,HL
ADD HL,HL ; HL<-HL*376
ADD HL,DE ; HL<-HL*377
ADD HL,HL
ADD HL,HL ; HL<-HL*1508
ADD HL,DE ; HL<-HL*1509
LD DE,41
ADD HL,DE ; HL<-HL*1509+41
LD (SEED),HL
RET
SCALE: PUSH HL ; RANDOM # IN HL
LD DE,480 ; ?LOWER THAN 480
XOR A ; CLEAR CARRY (A<-0)
SBC HL,DE
POP HL
JR C,SCAL50 ; LOWER
PUSH HL
LD DE,11520 ; ?HIGHER THAN 11519
XOR A
SBC HL,DE
POP HL
JR NC,SCAL50 ; HIGHER
INC A ; NZ IF WITHIN RANGE
RET
SCAL50: XOR A ; Z IF OUT OF RANGE
RET
; ***** SUBROUTINES THAT ALLOW PIXEL LEVEL GRAPHICS ***********
;
; BY: ROBERT JOHANSON 20/04/87
;
;
; CALL MEMPOS WITH PIXEL NUMBER STORED IN (CRSPOS), OR
; CALL MEMPOS+3 WITH NUMBER IN HL
; ADDRESS IN WHICH PIXEL IS HELD IS RETURNED IN
; HL, AND IS ALSO STORED IN (SCRADD)
MEMPOS: LD HL,(CRSPOS) ; PIXEL NUMBER IN HL
PUSH HL ; SAVE FOR LATER
LD BC,0000H ; (0<=PIXEL<=11,999)
LD DE,480 ; # PIXELS PER LINE
MEM10: AND A ; CLEAR CARRY
SBC HL,DE ; 80*INT(N/480)
JR C,MEM20 ; EXIT WITH RESULT IN BC
PUSH HL ; OR ADD 80 TO BC
LD HL,80
ADD HL,BC
PUSH HL
POP BC
POP HL
JR MEM10
MEM20: POP HL ; GET ORIGINAL # IN HL
LD DE,160 ; # PIXELS PER ROW
AND A ; CLEAR CARRY
MEM30: SBC HL,DE ; INT((N MOD 160)/2)
JR NC,MEM30 ; SUB UNTIL RESULT IS NEGATIVE
ADD HL,DE ; N MOD 160 IN HL
AND A ; CLEAR CARRY
RR L ; L/2
LD H,0F8H ; GENERATE SCREEN ADDRESS
ADD HL,BC
LD (SCRADD),HL ; AND STORE RESULT
RET ; FINALLY RETURN
; CALL MASK WITH PIXEL # IN (CRSPOS), OR CALL MASK+3 WITH VALUE
; IN HL. RETURNS MASK IN A. USES ALL REGISTERS.
MASK: LD HL,(CRSPOS) ; GET PIXEL # IN HL
PUSH HL ; SAVE FOR LATER
LD DE,480 ; # PIXELS PER LINE
AND A ; CLEAR CARRY
MASK10: SBC HL,DE
JR NC,MASK10 ; SUB UNTIL RESULT IS NEGATIVE
ADD HL,DE ; HL=N MOD 480
LD BC,0000H
LD DE,160 ; # PIXELS PER ROW
AND A
MASK20: SBC HL,DE
JR C,MASK30 ; EXIT WITH INT(HL/160) IN BC
INC BC
JR MASK20 ; SUB UNTIL RESULT IS NEGATIVE
MASK30: RLC C ; C*2 =0, 2, OR 4
LD A,01
ADD A,C
POP HL ; ? PIXEL # ODD OR EVEN
BIT 0,L ; TEST BIT 0
JR NZ,MASK40 ; RIGHT COLUMN OF CHARACTER
INC A ; LEFT COLUMN OF CHARACTER
MASK40: LD B,A ; B=BIT POSITION + 1
LD A,10000000B ; BIT POSITION 0 WILL GIVE 00000001
MASK50: RLCA ; BIT POSITION 5 WILL GIVE 00010000
DJNZ MASK50
RET ; AND RETURN
; CALL RANGE WITH NUMBER TO BE CHECKED IN A. WILL RETURN
; Z IF A CONTAINS A VALID GRAPHIC CHARACTER, NZ IF IT ISN'T.
; ALSO WILL RETURN C IF THE VALID CHARACTER IS >7F (IE REQUIRES
; XOR 0BFH TO BE USED), NC IF CHARACTER IS <20.
RANGE: PUSH AF ; SAVE FOR LATER
CP 20H ; ?<=1FH
JR C,RANG10 ; YES - Z & NC
CP 80H ; ?<=7FH
JR C,RANG20 ; YES - NZ
CP 0A0H ; ?<=9FH
JR C,RANG30 ; YES - Z & C
RANG20: POP AF ; (A >9FH) OR (1FH<A<80H) - NZ
OR A ; SET NZ
RET ; AND RETURN
RANG10: XOR A ; (A<20H) - Z & NC
POP BC ; GET A OFF STACK
LD A,B ; WITHOUT CHANGING FLAGS
RET ; AND RETURN
RANG30: XOR A ; (7FH<A<A0H) - Z
CCF ; & C
POP BC ; GET A OFF STACK
LD A,B ; WITHOUT CHANGING FLAGS
RET ; AND RETURN
; CALL SET WITH PIXEL NUMBER TO BE TURNED ON IN (CRSPOS)
SET: CALL MEMPOS ; GET SCREEN ADDRESS OF PIXEL
LD A,(HL) ; GET THE CURRENT CHARACTER THERE
CALL RANGE ; IS IT GRAPHIC
JR Z,SET10 ; YES
LD A,00H ; NO - MAKE IT A GRAPHIC SPACE
AND A ; CLEAR CARRY
SET10: JR NC,SET20 ; IS IT >7FH
XOR 0BFH ; YES - ADJUST IT
SET20: PUSH AF ; SAVE CHARACTER ON STACK
CALL MASK ; GET BIT MASK
POP BC ; CHARACTER IN B
OR B ; MASK OR CHARACTER = NEW CHARACTER
RSET: CP 20H ; ?>1FH - COMMON CODE WITH RESET
JR C,RSET10 ; NO - NO NEED TO ADJUST
XOR 0BFH ; ADJUST FOR >1FH
RSET10: LD HL,(SCRADD) ; GET CURRENT SCREEN ADDRESS
LD (HL),A ; AND PUT NEW CHARACTER THERE
RET ; AND RETURN
; CALL POINT WITH PIXEL NUMBER TO BE TESTED IN (CRSPOS)
POINT: CALL MEMPOS ; GET SCREEN ADDRESS OF PIXEL
LD A,(HL) ; GET THE CURRENT CHARACTER INTO A
CALL RANGE ; IS IT GRAPHIC
JR Z,POINT10 ; YES
RET ; NON GRAPHIC - SAME AS PIXEL SET
; FOR THIS GAME
POINT10:
JR NC,POINT20 ; GRAPHIC, NO NEED TO ADJUST
XOR 0BFH ; GRAPHIC ADJUST
POINT20:
PUSH AF ; SAVE CHARACTER ON STACK
CALL MASK ; GET BIT MASK
POP BC ; CHARACTER IN B
AND B ; CHARACTER AND MASK
RET ; Z & NC = PIXEL NOT SET
; NZ = PIXEL SET
; ***** END OF PROGRAM EXECUTION *******************************
DONE: CALL CLS ; CLEAR SCREEN
LD A,(SCRFLAG) ; SEE IF HIGH SCORES HAVE TO BE RESAVED
OR A ; Z IF OK, NZ IF NEED TO SAVE
JR Z,DO10
; WRITE THE ALTERED RECORDS BACK OUT TO THE DISK
LD C,SETDMA ; SET DMA TO DBUFF
LD DE,DBUFF
CALL BDOS
LD C,SETMSC ; SET MULTI-SECTOR COUNT
LD E,2 ; FOR 2 SECTORS
CALL BDOS
LD HL,FCB ; HL=ADDRESS OF SOURCE
LD DE,TFCB ; DE=ADDRESS OF DEST.
PUSH DE ; SAVE FOR RON.
LD BC,13 ; BC=# BYTES TO MOVE
LDIR ; MOVE IT
LD A,(50H) ; CONTAINS DRIVE CODE FROM
; WHICH PROGRAM WAS LOADED
LD (TFCB),A ; PUT IN TFCB
POP DE ; OPEN THE FILE
LD C,OPENF
CALL BDOS ; A=FFH IF ERROR
INC A ; NOW A = 00 IF ERROR
JR Z,ERROR ; IF SO, HALT PROGRAM.
LD HL,FCBCR ; SET RECORD # TO ZERO
LD (HL),0
LD DE,TFCB ; WRITE OUT THE 2 RECORDS
LD C,WRITF
CALL BDOS ; A=0 IF SUCCESSFUL
OR A
JR NZ,ERROR ; OTHERWISE HALT PROG
LD DE,TFCB ; CLOSE THE FILE
LD C,CLOSF
CALL BDOS
OR A ; A=0 IF SUCCESSFUL
JR NZ,ERROR
DO10: LD C,60H ; TURN CURSOR BACK ON
CALL CURSOR
LD SP,(CPMSP) ; RESTORE CP/M STACK
RET ; RETURN TO CP/M
ERROR: CALL SPMSG ; DISK ERROR HAS OCCURED
.XLIST
DEFB 0DH,0AH,0AH
DEFB 'CRAM has tried to save the new High Scores '
DEFB 'but has been unsuccessful.',0DH,0AH,0AH
DEFB 'This could be due to a real disk I/O error, '
DEFB 'but will also occur if you ',0DH,0AH
DEFB 'have RENamed this program. It must be called '
DEFB 'CRAM.COM for successful ',0DH,0AH,'operation.'
DEFB 0DH,0AH,0AH,0
.LIST
JP DO10 ; BACK TO CP/M
; ***** DATA BUFFERS *******************************************
FCB: DEFB 0,'CRAM COM',0
SCRADD: DEFW 0F800H ; ADDRESS OF PIXEL
DIFBUF: DEFS 1 ; CURRENT DIFICULTY 0 - 8
MODBUF: DEFS 1 ; GAME MODE 0,1,2
SPDBUF: DEFS 1 ; SPEED (DELAY COUNT)
DTABLE: DEFB 40,25,10 ; DELAY TABLE
BLKBUF: DEFS 1 ; # BLOCKS FOR MODE 2
BLKTAB: DEFB 90,180,240 ; BLOCK TABLE
CRSPOS: DEFS 2 ; CURRENT PIXEL #
SCRBUF: DEFW 0000H ; CURRENT SCORE
SAVARR: DEFB 13H ; CURRENT DIRECTION
TONPTR: DEFW TONTOP ; CURRENT NOTE TO PLAY
PWRTAB: DEFW 10000
DEFW 1000
DEFW 100
DEFW 10
DEFW 1
SEED: DEFS 2 ; RANDOM NUMBER SEED
NOTE: DEFW 0000H ; RANDOM NOTE DURATION
; AND FREQUENCY
SCRFLAG:
DEFB 00H ; FLAG FOR HIGH SCORE CHANGE
OFFSET: DEFB 00H ; OFFSET IN DBUFF FOR CURRENT
; DIFFICULTY LEVEL
OSTAB: DEFB 0*28+3 ; OFFSETS FOR 0-8 LEVELS
DEFB 1*28+3
DEFB 2*28+3
DEFB 3*28+3
DEFB 4*28+3
DEFB 5*28+3
DEFB 6*28+3
DEFB 7*28+3
DEFB 8*28+3
CONBUFF: ; CONSOLE BUFFER FOR NAME
DEFB 26,0,0,0,0,0,0,0,0,0,0,0,0
DEFB 0,0,0,0,0,0,0,0,0,0
DEFB 0,0,0,0,0,0
; **** TONE LIST ****
TONTOP: DEFB 150 ; DURATION OF FIRST NOTE
DEFB 214 ; FREQ.
DEFB 200
DEFB 161
DEFB 169
DEFB 191
DEFB 126
DEFB 255
DEFW 0000H ; MARK END OF LIST
CPMSP: DEFW 0 ; CP/M STACK POINTER
STAK EQU CPMSP+130 ; PLENTY OF STACK ROOM
END BEGIN