.TITLE ZSCREEN .IDENT /V1.35/ ; ++ ; This is the Z-machine screen handling. ; (c) 2000, 2003 by Johnny Billquist ; ; History: ; ; 00-08-01 BQT Initial coding started. ; Y1.0 00-08-26 21:00 BQT First release. ; Y1.1 00-08-29 14:30 BQT Modified more processing. ; Y1.2 00-09-01 05:00 BQT Beyond Zork have a bug, that in atleast one ; room, print table is used to print one too ; many lines. Since that last list is also ; at the bottom of screen 1, a workaround ; has been implemented whereby print_table ; aren't allowed to print at the bottom ; line of a screen. ; Y1.3 00-09-07 15:30 BQT Added screen modified information. ; Y1.4 00-09-11 19:15 BQT Bugfix in SCRSTS. The score was not correcly ; detecting what game type it was. ; V1.5 00-09-16 12:00 BQT Changed ZEXIT to ABORT. Added a flag to tell ; that the screen has been initiated. ; Made version officially done. ; V1.6 00-09-17 20:00 BQT Found the actual bug I worked around in Y1.2. ; print_table strings can hold control characters, ; which we should replace with spaces! ; V1.7 00-09-22 01:00 BQT Added a check for zero length buffer in FLUSH. ; Added zero timeout for more prompt. ; V1.8 00-09-24 01:30 BQT Added handling of narrow screens in SCRSTS. ; V1.9 00-10-10 01:40 BQT Bugfix in set window. In V3, the cursor position ; should always move to top left if screen 1 is ; selected. Also, the clear screen function didn't ; clear the bottom line if screen 1 was selected. ; V1.10 00-10-12 02:30 BQT When we change window, the text attributes ; appearantly should be cleared. ; V1.11 00-11-07 14:00 BQT Moved SETCOL from ZIO. ; Added color capabilities. ; V1.12 00-12-05 15:30 BQT Bugfix. We need to flush the buffer when we ; change screen. ; V1.13 00-12-29 04:00 BQT Bugfix. When doing a more prompt, we should ; reset the SCRPTR variable, in case ABORT ; is called. ; V1.14 01-01-04 23:00 BQT Bugfix. The scripting function should ; only script when screen 0 is selected. ; V1.15 01-02-26 12:30 BQT Added print_unicode and check_unicode. ; V1.16 01-03-04 03:30 BQT Changed set_font to always allow font 3 if ; VT200 or better. ; V1.17 01-03-04 04:30 BQT Changed more-handling. It now triggers ; at the newline instead of just getting ; to the last line. This allows us to ; get a prompt on the last line without ; a more prompt. ; Changed set_font again. We now let flg2 ; reflect wether we have font 3 or not. ; V1.18 01-03-06 01:00 BQT Bugfix to V1.17 newline handling. ; V1.19 03-01-25 19:00 BQT Bugfix. Wrapping and full-screen DELLIN ; didn't handle if we were at start of ; buffer. ; V1.20 03-01-27 15:00 BQT Added handling of backspace wrap. ; V1.21 03-08-17 11:30 BQT Bugfix in more handling. If we only had one ; line in buffer, MORE garbled. ; V1.22 05-02-21 17:00 BQT Modified code for better reading. ; V1.23 05-02-23 16:00 BQT Started adding new V6 functions. ; V1.24 05-03-07 14:00 BQT Changed screen handling to be much more ; efficient. ; V1.25 05-05-03 22:00 BQT Added SCRZAP ; V1.26 05-05-24 16:00 BQT Added SCRECH for terminal output without space ; gobble. ; V1.27 05-07-25 16:00 BQT Changed move_cursor to not have boundary checks. ; ZOKOBAN is buggy, and we'll allow it. ; V1.28 05-10-25 01:00 BQT Added new Latin-1 <-> ZSCII conversion. ; V1.29 07-11-06 20:30 BQT Bugfix in DELLN2, where we didn't check for ; # of del chr = 0. ; Removed scrolling when split screen. ; V1.30 07-11-11 19:00 BQT Added scrolling on split screen again. ; However, only of text should move down. ; V1.31 07-11-21 18:30 BQT Added check that LF don't get inserted ; if bottom of anything but screen 0. ; V1.32 08-02-26 22:30 BQT Bugfix. Output stream 3 takes a table ; argument in V3 and V4 games as well. ; V1.33 09-04-16 20:30 BQT Bugfix. split_window should not change active ; window. ; V1.34 09-05-13 14:30 BQT Bugfix. In V6, set_cursor can have only one ; argument, and that is valid. ; V1.35 09-05-14 16:00 BQT Bugfix. window_margin was buggy. ; Also did small improvements in output code. ; -- .INCLUDE /ZMAC/ .ASECT ; ; Screen information block. ; .=0 SI: W.WY: .BLKW 1 ; Window Y position W.WX: .BLKW 1 ; Window X position W.YS: .BLKW 1 ; Window Y size W.XS: .BLKW 1 ; Window X size W.CY:: .BLKW 1 ; Cursor Y position W.CX:: .BLKW 1 ; Cursor X position W.LM: .BLKW 1 ; Window left margin W.RM: .BLKW 1 ; Window right margin W.NLI: .BLKW 1 ; Window newline interrupt routine W.NLC: .BLKW 1 ; Window newline interrupt count W.STY: .BLKW 1 ; Window text style W.FCOL: .BLKB 1 ; Window foreground color data W.BCOL: .BLKB 1 ; Window foreground color data W.FONT: .BLKW 1 ; Font number W.FS: .BLKW 1 ; Font size W.ATTR: .BLKW 1 ; Attribute W.LC: .BLKW 1 ; Line count PROC: .BLKW 1 ; Pointer to processing routine at scr. FLAGS: .BLKW 1 ; Local flags. SILEN: WA.WRP=1 ; Style wrap WA.SCR=2 ; Style scroll WA.ST2=4 ; Style to stream 2 WA.BUF=10 ; Style buffering MOD=1 ; Screen is modified. NOMOR=2 ; Perform more processing. SPCGOB=4 ; Gobble spaces. ; .PSECT DATA,D,RW ; ; The screen. ; =========== ; ; The screen is described with a coordinate system with origo at the top left, ; which is (1,1). ; ; SCRBOT is the bottom line on screen. ; SCRWID is the total width of the screen. ; SCRTOP is the top line usable on the screen. In V3 this is 2, otherwise 1. ; SCRLEN is the length usable on the screen. ; SCRTYP is the terminal type. ; SCRBOT: .WORD 0 ; Screen bottom line. SCRWID: .WORD 0 ; Screen width. SCRTOP: .WORD 0 ; Top of screen line. SCRLEN: .WORD 0 ; Length of screen. SCRTYP:: .WORD 0 ; Screen type. ; ; Now some tricky information. We keep both the wanted and actual ; positions around. Whenever we do something that actually modifies ; the screen, we first check if the wanted and actual match, otherwise ; we update the screen and actual values to the wanted. ; A.CY: .WORD 0 ; Actual cursor Y A.CX: .WORD 0 ; Actual cursor X A.RT: .WORD 0 ; Actual region top A.RB: .WORD 0 ; Actual region bottom A.FONT: .WORD 1 ; Actual font A.ATTR: .WORD 0 ; Actual attributes A.FCOL: .WORD 1 ; Actual foreground color A.BCOL: .WORD 1 ; Actual background color ; R.CY: .WORD 0 ; Requested cursor Y R.CX: .WORD 0 ; Requested cursor X R.RT: .WORD 0 ; Requested region top R.RB: .WORD 0 ; Requested region bottom R.FONT: .WORD 1 ; Requested font R.ATTR: .WORD 0 ; Requested attributes R.FCOL: .WORD 1 ; Requested foreground color R.BCOL: .WORD 1 ; Requested background color ; MWINPT: .WORD 1 ; Mouse window ; SCR0: .BLKB SILEN ; Screen 0 info. (lower) SCR1: .BLKB SILEN ; Screen 1 info. (upper) SCR2: .BLKB SILEN SCR3: .BLKB SILEN SCR4: .BLKB SILEN SCR5: .BLKB SILEN SCR6: .BLKB SILEN SCR7: .BLKB SILEN ; OSTFLG: .BYTE 0,1,0,0,0,0 ; Output stream flags. ; ACTSCR:: .WORD 0 ; Current active screen. INIDON: .WORD 0 ; Flag that INIT is done. ; CBUF: .BLKB 400 ; Buffer for temporary control strings. ; ; Some buffers. ; Note that these buffers double up for various duties, which do not ; overlap. However, IOBUF and IOBUF2 must be 1000(8) bytes each. ; .BYTE 0,10. ; Fake a newline before scrbuf... IOBUF:: ; Buffer for save/restore. SCRBUF:: .BLKB 1000 ; Output buffer for screen. SCREND: ; Address of end of screen buffer. ESCBF:: ; Input ESC handling buffer. IOBUF2:: ; Buffer for save. .BLKB 1000 DELBUF: ; Where to place deleted chars at wrap. ; SCRPTR:: .WORD SCRBUF ; Pointer into screen buffer. ; ST3BUF: .WORD 0 ; Buffer pointer for stream 3. ST3PTR: .WORD 0 ; Current pointer for stream 3. ; BUFFLG: .WORD 0 ; Flag for internal buffer write. BUFPTR: .WORD 0 ; Pointer to internal buffer. ; TFLG: .WORD 0 ; Pointer to transcript flag. ; .PSECT CONST,D,RO ; .MACRO TFUN TYP FINI=0 .WORD TYP'INI FRES=2 .WORD TYP'RES FCS=4 .WORD TYP'CS FCL=6 .WORD TYP'CL FCUR=10 .WORD TYP'CUR FSPL=12 .WORD TYP'SPL FATR=14 .WORD TYP'ATR FSTS=16 .WORD TYP'STS FFS=20 .WORD TYP'FS FCOL=22 .WORD TYP'COL FIND=24 .WORD TYP'IND FSCR=26 .WORD TYP'SCR FEND=30 .ENDM TFUN ; FUNTAB: .WORD UNKFUN .WORD ANSFUN .WORD V52FUN .WORD V10FUN .WORD V12FUN .WORD V20FUN .WORD V30FUN .WORD V40FUN .WORD V50FUN ; UNKFUN: TFUN UNK V52FUN: TFUN V52 ANSFUN: TFUN ANS V10FUN: TFUN V10 V12FUN: TFUN V12 V20FUN: TFUN V20 V30FUN: TFUN V30 V40FUN: TFUN V40 V50FUN: TFUN V50 ; ; Table of more prompts for different terminals. ; This table holds two entries, each consist of one length ; and one pointer field, for each terminal type. ; See ZMAC for different terminal types. ; MORTAB: .WORD UM1L,UM1,UM2L,UM2 ; Unknown .WORD AM1L,AM1,AM2L,AM2 ; ANSI .WORD UM1L,UM1,UM2L,UM2 ; VT52 .WORD VTM1L,VTM1,VTM2L,VTM2 ; VT100 .WORD VTM1L,VTM1,VTM2L,VTM2 ; VT102 .WORD VTM1L,VTM1,VTM2L,VTM2 ; VT200 .WORD VTM1L,VTM1,VTM2L,VTM2 ; VT300 .WORD VTM1L,VTM1,VTM2L,VTM2 ; VT400 .WORD VTM1L,VTM1,VTM2L,VTM2 ; VT500 ; ; The color tables... ; FCTAB: .WORD 39.,30.,31.,32.,33.,34.,35.,36.,37. BCTAB: .WORD 49.,40.,41.,42.,43.,44.,45.,46.,47. ; .PSECT TEXT,D,RO ; ; Unknown... ; UM1: .ASCIZ /[More]/ UM1L=.-UM1-1 UM2: .ASCIZ <15>/ /<15> UM2L=.-UM2-1 ; ; ANSI ; AM1: .ASCIZ /[More]/ AM1L=.-AM1-1 AM2: .ASCIZ <15><33>/[K/ AM2L=.-AM2-1 ; ; VT-series. ; VTM1: .ASCIZ <33>/7/<33>/[0;7m[More]/ VTM1L=.-VTM1-1 VTM2: .ASCIZ <33>/8/<33>/[K/ VTM2L=.-VTM2-1 ; TMBUF: .ASCIZ /Time: / SCOTXT: .ASCIZ /Score: / MOVTXT: .ASCIZ /Moves: / ; ; Sequence to initialize VT100. ; . Turn off wrapping. ; . Clear whole screen. ; . Set application keypad. ; V20INT: .ASCII <33>/)w/ ; Set 94 char user font "w" as G1. V10INT: .ASCIZ <33>/[?7l/<33>/[2J/<33>/=/<33>/[r/ V52INT: .ASCIZ <33>/H/<33>/J/ ; ; Sequence to reset VT100. ; . Clear scrolling region. ; . Set numeric keypad. ; . Turn off all attributes. ; V10RET: .ASCIZ <33>/[m/<33>/[J/<33>/[r/<33>/>/ ; ; Clear screen texts: ; V52CST: .ASCIZ <33>/H/<33>/J/ ; ; Clear line texts: ; V52CLT: .ASCIZ <33>/K/ V10CLT: .ASCIZ <33>/[K/ ; ; Status line strings. ; V52STT: .ASCIZ <33>/Y / V10STT: .ASCIZ <33>/7/<33>/[H/<33>/[0;7m/ V11STT: .ASCIZ <33>/8/ ; .PSECT DATA,D,RW ; PFTAB: PFINI: .WORD 0 PFRES: .WORD 0 PFCS: .WORD 0 PFCL: .WORD 0 PFCUR: .WORD 0 PFSPL: .WORD 0 PFATR: .WORD 0 PFSTS: .WORD 0 PFFS: .WORD 0 PFCOL: .WORD 0 PFIND: .WORD 0 PFSCR: .WORD 0 .IIF NE .-PFTAB-FEND .ERROR ; Function table missing data. ; .PSECT CODE,I,RO ; ; Initiate screen handling. ; .ENABL LSB SCRINI:: ; ; First thing is to find out some screen information. ; CALL GETSLN ; Get screen length. MOV R0,SCRBOT ; Save bottom position. MOV R0,A.RB ; Save region bottom. MOV R0,R.RB CALL GETSCL ; Get screen width. CMP R0,#20. ; < 20? BHIS 1$ ; No. MOV #80.,R0 ; Yes. Set it to 80. 1$: MOV R0,SCRWID CALL GETSTP ; Get screen type. MOV R0,SCRTYP ; MOV #1,SCRTOP ; Default top line is 1. CMP ZVER,#3 ; Version 3? BNE 2$ ; No. INC SCRTOP ; Yes. Top line is 2. 2$: MOV SCRBOT,SCRLEN ; Length is bottom... SUB SCRTOP,SCRLEN ; -top... INC SCRLEN ; +1. ; MOV SCRTYP,R0 ; Get screen type. ASL R0 ; *2 MOV FUNTAB(R0),R0 ; Get pointer to correct function tbl. MOV #PFTAB,R1 ; Where to put functions. MOV #FEND/2,R2 ; # of words to copy. 4$: MOV (R0)+,(R1)+ ; Copy correct function table. SOB R2,4$ ; ; Screen initialization. ; MOV #SCR7+SILEN,R0 ; Setup screens. MOV #10,R1 ; A total of 8 screens... 40$: SUB #SILEN,R0 ; Do next (previous) screen. CALL SCRSET SOB R1,40$ ; And repeat. ; ; At this point, R0 points to screen 0, which we will setup ; with more specific data, since it originally will hold the ; whole physical screen. ; MOV R0,ACTSCR ; Initial screen selected. ; MOV SCRTOP,W.WY(R0) ; Top of screen. MOV SCRLEN,W.YS(R0) ; Size. MOV W.YS(R0),W.LC(R0) ; Get line count. MOV SCRWID,W.XS(R0) ; Width. BIS #WA.SCR!WA.ST2,W.ATTR(R0) ; Set attributes. ; CMP ZVER,#6 ; BEQ 41$ BIS #WA.WRP,W.ATTR(R0) ; Other than v6 defaults to wrap. 41$: CMP ZVER,#4 ; In V1-V4 the cursor start at bottom. BHI 42$ MOV W.YS(R0),W.CY(R0) ; Cursor at bottom. 42$: ADD #SILEN,R0 ; Setup screen 1. MOV SCRWID,W.XS(R0) ; Width. ; ; We need to do more: ; Clear screen. ; Place cursor. ; Setup pointers. ; MOV #CBUF,R1 MOV ACTSCR,R3 CALL @PFINI ; Do terminal init. CLRB (R1) MOV #CBUF,R0 SUB R0,R1 CALL PUTTXT ; Output init string. ; MOV #1,A.RT ; We know that the scroll region have MOV #1,R.RT ; been reset... CALL SCRSPL ; Split screen. CALL SCRCUR ; Move cursor. CALL SCRCOL ; Set color. CALL SCRFS ; Select font. CALL SCRATR ; Set attributes. MOV #1,INIDON ; Mark that init is done. ; ; Setup screen related game variables. ; This function is also called after restore, which means ; it can deal with screen resize stuff between save and restore. ; SCRVAR:: .PUTBB #40,SCRBOT ; Save lines. (20h) .PUTBB #41,SCRWID ; Save columns. (21h) CMP ZVER,#5 ; V3... 20$: BIS #224,R0 ; Bold and timed input available. CALL GETAVO BCC 21$ BIS #10,R0 ; Italic. 21$: CALL GETCOL BCC 22$ BIS #1,R0 ; Color. 22$: BIC #42,R0 ; no picture, no sound BIC #660,R1 ; No mouse, sound, menus. CMP ZVER,#5 ; If V5, we might have pictures. BNE 221$ ; Not. V5. No pictures. CALL GETSOF BCS 23$ 221$: BIC #10,R1 ; No pictures. 23$: 30$: MOV R0,ZFLG1 ; Set flags 1. MOV R1,ZFLG2 ; RETURN .DSABL LSB ; ; SCRSET - Setup screen ; ; In: R0 - Screen base pointer. ; SCRSET: CALL $SAVAL ; Set default screen values... MOV #1,W.WY(R0) ; Orgin is (1,1) MOV #1,W.WX(R0) CLR W.YS(R0) ; Size is (0,0) CLR W.XS(R0) MOV #1,W.CY(R0) ; Cursor is at (1,1) MOV #1,W.CX(R0) CLR W.LM(R0) ; Margins is 0 CLR W.RM(R0) CLR W.NLI(R0) ; No interrupt stuff. CLR W.NLC(R0) CLR W.STY(R0) ; Style is 0. MOV #401,W.FCOL(R0) ; Colors are 1/1 (101h) MOV #1,W.FONT(R0) ; Font is #1. MOV #401,W.FS(R0) ; Font size is 1/1 (101h) MOV #WA.BUF,W.ATTR(R0) ; All windows are buffered. CLR W.LC(R0) ; Line count starts at 0. MOV #NORM,PROC(R0) ; Normal processing. CLR FLAGS(R0) RETURN ; ; Init screen for unknown. ; For all INIT functions, the following holds true: ; R0 - Free to use. ; R1 - Points at buffer where to place data to reset screen. ; R2 - Free to use. ; R3 - Pointer to active screen. ; ; At the end, R1 should point past the init string to be printed. ; UNKINI: MOV ZFLG1,R0 ; Get flags. CMP ZVER,#3 ; V1-V3? BHI 10$ ; No. BIC #6,R0 ; Yes. No status line. No split screen. BR 20$ 10$: BIC #34,R0 ; No bold, italc, fixed space. 20$: MOV R0,ZFLG1 .PUTBB #1,R0 MOV #1,A.CY MOV #1,A.CX RETURN ; V52INI: MOV ZFLG1,R0 ; Get flags. CMP ZVER,#3 ; V1-V3? BHI 10$ ; No. BIC #6,R0 ; Yes. No status line. No split screen. BR 20$ 10$: BIC #34,R0 ; No bold, italic, fixed space. 20$: MOV R0,ZFLG1 .PUTBB #1,R0 MOV #1,A.CY MOV #1,A.CX MOV #V52INT,R0 ; VT52 init string. ; ; CPYSTR - Copy a string. ; ; In: R0 -> NUL-terminated source string. ; R1 -> Destination ; ; Out: R1 -> NUL-char in destination. ; ; R0 destroyed. ; CPYSTR: MOVB (R0)+,(R1)+ ; Copy byte. BNE CPYSTR ; until NUL. DEC R1 ; Backup before NUL. RETURN ; Done. ; ANSINI: .MSG <"ANSI screen support not done yet."> JMP ABORT ; ; V20INI: V30INI: V40INI: V50INI: MOV #V20INT,R0 MOV #1,A.CY MOV #1,A.CX CALLR CPYSTR V10INI: V12INI: MOV #V10INT,R0 MOV #1,A.CY MOV #1,A.CX CALLR CPYSTR ; ; SCRRES - Reset screen. ; ; This function is called at game end. ; SCRRES:: TST INIDON ; Have we done init? BNE 10$ ; Yes. RETURN ; No. 10$: CALL FLUSH MOV #CBUF,R1 ; Buffer for string. MOV ACTSCR,R3 ; active screen in R3. CALL @PFRES ; Reset screen. ; MOVB #12,(R1)+ ; And output an LF. CLRB (R1) MOV #CBUF,R0 SUB R0,R1 CALLR PUTTXT ; ; Reset handlers. ; UNKRES: V52RES: RETURN ; ANSRES: .MSG <"Ansi screen handler not done yet."> RETURN ; V10RES: V12RES: V20RES: V30RES: V40RES: V50RES: MOV #V10RET,R0 CALL CPYSTR MOV #1,A.CY MOV #1,A.CX CALLR DOCUR ; Move cursor back. ; ; Screen ZAP. ; This will cause ZEMU to setup the terminal anew. ; (Useful if attributes and stuff have been lost. ; This function is probably something you'd call ; upon the user pressing a certain key or so.) ; SCRZAP:: MOV R0,-(SP) MOV #-1,R0 MOV R0,A.CY ; Actual cursor Y MOV R0,A.CX ; Actual cursor X MOV R0,A.RT ; Actual region top MOV R0,A.RB ; Actual region bottom MOV R0,A.FONT ; Actual font MOV R0,A.ATTR ; Actual attributes MOV R0,A.FCOL ; Actual foreground color MOV R0,A.BCOL ; Actual background color MOV (SP)+,R0 RETURN ; ; Clear screen. ; SCRCS: MOV #CBUF,R1 ; Buffer for string. MOV ACTSCR,R3 ; Active screen. CALL DOCOL ; Set color. CALL @PFCS ; Perform screen clear. CLRB (R1) MOV #CBUF,R0 CALLR SCRTXT ; Print through control output. ; UNKCS: MOVB #14,(R1)+ ; FF for unknown. RETURN ; V52CS: MOV #1,A.CX ; Actual cursor position now. MOV #1,A.CY MOV #V52CST,R0 ; String to clear screen. CALLR CPYSTR ; ANSCS: V10CS: V12CS: V20CS: V30CS: V40CS: V50CS: MOV W.WY(R3),R0 ; Get top line. ADD W.YS(R3),R0 ; Add size. CMPB R0,SCRBOT ; Does screen go to bottom? BGE 10$ ; Yes. MOVB #33,(R1)+ ; No. We assume it goes to top then. MOVB #'[,(R1)+ ; So we go to bottom. MOV R0,A.CY CALL NUMSTR MOVB #';,(R1)+ MOVB #'1,(R1)+ MOVB #'H,(R1)+ MOVB #33,(R1)+ ; Clear from top to current. MOVB #'[,(R1)+ MOVB #'1,(R1)+ BR 20$ ; 10$: MOVB #33,(R1)+ ; Move to top of screen. MOVB #'[,(R1)+ MOV W.WY(R3),R0 MOV R0,A.CY CALL NUMSTR MOVB #';,(R1)+ MOVB #'1,(R1)+ MOVB #'H,(R1)+ MOVB #33,(R1)+ ; Yes. Easy to clear that one. MOVB #'[,(R1)+ 20$: MOVB #'J,(R1)+ MOV #1,A.CX ; Reflect true cursor position. RETURN ; ; Scroll screen (for resize) ; ; In: R2 - # of lines to scroll ; ; Negative lines means downwards. (R2 is delta of size of window 0) ; SCRSCR: TST R2 ; Any change? BNE 10$ ; Yes. RETURN ; No. Done. 10$: CALL $SAVAL MOV ACTSCR,R3 ; Get active screen. CALL SCRSPL ; Perform screen split. CALL SCRCOL ; Set colors. MOV A.CY,R.CY ; Make sure cursor don't move. MOV A.CX,R.CX ; (because we don't know where yet) MOV #CBUF,R1 ; Buffer for string. CALL DOCUR ; Move cursor and scroll region. CALL DOCOL ; Setup color. CALL @PFSCR ; Perform screen scroll CLRB (R1) MOV #CBUF,R0 CALLR SCRTXT ; Print through control output. ; UNKSCR: V52SCR: RETURN ; Cannot do. ; ANSSCR: V10SCR: V12SCR: V20SCR: V30SCR: V40SCR: V50SCR: MOVB #33,(R1)+ ; Scrolling down. Move cursor... MOVB #'[,(R1)+ MOV W.WY(R3),R0 TST R2 ; Up or down? BPL 100$ ; Up... MOV R0,A.CY ; Down. Cursor should be at top. MOV #1,A.CX CALL NUMSTR MOVB #'H,(R1)+ NEG R2 10$: MOVB #33,(R1)+ ; Inser correct number of RI. MOVB #'M,(R1)+ SOB R2,10$ RETURN ; Done. 100$: ADD W.YS(R3),R0 ; Cursor should be at bottom... DEC R0 MOV R0,A.CY ; Save cursor pos. MOV #1,A.CX CALL NUMSTR ; And move... MOVB #'H,(R1)+ 110$: MOVB #12,(R1)+ ; Then insert correct number of LF. SOB R2,110$ RETURN ; ; Clear line. ; SCRCL: MOV #CBUF,R1 ; String buffer. MOV ACTSCR,R3 ; Active screen. CALL DOCUR ; Move cursor. CALL DOCOL CALL @PFCL ; Call correct function. CLRB (R1) MOV #CBUF,R0 CALLR SCRTXT ; Print through control function. ; UNKCL: RETURN ; Q: Can we do this? ; V52CL: MOV #V52CLT,R0 CALLR CPYSTR ; ANSCL: V10CL: V12CL: V20CL: V30CL: V40CL: V50CL: MOV #V10CLT,R0 CALLR CPYSTR ; ; Move cursor to correction position for active screen. ; SCRCUR:: MOV R3,-(SP) ; Save R3 MOV ACTSCR,R3 ; Get active screen. MOV W.WY(R3),R.CY ; Get new cursor Y. ADD W.CY(R3),R.CY DEC R.CY MOV W.WX(R3),R.CX ; Get new cursor X. ADD W.CX(R3),R.CX DEC R.CX BIC #SPCGOB,FLAGS(R3) ; Don't gobble any more spaces. MOV (SP)+,R3 RETURN ; No. So we do nothing. ; ; Normal character processing. ; Update the cursor depending on character, and possibly insert char. ; ; This will also mean moving the cursor, and setting attributes, if ; neccesary. ; ; In: R0 - Character ; R1 -> Buffer ; R3 -> Active screen ; ; Out: Carry set - Cursor at right margin. No character effect. ; Carry clear - all ok. ; ; R1 updated. ; NORM: JSR R5,$SAVRG ; Save R3-R5 CMPB R0,#' ; Control character? BLO 10$ ; Yes. MOV W.XS(R3),R4 ; No. Find right margin of window. SUB W.RM(R3),R4 CMP R.CX,R4 ; Have we passed right margin? BLOS 1$ ; No. SEC ; Yes. Error return. RETURN 1$: MOV R0,-(SP) CALL DOCUR ; Move cursor. CALL DOATR ; Set text attributes. CALL DOFS ; Select font. CALL DOCOL ; Select color. MOV (SP)+,R0 MOVB R0,(R1)+ ; Save character. INC A.CX ; Bump cursor address. INC R.CX INC W.CX(R3) BIS #MOD,FLAGS(R3) CLC ; Success. RETURN ; Done. 10$: CMPB R0,#13. ; CR? BEQ 113$ CMPB R0,#8. ; BS? BEQ 108$ SEC ; All else is not handled. RETURN 108$: MOV W.LM(R3),R4 ; Get left margin. INC R4 CMP W.CX(R3),R4 ; At BS we check for left margin. BLOS 1081$ DEC R.CX ; And if not, the requested pos change. DEC W.CX(R3) CLC RETURN 1081$: DEC W.CY(R3) ; We were at left margin... DEC R.CY ; Move up one line. MOV W.XS(R3),W.CX(R3) ; Set cursor at right margin. SUB W.RM(R3),W.CX(R3) MOV W.WX(R3),R.CX ADD W.CX(R3),R.CX DEC R.CX RETURN 113$: MOV W.LM(R3),W.CX(R3) ; At CR we move to left margin. INC W.CX(R3) MOV W.WX(R3),R.CX ; Requested X pos is window left pos. ADD W.LM(R3),R.CX ; plus margin. RETURN ; ; Move cursor and flush output. ; MCUR:: CALL $SAVAL MOV SCRPTR,R1 MOV ACTSCR,R3 CALL DOCUR MOV R1,SCRPTR CALLR FLUSH ; ; Do actual cursor movement. ; ; In: R1 -> Buffer ; R3 -> Active screen ; DOCUR:: JSR R5,$SAVRG ; Save R3-R5 ; CMP R.RT,A.RT ; Start with the screen splitting. BNE 10$ ; Changed... CMP R.RB,A.RB BNE 10$ ; Changed... BR 20$ ; No change. 10$: MOV R.RT,A.RT ; Do screen splitting. MOV R.RB,A.RB CMP R.RT,R.RB ; Same line? BGE 20$ ; Yes. Do nothing. CALL @PFSPL ; 20$: CMP A.CY,R.CY ; Are we on same line? BNE 100$ ; No. Let's do the full monty for now. ; ; New cursor position is on same line. ; Let's see if we can do some smart stuff. ; MOV R.CX,R5 ; Get requested X MOV A.CX,R4 ; Get actual X CMP R5,R4 ; Get X backup delta BNE 30$ ; No change? RETURN ; They were equal. Nothing to do. 30$: CMP R5,#1 ; Left margin? BNE 40$ ; No. MOVB #13.,(R1)+ ; Yes. This is easy... :-) MOV R5,A.CX ; Save new position. RETURN 40$: SUB R4,R5 ; Get X delta. CMP R4,SCRWID ; On screen edge right now? BLOS 50$ ; No. DEC A.CX ; Yes. Move cursor inside. INC R5 ; Backing up. Do one less. BNE 50$ RETURN ; Yes. Do nothing. 50$: INC R5 ; Do we backup one char? BEQ 60$ ; Yes. INC R5 ; Backup 2 chars? BNE 70$ ; No. MOVB #8.,(R1)+ ; Back two chars. 60$: MOVB #8.,(R1)+ ; Back one char. MOV R.CX,A.CX RETURN 70$: CALLR @PFIND ; Do indentation. ; 100$: MOV R.CY,A.CY ; Save new position MOV R.CX,A.CX CALLR @PFCUR ; Do full cursor movement. ; ; Functions to perform actual cursor placement... ; UNKIND: UNKCUR: RETURN ; Q: Can we do this? ; V52IND: V52CUR: MOVB #33,(R1)+ ; VT52: ESC Y line col MOVB #'Y,(R1)+ ; line and col are binary, with MOV R.CY,R0 ; Get current cursor Y. MOV R0,A.CY ADD #37,R0 ; Adjust for 1-bias coordinate, and ; make into code. MOVB R0,(R1)+ MOV R.CX,R0 ; Get current cursor X. MOV R0,A.CX ADD #37,R0 ; Adjust for 1-bias coordinate, and ; make into code. MOVB R0,(R1)+ RETURN ; ANSCUR: V10CUR: V12CUR: V20CUR: V30CUR: V40CUR: V50CUR: MOVB #33,(R1)+ ; ANSI: CSI line ; col H MOVB #'[,(R1)+ ; line and column are in ascii. MOV R.CY,R0 ; Get line. MOV R0,A.CY CALL NUMSTR MOVB #';,(R1)+ MOV R.CX,R0 ; Get column. MOV R0,A.CX CALL NUMSTR MOVB #'H,(R1)+ RETURN ; ; Indent functions. ; ANSIND: V10IND: V12IND: V20IND: V30IND: V40IND: V50IND: MOVB #'C,-(SP) MOV R.CX,R0 SUB A.CX,R0 BPL 10$ NEG R0 INC (SP) 10$: MOVB #33,(R1)+ MOVB #'[,(R1)+ CALL NUMSTR MOVB (SP)+,(R1)+ MOV R.CX,A.CX RETURN ; ; Split screen. Set scrolling region to current screen. ; SCRSPL: MOV R3,-(SP) MOV ACTSCR,R3 CMP R3,#SCR0 ; Only for screen 0. BNE 10$ MOV W.WY(R3),R.RT MOV R.RT,R.RB ADD W.YS(R3),R.RB DEC R.RB 10$: MOV (SP)+,R3 RETURN ; UNKSPL: V52SPL: RETURN ; Q: Can we do this? ; ANSSPL: V10SPL: V12SPL: V20SPL: V30SPL: V40SPL: V50SPL: MOVB #33,(R1)+ ; ANSI: CSI top ; bottom r MOVB #'[,(R1)+ ; where top and botttom are in MOV R.RT,R0 CALL NUMSTR MOVB #';,(R1)+ MOV R.RB,R0 CALL NUMSTR MOVB #'r,(R1)+ MOV #1,A.CY ; This function have now moved MOV #1,A.CX ; the cursor. RETURN ; ; Set attributes according to current screen. ; SCRATR: MOV R3,-(SP) MOV ACTSCR,R3 MOV W.STY(R3),R.ATTR MOV (SP)+,R3 RETURN ; ; A trick here is that OLDATR will hold the current attributes ; when the terminal dependant code is called, and thus one ; can check and do only the change stuff. ; DOATR: CMP R.ATTR,A.ATTR ; Change? BNE 10$ RETURN ; No. 10$: CALL @PFATR ; Yes. Perform. MOV R.ATTR,A.ATTR ; Save new. RETURN ; UNKATR: V52ATR: RETURN ; Q: We can't do this. ; ANSATR: V10ATR: V12ATR: V20ATR: V30ATR: V40ATR: V50ATR: MOVB #33,(R1)+ ; Start with CSI. MOVB #'[,(R1)+ MOV A.ATTR,R0 ; Get current attribs. BIC R.ATTR,R0 ; Have any been removed? BEQ 5$ ; No. MOVB #'0,(R1)+ ; Yes. Then start by clearing. MOVB #';,(R1)+ MOV R.ATTR,R0 ; And get what should be set. MOV #1,A.BCOL ; This resets colors... MOV #1,A.FCOL MOV #DOCOL,-(SP) ; We should append colors at the end. BR 6$ 5$: MOV R.ATTR,R0 ; No attrib was removed. See which was BIC A.ATTR,R0 ; added... 6$: BIT #1,R0 ; Reverse video? BEQ 10$ ; No. MOVB #'7,(R1)+ MOVB #';,(R1)+ ; Yes. 10$: BIT #2,R0 ; Bold? BEQ 20$ ; No. MOVB #'1,(R1)+ MOVB #';,(R1)+ ; Yes. 20$: BIT #4,R0 ; Italic? BEQ 30$ ; No. MOVB #'4,(R1)+ ; (use underline) MOVB #';,(R1)+ ; Yes. 30$: CMPB -(R1),#'; ; Do we have anything? BNE 40$ ; No. MOVB #'m,(R1)+ ; Done. RETURN ; (We also have 10; fixed pitch) 40$: DEC R1 ; Nothing to print. Back one more. RETURN ; ; Show status line. ; This function is only used in V1-V3 games... ; SCRSTS:: CMP SCRWID,#40. ; Check screen width. BHIS 10$ ; We don't like too narrow stuff. RETURN 10$: MOV #CBUF,R1 ; Buffer. MOV ACTSCR,R3 ; Active screen. CALL @PFSTS ; Call function. MOV R1,-(SP) ; Find out position for eol. ADD SCRWID,(SP) MOV (SP),-(SP) ; Find out position for last field. SUB #12.,(SP) MOV (SP),-(SP) ; Find out position for first field. SUB #12.,(SP) MOVB #' ,(R1)+ ; Start with a space. MOV #1,BUFFLG ; Set flag for printing to buffer. MOV R1,BUFPTR ; Save pointer. MOV #20,R0 ; Get 1:st global variable value. CALL VARVAL MOV R1,R0 ; Move value into R0. CALL OBJTXT ; Insert the object text. CMP ZVER,#3 ; V3 game? BLT SCRGAM ; No. Then it's a score game. BIT #2,ZFLG1 ; Bit set for time game? BEQ SCRGAM ; No. Score game. TST (SP)+ ; Time game. Drop first field pos. CALL FILL ; Fill to last field. MOV #TMBUF,R0 ; String to insert here. CALL CPTXT MOV #21,R0 ; Get value of second global. CALL VARVAL MOV R1,R0 ; Value in R0, and pointer in R1. CMP R0,#10. ; If value is less than 10, we'd BHIS 30$ ; like to have a preceding '0', MOVB #'0,@BUFPTR ; since hours look better that way. INC BUFPTR 30$: CALL NUMTXT MOVB #':,@BUFPTR ; Separate hours from minutes. INC BUFPTR MOV #22,R0 ; But minutes live in the third global. CALL VARVAL MOV R1,R0 CMP R0,#10. BHIS 40$ MOVB #'0,@BUFPTR INC BUFPTR 40$: CALL NUMTXT BR EOS ; Round things off. ; SCRGAM: CALL FILL ; Fill out to first pos. MOV #SCOTXT,R0 ; Score game. Score text. CALL CPTXT MOV #21,R0 ; which is located in second global. CALL VARVAL MOV R1,R0 CALL NUMTXT CALL FILL ; Fill out to last field. MOV #MOVTXT,R0 ; Move text. CALL CPTXT MOV #22,R0 ; which is located in third global. CALL VARVAL MOV R1,R0 CALL NUMTXT EOS: CALL FILL ; Fill to end of line. MOV BUFPTR,R1 CALL @(SP)+ ; Call back to screen dependant stuff. CLRB (R1) ; Done. CLR BUFFLG MOV #CBUF,R0 SUB R0,R1 CALLR PUTTXT ; Print directly. ; CPTXT: MOV BUFPTR,R1 CALL CPYSTR MOV R1,BUFPTR RETURN ; FILL: CMP BUFPTR,2(SP) ; Check if we already passed pos. BLO 10$ ; No... MOV 2(SP),BUFPTR ; Yes. Backup. SUB #4,BUFPTR MOVB #'.,@BUFPTR INC BUFPTR MOVB #'.,@BUFPTR INC BUFPTR MOVB #'.,@BUFPTR INC BUFPTR 10$: MOVB #' ,@BUFPTR ; Fill buffer until position, INC BUFPTR CMP BUFPTR,2(SP) ; which is given at 2(SP). BNE FILL MOV (SP)+,(SP) ; Remove position from stack. RETURN ; UNKSTS: ADD #2,SP ; Reject. RETURN ; V52STS: MOV #V52STT,R0 CALL CPYSTR CALL @(SP)+ MOV #1,A.CY MOV SCRWID,A.CX RETURN ; ANSSTS: V10STS: V12STS: V20STS: V30STS: V40STS: V50STS: MOV #V10STT,R0 CALL CPYSTR CALL @(SP)+ ; Callback. MOV #V11STT,R0 CALLR CPYSTR ; ; Font selection for screen. ; SCRFS: MOV R3,-(SP) MOV ACTSCR,R3 ; Active screen. MOV W.FONT(R3),R.FONT MOV (SP)+,R3 RETURN ; DOFS: CMP R.FONT,A.FONT BNE 10$ RETURN 10$: MOV R.FONT,A.FONT CALLR @PFFS ; Call function. ; UNKFS: V52FS: ANSFS: V10FS: V12FS: RETURN ; None of these can do fonts. ; V20FS: V30FS: V40FS: V50FS: CMP R.FONT,#3 ; Char font? BEQ 10$ ; Yes. MOVB #15.,(R1)+ ; G1 to GL. RETURN 10$: MOVB #14.,(R1)+ ; G2 to GL. RETURN ; ; SCRCOL - Set screen color. ; SCRCOL: MOV R3,-(SP) MOV ACTSCR,R3 ; Active screen. MOVB W.FCOL(R3),R.FCOL MOVB W.BCOL(R3),R.BCOL MOV (SP)+,R3 RETURN ; DOCOL: CMPB R.FCOL,A.FCOL BNE 10$ CMPB R.BCOL,A.BCOL BNE 10$ RETURN 10$: MOV R.FCOL,A.FCOL MOV R.BCOL,A.BCOL CALLR @PFCOL ; Call function. ; UNKCOL: V52COL: RETURN ; ANSCOL: V10COL: V12COL: V20COL: V30COL: V40COL: V50COL: MOVB #33,(R1)+ MOVB #'[,(R1)+ MOVB R.FCOL,R0 DEC R0 ASL R0 MOV FCTAB(R0),R0 CALL NUMSTR MOVB #';,(R1)+ MOVB R.BCOL,R0 DEC R0 ASL R0 MOV BCTAB(R0),R0 CALL NUMSTR MOVB #'m,(R1)+ RETURN ; ; NUMSTR - Make number to a string. ; ; In: R0 - Number. ; R1 - Pointer to buffer. ; NUMSTR: MOV R2,-(SP) MOV #30$,-(SP) MOV R1,R2 10$: MOV R0,R1 BNE 20$ RETURN 20$: CLR R0 DIV #10.,R0 ADD #'0,R1 MOVB R1,-(SP) CALL 10$ MOVB (SP)+,(R2)+ RETURN 30$: CLRB (R2) MOV R2,R1 MOV (SP)+,R2 RETURN ; ; RESLIN - Reset the screen line count. ; RESLIN:: MOV R3,-(SP) MOV ACTSCR,R3 MOV W.YS(R3),W.LC(R3) ; Setup line count as size. MOV (SP)+,R3 CALLR MCUR ; Move cursor and flush. ; ; EXT:12 C 5/* check_unicode char-number -> (result) ; .ENABL LSB CUNICD:: .INSTR "check_unicode",#1 MOV (R2),R1 ; Get character. CLR R0 ; Default answer. CMP R1,#400 BHIS 10$ MOV #3,R0 ; Latin-1 character. All is possible. 10$: CALLR RESULT ; ; EXT:11 B 5/* print_unicode char-number ; .ENABL LSB PUNICD:: .INSTR "print_unicode",#1 MOV (R2),R1 ; Get character. CMP R1,#400 BLO PUTLCHR ; Normal Latin-1. MOVB #'?,R1 ; Unknown char. BR PUTLCHR .DSABL LSB ; ; PUTCHR - Output a ZSCII character to currently selected streams. ; ; In: R1 - ZSCII Character. ; ; R1 destroyed. ; PUTCHR:: TST BUFFLG ; Are we writing internally? ; (This is just used by the V3 status ; line) BEQ 10$ ; No. CALLR PUTLCHR ; Yes. Write to internal only. ; ; No ZEMU-internall stuff going on. Let's do what any sane interpreter would... ; 10$: TSTB OSTFLG+3 ; Stream 3 on? BEQ 20$ ; No. CALLR PUTLCHR ; Yes. Only write to stream 3. ; ; Stream 3 not active. The others can be working in parallell. ; 20$: CALL CZ2L ; Convert. ; Fall through... ; ; PUTLCHR - Output a Latin-1 character to currently selected streams. ; ; In: R1 - Latin-1 character. ; PUTLCHR: JSR R2,$SAVVR 10$: TST BUFFLG ; Are we writing internally? ; (This is just used by the V3 status ; line) BEQ 20$ ; No. ; ; Print to internal buffer. ; ; In: R1 - character. ; CMPB R1,#10. ; LF? BEQ 11$ ; Yes. MOVB R1,@BUFPTR ; No. Save char. INC BUFPTR ; Bump pointer. 11$: RETURN ; ; No ZEMU-internall stuff going on. Let's do what any sane interpreter would... ; 20$: TSTB OSTFLG+3 ; Stream 3 on? BEQ 30$ ; No. ; ; Write to stream 3. ; .PUTBB ST3PTR,R1 ; Write byte. INC ST3PTR ; Increment pointer. RETURN ; Done. ; ; Stream 3 not active. The others can be working in parallell. ; 30$: CMP ACTSCR,#SCR0 ; At screen 0? BNE 40$ ; If not, skip check for transcipt. CALL PRNCHR ; Perform possible transcript. 40$: TSTB OSTFLG+1 ; Stream 1 active? BEQ 50$ ; No. CALL SCRCHR ; Yes. Output character. 50$: RETURN ; Done. ; ; RESMOD - Reset screen modified flag. ; RESMOD:: MOV R3,-(SP) MOV ACTSCR,R3 BIC #MOD,FLAGS(R3) MOV (SP)+,R3 RETURN ; ; ISMOD - Check if screen has been modified. ; ; Out: CS - Screen has been modified. ; ISMOD:: MOV R0,-(SP) MOV ACTSCR,R0 BIT #MOD,FLAGS(R0) BEQ 10$ SEC BR 20$ 10$: CLC 20$: MOV (SP)+,R0 RETURN ; ; SCRCHR - Write a character to the currently selected screen. ; ; In: R1 - Character. ; SCRCHR:: CALL $SAVAL MOV R1,R0 MOV SCRPTR,R1 ; Get pointer to buffer. MOV ACTSCR,R3 ; Get active screen. CALL SCRCH2 ; Insert character. MOV R1,SCRPTR ; Save new pointer. RETURN ; ; SCRECH - Write a character to the currently selected screen. ; Special version for output where we don't want any space gobbling. ; ; In: R1 - Character. ; SCRECH:: CALL $SAVAL MOV R1,R0 MOV SCRPTR,R1 ; Get pointer to buffer. MOV ACTSCR,R3 ; Get active screen. MOV W.ATTR(R3),-(SP) ; Save current attributes. MOV #WA.WRP,W.ATTR(R3) ; Set style to only wrap, no buffer... CALL SCRCH2 ; Insert character. MOV R1,SCRPTR ; Save new pointer. MOV (SP)+,W.ATTR(R3) ; Restore attributes. RETURN ; ; Put the character in buffer. ; R0 - Character ; R1 -> Buffer ; R3 - Active screen ; ; R1 is updated. R3 is preserved. ; R0 is destroyed. ; SCRCH2: CMP R1,#SCREND ; Are we at end of buffer? BLO 10$ ; No. ; ; We have filled the buffer. We need to flush it. ; MOV R0,-(SP) ; Save character. CALL DELLN1 ; Do only up to last newline. SUB R0,R1 ; Get length. CALL PUTTXT ; Flush buffer. MOV R0,R1 ; Now let R1 point to start of buf. CALL @(SP)+ ; And restore line. MOV (SP)+,R0 ; Restore character. ; ; Time to insert a new character in the buffer. At this point we know ; that we have room for the character. ; 10$: CMPB R0,#' ; Space? BNE 11$ ; No. BIT #SPCGOB,FLAGS(R3) ; Should we gobble them? BEQ 11$ ; No. RETURN ; Yes. So we do nothing. 11$: BIC #SPCGOB,FLAGS(R3) ; No more gobbling... CALL @PROC(R3) ; Processing of character. BCS 20$ ; Processing went bad. Let's figure ; out why... RETURN ; All went fine. We're done. 20$: CMPB R0,#' ; Was it a printing char? BLO CTRL ; No. Special characters... ; ; Processing of printing char failed. It must have been a full line. ; We can then do one of two things... ; BIT #WA.WRP,W.ATTR(R3) ; Wrapping on? BNE 30$ ; Yes. RETURN ; No wrapping. Drop it. ; 30$: BIT #WA.BUF,W.ATTR(R3) ; Buffering? BNE 40$ ; Yes. ; ; Wrapping, but no buffering. Insert a newline, and then char. ; 35$: MOVB R0,-(SP) ; Save char. MOVB #13.,R0 ; CR CALL SCRCH2 MOVB #10.,R0 ; LF CALL SCRCH2 MOVB (SP)+,R0 ; And char again. CALLR SCRCH2 ; ; New line, and buffering. Back up and play. ; 40$: MOVB R0,(R1)+ ; Insert char. CLR R0 ; Char counter. MOV #DELBUF,R2 ; Point at delete buffer. 41$: CMP R1,#SCRBUF ; Beginning of buffer. BNE 42$ ; No. ADD R0,R1 ; Yes. Restore regs. MOVB -(R1),R0 ; Get char back. BR 35$ ; No helping it. Act as no buffering. 42$: INC R0 ; Count chars. MOVB -(R1),-(R2) ; Copy out char. CMPB (R1),#' ; Space? BNE 41$ ; No. Continue. DEC R0 ; One less char. INC R2 ; Skip space. MOV R0,-(SP) ; Save count. MOV R2,-(SP) ; Save delete pointer. ; ; This is tricky. We have now actually removed inserted characters. ; This means our calculated X position is wrong. ; We have a very hard time to figure out the correct value as well, ; since we don't know which of the backed/up characters actually ; were printing chars. ; The simple solution for now is to force in a CR, set position to 1, ; and then do the normal CR. If we actually do want to end up at the ; left edge, we're already done. Otherwise, we'll indent to the right ; position now. ; MOV #13.,R0 ; Output newline. MOVB R0,(R1)+ MOV #1,A.CX CALL SCRCH2 ; Tricky. We inserted CR, and now we MOV #10.,R0 ; requested LF... CALL SCRCH2 TST 2(SP) ; Delete count... BNE 44$ ; Something in there? BIS #SPCGOB,FLAGS(R3) ; Nothing deleted. We might have ; more spaces coming. Gobble them... ADD #4,SP RETURN 44$: MOVB @(SP),R0 ; Get deleted char. INC (SP) CALL SCRCH2 ; Insert again. DEC 2(SP) BNE 44$ ; Repeat for all chars. ADD #4,SP RETURN ; Done. ; ; Special characters... ; CTRL: CMPB R0,#10. ; LF? BEQ 110$ CMPB R0,#33 ; ESC? BEQ 133$ MOVB R0,(R1)+ ; We just insert unknowns. RETURN ; Nothing to care about... ; ; Handle esc. ; 133$: MOVB R0,(R1)+ ; Insert ESC. MOV #ESCH,PROC(R3) ; Continuation routine. RETURN ; Done. ; ; Handle LF. ; 110$: CMP R3,#SCR0 ; Screen 0? BNE 11010$ ; No. Don't... CMP W.LC(R3),#-999. ; Should we process "more"? BEQ 11010$ ; No. BIT #NOMOR,FLAGS(R3) BNE 11010$ CMP W.YS(R3),#3 BLOS 11010$ ; ; We have more processing. Let's count lines. ; DEC W.LC(R3) ; Count lines. BGT 11010$ ; Not a full screen. Done. ; ; We're about to print a full screen. Lets so some more processing... ; First we must remove the last line we have printed, since we are ; about to print a more-prompt instead. ; CALL DELLN2 ; Delete to previous newline. ; ; We now have deleted the last line... ; The next thing is to flush the current buffer. ; MOV R0,SCRPTR SUB R0,R1 ; Calculate length. CALL PUTTXT ; Print it. ; ; We have a full screen. Let's do some "more" stuff... ; MOV R3,-(SP) MOV R4,-(SP) MOV SCRTYP,R4 ASH #3,R4 ADD #MORTAB,R4 ; Now R4 points at more prompt table. MOV (R4)+,R1 ; Get first prompt string. MOV (R4)+,R0 CALL PUTTXT ; Output it. CLR R3 ; No timeout. MOV A.CX,-(SP) MOV R.CX,A.CX CALL GETCH2 ; Get a character. MOV (SP)+,A.CX MOV (R4)+,R1 ; Second prompt string. MOV (R4)+,R0 CALL PUTTXT ; Output it. MOV (SP)+,R4 ; Restore registers. MOV (SP)+,R3 MOV W.YS(R3),W.LC(R3) ; Reset line count to number of lines SUB #2,W.LC(R3) ; and setup for overlap... ; ; We now have to retrieve that last line we deleted... ; MOV #SCRBUF,R1 ; Point at start of buffer. CALL @(SP)+ ; Insert characters back. ; 11010$: TST W.NLC(R3) ; Do we have interrupt line count? BEQ NEWLIN ; No. DEC W.NLC(R3) ; Yes. Decrement it. BNE NEWLIN ; Until done. ; ; %%% The interrupt line count is still untested... ; MOV #1,W.CX(R3) ; Setup X pos MOV R1,-(SP) MOV R3,-(SP) MOV #ARGS,R2 ; Point at argument buffer. MOV W.NLI(R3),(R2) ; Save address. MOV #1,R3 ; One argument. MOV #R.LIN,-(R5) ; Resturn handler. CALL DOCALL ; Perform call. JMP FETCH ; And start executing. ; ; A plain, normal linefeed. ; NEWLIN: CALL DOCUR ; Update cursor position. CALL DOCOL ; Update colors. This is important ; here, since a scroll means a new line ; appears, which should have the right ; background color. MOVB #10.,(R1)+ ; Insert linefeed. CMP W.CY(R3),W.YS(R3) ; At bottom of window? BEQ 10$ ; Yes. INC W.CY(R3) ; No. Update pos. INC R.CY INC A.CY RETURN ; Done. 10$: CMP R3,#SCR0 ; Bottom of screen. Screen 0? BEQ 20$ ; Yes. DEC R1 ; No. If so, we don't allow LFs ; at the bottom. Leave cursor in place. 20$: RETURN ; Done. ; ; Interrupt return entry point for newline interrupts. ; LININT:: TST (SP)+ ; Drop return to fetch. MOV (SP)+,R3 ; Restore registers. MOV (SP)+,R1 BR NEWLIN ; And continue. ; ESCH: MOVB R0,(R1)+ ; Save char. CMPB R0,#'[ ; CSI? BEQ 1$ ; Yes. MOV #NORM,PROC(R3) ; Nothing special. Go back to normal. CLC RETURN 1$: MOV #CSI,PROC(R3) ; Do CSI processing. CLC RETURN ; CSI: MOVB R0,(R1)+ ; Save char. CMPB R0,#100 ; Alpha? BLT 10$ ; No. MOV #NORM,PROC(R3) ; Yes. Go back to normal processing. 10$: CLC RETURN ; ; The DELLNx routines are called as co-routines two times. ; The first call should have R1 pointing past the buffer to ; do the delete in. ; At the first return, the last line will be deleted from the buffer. ; R1 will point past the buffer, which will be NUL-terminated. ; R0 will point at SCRBUF ; ; At the second call, R1 should point at where the previously deleted ; line should be placed (SCRBUF). ; At return, the co-routine have exited with the registers as follows: ; R1 points past the screen buffer (as given by R1 in). ; ; R0 and R2 are destroyed by these routines. ; ; DELLN1 - Delete a buffer up to the last newline. ; Leave that previous newline in the buffer. Call back as ; a co-routine that allow some processing to be done, ; and finally reinsert all deleted characters. ; ; In: R1 - Buffer to delete in. ; ; R0 is destroyed. R1 is updated. ; ; If no newline was found, delete nothing. ; DELLN1: SUB #6,SP ; Make room on stack. MOV 6(SP),(SP) ; Move down return address. CLR R2 ; Clear count. MOV #SCRBUF,R0 ; Point at head. 10$: CMP R1,R0 ; Start of buffer? BEQ 20$ INC R2 ; Count chars. CMPB -(R1),#10. ; LF? BNE 10$ ; No. Keep looking. INC R1 ; LF found. Move over it. DEC R2 ; Count one less. BNE 30$ ; Something was deleted... 20$: ADD R2,R1 ; Nothing deleted. Simplify! CLRB (R1) ; Mark end. CALL @(SP)+ ; Call back. BR 40$ ; Done. 30$: MOVB (R1),2(SP) ; Save first char. MOV R2,4(SP) ; Save count. MOV R1,6(SP) ; Save pointer. CLRB (R1) ; Mark end. CALL @(SP)+ ; Call back. MOV 6(SP),R0 ; Get pointer to buffer. MOVB 2(SP),(R0) ; Restore first char. MOV 4(SP),R2 ; Length. BEQ 40$ ; No length. 35$: MOVB (R0)+,(R1)+ ; Copy... SOB R2,35$ 40$: MOV (SP),6(SP) ; Move up return. ADD #6,SP RETURN ; Done. ; ; DELLN2 - Delete a buffer up to the last newline. ; Leave that previous newline in the buffer. Call back as ; a co-routine that allow some processing to be done, ; and finally reinsert all deleted characters. ; ; In: R1 - Buffer to delete in. ; ; R0 is destroyed. R1 is updated. ; ; If no newline was found, delete to start of buffer. ; DELLN2: SUB #6,SP MOV 6(SP),(SP) ; Make space on stack. CLR R2 ; Counter... MOV #SCRBUF,R0 10$: CMP R1,R0 ; Start of buffer? BEQ 15$ ; Yes. INC R2 ; No. Count... CMPB -(R1),#10. ; LF? BNE 10$ ; No. Loop. INC R1 ; Yes. Include LF. DEC R2 BNE 15$ ; Deleted something... CLRB (R1) ; Deleted nothing. Mark end. CALL @(SP)+ ; Callback. BR 40$ ; Done. 15$: MOVB (R1),2(SP) ; Save deleted char. MOV R2,4(SP) ; Save count. MOV R1,6(SP) ; Save pointer. CLRB (R1) ; Mark end of string. CALL @(SP)+ ; Callback. MOV 6(SP),R0 ; Point at delete buffer. MOVB 2(SP),(R0) ; Restore deleted char. MOV 4(SP),R2 ; Counter. BEQ 40$ ; Nothing to restore. 20$: MOVB (R0)+,(R1)+ ; Copy string. SOB R2,20$ 40$: MOV (SP),6(SP) ; Clear stack. ADD #6,SP RETURN ; ; SCRTXT - Output a screen text. ; This routine does not take streams into consideration, but instead ; always does the printing to the screen. ; ; In: R0 - Pointer to text. NUL terminated. ; SCRTXT:: MOV R0,-(SP) MOV R1,-(SP) 10$: MOVB (R0)+,R1 BEQ 20$ BPL 15$ BIC #^C177,R1 MOVB ZSCII(R1),R1 15$: CALL SCRECH BR 10$ 20$: MOV (SP)+,R1 MOV (SP)+,R0 RETURN ; ; FLUSH - Flush the buffer. ; FLUSH:: MOV R0,-(SP) ; Save registers. MOV R1,-(SP) MOV #SCRBUF,R0 ; Point at buffer start. MOV SCRPTR,R1 ; Point at current position. CLRB (R1) ; Set end marker. SUB R0,R1 ; Get length. BEQ 10$ ; Nothing in there... MOV R0,SCRPTR ; Reset current position. CALL PUTTXT ; Really write buffer out. 10$: MOV (SP)+,R1 ; Restore registers. MOV (SP)+,R0 RETURN ; ; VAR:237 D 4 erase_window window ; ; -1 means whole screen, and collapse window 1. ; 0,1 are the two windows. ; In V6 we have 8 windows... ; .ENABL LSB ERWIN:: .INSTR "erase_window",#1 CMP (R2),#-1 ; Special ops... BEQ 100$ ; Yes. MOV ACTSCR,-(SP) ; No. Save current window... MOV (R2),R0 ; Get window to erase. CALL GWIN ; Get pointer to structure. MOV #1,W.CY(R3) ; Reset line on that window. CMP ZVER,#5 ; In V1-V4, window 0 moves cursor BHIS 20$ ; to bottom instead... TST R0 BNE 20$ MOV W.YS(R3),W.CY(R3) 20$: MOV #1,W.CX(R3) ; Column is always 1. MOV W.YS(R3),W.LC(R3) ; Clear line count. MOV R3,ACTSCR ; Save active screen for SCRCS. CALL SCRCS MOV (SP)+,ACTSCR ; Restore active screen. CALLR SCRCUR ; ; erase_window -1 have special meaning... ; 100$: MOV #SCR0,R0 ; Screen 0. MOV #SCR1,R1 ; Screen 1. MOV SCRTOP,W.WY(R0) ; Window 0 top at "top". MOV SCRLEN,W.YS(R0) ; Get new length. CLR W.YS(R1) ; Collapse screen 1. MOV #1,W.CY(R0) ; Move cursor to top of window. CMP ZVER,#5 BHIS 110$ MOV W.YS(R0),W.CY(R0) ; JMP BADFUN ; 1$: MOV (R2)+,R0 ; Find out which stream, and func. BMI 10$ ; Turn off... TSTB OSTFLG(R0) ; Already on? BEQ 9$ ; No. .MSG <"Turning on stream %D, already on.">,R0 9$: MOVB #1,OSTFLG(R0) ; Turn on. CMP R0,#3 ; #3? BNE 2$ ; No. MOV (R2),ST3BUF ; Yes. Save pointers. MOV (R2),ST3PTR ADD #2,ST3PTR RETURN 2$: CMP R0,#2 ; Transcript? BNE 3$ ; No. BISB #1,@TFLG ; Yes. Set flag. 3$: RETURN ; 10$: NEG R0 ; Get stream number. TSTB OSTFLG(R0) ; Already off? BNE 19$ .MSG <"Turning off stream %D, already off.">,R0 19$: CLRB OSTFLG(R0) ; Turn off stream. CMP R0,#3 ; #3? BNE 20$ ; No. MOV ST3PTR,R1 ; Yes. Find out how much written, SUB ST3BUF,R1 ; and store that at start of buffer. SUB #2,R1 .PUTWB ST3BUF,R1 .PUTWB #60,R1 ; (30h) RETURN 20$: CMP R0,#2 ; Transcripting? BNE 21$ ; No. BICB #1,@TFLG ; Yes. Turn off. 21$: RETURN .DSABL LSB ; ; EXT:4 4 5 set_font font -> (result) ; .ENABL LSB SETFNT:: .INSTR "set_font",#1 CMP (R2),#1 ; Selecting font 1 is always good... BEQ 10$ BIT #10,ZFLG2 ; Font 3 available? BEQ 20$ ; No. CMP (R2),#3 ; Yes. Did we ask for font 3? BEQ 10$ ; Yes. We can do that... 20$: CLR R0 ; Can't do requested font... CALLR RESULT 10$: MOV ACTSCR,R0 ; Get active screen. MOV W.FONT(R0),-(SP) ; Save old font. MOV (R2),W.FONT(R0) ; Set new font. CALL SCRFS ; Output control for this. MOV (SP)+,R0 ; Get old font again. CALLR RESULT ; And answer. .DSABL LSB ; ; VAR:234 A 3 split_window lines ; Screen 1 will have the size specified as argument. ; .ENABL LSB SPLITW:: .INSTR "split_window",#1 MOV (R2),R2 ; Get split line. MOV #SCR0,R0 ; Get both screens. MOV #SCR1,R1 ; MOV R0,ACTSCR ; We shouldn't do this...? ; ; Start by setting up window 1. ; MOV W.YS(R1),-(SP) ; Save old size. MOV SCRTOP,W.WY(R1) ; Setup w1 pos. MOV #1,W.WX(R1) MOV R2,W.YS(R1) ; Setup w1 size MOV SCRWID,W.XS(R1) MOV R2,W.LC(R1) ; Line count MOV #1,W.CY(R1) ; Cursor pos. MOV #1,W.CX(R1) BIS #NOMOR,FLAGS(R1) CLR W.STY(R1) ; ; Window 1 done. ; ; Next we fiddle with window 0. ; This is trickier. If W0 is moving down because W1 grew, we might ; consider scrolling the screen down as well. But no more than what ; it takes to move the cursor to the bottom line. ; SUB (SP)+,R2 ; Get size change. MOV W.WY(R0),-(SP) ; Save new Y pos. ADD R2,(SP) MOV W.YS(R0),-(SP) ; Save new Y size. SUB R2,(SP) TST R2 ; Was window enlarged? BMI 2$ ; Yes. SUB R2,W.LC(R0) ; No. Adjust current line count. CMP W.CY(R0),(SP) ; Is cursor outside of window now? BLOS 1$ ; No. SUB W.CY(R0),R2 ; Yes. Adjust size adjustment. ADD (SP),R2 MOV (SP),W.CY(R0) ; Set cursor Y to last line. ; ; Now we have adjusted cursor because of shrunk window. ; R2 is now the amount to scroll down. ; 1$: NEG R2 CALL SCRSCR ; Scroll. BR 3$ ; ; W0 was grown. We just adjust the cursor position. ; 2$: SUB R2,W.CY(R0) ; New relative cursor. ; ; Done with the size and position stuff. ; Do final play. ; 3$: MOV (SP)+,W.YS(R0) ; Set new size. MOV (SP)+,W.WY(R0) CLR W.STY(R0) ; Reset style. CALL SCRSPL ; Split screen. CALL SCRATR ; Set text attributes. CALL SCRCOL ; Set color. CALL SCRFS ; Select font. CMP ZVER,#3 ; V3 game? BNE 10$ ; No. MOV #SCR1,ACTSCR ; Yes. Screen 1? CALL SCRCS ; Yes. Clear screen. MOV #SCR0,ACTSCR 10$: CALLR SCRCUR ; Move cursor. .DSABL LSB ; ; VAR:235 B 3 set_window window ; .ENABL LSB SETW:: .INSTR "set_window",#1 MOV (R2),R0 ; Get window number. CALL GWIN ; Get window structure. CMP R3,#SCR1 ; Screen 1? BNE 10$ ; No. CMP ZVER,#6 ; Yes. Is this V6? BEQ 10$ ; No. MOV #1,W.CY(R3) ; Yes. Reset position. MOV #1,W.CX(R3) SETW2: 10$: MOV R3,ACTSCR ; Save new screen. ; CLR W.STY(R3) ; Clear attributes. CALL SCRATR ; Set attributes. CALL SCRFS ; Select font. CALL SCRCOL ; Set color. CALL SCRSPL ; Set region. CALLR SCRCUR ; Move cursor. ; MOV SCRPTR,R1 ; CALL DOCUR ; Actually place cursor. ; MOV R1,SCRPTR ; CALLR FLUSH ; And flush this. .DSABL LSB ; ; VAR:243 13 3 output_stream number ; VAR:243 13 5 output_stream number table ; ; *** Note. The Z-spec is wrong here. ; In version 3 & 4, output_stream to stream #3 ; also takes a table argument (how could it work ; otherwise?) ; .ENABL LSB OUTSTR:: OUTST2:: .INSTR "output_stream" 10$: MOV (R2)+,R0 ; Find out which stream, and func. BMI 100$ ; Turn off... TSTB OSTFLG(R0) ; Already on? BEQ 20$ ; No. .MSG <"Turning on stream %D, already on.">,R0 20$: MOVB #1,OSTFLG(R0) ; Turn on. ; CMP ZVER,#3 ; ,R0 110$: CLRB OSTFLG(R0) ; Turn off stream. ; CMP ZVER,#3 ; Text ; ; New line... ; 10$: MOV ACTSCR,R0 INC W.CY(R0) ; Bump line. MOV (SP),W.CX(R0) ; Resore column. CALL SCRCUR ; Move cursor. 20$: MOV 2(SP),-(SP) ; Get column count. 30$: CALL ATRAN INC R3 BNE 31$ INC R2 31$: MOVB (R0),R1 ; Get character. BPL 35$ ; Positive is good. BIC #^C177,R1 MOVB ZSCII(R1),R1 ; Get actual character. 35$: CMPB R1,#32. ; Is it a control char? BHIS 36$ ; No. MOVB #' ,R1 ; Yes. Replace with space. 36$: CALL SCRCHR ; Output it. DEC (SP) ; Loop. BNE 30$ ADD #2,SP ; Drop loop counter. ADD 6(SP),R3 ; Skip... ADC R2 DEC 4(SP) ; Next line. BNE 10$ ADD #10,SP ; Drop stack. RETURN ; Done. .DSABL LSB ; ; 2OP:27 1B 5 set_colour foreground background ; 2OP:27 1B 6 set_colour foreground background window ; .ENABL LSB SETCOL:: .INSTR <"set_color"> CMP R3,#3 ; 3 args? BEQ 1$ MOV #-3,4(R2) ; No. Default window. CMP R3,#2 ; 2 args? BEQ 1$ JMP BADFUN ; No. Baaaaaad. 1$: MOV 4(R2),R0 CALL GWIN ; Get window structure. MOV (R2)+,R1 ; Get foreground color. BEQ 10$ ; No change. CMP R1,#2 BGE 5$ MOV #1,R1 ; Use default. 5$: MOVB R1,W.FCOL(R3) 10$: MOV (R2)+,R1 BEQ 20$ CMP R1,#2 BGE 15$ MOV #1,R1 15$: MOVB R1,W.BCOL(R3) 20$: CALLR SCRCOL .DSABL LSB ; ; EXT:23 17 6 mouse_window window ; .ENABL LSB MOUWIN:: .INSTR "mouse_window",#1 MOV (R2),MWINPT ; Save mouse window. RETURN ; ; Get requested window. ; In: R0 - window number. ; ; Out: R3 -> window structure. ; GWIN: CMP R0,#-3 ; -3 means current window. BNE 10$ MOV ACTSCR,R3 RETURN 10$: MOV #SILEN,R3 MUL R0,R3 ADD #SCR0,R3 RETURN ; ; EXT:8 8 6 set_margins left right window ; .ENABL LSB WINMAR:: .INSTR <"set_margins"> MOV 4(R2),R0 ; Get window. CMP R3,#3 ; 3 args? BEQ 10$ ; Yes. MOV #-3,R0 ; No. Default window. CMP R3,#2 BEQ 10$ ; 2 args? JMP BADFUN ; No. Baaaad. 10$: CALL GWIN MOV (R2)+,W.LM(R3) MOV (R2),W.RM(R3) CMP W.CX(R3),W.LM(R3) ; Outside margins? BLOS 20$ ; Yes. CMP W.CX(R3),W.RM(R3) BHIS 20$ ; Yes. RETURN ; No. Done. 20$: MOV W.LM(R3),W.CX(R3) ; Outside margins. Move to left margin. INC W.CX(R3) CALLR SCRCUR ; And move actual cursor. ; ; EXT:16 10 6 move_window window y x ; .ENABL LSB WINMOV:: .INSTR "move_window",#3 MOV (R2)+,R0 ; Get window number. CALL GWIN ; Point at structure. MOV (R2)+,W.WY(R3) ; Set window coordinates. MOV (R2),W.WX(R3) CALLR SCRCUR ; Move cursor, since window moved. ; ; EXT:17 11 6 window_size window y x ; .ENABL LSB WINSIZ:: .INSTR "window_size",#3 MOV (R2)+,R0 CALL GWIN MOV (R2)+,W.YS(R3) MOV (R2),W.XS(R3) MOV W.YS(R3),W.LC(R3) RETURN ; ; EXT:18 12 6 window_style window flags operation ; .ENABL LSB WINSTY:: .INSTR "window_style",#3 MOV (R2)+,R0 CALL GWIN MOV (R2)+,R1 DEC R1 BLT 10$ BEQ 20$ DEC R1 BEQ 30$ MOV (R2),R2 XOR R2,W.ATTR(R3) RETURN 10$: MOV (R2),W.ATTR(R3) RETURN 20$: BIS (R2),W.ATTR(R3) RETURN 30$: BIC (R2),W.ATTR(R3) RETURN ; ; EXT:19 13 6 get_wind_prop window property-number -> (result) ; .ENABL LSB GWINPR:: .INSTR "get_wind_prop",#2 MOV (R2)+,R0 CALL GWIN MOV (R2),R2 ASL R2 ADD R2,R3 ; Hey, on a VAX we would have MOV (R3),R0 ; MOVW (R3)[R2],R0 CALLR RESULT ; ; EXT:25 19 6 put_wind_prop window property-number value ; .ENABL LSB PWINPR:: .INSTR "put_wind_prop",#3 MOV (R2)+,R0 CALL GWIN MOV (R2)+,R1 ASL R1 ADD R1,R3 MOV (R2),(R3) RETURN ; ; EXT:20 14 6 scroll_window window pixels ; SCROLL:: .INSTR "scroll_window",#2 MOV ACTSCR,-(SP) ; Save active screen. MOV (R2)+,R0 ; Get window #. CALL GWIN ; Point to structure. CALL SETW2 ; Select window. MOV (R2),R2 ; Get scroll amount. CALL SCRSCR ; Perform scroll. MOV (SP)+,R3 ; Get old active screen. CALLR SETW2 ; Restore it. ; .END