Files
erkyrath.infocom-zcode-terps/apple/xzip/io.asm
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

1485 lines
30 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
STTL "--- GAME I/O: APPLE II ---"
PAGE
; --------------
; INTERNAL ERROR
; --------------
; ENTRY: ERROR CODE IN [A]
; EXIT: HA!
ERRM: DB "Internal error "
ENUMB: DB "00. "
ERRML EQU $-ERRM
ZERROR: LDY #1 ; CONVERT ERROR BYTE IN [A]
ZERR0: LDX #0 ; TO ASCII AT "ENUMB"
ZERR1: CMP #10
BCC ZERR2
SBC #10
INX
BNE ZERR1
ZERR2: ORA #'0'
STA ENUMB,Y
TXA
DEY
BPL ZERR0
LDX #<ERRM
LDA #>ERRM
LDY #ERRML
JSR DLINE ; PRINT ERROR MESSAGE
JMP ZQUIT1
; ----
; QUIT
; ----
ZQUIT: JSR ZCRLF ; FLUSH BUFFER
ZQUIT1: LDX #<ENDM
LDA #>ENDM
LDY #ENDML
JSR DLINE ; "END OF STORY"
FREEZE: JMP FREEZE ; AND STOP
ENDM: DB "End of session."
DB EOL
ENDML EQU $-ENDM
; -------
; RESTART
; -------
ZSTART: LDX #0
STX WTOP ; RESET FULL SCREEN FOR CLEAR
LDA SCRIPTF ; PRINTING?
BEQ REX ; NO
DEX ; = $FF
STX PSTAT ; MAKE TO CONTINUE PRINTING AFTER RESTART
REX: JSR SIDE1 ; NEED SIDE 1 AGAIN
JMP WARM ; AND DO WARMSTART
; --------------------------
; RETURN TOP RAM PAGE IN [A]
; --------------------------
MEMTOP: LDA #$FB ; FOR NOW, ASSUME LAST "BUFFER"
RTS ; OF AUX MEMORY
; --------------------------------
; RETURN RANDOM BYTES IN [A] & [X]
; --------------------------------
RANDOM: INC RNUM1
DEC RNUM2
LDA RNUM1 ; GENERATED BY MONITOR GETBYT
ADC RAND1
TAX
LDA RNUM2
SBC RAND2
STA RAND1
STX RAND2
RTS
; -------------------
; Z-PRINT A CHARACTER
; -------------------
; ENTRY: ASCII CHAR IN [A]
; COMMENT: SCRIPTING IS HANDLED IN UNBUFR AND FLUSH,
; SO CAN OUTPUT TO PRINTER AS A LINE. TABLE AND SCREEN
; OUTPUT IS SET UP HERE, HANDLED A BYTE AT A TIME
; (DIROUT CHANGES 6/24/85)
COUT: STA IOCHAR ; HOLD IT A SEC
LDX TABLEF ; OUTPUT TO TABLE?
BEQ COUT4 ; NO
JMP TBLRTN ; YES, DO IT (TBL ONLY)
COUT4:
LDX SCREENF ; OUTPUT TO SCREEN?
BNE COUT5 ; YES
LDX SCRIPTF ; OUTPUT TO PRINTER?
BNE COUT5 ; YES
RTS ; NO, SO DONE
COUT5:
LDA IOCHAR ; RETRIEVE CHAR
LDX BUFFLG ; UNBUFFERED OUTPUT?
BNE UNBUFR ; YES, PLACE ON SCREEN IMMED.
CMP #$0D ; IF ASCII EOL,
BNE COUT0
JMP ZCRLF ; DO IT
COUT0:
CMP #SPACE ; IGNORE ALL OTHER
BCC CEX ; CONTROLS
; LDX INVFLG ; CHECK IF NORMAL
; BPL COUT3 ; OR INVERSE
ORA #%10000000 ; SET HIGH BIT FOR NORMAL
COUT3:
LDX CHRCNT ; GET LINE POINTER
STA LBUFF,X ; ADD CHAR TO BUFFER
LDA SPLITF ; are we in screen 1
BNE COUT2 ; yes
LDY LENGTH ; GET LINE LENGTH COUNTER
INC LENGTH ; ELSE UPDATE
CPY XSIZE ; END OF SCREEN LINE?
BCC COUT2
JMP FLUSH ; YES, FLUSH THE LINE
COUT2:
INC CHRCNT
CEX: RTS
; --------------------------
; DIRECT, UNBUFFERED DISPLAY
; --------------------------
UNBUFR: STA IOCHAR ; HOLD IN CASE NEED TO PRINT
LDA EHZ ; CHECK IF BEYOND SCREEN
CMP #80
BCS UNBEX ; YES, LEAVE
LDA SPLITF ; CHECK WHICH WINDOW
BEQ UNBBOT ; BOTTOM WINDOW
LDA CVT ; CHECK IF WITHIN WINDOW
CMP WTOP
BCS UNBEX ; NO, JUST LEAVE
BCC UNBDIS ; YES, GO DISPLAY
UNBBOT: LDA CVT
CMP WTOP
BCC UNBEX ; NOT WITHIN WINDOW, LEAVE
UNBDIS: LDA SCREENF ; DISPLAY TO SCREEN?
BEQ UNBPRN ; NO, CHECK IF PRINTING
LDA IOCHAR
ORA #%10000000 ; SET BIT 7 FOR NORMAL DISPLAY IF WANTED
JSR CHAR
;SEND CHAR TO PRINTER
UNBPRN:
LDA SCRIPT ; SCRIPTING INTERNALLY ENABLED?
BEQ UNBEX ; NO
LDA SCRIPTF ; SCRIPTING ON ?
BEQ UNBEX ; NO
LDA CSW+LO ; SAVE NORMAL OUTPUT HOOK
PHA
LDA CSW+HI
PHA
LDA EHZ ; + CURRENT CURSOR POSITION
PHA
LDA ALTCSW+LO
STA CSW+LO
LDA ALTCSW+HI
STA CSW+HI
LDA IOCHAR ; GET CHAR
JSR MCOUT ; PRINT IT @ CURRENT EHZ
PLA
STA EHZ ; IIe USES CHZ ALSO
PLA
STA CSW+HI
PLA
STA CSW+LO
UNBEX: RTS
; ---------------
; OUTPUT TO TABLE
; ---------------
TBLRTN: TAX ; HOLD CHAR A SEC.
;PUT BYTE IN TABLE AT CURRENT OFFSET
LDA DIRITM+LO ; ADD IN OFFSET
CLC
ADC DIRTBL+LO
STA I+LO
LDA DIRITM+HI
ADC DIRTBL+HI
STA I+HI
LDY #0
TXA ; PICK UP ASCII CHAR
STA (I),Y ; STORE IT IN TBL @ BYTE ALIGNED @
;SET ITM OFFSET TO NEXT POSITION, INCREMENT COUNTER
INC DIRITM+LO ; INC OFFSET TO NEXT BYTE
BNE TBLRTS
INC DIRITM+HI
TBLRTS: RTS
; -------------------
; FLUSH OUTPUT BUFFER
; -------------------
; ENTRY: LENGTH OF BUFFER IN [X]
FLUSH: LDA #$A0 ; SPACE
STX OLDEND ; SAVE CURRENT END OF LINE
FL0: CMP LBUFF,X ; FIND LAST SPACE CHAR
BEQ FL1 ; IN THE LINE
DEX
BNE FL0 ; IF NONE FOUND,
LDX XSIZE ; FLUSH ENTIRE LINE
FL1: STX OLDLEN ; SAVE OLD LINE POS HERE
STX CHRCNT ; MAKE IT THE NEW LINE LENGTH
JSR ZCRLF ; PRINT LINE UP TO LAST SPACE
; START NEW LINE WITH REMAINDER OF OLD
LDX OLDLEN ; GET OLD LINE POS
LDY #0 ; START NEW LINE AT BEGINNING
FL2: INX
CPX OLDEND ; CONTINUE IF
BCC FL3 ; INSIDE OR
BEQ FL3 ; AT END OF LINE
STY LENGTH ; ELSE SET NEW LINE LENGTH
STY CHRCNT
RTS
FL3: LDA LBUFF,X ; GET CHAR FROM OLD LINE
STA LBUFF,Y ; MOVE TO START OF NEW LINE
INY ; UPDATE LENGTH OF NEW LINE
BNE FL2 ; (ALWAYS)
; ---------------
; CARRIAGE RETURN
; ---------------
ZZCRLF: LDX TABLEF ; OUTPUT TO TABLE?
BEQ ZCRLF ; NO
LDA #$0D
JMP TBLRTN ; YES, DO IT (TBL ONLY)
ZCRLF: LDX CHRCNT
LDA #$8D ; INSTALL EOL AT
STA LBUFF,X ; END OF CURRENT LINE
INC CHRCNT ; UPDATE LINE LENGTH
LDA SCREENF ; CHECK IF DISPLAYING TO SCREEN
BEQ ZCRLFX ; NO, GO HANDLE IF PRINTING
LDA SPLITF ; AT SPLIT SCREEN
BNE ZCRLFX ; YES, SKIP ALL THIS
INC LINCNT ; NEW LINE GOING OUT
ZCRLF0: LDX LINCNT ; IS IT TIME TO
CPX WBOTM ; PRINT "MORE" YET?
BNE ZCRLFX ; NO, CONTINUE
LDA WTOP
STA LINCNT ; RESET LINE COUNTER
INC LINCNT ; to leave this line there
INC LINCNT ; to leave one line from previous screen
; there
BIT ANYKEY ; CLEAN STROBE SO GET CLEAN READING
LDA ZBEGIN+ZLMRG+1 ; SET LEFT MARGIN
STA EHZ
LDA #>MORE
LDX #<MORE
LDY #MOREL
JSR DLINE
WAIT: BIT KBD
BPL WAIT
BIT ANYKEY ; CLEAR STROBE SO THIS KEY WILL BE DISCOUNTED
LDY #MOREL ; ERASE [MORE]
WWLOOP: LDA #08
JSR MCOUT
DEY
BNE WWLOOP
JSR CLEOL ; CLEAR TO EOL
ZCRLFX: JSR LINOUT ; DISPLAY LINE
JSR CHKFNC ; CHECK FOR CR FUNCTION (XZIP)
LDA #0
STA LENGTH ; AND RESET LINE COUNT
STA CHRCNT
RTS
LINOUT: LDY CHRCNT ; IF BUFFER EMPTY,
BEQ LINEX ; DON'T PRINT ANYTHING
STY PRLEN ; SAVE LENGTH HERE FOR "PPRINT"
LDA SCREENF ; DISPLAY TO SCREEN?
BEQ LOUT1 ; NO, GO CHECK IF PRINT
LDX #0 ; SEND CONTENTS OF [LBUFF]
LOUT: LDA LBUFF,X ; TO SCREEN
JSR CHAR
INX
DEY
BNE LOUT
LOUT1: JSR PPRINT ; PRINT [LBUFF] IF ENABLED
LINEX: RTS ; AND RETURN
; CHECK IF THERE IS A PENDING FUNCTION CALL ASSOCIATED WITH <CR>'S
CHKFNC: LDA ZBEGIN+ZCRCNT+1 ; IF NULL IGNORE
ORA ZBEGIN+ZCRCNT+0
BEQ CHKOUT
LDA ZBEGIN+ZCRCNT+1 ; DECR COUNTER
SEC
SBC #1
STA ZBEGIN+ZCRCNT+1
LDA ZBEGIN+ZCRCNT+0
SBC #0
STA ZBEGIN+ZCRCNT+0
LDA ZBEGIN+ZCRCNT+1 ; IF NULL NOW, CALL FCN
ORA ZBEGIN+ZCRCNT+0
BNE CHKOUT
LDA ZBEGIN+ZCRFUNC+1 ; SET UP FUNCTION
STA J+LO
LDA ZBEGIN+ZCRFUNC+0
STA J+HI
JSR INTCLL ; DO FUNCTION CALL
CHKOUT: RTS
; ----------------------
; UPDATE THE STATUS LINE
; ----------------------
; NOT APPLICABLE IN EZIP.
ZUSL: RTS
; ------
; VERIFY
; ------
; VERIFY GAME CODE ON DISK
ZVER: JSR ZCRLF ; DISPLAY VERSION NUMBER, GET SIDE 1
LDX #3
LDA #0
STA IOCHAR ; COFFEE FLAG
ZVR: STA K+LO,X ; CLEAR [K], [L]
STA MPC,X ; [MPC] AND [MPCFLG]
DEX
BPL ZVR
LDA #64 ; POINT [MPC] TO Z-ADDRESS $00040
STA MPCL ; 1ST 64 BYTES AREN'T CHECKED
LDA ZBEGIN+ZLENTH ; GET MSB
STA I+HI ; AND
LDA ZBEGIN+ZLENTH+1 ; LSB OF Z-CODE LENGTH IN BYTES
ASL A ; MULTIPLY BY
ROL I+HI ; FOUR
ROL K+LO
ASL A
STA I+LO
ROL I+HI ; TO GET # BYTES
ROL K+LO ; IN GAME
LDA #0 ; START AT BEGINNING
STA DBLOCK+LO
STA DBLOCK+HI
JMP READIN ; READ FIRST BLOCK IN
VSUM: LDA MPCL ; NEW PAGE?
BNE VSUM2 ; NO, CONTINUE
READIN: LDA #>IOBUFF ; FAKE READ OUT SO
STA DBUFF+HI ; IT DOESN'T MOVE BUFFER
LDA #MAIN
STA DSKBNK ; SET FOR MAIN BANK
JSR GETDSK ; GO READ A PAGE
LDA IOCHAR ; CHECK COFFEE FLAG
BNE VSUM2 ; ALL DONE
LDA SIDEFLG
CMP #2 ; IF ON SIDE 2
BNE VSUM2
LDA #>COFMSG ; FIRST SECTOR, TELL THEM
LDX #<COFMSG ; IT WILL TAKE A WHILE
LDY #COFML
JSR DLINE
INC IOCHAR ; TURN FLAG TO DONE
VSUM2: LDY MPCL ; GET THIS BYTE
LDA IOBUFF,Y
INC MPCL ; SET FOR NEXT BYTE
BNE VSUM3
INC MPCM
BNE VSUM3
INC MPCH
VSUM3: CLC
ADC L+LO ; ADD IT TO SUM
STA L+LO ; IN [J]
BCC VSUM1
INC L+HI
VSUM1: LDA MPCL ; END OF Z-CODE YET?
CMP I+LO ; CHECK LSB
BNE VSUM
LDA MPCM ; MIDDLE BYTE
CMP I+HI
BNE VSUM
LDA MPCH ; AND >BIT
CMP K+LO
BNE VSUM
LDA ZBEGIN+ZCHKSM+1 ; GET LSB OF CHECKSUM
CMP L+LO ; DOES IT MATCH?
BNE BADVER ; NO, PREDICATE FAILS
LDA ZBEGIN+ZCHKSM ; ELSE CHECK MSB
CMP L+HI ; LOOK GOOD?
BNE BADVER ; IF MATCHED,
JMP PREDS ; GAME IS OKAY
BADVER: JMP PREDF
COFMSG: DB EOL
DB "Please be patient, this takes a while"
DB EOL
COFML EQU $-COFMSG
; ------
; BUFOUT
; ------
; ENTER: ARG1 = BUFFERED (1) OR NONBUFFERED (0) OUTPUT CHOICE
; EXIT: FLAG (BUFFLG) IS SET TO TELL COUT WHICH TO DO
ZBUFOUT: LDX ARG1+LO
BNE ZBUF1 ; SET TO BUFFERED OUTPUT
JSR CLRBUF ; CLEAR BUFFER
LDX #1
STX BUFFLG ; SET FUTURE OUTPUT TO BE UNBUFFERED
RTS
ZBUF1: DEX
BNE ZBUFEX ; INVALID
STX BUFFLG ; SET TO BUFFERED
ZBUFEX: RTS
; CLEAR OUTPUT BUFFER BEFORE DOING ANYTHING FANCY
CLRBUF: JSR LINOUT ; CLEAR BUFFER (DON'T RESET LINE COUNT)
LDX #0
STX CHRCNT
RTS
; ------
; DIROUT
; ------
; ARG1 CONTAINS VALUE OF WHICH DEVICE TO SELECT
; OR DESELECT, ARG2 = THE TABLE ADDR FOR TABLE OUTPUT
; MULTIPLE DEVICE USAGE IS POSSIBLE.
ZDIRT: LDX ARG1+LO
BMI DIRRES ; NEGATIVE VALUE, DESELECTING
DEX
BEQ DIR1 ; 1 = SET OUTPUT TO SCREEN
DEX
BEQ DIR2 ; 2 = SCRIPTING
DEX
BEQ DIR3 ; 3 = TABLE
DEX
BEQ DIR4 ; 4 = RECORDING DEVICE
RTS ; INVALID VALUE
DIRRES: INX
BEQ DRES1 ; -1 = RESET TO SCREEN
INX
BEQ DRES2
INX
BEQ DRES3
INX
BEQ DRES4
RTS ; INVALID VALUE, JUST LEAVE
DIR1: INX ; 1, TURN SCREEN OUTPUT ON
STX SCREENF
RTS
DRES1:; JSR CLRBUF
STX SCREENF ; 0, TURN SCREEN OFF
RTS
DIR2: INX
STX SCRIPTF ; SET SCRIPT FLAG ON
LDA ZBEGIN+ZSCRIP+1 ; SET GAME FLAG ALSO
ORA #%00000001
STA ZBEGIN+ZSCRIP+1
LDA PSTAT ; CHECK IF PRINTER ALREADY INIT'D
BNE DIR2A
JSR PCHK ; NO, GO DO IT
DIR2A: RTS ; YES, READY TO LEAVE
DRES2: STX SCRIPTF ; TURN PRINTER OFF
LDA ZBEGIN+ZSCRIP+1 ; AND TURN OFF GAME FLAG TOO
AND #%11111110
STA ZBEGIN+ZSCRIP+1
RTS
DIR3: INX
STX TABLEF ; TURN TABLE OUTPUT FLAG ON
LDA ARG2+HI ; SET UP TBL
CLC
ADC ZCODE
LDX ARG2+LO ; TO STORE CHARS IN
STX DIRTBL+LO
STA DIRTBL+HI
LDA #2
STA DIRITM+LO
LDA #0
STA DIRITM+HI
RTS
DRES3: LDA TABLEF ; IF OFF ALREADY
BEQ OUT3 ; LEAVE AS IS
STX TABLEF ; TURN TBL OUTPUT OFF
LDA DIRITM+LO ; MARK END OF CHARS IN TBL
CLC ; WITH A NULL CHAR
ADC DIRTBL+LO
STA I+LO
LDA DIRITM+HI
ADC DIRTBL+HI
STA I+HI ; ALIGNED AT EOL
LDA #0
TAY
STA (I),Y ; PLACE 0 IN TBL
LDY #1 ; GET CHAR COUNT
LDA DIRITM+LO ; (2 LESS THAN [DIRITM])
SEC
SBC #2
STA (DIRTBL),Y
BCS RESET0
DEC DIRITM+HI
RESET0: LDA DIRITM+HI
DEY
STA (DIRTBL),Y ; STORE CHAR COUNT IN TBL
LDA #0 ; CLEAR COUNT FOR NEXT TIME
STA DIRFLG ; SET OUTPUT TO SCREEN
OUT3: RTS
DIR4:
DRES4: RTS ; NOT YET IMPLEMENTED
; ------
; CURSET
; ------
; SET CURSOR AT LINE (ARG1) AS OFFSET FROM TOP OF WINDOW
; AND AT COLUMN (ARG2)
ZCURST: JSR CLRBUF ; CLEAR OUT ANY NON DISPLAYED TEXT 1ST
LDX ARG1+LO ; GET LINE
DEX ; ZERO ALIGN IT
STX CVT
LDX ARG2+LO ; GET COLUMN
DEX ; ZERO ALIGN IT
STX EHZ
; STX CHZ ; IIe SEEMS TO USE BOTH
JMP BASCAL ; MOVE THE CURSOR
; ------
; CURGET
; ------
ZCURGT: LDA ARG1+LO
STA I+LO
LDA ARG1+HI
CLC
ADC ZCODE ; ABSOLUTE
STA I+HI
LDY CVT ; GET CURSOR POSITION
LDX EHZ
INX ; 1 ALIGN IT
INY
TYA ; SLIP IT INTO PLACE
LDY #1 ; TO RETURN IT
STA (I),Y
DEY ; ZERO TOP BYTE
TYA
STA (I),Y
INY
INY
STA (I),Y
INY
TXA
STA (I),Y
RTS
; -----
; DIRIN
; -----
; NOT YET IMPLEMENTED, BUT RESERVED
ZDIRIN: RTS
; ------
; HLIGHT
; ------
ZLIGHT:
JSR CLRBUF ; flush the ole buffer
LDA ARG1+LO ; GET CHOICE OF MODE
BNE ZL1
LDA #$FF ; NORMAL DISPL
STA INVFLG
ZLIEX:
RTS ; MONO SPACE IS ONLY OPTION SO JUST IGNORE IT
ZL1:
CMP #1 ; INVERSE?
BNE ZLIEX ; NO OTHER OPTIONS ON APPLE
LDA #$3F ; SET INVERSE DISPLAY
STA INVFLG
RTS
; -----
; ERASE
; -----
ZERASE: LDA ARG1+LO
CMP #1
BNE ZEROUT ; INVALID
JSR CLRBUF
JMP CLEOL ; CLEAR TO END OF LINE
ZEROUT: RTS
; -----
; CLEAR
; -----
ZCLR: JSR CLRBUF
; LDA CHZ ; SAVE CURSOR JIC CLEARING OTHER WINDOW
STA OLDCHZ
LDA EHZ
STA OLDEHZ
LDA CVT
STA OLDCVT
LDA ARG1+LO ; CHECK WHAT TO DO
BEQ CLR0 ; BOTTOM SCREEN
CMP #1
BEQ CLR1 ; TOP SCREEN
CMP #$FF
BNE ZEROUT ; INVALID
; UNSPLIT SCREEN & CLEAR IT
JSR NORL ; RESET TO FULL
JMP CLS ; & CLEAR IT
CLR0: LDA WTOP ; SET COUNT
STA LINCNT ; FOR "MORE"
JSR CLS ; CLEAR & HOME
LDX #0
JMP SETOLD
CLR1: LDA WTOP ; SAVE SCROLLING TOP
PHA
LDX #0 ; TOP OF SCREEN
STX WTOP
STA WBOTM ; MAKE BOTTOM OF TOP SCREEN
JSR CLS
LDA #$18 ; RESET TOP & BOTTOM
STA WBOTM
PLA
STA WTOP
LDX #1 ; SET SO NEXT TIME INTO WINDOW TOP LEFTS
SETOLD: LDA #0
STA OLD0CVT,X
STA OLD0CHZ,X
STA OLD0EHZ,X
CPX SPLITF
BEQ CLROUT ; LEAVE CURSOR TOP LEFT
LDA OLDCHZ
; STA CHZ
LDA OLDEHZ
STA EHZ
LDA OLDCVT
STA CVT
JMP BASCAL
CLROUT: RTS
; ------
; PRINTT
; ------
; PRINT A TABLE TO SCREEN, ARG1 = # OF BYTES
; ARG2 = WIDTH, ARG3 (DEF = 1) = HEIGHT
OLDCHZ EQU I+LO ; EASIER TO READ
OLDEHZ EQU I+HI
OLDCVT EQU L+LO
ZPRNTT:
LDA SPLITF ; check if in window 0
BEQ PTTj ; don't clear buf in w0 (cuz we wrap)
;
; make sure the buffer is empty, thanks
;
JSR CLRBUF
PTTj:
LDA ARG1+LO ; USE GETBYT AS TBL COULD
STA MPCL ; BE ANYWHERE
LDA ARG1+HI
STA MPCM
LDA #0
STA MPCH
JSR VLDMPC
LDA ARG2+LO ; ONLY A BYTE AS MAX
CMP #0
BEQ PTTDUN ; QUIT NOW IF NULL
STA J+HI ; SCREEN WIDTH IS 80
STA J+LO
DEC NARGS
LDA NARGS
CMP #1
BEQ NOHIGHT ; DEFAULT HEIGHT IS 1
LDA ARG3+LO ; & SCREEN LENGTH MAX IS 25
NOHIGHT: STA K+LO
LDA EHZ
STA OLDEHZ
LDA CVT
STA OLDCVT
PTTLP: JSR GETBYT ; GET A BYTE
JSR COUT
DEC J+LO
BNE PTTLP
DEC K+LO ; IF DONE ALL LINES
BEQ PTTDUN ; LEAVE
LDA OLDEHZ
STA EHZ
LDX OLDCVT
INX ; TO NEXT LINE
STX OLDCVT
STX CVT
JSR BASCAL ; PLACE CURSOR ON NEXT LINE
LDA J+HI ; RESET COUNT
STA J+LO
JMP PTTLP ; GO DO NEXT LINE
PTTDUN: RTS
; ------------
; SET NEW FONT
; ------------
; FONT 1 (NORMAL) AND 3 (MOUSETEXT - ON IIC'S ONLY) ONLY
; FWRD (PIXEL HEIGHT & WIDTH) DOESN'T CHANGE
ZFONT:
LDA ARG1+LO ; GET FONT CHOICE
LDX SPLITF ; get which window
CMP FONT,X ; see if it is a change
BEQ ZFDONE ; nope, so just return
JSR CLRBUF ; got to clear the buffer!
LDA ARG1+LO ; GET FONT CHOICE, again
JSR CHFONT ; go change it
BCS ZFBAD ; bad choice
ZFDONE:
LDX SPLITF ; get old font for returning
LDA FONT,X
PHA
LDA ARG1+LO ; and save the new one
STA FONT,X ; REMEMBER NEW FONT FOR NEXT TIME
PLA
LDX #0
JMP PUTVAL ; RETURN PREVIOUS FONT
ZFBAD: JMP RET0 ; TELL IT DOESN'T WORK
;
; entry point for local calls
; [A] has font # to change to
;
CHFONT:
LDX SIG
BNE CFBAD ; NOT A IIC
CMP #1
BEQ NORML
CMP #3
BNE CFBAD
FONT3:
LDA #$3F ; SET INVERSE ON
STA INVFLG
LDA #$1B ; AND MOUSETEXT ON
JSR MCOUT ; GO THRU THE CHANNELS FOR ANY OUTPUT TYPE
JMP CHFOUT
NORML:
LDA #$18 ; TURN OFF MOUSE TEXT
JSR MCOUT
LDA #$FF
STA INVFLG
CHFOUT:
CLC ; clear carry to show goodness
RTS
CFBAD:
SEC ; set carry to show naughtiness
RTS
; ------------------------------
; FETCH A LINE OF INPUT FOR READ
; ------------------------------
; ENTRY: ABS ADDR OF READ BUFFER IN [ARG1]
; EXIT: # CHARS READ IN [A]
INPUT:
JSR CLRBUF ; FLUSH [LBUFF]
LDA #0 ; RESET LINE COUNT
STA I+HI ; clear local variables
STA I+LO
STA J+HI
STA J+LO
STA BRKCHR ; init break char
LDY WTOP
STY LINCNT ; RESET LINE COUNT
TAY ; get length stuff
LDA (RDTBL1),Y ; get maximum size of buffer
CMP #79 ; IF OVER 78, CUT DOWN TO 78
BCC MAX ; LEAVE IT AS IT IS, IT IS LESS
LDA #78
MAX:
STA CHRMAX ; and save it
INY
LDA (RDTBL1),Y ; get current offset into buffer
TAX ; get so we can inc it
INX ; and not
INX ; count the 2 info-bytes
STX CHARCNT ; save how many chars out there
JSR CHKTME ; START TIME LIMIT
INLOOP:
LDA I+HI ; is there a time?
BEQ INPL1 ; nope
JSR TIMIN ; do timed input
BCC INPL2 ; got a char, process it
JMP LEXBAD ; timed out with nothing there!
INPL1:
JSR GETKEY ; let apple do the walking
INPL2:
JSR ISTCHR ; CHECK IF IT'S AN ACCEPTABLE TERMINATOR KEY
BCS NOTYET
STA BRKCHR
CMP #EOL ; IF EOL PUT TO SCREEN
BEQ ENDLIN
JMP ENDIN ; ELSE JUST END
NOTYET:
TAY ; check for functions keys that aren't
BMI CBAD ; terminators and feep if it is
CMP #EOL ; EOL?
BEQ ENDLIN ; LINE DONE IF SO
CMP #BACKSP ; BACKSPACE?
BEQ BACKUP ; SPECIAL HANDLING
LDY CHARCNT ; where do we put char?
CPY CHRMAX ; are we filled up?
BCS CBAD ; boy, am i full
CMP #$80 ; DON'T SHOW FCN KEYS
BCS LEX
SHOWIT:
STA SVCHAR ; save it
CMP #$80 ; don't display function keys
BCS NOSHOW ; okay, i won't
; LDX INVFLG
; BPL SHOW1 ; INVRSE
ORA #$80 ; ELSE MAKE IT NORMAL
SHOW1: JSR CHAR ; SEND TO SCREEN
;
; now save it for posterity
;
NOSHOW:
LDA SVCHAR ; get it to work on
CMP #'A' ; IF CHAR IS UPPERCASE ALPHA,
BCC LEX ; CONVERT TO LOWER CASE
CMP #'Z'+1
BCS LEX
ADC #$20 ; converting away
LEX:
STA (RDTBL1),Y ; ADD CHAR TO INPUT BUFFER
INC CHARCNT ; NEXT POSITION IN LINE
JMP INLOOP ; NO, GET ANOTHER CHAR
; HANDLE BACKSPACE
BACKUP:
LDA CHARCNT ; if == 2 then empty
CMP #2 ; and if not, then we still have room
BEQ CBAD ; JMP to beeping
DEC CHARCNT ; get rid of char
LDA #$08 ; BACKSP STRANGE SO DO 082008
JSR CHAR
LDA #$A0
JSR CHAR
LDA #$08
JSR CHAR
JMP INLOOP
CBAD: JSR BEEP ; ELSE SCREAM WITH PAIN
JMP INLOOP ; AND WAIT FOR SOMETHING BETTER
; HANDLE END OF LINE
ENDLIN: STA BRKCHR
LDA #$8D
JSR CHAR ; SEND EOL TO SCREEN
INC LINCNT ; take into account the <CR> at EOL
;
; now, build lbuff so we can send it to the printer if necessary
; but only build it if it is necessary, really!
;
LDA SCRIPT ; find out if we are scripting
BEQ ENDIN ; i guess not
LDA ZBEGIN+ZSCRIP+1 ; check for printing
AND #$01 ; check bit flag
BEQ ENDIN ; no printing, continue on
LDY CHARCNT ; start at end of buffer
LDA #0 ; to print <CR> (put in by clearp)
STA (RDTBL1),Y
LDX CHARCNT ; fill in backwards
DEX
STX LINLEN ; say how many chars for printing
DEX ; we don't need to count info-bytes here
SLOOP:
LDA (RDTBL1),Y ; get char
STA LBUFF,X ; store char
DEY ; point to next get place
DEX ; point to next lbuff place
BPL SLOOP ; go to some more
SDONE:
JSR CLEARP ; CLEAR OFF FCN KEYS BEFORE PRINTING
JSR PPRINT ; SCRIPT [LBUFF] IF ENABLED
ENDIN:
LDY CHARCNT ; how many chars in buffer
LDA #00 ; to show end of line
STA (RDTBL1),Y ; and save it
DEY ; DON'T INCLUDE LENGTH BYTES
DEY ; IN COUNT
TYA ; SAVE INBUF LENGTH
LDY #1
STA (RDTBL1),Y ; and tell the world about it!
LEXBAD: RTS ; INTO [A]
; CHKTME RTN - CALLED BY INPUT & ZINPUT
CHKTME:
LDA NARGS ; CHECK IF TIME LIMIT
CMP #2
BEQ CHKT1 ; NO
LDA ARG3+LO ; GET DELAY WANTED
STA I+HI
LDA NARGS ; IS THERE A FCN?
CMP #4
BNE CHKT1 ; NO
LDA ARG4+LO ; YES, SET IT
STA J+LO
LDA ARG4+HI
STA J+HI
CHKT1:
RTS ; just set things up, please
; ZINPUT ENTRY (DIFFERENT ARG #'S SO SETUP AHEAD)
TIMEK:
BIT ANYKEY ; CLEAR STROBE
TIMEST:
JSR STCUR ; start the cursor
LDA I+LO ; don't reset if not zero
BNE TIME0 ; so keep goin' then
LDA I+HI
STA I+LO
TIME0: LDX #8 ; .09 SEC (time to do other stuff)
TIME1: LDA #$30 ; .O1 SEC
JSR MWAIT
DEX
BNE TIME1
BIT KBD ; CHECK FOR KEYSTROKE
BMI TIME2 ; OK, HE'S THERE, CONTINUE
DEC I+LO ; 10TH'S OF SECONDS TO WAIT
BEQ TIMEOUT ; SOME TIME LEFT
BNE TIME0 ; so gwon back and try again! (JMP)
; TIME OUT, CHECK FOR A FCN
TIMEOUT:
JSR ERCUR ; after erasing cursor
LDA J+HI ; IS THERE A FCN
BEQ TIMEBAD ; NO FCN, LEAVE WITH NOTHING
TIME3:
JSR INTCLL ; INTERNALLY CALL THE FCN
LDA VALUE+LO ; CHECK RESULTS
BNE TIMEBAD ; ELSE TRY AGAIN (END EZIP)
LDA LINCNT
CMP WTOP ; check against start
BEQ TIMEST ; if anything printed out, reprint input
JSR FLUSHRD
JMP TIMEST
TIMEBAD:
SEC
RTS
TIME2:
CLC ; GOT A KEY
RTS
;
; send out the input chars type in so far
;
FLUSHRD:
ldy #1 ; start at 1 to skip junk in front
FRLOOP:
iny ; next char?
cpy CHARCNT ; see if we are full
beq FREND ; nope, still some more
lda (RDTBL1),Y ; get the char
CMP #$80 ; don't display function keys
BCS FRLOOP ; okay, i won't
ora #$80 ; make normal
jsr CHAR ; and send it out
jmp FRLOOP
FREND:
lda WTOP
sta LINCNT
rts
;
; display the cursor in the current spot
;
STCUR:
LDX INVFLG ; save old invers
TXA ; and get it
EOR #$C0 ; set/clear inverse bits
STA INVFLG ; and save it
LDA #$A0 ; just an inverse space char
JSR CHAR ; display it
LDA #$08 ; gwon back
JSR CHAR ; and wait
STX INVFLG ; and reset it
RTS
; just erase the cusor char, but leave cursor in its old place
;
ERCUR:
PHA ; save a
LDA #$A0 ; get space char
JSR CHAR ; and put it out there
LDA #$08 ; get backspace
JSR CHAR ; moving cursor back
PLA ; retrieve [A]
RTS
;
; timed key input loop
;
; carry set if timed out
; char in [A], if there is one!
TIMIN:
JSR TIMEK ; check for keystroke
BCC TM1 ; SOMEBODY'S THERE
BCS TMBAD ; ELSE ABORT
TM1:
JSR GOTKEY ; GET ASCII INTO [A] AND [IOCHAR]
BEQ TIMIN ; 0 means no good char
JSR ERCUR ; erase the cursor, please
CLC ; clear to show goody
BCC TMRET ; and go away
TMBAD:
SEC ; set carry to show timeout
TMRET:
RTS ; and away we go
; ------------------------
; IS IT A TERMINATOR CHAR?
; ------------------------
ISTCHR:
PHA
LDA TCHARS+HI ; check if there is a tchars table
ORA TCHARS+LO ; == 0 if not
BEQ ISDUN ; nope
PLA
LDX ALLFLG ; ARE ALL FCN KEYS (<127) TERMINATORS
BEQ ISCHK ; 0 = NO, GO CHECK LIST
CMP #$80 ; YES, SO CHECK IF PAST 127
BCS ISFND ; YUP
BCC ISNOT
ISCHK:
LDY #0
ISLP: CMP (TCHARS),Y ; IS CHAR WE HAVE A TCHAR?
BEQ ISFND ; YES
PHA
LDA (TCHARS),Y ; NULL = END OF STRING
BEQ ISDUN
PLA
INY
BNE ISLP ; SHOULD ALWAYS LOOP
ISDUN:
PLA ; RETRIEVE CHAR
ISNOT: SEC
RTS ; NOT FOUND
ISFND:
CLC
RTS
; ------------------------
; CLEAR LBUFF FOR PRINTING
; ------------------------
CLEARP: LDY #0
LDX #0
CLRLP: LDA LBUFF,Y
CMP #$80
BCS CLSKIP ; DON'T PRINT FCN KEYS
CMP #00 ; (X) EOL BECOMES 00 IN XZIP
BNE CLRLP0
LDA #$8D ; PRINTER NEEDS $8D
CLRLP0: STA LBUFF,X
INX
CLSKIP: INY
CPY LINLEN
BNE CLRLP ; CHECK ALL CHARS
STX PRLEN ; X = NEW LENGTH FOR PRINT
RTS
; -----
; INPUT
; -----
ZINPUT: LDA ARG1+LO
CMP #1 ; KEYBOARD?
BNE ZINPEX ; NO, INVALID
JSR CLRBUF
LDA WTOP ; RESET LINE COUNT
STA LINCNT
INC LINCNT ; save command line for later
LDA #0
STA CHRCNT
STA I+HI ; init locals too
STA I+LO
STA J+HI
STA J+LO
DEC NARGS
BEQ ZINP3 ; NO TIME LIMIT
LDA ARG2+LO ; GET DELAY WANTED
STA I+HI
DEC NARGS
BEQ ZINP4 ; NO FCN
LDA ARG3+LO
STA J+LO
LDA ARG3+HI
STA J+HI
ZINP4: JSR TIMIN ; CALL timed input rotine
BCS ZINPEX ; NOBODY HOME
BCC ZINPRK ; send char on home
ZINP3:
JSR GETKEY ; OK, FIND WHICH CHAR WAS PRESSED
ZINPRK:
LDX #0
JMP PUTBYT ; RETURN CHAR
ZINPEX: JMP RET0 ; OOPS
INTCLL:
;
; can't do this in re-entrant code!!!
;
; LDA #>ZIRET ; SET ZRETURN TO RETURN HERE
; STA PATCHI+HI
; LDA #<ZIRET
; STA PATCHI+LO
LDA I+HI ; SAVE VALUES FOR CALLING RTN
PHA
LDA I+LO
PHA
LDA J+HI
STA ARG1+HI ; pretend it's arg1
PHA
LDA J+LO
STA ARG1+LO ; and this is the other half
PHA
LDX #1
STX NARGS ; 0 args for internal call
DEX
STX IRET ; make sure it returns here!
LDA ZPCL ; a fake one to say we
PHA ; are an internal call
LDA ZPCM ; so save real one
PHA
LDA ZPCH
PHA
LDA #0 ; return addr of zero is
STA ZPCH ; internal call!
STA ZPCM
STA ZPCL
JSR DOCALL
IF 0
LDX OLDZSP+LO ; STUFF TAKEN FROM CALL.
LDA OLDZSP+HI
JSR PUSHXA
; FORM QUAD ALIGNED ADDR FROM [ARG3]
LDA #0
ASL J+LO ; *4
ROL J+HI
ROL A
STA ZPCH
ASL J+LO
ROL J+HI
ROL ZPCH
LDA J+HI ; PICK UP NEW <BYTES
STA ZPCM
LDA J+LO
STA ZPCL
JSR VLDZPC
JSR NEXTPC ; FETCH # LOCALS TO PASS
STA J+LO ; SAVE HERE FOR COUNTING
STA J+HI ; AND HERE FOR LATER REFERENCE
BEQ INT2 ; SKIP IF NO LOCALS
LDA #0
STA I+LO ; ELSE INIT STORAGE INDEX
INT1: LDY I+LO
LDX LOCALS+LO,Y ; GET LSB OF LOCAL INTO [X]
LDA LOCALS+HI,Y ; AND MSB INTO [A]
JSR PUSHXA ; PUSH LOCAL IN [X/A] ONTO Z-STACK
JSR NEXTPC ; GET MSB OF NEW LOCAL
STA I+HI ; SAVE IT HERE
JSR NEXTPC ; NOW GET LSB
LDY I+LO ; RESTORE INDEX
STA LOCALS+LO,Y ; STORE LSB INTO [LOCALS]
LDA I+HI ; RETRIEVE MSB
STA LOCALS+HI,Y ; STORE IT INTO [LOCALS]
INY
INY ; UPDATE
STY I+LO ; THE STORAGE INDEX
DEC J+LO ; ANY MORE LOCALS?
BNE INT1 ; YES, KEEP LOOPING
INT2:
LDA ASSVLU ; get # of args for current one
JSR PUSHXA ; and save for restoring
LDA #0 ; 0 parms for internal calls
STA ASSVLU ; and save for ASSIGNED?
LDX J+HI ; # OF LOCALS
TXA
JSR PUSHXA
LDA ZSP+LO
STA OLDZSP+LO
LDA ZSP+HI
STA OLDZSP+HI
ENDIF
JMP MLOOP ; GO DO FCN
; RETURN FROM FCN WILL COME HERE
ZIRET:
; LDA #>PUTVAL ; REPAIR ZRETURN
; STA PATCHI+HI
; LDA #<PUTVAL
; STA PATCHI+LO
PLA ; GET RID OF RTS FROM ZRET
PLA
PLA ; get old zpc back
STA ZPCH
PLA
STA ZPCM
PLA
STA ZPCL
JSR VLDZPC ; and validate it
PLA ; RESTORE FOR CALLING RTN
STA J+LO
PLA
STA J+HI
PLA
STA I+LO
PLA
STA I+HI
RTS ; GO BACK TO CALLER
; ----------------------------
; FETCH ASCII KEYCODE INTO [A]
; ----------------------------
; EXIT: ASCII IN [A] & [IOCHAR]
WTFLAG: DB 0 ; wait for key or not
GOTKEY: PHA ; save A
LDA #1 ; flag as a no wait
STA WTFLAG ; ayyup
PLA ; get a back
JMP GKj ; and continue as normal
GETKEY: PHA ; save a
LDA #0 ; flag as wait for good key
STA WTFLAG ; wait please
PLA
GKj:
CLD
TXA ; SAVE [X] & [Y]
PHA
TYA
PHA
GKEY0: JSR RDKEY ;GET A CHAR
LDA KBD ; get it again
;CHECK TO MAKE SURE KEY IS VALID, ONLY ACCEPT IT IF IT IS
AND #$7F ;SCREEN OUT SHIFTS
CMP #EOL ;CHECK FOR GOOD (BAD) CHAR
BNE GK0
JMP OK
GK0: CMP #BACKSP
BNE GK1
JMP OK
;CHECK FOR "ARROWS" & FUNCTION KEYS (X), CONVERT FOR USE (EZIP)
;ALSO : CHANGE <_>)@%^&*( TO ,-.0256789
GK1:
LDX #ENDKEY ; GET LENGTH OF LIST
GK2: CMP HAVE,X ; CHECK AGAINST LIST OF UNWANTED KEYS
BEQ GK3 ; FOUND IT
DEX
BPL GK2 ; CHECK THEM ALL
BMI GK4 ; NOT FOUND, CONTINUE OTHER CHECKS
GK3: LDA WANT,X ; GET KEY TO USE INSTEAD
JMP OKj ; JMP
GK4: CMP #SPACE ; NO CTRL CHARS ACCEPTABLE
BCC BADKEY ; IF < SPACE, BAD
; please allow '+'
; CMP #$2B ; +
; BEQ BADKEY
CMP #$3C ;
BCC OK
CMP #$7C ; |
BEQ OK
CMP #$3F ; ?
BEQ OK
MASK0: CMP #'z'+1 ;PICK OUT LETTERS NOW
BCS BADKEY ;IF > BAD
CMP #'a'
BCS OK ;IF > OK
CMP #'A'
BCC BADKEY
CMP #'Z'+1
BCC OK ;IF < OK
BADKEY: JSR BEEP ;BAD KEY, GIVE WARNING NOISE
LDA WTFLAG ; 1 - means don't wait
BNE BDj ; so don't
JMP GKEY0 ;TRY AGAIN
BDj:
LDA #0 ; make char a 0
OK:
CMP #'0' ; check for number keys
BCC OKj ; nope, < 0
CMP #'9'+1 ; more than a nine?
BCS OKj ; ayyup
;
; here we check for the apple keys being down too
;
LDX APKEY1 ; check for open apple
BMI OKj1 ; pressed, so pretend it is a function key
LDX APKEY2 ; how about the other one
BPL OKj ; not pressed, so use as number key
;
; transform number key into a function key
OKj1:
CLC ; get ready for add
ADC #84 ; transforms '1'-'9' to 133-141
CMP #132 ; but '0' wants to be a 142!
BNE OKj ; but it's not it
CLC ; again, don't want carry
ADC #10 ; voila!
OKj:
STA IOCHAR ;HOLD ON TO IT
ADC RNUM1 ;FUTZ WITH RANDOM
STA RNUM1
EOR RNUM2
STA RNUM2
PLA ; RESTORE
TAY ; EVERYTHING
PLA
TAX
LDA IOCHAR ; GET CHAR INTO [A]
RTS ; AND RETURN IT
HAVE: DB $0B,$0A,$08,$15
; turns ctrl-(left side of keyboard) to function keys
; DB $11,$01,$1A,$17,$13,$18,$05,$04,$03,$12,$06,$16,$14,$07,$02,$19
DB $3C,$5F,$3E,$40,$25,$5E,$26
WANT: DB 129,130,131,132
; DB 133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148
DB $2C,$2D,$2E,$32,$35,$36,$37
ENDKEY EQU $-WANT-1
; INPUT: routine locals!
CHARCNT: DB 0 ; where into buffer goes char
SVCHAR: DB 0 ; where to save the char before printing
IRET: DB 0 ; FLAG TELLS IF RETURNLESS CALL
OLD0CHZ: DB 0 ; HOLDS WHERE CURSOR WAS WHEN LEFT
OLD1CHZ: DB 0 ; A WINDOW SO CAN RETURN THERE
OLD0EHZ: DB 0 ; WHEN REENTER THE WINDOW
OLD1EHZ: DB 0 ; (MUST BE IN THIS ORDER!)
OLD0CVT: DB 0
OLD1CVT: DB 0
OLDWL: DB 0 ; SAVE WLEFT & WWDTH WHILE IN SCREEN 1
OLDWD: DB 0
MTEMP: DB 00,00 ; temp spot for math routines
TYPE: DB 0 ; PARTIAL OR NORMAL (WHOLE) SAVE/RESTORE
ASSVLU: DB 0 ; how many args to this subroutine
BRKCHR: DB 0 ; READ BREAK CHAR
RDFLAG: DB 0 ; 0 - only read 1 - do lex on it
FONT: DB 1,1 ; KEEP TRACK OF CURRENT FONT FOR CHANGES
; remember for each window
MORE: DB "[MORE]"
MOREL EQU $-MORE
SLOTM: DB EOL
DB "Printer Slot 1-7: "
SLOTML EQU $-SLOTM
STRYM: DB "The story is loading ..."
STRYML EQU $-STRYM
END