mirror of
https://github.com/erkyrath/infocom-zcode-terps.git
synced 2026-02-08 09:11:27 +00:00
4362 lines
116 KiB
NASM
4362 lines
116 KiB
NASM
TITLE ZIP Z-LANGUAGE INTERPRETER IBM/MS-DOS 2.0 VERSION
|
|
|
|
PAGE 58,132
|
|
.LIST
|
|
|
|
; Modification History -
|
|
;---------------------------------------------------
|
|
;
|
|
; 1) REWORKED FOR NEW SETUP FILE USAGE
|
|
; 2) FIXED NON-WORKING STACK SAVE AND RESTORE FILE
|
|
; 3) FIX RANDOM BUG - 6/25/84
|
|
; 4) FIXED STATUS LINE (LONG ROOM DESCRIPTION) - 07/24/84
|
|
; 5) Fixed status line bug on restart 22-Oct-84 - PHG "G"
|
|
; 6) REWRITE OF ZIP TO USE ALL MEMORY 1-NOV-84 - PHG "H"
|
|
; 7) Combination of IBM and MSZIP with new copy protection
|
|
; for all IBM compatible machines. 11-Mar-85 - PHG
|
|
; Minor versions: I -- original to test
|
|
; J -- fixed status line and more
|
|
; k -- enhanced printer timeout for IBM
|
|
; l -- mcrlf added to save, commenting
|
|
; m -- fixed status line for TI-PRO
|
|
; n -- added insert game disk on save
|
|
; and paging problems. Also reworked
|
|
; scripting.
|
|
; o -- fixed script on restart, no script on
|
|
; more, and minor save problems
|
|
; q -- fixed disk switch for verify
|
|
;
|
|
; r -- fixed status line bugs and refixed
|
|
; disk switch on restart.
|
|
; s -- restart bug on Tandy (their incompati-
|
|
; bility and more on restart
|
|
; t -- removed extra CR from opening screen bet
|
|
; ween last line of text and prompt.
|
|
; u -- Fixed mchri not to echo character on
|
|
; more or insert game disks.
|
|
; v -- fixed broken restore or failed save on
|
|
; low memory configuration, error in fit
|
|
; calculation, /k was fixed to work any
|
|
; where on the cmdline.
|
|
; w -- added /P for PCjr support, fixed still
|
|
; broken end of memory calculation caused
|
|
; by forgetting to count prelod blocks as
|
|
; used memory blocks. Also fixed opread
|
|
; so that it would flush words read greater
|
|
; than 59.
|
|
; x -- fix script checks from cmp to test.
|
|
; to fix wishbringer. RELEASE AS H
|
|
; J z -- stab at verify/paging bug, found in
|
|
; newzpc when setting curtab to zero since
|
|
; page is preloaded, didn't set zpcseg to
|
|
; 0 as well. RELEASE AS J
|
|
; J 1 -- fixed script bug on failed restore
|
|
; K 1 -- fixed save/restore bug. Removed srblks
|
|
; 2 -- fixed fix above which was still broken.
|
|
; 3 -- j1 was broken by k2 edit. fixed here
|
|
; 4 -- above
|
|
; 5 -- fixed restart to set segs to 0
|
|
; 6 -- stab at fixing screwy dos disk flush on
|
|
; create.
|
|
; 7 -- fix screen op to not clear window first
|
|
; 8 -- set min memory to 32k
|
|
; L RELEASE VERSION -- minmem set to 24K
|
|
;
|
|
; M 1 -- fix read in of last virtual block for full game
|
|
; 2 -- fixed a cross segment boundary get in nxtbyt
|
|
; N 1 -- fixed zip to not NEED setup.inf
|
|
; 2 -- added boss key function to MCHRI
|
|
SUBTTL STACK AND DATA SEGMENTS INITIALIZATION
|
|
|
|
ZVERSN EQU "N" ;ZIP VERSION NUMBER
|
|
ZEDIT EQU 0 ; EDIT NUMBER
|
|
ZMVERS EQU 3 ;Z-MACHINE VERSION NUMBER
|
|
LSTACK EQU 512 ;LENGTH OF USER STACK(MUST BE 1 PAGE FOR NOW)
|
|
DEBUG EQU 0
|
|
|
|
PVERS1 EQU 0 ;POSITION OF ZVERSION VERSION BYTE
|
|
PVERS2 EQU 1 ;ZVERSION MODE BYTE
|
|
PZRKID EQU 2 ;ZORKID
|
|
PENDLD EQU 4 ;ENDLOD
|
|
PSTART EQU 6 ;START
|
|
PVOCTB EQU 8 ;VOCAB
|
|
POBJTB EQU 10 ;OBJECT
|
|
PGLOTB EQU 12 ;GLOBALS
|
|
PPURBT EQU 14 ;PURBOT
|
|
PFLAGS EQU 16 ;USER FLAG WORD
|
|
PSERNM EQU 18 ;SERIAL NUMBER (6 BYTES)
|
|
PWRDTB EQU 24 ;WORDS
|
|
PLENTH EQU 26 ;GAME LENGTH
|
|
PCHKSM EQU 28 ;GAME CHECKSUM
|
|
|
|
PADCHR EQU 5 ;PADDING CHARACTER
|
|
|
|
SSVER EQU "A"-10 ; ADD THIS TO THE VERTICAL SETUP HEIGHT
|
|
SSHOR EQU -6 ; ADD THIS TO THE HORIZONTAL SETUP WIDTH
|
|
SSLNT EQU 3 ; LENGTH OF SETUP FILE
|
|
|
|
|
|
CRESET EQU 0H ;MS-DOS FUNCTION CALLS WITH INT 21H
|
|
CCONIN EQU 1H
|
|
CPROUT EQU 5H
|
|
CCONIO EQU 6H
|
|
CNOECHO EQU 7H ; (7) FIX MCHRI TO HAVE NO ECHO
|
|
CRDLIN EQU 0AH
|
|
CDRESET EQU 0DH ; (7o) DISK RESET
|
|
CSELDSK EQU 0EH ; (7n) SELECT DISK
|
|
CFOPEN EQU 0FH
|
|
CFCLOS EQU 10H
|
|
CFDELE EQU 13H
|
|
CFMAKE EQU 16H
|
|
CURDSK EQU 19H ; (7n) CURRENT DISK
|
|
CSDMAO EQU 1AH
|
|
CRDRND EQU 21H
|
|
CWRRND EQU 22H
|
|
CPRSNM EQU 29H
|
|
; FUNCTION CALLS ADDED FOR VERSION "H"
|
|
; UPGRADE TO DOS 2.0 AND ABOVE
|
|
CFCREAZ EQU 3CH
|
|
CFOPENZ EQU 3DH
|
|
CFCLOSZ EQU 3EH
|
|
CRDRNDZ EQU 3FH
|
|
CWRRNDZ EQU 40H
|
|
CFDELEZ EQU 41H
|
|
CFSEEK EQU 42H
|
|
CSETBLK EQU 4AH ; FOR DETERMINING MEM SIZE
|
|
SCROLLUP EQU 6 ; (7) FOR VIDEO BIOS CALL
|
|
DOSVER EQU 30H ; (7) REQUEST FOR DOS VERSION
|
|
BIOSEG EQU 0F800H ; (7) STRINGS ARE FOUND AT F000:E0++
|
|
BIOSOFF EQU 0000H ; (7)
|
|
COLCUR EQU 0607H ; (7) CURSOR SCAN LINES FOR COLOR
|
|
SETCUR EQU 1 ; (7) VIDEO FUNCTION TO SET CURSOR SIZE
|
|
COLATR EQU 17H ; (7) COLOR ATTRIBUTE IS WHITE ON BLUE
|
|
SCRBIT EQU 100000B ; (7) 5 BIT TURNS ON SCREEN SPLITTING
|
|
TOPSCR EQU 0100H ; (7) COORD'S OF TOP OF WINDOW
|
|
STDPRT EQU 4 ; (7) STANDARD PRINTER DEVICE
|
|
PRTMSK EQU 0A1H ; (7) PRINTER INI STATUS MASK
|
|
SCRMSK EQU 0FEFFH ; (7) WORD TO MASK SCRIPT BIT IN MODE WORD
|
|
RDYBIT EQU 1 ; (7) WAS THE PRINTER READY
|
|
MINMEM EQU (24*1024)/16 ; (7) MINIMUM MEMORY IN PARAGRAPHS
|
|
MAXLIN EQU 78 ; (7r) MAXIMUM INPUT LINE LENGTH
|
|
|
|
; ALL SEGS ORIGINALLY POINT TO CSEG. THE ORG 100H IS STANDARD FOR
|
|
; PRODUCING A .COM FILE. THE ES SEGMENT IS ADJUSTED DYNAMICALLY IN THE
|
|
; SYSINI ROUTINE TO ALLOW GAME SEGMENTS TO START AT OFFSET ZERO.
|
|
; SEE COMMENTS IN SYSINI FOR GAME SEGMENT ALLOCATION AND CALCULATION.
|
|
|
|
CSEG SEGMENT PARA PUBLIC
|
|
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
|
|
ORG 100H
|
|
;
|
|
PUBLIC MSZIP
|
|
MSZIP PROC
|
|
JMP START ; SKIP OVER ZIP DATA
|
|
;
|
|
; ALL DATA SAVE THE PAGE TABLE (PAGTAB) ARE DEFINED BETWEEN THE ABOVE JMP
|
|
; AND THE STARTING DESTINATION.
|
|
;
|
|
;VARIBLE DEFINITIONS:
|
|
|
|
PUBLIC START,GAMFILE,SAVFILE,GAMHNDL,SAVHNDL,HANDLE,SEEKF
|
|
PUBLIC LASTDRV,LSTDFLG,DRVFLG,LASTSAV,SSBUF,DEFDRV,CURDRV
|
|
;GTBLKS
|
|
;************************************************************************
|
|
; DO NOT MOVE THESE VARIABLES. DEFINE NOTHING ABOVE THEM. CREATE
|
|
; IS DEPENDENT UPON THIS FIXED VARIABLE SETUP FOR GAMFILE AND
|
|
; SAVFILE.
|
|
;************************************************************************
|
|
;
|
|
GAMFILE DB "WITNESS.DAT",0 ; PATCHED BY CREATE
|
|
DB 53 DUP (0) ; POTENTIAL LENGTH OF FILENAME
|
|
SAVFILE DB "WITNESS.SAV",0
|
|
DB 53 DUP (0) ; POTENTIAL LENGTH OF FILENAME
|
|
LASTSAV DB 64 DUP (0)
|
|
;
|
|
GAMESIZ DW ? ; GAME SIZE IN 512 BYTE BLOCKS
|
|
GAMHNDL DW ? ; FOR STORAGE OF FILE HANDLES
|
|
SAVHNDL DW ?
|
|
SSFILE DB "SETUP.INF",0
|
|
SSBUF DW SSLNT/2 DUP (0)
|
|
SKPDRV DB 0 ; (7n) DON'T OUTPUT DRIVE NAME
|
|
DEFDRV DB ? ; BYTE FOR DEFAULT DRIVE
|
|
CURDRV DB ? ; BYTE FOR NEW DRIVE (SAVES)
|
|
DRVFLG DB 0 ; FLAG WHETHER DRIVE SPECIFIED ON SAVE
|
|
LASTDRV DB ? ; TEMPORARY STORAGE FOR SAVE AND
|
|
LSTDFLG DB ? ; RESTORE FAILURE
|
|
HANDLE DW ? ; GENERAL HANDLE FOR GTBLKS ROUTINE
|
|
SEEKF DB 1 ; FLAG FOR WHETHER OR NOT TO SEEK
|
|
PRTBUF DB ? ; (7) BUFFER FOR PRINTER OUTPUT
|
|
|
|
PUBLIC DSKDIR
|
|
DSKDIR DB 0 ;0 FOR READ, 1 FOR WRITE
|
|
|
|
; SCREEN DEFINITIONS AND ANSI STRINGS
|
|
PUBLIC SCRATR,COLFLG,SCP,RCP,SCPL,SLPP,STINIT,STRESET,SBLINE
|
|
PUBLIC SELINE,SPINIT,STINIT,CTRESET,CBLINE,CELINE,CLS,CLSC
|
|
SCRATR DB 7 ;(7) BLACK BACKGROUND FOR DEFAULT
|
|
COLFLG DB 0 ;(7) ARE WE USING COLOR
|
|
SCPL DB 80 ; WIDTH OF THE SCREEN IN COLUMNS (DEFAULTS)
|
|
SLPP DB 25 ; LENGTH OF THE SCREEN IN ROWS
|
|
SCP DB 3 ; (7) ANSI SAVE CURSOR POSITION
|
|
DB 27,'[s'
|
|
RCP DB 3 ; (7) ANSI RESTORE CURSOR POSITION
|
|
DB 27,'[u'
|
|
STINIT DB 16
|
|
DB 27,"[2J",27,"[0m",27,"[01;01H"
|
|
STRESET DB 4
|
|
DB 27,"[0m"
|
|
SBLINE DB 15
|
|
DB 27,"[37;7m",27,"[01;01H"
|
|
SELINE DB 12
|
|
DB 27,"[0m",27,"["
|
|
SELINE1 DB "25;01H"
|
|
SPINIT DB 0
|
|
CTINIT DB 20
|
|
DB 27,"[37;44m",27,"[2J",27,"[01;01H"
|
|
CTRESET DB 0
|
|
CBLINE DB 16
|
|
DB 27,"[31;47m",27,"[01;01H"
|
|
CELINE DB 16
|
|
DB 27,"[37;44m",27,"["
|
|
CELINE1 DB "25;01H"
|
|
CPINIT DB 0
|
|
CLS DB 12
|
|
DB 27,"[2J",27,"["
|
|
CLS1 DB "25;01H"
|
|
CLSC DB 20
|
|
DB 27,"[37;44m",27,"[2J",27,"["
|
|
CLS1C DB "25;01H"
|
|
;
|
|
PUBLIC WINDOW1,COLWIN1,WINDOW0,COLWIN0,RADIX
|
|
WINDOW1 DB 8
|
|
DB 27,'[02;01H'
|
|
COLWIN1 DB 16
|
|
DB 27,'[02;01H',27,'[34;42m'
|
|
WINDOW0 DB 4
|
|
DB 27,'[0m'
|
|
COLWIN0 DB 8
|
|
DB 27,'[37;44m'
|
|
RADIX DB 10 ; THE DEFAULT RADIX FOR THE SCREEN
|
|
;SCRIPTING STUFF
|
|
PUBLIC GAMEIN,SCRHLD,SCRFLG,PRNNRDY
|
|
GAMEIN DB 0
|
|
SCRHLD DB 0 ; (7n) IS SCRIPTING TEMPORARILY OFF
|
|
SCRFLG DB 0
|
|
PRNNRDY DB " %Printer not ready: Abort or Retry? ",80H
|
|
|
|
;USL STUFF
|
|
SLFLG DB 1 ;STATUS LINE ASSUMED PRESENT
|
|
PMFLAG DB 0 ;AM/PM
|
|
|
|
PUBLIC SLSTR,SLTAB,SLSTAB,SLTTAB
|
|
SLSTR DW 0 ;TOP OF SCREEN STRING
|
|
SLTAB DW 0 ;TABLE USED BY OPUSL
|
|
|
|
|
|
; STATUS LINE DESCRIPTOR TABLE. CHOSEN BASED ON SETUP.INF AND MODE
|
|
; WORD. CHOICE OF STATUS LINE RESULTS WITH STATUS LINE STRING POINTER
|
|
; IN SLSTR AND TABLE DESCRIBING STATUS LINE IN SLTAB.
|
|
;
|
|
SLSTAB DW SLS40
|
|
DW SLS40T
|
|
DW SLS80
|
|
DW SLS80T
|
|
SLTTAB DW SLT40
|
|
DW SLT40T
|
|
DW SLT80
|
|
DW SLT80T
|
|
|
|
; THE FOLLOWING DATA STRUCTURES ARE TABLES AND STRINGS THAT ARE
|
|
; DEFINED TO CREATE AND MAINTAIN A WIDE VARIETY OF STATUS LINES.
|
|
; THE STRUCTURE OF THE DATA IS FIRST A STRING WHERE THE ROOM DESCRIPTION
|
|
; AND THE SCORE/MOVES OR TIME WILL BE WRITTEN. (A POINTER INTO THIS
|
|
; STRING IS CREATED IN TSETUP BASED ON TERMINAL WIDTH)
|
|
;
|
|
; THE STRING IS FOLLOWED BY A TABLE 12 WORDS IN LENGTH. THOSE WORDS
|
|
; CAN BE BROKEN UP INTO 3 GROUPS OF 4 WORDS. THERE IS ONE GROUP FOR
|
|
; EACH OF ROOM DESCRIPTION, SCORE AND MOVES (OR HOURS AND MINUTES).
|
|
; THE FIRST WORD INDICATES WHEN THE ENTRY WAS LAST UPDATED, THE SECOND
|
|
; IS A POINTER TO THE ROUTINE THAT OUTPUTS THE QUANTITY, AND THE THIRD
|
|
; AND FOURTH ARE THE BOUNDARIES OF THE FIELD IN WHICH THE QUANTITY IS
|
|
; WRITTEN.
|
|
;
|
|
; OPUSL AND TSETUP ARE THE ONLY ROUTINES THAT "KNOW" ABOUT THESE DATA
|
|
; STRUCTURES
|
|
|
|
;40 COLUMN, SCORE
|
|
PUBLIC SLS40,SLS40T
|
|
SLS40 DB 40 DUP(32),"S:",5 DUP(32),"M:",6 DUP(32),0,80H
|
|
SLS40T DW -1 ; LAST UPDATE
|
|
DW OPPRND ; ADDR OF PRINT ROOM DESC
|
|
DW 1 ; STARTING COLUMN
|
|
DW 25 ; ENDING COLUMN
|
|
DW -1
|
|
DW OPPRNN
|
|
DW 28
|
|
DW 30
|
|
DW -1
|
|
DW OPPRNN
|
|
DW 35
|
|
DW 40
|
|
|
|
;40 COLUMN, TIME
|
|
PUBLIC SLT40,SLT40T
|
|
SLT40 DB 40 DUP(32),"Time:",10 DUP(32),0,80H
|
|
SLT40T DW -1
|
|
DW OPPRND
|
|
DW 1
|
|
DW 24
|
|
DW -1
|
|
DW OPPRNH
|
|
DW 31
|
|
DW 33
|
|
DW -1
|
|
DW OPPRNM
|
|
DW 34
|
|
DW 40
|
|
|
|
;80 COLUMN, SCORE
|
|
PUBLIC SLS80,SLS80T
|
|
SLS80 DB 110 DUP(32),"Score:", 10 DUP(32),"Moves:",7 DUP(32),0,80H
|
|
SLS80T DW -1
|
|
DW OPPRND
|
|
DW 1
|
|
DW 27
|
|
DW -1
|
|
DW OPPRNN
|
|
DW 57 ; (7) ADJUST SCORE AND MOVES UNITS
|
|
DW 61 ; (7) BACK ONE FOR DA
|
|
DW -1
|
|
DW OPPRNN
|
|
DW 73 ; (7)
|
|
DW 80 ; (7)
|
|
|
|
;80 COLUMN, TIME
|
|
PUBLIC SLT80,SLT80T
|
|
SLT80 DB 120 DUP(32),"Time:", 13 DUP(32),0,80H
|
|
SLT80T DW -1
|
|
DW OPPRND
|
|
DW 1 ; (7) CHANGED FROM 3 FOR CONSISTENCY
|
|
DW 29 ; (7) UNDER DIRECTION BY DA
|
|
DW -1
|
|
DW OPPRNH
|
|
DW 66 ; (7) ADJUST BACKWARDS BY 3 FOR DA
|
|
DW 68 ; (7)
|
|
DW -1
|
|
DW OPPRNM
|
|
DW 69 ; (7)
|
|
DW 80 ; (7)
|
|
|
|
PUBLIC RSEED1,RSEED2
|
|
;OPRAND
|
|
RSEED1 DW ? ;SEED1 FOR RANDOM NUMBERS
|
|
RSEED2 DW ? ;SEED2 FOR RANDOM NUMBERS
|
|
RTEMP DW ? ;TEMP FOR RANDOM ROUTINE
|
|
|
|
PUBLIC RDWSTR,RDBOS,RDEOS,RDRET,RDNWDS,WRDOFF
|
|
;READ
|
|
RDWSTR DW 4 DUP(0) ;WORD STRING BUFFER FOR ZWORD
|
|
RDBOS DW 0 ;BEGINNING OF STRING POINTER
|
|
RDEOS DW 0 ;END OF STRING POINTER
|
|
RDRET DW 0 ;RETURN TABLE POINTER
|
|
RDNWDS DB 0 ;NUMBER OF WORDS READ
|
|
;PUTSTR
|
|
WRDOFF DW 0 ;OFFSET INTO WORD TABLE FOR CURRENT SET
|
|
|
|
PUBLIC CHRPTR,ENDBUF
|
|
;PUTCHR
|
|
CHRPTR DW 0 ;POINTS TO NEXT CHARACTER POSITION
|
|
ENDBUF DW 0 ;POINTS JUST PAST END OF OUTPUT BUFFER (0)
|
|
;GETNUM
|
|
STATUS DW 0 ;STATUS-LINE-REQUESTED FLAG
|
|
|
|
PUBLIC IRBRKS,TIMEMD,ZORKID,ENDLOD,VOCTAB,OBJTAB
|
|
PUBLIC GLOTAB,WRDTAB,PURBOT,ESIBKS,VWLEN,VWORDS,VOCBEG
|
|
PUBLIC OUTBUF,INBUF,RBRKS,BUFFERS,PAGES,INITTBL,SEGEND
|
|
;ZIPBGN
|
|
IRBRKS DB " ",9,13,12,".,?",0 ;INITIAL SET OF READ BREAK CHARS
|
|
TIMEMD DW 0 ;TIME(VERSUS SCORE)-MODE-FOR-STATUS-LINE FLAG
|
|
ZORKID DW 0 ;UNIQUE GAME & VERSION IDENTIFIER
|
|
ENDLOD DW 0 ;ENDLOD BLOCK NUMBER
|
|
SEGEND DW 0 ; (6) ENDLOD THAT DOESN'T GET DIDDLED
|
|
VOCTAB DW 0 ;SAVE VOCABULARY TABLE POINTER
|
|
OBJTAB DW 0 ;OBJECT TABLE POINTER
|
|
GLOTAB DW 0 ;GLOBAL TABLE POINTER
|
|
WRDTAB DW 0 ;WORD TABLE POINTER
|
|
PURBOT DW 0 ;PURE CODE POINTER
|
|
ESIBKS DW 0 ;END OF SELF-INSERTING BREAK CHARACTERS
|
|
VWLEN DW 0 ;NUMBER OF BYTES IN A VOCABULARY WORD ENTRY
|
|
VWORDS DW 0 ;NUMBER OF WORD ENTRIES IN VOCABULARY
|
|
VOCBEG DW 0 ;BEGINNING OF ACTUAL VOCABULARY
|
|
OUTBUF DB 81 DUP(?) ;OUTPUT BUFFER
|
|
INBUF DB MAXLIN+2 DUP(?) ;INPUT BUFFER
|
|
RBRKS DB 32 DUP(?) ;STRING OF READ BREAK CHARACTERS
|
|
BUFFERS DW 0 ;(6) NUMBER OF 512 BYTE BUFFERS FOR PAGING
|
|
PAGES DW 0 ;SWAPPING AREA
|
|
CHRFLG DB 0
|
|
INITTBL DB 254,0,0,0
|
|
|
|
; CMDLIN WAS CREATED FOR CHANGING CERTAIN PARAMETERS ON THE COMMAND LINE
|
|
; CURRENTLY THERE ARE SWITCHES (C,M,W). BITS ARE SET IN SCANCMD AND
|
|
; PROCESSED IN SYSINI OR SSETUP.
|
|
;
|
|
PUBLIC CMDLIN,MEMORY
|
|
CMDLIN DB 0 ; (7n) 16=IBM PARALLEL PRINTER
|
|
; (7) 8=SCROLL SET
|
|
; (7) 4=MEMORY SET
|
|
; (7) 2=COLOR SET
|
|
; (7) 1=MONOCHROME SET
|
|
MEMORY DW 0 ; (7) MEMORY SIZE SET ON CMDLIN
|
|
|
|
PUBLIC ZLOCS,ZPC1,ZPC2,ARGBLK,ZPCSEG,ZPCFLG
|
|
;RESTRT
|
|
ZLOCS DW 0 ;POINTER TO LOCALS
|
|
ZPC1 DW 0 ;ZPC BLOCK-POINTER
|
|
ZPC2 DW 0 ;ZPC BYTE-POINTER
|
|
ZPCSEG DB 0 ;(6) GAME SEGMENT WHERE ZPC IS
|
|
ZPCFLG DB 0 ; (7n) ZPC PAGE IS MUNGED?
|
|
ARGBLK DW 4 DUP(?) ;ARGUMENT BLOCK FOR EXTENDED OPERATIONS
|
|
|
|
PUBLIC CURPAG,CURBLK,CURTAB,CURSEG
|
|
;NEWZPC
|
|
CURPAG DW 0 ;CURRENT PAGE (WHERE ZPC IS) POINTER
|
|
CURBLK DW 0 ;CURRENT BLOCK, USUALLY SAME AS ZPC1
|
|
CURTAB DW 0 ;CURRENT PAGE TABLE POINTER +1
|
|
|
|
PUBLIC RTIME1,RTIME2,LPAGE,LPLOC,LPTAB,GAMESEG,SEG1,FITS
|
|
;GETPAG
|
|
RTIME1 DB 0 ;REFERENCE TIME, 1 1/2 WORDS USED
|
|
RTIME2 DW 0
|
|
LPAGE DW 0 ;LAST REFERENCED PAGE NUMBER
|
|
LPLOC DW 0 ;AND ITS CORE LOCATION
|
|
LPTAB DW 0 ;AND ITS TABLE POINTER
|
|
GAMESEG DW ? ;(6) FIRST (OR ZERO) GAME SEGMENT
|
|
SEG1 DW ? ;(6) SECOND GAMESEG (GAMESEG+64K)
|
|
CURSEG DB 0 ;(6) SEGMENT (0/1) FOR CURRENT PAGE
|
|
FITS DB 0 ;(6) FLAG FOR GAME ALL IN MEMORY
|
|
|
|
; SPLIT AND SCREEN VARS
|
|
PUBLIC SCRNFLG,SPLCOL,SPLTFLG
|
|
SCRNFLG DB 0 ; (7) WINDOW THAT WE ARE WRITING IN
|
|
SPLCOL DB 27H ; (7) GREEN BACKGROUD FOR WINDOW 1
|
|
SPLTFLG DB 0 ; (7) IS THE SCREEN SPLIT
|
|
|
|
;OPERATION TABLES: ;ZERO ARGUMENT OPERATIONS
|
|
PUBLIC ZEROOP,ONEOP,EXTOP
|
|
ZEROOP DW OPRTRU ;176
|
|
DW OPRFAL ;177
|
|
DW OPPRNI ;178
|
|
DW OPPRNR ;179
|
|
DW OPNOOP ;180
|
|
DW OPSAVE ;181
|
|
DW OPREST ;182
|
|
DW OPRSTT ;183
|
|
DW OPRSTA ;184
|
|
DW OPFSTA ;185
|
|
DW OPQUIT ;186
|
|
DW OPCRLF ;187
|
|
DW OPUSL ;188
|
|
DW OPVERI ;189
|
|
DW 0 ;190
|
|
DW 0 ;191
|
|
;ONE ARGUMENT OPERATIONS
|
|
ONEOP DW OPQZER ;128
|
|
DW OPQNEX ;129
|
|
DW OPQFIR ;130
|
|
DW OPLOC ;131
|
|
DW OPPTSI ;132
|
|
DW OPINC ;133
|
|
DW OPDEC ;134
|
|
DW OPPRNB ;135
|
|
DW 0 ;136
|
|
DW OPREMO ;137
|
|
DW OPPRND ;138
|
|
DW OPRETU ;139
|
|
DW OPJUMP ;140
|
|
DW OPPRIN ;141
|
|
DW OPVALU ;142
|
|
DW OPBCOM ;143
|
|
;TWO ARGUMENT AND EXTENDED ARGUMENT OPERATIONS
|
|
EXTOP DW 0 ;0
|
|
DW OPQEQU ;1
|
|
DW OPQLES ;2
|
|
DW OPQGRT ;3
|
|
DW OPQDLE ;4
|
|
DW OPQIGR ;5
|
|
DW OPQIN ;6
|
|
DW OPBTST ;7
|
|
DW OPBOR ;8
|
|
DW OPBAND ;9
|
|
DW OPQFSE ;10
|
|
DW OPFSET ;11
|
|
DW OPFCLE ;12
|
|
DW OPSET ;13
|
|
DW OPMOVE ;14
|
|
DW OPGET ;15
|
|
DW OPGETB ;16
|
|
DW OPGETP ;17
|
|
DW OPGTPT ;18
|
|
DW OPNEXT ;19
|
|
DW OPADD ;20
|
|
DW OPSUB ;21
|
|
DW OPMUL ;22
|
|
DW OPDIV ;23
|
|
DW OPMOD ;24
|
|
DW 0 ;25
|
|
DW 0 ;26
|
|
DW 0 ;27
|
|
DW 0 ;28
|
|
DW 0 ;29
|
|
DW 0 ;30
|
|
DW 0 ;31
|
|
DW OPCALL ;224
|
|
DW OPPUT ;225
|
|
DW OPPUTB ;226
|
|
DW OPPUTP ;227
|
|
DW OPREAD
|
|
;228
|
|
DW OPPRNC ;229
|
|
DW OPPRNN ;230
|
|
DW OPRAND ;231
|
|
DW OPPUSH ;232
|
|
DW OPPOP ;233
|
|
DW OPSPLT ;234
|
|
DW OPSCRN ;235
|
|
DW 0 ;236
|
|
DW 0 ;237
|
|
DW 0 ;238
|
|
DW 0 ;239
|
|
DW 0 ;240
|
|
DW 0 ;241
|
|
DW 0 ;242
|
|
DW 0 ;243
|
|
DW 0 ;244
|
|
DW 0 ;245
|
|
DW 0 ;246
|
|
DW 0 ;247
|
|
DW 0 ;248
|
|
DW 0 ;249
|
|
DW 0 ;250
|
|
DW 0 ;251
|
|
DW 0 ;252
|
|
DW 0 ;253
|
|
DW 0 ;254
|
|
DW 0 ;255
|
|
|
|
;(7) COPY PROTECTION STUFF
|
|
PUBLIC COMPATS,COMP1
|
|
COMPATS DW 2 ; (7) NUMBER OF STRINGS IN THE LIST
|
|
COMP1 DB 'COMPAQ Co$'
|
|
DB 'COPR. IBM$' ; (7) EACH STRING MUST BE 9 CHARS
|
|
; DB 'Tandy Cor$' ; (7v) ADD TANDY
|
|
|
|
;MCRLF
|
|
PUBLIC SCROLL,TOPLIN,MORLIN
|
|
; (7) SCROLL IS SEEMINGLY BACKWARDS BUT TOO INTERWOVEN TO
|
|
; GO AROUND AND FIX NOW.
|
|
; 0 = IBM Compatible 100% (use windowed scrolling)
|
|
; 1 = MS-DOS, no windowed scrolling
|
|
;
|
|
SCROLL DB 1
|
|
TOPLIN DW TOPSCR ; (7) WORD FOR CH,CL FOR UPPER RIGHT
|
|
MORE DB "**MORE** ",80H
|
|
EMORE DB 13," ",13,80H
|
|
MORLIN DW 0 ; (7) COUNT OF LINES SCROLLED WITHOUT PAUSE
|
|
|
|
;STRUCTURE AND RECORD DEFINITIONS:
|
|
;OBJECT OPERATIONS
|
|
OBJECT STRUC
|
|
FLAGS1 DW ?
|
|
FLAGS2 DW ?
|
|
PARENT DB ?
|
|
SIBLING DB ?
|
|
CHILD1 DB ?
|
|
PROPS DW ?
|
|
OBJECT ENDS
|
|
PROPID RECORD PROPSIZE:3,PROPNUM:5
|
|
|
|
;STRING DEFINITIONS
|
|
|
|
;STATION IDENTIFICATION
|
|
PUBLIC IDSTR
|
|
IDSTR DB "IBM/MS-DOS 2.0 Interpreter Version ",ZVERSN,ZEDIT,0
|
|
|
|
;TERMINAL SETUP
|
|
SSMSG1 DB "Cannot open Setup File.",0
|
|
SSMSG2 DB "Cannot read Setup File.",0
|
|
SSMSG3 DB "Cannot close Setup File.",0
|
|
|
|
PUBLIC SAV0,SAV1,SAV2,SAV3,ERR1,ERR2,ERR3,ERR4,ERR5,ERR6
|
|
;SAVE/RESTORE
|
|
SAV0 DB "Insert save disk then enter file name.",0
|
|
SAV1 DB "(Default is ",80H
|
|
SAV2 DB "): ",80H
|
|
SAV3 DB "Insert game disk then strike any key to continue.",0
|
|
|
|
ERR1 DB "SAVE file not found",0
|
|
ERR3 DB "Bad file name syntax",0
|
|
ERR4 DB "Unable to access file",0
|
|
ERR5 DB "No room on diskette for SAVE file",0
|
|
ERR6 DB "Read of SAVE file failed",0
|
|
;READ
|
|
ERR2 DB "Too many words typed, flushing: ",80H
|
|
|
|
PUBLIC FTL2,FTL4,FTL5,FTL6,FTL7,FTL9
|
|
;OPNEXT/OPPUTP
|
|
FTL2 DB "No such property",0
|
|
;ZIPBGN
|
|
FTL4 DB "Wrong game or version",0
|
|
;NXTINS
|
|
FTL5 DB "Illegal operation",0
|
|
;FINDPG
|
|
FTL6 DB "No free pages",0
|
|
;GTBLKS
|
|
FTL7 DB "Game file read error",0
|
|
;SYSINI
|
|
FTL9 DB "Game file not found",0
|
|
FTL10 DB 'Unauthorized copy',0
|
|
FTL11 DB 'Wrong DOS version. Must be 2.0 or higher',0
|
|
FTL12 DB 'Insufficient memory to play game',0
|
|
|
|
;Fatal error header
|
|
FATHDR DB "Fatal error: ",80H
|
|
;ZSTR CHARACTER CONVERSION VECTOR
|
|
|
|
PUBLIC ZCHRS
|
|
ZCHRS DB "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
DB " 0123456789.,!?_#'"
|
|
DB '"/\-:()'
|
|
|
|
PUBLIC STK_TOP,STKBOT,ZSTK_TP
|
|
; STACK SETUP
|
|
DW 200H DUP(?)
|
|
STK_TOP LABEL WORD
|
|
STKBOT DW LSTACK DUP(?)
|
|
ZSTK_TP LABEL WORD
|
|
;
|
|
SUBTTL MACROS
|
|
PAGE +
|
|
GTAWRD MACRO D,S ;;GET ABSOLUTE WORD
|
|
MOV D&X,ES:&S
|
|
XCHG D&H,D&L
|
|
ENDM
|
|
|
|
PTAWRD MACRO D,S ;;PUT ABSOLUTE WORK
|
|
XCHG S&H,S&L
|
|
MOV ES:&D,S&X
|
|
ENDM
|
|
|
|
MOVM MACRO D,S,R ;;MOVE MEMORY TO MEMORY
|
|
MOV R,S
|
|
MOV D,R
|
|
ENDM
|
|
|
|
PUSHZ MACRO S ;;PUSH ONTO Z STACK
|
|
XCHG SP,DI
|
|
PUSH S
|
|
XCHG SP,DI
|
|
ENDM
|
|
|
|
POPZ MACRO D ;;POP FROM Z STACK
|
|
XCHG SP,DI
|
|
POP D
|
|
XCHG SP,DI
|
|
ENDM
|
|
|
|
POPZT MACRO D ;;GET TOP OF Z STACK
|
|
MOV D,SS:[DI]
|
|
ENDM
|
|
|
|
PUSHZT MACRO S ;;PUT TOP OF Z STACK
|
|
MOV SS:[DI],S
|
|
ENDM
|
|
|
|
PRINT MACRO STR ;;PRINT A STRING, POINTER IS ARGUMENT
|
|
PUSH AX
|
|
MOV AX,OFFSET STR
|
|
CALL MPRNT
|
|
POP AX
|
|
ENDM
|
|
|
|
FATAL MACRO ERR ;;PRINT FATAL ERROR AND DIE
|
|
CALL MCRLF
|
|
MOV AX,OFFSET FATHDR
|
|
CALL MPRNT
|
|
MOV AX,OFFSET ERR
|
|
CALL MPRNT
|
|
JMP FINISH
|
|
ENDM
|
|
|
|
SUBTTL SYSTEM INITIALIZATION
|
|
PAGE +
|
|
|
|
PUBLIC START
|
|
START: MOV SP,OFFSET STK_TOP
|
|
MOV DI,OFFSET ZSTK_TP
|
|
JMP ZIPBGN ;JUMP TO BEGINNING OF ZIP CODE
|
|
;
|
|
PUBLIC OPSPLT,OPSCRN
|
|
OPSCRN PROC
|
|
MOV SCRNFLG,AL ; (7) TOGGLE SCREEN CURRENTLY ON
|
|
TEST AL,AL ; (7) WHICH DO WE WANT
|
|
JZ SCRN0 ; (7) SELECT BOTTOM, SCROLLING WINDOW
|
|
CALL SAVECUR
|
|
SCRN1: MOV BX,OFFSET WINDOW1 ; (7) HOME THE CURSOR
|
|
TEST COLFLG,1 ; (7) SHOULD WE SET THE COLOR
|
|
JZ SCRN2 ; (7) NOPE
|
|
MOV BX,OFFSET COLWIN1 ; (7) CLEAR SCREEN WITH COLOR
|
|
SCRN2: CALL MSPRT ; (7) WITH ANSI LOCATE
|
|
RET
|
|
SCRN0: CALL RESTCUR ; (7) RESTORE THE CURSOR POSITION
|
|
MOV BX,OFFSET WINDOW0
|
|
TEST COLFLG,1 ; (7) SHOULD WE CHANGE THE COLOR
|
|
JZ SCRN3 ; (7) NOPE...
|
|
MOV BX,OFFSET COLWIN0
|
|
SCRN3: CALL MSPRT ; (7) RESTORE COLOR
|
|
RET
|
|
OPSCRN ENDP
|
|
|
|
OPSPLT PROC
|
|
XOR AH,AH
|
|
CMP AL,0
|
|
JNZ SPL1 ; (7) YES, FIGURE WINDOW SIZE
|
|
MOV SPLTFLG,0 ; (7) TURN OFF SPLIT SCREEN
|
|
MOV TOPLIN,TOPSCR ; (7) RESTORE TOPLIN TO WHOLE SCR
|
|
MOV MORLIN,0 ; (7) RESET THE MORE LINE COUNT
|
|
CALL RESTCUR
|
|
RET
|
|
SPL1: MOV SPLTFLG,1 ; (7) TURN ON SPLIT SCREEN
|
|
CMP AL,SLPP ; (7) ARE THERE THIS MANY LINES
|
|
JLE SPL2
|
|
MOV AL,SLPP ; (7) USE NO MORE THAN THE SCREEN
|
|
DEC AL ; (7) LEAVE A SCROLL LINE
|
|
SPL2: XCHG AH,AL ; (7) GET #LINES IN TOP HALF
|
|
ADD TOPLIN,AX ; (7) THIS FIXES WINDOW 0 SCROLL SIZE
|
|
PUSH AX ; (K7) FIX CLEAR ON SPLIT SCREEN
|
|
CALL SAVECUR ; (7) SAVE THE CURSOR POSITION
|
|
MOV BH,SCRATR ; (7) GET ATTRIBUTE INTO BH FOR CLS
|
|
TEST COLFLG,1 ; (7) COLOR BLANK OR VANILLA BLANK
|
|
JZ SPL3 ; (7) VANILLA...
|
|
MOV BH,SPLCOL ; (7) USE THE GREEN CLEAR
|
|
SPL3: POP AX ; (K7) RESTORE AX
|
|
MOV DH,AH ; (7) BLANK WINDOW #1
|
|
; DEC DH ; (7) LESS ONE LINE (REMOVED (K7))
|
|
MOV AH,SCROLLUP ; (7) BLANK THE SCREEN
|
|
MOV AL,0 ; (7) ZERO MEANS ENTIRE WINDOW
|
|
MOV CX,TOPSCR ; (7) FROM UPPER LEFT
|
|
MOV DL,SCPL ; (7) TO LOWER RIGHT
|
|
DEC DL ; (7v) COORDINATES ARE ZERO BASED
|
|
INT 10H ; (7) CALL VIDEO BIOS ROUTINE TO CLS
|
|
CALL RESTCUR ; (7) RESTORE CURSOR POSITION
|
|
RET
|
|
OPSPLT ENDP
|
|
|
|
PUBLIC SAVECUR
|
|
SAVECUR PROC
|
|
MOV BX,OFFSET SCP ; (7) ANSI SAVE CURSOR
|
|
CALL MSPRT
|
|
RET
|
|
SAVECUR ENDP
|
|
|
|
PUBLIC RESTCUR
|
|
RESTCUR PROC
|
|
MOV BX,OFFSET RCP ; (7) ANSI RESTORE CURSOR
|
|
CALL MSPRT
|
|
RET
|
|
RESTCUR ENDP
|
|
|
|
PUBLIC FEEP
|
|
FEEP PROC
|
|
MOV AX,7
|
|
CALL MTTYO ;BELL
|
|
RET
|
|
FEEP ENDP
|
|
;
|
|
; VERIFY
|
|
;
|
|
; OP VERIFY HAS BEEN GIVEN A SPLIT PERSONALITY. THE CASE THAT THE ENTIRE
|
|
; GAME FITS INTO MEMORY CALLS ON OPVR2$ WHICH READS THE GAME IN TWO 64K
|
|
; READS. THE SECOND ES SEGMENT IS USED SO THAT THE SECOND READ WILL RESTORE
|
|
; THE GAME TO ITS ORIGINAL STATE. 64K IS READ IN AND CHECKSUMED AND THEN
|
|
; THE REMAINDER OF THE GAME IS READ BACK IN AND CHECKSUMED.
|
|
;
|
|
; THE ORIGINAL VERIFY FORCES THE PRELOAD TO BE LOADED AGAIN BY SETTING THE
|
|
; ENDLOD POINTER TO ZERO. THIS TRICKS GETBYT INTO THINKING THAT NO PAGES
|
|
; ARE LOCKED ALREADY IN CORE AND FORCES A CALL TO THE PAGING ROUTINES.
|
|
;
|
|
;
|
|
PUBLIC OPVERI
|
|
OPVERI PROC
|
|
CALL GAMOPEN ; (7q) PUT THE DISK BACK IN
|
|
PRINT IDSTR
|
|
CMP FITS,1 ; (6) WHOLE GAME IN???
|
|
JNZ OPVR1$
|
|
JMP OPVR2$
|
|
OPVR1$: MOV AX,ES:[PLENTH] ; (7q) GET END BYTE ADDR
|
|
XCHG AH,AL ; (7q) FLOP BYTES
|
|
MOV ZPCFLG,1 ; (7n) SET MUNGED ZPC FLAG
|
|
PUSH SI
|
|
PUSH DI
|
|
PUSH ENDLOD
|
|
CALL BSPLIT
|
|
MOV SI,AX
|
|
MOV DI,BX
|
|
|
|
CALL TBLINI ; (7n) REINITIALIZE THE PAGE TABLE
|
|
MOV BX,CURTAB
|
|
DEC BX
|
|
MOV AX,CURBLK
|
|
MOV [BX],AX
|
|
MOV AX,0FFFFH
|
|
INC BX
|
|
MOV [BX],AX
|
|
MOV BYTE PTR 2[BX],AL
|
|
|
|
MOV AX,0
|
|
MOV BX,64
|
|
MOV DX,0
|
|
MOV ENDLOD,0
|
|
OPVR1: PUSH SI
|
|
PUSH DI
|
|
PUSH DX
|
|
CALL GETBYT ; GET A BYTE FROM SEG1
|
|
POP DX
|
|
POP DI
|
|
POP SI
|
|
ADD DX,CX ; SUM IT
|
|
CMP AX,SI
|
|
JNE OPVR1
|
|
CMP BX,DI
|
|
JNE OPVR1
|
|
MOV AX,ES:[PCHKSM] ; REMOVED SEG OVERRIDE
|
|
XCHG AH,AL
|
|
POP ENDLOD
|
|
POP DI
|
|
POP SI
|
|
; CALL TBLINI ; (7n) RESET THE TABLE YET AGAIN
|
|
OPVR4: CMP AX,DX
|
|
JE OPVR2
|
|
JMP PFALSE
|
|
OPVR2: JMP PTRUE
|
|
;
|
|
; VERIFY FOR FITS==1 OR ALL OF GAME IS IN MEMORY
|
|
;
|
|
OPVR2$: PUSH SI
|
|
PUSH DI
|
|
PUSH CX
|
|
PUSH DS ; (6) ADDRESS SEGMENT 1
|
|
MOV BX,GAMHNDL ; (6) READ FROM GAME FILE
|
|
MOV SI,GAMESEG ; (6) THROUGH DS
|
|
MOV DS,SI ; (6) SO THAT WE OVERLAY GAME
|
|
MOV CX,0 ; (6) MOVE FILE PTR TO BEGINNING
|
|
MOV DX,64 ; (6) SKIP FIRST 64 BYTES
|
|
MOV AL,0 ; (6) METHOD OF SEEKING
|
|
MOV AH,CFSEEK ; (6) SEEK FUNCTION
|
|
INT 21H ; (6) DO IT
|
|
MOV CX,03FC0H ; (7n) READ 16K AT A TIME
|
|
MOV DX,0C000H ; (6) OFFSET INTO SEGMENT
|
|
MOV AH,CRDRNDZ ; (6) READ FUNCTION
|
|
INT 21H ; (6) DO IT
|
|
CMP AX,CX ; (6) DID WE GET IT ALL
|
|
JNE OPVR5 ; (6) DIE PAINFULLY
|
|
XOR DX,DX ; (7n) ZERO THE CHECKSUM
|
|
CALL CHKSUM ; (6) DO A CHKSUM
|
|
;
|
|
OPVR6: MOV DI,DX ; (7n) SAVE CHECK SUM
|
|
MOV DX,0C000H ; (7n) BUFFER SPACE
|
|
MOV CX,4000H ; (7n) READ 16K EACH TIME
|
|
MOV AH,CRDRNDZ ; (7n) DO A RANDOM READ
|
|
INT 21H ; (7n) DO IT
|
|
CMP AX,CX ; (7n) LAST READ?
|
|
JNE OPVR8
|
|
MOV DX,DI ; (7n) RESTORE CHECKSUM
|
|
CALL CHKSUM
|
|
JMP OPVR6
|
|
OPVR8: MOV AX,ES:[PLENTH] ; (7n) GET FILE LENGTH IN WORDS
|
|
XCHG AH,AL ; (7n) INTO AX
|
|
MOV DX,0 ; (7n) ZERO THIS FOR DIVIDE
|
|
MOV CX,2000H ; (7n) DIVIDE BY NUMBER OF BYTES/2
|
|
DIV CX ; (7n) TO GET REMAINDER
|
|
SHL DX,1 ; (7n) MULT BY 2 TO GET BYTES
|
|
MOV AX,DX ; (7n) DX SHOULD HAVE REM BYTES
|
|
MOV DX,DI ; (7n) RESTORE CHECKSUM
|
|
CALL CHKSUM
|
|
;
|
|
PUSH DX
|
|
MOV CX,0 ; (7n) SEEK TO 48K INTO FILE
|
|
MOV DX,0C000H ; (7n) TO GET OVERWRITTEN PART
|
|
MOV AH,CFSEEK ; (7n) FUNCTION IS SEEK
|
|
MOV AL,0 ; (7n) TO OFFSET FROM BEGINNING
|
|
INT 21H ; (7n) DO IT
|
|
MOV DX,0C000H ; (7n) NOW REFILL SEG WITH ORIG
|
|
MOV CX,4000H ; (7n) READ 16K IN
|
|
MOV AH,CRDRNDZ ; (7n) FUNCTION READ
|
|
INT 21H
|
|
POP DX
|
|
|
|
POP DS ; (6) RESTORES
|
|
POP CX
|
|
POP DI
|
|
POP SI
|
|
MOV AX,ES:[PCHKSM] ; (6) GET CHKSUM
|
|
XCHG AH,AL
|
|
JMP OPVR4
|
|
;
|
|
CHKSUM: MOV CX,AX ; (7n) GET NUMBER ACTUALLY READ
|
|
XOR AX,AX ; (6) ZERO THIS
|
|
MOV SI,0C000H ; (7n) 48K INTO THE BUFFER
|
|
OPVR3: LODSB ; (6) GET A BYTE
|
|
ADD DX,AX ; (6) ADD IT ALL UP
|
|
LOOP OPVR3
|
|
RET
|
|
;
|
|
OPVR5: FATAL FTL7 ; GAME FILE READ ERROR
|
|
OPVERI ENDP
|
|
|
|
;
|
|
; SAVE AND RESTORE HAVE BEEN MODIFIED TO USE DOS 2.0 FILE NAMES. THIS
|
|
; ALLOWS THE USER TO SAVE AND RESTORE TO ANY DISK DRIVE AND ANY SUBDIRECTORY.
|
|
; FILE NAMES ARE READ FROM THE CONSOLE AND TRANSFERRED INTO THE SAVFILE
|
|
; VARIABLE WITH NO PARSING OTHER THAN A CHECK FOR A DISK DRIVE SPECIFIER.
|
|
; IF THE NAME IS TYPED INCORRECTLY, THEN DOS RETURNS AN ERROR WHICH WE
|
|
; REPORT ACCORDINGLY.
|
|
|
|
;
|
|
; RESTORE
|
|
;
|
|
PUBLIC OPREST
|
|
OPREST PROC
|
|
MOV DSKDIR,0 ;INDICATE RESTORE (READ)
|
|
JMP OSV0$
|
|
OPREST ENDP
|
|
|
|
;
|
|
; SAVE
|
|
;
|
|
PUBLIC OPSAVE
|
|
OPSAVE PROC
|
|
MOV DSKDIR,1 ;INDICATE SAVE (WRITE)
|
|
|
|
;
|
|
;COMMON ENTRYPOINT FOR SAVE AND RESTORE
|
|
;
|
|
PUBLIC OSV0$,OSVD1,OSVD2,OSVD3,OSVD4A,OSVPSX,OSVOPW
|
|
PUBLIC OSVOPDF,OSVPS,OSVT0,OSV4X,OSV4Y
|
|
; PUBLIC OSVCC,OSV1C,OSV2C
|
|
PUBLIC OSV4,OSVPRR
|
|
; DO A DISK RESET IN CASE THEY WANT TO CHANGE DISKS
|
|
; UNFORTUNATELY WE HAVE TO ASSUME A 1 DRIVE SYSTEM AT THIS POINT
|
|
|
|
OSV0$: CMP FITS,1 ; (n) ARE WE ALL THERE
|
|
JZ OSV0A ; (n) YES, NO CLOSE
|
|
MOV AH,CFCLOSZ ; (7s) CLOSE THE GAME FILE
|
|
MOV BX,GAMHNDL ; (7s) FOR REINSERTION
|
|
INT 21H
|
|
MOV AH,CDRESET ; (K6) WILL RESET FLUSH BUFFERS?
|
|
INT 21H ; (K6) HOPE SO...
|
|
|
|
; PRINT "FILENAME (DEFAULT IS drv:filename.ext):"
|
|
|
|
; PRINT "FILENAME (DEFAULT IS drv:"
|
|
OSV0A: PRINT SAV0 ;PRINT "INSERT SAVE DISK THEN ENTER FILE NAME."
|
|
PRINT SAV1 ;PRINT "FILE NAME (DEFAULT IS "
|
|
TEST DRVFLG,1 ; HAS USER SPECIFIED A DRIVE
|
|
JNZ OSVD1 ; YES, USE USER DEFAULT DRIVE
|
|
MOV AL,CURDRV ;AL <= DRIVE NO.
|
|
ADD AL,65 ;....NO. ADD 65 TO GET ASCII CHARACTER
|
|
CALL MTTYO ;PRINT DRIVE B, C, OR D
|
|
MOV AL,":" ;PRINT ":"
|
|
CALL MTTYO
|
|
|
|
; PRINT "filename"
|
|
OSVD1: PUSH SI ; (6) SAVE THIS
|
|
MOV SI,OFFSET SAVFILE ; (6) POINTER TO SAVE FILENAME (6)
|
|
MOV CX,SI ; (6) SAVE POINTER
|
|
CLD ; (6) SET DIR INCREMENT
|
|
OSVD2: LODSB ; (6) GET A BYTE INTO AL
|
|
TEST AL,AL ; (6) CHECK IF NULL
|
|
JZ OSVD3 ; (6) EXIT THIS LOOP
|
|
CALL MTTYO ; (6) OUTPUT IT
|
|
JMP OSVD2
|
|
OSVD3: SUB SI,CX ; (6) CALCULATE NUMBER OF CHARS
|
|
MOV CX,SI ; (6) GET NUMBER BACK INTO CX
|
|
POP SI ; (6) RESTORE THIS
|
|
|
|
; PRINT " ): "
|
|
PRINT SAV2 ;PRINT " ): "
|
|
CMP SCPL,50 ;ARE MAX CHARS/LINE >50?
|
|
JG OSVD4A ;....YES
|
|
CALL MCRLF ;....NO. PRINT A <cr><lf>
|
|
|
|
; GET LOSER'S SAVE FILENAME FROM THE KEYBOARD
|
|
OSVD4A: MOV BX,OFFSET INBUF ;^ KEYBOARD INPUT BUFFER
|
|
MOV AL,63 ;(6) COULD BE A WHOLE PATH
|
|
MOV BYTE PTR [BX],AL ;SET UP BUFFER TO TAKE 15 CHARACTERS
|
|
MOV DX,BX ;DX ^ BUFFER
|
|
MOV AH,CRDLIN ;READ A LINE FROM THE KEYBOARD
|
|
INT 21H
|
|
|
|
; PARSE THE FILENAME
|
|
|
|
CALL SAVESAV ; (7o) PRESERVE THE SAVE NAME
|
|
PUSH SI
|
|
PUSH DI
|
|
PUSH CX ; SAVE THIS
|
|
PUSH ES
|
|
PUSH DS
|
|
POP ES
|
|
LEA SI,INBUF[1] ; POINT TO NUM CHARS READ
|
|
LODSB ; GET NUM
|
|
TEST AL,AL ; ANY CHARS READ
|
|
JZ LOOK
|
|
MOV CL,AL ; STORE IT
|
|
XOR CH,CH ; CLEAR TOP HALF OF COUNTER
|
|
MOV DI,OFFSET SAVFILE ; (6) DI ^FCB
|
|
REPZ MOVSB ; TRANSFER THE STRING IF ANY
|
|
MOV AL,0 ; (6) GET A NULL
|
|
STOSB ; (6) DROP IT IN AT END OF STRING
|
|
LOOK: TEST SCRFLG,1 ; (7p) IS SCRIPTING ON?
|
|
JZ NOSCR ; (7p) NO SCRIPTING
|
|
CALL SCRSAVE ; (7p) SCRIPT THE SAVE FILE NAME
|
|
NOSCR: MOV SI,OFFSET SAVFILE ; (6) IS THERE A ':'
|
|
INC SI
|
|
LODSB ; (6) CHECK IT
|
|
CMP AL,':' ; (6) IF SO, FIX DEFDRV
|
|
JNZ NODRV ; (6) NOPE...
|
|
MOV DRVFLG,1 ; (6) SET FLAG
|
|
MOV AL,SAVFILE ; (7n) GET DRIVE LETTER
|
|
AND AL,5FH ; (7n) UPPERCASIFY
|
|
SUB AL,'A' ; (7n) BASIFY
|
|
CMP AL,CURDRV ; (7n) DON'T CHANGE IF UNNECESSARY
|
|
JZ DRV
|
|
MOV DL,AL ; (7n) SET UP FOR CHGDSK
|
|
MOV AH,CSELDSK ; (7n) SELECT DISK IN DL
|
|
INT 21H
|
|
MOV AH,CURDSK ; (7n) CHECK IF IT WORKED
|
|
INT 21H
|
|
MOV CURDRV,AL ; (7n) SAVE IT
|
|
JMP DRV
|
|
USEDEF: MOV SKPDRV,1 ; (7n) DON'T OUTPUT A DRIVE
|
|
NODRV: MOV DRVFLG,0
|
|
DRV: POP ES
|
|
POP CX
|
|
POP DI ;RESTORE'M
|
|
POP SI
|
|
CALL MCRLF ; (7) SCROLL PROPERLY
|
|
|
|
; OPEN THE FILE IF OP RESTORE
|
|
|
|
CMP DSKDIR,1 ;OP SAVE?
|
|
JE OSVOPW ;....YES
|
|
MOV DX,OFFSET SAVFILE ; 6) ....NO. OP RESTORE. DX ^ FCB
|
|
MOV AH,CFOPENZ ; (6) SELECT DOS OPEN FUNCTION
|
|
MOV AL,0 ; (6) FILE OPEN FOR READING
|
|
INT 21H ;OPEN THE FILE
|
|
JC OSVPSX ; (6) ....NO. FILE NOT FOUND
|
|
JMP OSVPS ;....YES
|
|
;
|
|
; **** ERROR **** [File Not Found]
|
|
;
|
|
OSVPSX: MOV AX,OFFSET ERR1 ;^ "SAVE FILE NOT FOUND" MSG
|
|
JMP OSVPER ;ERROR EXIT
|
|
|
|
; CREATE THE FILE IF OP SAVE
|
|
OSVOPW: MOV DX,OFFSET SAVFILE ; (6) ^ FCB
|
|
MOV CX,0 ; (6) NO SPECIAL ATTRIBUTE
|
|
MOV AH,CFCREAZ ; (6) SELECT DOS CREATE FUNCTION
|
|
INT 21H
|
|
JC OSVOPDF
|
|
JMP OSVPS ;....YES
|
|
;
|
|
; **** ERROR **** [Directory Full]
|
|
;
|
|
OSVOPDF:MOV AX,OFFSET ERR4 ;....NO. ^ "NO ROOM IN DIRECTORY" MSG
|
|
JMP OSVPER ;HOP TO ERROR EXIT
|
|
;
|
|
; WE'VE GOT AN OPEN FILE (WHICH WE CREATED IF IT WAS A SAVE FUNCTION)
|
|
; AND ARE READY TO EITHER READ (RESTORE) OR WRITE (SAVE) AS REQUIRED
|
|
;
|
|
; THE BELOW CODE GRIMLY EXPLAINS THE FORMAT OF A SAVE FILE. BASICALLY,
|
|
; FROM WHAT I CAN TELL, THE LOCALS AND VITALS ARE PUSHED ONTO THE ZSTACK
|
|
; AS WELL AS THE ZPC AND THE ZSTACK POINTER. THIS INFORMATION IS FIRST
|
|
; WRITTEN TO DISK. THEN THE REST OF PURBOT IS WRITTEN TO DISK. THIS CODE
|
|
; ALSO WORKS FOR A RESTORE. SO THE SAVE FILE CONSISTS OF FIRST ZIP INFO
|
|
; SAVED ON DISK FOLLOWED BY THE IMPURE PART OF THE GAME CODE.
|
|
;
|
|
OSVPS: XCHG DI,SP
|
|
PUSH ZPC1 ; PUSH VITALS ONTO ZSTACK
|
|
PUSH ZPC2
|
|
PUSH ZLOCS
|
|
PUSH ZORKID
|
|
|
|
|
|
SUB SP,OFFSET STKBOT ; (7v) RELATIVISE THE POINTER
|
|
MOV STKBOT,SP ; PUT DEST. INDEX INTO STACKBOTTOM
|
|
MOV SP,DI ; RESTORE SP
|
|
|
|
MOV SAVHNDL,AX ; SAVE FILE HANDLE
|
|
PUSH ES
|
|
|
|
MOV AX,SS ; FLOP STACK SEG AND EXTRA SEG
|
|
MOV ES,AX ; ES<=SS
|
|
|
|
MOV DX,OFFSET STKBOT ; CORE LOCATION
|
|
MOV CX,400H ; (6) DO TRANSFER HERE
|
|
MOV BX,SAVHNDL ; (6) GET HANDLE
|
|
MOV AH,CRDRNDZ ; SETUP FOR A READ
|
|
ADD AH,DSKDIR ; MAKE IT A WRITE IF NECESSARY
|
|
INT 21H ;
|
|
CMP AX,400H ; DID WE GET IT ALL
|
|
PUSHF ;SAVE RETURN CODE
|
|
MOV DI,SP ;DI ^ CURRENT ZSTACK POSITION
|
|
MOV SP,STKBOT ;SP <= ZSTACK POINTER
|
|
ADD SP,OFFSET STKBOT ; (7v) RELATIVISE THIS VALUE
|
|
POP AX ; POP OFF AND COMPARE FOR ZORKID
|
|
CMP AX,ZORKID ;ID OK?
|
|
JE OSVT0 ;....YES
|
|
MOV GAMEIN,0 ; (7v) INDICATE THAT THE GAME IS LOST
|
|
FATAL FTL4 ;....NO. FATAL ERROR
|
|
|
|
OSVT0: POP ZLOCS ;RESTORE LOCALS AND ZIP PROGRAM COUNTERS
|
|
POP ZPC2
|
|
POP ZPC1
|
|
|
|
XCHG DI,SP ;RESTORE MACHINE SP AND ZSTACK POINTER
|
|
POPF ;RESTORE REGS
|
|
POP ES
|
|
JNE OSV4Y ;TRANSFER WAS UNSUCCESSFUL
|
|
;
|
|
; THE OPEN/CREATE FILE WAS SUCCESSFUL, AND SO WAS THE BLOCK TRANSFER
|
|
; SO TRANSFER THE REST
|
|
;
|
|
OSV4X: MOV CX,ES:[PPURBT] ; (K3) MAYBE THIS IS WRONG
|
|
XCHG CH,CL ; (K3) XCHANGE BYTES
|
|
MOV AH,CRDRNDZ ; (K1) FUNCTION IS READ (OR WRITE)
|
|
ADD AH,DSKDIR ; (K1) ADD IN WRITE STUFF
|
|
MOV BX,SAVHNDL ; (K1) READ IT FROM HERE
|
|
MOV DX,0 ; (K1) READ IT RIGHT IN TO SEG0
|
|
PUSH DS ; (K1) SAVE DS
|
|
PUSH ES ; (K1) FLOP BYTES
|
|
POP DS ; (K1) ES IS NOW DOS ADDRESSIBLE
|
|
INT 21H ; (K1) DO THE SAVE/RESTORE
|
|
POP DS ; (K1) RESTORE DS
|
|
CMP AX,CX ; (K1) DID WE GET IT ALL?
|
|
OSV4Y: PUSHF ;SAVE DOS RETURN CODE
|
|
MOV AH,CFCLOSZ ; (6) CLOSE THE FILE
|
|
MOV BX,SAVHNDL ; (6) WITH THIS HANDLE
|
|
INT 21H
|
|
POPF ;RESTORE DOS RETURN CODE
|
|
JNE OSV4 ;ERROR EXIT
|
|
;
|
|
;ELSE EVERYTHING WORKED SUCCESSFULLY
|
|
;AND WE CAN GO BACK TO WHAT WE WERE
|
|
;DOING..........
|
|
;
|
|
MOV AH,SCRFLG ; (J2) FIX SCRFLG
|
|
XOR AL,AL ; (J2)
|
|
MOV WORD PTR ES:[PFLAGS],AX ; (J1) SCRIPT SHOULD MATCH SCRFLG
|
|
CMP FITS,1 ;(n) do not need to replace disk if in mem
|
|
JZ n1
|
|
CALL GAMOPEN ; (7s) OPEN GAME FILE
|
|
MOV DL,CURDRV ; (7n) RETURN TO SAVE DISK
|
|
MOV AH,CSELDSK ; (7n) AND SELECT IT FOR OPEN
|
|
INT 21H
|
|
N1: CALL NEWZPC ;GET A NEW PC
|
|
JMP PTRUE
|
|
;
|
|
; **** ERROR **** [Unable to Read File]
|
|
;
|
|
OSV4: MOV AX,OFFSET ERR6 ;^ "Read of SAVE file failed."
|
|
CMP DSKDIR,1 ;OP SAVE?
|
|
JNE OSVPRR ;....NO
|
|
MOV AH,CFCLOSZ ; (6) ....YES. CLOSE IT
|
|
MOV BX,SAVHNDL ; (6) GET HANDLE FOR CLOSE
|
|
INT 21H
|
|
;
|
|
; **** ERROR **** [Diskette Full]
|
|
;
|
|
MOV DX,OFFSET SAVFILE ; (7n) DELETE THE PIECE OF A FILE
|
|
MOV AH,CFDELEZ ; (7n) SO AS NOT TO CONFUSE
|
|
INT 21H
|
|
MOV AX,OFFSET ERR5 ;^ "No room on diskette for SAVE file."
|
|
OSVPRR: JMP OSVPER
|
|
OPSAVE ENDP
|
|
;
|
|
; ERROR EXIT R/W operations
|
|
;
|
|
OSVPER PROC
|
|
CALL MPRNT ;PRINT ERROR MESSAGE
|
|
CALL ZRESTOR ; (7o) RESTORE OLD SAVE NAME
|
|
CMP FITS,1 ; (7v) HAVE WE CLOSED THE GAME FILE
|
|
JZ OSVPR1 ; (7v) SKIP REOPEN
|
|
CALL GAMOPEN ; (7v) OPEN IT
|
|
OSVPR1: MOV AL,SCRFLG ;REENABLE SCRIPTING
|
|
XCHG AH,AL
|
|
XOR AL,AL ; (J1) FIX SCRIPT ON BAD RESTART (RANDOM)
|
|
MOV ES:[PFLAGS],AX
|
|
JMP PFALSE
|
|
OSVPER ENDP
|
|
;
|
|
PUBLIC SAVESAV,ZRESTOR,SCRSAVE
|
|
SCRSAVE PROC
|
|
PUSH AX ; (7p) SAVES
|
|
PUSH SI
|
|
PUSH DX
|
|
MOV SI,OFFSET SAVFILE ; (7p) POINTER TO SAVE
|
|
SCRS0: LODSB ; (7p) GET A CHARACTER
|
|
TEST AL,AL ; (7p) LOOK FOR A NULL
|
|
JNZ SCRS1 ; (7p) DIE ON A NULL
|
|
POP DX
|
|
POP SI
|
|
POP AX
|
|
RET ; (7p) RETURN
|
|
SCRS1: MOV DL,AL ; (7p) GET CHARACTER INTO DL
|
|
MOV AH,CPROUT ; (7p) FOR DOS"IE" OUTPUT
|
|
INT 21H ; (7p) PRINT IT
|
|
JMP SCRS0
|
|
SCRSAVE ENDP
|
|
|
|
SAVESAV PROC
|
|
PUSH DI ; (7o) SAVES
|
|
PUSH SI
|
|
PUSH AX
|
|
PUSH ES
|
|
MOV AX,DS ; (7o) SET UP REGS
|
|
MOV ES,AX
|
|
MOV AL,CURDRV ; (7o) SAVE CURRENT DRIVE SPEC
|
|
MOV LASTDRV,AL ; (7o) IN CASE OF FAILURE
|
|
MOV AL,DRVFLG ; (7o) TEST DRIVE FLAG
|
|
MOV LSTDFLG,AL ; (7o) IN CASE OF FAILURE
|
|
MOV SI,OFFSET SAVFILE ; (7o) SETUP SOURCE AND DESTINATION
|
|
MOV DI,OFFSET LASTSAV
|
|
COPYLP: LODSB ; (7o) GET A BYTE
|
|
STOSB ; (7o) STORE A BYTE
|
|
TEST AL,AL ; (7o) STOP ON A NUL
|
|
JNZ COPYLP ; (7o) CONTINUE THE COPY
|
|
POP ES
|
|
POP AX ; (7o) RESTORES
|
|
POP SI
|
|
POP DI
|
|
RET
|
|
SAVESAV ENDP
|
|
;
|
|
;
|
|
ZRESTOR PROC
|
|
PUSH DI ; (7o) SAVES
|
|
PUSH SI
|
|
PUSH AX
|
|
PUSH ES
|
|
MOV AX,DS ; (7o) SET UP REGS
|
|
MOV ES,AX
|
|
MOV AL,LSTDFLG ; (7o) GET LAST DRIVE FLAG
|
|
MOV DRVFLG,AL ; (7o) AND RESTORE IT
|
|
MOV AL,LASTDRV ; (7o) GET ORIGINAL DRIVE SPEC
|
|
CMP AL,CURDRV ; (7o) HAS IT CHANGED
|
|
JZ ZRES1
|
|
MOV DL,AL ; (7o) SELECT DISK
|
|
MOV AH,CSELDSK ; (7o) TO CORRECT
|
|
INT 21H
|
|
MOV CURDRV,DL ; (7o) UPDATE THIS BABY
|
|
ZRES1: MOV DI,OFFSET SAVFILE ; (7o) SETUP SOURCE AND DESTINATION
|
|
MOV SI,OFFSET LASTSAV
|
|
ZRESLP: LODSB ; (7o) GET A BYTE
|
|
STOSB ; (7o) STORE A BYTE
|
|
TEST AL,AL ; (7o) STOP ON A NUL
|
|
JNZ ZRESLP ; (7o) CONTINUE THE COPY
|
|
POP ES
|
|
POP AX ; (7o) RESTORES
|
|
POP SI
|
|
POP DI
|
|
RET
|
|
ZRESTOR ENDP
|
|
;
|
|
; OP RESTART
|
|
;
|
|
PUBLIC OPRSTT
|
|
OPRSTT PROC
|
|
MOV BP,CHRPTR
|
|
MOV BYTE PTR DS:[BP],0 ;FORCE OUT THE BUFFER
|
|
PRINT OUTBUF
|
|
JMP RESTRT ;JUMP TO RESTART ADDRESS
|
|
OPRSTT ENDP
|
|
|
|
PUBLIC OPQUIT
|
|
OPQUIT PROC
|
|
JMP FINISH
|
|
OPQUIT ENDP
|
|
|
|
; THIS OPCODE IS A PSEUDO-OP. IT IS NEVER CALLED BY THE GAME BUT INSTEAD
|
|
; BY OPREAD. IT IS HEAVILY TIED TO THE STATUS LINE DATA STRUCTURES.
|
|
PUBLIC OPUSL
|
|
OPUSL PROC
|
|
CMP SLFLG,0
|
|
JNE OPUSL1
|
|
RET
|
|
OPUSL1: PUSH DI
|
|
PUSH CHRPTR
|
|
MOV BX,SLSTR
|
|
MOV CHRPTR,BX
|
|
MOV AX,16
|
|
MOV DI,SLTAB
|
|
MOV CX,3
|
|
USLLP: PUSH AX
|
|
CALL GETVAR
|
|
MOV DX,[DI+4]
|
|
CALL USLSET
|
|
PUSH CX
|
|
PUSH DI
|
|
CALL WORD PTR [DI+2]
|
|
POP DI
|
|
MOV DX,[DI+6]
|
|
CALL USLSPC
|
|
USLN: ADD DI,8
|
|
POP CX
|
|
USL1: POP AX
|
|
INC AX
|
|
LOOP USLLP
|
|
MOV AX,"$"
|
|
CALL PUTCHR
|
|
CALL MSOUT
|
|
POP CHRPTR
|
|
POP DI
|
|
RET
|
|
|
|
USLSET: MOV BX,SLSTR
|
|
MOV CHRPTR,BX
|
|
ADD CHRPTR,DX
|
|
RET
|
|
|
|
USLSPC: MOV CX,CHRPTR
|
|
SUB CX,SLSTR
|
|
SUB DX,CX
|
|
MOV CX,DX
|
|
JLE USLSP1
|
|
USLSPL: MOV AX,20H
|
|
CALL PUTCHR
|
|
LOOP USLSPL
|
|
USLSP1: RET
|
|
OPUSL ENDP
|
|
|
|
SUBTTL ARITHMETIC OPERATIONS
|
|
PAGE +
|
|
|
|
PUBLIC OPADD,OPSUB,OPMUL,OPDIV,OPMOD
|
|
;ADD
|
|
OPADD PROC
|
|
ADD AX,BX ;ADD OPR1 AND OPR2
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPADD ENDP
|
|
|
|
;SUB
|
|
OPSUB PROC
|
|
SUB AX,BX ;SUBTRACT OPR2 FROM OPR1
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPSUB ENDP
|
|
|
|
;MULTIPLY AX BY BX
|
|
OPMUL PROC
|
|
IMUL BX ;MULTIPLY OPR1 BY OPR2,IGNORING OVERFLOW(DX)
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPMUL ENDP
|
|
|
|
;DIVIDE AX BY BX
|
|
OPDIV PROC
|
|
CWD ;CLEAR HIGH WORD AND EXTEND SIGN FOR DIVIDE
|
|
IDIV BX ;DIVIDE OPR1 BY OPR2
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPDIV ENDP
|
|
|
|
;MOD
|
|
OPMOD PROC
|
|
CWD ;CLEAR HIGH WORD AND EXTEND SIGN FOR DIVIDE
|
|
IDIV BX ;DIVIDE OPR1 BY OPR2
|
|
MOV AX,DX ;WE WANT REMAINDER
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPMOD ENDP
|
|
|
|
;RANDOM BY DAN
|
|
PUBLIC OPRAND
|
|
OPRAND PROC
|
|
SUB AH,AH ; HACK RANDOM TO ONE BYTE
|
|
MOV RTEMP,AX ; SAVE ARGUMENT FOR LATER
|
|
MOV AX,RSEED1
|
|
MOV BX,RSEED2
|
|
MOV RSEED2,AX
|
|
CLC
|
|
RCR AX,1
|
|
RCR BX,1
|
|
XOR RSEED1,BX ;PUT XOR'D NUBMER INTO RSEED1
|
|
MOV AX,RSEED1 ;THIS IS RANDOM VALUE
|
|
|
|
AND AX,0EFFFH ;CHOP HIGH BIT FOR DIVIDE
|
|
SUB DX,DX ;CLEAR MOST SIGN. PORTION OF 32 BIT WORD
|
|
DIV RTEMP ;DIVIDE WORD BY WORD
|
|
MOV AX,DX ;MOVE REMAINDER INTO AX
|
|
INC AX ;MAKE SURE NO ZERO
|
|
JMP PUTVAL
|
|
OPRAND ENDP
|
|
|
|
;LESS?
|
|
PUBLIC OPQLES,OPQGRT,OPBTST,OPBOR,OPBCOM,OPBAND
|
|
OPQLES PROC
|
|
CMP AX,BX ;IS OPR1 LESS THAN OPR2?
|
|
JL JPT ;YES, PREDICATE TRUE
|
|
JPF: JMP PFALSE ;NO, PREDICATE FALSE
|
|
JPT: JMP PTRUE
|
|
OPQLES ENDP
|
|
|
|
;GRTR?
|
|
OPQGRT PROC
|
|
CMP AX,BX ;IS OPR1 GREATER THAN OPR2?
|
|
JG JPT ;YES, PREDICATE TRUE
|
|
JMP JPF ;NO, PREDICATE FALSE
|
|
OPQGRT ENDP
|
|
|
|
SUBTTL LOGICAL OPERATIONS
|
|
PAGE +
|
|
|
|
;BTST
|
|
OPBTST PROC
|
|
NOT AX ;TURN OFF BITS IN OPR2 THAT ARE ON IN OPR1
|
|
AND BX,AX
|
|
JE JPT ;SUCCESS IF OPR2 COMPLETELY CLEARED
|
|
JMP JPF
|
|
OPBTST ENDP
|
|
|
|
;BOR
|
|
OPBOR PROC
|
|
OR AX,BX ;LOGICAL OR
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPBOR ENDP
|
|
|
|
;BCOM
|
|
OPBCOM PROC
|
|
NOT AX ;LOGICAL COMPLEMENT
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPBCOM ENDP
|
|
|
|
;BAND
|
|
OPBAND PROC
|
|
AND AX,BX ;LOGICAL AND
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPBAND ENDP
|
|
|
|
SUBTTL GENERAL PREDICATES
|
|
PAGE +
|
|
|
|
PUBLIC OPQEQU,OPQZER
|
|
;EQUAL?
|
|
OPQEQU PROC
|
|
NOP ;TELL CALLER TO USE ARGUMENT BLOCK
|
|
MOV BX,ARGBLK ;GET OPR1
|
|
CMP BX,ARGBLK[2] ;IS OPR1 EQUAL TO OPR2?
|
|
JE OQE1$ ;YES
|
|
CMP AX,3 ;NO, IS THERE A THIRD OPERAND?
|
|
JL OQE2$ ;NO
|
|
CMP BX,ARGBLK[4] ;YES, IS IT EQUAL TO OPR1?
|
|
JE OQE1$ ;YES
|
|
CMP AX,4 ;NO, IS THERE A FOURTH?
|
|
JL OQE2$ ;NO
|
|
CMP BX,ARGBLK[6] ;YES, IS IT EQUAL TO OPR1?
|
|
JNE OQE2$ ;NO
|
|
OQE1$: JMP PTRUE ;PREDICATE TRUE IF EQUAL
|
|
OQE2$: JMP PFALSE ;PREDICATE FALSE IF NOT
|
|
OPQEQU ENDP
|
|
|
|
;ZERO?
|
|
OPQZER PROC
|
|
CMP AX,0 ;IS OPR ZERO?
|
|
JNE OQZ1$ ;NO, PREDICATE FALSE
|
|
JMP PTRUE ;YES, PREDICATE TRUE
|
|
OQZ1$: JMP PFALSE
|
|
OPQZER ENDP
|
|
|
|
SUBTTL OBJECT OPERATIONS
|
|
PAGE +
|
|
|
|
PUBLIC OPMOVE,OPREMO,OPQFSE,OPFSET
|
|
;MOVE (OBJ1 INTO OBJ2)
|
|
OPMOVE PROC
|
|
PUSH AX ;PROTECT OPRS FROM REMOVE CALL
|
|
PUSH BX
|
|
CALL OPREMO ;REMOVE OBJ1 FROM WHEREVER IT IS
|
|
POP DX ;OBJ2
|
|
MOV AX,DX
|
|
CALL OBJLOC ;FIND ITS LOCATION
|
|
MOV BX,AX ;MOVE TO BASE
|
|
POP CX ;OBJ1
|
|
MOV AX,CX
|
|
CALL OBJLOC ;FIND ITS LOCATION
|
|
MOV BP,AX ;MOVE TO BASE
|
|
MOV ES:[BP].PARENT,DL ; PUT OBJ2 INTO OBJ1'S LOC SLOT
|
|
MOV DH,ES:[BX].CHILD1 ; GET CONTENTS OF OBJ2'S FIRST SLOT
|
|
MOV ES:[BX].CHILD1,CL ; MAKE OBJ1 FIRST CONTENT OF OBJ2
|
|
CMP DH,0 ;WERE THERE ANY OTHER CONTENTS?
|
|
JE OMV1$ ;NO
|
|
MOV ES:[BP].SIBLING,DH ; YES, CHAIN ONTO OBJ1'S SIBLING SLOT
|
|
OMV1$: RET
|
|
OPMOVE ENDP
|
|
|
|
;REMOVE (OBJ FROM ITS PARENT)
|
|
OPREMO PROC
|
|
MOV CX,AX ;SAVE OBJ FOR LATER
|
|
CALL OBJLOC ;FIND ITS LOCATION
|
|
MOV BX,AX ;MOVE TO BASE
|
|
MOV CH,ES:[BX].PARENT ; GET ITS PARENT
|
|
CMP CH,0 ;DOES IT HAVE A PARENT?
|
|
JE ORM3$ ;IF NOT, WE'RE DONE
|
|
MOV AL,CH ;PARENT
|
|
CALL OBJLOC ;FIND PARENT'S LOCATION
|
|
MOV BP,AX ;MOVE TO BASE
|
|
MOV DL,ES:[BP].CHILD1 ; GET PARENT'S FIRST CONTENT
|
|
CMP DL,CL ;IS IT OBJ?
|
|
JNE ORM1$ ;NO
|
|
MOVM ES:[BP].CHILD1,ES:[BX].SIBLING,AL ;YES, CHANGE SLOT TO
|
|
;OBJ'S SIBLING
|
|
JMP ORM2$ ;AND RETURN
|
|
ORM1$: MOV AL,DL ;CURRENT SIBLING
|
|
CALL OBJLOC ;FIND ITS LOCATION
|
|
MOV BP,AX ;MOVE TO BASE
|
|
MOV DL,ES:[BP].SIBLING ;GET NEXT SIBLING IN CHAIN
|
|
CMP DL,CL ;IS IT OBJ?
|
|
JNE ORM1$ ;NO, CONTINUE LOOP
|
|
MOVM ES:[BP].SIBLING,ES:[BX].SIBLING,AL ;YES, CHANGE IT TO
|
|
;OBJ'S SIBLING
|
|
ORM2$: MOV ES:[BX].PARENT,0 ;OBJ NOW HAS NO PARENT
|
|
MOV ES:[BX].SIBLING,0 ;OR SIBLING
|
|
ORM3$: RET
|
|
OPREMO ENDP
|
|
|
|
;FSET? (IS FLAG SET IN OBJ?)
|
|
OPQFSE PROC
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
CMP BX,16 ;SECOND WORD FLAG?
|
|
JL OQF1$ ;NO
|
|
SUB BX,16 ;YES, SUBTRACT 16 FROM FLAG NUMBER
|
|
INC AX ;AND USE SECOND FLAG WORD
|
|
INC AX
|
|
OQF1$: MOV CX,BX ;MOVE TO COUNT
|
|
MOV BX,AX ;MOVE TO BASE
|
|
GTAWRD A,[BX] ;GET THE FLAG WORD
|
|
MOV DX,8000H ;SHIFT A BIT TO PROPER POSITION
|
|
SHR DX,CL
|
|
TEST AX,DX ;IS THIS BIT SET IN FLAG WORD?
|
|
JE OQF2$ ;NO, PREDICATE FALSE
|
|
JMP PTRUE ;YES, PREDICATE TRUE
|
|
OQF2$: JMP PFALSE
|
|
OPQFSE ENDP
|
|
|
|
;FSET (SET A FLAG IN OBJ)
|
|
OPFSET PROC
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
CMP BX,16 ;SECOND WORD FLAG?
|
|
JL OFS1$ ;NO
|
|
SUB BX,16 ;YES, SUBTRACT 16 FROM FLAG NUMBER
|
|
INC AX ;AND USE SECOND FLAG WORD
|
|
INC AX
|
|
OFS1$: MOV CX,BX ;MOVE TO COUNT
|
|
MOV BX,AX ;MOVE TO BASE
|
|
GTAWRD A,[BX] ;GET THE FLAG WORD
|
|
MOV DX,8000H ;SHIFT A BIT TO PROPER POSITION
|
|
SHR DX,CL
|
|
OR AX,DX ;SET THIS BIT IN FLAG WORD
|
|
PTAWRD [BX],A ;STORE THE NEW FLAG WORD
|
|
RET
|
|
OPFSET ENDP
|
|
|
|
PUBLIC OPFCLE,OPLOC,OPQFIR,OPQNEX,OPQIN
|
|
;FCLEAR (CLEAR A FLAG IN OBJ)
|
|
OPFCLE PROC
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
CMP BX,16 ;SECOND WORD FLAG?
|
|
JL OFC1$ ;NO
|
|
SUB BX,16 ;YES, SUBTRACT 16 FROM FLAG NUMBER
|
|
INC AX ;AND USE SECOND FLAG WORD
|
|
INC AX
|
|
OFC1$: MOV CX,BX ;MOVE TO COUNT
|
|
MOV BX,AX ;MOVE TO BASE
|
|
GTAWRD A,[BX] ;GET THE FLAG WORD
|
|
MOV DX,7FFFH ;SHIFT A BIT TO PROPER POSITION
|
|
ROR DX,CL
|
|
AND AX,DX ;CLEAR THIS BIT IN FLAG WORD
|
|
PTAWRD [BX],A ;STORE THE NEW FLAG WORD
|
|
RET
|
|
OPFCLE ENDP
|
|
|
|
;LOC (RETURN CONTAINER OF OBJ)
|
|
OPLOC PROC
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
MOV BX,AX ;MOVE TO BASE
|
|
MOV AL,ES:[BX].PARENT ; GET LOC SLOT
|
|
JMP BYTVAL ;RETURN THE BYTE VALUE
|
|
OPLOC ENDP
|
|
|
|
;FIRST? (RETURN FIRST SLOT OF OBJ, FAIL IF NONE)
|
|
OPQFIR PROC
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
MOV BX,AX ;MOVE TO BASE
|
|
MOV AL,ES:[BX].CHILD1 ; GET FIRST SLOT
|
|
PUSH AX ;SAVE IT
|
|
CALL BYTVAL ;RETURN THE BYTE VALUE
|
|
POP AX ;RESTORE IT
|
|
CMP AL,0 ;WAS IT ZERO?
|
|
JE JPF1 ;YES, PREDICATE FALSE
|
|
JPT1: JMP PTRUE ;NO, PREDICATE TRUE
|
|
JPF1: JMP PFALSE
|
|
OPQFIR ENDP
|
|
|
|
;NEXT? (RETURN THE NEXT (SIBLING) SLOT OF OBJ, FAIL IF NONE)
|
|
OPQNEX PROC
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
MOV BX,AX ;MOVE TO BASE
|
|
MOV AL,ES:[BX].SIBLING ; GET SIBLING SLOT
|
|
PUSH AX ;SAVE IT
|
|
CALL BYTVAL ;RETURN THE BYTE VALUE
|
|
POP AX ;RESTORE IT
|
|
CMP AL,0 ;WAS IT ZERO?
|
|
JE JPF1 ;YES, PREDICATE FALSE
|
|
JMP JPT1 ;NO, PREDICATE TRUE
|
|
OPQNEX ENDP
|
|
|
|
;IN? (IS OBJ1 CONTAINED IN OBJ2?)
|
|
OPQIN PROC
|
|
CALL OBJLOC ;FIND OBJ1'S LOCATION
|
|
XCHG AX,BX ;MOVE TO BASE
|
|
CMP ES:[BX].PARENT,AL ; IS OBJ1'S PARENT OBJ2?
|
|
JE JPT1 ;YES, PREDICATE TRUE
|
|
JMP JPF1 ;NO, PREDICATE FALSE
|
|
OPQIN ENDP
|
|
|
|
PUBLIC OPGETP
|
|
;GETP (GET SPECIFIED PROPERTY OF OBJ, DEFAULT IF NONE)
|
|
OPGETP PROC
|
|
MOV DX,BX ;PROPERTY
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
MOV BP,AX ;MOVE TO BASE
|
|
GTAWRD B,[BP].PROPS ;GET LOCATION OF ITS PROPERTY TABLE
|
|
MOV AL,ES:[BX] ; LENGTH OF SHORT DESCRIPTION IN WORDS
|
|
SUB AH,AH ;CLEAN OFF ANY HIGH-ORDER BYTE
|
|
SHL AX,1 ;CONVERT TO BYTES
|
|
ADD BX,AX ;ADJUST POINTER TO SKIP IT
|
|
INC BX ;ALSO SKIP LENGTH BYTE
|
|
JMP OGP2$ ;SKIP NEXT LINE FIRST TIME THROUGH LOOP
|
|
OGP1$: CALL NXTPRP ;POINT TO NEXT PROPERTY
|
|
OGP2$: MOV AL,ES:[BX] ; GET PROPERTY IDENTIFIER
|
|
AND AL,MASK PROPNUM ;CLEAN OFF LENGTH BITS
|
|
CMP AL,DL ;COMPARE PROPERTY NUMBER WITH DESIRED ONE
|
|
JG OGP1$ ;IF GREATER, LOOP (TABLE SORTED IN REVERSE)
|
|
JL OGP3$ ;IF LESS, NO SUCH PROPERTY HERE
|
|
MOV AL,ES:[BX] ;GOT IT, NOW FIND LENGTH OF PROPERTY
|
|
INC BX ;POINT TO PROPERTY VALUE
|
|
AND AL,MASK PROPSIZE;GET LENGTH BITS
|
|
MOV CL,PROPSIZE
|
|
SHR AL,CL
|
|
CMP AL,0 ;BYTE VALUE?
|
|
JNE OGP5$ ;NO
|
|
MOV AL,ES:[BX] ;GET THE BYTE
|
|
JMP BYTVAL ;AND RETURN IT
|
|
OGP3$: DEC DX ;POINT INTO DEFAULT PROPERTY TABLE
|
|
SHL DX,1
|
|
MOV BX,DX
|
|
OGP4$: ADD BX,OBJTAB ;GET THE WORD
|
|
OGP5$: GTAWRD A,[BX]
|
|
JMP PUTVAL ;AND RETURN IT
|
|
OPGETP ENDP
|
|
|
|
;PUTP (CHANGE VALUE OF A PROPERTY, ERROR IF BAD NUMBER)
|
|
PUBLIC OPPUTP,OPP2$
|
|
OPPUTP PROC
|
|
PUSH CX ;SAVE NEW VALUE
|
|
MOV DX,BX ;PROPERTY
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
MOV BP,AX ;MOVE TO BASE
|
|
GTAWRD B,[BP].PROPS ;GET LOCATION OF ITS PROPERTY TABLE
|
|
MOV AL,ES:[BX] ; LENGTH OF SHORT DESCRIPTION IN WORDS
|
|
SUB AH,AH ;CLEAN OFF ANY HIGH-ORDER BYTE
|
|
SHL AX,1 ;CONVERT TO BYTES
|
|
ADD BX,AX ;ADJUST POINTER TO SKIP IT
|
|
INC BX ;ALSO SKIP LENGTH BYTE
|
|
JMP OPP2$ ;SKIP NEXT LINE FIRST TIME THROUGH LOOP
|
|
OPP1$: CALL NXTPRP ;POINT TO NEXT PROPERTY
|
|
OPP2$: MOV AL,ES:[BX] ; GET PROPERTY IDENTIFIER
|
|
AND AL,MASK PROPNUM ;CLEAN OFF LENGTH BITS
|
|
CMP AL,DL ;COMPARE PROPERTY NUMBER WITH DESIRED ONE
|
|
JE OPP3$ ;IF EQUAL, GOT IT
|
|
JG OPP1$ ;IF GREATER, LOOP (TABLE SORTED IN REVERSE)
|
|
FATAL FTL2 ;OTHERWISE, FATAL ERROR
|
|
OPP3$: MOV AL,ES:[BX] ;NOW FIND LENGTH OF PROPERTY
|
|
INC BX ;POINT TO PROPERTY VALUE
|
|
AND AL,MASK PROPSIZE;GET LENGTH BITS
|
|
MOV CL,PROPSIZE
|
|
SHR AL,CL
|
|
CMP AL,0 ;BYTE VALUE?
|
|
POP AX ;RESTORE NEW VALUE
|
|
JNE OPP4$ ;ZERO MEANS BYTE VALUE
|
|
MOV ES:[BX],AL ;STORE THE NEW BYTE
|
|
RET ;AND RETURN
|
|
OPP4$: PTAWRD [BX],A ;STORE THE NEW WORD VALUE
|
|
RET
|
|
OPPUTP ENDP
|
|
|
|
;NEXTP (RETURN NUMBER OF NEXT PROP FOLLOWING GIVEN PROB IN OBJ)
|
|
PUBLIC OPNEXT,ONX2$
|
|
OPNEXT PROC
|
|
MOV DX,BX ;PROPERTY
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
MOV BP,AX ;MOVE TO BASE
|
|
GTAWRD B,[BP].PROPS ;GET ITS LOCATION
|
|
MOV AL,ES:[BX] ; LENGTH OF SHORT DESCRIPTION IN WORDS
|
|
SUB AH,AH ;CLEAN OFF ANY HIGH-ORDER BYTE
|
|
SHL AX,1 ;CONVERT TO BYTES
|
|
ADD BX,AX ;ADJUST POINTER TO SKIP IT
|
|
INC BX ;ALSO SKIP LENGTH BYTE
|
|
CMP DX,0 ;WERE WE GIVEN ZERO AS PROP?
|
|
JE ONX4$ ;YES, GO RETURN FIRST PROPERTY NUMBER
|
|
JMP ONX2$ ;NO, SKIP NEXT LINE FIRST TIME THROUGH LOOP
|
|
ONX1$: CALL NXTPRP ;POINT TO NEXT PROPERTY
|
|
ONX2$: MOV AL,ES:[BX] ; GET PROPERTY IDENTIFIER
|
|
AND AL,MASK PROPNUM ;CLEAN OFF LENGTH BITS
|
|
CMP AL,DL ;COMPARE PROPERTY NUMBER WITH DESIRED ONE
|
|
JE ONX3$ ;IF EQUAL, GOT IT
|
|
JG ONX1$ ;IF GREATER, LOOP (TABLE SORTED IN REVERSE)
|
|
FATAL FTL2 ;OTHERWISE, FATAL ERROR
|
|
ONX3$: CALL NXTPRP ;POINT TO NEXT PROPERTY
|
|
ONX4$: MOV AL,ES:[BX] ; GET PROPERTY IDENTIFIER
|
|
AND AL,MASK PROPNUM ;EXTRACT PROPERTY NUMBER
|
|
JMP PUTVAL ;AND RETURN IT
|
|
OPNEXT ENDP
|
|
|
|
SUBTTL TABLE OPERATIONS
|
|
PAGE +
|
|
|
|
PUBLIC OPGET,OPGETB,OPPUT,OPGTPT
|
|
;GET (GET THE ITEM'TH WORD FROM TABLE)
|
|
OPGET PROC
|
|
SHL BX,1 ;CONVERT ITEM TO BYTE COUNT
|
|
ADD AX,BX ;INDEX INTO TABLE
|
|
CALL BSPLTB ;SPLIT THE POINTER
|
|
CALL GETWRD ;GET THE WORD
|
|
MOV AX,CX
|
|
JMP PUTVAL ;AND RETURN IT
|
|
OPGET ENDP
|
|
|
|
;GETB (GET THE ITEM'TH BYTE FROM TABLE)
|
|
OPGETB PROC
|
|
ADD AX,BX ;INDEX INTO TABLE
|
|
CALL BSPLTB ;SPLIT THE POINTER
|
|
CALL GETBYT ;GET THE BYTE
|
|
MOV AX,CX
|
|
JMP BYTVAL ;AND RETURN IT
|
|
OPGETB ENDP
|
|
|
|
;PUT (REPLACE THE ITEM'TH WORD IN TABLE)
|
|
OPPUT PROC
|
|
SHL BX,1 ;CONVERT ITEM TO BYTE COUNT
|
|
ADD BX,AX ;INDEX INTO TABLE
|
|
PTAWRD [BX],C ;STORE THE WORD
|
|
RET
|
|
OPPUT ENDP
|
|
|
|
;PUTB (REPLACE ITEM'TH BYTE IN TABLE)
|
|
OPPUTB PROC
|
|
ADD BX,AX ;INDEX INTO TABLE
|
|
MOV ES:[BX],CL ; STORE BYTE
|
|
RET
|
|
OPPUTB ENDP
|
|
|
|
;GETPT (GET POINTER TO PROPERTY TABLE FOR GIVEN PROP)
|
|
OPGTPT PROC
|
|
MOV DX,BX ;PROPERTY
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
MOV BP,AX ;MOVE TO BASE
|
|
GTAWRD B,[BP].PROPS ;GET LOCATION OF ITS PROPERTY TABLE
|
|
MOV AL,ES:[BX] ;LENGTH OF SHORT DESCRIPTION IN WORDS
|
|
SUB AH,AH ;CLEAN OFF ANY HIGH-ORDER BYTE
|
|
SHL AX,1 ;CONVERT TO BYTES
|
|
ADD BX,AX ;ADJUST POINTER TO SKIP IT
|
|
INC BX ;ALSO SKIP LENGTH BYTE
|
|
JMP OGT2$ ;SKIP NEXT LINE FIRST TIME THROUGH LOOP
|
|
OGT1$: CALL NXTPRP ;POINT TO NEXT PROPERTY
|
|
OGT2$: MOV AL,ES:[BX] ;GET PROPERTY IDENTIFIER
|
|
AND AL,MASK PROPNUM ;CLEAN OFF LENGTH BITS
|
|
CMP AL,DL ;COMPARE PROPERTY NUMBER WITH DESIRED ONE
|
|
JG OGT1$ ;IF GREATER, LOOP (TABLE SORTED IN REVERSE)
|
|
JE OGT3$ ;FOUND THE PROPERTY
|
|
SUB AX,AX ;RETURN ZERO FOR NO SUCH PROPERTY
|
|
JMP OGT4$
|
|
OGT3$: INC BX ;POINT TO PROPERTY VALUE
|
|
MOV AX,BX ;AND RETURN IT
|
|
OGT4$: JMP PUTVAL
|
|
OPGTPT ENDP
|
|
|
|
PUBLIC OPPTSI
|
|
;PTSIZE (RETURN SIZE OF PROPERTY TABLE)
|
|
OPPTSI PROC
|
|
MOV BX,AX ;TABLE POINTER
|
|
MOV AL,ES:[BX-1] ;GET PROPERTY INDENTIFIER
|
|
AND AL,MASK PROPSIZE;EXTRACT LENGTH BITS
|
|
SUB AH,AH
|
|
MOV CL,PROPSIZE
|
|
SHR AX,CL
|
|
INC AX ;ADJUST TO ACTUAL LENGTH
|
|
JMP PUTVAL ;RETURN IT
|
|
OPPTSI ENDP
|
|
|
|
SUBTTL VARIABLE OPERATIONS
|
|
PAGE +
|
|
|
|
PUBLIC OPVALU,OPSET,OPPUSH,OPPOP
|
|
;VALUE (GET VALUE OF VAR)
|
|
OPVALU PROC
|
|
CALL GETVAR ;GET THE VALUE
|
|
JMP PUTVAL ;AND RETURN IT
|
|
OPVALU ENDP
|
|
|
|
;SET (VAR TO VALUE)
|
|
OPSET PROC
|
|
JMP PUTVAR ;STORE THE VALUE
|
|
OPSET ENDP
|
|
|
|
;PUSH (A VALUE ONTO THE STACK)
|
|
OPPUSH PROC
|
|
PUSHZ AX ;PUSH THE VALUE
|
|
RET
|
|
OPPUSH ENDP
|
|
|
|
;POP (A VALUE OFF THE STACK INTO VAR)
|
|
OPPOP PROC
|
|
POPZ BX ;POP A VALUE
|
|
JMP PUTVAR ;AND STORE IT
|
|
OPPOP ENDP
|
|
|
|
PUBLIC OPINC,OPDEC
|
|
;INC (INCREMENT VAR)
|
|
OPINC PROC
|
|
MOV CX,AX ;VARIABLE
|
|
CALL GETVAR ;GET VAR'S VALUE
|
|
INC AX ;INCREMENT IT
|
|
OPINC1: MOV BX,AX ;VALUE
|
|
MOV AX,CX ;VARIABLE
|
|
JMP PUTVAR ;STORE NEW VALUE
|
|
OPINC ENDP
|
|
|
|
;DEC (DECREMENT VAR)
|
|
OPDEC PROC
|
|
MOV CX,AX ;VARIABLE
|
|
CALL GETVAR ;GET VAR'S VALUE
|
|
DEC AX ;DECREMENT IT
|
|
JMP OPINC1 ;STORE NEW VALUE
|
|
OPDEC ENDP
|
|
|
|
PUBLIC OPQIGR,OPQDLE
|
|
;IGRTR? (INCREMENT VAR & TEST IF GREATER THAN VAL)
|
|
OPQIGR PROC
|
|
PUSH AX ;SAVE VARIABLE
|
|
CALL GETVAR ;GET VAR'S VALUE
|
|
INC AX ;INCREMENT IT
|
|
SUB CX,CX ;SET FLAG FALSE
|
|
CMP AX,BX ;NEW VALUE GREATER THAN VAL?
|
|
JLE OPQIG1 ;NO
|
|
OPQIG0: INC CX ;YES, CHANGE FLAG TO TRUE
|
|
OPQIG1: MOV BX,AX ;VALUE
|
|
POP AX ;RESTORE VARIABLE
|
|
CALL PUTVAR ;STORE NEW VALUE
|
|
CMP CX,0 ;TEST FLAG
|
|
JE OQI1$ ;FALSE, PREDICATE FALSE
|
|
JMP PTRUE ;ELSE, PREDICATE TRUE
|
|
OQI1$: JMP PFALSE
|
|
OPQIGR ENDP
|
|
|
|
;DLESS? (DECREMENT VAR & TEST IF LESS THAN VAL)
|
|
OPQDLE PROC
|
|
PUSH AX ;SAVE VARIABLE
|
|
CALL GETVAR ;GET VAR'S VALUE
|
|
DEC AX ;DECREMENT IT
|
|
SUB CX,CX ;SET FLAG FALSE
|
|
CMP AX,BX ;NEW VALUE LESS THAN VAL?
|
|
JGE OPQIG1 ;NO, PREDICATE FALSE
|
|
JMP OPQIG0 ;YES, PREDICATE TRUE
|
|
OPQDLE ENDP
|
|
|
|
SUBTTL I/O OPERATIONS
|
|
PAGE +
|
|
PUBLIC GETLIN,GETLLP,GETLLC,GETLEM
|
|
|
|
;for the boss key, include the boss file
|
|
INCLUDE iboss.asm
|
|
|
|
GETLIN PROC
|
|
PUSH BX
|
|
MOV SCRHLD,1 ; (7n) HOLD SCRIPTING
|
|
PUSH SI
|
|
MOV CL,ES:[SI]
|
|
MOV BX,OFFSET INBUF
|
|
MOV BYTE PTR [BX],CL
|
|
CMP CL,MAXLIN ; (7r) DON'T EXCEED BUFFER LENGTH
|
|
JBE GTLN0 ; (7r) FIX IF ABOVE
|
|
MOV BYTE PTR [BX],MAXLIN ; (7r) WITH OUR NEW MAXIMUM
|
|
GTLN0: MOV DX,BX
|
|
MOV AH,CRDLIN
|
|
INT 21H
|
|
TEST SCROLL,1 ;(7) WHAT KIND OF SCROLLING
|
|
JNZ GTLN1
|
|
MOV AH,SCROLLUP ;(7) USE A VIDEO BIOS SCROLL
|
|
MOV AL,1 ;(7) ONLY 1 LINE
|
|
MOV CX,TOPLIN ;(7) ALWAYS FREEZE TOP LINE
|
|
MOV DH,SLPP ;(7) GET SCREEN LENGTH
|
|
MOV DL,SCPL ;(7) GET THE WIDTH OF THE SCREEN
|
|
DEC DL ; (7v) COORDINATES ARE ZERO BASED
|
|
MOV BH,SCRATR ;(7) GET THE SCREEN ATTRIBUTE
|
|
INT 10H ;(7) CALL THE VIDEO
|
|
JMP GTLN2 ;(7) SKIP LINE FEED OUTPUT
|
|
GTLN1: MOV AH,CCONIO
|
|
MOV DL,10
|
|
INT 21H
|
|
GTLN2: POP DX
|
|
MOV BX,OFFSET INBUF
|
|
MOV CL,BYTE PTR [BX+1]
|
|
SUB CH,CH
|
|
INC BX
|
|
CMP CL,0
|
|
JE GETLEM
|
|
GETLLP: INC SI
|
|
INC BX
|
|
MOV AL,BYTE PTR [BX]
|
|
|
|
CALL boss
|
|
JNC GETLLC1 ;boss returns Carry Set if boss chr
|
|
MOV AL," "
|
|
GETLLC1:
|
|
CMP AL,"A"
|
|
JL GETLLC
|
|
CMP AL,"Z"
|
|
JG GETLLC
|
|
ADD AL,32
|
|
GETLLC: MOV ES:[SI],AL
|
|
LOOP GETLLP
|
|
GETLEM: INC SI
|
|
SUB AL,AL
|
|
MOV ES:[SI],AL
|
|
MOV SCRHLD,0 ; (7n) TURN OFF SCRIPT HOLD
|
|
POP BX
|
|
RET
|
|
GETLIN ENDP
|
|
|
|
PUBLIC PRTOUT
|
|
PRTOUT PROC
|
|
PUSH AX
|
|
PUSH BX
|
|
PUSH CX
|
|
PUSH DX ; (7) SAVE THIS, USING STD PRT
|
|
CMP SCROLL,1 ; (7) ARE WE COMPATIBLE
|
|
JZ POUT1 ; (7) NO
|
|
TEST CMDLIN,16 ; (7n) DO WE WANT IBM PRINTER
|
|
JZ POUT1 ; (7n) GUESS NOT
|
|
POUT0: MOV AH,0 ; (7) FUNCTION TO PRINT
|
|
MOV DX,0 ; (7) TO THE FIRST PRINTER
|
|
INT 17H ; (7) TRY IT
|
|
TEST AH,RDYBIT ; (7) TIME OUT?
|
|
JZ POUT2 ; (7) WORKED, RETURN
|
|
CALL PRNRDY ; (7)
|
|
JC POUT2
|
|
JMP POUT0 ; (7) RETRY
|
|
POUT1: MOV DL,AL ; (7n) GET CHARACTER TO PRINT
|
|
MOV AH,CPROUT ; (7n) PRINT IT
|
|
INT 21H
|
|
POUT2: POP DX ; (7n) FORGET THIS AND BREAK...
|
|
POP CX
|
|
POP BX
|
|
POP AX
|
|
RET
|
|
PRTOUT ENDP
|
|
|
|
PUBLIC PRNRDY,SCRCHK
|
|
PRNRDY PROC
|
|
PUSH AX
|
|
MOV SCRHLD,1 ; (7n) HOLD OFF SCRIPTING
|
|
PRINT PRNNRDY ; (7) ASK USER ABOUT ACTION
|
|
RDY1: CALL MCHRI ; (7) GET A RESPONSE
|
|
CALL MTTYO ; (7u) ECHO THE CHARACTER
|
|
AND AL,5FH ; (7) UPPPER CASIFY
|
|
CMP AL,'A' ; (7) SHOULD WE ABORT
|
|
JNZ RDY2 ; (7) ATTEMPTING RETRY
|
|
MOV SCRFLG,0 ; (7) TURN OFF SCRIPTING
|
|
AND ES:[PFLAGS],SCRMSK ; (7) AND IN THE MODE WORD
|
|
MOV SCRHLD,0 ; (7n) TURN OFF BAN ON SCRIPTING
|
|
STC ; (7) SET CARRY FOR NO RETRY
|
|
PUSHF ; (7) SAVE THESE
|
|
JMP RDY3 ; (7) CR LF ON EXIT
|
|
RDY2: CMP AL,'R' ; (7) RETRY???
|
|
JNZ RDY1 ; (7) WRONG CHARACTER
|
|
CLC ; (7) CLEAR CARRY FOR RETRY
|
|
PUSHF ; (7) SAVE FLAGS
|
|
RDY3: CALL MCRLF ; (7) DO A <CR><LF>
|
|
MOV SCRHLD,0 ; (7n) TURN OFF BAN ON SCRIPTING
|
|
POPF ; (7) RESTORE FLAGS AND
|
|
POP AX ; (7) CHARACTER TO PRINT
|
|
RET
|
|
PRNRDY ENDP
|
|
|
|
SCRCHK PROC
|
|
PUSH AX
|
|
PUSH BX
|
|
PUSH DX
|
|
GTAWRD A,[PFLAGS]
|
|
TEST AL,1 ;CHECK IF SCRIPTING IS REQUESTED
|
|
JZ SCRNN$
|
|
TEST SCRFLG,1 ; (7) NEW STATE?
|
|
JNZ SCR0L$ ; (7x) NO, CONTINUE
|
|
MOV SCRFLG,1 ; (7n) TURN ON SCRIPT FLAG
|
|
CMP SCROLL,0 ; (7) SHOULD WE BE DOING THIS?
|
|
JNZ SCR0L$ ; (7) NOPE...
|
|
TEST CMDLIN,16 ; (7n) DID WE REALLY REQUEST IBM
|
|
JZ SCR0L$
|
|
SCR_1$: MOV DX,0 ; (7) TRY TO INIT THE PRINTER
|
|
MOV AH,1
|
|
INT 17H ; (7) SO THAT WE WILL TIME OUT FAST
|
|
TEST AH,PRTMSK ; (7) TEST FOR TIME OUT
|
|
JZ SCR0L$ ; (7) NO PROBLEM, WE'RE FINE
|
|
CALL PRNRDY ; (7) INFORM USER OF PROBLEM
|
|
JNC SCR_1$
|
|
JMP SCRNN$ ; (7) TURN OFF SCRIPTING
|
|
SCR0L$: SUB CX,CX
|
|
MOV BP,DX
|
|
INC BP
|
|
SCR1L$: MOV AL,ES:[BP]
|
|
INC BP
|
|
CMP BP,SI
|
|
JLE SCR2L$
|
|
CALL PRTCRL
|
|
JMP SCREX$
|
|
SCR2L$: CALL PRTOUT
|
|
INC CX
|
|
CMP CL,SCPL
|
|
JNE SCR1L$
|
|
CALL PRTCRL
|
|
JC SCREX$
|
|
SUB CX,CX
|
|
JMP SCR1L$
|
|
|
|
SCRNN$: MOV SCRFLG,0
|
|
SCREX$: POP DX
|
|
POP BX
|
|
POP AX
|
|
RET
|
|
SCRCHK ENDP
|
|
|
|
PUBLIC PRTCRL
|
|
PRTCRL PROC
|
|
MOV AL,13 ;FINISH UP WITH CRLF
|
|
CALL PRTOUT
|
|
MOV AL,10
|
|
CALL PRTOUT
|
|
RET
|
|
PRTCRL ENDP
|
|
|
|
;READ (A LINE OF INPUT & PARSE IT, LINE BUF IN ES:AX,
|
|
;RETURN BUF IN ES:BX)
|
|
PUBLIC OPREAD,ORD1$,ORDNS$,ORD8$,ORD9$,ORD10$,ORD1A$,ORD11$,ORD12$
|
|
PUBLIC ORD13$,ORD14$,ORD15$,ORD16$,ORD17$,ORD18$,ORD19$,ORD20$
|
|
PUBLIC ORD21$,ORD22$,ORD23$
|
|
OPREAD PROC
|
|
PUSH AX ;SAVE LINE BUF
|
|
PUSH AX
|
|
PUSH BX
|
|
CALL OPUSL ;UPDATE STATUS LINE
|
|
POP BX
|
|
POP AX
|
|
MOV BP,CHRPTR ;NEXT CHARACTER POSITION
|
|
MOV BYTE PTR DS:[BP],80H ;(6)DON'T END OUTPUT, IF ANY, WITH NEW LINE
|
|
ORD1$: PRINT OUTBUF ;FORCE OUT ANY QUEUED TEXT
|
|
MOV CHRPTR,OFFSET OUTBUF ;RESET CHARACTER POINTER
|
|
POP SI ;INPUT BUFFER POINTER
|
|
MOV MORLIN,0 ;RE-INITIALIZE MORE COUNT FROM HERE
|
|
CALL GETLIN ;GET SOME CHARACTERS
|
|
CALL SCRCHK
|
|
ORDNS$: PUSH DI
|
|
MOV RDBOS,DX ;INITIALIZE RDBOS
|
|
MOV RDEOS,SI ;AND RDEOS
|
|
MOV RDRET,BX ;STORE RET POINTER
|
|
MOV RDNWDS,0 ;NO WORDS SO FAR
|
|
INC DX ;SKIP LENGTH BYTE
|
|
MOV DI,BX ;THIS WILL BE WORD ENTRY POINTER
|
|
INC DI ;SKIP MAX WORDS & NWORDS BYTES
|
|
INC DI
|
|
ORD8$: MOV CX,OFFSET RDWSTR;HERE FOR NEXT WORD, POINT TO WORD STRING
|
|
MOV BX,DX ;AND SAVE BEGINNING OF WORD POINTER
|
|
ORD9$: CMP DX,RDEOS ;END OF STRING?
|
|
JNE ORD10$ ;NO
|
|
CMP CX,OFFSET RDWSTR;YES, WAS A WORD FOUND?
|
|
JNE ORD15$ ;YES, WE STILL HAVE TO LOOKUP WORD
|
|
JMP ORD23$ ;NO, WE'RE DONE
|
|
ORD10$: MOV BP,DX ;GET NEXT CHARACTER FROM BUFFER
|
|
MOV AL,ES:[BP]
|
|
CMP AL,"A"
|
|
JL ORD1A$
|
|
CMP AL,"Z"
|
|
JG ORD1A$
|
|
ADD AL,32 ;LOWERCASIFY ALPHABETICS
|
|
ORD1A$: INC DX
|
|
MOV SI,OFFSET RBRKS ;LIST OF READ BREAK CHARACTERS
|
|
ORD11$: INC SI
|
|
CMP AL,[SI-1] ;SEARCH LIST FOR THIS ONE
|
|
JE ORD12$ ;FOUND IT
|
|
CMP BYTE PTR [SI],0 ;END OF LIST?
|
|
JNE ORD11$ ;NO, CONTINUE SEARCH
|
|
CMP CX,OFFSET RDWSTR[6] ;YES, NOT A BREAK, WORD STRING FULL?
|
|
JE ORD9$ ;YES, LOOP UNTIL END OF WORD
|
|
MOV BP,CX ;NO, TACK THIS CHARACTER ONTO STRING
|
|
MOV DS:[BP],AL
|
|
INC CX
|
|
JMP ORD9$ ;AND LOOP
|
|
ORD12$: CMP CX,OFFSET RDWSTR;WORD READ BEFORE THIS BREAK?
|
|
JNE ORD14$ ;YES
|
|
CMP SI,ESIBKS ;NO, BUT IS IT A SELF-INSERTING BREAK?
|
|
JBE ORD13$ ;YES
|
|
INC BX ;NO, UPDATE BEGINNING OF WORD TO SKIP BREAK
|
|
JMP ORD9$ ;AND RETURN TO LOOP TO FIND A WORD
|
|
ORD13$: MOV BP,CX ;STORE THE BREAK IN WORD STRING
|
|
MOV DS:[BP],AL
|
|
INC CX
|
|
JMP ORD15$ ;AND GO FOR THE WORD
|
|
ORD14$: DEC DX ;UNREAD TERMINATING BREAK IN CASE IT WAS SI
|
|
ORD15$: INC RDNWDS ;INCREMENT FOUND WORD COUNT
|
|
MOV BP,BX ;GREATER THAN MAX ALLOWED?
|
|
MOV BX,RDRET
|
|
MOV BL,ES:[BX]
|
|
CMP BL,59 ; (7w) GAME FIX
|
|
JBE ORD15A ; (7w) FIX NUMBER OF TOKENS ALLOWED
|
|
MOV BL,59 ; (7w) OTHERWISE WE OVERRUN A TABLE
|
|
ORD15A: CMP RDNWDS,BL
|
|
MOV BX,BP
|
|
JLE ORD16$ ;NO
|
|
PRINT ERR2 ;YES, INFORM LOSER
|
|
MOV AX,BX ;BEGINNING OF THIS WORD
|
|
MOV BP,RDEOS ;SAVE BYTE AFTER EOS
|
|
MOV BL,ES:[BP]
|
|
MOV BYTE PTR ES:[BP],0 ; ZERO IT TO MAKE STRING ASCIZ
|
|
PUSH BX ; (7w) SAVE THIS ADDRESS
|
|
MOV BX,DS ; (7w) FIGURE WHERE STRING IS IN DS
|
|
NEG BX ; (7w) SUBTRACT DS FROM ES
|
|
ADD BX,GAMESEG ; (7w) BX HAS PARAGRAPHS OF DIFFERENCE
|
|
MOV CL,4 ; (7w) CONVERT TO AN OFFSET
|
|
SHL BX,CL ; (7w) TO ADD IN WITH AX
|
|
ADD AX,BX ; (7w) NOW DS:AX SHOULD EQUAL PREV ES:AX
|
|
POP BX ; (7w) RESTORE BX
|
|
CALL MPRNT ;PRINT IT
|
|
MOV ES:[BP],BL ; AND RESTORE OLD BYTE
|
|
DEC RDNWDS ;REMEMBER THAT WE FLUSHED THIS WORD
|
|
JMP ORD23$ ;AND WE'RE DONE
|
|
ORD16$: MOV AX,BX ;CALCULATE NUMBER OF CHARACTERS IN WORD
|
|
NEG AX
|
|
ADD AX,DX
|
|
MOV ES:[DI+2],AL ;(6)SAVE THE NUMBER IN RET TABLE
|
|
SUB BX,RDBOS ;BYTE OFFSET FOR BEGINNING OF WORD
|
|
MOV ES:[DI+3],BL ;(6)STORE IT, TOO
|
|
MOV BP,CX ;MAKE WORD STRING ASCIZ
|
|
MOV BYTE PTR DS:[BP],0 ;(6) REMOVED SEG OVERRIDE (DS)
|
|
MOV AX,OFFSET RDWSTR;POINT TO IT
|
|
CALL ZWORD ;AND CONVERT TO (2-WORD) ZWORD
|
|
PUSH DX ;SAVE CHAR & WORD ENTRY POINTERS
|
|
PUSH DI
|
|
MOV DI,AX ;FIRST ZWORD WORD
|
|
MOV SI,VWORDS ;NUMBER OF VOCABULARY WORDS
|
|
MOV AX,SI
|
|
DEC AX ;WE WANT TO POINT TO LAST WORD
|
|
MUL VWLEN ;MULTIPLY BY WORD LENGTH IN BYTES
|
|
ADD AX,VOCBEG ;ADD POINTER TO BEGINNING TO FIND LAST WORD
|
|
MOV CX,AX ;POINTER TO LAST WORD
|
|
MOV DX,DI ;FIRST ZWORD WORD
|
|
MOV DI,BX ;SECOND ZWORD WORD
|
|
MOV BX,VWLEN ;CALCULATE INITIAL OFFSET FOR BINARY SEARCH
|
|
SAR SI,1
|
|
ORD17$: SAL BX,1
|
|
SAR SI,1
|
|
CMP SI,0
|
|
JNE ORD17$
|
|
MOV SI,VOCBEG ;BEGINNING OF WORD TABLE
|
|
ADD SI,BX ;ADD CURRENT OFFSET(HALF OF POWER-OF-2 TABLE)
|
|
PUSH AX ;SAVE
|
|
MOV AX,VWLEN ;AVOID FENCEPOST BUG FOR EXACT POWER-OF-2 TBL
|
|
SUB SI,AX
|
|
POP AX ;RESTORE
|
|
ORD18$: SAR BX,1 ;NEXT OFFSET WILL BE HALF OF PREVIOUS ONE
|
|
GTAWRD A,[SI] ;GET FIRST HALF OF CURRENT ZWORD
|
|
CMP DX,AX ;COMPARE DESIRED ONE TO IT
|
|
JA ORD19$ ;GREATER, WE'LL HAVE TO MOVE UP
|
|
JB ORD20$ ;LESS, WE'LL HAVE TO MOVE DOWN
|
|
MOV BP,SI ;SAME, GET SECOND HALF
|
|
INC BP
|
|
INC BP
|
|
GTAWRD A,[BP]
|
|
CMP DI,AX ;COMPARE DESIRED WORD WITH IT
|
|
JA ORD19$ ;GREATER, WE'LL HAVE TO MOVE UP
|
|
JB ORD20$ ;LESS, WE'LL HAVE TO MOVE DOWN
|
|
JMP ORD22$ ;SAME, WE'VE FOUND IT, RETURN IT
|
|
ORD19$: ADD SI,BX ;TO MOVE UP, ADD CURRENT OFFSET
|
|
CMP SI,CX ;HAVE WE MOVED PAST END OF TABLE?
|
|
JBE ORD21$ ;NO
|
|
MOV SI,CX ;YES, POINT TO END OF TABLE INSTEAD
|
|
JMP ORD21$
|
|
ORD20$: SUB SI,BX ;TO MOVE DOWN, SIMPLY SUBTRACT OFFSET
|
|
ORD21$: CMP BX,VWLEN ;IS OFFSET RESOLUTION BELOW ONE WORD?
|
|
JGE ORD18$ ;NO, CONTINUE LOOP
|
|
SUB SI,SI ;YES, WORD NOT FOUND, RETURN ZERO
|
|
ORD22$: POP DI ;RESTORE WORD ENTRY POINTER
|
|
MOV DX,SI ;POINTER TO WORD FOUND
|
|
XCHG DH,DL
|
|
MOV ES:[DI],DX ;(6) STORE IT
|
|
POP DX ;RESTORE CHAR POINTER
|
|
ADD DI,4 ;UPDATE POINTER FOR NEXT WORD ENTRY
|
|
JMP ORD8$ ;GO FOR IT
|
|
ORD23$: INC RDRET ;DONE, STORE NUMBER OF WORDS FOUND
|
|
MOV BP,RDRET
|
|
MOVM ES:[BP],RDNWDS,DL ; REMOVED ES OVERRIDE
|
|
POP DI ;RESTORE USER STACK POINTER
|
|
RET ;AND RETURN
|
|
OPREAD ENDP
|
|
|
|
;PRINTC (PRINT CHAR WHOSE ASCII VALUE IS GIVEN)
|
|
PUBLIC OPPRNC,OPPRNN
|
|
OPPRNC PROC
|
|
JMP PUTCHR ;QUEUE THE CHARACTER FOR PRINTING
|
|
OPPRNC ENDP
|
|
|
|
;PRINTN (PRINT A NUMBER)
|
|
OPPRNN PROC
|
|
MOV BX,AX ;NUMBER TO PRINT
|
|
CMP BX,0
|
|
JNE OPN1$ ;NON-ZERO
|
|
MOV AX,"0" ;SPECIAL CASE ZERO
|
|
JMP PUTCHR
|
|
OPN1$: JG OPN2$ ;POSITIVE?
|
|
MOV AX,"-" ;NO, PRINT MINUS SIGN
|
|
CALL PUTCHR
|
|
NEG BX ;AND MAKE IT POSITIVE
|
|
OPN2$: SUB CX,CX ;COUNT OF DIGITS ON STACK
|
|
JMP OPN4$ ;START WITH GREATER-THAN-10 TEST
|
|
OPN3$: MOV AX,BX ;EXTRACT A DIGIT
|
|
MOV BP,10
|
|
CWD
|
|
IDIV BP
|
|
PUSH DX ;PUSH IT
|
|
INC CX ;BUMP COUNT
|
|
MOV BX,AX ;GET QUOTIENT
|
|
OPN4$: CMP BX,10 ;MORE DIGITS TO EXTRACT?
|
|
JGE OPN3$ ;YES, GO LOOP
|
|
MOV AX,BX ;NO, GET LAST (FIRST) DIGIT
|
|
JMP OPN6$ ;ALREADY IN PLACE
|
|
OPN5$: POP AX ;POP NEXT DIGIT
|
|
OPN6$: ADD AX,"0" ;ASCIIZE IT
|
|
CALL PUTCHR ;QUEUE IT
|
|
DEC CX ;REDUCE DIGIT COUNT
|
|
JGE OPN5$ ;LOOP IF SOME LEFT
|
|
RET ;ELSE, RETURN
|
|
OPPRNN ENDP
|
|
|
|
PUBLIC OPPRIN,OPPRNB
|
|
;PRINT (THE STRING POINTED TO BY ES:AX)
|
|
OPPRIN PROC
|
|
CALL BSPLIT ;SPLIT THE BLOCK & WORD NUMBERS
|
|
JMP PUTSTR ;PRINT THE STRING
|
|
OPPRIN ENDP
|
|
|
|
;PRINTB (PRINT THE STRING POINTED TO BY THE BYTE-POINTER ES:AX)
|
|
OPPRNB PROC
|
|
CALL BSPLTB ;SPLIT THE BLOCK & BYTE NUMBERS
|
|
JMP PUTSTR ;PRINT THE STRING
|
|
OPPRNB ENDP
|
|
|
|
;PSEUDO-INSTRUCTIONS FOR HOURS/MINUTES HERE FOR STATUS LINE
|
|
OPPRNH PROC
|
|
MOV PMFLAG,0
|
|
CMP AL,12
|
|
JL OPH0$
|
|
MOV PMFLAG,1
|
|
OPH0$: CMP AL,12
|
|
JLE OPH1$
|
|
SUB AL,12 ;HOUR SLOT IS 24 HOUR TIME
|
|
OPH1$: CMP AL,0
|
|
JNE OPHZ$
|
|
MOV AL,12
|
|
OPHZ$: CMP AL,9
|
|
JG OPH2$
|
|
PUSH AX
|
|
MOV AL,32
|
|
CALL PUTCHR ;OUTPUT SPACE FOR HOUR LESS THAN 10
|
|
POP AX
|
|
OPH2$: CALL OPPRNN
|
|
MOV AL,":"
|
|
JMP PUTCHR ;AND COLON
|
|
OPPRNH ENDP
|
|
|
|
OPPRNM PROC
|
|
CMP AL,9
|
|
JG OPM1$
|
|
PUSH AX
|
|
MOV AL,"0"
|
|
CALL PUTCHR
|
|
POP AX
|
|
OPM1$: CALL OPPRNN
|
|
MOV AL,32
|
|
CALL PUTCHR
|
|
MOV AL,"a"
|
|
CMP PMFLAG,0
|
|
JE OPM2$
|
|
MOV AL,"p"
|
|
OPM2$: CALL PUTCHR
|
|
MOV AL,"m"
|
|
JMP PUTCHR
|
|
OPPRNM ENDP
|
|
|
|
PUBLIC OPPRND,OPPRNI,OPPRNR
|
|
;PRINTD (PRINT OBJ'S SHORT DESCRIPTION)
|
|
OPPRND PROC
|
|
CALL OBJLOC ;FIND OBJ'S LOCATION
|
|
ADD AX,7 ;PROPERTY TABLE POINTER
|
|
MOV BP,AX
|
|
GTAWRD A,[BP] ;GET IT
|
|
INC AX ;POINT TO STRING
|
|
CALL BSPLTB ;SPLIT POINTER
|
|
JMP PUTSTR ;AND PRINT THE STRING
|
|
OPPRND ENDP
|
|
|
|
;PRINTI (PRINT THE STRING FOLLOWING THIS INSTRUCTION)
|
|
OPPRNI PROC
|
|
MOV AX,ZPC1 ;GET POINTER TO STRING
|
|
MOV BX,ZPC2
|
|
CALL PUTSTR ;AND PRINT IT
|
|
MOV ZPC1,AX ;UPDATE ZPC
|
|
MOV ZPC2,BX
|
|
JMP NEWZPC
|
|
OPPRNI ENDP
|
|
|
|
;PRINTR (PRINTI FOLLOWED BY RTRUE)
|
|
OPPRNR PROC
|
|
CALL OPPRNI ;DO A PRINTI
|
|
CALL OPCRLF ;A CRLF
|
|
JMP OPRTRU ;AND AN RTRUE
|
|
OPPRNR ENDP
|
|
|
|
PUBLIC OPCRLF
|
|
;CRLF (DO A NEWLINE)
|
|
OPCRLF PROC
|
|
JMP NEWLIN ;DO A NEWLINE
|
|
OPCRLF ENDP
|
|
|
|
SUBTTL CONTROL OPERATIONS
|
|
PAGE +
|
|
|
|
PUBLIC OPCALL
|
|
;CALL (A FUNCTION WITH OPTIONAL ARGUMENTS), # OF ARGS IN AX
|
|
OPCALL PROC
|
|
NOP ;TELL CALLER TO USE ARGUMENT BLOCK
|
|
MOV DX,AX ;NUMBER OF ARGUMENTS TO CALL
|
|
MOV AX,ARGBLK ;FUNCTION TO CALL
|
|
CMP AX,0
|
|
JNE OCL1$ ;ZERO?
|
|
SUB AX,AX ;YES, SIMPLY RETURN A ZERO
|
|
JMP PUTVAL
|
|
OCL1$: PUSHZ ZPC1 ;OTHERWISE, SAVE OLD ZPC
|
|
PUSHZ ZPC2
|
|
MOV CX,ZLOCS ;AND OLD LOCAL POINTER
|
|
; SUB CX,STKBOT ;BUT RELATIVIZE IT IN CASE OF SAVE
|
|
PUSHZ CX ;AND SAVE IT
|
|
CALL BSPLIT ;SPLIT FUNCTION POINTER
|
|
MOV ZPC1,AX ;MAKE IT THE NEW ZPC
|
|
MOV ZPC2,BX
|
|
CALL NEWZPC ;UPDATE ZPC STUFF
|
|
MOV ZLOCS,DI ;LOCALS WILL START AT NEXT STACK SLOT
|
|
SUB ZLOCS,2
|
|
CALL NXTBYT ;NUMBER OF LOCALS
|
|
MOV BX,AX
|
|
MOV BP,OFFSET ARGBLK[2] ;POINT TO FIRST OPTIONAL ARG
|
|
OCL2$: DEC BX ;ANY MORE LOCALS?
|
|
JL OCL4$ ;NO, WE'RE DONE
|
|
CALL NXTWRD ;YES, GET THE NEXT LOCAL DEFAULT VALUE
|
|
DEC DX ;ANY MORE OPTIONALS GIVEN?
|
|
JLE OCL3$ ;NO
|
|
PUSHZ [BP] ;(6) YES, USE ITS VALUE
|
|
ADD BP,2
|
|
JMP OCL2$ ;AND CONTINUE LOOP
|
|
OCL3$: PUSHZ AX ;OTHERWISE, USE DEFAULT
|
|
JMP OCL2$ ;AND LOOP
|
|
OCL4$: RET
|
|
OPCALL ENDP
|
|
|
|
PUBLIC OPRETU
|
|
;RETURN (FROM CURRENT FUNCTION CALL)
|
|
OPRETU PROC
|
|
MOV DI,ZLOCS ;RESTORE OLD TOP OF STACK
|
|
POPZ DX ;DUMMY POP [WHY?]
|
|
POPZ ZLOCS ;AND OTHER VALUES
|
|
|
|
; MOV DX,STKBOT ;RE-ABSOLUTIZE THIS ONE
|
|
; ADD ZLOCS,DX
|
|
|
|
POPZ ZPC2
|
|
POPZ ZPC1
|
|
PUSH AX ;VALUE TO RETURN
|
|
CALL NEWZPC ;UPDATE ZPC STUFF
|
|
POP AX
|
|
JMP PUTVAL ;RETURN THE VALUE
|
|
OPRETU ENDP
|
|
|
|
PUBLIC OPRTRU,OPRFAL,OPJUMP,OPRSTA,OPFSTA,OPNOOP
|
|
;RTRUE
|
|
OPRTRU PROC
|
|
MOV AX,1 ;RETURN A 1
|
|
JMP OPRETU
|
|
OPRTRU ENDP
|
|
|
|
;RFALSE
|
|
OPRFAL PROC
|
|
SUB AX,AX ;RETURN A 0
|
|
JMP OPRETU
|
|
OPRFAL ENDP
|
|
|
|
;JUMP (TO A NEW LOCATION)
|
|
OPJUMP PROC
|
|
ADD ZPC2,AX ;ADD OFFSET TO CURRENT ZPC
|
|
SUB ZPC2,2 ;ADJUST IT
|
|
JMP NEWZPC ;NORMALIZE IT & UPDATE ZPC STUFF
|
|
OPJUMP ENDP
|
|
|
|
;RSTACK (RETURN STACK)
|
|
OPRSTA PROC
|
|
POPZ AX ;POP A VALUE
|
|
JMP OPRETU ;AND RETURN IT
|
|
OPRSTA ENDP
|
|
|
|
;FSTACK (FLUSH A VALUE OFF THE STACK)
|
|
OPFSTA PROC
|
|
POPZ DX ;FLUSH ONE
|
|
RET
|
|
OPFSTA ENDP
|
|
|
|
;NOOP (NO OPERATION)
|
|
OPNOOP PROC
|
|
RET ;DO NOTHING
|
|
OPNOOP ENDP
|
|
|
|
SUBTTL LOW LEVEL FUNCTIONS
|
|
PAGE +
|
|
|
|
;GET A BYTE, BLOCK-POINTER ES:AX, BYTE-POINTER ES:BX, RESULT IN CX,
|
|
;UPDATE AX & BX TO REFLECT BYTE GOTTEN
|
|
;
|
|
; GETBYT UNDERWENT SERIOUS RE-WRITING AND EVALUATION IN THE UPDATE TO USE
|
|
; ALL OF MEMORY. THE ORIGINAL ROUTINE WAS KEPT BUT CHANGES WERE MADE IN
|
|
; TWO SETS: THE FIRST TO HANDLE THE CASE IN WHICH ALL OF THE GAME IS IN
|
|
; MEMORY; AND THE SECOND IN WHICH THE GAME BUFFERS EXTEND PAST 64K AND THUS
|
|
; REQUIRING A SEGMENT SWITCH TO RETRIEVE THE BYTE.
|
|
;
|
|
; FOR THE FIRST CASE, THE BLOCK PTR IS USED TO DETERMINE THE SEGMENT IN
|
|
; WHICH THE BLOCK RESIDES, THE GAME SEGMENT IS SET ACCORDINGLY, AND THE
|
|
; BYTE IS FETCHED.
|
|
;
|
|
; THE SECOND CASE WILL CALL GETPAG TO DETERMINE WHERE THE PAGE IS LOCATED IN
|
|
; CORE. CALLING GETPAG WILL SET A VARIABLE CALLED CURSEG TO 0 OR 1 TO INDICATE
|
|
; THAT THE PAGE WE ARE TOUCHING IS IN THE FIRST OR SECOND SEGMENT. GETPAG
|
|
; RETURNS A VALID POINTER ASSUMING THAT THIS ROUTINE WILL SET ES ACCORDING TO
|
|
; CURSEG. IF CURSEG IS 0, GAMESEG (THE FIRST SEGMENT [OR ZEROTH]) WILL
|
|
; CONTAIN THE BLOCK, AND IF CURSEG IS 1, SEG1 (GAMESEG + 64K) WILL CONTAIN
|
|
; THE BLOCK.
|
|
;
|
|
; NOTE THAT ES ALWAYS CONTAINS THE VALUE GAMESEG UNLESS WE NEED TO FETCH
|
|
; OR PUT SOMETHING IN THE SECOND SEGMENT. AT THAT POINT ES IS SET TO SEG1
|
|
; ONLY FOR THAT OPERATION.
|
|
;
|
|
PUBLIC GETBYT,FETCH,GTY1A$,GTSEG1,GTY1$,GTY1B$,GTY2$,GTY3$
|
|
GETBYT PROC
|
|
PUSH SI ; SAVE THIS BEAR
|
|
PUSH AX ;SAVE BLOCK-POINTER
|
|
CMP FITS,1 ; (6) IS ALL OF THE GAME RESIDENT
|
|
JZ FETCH ; (6) IT'S THERE, GO GET IT
|
|
CMP AX,ENDLOD ;IS THIS A PRELOADED LOCATION?
|
|
JGE GTY1$ ;NO
|
|
FETCH: CMP AX,128 ; (6) CHECK SEGMENT FOR BLOCK
|
|
JGE GTSEG1 ; (6) GET BYTE FROM SEGMENT 1
|
|
GTY1A$: MOV CL,9 ;YES, RECONSTRUCT POINTER
|
|
SHL AX,CL ;SHIFT BLOCK POINTER BY 9
|
|
OR AX,BX ;ADD IN THE OFFSET
|
|
XCHG AX,BX
|
|
MOV CL,ES:[BX] ;GET THE BYTE
|
|
JMP GTY2$ ;CLEAR UNWANTED BYTE & RETURN IT
|
|
GTSEG1: MOV SI,SEG1 ; (6) GET SECOND GAME SEG
|
|
MOV ES,SI ; (6) ADDRESS SEG1
|
|
JMP GTY1A$ ; (6) USE SEG0 LOGIC
|
|
GTY1$: CALL GETPAG ;FIND THE PROPER PAGE
|
|
ADD AX,BX ;POINT TO DESIRED BYTE
|
|
XCHG AX,BX
|
|
CMP CURSEG,1 ;(6) CHECK SEGMENT THAT WERE LOOKING IN
|
|
JNZ GTY1B$ ;(6) ITS IN 0, GET IT NORMALLY
|
|
MOV SI,SEG1 ;(6) ITS NOT, SET UP ES TO SEG1
|
|
MOV ES,SI ;(6) GETPAG RETURNED RIGHT POINTER
|
|
GTY1B$: MOV CL,ES:[BX] ;GET IT
|
|
GTY2$: SUB CH,CH ;CLEAR UNWANTED BYTE & RETURN IT
|
|
MOV BX,AX
|
|
MOV SI,GAMESEG ; (6) MAKE SURE GAME SEG IS RESTORED
|
|
MOV ES,SI ; (6) TO SEG 0
|
|
POP AX ;RESTORE BLOCK-POINTER
|
|
POP SI ; RESTORE THIS
|
|
INC BX ;UPDATE POINTER
|
|
CMP BX,200H ;END-OF-PAGE?
|
|
JNE GTY3$ ;NO
|
|
SUB BX,BX ;YES, CLEAR BYTE-POINTER
|
|
INC AX ;AND UPDATE BLOCK-POINTER
|
|
GTY3$: RET
|
|
GETBYT ENDP
|
|
|
|
;GET A WORD, BLOCK POINTER ES:AX, BYTE-POINTER ES:BX, RESULT IN CX
|
|
PUBLIC GETWRD
|
|
GETWRD PROC
|
|
PUSH DX ;SAVE
|
|
CALL GETBYT ;GET HIGH-ORDER BYTE
|
|
PUSH CX ;SAVE IT
|
|
CALL GETBYT ;GET LOW-ORDER BYTE
|
|
POP DX ;GET OTHER BYTE
|
|
MOV CH,DL ;POSITION IT
|
|
POP DX ;RESTORE
|
|
RET
|
|
GETWRD ENDP
|
|
|
|
;GET THE NEXT BYTE, RETURN IT IN AX
|
|
; THIS ROUTINE ALSO WENT UNDER SIGNIFICANT REVISION TO ACCOMODATE MORE
|
|
; PAGING SPACE. TWO CASES HAD TO BE HANDLED: ALL OF GAME IN MEMORY AND
|
|
; MORE THAN 64K OF PAGING SPACE. THE FIRST CASE REQUIRED THAT THE VARIABLE
|
|
; ZPCSEG BE SET IN NEWZPC TO INDICATE IN WHICH SEGMENT OUR ZPC BLOCK COULD
|
|
; BE FOUND. THE SECOND CASE REQUIRES THAT ZPCSEG BE SET ONLY WHEN GETPAG
|
|
; IS CALLED FROM NEWZPC AND THE PAGE THAT IT GOT WAS PUT IN THE SECOND GAME
|
|
; SEGMENT.
|
|
;
|
|
PUBLIC NXTBYT,NXBA$,NXB1$
|
|
NXTBYT PROC
|
|
PUSH SI ;(6) PRESERVE THIS ONE TOO
|
|
PUSH BX ;SAVE
|
|
TEST ZPCFLG,1 ;(7n) HAS THIS PAGE SEEN FOUL PLAY?
|
|
JZ NXB0$ ; (7n) NOPE
|
|
CALL NEWZPC ; (7n) FIX INDEX INTO CURRENT PAGE
|
|
NXB0$: MOV BX,ZPC2 ;BYTE POINTER
|
|
ADD BX,CURPAG ;INDEX INTO CURRENT PAGE
|
|
CMP ZPCSEG,0 ;(6) WHERE ARE WE?
|
|
JZ NXBA$ ;(6) SEG0, ACT NORMALLY
|
|
MOV SI,SEG1 ;(6) GET SEG1 VALUE
|
|
MOV ES,SI ;(6) INTO ES
|
|
NXBA$: MOV AL,BYTE PTR ES:[BX] ; GET BYTE
|
|
PUSH AX ; AND SAVE
|
|
;PUSH ES:[BX] ;SAVE BYTE -- AT KILLER CODE ON FFFF
|
|
MOV SI,GAMESEG ;(6) GET BASE GAME SEG
|
|
MOV ES,SI ;(6) BACK INTO ES
|
|
INC ZPC2 ;UPDATE PC
|
|
CMP ZPC2,200H ;END-OF-PAGE?
|
|
JL NXB1$ ;NO
|
|
CALL NEWZPC ;YES, UPDATE PAGE
|
|
NXB1$: POP AX ;RETRIEVE BYTE
|
|
SUB AH,AH ;CLEAR UNWANTED BYTE
|
|
POP BX ;RESTORE
|
|
POP SI
|
|
RET ;AND RETURN IT
|
|
NXTBYT ENDP
|
|
|
|
;GET THE NEXT WORD, RETURN IT IN AX
|
|
PUBLIC NXTWRD
|
|
NXTWRD PROC
|
|
PUSH BX ;SAVE
|
|
CALL NXTBYT ;GET HIGH-ORDER BYTE
|
|
PUSH AX ;SAVE IT
|
|
CALL NXTBYT ;GET LOW-ORDER BYTE
|
|
POP BX ;GET HIGH-ORDER BYTE
|
|
MOV AH,BL ;POSITION IT
|
|
POP BX ;RESTORE
|
|
RET ;RETURN THE WORD
|
|
NXTWRD ENDP
|
|
|
|
;GET AN ARGUMENT GIVEN ITS TYPE IN AX
|
|
PUBLIC GETARG
|
|
GETARG PROC
|
|
DEC AX ;EXAMINE ARGUMENT
|
|
JL NXTWRD ;0 MEANT LONG IMMEDIATE
|
|
JE NXTBYT ;1 MEANT SHORT IMMEDIATE
|
|
CALL NXTBYT ;2 MEANT VARIABLE, GET THE VAR
|
|
CMP AX,0 ;STACK?
|
|
JNE GETVAR ;NO, JUST GET THE VAR'S VALUE
|
|
POPZ AX ;YES, POP THE STACK
|
|
RET
|
|
GETARG ENDP
|
|
|
|
;GET VALUE OF A VARIABLE, VAR IN AX, VALUE RETURNED IN AX
|
|
PUBLIC GETVAR
|
|
GETVAR PROC
|
|
CMP AX,0 ;STACK?
|
|
JNE GTV1$ ;NO
|
|
POPZT AX ;YES, GET TOP-OF-STACK
|
|
RET
|
|
GTV1$: PUSH BP ;SAVE
|
|
CMP AX,16 ;LOCAL?
|
|
JGE GTV3$ ;NO
|
|
DEC AX ;YES, POINT TO PROPER STACK ELEMENT
|
|
SHL AX,1
|
|
MOV BP,ZLOCS
|
|
SUB BP,AX
|
|
MOV AX,[BP] ;AND GET IT
|
|
GTV2$: POP BP ;RESTORE
|
|
RET
|
|
GTV3$: SUB AX,16 ;GLOBAL, POINT TO PROPER GLOBAL TABLE ELEMENT
|
|
SHL AX,1
|
|
ADD AX,GLOTAB
|
|
MOV BP,AX ;AND GET IT
|
|
GTAWRD A,[BP]
|
|
JMP GTV2$
|
|
GETVAR ENDP
|
|
|
|
;UPDATE VALUE OF A VARIABLE, VAR IN AX, NEW VALUE IN BX
|
|
PUBLIC PUTVAR
|
|
PUTVAR PROC
|
|
CMP AX,0 ;STACK?
|
|
JNE PTV1$ ;NO
|
|
PUSHZT BX ;YES, UPDATE TOP-OF-STACK
|
|
RET
|
|
PTV1$: CMP AX,16 ;LOCAL?
|
|
JGE PTV2$ ;NO
|
|
PUSH BP ;SAVE
|
|
DEC AX ;YES, POINT TO PROPER STACK ELEMENT
|
|
SHL AX,1
|
|
MOV BP,ZLOCS
|
|
SUB BP,AX
|
|
MOV [BP],BX ;AND UPDATE IT
|
|
POP BP ;RESTORE
|
|
RET
|
|
PTV2$: SUB AX,16 ;GLOBAL, POINT TO PROPER GLOBAL TABLE ELEMENT
|
|
SHL AX,1
|
|
ADD AX,GLOTAB
|
|
XCHG AX,BX ;AND UPDATE IT
|
|
PTAWRD [BX],A
|
|
RET
|
|
PUTVAR ENDP
|
|
|
|
;RETURN VAL IN AX TO LOCATION SPECIFIED BY NEXTBYTE
|
|
;DESTROYS BX, BUT IS USUALLY CALLED AT END OF TOP-LEVEL FUNCTION
|
|
PUBLIC BYTVAL
|
|
BYTVAL PROC
|
|
SUB AH,AH ;THIS ENTRY FOR BYTE VALUE TO CLEAR HIGH BYTE
|
|
JMP PUTVAL
|
|
BYTVAL ENDP
|
|
|
|
PUBLIC PUTVAL
|
|
PUTVAL PROC
|
|
MOV BX,AX ;NORMAL ENTRY
|
|
CALL NXTBYT ;GET VAR TO USE
|
|
CMP AX,0 ;STACK?
|
|
JNE PUTVAR ;NO, GO STORE VALUE
|
|
PUSHZ BX ;YES, PUSH ONTO STACK
|
|
RET ;AND RETURN
|
|
PUTVAL ENDP
|
|
|
|
;PREDICATE HANDLERS TRUE & FALSE
|
|
;DESTROYS REGISTERS, BUT ARE ONLY CALLED FROM END OF TOP-LEVEL FCNS
|
|
PUBLIC PFALSE,PTRUE
|
|
PFALSE PROC
|
|
SUB BX,BX ;PREDICATE WAS FALSE, CLEAR FLAG
|
|
JMP PPRED
|
|
PFALSE ENDP
|
|
|
|
PTRUE PROC
|
|
MOV BX,1 ;PREDICATE WAS TRUE, SET FLAG
|
|
JMP PPRED
|
|
PTRUE ENDP
|
|
|
|
PUBLIC PPRED
|
|
PPRED PROC
|
|
CALL NXTBYT ;GET FIRST (OR ONLY) PREDICATE JUMP BYTE
|
|
TEST AX,80H ;NORMAL POLARITY PREDICATE?
|
|
JE PPR1$ ;NO, LEAVE FLAG ALONE
|
|
INC BX ;YES, INCREMENT FLAG
|
|
PPR1$: TEST AX,40H ;ONE-BYTE JUMP OFFSET?
|
|
JE PPR2$ ;NO
|
|
AND AX,0FF3FH ;YES, CLEAR SPECIAL BITS
|
|
JMP PPR3$
|
|
PPR2$: AND AX,0FF3FH ;CLR SPECIAL BITS FROM HIGH-ORDER OFFSET BYTE
|
|
MOV CX,AX ;HIGH-ORDER BYTE
|
|
CALL NXTBYT ;GET LOW-ORDER BYTE
|
|
MOV AH,CL ;MOVE IN HIGH-ORDER BITS
|
|
TEST AX,2000H ;IS NUMBER NEGATIVE (14-BIT 2'S COMP NUMBER)?
|
|
JE PPR3$ ;NO
|
|
OR AX,0C000H ;YES, MAKE 16-BIT NUMBER NEGATIVE
|
|
PPR3$: DEC BX ;TEST FLAG
|
|
JE PPR6$ ;WAS 1, THAT MEANS DO NOTHING
|
|
CMP AX,0 ;ZERO JUMP?
|
|
JNE PPR4$ ;NO
|
|
JMP OPRFAL ;YES, THAT MEANS DO AN RFALSE
|
|
PPR4$: DEC AX ;ONE JUMP?
|
|
JNE PPR5$ ;NO
|
|
JMP OPRTRU ;YES, THAT MEANS DO AN RTRUE
|
|
PPR5$: DEC AX ;ADJUST OFFSET
|
|
ADD ZPC2,AX ;ADD TO PC
|
|
JMP NEWZPC ;AND UPDATE ZPC STUFF
|
|
PPR6$: RET
|
|
PPRED ENDP
|
|
|
|
;SPLIT BYTE-POINTER IN AX TO BLOCK-POINTER IN AX & BYTE OFFSET IN BX
|
|
PUBLIC BSPLTB
|
|
BSPLTB PROC
|
|
MOV BX,AX
|
|
XCHG AL,AH ;EXTRACT BLOCK BITS
|
|
SHR AX,1
|
|
AND AX,7FH ;CLEAR UNWANTED BITS
|
|
AND BX,1FFH ;CLEAR ALL BUT BYTE OFFSET BITS
|
|
RET
|
|
BSPLTB ENDP
|
|
|
|
;SPLIT WORD-POINTER IN AX TO BLOCK-POINTER IN AX & BYTE-OFFSET IN BX
|
|
PUBLIC BSPLIT
|
|
BSPLIT PROC
|
|
MOV BX,AX
|
|
MOV AL,AH ;EXTRACT BLOCK BITS
|
|
SUB AH,AH ;CLEAR UNWANTED BITS
|
|
SUB BH,BH ;CLEAR ALL BUT WORD OFFSET BITS
|
|
SHL BX,1 ;CONVERT TO BYTE OFFSET
|
|
RET
|
|
BSPLIT ENDP
|
|
|
|
SUBTTL OBJECT HACKERS
|
|
PAGE +
|
|
|
|
PUBLIC OBJLOC,NXTPRP
|
|
;GIVEN OBJ NUMBER IN AX, RETURN OBJ LOCATION IN AX
|
|
OBJLOC PROC
|
|
SUB AH,AH ;CLEAR UNWANTED BITS
|
|
PUSH BX ;MULTIPLY BY 9 THE LAZY WAY
|
|
MOV BX,AX
|
|
SHL AX,1
|
|
SHL AX,1
|
|
SHL AX,1
|
|
ADD AX,BX
|
|
POP BX ;RESTORE
|
|
ADD AX,OBJTAB ;INDEX INTO OBJECT TABLE
|
|
ADD AX,53 ;SKIPPING DEFAULT PROPERTY TABLE
|
|
RET
|
|
OBJLOC ENDP
|
|
|
|
;GIVEN POINTER TO A PROPERTY IN BX!, UPDATE IT TO POINT TO NEXT PROP
|
|
NXTPRP PROC
|
|
PUSH AX ;SAVE
|
|
PUSH CX ;SAVE
|
|
MOV AL,ES:[BX] ; GET PROPERTY IDENTIFIER
|
|
AND AL,MASK PROPSIZE;EXTRACT PROPERTY LENGTH (MINUS 1)
|
|
MOV CL,PROPSIZE
|
|
SHR AL,CL
|
|
SUB AH,AH
|
|
ADD BX,AX ;ADD IT TO OLD POINTER
|
|
ADD BX,2 ;ADJUST FOR EXTRA LENGTH BYTE PLUS IDENTIFIER
|
|
POP CX ;RESTORE
|
|
POP AX ;RESTORE
|
|
RET
|
|
NXTPRP ENDP
|
|
|
|
SUBTTL STRING FUNCTIONS
|
|
PAGE +
|
|
|
|
;OUTPUT A ZSTR, BLOCK-POINTER IN AX, BYTE-POINTER IN BX
|
|
;RETURN UPDATED POINTER
|
|
PUBLIC PUTSTR
|
|
PUTSTR PROC
|
|
PUSH SI ;SAVE
|
|
PUSH CX ;SAVE
|
|
PUSH DX ;SAVE
|
|
PUSH DI ;SAVE
|
|
PUSH BP ;SAVE
|
|
SUB DX,DX ;TEMP CS STARTS AT 0
|
|
SUB DI,DI ;PERM CS STARTS AT 0
|
|
PTS1$: CALL GETWRD ;GET NEXT STRING WORD
|
|
MOV SI,CX
|
|
PUSH AX ;SAVE POINTER & COPY OF STRING WORD
|
|
PUSH BX
|
|
PUSH SI
|
|
MOV CX,3 ;3 BYTES IN WORD
|
|
PTS2$: PUSH SI ;SAVE CURRENT BYTE (IN LOW-ORDER POSITION)
|
|
MOV BP,CX ;SHIFT TO NEXT BYTE
|
|
MOV CL,5
|
|
SAR SI,CL
|
|
MOV CX,BP
|
|
LOOP PTS2$ ;LOOP UNTIL DONE
|
|
MOV CX,3 ;RETRIEVE THE 3 BYTES
|
|
PTS3$: POP SI ;GET NEXT BYTE
|
|
AND SI,1FH ;CLEAR UNWANTED BITS
|
|
CMP DX,0 ;IN WORD MODE?
|
|
JGE PTS4$ ;NO {WAS BPL, CHECK}
|
|
SAL SI,1 ;YES, CALCULATE WORD OFFSET
|
|
ADD SI,WRDTAB ;POINT INTO WORD TABLE
|
|
ADD SI,WRDOFF ;USING PROPER 32-WORD BLOCK
|
|
GTAWRD A,[SI] ;POINT TO WORD STRING
|
|
CALL BSPLIT ;SPLIT IT
|
|
CALL PUTSTR ;AND PRINT IT
|
|
JMP PTS15$ ;CONT. WHERE WE LEFT OFF WITH TEMP CS RESET
|
|
PTS4$: CMP DX,3 ;CS 3 SELECTED (ASCII MODE)?
|
|
JL PTS6$ ;NO, NORMAL CS
|
|
JNE PTS5$ ;NO, BUT WE ARE IN ASCII MODE
|
|
XCHG DL,DH ;SHIFT SOME BITS HIGH TO MAKE NUMBER LARGE
|
|
OR DX,SI ;SAVE HIGH-ORDER ASCII BITS HERE
|
|
JMP PTS16$ ;GO GET NEXT BYTE
|
|
PTS5$: AND DX,3 ;EXTRACT PREVIOUSLY SAVED HIGH-ORDER BITS
|
|
MOV BP,CX ;POSITION THEM
|
|
MOV CL,5
|
|
SAL DX,CL
|
|
MOV CX,BP
|
|
OR DX,SI ;OR IN LOW-ORDER BITS
|
|
MOV AX,DX
|
|
JMP PTS14$ ;GO PRINT THE CHARACTER
|
|
PTS6$: CMP SI,6 ;SPECIAL CODE?
|
|
JL PTS9$ ;YES, SPACE, WORD, OR SHIFT
|
|
CMP DX,2 ;MIGHT ALSO BE SPECIAL IF IN CS 2
|
|
JNE PTS8$ ;BUT WE'RE NOT
|
|
CMP SI,7 ;CRLF?
|
|
JE PTS7$ ;YES
|
|
JG PTS8$ ;NO, NOT ASCII MODE, EITHER?
|
|
INC DX ;YES IT IS, SWITCH TO ASCII MODE
|
|
JMP PTS16$ ;AND GO GET NEXT BYTE
|
|
PTS7$: CALL NEWLIN ;CRLF REQUESTED, DO A NEWLINE
|
|
JMP PTS15$
|
|
PTS8$: MOV AX,DX ;NORMAL CHARACTER, GET CS
|
|
MOV BP,26 ;CALCULATE OFFSET FOR THIS CS
|
|
MUL BP
|
|
ADD AX,SI ;ADD IN CHARACTER OFFSET (+6)
|
|
SUB AX,6 ;CHARACTER OFFSET
|
|
MOV BX,OFFSET ZCHRS ;GET THE CHARACTER FROM CONVERSION VECTOR
|
|
XLAT ZCHRS
|
|
JMP PTS14$ ;GO PRINT IT
|
|
PTS9$: CMP SI,0 ;IS IT A SPACE?
|
|
JNE PTS10$ ;NO
|
|
MOV AX," " ;YES, GO PRINT A SPACE
|
|
JMP PTS14$
|
|
PTS10$: CMP SI,3 ;IS IT A WORD?
|
|
JG PTS11$ ;NO, MUST BE A SHIFT
|
|
OR DX,8000H ;SWITCH TO WORD MODE FOR NEXT BYTE
|
|
DEC SI ;CALCULATE WORD-TABLE BLOCK OFFSET
|
|
MOV BP,CX ;64 BYTES IN A BLOCK
|
|
MOV CL,6
|
|
SHL SI,CL
|
|
MOV CX,BP
|
|
MOV WRDOFF,SI ;SAVE IT AND LOOP
|
|
JMP PTS16$
|
|
PTS11$: SUB SI,3 ;CALCULATE NEW CS
|
|
CMP DX,0 ;TEMPORARY SHIFT (FROM CS 0)?
|
|
JNE PTS12$ ;NO
|
|
MOV DX,SI ;YES, JUST SAVE NEW TEMP CS
|
|
JMP PTS16$
|
|
PTS12$: CMP SI,DX ;IS THIS THE CURRENT CS?
|
|
JE PTS13$ ;YES, DO A PERM SHIFT TO IT
|
|
SUB DX,DX ;OTHERWISE, PERM SHIFT TO CS 0
|
|
PTS13$: MOV DI,DX ;TEMP & PERM CS'S ARE SAME NOW
|
|
JMP PTS16$
|
|
PTS3A$: JMP PTS3$ ;DUMMY FOR NON-SHORT LOOP
|
|
PTS14$: CALL PUTCHR ;PRINT THE CHARACTER
|
|
PTS15$: MOV DX,DI ;RESET TEMP CS TO PERM CS
|
|
PTS16$: LOOP PTS3A$ ;NEXT BYTE
|
|
POP SI ;RESTORE POINTERS & ORIGINAL STRING WORD
|
|
POP BX
|
|
POP AX
|
|
CMP SI,0 ;END-OF-STRING?
|
|
JL PTS1A$ ;YES, CLEAN UP & RETURN UPDATED POINTER
|
|
JMP PTS1$ ;NO, GET NEXT WORD
|
|
PTS1A$: POP BP ;RESTORES
|
|
POP DI
|
|
POP DX
|
|
POP CX
|
|
POP SI
|
|
RET
|
|
PUTSTR ENDP
|
|
|
|
;GIVEN AN ASCII CHARACTER IN AX, RETURN THE CHARACTER SET # IN AX
|
|
PUBLIC CHRCS
|
|
CHRCS PROC
|
|
CMP AX,0 ;IS THIS A NULL?
|
|
JNE CCS1$ ;NO
|
|
MOV AX,3 ;YES, RETURN DUMMY CS NUMBER
|
|
RET
|
|
CCS1$: PUSH BX ;SAVE
|
|
MOV BX,OFFSET ZCHRS ;POINT TO CONVERSION VECTOR
|
|
CCS2$: INC BX ;FOUND THE CHARACTER?
|
|
CMP AL,[BX-1]
|
|
JE CCS3$ ;YES
|
|
CMP BYTE PTR [BX],0 ;NO, END OF STRING?
|
|
JNE CCS2$ ;NO, CONTINUE LOOP
|
|
MOV AX,2 ;YES, CALL IT CS 2
|
|
JMP CCS5$
|
|
CCS3$: SUB BX,OFFSET ZCHRS ;FIND CHARACTER POSITION
|
|
SUB AX,AX ;START WITH CS 0
|
|
CCS4$: SUB BX,26 ;EVERY 26 CHARACTERS IS A NEW CS
|
|
JLE CCS5$ ;DONE
|
|
INC AX ;INCREMENT CS # & CONTINUE LOOP
|
|
JMP CCS4$
|
|
CCS5$: POP BX
|
|
RET
|
|
CHRCS ENDP
|
|
|
|
;GIVEN AN ASCII CHARACTER IN AX, RETURN ZSTR BYTE VALUE IN AX
|
|
PUBLIC CHRBYT
|
|
CHRBYT PROC
|
|
PUSH BX ;SAVE
|
|
MOV BX,OFFSET ZCHRS ;POINT TO CHARACTER CONVERSION TABLE
|
|
CHB1$: INC BX ;FOUND THE CHARACTER?
|
|
CMP AL,[BX-1]
|
|
JE CHB2$ ;YES
|
|
CMP BYTE PTR [BX],0 ;NO, END OF STRING?
|
|
JNE CHB1$ ;NO, CONTINUE LOOP
|
|
SUB AX,AX ;YES, RETURN ZERO FOR FAILURE
|
|
JMP CHB4$
|
|
CHB2$: SUB BX,OFFSET ZCHRS-5 ;ADJUST POINTER SO FIRST CHARACTER IS 6
|
|
MOV AX,BX
|
|
CHB3$: CMP AX,32 ;SUBTRACT MULTIPLES OF 26 UNTIL BASE CODE
|
|
JL CHB4$
|
|
SUB AX,26
|
|
JMP CHB3$
|
|
CHB4$: POP BX ;RESTORE
|
|
RET
|
|
CHRBYT ENDP
|
|
|
|
;CONVERT UP TO 6 ASCIZ CHARS POINTED TO BY DS:AX
|
|
;TO A 2-WORD ZSTR RETURNED IN AX & BX
|
|
PUBLIC ZWORD
|
|
ZWORD PROC
|
|
PUSH SI ;SAVES
|
|
PUSH CX
|
|
PUSH DX
|
|
PUSH DI
|
|
PUSH BP
|
|
MOV SI,AX ;CHARACTER STRING POINTER
|
|
SUB DI,DI ;CS STARTS AT 0
|
|
MOV CX,6 ;MAKE 6 ZSTR BYTES
|
|
ZWD1$: INC SI ;GET NEXT CHARACTER
|
|
MOV BL,[SI-1]
|
|
CMP BL,0
|
|
JNE ZWD3$ ;NOT END-OF-STRING
|
|
MOV AX,OFFSET PADCHR;AT END-OF-STRING, PAD WITH PAD CHARACTER
|
|
ZWD2$: PUSH AX ;SAVE A PAD BYTE
|
|
LOOP ZWD2$ ;LOOP UNTIL DONE
|
|
JMP ZWD6$ ;THEN GO FORM ZWORD
|
|
ZWD3$: MOV AX,BX
|
|
CALL CHRCS ;FIND THE CS NUMBER FOR THIS CHAR
|
|
CMP AX,0 ;CS 0?
|
|
JE ZWD4$ ;YES
|
|
ADD AX,3 ;NO, CALCULATE TEMP SHIFT BYTE
|
|
PUSH AX ;SAVE THE SHIFT BYTE
|
|
DEC CX ;REDUCE BYTE COUNT
|
|
JE ZWD6$ ;DONE
|
|
ZWD4$: MOV AX,BX ;FIND THE PROPER BYTE VALUE FOR THIS CHAR
|
|
CALL CHRBYT
|
|
CMP AX,0 ;IN NORMAL CS'S?
|
|
JNE ZWD5$ ;YES
|
|
MOV AX,6 ;NO, USE ASCII SHIFT
|
|
PUSH AX
|
|
DEC CX ;DONE YET?
|
|
JE ZWD6$ ;YES
|
|
MOV AX,BX ;NO, SAVE HIGH-ORDER ASCII BITS
|
|
MOV BP,CX
|
|
MOV CL,5
|
|
SAR AX,CL
|
|
MOV CX,BP
|
|
PUSH AX
|
|
DEC CX ;DONE YET?
|
|
JE ZWD6$ ;YES
|
|
AND BX,1FH ;NO, SAVE LOW-ORDER ASCII BITS
|
|
MOV AX,BX
|
|
ZWD5$: PUSH AX ;SAVE THIS BYTE
|
|
LOOP ZWD1$ ;LOOP UNTIL ZWORD FULL
|
|
ZWD6$: MOV BP,SP ;BUILD ZWORD WORDS FROM 6 SAVED BYTES
|
|
MOV AX,[BP+10]
|
|
MOV CL,5
|
|
SHL AX,CL
|
|
OR AX,[BP+8]
|
|
SHL AX,CL
|
|
OR AX,[BP+6]
|
|
MOV BX,[BP+4]
|
|
SHL BX,CL
|
|
OR BX,[BP+2]
|
|
SHL BX,CL
|
|
OR BX,[BP]
|
|
OR BX,8000H ;SET END-OF-STRING BIT IN SECOND WORD
|
|
ADD SP,12 ;FLUSH STACK
|
|
POP BP ;RESTORES
|
|
POP DI
|
|
POP DX
|
|
POP CX
|
|
POP SI
|
|
RET
|
|
ZWORD ENDP
|
|
|
|
SUBTTL TERMINAL I/O
|
|
PAGE +
|
|
|
|
;QUEUE CHARACTER IN AX FOR OUTPUT
|
|
PUBLIC PUTCHR
|
|
PUTCHR PROC
|
|
PUSH BP
|
|
MOV BP,CHRPTR
|
|
CMP BP,ENDBUF
|
|
JNE PTC7
|
|
PUSH AX
|
|
PUSH BX
|
|
PUSH SI
|
|
MOV BX,ENDBUF
|
|
MOV SI,OFFSET OUTBUF
|
|
PTC1: DEC BX
|
|
CMP BYTE PTR [BX]," "
|
|
JE PTC3
|
|
CMP BX,SI
|
|
JNE PTC1
|
|
PTC2: PRINT OUTBUF
|
|
MOV CHRPTR,SI
|
|
MOV BP,SP
|
|
CMP BYTE PTR 4 [BP]," "
|
|
JNE PTC6
|
|
MOV WORD PTR 4 [BP],0
|
|
JMP PTC6
|
|
PTC3: CMP BX,SI
|
|
JE PTC2
|
|
MOV BYTE PTR [BX],0
|
|
PRINT OUTBUF
|
|
MOV AX,ENDBUF
|
|
INC BX
|
|
PTC4: CMP BX,AX
|
|
JE PTC5
|
|
MOV BP,AX
|
|
MOV AL,[BX]
|
|
MOV [SI],AL
|
|
MOV AX,BP
|
|
INC BX
|
|
INC SI
|
|
JMP PTC4
|
|
PTC5: MOV CHRPTR,SI
|
|
PTC6: POP SI
|
|
POP BX
|
|
POP AX
|
|
CMP AX,0
|
|
JE PTC8
|
|
PTC7: MOV BP,CHRPTR
|
|
MOV [BP],AL ; (6) REMOVED DS OVERRIDE
|
|
INC CHRPTR
|
|
PTC8: POP BP
|
|
RET
|
|
PUTCHR ENDP
|
|
|
|
;GO TO NEW LINE, OUTPUTTING CURRENT BUFFER
|
|
NEWLIN PROC
|
|
PUSH BX ;SAVE
|
|
MOV BX,CHRPTR ;END LINE AT CURRENT POINT
|
|
MOV BYTE PTR [BX],0
|
|
MOV CHRPTR,OFFSET OUTBUF ;RESET CHARACTER POINTER
|
|
POP BX ;RESTORE
|
|
PRINT OUTBUF ;AND OUTPUT LINE
|
|
RET
|
|
NEWLIN ENDP
|
|
|
|
SUBTTL TOP LEVEL STUFF
|
|
PAGE +
|
|
|
|
; READ THE SETUP FILE
|
|
; SSETUP HAS UNDER GONE TO SETS OF REVISIONS. REVISION 6 IS RESPONSIBLE
|
|
; FOR ALL OF THE DOS 2.0 FILE HANDLING PATCHES. REVISION 7 IS RESPONSIBLE
|
|
; FOR SETTING UP COLOR OR MONOCHROME BASED ON THE VIDEO SETTINGS AND WHAT
|
|
; WAS SPECIFIED ON THE COMMAND LINE.
|
|
;
|
|
PUBLIC SSETUP
|
|
SSETUP PROC NEAR
|
|
MOV DX,OFFSET SSFILE ; (6) USE ASCIZ FILENAME
|
|
MOV AH,CFOPENZ ; TRY OPENING THE SETUP FILE
|
|
MOV AL,0 ; (6) OPEN FILE FOR READING
|
|
INT 21H
|
|
JC SSET1 ; IF OPEN FAIL, COMPLAIN
|
|
MOV BX,AX ; (6) PUT HANDLE IN BX
|
|
MOV AH,CRDRNDZ ; (6) READ INTO THE BUFFER
|
|
MOV DX,OFFSET SSBUF ; (6) BUFFER TO READ INTO
|
|
MOV CX,SSLNT ; (6) READ (CX) BYTES
|
|
INT 21H
|
|
CMP AL,SSLNT ; (6) DID WE GET ALL THE BYTES
|
|
JNE SSET2 ; IF READ FAIL, COMPLAIN
|
|
PUSH BX ; (6) SAVE THE HANDLE
|
|
MOV BX,DX ; (6) GET OFFSET TO BUFFER
|
|
MOV AL,[BX]
|
|
SUB AL,SSVER
|
|
DEC AL ; FOR A 25 LINE SCREEN, SLPP HAS 24 IN IT
|
|
MOV SLPP,AL
|
|
MOV AL,[BX+1]
|
|
SUB AL,SSHOR
|
|
MOV SCPL,AL
|
|
MOV SLFLG,1 ; SET IT TO ANSI
|
|
MOV AL,[BX+2]
|
|
CMP AL,"N" ; IS IT ASCII
|
|
JNE SSET4 ; NO, THEN LEAVE IT ALONE
|
|
MOV SLFLG,0 ; YES, THEN SET IT TO ASCII
|
|
MOV SCROLL,1 ; (7) NO SCROLLING IF NO ANSI.SYS
|
|
JMP SSET6
|
|
SSET4: TEST SCROLL,1 ; (7) SHOULD WE CONSIDER COLOR
|
|
JNZ SSET6 ; (7u) I GUESS NOT
|
|
MOV AH,15 ; (7) CHECK VIDEO STATE
|
|
INT 10H ; (7) TO SEE IF IN A COLOR MOOD
|
|
CMP AL,1 ; (7) THIS IS 40x25 COLOR
|
|
JNZ SSET5
|
|
SSET4A: TEST CMDLIN,1 ; (7) WAS THIS SET ON CMD LINE
|
|
JNZ SSET6 ; (7) YES, CANNOT OVERRIDE
|
|
CMP SCROLL,1 ; (7u) NO COLOR WITHOUT SCROLL CAPABILITY
|
|
JZ SSET6 ;
|
|
MOV COLFLG,1 ; (7) SET COLOR FLAG
|
|
MOV SCRATR,COLATR ; (7) SET VIDEO ATTRIBUTE
|
|
JMP SSET6
|
|
SSET5: CMP AL,3 ; (7) THIS IS 80x25 COLOR
|
|
JZ SSET4A
|
|
TEST CMDLIN,2 ; (7) DID THEY SET COLOR FROM CMD LINE
|
|
JNZ SSET4A ; (7) TURN IT ON
|
|
SSET6: POP BX ; (6) RESTORE THE HANDLE
|
|
MOV AH,CFCLOSZ ; (6) CLOSE THE SETUP FILE
|
|
INT 21H
|
|
JC SSET3 ; (6) IF CANNOT CLOSE FILE, COMPLAIN
|
|
RET
|
|
SSET1: DEC SLPP ; (N1) SET TO 24 TO WORK RIGHT ANYWAY!
|
|
PRINT SSMSG1
|
|
RET
|
|
SSET2: PRINT SSMSG2
|
|
RET
|
|
SSET3: PRINT SSMSG3
|
|
RET
|
|
SSETUP ENDP
|
|
|
|
;INITIALIZATION
|
|
PUBLIC TSET4
|
|
TSETUP PROC
|
|
MOV BX,OFFSET SELINE1
|
|
TEST COLFLG,1 ; (7) ARE WE USING COLOR
|
|
JZ TSET0 ; (7) NOPE, ...
|
|
MOV BX,OFFSET CELINE1 ; (7) FIX COLOR IF NECESSARY
|
|
TSET0: MOV AL,SLPP ; NUMBER OF LINES
|
|
SUB AH,AH ; ASCIIFY THIS NUMBER INTO AX
|
|
INC AX ; FOR SLPP = 24, THE CURSOR IS AT 25
|
|
DIV RADIX ; SO THAT WE CAN PUT THE CURSOR
|
|
ADD AH,"0" ; THERE WHEN WE FINISH THE STATUS
|
|
ADD AL,"0" ; LINE OUTPUT IN MSOUT
|
|
MOV [BX],AX ; DO THE PATCH
|
|
MOV BX,OFFSET CLS1 ; (7t) PATCH CLEAR SCREEN
|
|
MOV [BX],AX ; (7t) SO THAT IT RESTORE CURPOS
|
|
MOV BX,OFFSET CLS1C ; (7t) PATCH IT IN COLOR TOO
|
|
MOV [BX],AX
|
|
MOV BX,OFFSET OUTBUF ; NO DETERMINE END OF OUTPUT BUFFER
|
|
|
|
MOV CL,SCPL
|
|
SUB CH,CH
|
|
ADD BX,CX
|
|
DEC BX ; (7v) SHORTEN BY ONE TO AVOID HARD
|
|
MOV ENDBUF,BX ; WRAP
|
|
MOV BYTE PTR [BX],0
|
|
MOV BX,OFFSET SLSTAB ; NOW, CHOSE A STATUS LINE
|
|
CMP TIMEMD,0 ; CHECK FOR TIME MODE
|
|
JE TSET1 ; NOPE, USE OTHER STATUS LINE
|
|
ADD BX,8 ; YES, GET OFFSET TO TIME STAT LINES
|
|
TSET1: CMP CX,55 ; CX HAS WIDTH OF SCREEN IN COLUMNS
|
|
JL TSET2
|
|
MOV AX,60 ; MAKE AN INDEX INTO ROOM DESC
|
|
SUB CX,80 ; SCALE WITHIN 80 - WIDTH
|
|
MOV SI,4 ; SKIP SCORE PTR'S IN TABLE
|
|
JMP TSET3 ; FIX VALUES IN THE TABLE WITH CX
|
|
TSET2: MOV AX,15 ; MAKE AN INDEX INTO ROOM DESC BUFFER
|
|
SUB CX,40 ; SCALE WITHIN 40 - WIDTH
|
|
SUB SI,SI ; SI INDEXES INTO SCORE v. TIME
|
|
TSET3: SUB AX,CX ; BACKUP THE PTR IN BUFFER
|
|
ADD AX,[BX][SI] ; GET OFFSET TO BUFFER BEGINNING
|
|
MOV BX,2[BX][SI] ; GET OFFSET TO TABLE BEGINNING
|
|
TEST CX,CX ; SEE IF CX IS LESS THAN ZERO
|
|
JG TSET4 ; SKIP FIRST PATCH IF POSITIVE
|
|
ADD 6[BX],CX ; THESE PATCHES ADJUST THE RANGES FOR
|
|
;+EACH OF THE STATUS LINE FIELD ACCORDING
|
|
;+TO THE CALCULATED LENGTH OF THE STATUS
|
|
;+LINE
|
|
TSET4: ADD 12[BX],CX ; PATCH CX INTO THESE TABLE OFFSETS
|
|
ADD 14[BX],CX ; CX HAS DIFFERENCE BET TERM W & 80
|
|
ADD 20[BX],CX
|
|
ADD 22[BX],CX
|
|
TSET5: MOV SLSTR,AX ; SAVE STATUS LINE BUFFER ADDR IN HERE
|
|
MOV SLTAB,BX ; AND STATUS LINE TABLE ADDR IN HERE
|
|
CALL MINIT
|
|
RET
|
|
TSETUP ENDP
|
|
|
|
|
|
PUBLIC ZIPBGN,STR5$,STR8$,STR9$,STR10$,STR11$,STR12$,STR12A
|
|
PUBLIC STR12B,STR13$,STR14$,STR15$,STR17$
|
|
ZIPBGN PROC
|
|
CALL SYSINI ;DO ANY SYSTEM INITIALIZATION
|
|
CALL HERALD ;put up the herald file
|
|
STR5$: SUB AX,AX ;BLOCK 0
|
|
SUB BX,BX ;PUT AT BEGINNING OF GAME SEGMENT
|
|
CALL GETBLK ;GET THE BLOCK
|
|
MOV GAMEIN,1 ; (7q) INDICATE RELIABILITY OF SCRIPT BIT
|
|
CMP BYTE PTR ES:[PVERS1],ZMVERS ;PROPER Z-MACHINE VERSION?
|
|
JNE STR8$ ;NO
|
|
TEST BYTE PTR ES:[PVERS2],1 ;YES,PROPER MODE BITS?
|
|
JE STR9$ ;YES
|
|
STR8$: FATAL FTL4 ;SOMETHING WRONG, DIE
|
|
STR9$: TEST BYTE PTR ES:[PVERS2],2 ;TIME MODE REQUESTED?
|
|
JE STR10$ ;NO
|
|
INC TIMEMD ;YES, SET TIME-MODE FLAG
|
|
STR10$: MOV AL,BYTE PTR ES:[PVERS2]
|
|
CMP SLFLG,0
|
|
JNE STR11$
|
|
OR AL,10H ;TURN ON THE NO STATUS LINE BIT
|
|
MOV BYTE PTR ES:[PVERS2],AL
|
|
STR11$: TEST SCROLL,1 ; (7) CAN WE SPLIT THE SCREEN
|
|
JNZ STR11A ; (7) GUESS NOT...
|
|
MOV AL,BYTE PTR ES:[PVERS2]
|
|
OR AL,SCRBIT ; (7) TURN ON BIT FOR SPLIT
|
|
MOV BYTE PTR ES:[PVERS2],AL ;(7) SAVE IT
|
|
STR11A: GTAWRD A,[PZRKID] ;UNIQUE GAME & VERSION INDENTIFIER
|
|
MOV ZORKID,AX
|
|
GTAWRD A,[PENDLD] ;GET ENDLOD POINTER
|
|
TEST AX,1FFH ;ROUND UP TO NEXT BLOCK
|
|
JE STR12$
|
|
AND AX,0FE00H
|
|
ADD AX,200H
|
|
STR12$: MOV CX,AX
|
|
MOV BP,CX ;EXTRACT ENDLOD BLOCK
|
|
MOV CL,9
|
|
SAR BP,CL
|
|
MOV CX,BP
|
|
MOV ENDLOD,CX ;SAVE ENDLOD BLOCK NUMBER
|
|
MOV AX,128 ;(6) FIGURE BOUNDRY FOR SEG1
|
|
SUB AX,CX ;(6) SUBTRACT AMOUNT IN PRELOD
|
|
SHL AX,1 ;(6) MULTIPLY IT BY #BYTES PER
|
|
SHL AX,1 ;(6) ENTRY IN PAGTAB FOR SCALING
|
|
MOV SEGEND,AX ;(6) USED TO COMPARE TO PAGTAB TO LOCATE
|
|
;(6) SEGMENT IN WHICH GAMEBLOCK RESIDES
|
|
DEC CX ;NUMBER OF BLOCKS LEFT TO LOAD
|
|
CMP FITS,1 ;(6) READ THE WHOLE GAME IN
|
|
JNE STR12A ;(6) NO, DON'T READ IT ALL IN
|
|
MOV CX,127 ;(6) TWO 64K READS
|
|
MOV AX,1 ;(6) STARTING WITH BLK 1
|
|
MOV LPTAB,1 ;(6) STARTING LOCATION
|
|
CALL GTBLKS
|
|
MOV CX,127 ;(6) READ ALL BUT 1/2K
|
|
MOV LPTAB,128 ;(6) READ INTO SEG1
|
|
MOV AX,128 ;(6) THE LAST 64K BLKS
|
|
CALL GTBLKS
|
|
JNZ STR12$$ ;(8) READ LAST BLOCK?
|
|
MOV CX,1 ;(8) READ ONE MORE BLOCK
|
|
MOV AX,255 ;(8) LAST BLOCK NUMBER
|
|
MOV LPTAB,255 ;(8) PAGE LOCATION
|
|
CALL GTBLKS ;(8) GET IT
|
|
STR12$$:MOV LPTAB,0
|
|
JMP STR12B
|
|
STR12A: MOV AX,1 ;STARTING WITH BLOCK 1
|
|
MOV BX,OFFSET PAGTAB ; (6) GET A BUFFER ADDRESS
|
|
ADD BX,4 ; (6) SECOND ENTRY
|
|
MOV LPTAB,BX ; (6) SAVE THIS CALCULATED ADDR
|
|
CALL GTBLKS ;GET THE BLOCKS
|
|
STR12B: GTAWRD A,[PVOCTB] ;VOCAB LOCATION
|
|
MOV VOCTAB,AX ;SAVE VOCABULARY TABLE POINTER
|
|
GTAWRD A,[POBJTB] ;GET OBJECT TABLE POINTER
|
|
MOV OBJTAB,AX
|
|
GTAWRD A,[PGLOTB] ;GET GLOBAL TABLE POINTER
|
|
MOV GLOTAB,AX
|
|
GTAWRD A,[PWRDTB] ;GET WORD TABLE POINTER
|
|
MOV WRDTAB,AX
|
|
GTAWRD A,[PPURBT] ;GET PURE CODE POINTER
|
|
TEST AX,1FFH ;ROUND UP TO NEXT BLOCK
|
|
JE STR13$
|
|
ADD AX,200H
|
|
STR13$: MOV CL,9 ;EXTRACT BLOCK NUMBER
|
|
SAR AX,CL
|
|
AND AX,7FH ;CLEAR UNWANTED BITS
|
|
MOV PURBOT,AX ;SAVE IT
|
|
MOV BX,OFFSET RBRKS ;START OF READ BREAK CHARACTER TABLE
|
|
MOV SI,VOCTAB ;VOCAB TABLE POINTER
|
|
MOV CL,BYTE PTR ES:[SI] ;1ST BYTE IN VOCTAB IS # OF SIBREAKS
|
|
SUB CH,CH ;CLEAR HIGH BYTE
|
|
INC SI
|
|
STR14$: MOVM [BX],ES:[SI],AL ;TRANSFER THEM
|
|
INC BX
|
|
INC SI
|
|
LOOP STR14$
|
|
MOV ESIBKS,BX ;REMEMBER END OF SI BREAKS
|
|
MOV BP,OFFSET IRBRKS;ALWAYS END WITH INITIAL BREAK CHARACTERS
|
|
STR15$: MOVM [BX],[BP],AL ;(6)TRANSFER THEM
|
|
INC BX
|
|
INC BP
|
|
CMP AL,0
|
|
JNE STR15$
|
|
MOV AL,ES:[SI] ;GET VOCABULARY ENTRY LENGTH
|
|
SUB AH,AH
|
|
MOV VWLEN,AX ;AND STORE IT AWAY
|
|
INC SI
|
|
GTAWRD A,[SI] ;GET NEXT WORD IN TABLE
|
|
MOV VWORDS,AX ;NUMBER OF WORD ENTRIES IN VOCABULARY
|
|
ADD SI,2 ;MOVE TO NEXT WORD
|
|
MOV VOCBEG,SI ;BEGINNING OF ACTUAL VOCABULARY
|
|
|
|
MOV SI,ENDLOD ;GET # PAGES IN ENDLOD
|
|
MOV CL,9
|
|
SHL SI,CL ;THIS IS FIRST LOCATION (ES:) OF PAGING
|
|
MOV PAGES,SI ;SAVE THIS TO USE AS AN OFFSET
|
|
|
|
CALL MTIME
|
|
STR17$: JMP START1
|
|
ZIPBGN ENDP
|
|
|
|
;RESTART EXECUTION HERE
|
|
PUBLIC RESTRT,RESTRT1,START1
|
|
RESTRT PROC
|
|
CALL GAMOPEN ; (7q) OPEN THE GAME FILE
|
|
MOV MORLIN,0 ; (7s) RESET MORE COUNT
|
|
SUB AX,AX ;REREAD ALL OF THE IMPURE STUFF
|
|
MOV CURSEG,0 ; (K5) SET SEG FLAGS BACK TO SEG0
|
|
MOV ZPCSEG,0
|
|
MOV LPTAB,0 ; (6) FILL THE FIRST BIT OF STUFF
|
|
PUSH PAGES ; (6) SAVE THIS VARIABLE
|
|
MOV PAGES,0 ; (6) RESET IT FOR SMALL MEMORY READ
|
|
MOV CX,PURBOT
|
|
CALL GTBLKS
|
|
POP PAGES ; RESET IT AGAIN
|
|
MOV AH,SCRFLG ; (7o) WERE WE SCRIPTING
|
|
XOR AL,AL ; (7o) ZERO THIS
|
|
MOV WORD PTR ES:[PFLAGS],AX ; (7o) RESTORE SCRIPTING STATE
|
|
TEST SCROLL,1 ; (7) CAN WE SCROLL?
|
|
JNZ RESTRT1 ; (7) NEVER COULD, SKIP RE-INITS
|
|
OR BYTE PTR ES:[PVERS2],SCRBIT ; (7) TURN ON SPLIT
|
|
MOV TOPLIN,TOPSCR ; (7) FIX SCREEN VARIABLES ON RESTART
|
|
MOV SCRNFLG,0 ; (7) WHOLE SCREEN, ONLY 1
|
|
MOV SPLTFLG,0 ; (7) NO SPLIT SCREEN
|
|
JMP RESTRT1 ; PATCH TO FIX STATUS LINE BUG (5)/PHG
|
|
START1:
|
|
|
|
CALL TSETUP ;SETUP TERMINAL/STATUS LINE
|
|
RESTRT1:CALL CLRSCR ;CLEAR THE REMAINDER OF SCREEN
|
|
|
|
; MOV AL,BYTE PTR ES:[PVERS2]
|
|
; ADD AL,8 ;TANDY BIT
|
|
; MOV BYTE PTR ES:[PVERS2],AL
|
|
|
|
MOV SP,OFFSET STK_TOP ;INITIALIZE OUR STACK POINTER
|
|
MOV DI,OFFSET ZSTK_TP ;INITIALIZE USER STACK POINTER
|
|
MOV CHRPTR,OFFSET OUTBUF ;INITIALIZE OUTPUT CHARACTER POINTER
|
|
MOV ZLOCS,DI ;LOCALS WOULD START AT FIRST SLOT,
|
|
SUB ZLOCS,2 ;IF THERE WERE ANY
|
|
GTAWRD A,[PSTART] ;GET STARTING LOCATION
|
|
CALL BSPLTB ;SPLIT BLOCK & BYTE POINTERS
|
|
MOV ZPC1,AX ;INITIALIZE ZPC BLOCK-POINTER
|
|
MOV ZPC2,BX ;INITIALIZE ZPC BYTE-POINTER
|
|
CALL NEWZPC ;GET PAGE TO EXECUTE
|
|
JMP NXTINS
|
|
RESTRT ENDP
|
|
|
|
;MAIN INSTRUCTION INTERPRETATION LOOP
|
|
PUBLIC NXTINS,NXI0A$,NXI0B$,NXI0C$,NXI1$,NXI2$,NXI3$,NXI4$,NXI5$
|
|
PUBLIC NXI6$,NXI7$,NXI8$,NXI8A$,NXI9$,NXI10$,NXI11$,NXI12$,NXI14$,NXI15$
|
|
NXTINS PROC
|
|
CALL NXTBYT ;GET THE OPERATION BYTE
|
|
MOV DX,AX ;SAVE A COPY
|
|
CMP AX,80H ;IS IT A 2OP?
|
|
JL NXI9$ ;YES
|
|
CMP AX,0B0H ;NO, IS IT A 1OP?
|
|
JGE NXI0A$ ;NO
|
|
JMP NXI12$ ;YES
|
|
NXI0A$: CMP AX,0C0H ;IS IT A 0OP?
|
|
JG NXI0B$ ;NO
|
|
JMP NXI13$ ;YES
|
|
NXI0B$: AND AX,3FH ;IT'S EXTENDED, GET THE OPCODE
|
|
SHL AX,1 ;MAKE IT A WORD OFFSET
|
|
MOV BP,AX ;GET THE OPERATOR POINTER
|
|
MOV SI,[BP+EXTOP] ; (6) REMOVED DS OVERRIDE
|
|
CMP SI,0
|
|
JNE NXI0C$ ;OPERATION EXISTS
|
|
JMP NXI14$ ;NO SUCH OPERATION
|
|
NXI0C$: CALL NXTBYT ;GET THE ARGUMENT BYTE
|
|
MOV CX,4 ;SPLIT IT INTO 4 2-BIT MODE BYTES
|
|
NXI1$: PUSH AX
|
|
SAR AX,1
|
|
SAR AX,1
|
|
LOOP NXI1$
|
|
MOV CX,4 ;RETRIEVE THE 4 BYTES IN PROPER ORDER
|
|
SUB DX,DX
|
|
MOV BX,OFFSET ARGBLK;FIRST ARGUMENT SLOT
|
|
NXI2$: POP AX ;GET NEXT MODE BYTE?
|
|
AND AX,3 ;CLEAR OFF UNWANTED BITS
|
|
CMP AX,3 ;NO MORE ARGUMENTS?
|
|
JE NXI4$ ;YES, FLUSH ANY OTHER MODE BYTES
|
|
CALL GETARG ;ELSE, GET THE NEXT ARGUMENT
|
|
MOV [BX],AX ;SAVE IT IN ARGUMENT BLOCK
|
|
ADD BX,2
|
|
INC DX ;REMEMBER NUMBER OF ARGS GOTTEN
|
|
NXI3$: LOOP NXI2$ ;LOOP FOR REST OF MODE BYTES
|
|
JMP NXI5$
|
|
NXI4$: DEC CX ;DETERMINE NUMBER OF REMAINING MODE BYTES
|
|
SHL CX,1 ;WORD COUNT
|
|
ADD SP,CX ;FLUSH THEM
|
|
NXI5$: XCHG CX,DX
|
|
MOV AX,CX ;NUMBER OF ARGS GOES HERE FOR OPERATOR TO USE
|
|
CMP BYTE PTR [SI],90H ;(6)DOES OPERATOR WANT ARGBLK POINTER?
|
|
JE NXI8A$ ;YES, CALL OPERATOR NOW
|
|
DEC CX ;NO, IT WANTS ARGS IN REGISTERS
|
|
JL NXI8A$ ;NO ARGS, JUST CALL OPERATOR
|
|
JE NXI8$ ;1 ARG, GET IT
|
|
SUB CX,2
|
|
JL NXI7$ ;2 ARGS
|
|
JE NXI6$ ;3 ARGS
|
|
MOV DX,ARGBLK[6] ;ELSE, 4 ARGS, GET 4TH
|
|
NXI6$: MOV CX,ARGBLK[4] ;GET 3RD
|
|
NXI7$: MOV BX,ARGBLK[2] ;GET 2ND
|
|
NXI8$: MOV AX,ARGBLK ;GET FIRST ARG
|
|
NXI8A$: JMP NXI15$ ;AND CALL OPERATOR
|
|
NXI9$: AND AX,1FH ;2OP, EXTRACT OPERATION BITS
|
|
SHL AX,1 ;MAKE IT A WORD OFFSET
|
|
MOV BP,AX ;FIND POINTER TO OPERATOR ROUTINE
|
|
MOV SI,[BP+EXTOP] ;(6) REMOVED DS OVERRIDE
|
|
CMP SI,0
|
|
JE NXI14$ ;NO SUCH OPERATION
|
|
MOV AX,1 ;ASSUME FIRST ARG IS AN IMMEDIATE
|
|
TEST DX,40H ;IS IT INSTEAD A VARIABLE?
|
|
JE NXI10$ ;NO
|
|
INC AX ;YES, CHANGE MODE
|
|
NXI10$: CALL GETARG ;GET THE FIRST ARG
|
|
PUSH AX ;SAVE IT
|
|
MOV AX,1 ;ASSUME SECOND ARG IS AN IMMEDIATE
|
|
TEST DX,20H ;IS IT INSTEAD A VARIABLE?
|
|
JE NXI11$ ;NO
|
|
INC AX ;YES, CHANGE MODE
|
|
NXI11$: CALL GETARG ;GET THE SECOND ARG
|
|
MOV BX,AX ;POSITION IT
|
|
POP AX ;RECOVER FIRST ARG
|
|
CMP BYTE PTR [SI],90H ;(6)DOES ROUTINE WANT ARGUMENT BLOCK?
|
|
JNE NXI15$ ;NO, GO CALL IT
|
|
MOV ARGBLK,AX ;YES, MOVE ARGS TO ARGBLK
|
|
MOV ARGBLK[2],BX
|
|
MOV AX,2 ;ALWAYS 2 ARGS
|
|
JMP NXI15$ ;NOW CALL OPERATOR
|
|
NXI12$: AND DX,0FH ;1OP, EXTRACT OPERATION BITS
|
|
SHL DX,1 ;MAKE IT A WORD OFFSET
|
|
MOV BP,DX ;GET OPERATOR ROUTINE POINTER
|
|
MOV SI,[BP+ONEOP] ;(6) REMOVED DS OVERRIDE
|
|
CMP SI,0
|
|
JE NXI14$ ;ILLEGAL OPERATION
|
|
SAR AX,1 ;EXTRACT MODE BITS
|
|
SAR AX,1
|
|
SAR AX,1
|
|
SAR AX,1
|
|
AND AX,3
|
|
CALL GETARG ;GET THE ARGUMENT
|
|
JMP NXI15$ ;AND CALL OPERATOR
|
|
NXI13$: AND AX,0FH ;0OP, EXTRACT OPERATION BITS
|
|
SHL AX,1 ;MAKE IT A WORD OFFSET
|
|
MOV BP,AX ;GET OPERATOR ROUTINE POINTER
|
|
MOV SI,[BP+ZEROOP] ; (6) REMOVED DS OVERRIDE
|
|
CMP SI,0
|
|
JNE NXI15$ ;IT'S A LEGAL OPERATION
|
|
NXI14$: FATAL FTL5 ;OTHERWISE, COMPLAIN
|
|
NXI15$: CALL SI ;CALL THE OPERATOR ROUTINE
|
|
JMP NXTINS ;AND LOOP FOR NEXT INSTRUCTION
|
|
NXTINS ENDP
|
|
|
|
SUBTTL PAGING ROUTINES
|
|
PAGE +
|
|
|
|
;NORMALIZE ZPC & GET PROPER PAGE
|
|
; NEWZPC HAS BE EXTENDED TO UPDATE THE ZPCSEG VARIABLE. IT SETS THIS
|
|
; VARIABLE DIFFERENTLY ACCORDING TO PAGING SCHEME. IF THE GAME FITS IN
|
|
; MEMORY, ZPCSEG IS SET ACCORDING TO THE 17TH BIT OF THE ZPC, OTHERWISE
|
|
; IT IS SET WHEN CURSEG IS SET BY THE GETPAG ROUTINE INDICATING THAT
|
|
; THE CURRENT BLOCK IN THE SECOND ES SEGMENT.
|
|
;
|
|
PUBLIC NEWZPC,NWZ1$,NWZ2$,NWZ3$,NWZ4$,NWZ5$
|
|
NEWZPC PROC
|
|
PUSH SI ;SAVES
|
|
PUSH BP
|
|
PUSH BX
|
|
PUSH CX
|
|
PUSH DX
|
|
SUB AX,AX ;USE DOUBLE-WORD ARITHMETIC
|
|
MOV BX,ZPC1 ;GET BLOCK-POINTER
|
|
MOV BH,BL ;POSITION IT
|
|
SUB BL,BL
|
|
SHL BX,1
|
|
ADC AX,0
|
|
MOV SI,ZPC2 ;GET BYTE-OFFSET
|
|
XCHG SI,AX ;DOUBLE-WORDIFY IT (MIGHT BE NEGATIVE)
|
|
CWD
|
|
XCHG SI,AX
|
|
ADD BX,SI ;ADD IT TO OTHER DOUBLE WORD
|
|
ADC AX,DX
|
|
MOV DX,BX
|
|
AND DX,1FFH ;EXTRACT BYTE-OFFSET
|
|
MOV ZPC2,DX ;SAVE IT
|
|
MOV CL,9 ;EXTRACT BLOCK-POINTER
|
|
SAR BX,CL
|
|
AND BX,7FH
|
|
TEST AX,1 ;TEST 17TH BIT
|
|
JE NWZ1A$ ;WAS 0
|
|
OR BX,80H ;WAS 1, SET PROPER BIT IN BLOCK-POINTER
|
|
TEST FITS,1 ;(6) DO WE HAVE ALL OF THE GAME IN MEMORY
|
|
JZ NWZ1$ ; (6) BECAUSE PAGES ARE NOT CONTINUOUS
|
|
MOV ZPCSEG,1 ; WERE IN THE UPPER GAME SEG
|
|
JMP NWZ1$
|
|
NWZ1A$: TEST FITS,1 ;(6) SHOULD WE SET THIS HERE
|
|
JZ NWZ1$ ;(6) NO
|
|
MOV ZPCSEG,0 ;(6) SET SEGMENT TO BASE SEG
|
|
NWZ1$: MOV ZPC1,BX ;SAVE IT
|
|
TEST ZPCFLG,1 ;(7n) DO WE HAVE THE RIGHT BLOCK
|
|
JNZ NWZ1Q$ ;(7n) NO, SKIP THIS SKIP
|
|
CMP BX,CURBLK ;HAS IT CHANGED?
|
|
JE NWZ5$ ;NO
|
|
NWZ1Q$: MOV CURBLK,BX ;YES, REMEMBER NEW BLOCK
|
|
MOV AX,CURTAB ;IS OLD PAGE IN PAGING SPACE?
|
|
CMP AX,0
|
|
JE NWZ2$ ;NO
|
|
MOV BP,AX ;YES, STORE CURRENT REF TIME FOR OLD PAGE
|
|
MOVM [BP],RTIME1,CL ;(6) REMOVED DS OVERRIDE
|
|
MOVM [BP+1],RTIME2,CX ;(6) REMOVED DS OVERRIDE
|
|
INC AX
|
|
NWZ2$: CMP FITS,1 ;(6) IS THE WHOLE GAME THERE
|
|
JZ NWZ3$ ;(6) YES, GO DO WHATEVER
|
|
CMP BX,ENDLOD ;NEW PAGE ALREADY IN CORE?
|
|
JL NWZ3$ ;YES
|
|
MOV AX,BX ;NO, GET NEW PAGE
|
|
CALL GETPAG
|
|
MOV BL,CURSEG ;(6) SET ZPCSEG TO SAME AS CURSEG
|
|
MOV ZPCSEG,BL ;(6) SO THAT NXTBYT WORKS
|
|
MOV BX,AX
|
|
MOV AX,LPTAB ;GET NEW PAGE TABLE POINTER
|
|
INC AX ;POINT TO REF SLOT
|
|
MOV CURTAB,AX ;SAVE THIS POINTER FOR LATER
|
|
MOV BP,AX ;STORE HIGHEST RTIME TO KEEP PAGE FOR US
|
|
MOV BYTE PTR [BP],-1 ;(6) REMOVED DS OVERRIDE
|
|
MOV WORD PTR [BP+1],-1 ;(6) REMOVED DS OVERRIDE
|
|
INC AX
|
|
JMP NWZ4$
|
|
NWZ3$: MOV CL,9 ;CALCULATE PAGE ADDRESS
|
|
SHL BX,CL
|
|
TEST FITS,1
|
|
JNZ NWZ3A$ ; (7z) SKIP DURING WHOLE MEMORY EDITION
|
|
MOV ZPCSEG,0 ; (7z) RESET THIS TO SEG0
|
|
NWZ3A$: MOV CURTAB,0 ;CLEARING POINTER MEANS PAGE IS PRELOADED
|
|
NWZ4$: MOV CURPAG,BX ;UPDATE PAGE POINTER
|
|
NWZ5$: MOV ZPCFLG,0 ; (K3) RESET THIS FLAG
|
|
POP DX ;RESTORES
|
|
POP CX
|
|
POP BX
|
|
POP BP
|
|
POP SI
|
|
RET ;AND RETURN
|
|
NEWZPC ENDP
|
|
|
|
;GET THE PAGE WHOSE NUMBER IS IN AX, RETURN A POINTER TO IT IN AX
|
|
; GETPAG AND FINDPG WERE MODIFIED TO ACCOMMODATE THE EXTENDED PAGING
|
|
; SCHEMES. SEGEND, CURSEG AND PAGTAB ARE SIGNIFICANT VARIABLES IN THESE
|
|
; MODIFICATIONS. SEGEND IS USED TO COMPARE TO THE CURRENT LOCATION IN
|
|
; PAGTAB WHICH IN TURN INDICATES IN WHICH SEGMENT THE NEW BLOCK IS LOCATED.
|
|
; CURSEG IS SET TO TELL THE OUTSIDE WORLD WHICH SEGMENT THE LAST GETPAG
|
|
; TOUCHED. NOTE THAT BEING IN THE SECOND SEGMENT (SEG1) REQUIRES THAT
|
|
; ADDRESS CALCULATIONS DO NOT ADD IN PAGES (THE VARIABLE MARKING THE END
|
|
; OF PRELOAD). THIS REQUIREMENT IS NECESSARY BECAUSE THERE IS NO PRELOAD
|
|
; IN THE SECOND SEGMENT.
|
|
;
|
|
PUBLIC GETPAG,GTP1$,GTP2$,GTP2A$,GTP2B,GTP2C,GTP3$,GTP4$
|
|
GETPAG PROC
|
|
CMP AX,LPAGE ;IS THIS THE SAME PAGE AS LAST REFERENCED?
|
|
JNE GTP1$ ;NO
|
|
MOV AX,LPLOC ;YES, WE ALREADY HAVE LOCATION
|
|
RET ;RETURN IT
|
|
GTP1$: MOV LPAGE,AX ;SAVE NEW PAGE NUMBER
|
|
PUSH CX ;SAVES
|
|
PUSH BX
|
|
ADD RTIME2,1 ;UPDATE REFERENCE TIME (COUNT)
|
|
ADC RTIME1,0
|
|
MOV BX,OFFSET PAGTAB;PAGE INFORMATION TABLE
|
|
GTP2$: INC BX
|
|
CMP AL,[BX-1] ;SEARCH FOR DESIRED BLOCK
|
|
JNE GTP3$ ;NOT IT
|
|
CMP AX,CURBLK ;IS THIS THE CURRENT CODE PAGE?
|
|
JE GTP2A$ ;DON'T UPDATE REFERENCE TIME
|
|
MOVM [BX],RTIME1,CL ;FOUND IT, UPDATE ITS REFERENCE TIME
|
|
MOVM [BX+1],RTIME2,CX
|
|
GTP2A$: DEC BX ;BACKUP TO BEGINNING OF TABLE ENTRY
|
|
PUSH BX ; (6) SAVE THIS BEFORE SCALING IT
|
|
SUB BX,OFFSET PAGTAB;(6) BASIFY THE PAGTABLE ENTRY
|
|
CMP BX,SEGEND ;(6) CHECK IF PAGE IS IN 2ND SEGMENT
|
|
POP BX ; (6) RESTORE BX
|
|
JL GTP2B ;(6) NO, FUNCTION AS USUAL
|
|
MOV CURSEG,1 ;(6) YES, SET SEGMENT NUMBER FLAG
|
|
JMP GTP2C ;(6) SKIP SETTING TO ZERO
|
|
GTP2B: MOV CURSEG,0 ;(6) SET SEGMENT NUMBER TO 0
|
|
GTP2C: MOV LPTAB,BX ;SAVE IT
|
|
SUB BX,OFFSET PAGTAB;CALCULATE ADDRESS OF PAGE
|
|
TEST CURSEG,1 ;(6) DO A DIFFERENT CALC FOR SEG1
|
|
JZ GTP2D ;
|
|
SUB BX,SEGEND ; (6) FIGURE OFFSET INTO SEG1
|
|
GTP2D: MOV CL,7
|
|
SHL BX,CL
|
|
TEST CURSEG,1 ; (6) SKIP ADDING IN PAGES IF SEG1
|
|
JNZ GTP4$
|
|
ADD BX,PAGES
|
|
JMP GTP4$ ;AND RETURN PAGE POINTER
|
|
GTP3$: ADD BX,3 ;SKIP REFERENCE TIME
|
|
CMP WORD PTR [BX],-1;END OF TABLE?
|
|
JNE GTP2$ ;NO, CONTINUE SEARCH
|
|
CALL FINDPG ;YES, FIND A PAGE TO LOAD INTO
|
|
PUSH AX ;PAGE POINTER
|
|
MOV LPTAB,BX ;SAVE PAGE TABLE POINTER
|
|
MOV AX,LPAGE ;SAVE NEW BLOCK NUMBE
|
|
MOV [BX],AL
|
|
MOVM [BX+1],RTIME1,CL;AND CURRENT REF TIME
|
|
MOVM [BX+2],RTIME2,CX
|
|
POP BX ;PAGE POINTER
|
|
CALL GETBLK ;GET THE BLOCK
|
|
GTP4$: MOV AX,BX ;RETURN PAGE POINTER
|
|
MOV LPLOC,AX ;AND SAVE IT FOR LATER
|
|
POP BX ;RESTORES
|
|
POP CX
|
|
RET
|
|
GETPAG ENDP
|
|
|
|
;FIND A GOOD PAGE, RETURN PAGE POINTER IN AX & PAGTAB POINTER IN BX
|
|
; SEE COMMENTS UNDER GETPAG
|
|
PUBLIC FINDPG,FNP1$,FNP2$,FNP3$,FNP4$
|
|
FINDPG PROC
|
|
PUSH CX
|
|
MOV BX,OFFSET PAGTAB
|
|
MOV CX,-1 ;FAKE BEST-CASE REFERENCE COUNT
|
|
MOV DX,CX
|
|
INC BX ;SKIP BLOCK NUMBER FOR NOW
|
|
FNP1$: INC BX ;IS THIS REF TIME WORSE THAN CURRENT WORST?
|
|
CMP [BX-1],CL
|
|
JA FNP3$ ;NO
|
|
JB FNP2$ ;YES
|
|
CMP [BX],DX ;MAYBE, COMPARE LOW-ORDER WORDS, WORSE?
|
|
JAE FNP3$ ;NO
|
|
FNP2$: MOV CL,[BX-1] ;YES, SAVE ITS REF COUNT
|
|
MOV DX,[BX]
|
|
MOV AX,BX ;AND LOCATION (+2)
|
|
FNP3$: ADD BX,3 ;SKIP SECOND WORD
|
|
CMP BYTE PTR [BX-1],-1 ;LOOP UNTIL END OF TABLE
|
|
JNE FNP1$
|
|
INC CX ;WAS A PAGE REALLY FOUND?
|
|
JE FNP4$ ;NO, GROSS BUG!
|
|
SUB AX,2 ;YES, CALCULATE CORE LOCATION OF PAGE
|
|
|
|
MOV BX,AX
|
|
SUB AX,OFFSET PAGTAB
|
|
CMP AX,SEGEND ; (6) CHECK SEGMENT
|
|
JL FNP5$ ; (6) IN SEG0, SET CURSEG
|
|
MOV CURSEG,1 ; (6) SET CURSEG TO SEG1
|
|
SUB AX,SEGEND ; (6) SCALE DOWN THE PAGE PTR
|
|
JMP FNP6$
|
|
FNP5$: MOV CURSEG,0
|
|
FNP6$: MOV CL,7
|
|
SHL AX,CL
|
|
TEST CURSEG,1 ; (6) DON'T ADD IN PAGES IF IN SEG1
|
|
JNZ FNP7$
|
|
ADD AX,PAGES
|
|
FNP7$: POP CX ;RESTORES
|
|
RET
|
|
FNP4$: FATAL FTL6
|
|
FINDPG ENDP
|
|
|
|
SUBTTL HIGH LEVEL IBMPC DEPENDENT STUFF
|
|
|
|
;SYSTEM INITIALIZATION
|
|
; SYSINI HAS BEEN GREATLY MODIFIED TO INCLUDE DOS 2.0 FILE HANDLING,
|
|
; COMMAND LINE ARGUMENTS, COPY PROTECTION, AND DYNAMIC ALLOCATION OF
|
|
; PAGING SPACE.
|
|
;
|
|
; THE COPY PROTECTION SCHEME WORKS AS FOLLOWS: A NUMBER OF COMPUTERS ARE
|
|
; DEFINED AS COMPATIBLE WITH IBM IN THE DATA DECLARATIONS. INCLUDED FOR
|
|
; EACH IS THE FIRST 9 LETTERS OF THE COPYRIGHT NOTICE THAT EXISTS IN THE
|
|
; ROM. IF ANY OF THESE STRINGS IS FOUND IN THE ROM, COPY PROTECTION IS
|
|
; CHECKED, OTHERWISE IT IS NOT. IBM COMPATIBILITY MEANS TOTAL ROM BIOS
|
|
; COMPATIBILITY SUCH THAT WINDOWED SCROLLING AND SPECIAL DISK I/O MAY BE
|
|
; PERFORMED. NOT FINDING ANY OF THESE STRINGS RESULTS IN THE ZIP FUNCTIONING
|
|
; AS IF IT WERE ON A GENERIC MS-DOS BASED MACHINE.
|
|
;
|
|
; COMMAND LINE ARGUMENTS SET BITS IN THE VARIABLE CMDLIN IN THE ROUTINE
|
|
; SCANCMD. CMDLIN THEN AFFECTS VARIOUS PARAMETERS AND VARIABLES EITHER IN
|
|
; SYSINI OR SSETUP.
|
|
;
|
|
; THE PAGTAB IS SET UP ACCORDING TO AVAILABLE MEMORY. THERE EXISTS A WORD
|
|
; AT OFFSET 2 IN THE PSP (PROGRAM SEGMENT PREFIX, OR WHERE CS POINTS) WHICH
|
|
; INDICATES THE TOP OF PHYSICAL MEMORY. PAGTAB REPRESENTS THE LAST WORD USED
|
|
; BY THE ZIP. THE CODE SEGMENT REPRESENTS THE AMOUNT OF MEMORY TAKEN UP BY
|
|
; EVERYTHING UNDER THE ZIP SUCH AS THE OPERATING SYSTEM AND DEVICE DRIVERS.
|
|
; IF WE CONVERT PAGTAB TO PARAGRAPHS, THEN ALL OF THESE NUMBERS ARE IN
|
|
; PARAGRAPHS. SO:
|
|
;
|
|
; TOP_OF_MEM - (CS + PAGTAB) --> AVAILABLE MEMORY IN PARAGRAPHS
|
|
;
|
|
; AVAILABLE MEMORY IS CONVERTED INTO THE NUMBER OF BUFFERS AVAILABLE. FROM
|
|
; THIS NUMBER WE MUST SUBTRACT 1 OR 2 BUFFERS TO ALLOW FOR THE PAGTAB TO
|
|
; BE BUILT. KNOWING AVAILABLE BUFFERS TELLS US THE LENGTH OF OUR PAGTAB
|
|
; SINCE OUR PAGTAB IS 4 BYTES/BUFFER. AT THE NEXT PARAGRAPH BOUNDARDY BEYOND
|
|
; THE PAGTAB WE HAVE OUR FIRST GAME SEGMENT WHICH WILL BE MOVED TO ES AND
|
|
; STORED IN THE VARIABLE GAMESEG. ADDING 64K (IN PARAGRAPHS) TO GAMESEG
|
|
; WE ARRIVE AT OUT LOCATION FOR SEG1, THE SECOND GAME SEGMENT. THE PAGTAB
|
|
; IS THEN INITIALIZED.
|
|
;
|
|
PUBLIC SYSINI,SYS1,INITLP,SYSFTL
|
|
SYSINI PROC
|
|
MOV AH,DOSVER ; (7) GET DOS VERSION #
|
|
INT 21H ; (7) MUST BE 2.0 OR HIGHER
|
|
CMP AL,2 ; (7) DOS 2.0+
|
|
JGE GOODOS
|
|
FATAL FTL11 ; (7) DIE APPROPRIATELY
|
|
GOODOS: MOV AH,CURDSK ; (6) GET DEFAULT DRIVE
|
|
INT 21H ; (6) FROM DOS
|
|
MOV DEFDRV,AL ; (6) SAVE DEFAULT DRIVE
|
|
MOV CURDRV,AL ; (6) SAVE DEFAULT DRIVE
|
|
CALL SCANCMD ; (7) GET CMD LINE VARS
|
|
MOV AX,BIOSEG ; (7) GET SEG OF BIOS
|
|
MOV ES,AX ; (7) MAKE ADDRESSIBLE
|
|
MOV BX,COMPATS ; (7) GET NUMBER OF COMPATIBLES
|
|
MOV AX,OFFSET COMP1 ; (7) CHECK FOR COPYRIGHT
|
|
SYS$: MOV DX,9 ; (7) LENGTH FOR MATCHING STRING
|
|
MOV DI,BIOSOFF ; (7) OFFSET INTO BIOS TO CHECK
|
|
MOV CX,7000H ; (7) SEARCH THIS MANY BYTES
|
|
CALL CHK ; (7) LOOK FOR COPYRIGHT NOTICE
|
|
JNC GOTONE ; (7) JMP ON A MATCH
|
|
ADD AX,10 ; (7) ADVANCE TO NEXT STRING
|
|
DEC BX ; (7) DO WE HAVE ANOTHER STRING
|
|
JNZ SYS$ ; (7) YES, LOOK AT IT
|
|
JMP NOCMD ; (7) SKIP COPY PROTECT CHECK
|
|
GOTONE: MOV SCROLL,0 ; (7) USE WINDOWED SCROLLING
|
|
CALL CHKCOP ; (7) CHECK COPY PROTECTION
|
|
JNC NOCMD ; (7) CONTINUE ON
|
|
FATAL FTL10
|
|
NOCMD: MOV AH,CFOPENZ ; (6) ASCIZ STRINGS
|
|
MOV AL,0 ; (6) OPEN FOR READING
|
|
MOV DX,OFFSET GAMFILE
|
|
INT 21H
|
|
JNC SYSA$
|
|
JMP SYSFTL
|
|
SYSA$: MOV GAMHNDL,AX ; (6) SAVE THE FILE HANDLE
|
|
MOV BX,AX ; (7n) GET FILE HANDLE INTO BX
|
|
XOR CX,CX ; (7n) ZERO THESE
|
|
XOR DX,DX ; (7n) TO FIND EOF
|
|
MOV AH,CFSEEK ; (7n) SEEK TO END OF FILE
|
|
MOV AL,2 ; (7n) MOVE FILE PTR TO EOF
|
|
INT 21H ; (7n) DO IT
|
|
MOV CL,4 ; (7n) CONVERT AX TO PARAGRAPHS
|
|
SHR AX,CL ; (7n) TO SAVE AS FILESIZE
|
|
TEST DX,DX ; (7n) DO WE HAVE A 17TH BIT?
|
|
JZ SYSB$ ; (7n) NOPE
|
|
OR AH,10H ; (7n) TURN ON THAT BIT
|
|
SYSB$: MOV CL,5 ; (7n) REDUCE TO NUMBER OF 512 BLKS
|
|
SHR AX,CL ; (7n) FOR COMPARISON TO BUFFERS
|
|
MOV GAMESIZ,AX ; (7n) SAVE THIS SIZE FOR FITS
|
|
|
|
XOR CX,CX ; (7w) MOVE POINTER TO BOF
|
|
MOV DX,4 ; (7w) WE WANT THE WORD AT OFFSET 4
|
|
MOV AH,CFSEEK ; (7w) SEEK THERE
|
|
MOV AL,0 ; (7w) METHOD: OFFSET FROM BOF
|
|
INT 21H ; (7w) BX HAS FILE HANDLE
|
|
MOV AH,CRDRNDZ ; (7w) READ IN THE FIRST
|
|
MOV CX,2 ; (7w) READ THE WORD OF ENDLOD
|
|
MOV DX,OFFSET SSBUF ; (7w) ANY BUFFER BIG ENOUGH WILL DO
|
|
INT 21H ; (7w) READ IT
|
|
MOV AX,SSBUF ; (7w) GET THE WORD
|
|
XCHG AH,AL ; (7w) FLOP THE BYTES
|
|
TEST AX,1FFH ; (7w) ROUND UP TO NEXT BLOCK
|
|
JE SYSC$
|
|
AND AX,0FE00H ; (7w) TURN OF LOW BITS
|
|
ADD AX,200H ; (7w) ADD A BLOCK
|
|
SYSC$: MOV CL,9 ; (7w) CONVERT TO NUMBER OF BLOCKS
|
|
SAR AX,CL
|
|
MOV DX,AX ; (7w) AND SAVE NUMBER IN DX
|
|
|
|
MOV BX,2 ; (6) GET TOP OF MEMORY
|
|
MOV BX,CS:[BX] ; (6) FROM OUT OF THE PSP
|
|
MOV AX,CS ; (6) GET CODE SEG
|
|
SUB BX,AX ; (6) SUB CSEG FROM TOPMEM
|
|
MOV CL,4 ; (6) SHIFT COUNT
|
|
MOV AX,OFFSET PAGTAB ; (6) USE OFFSET TO FIGURE PARAG'S
|
|
SHR AX,CL ; (6) REDUCE THIS OFFSET TO PARAS
|
|
INC AX ; (6) SKIP ONE PARAGRAPH
|
|
AND AX,0FE0H ; (7z) BLOCKIFY THIS NUMBER
|
|
ADD AX,20H ; (7z) OTHERWISE LOSE A PAGE
|
|
SUB BX,AX ; (6) YIELDS PARAS AVAILABLE
|
|
|
|
TEST CMDLIN,4 ; (7) SET ON CMDLIN?
|
|
JZ SYS2
|
|
CMP BX,MEMORY ; (7) REASONABLE REQUEST
|
|
JBE SYS2 ; (7) NO, NOT REALLY THERE
|
|
MOV BX,MEMORY ; (7) USE USER SETTING
|
|
|
|
SYS2: CMP BX,MINMEM ; (7) AT LEAST 48K?
|
|
JAE SYS3 ; (7) YES
|
|
FATAL FTL12 ; (7) DIE APPROPRIATELY
|
|
SYS3: MOV CL,5 ; (6) DIVIDE BY 32 TO GET BUFFERS
|
|
SHR BX,CL ; (6) TO GET #BUFFERS
|
|
SUB BX,DX ; (7w) SUBTRACT ALL PRELOD BLOCKS
|
|
DEC BX ; (6) SUBTRACT 1 BUFFER FOR PAGTBL
|
|
CMP BX,128 ; (6) ABOVE 80H, WE NEED ANOTHER TBL
|
|
JL SYS1 ; (6) WE HAVE THIS MANY OR FEWER
|
|
DEC BX ; (6) TAKE AWAY ANOTHER PAGE
|
|
CMP BX,255 ; (6) THIS IS THE MOST WE WILL NEED
|
|
JLE SYS1 ; (6) DON'T MODIFY BX <= 255
|
|
MOV FITS,1 ; (6) FLAG THAT GAME FITS IN MEMORY
|
|
MOV BX,255 ; (6) DON'T ALLOW MORE THAN THIS
|
|
SYS1: PUSH BX ; (7w) SAVE THIS FOR FIDDLING
|
|
ADD BX,DX ; (7w) ADD IN THE BLOCKS PREV SBTRCTED
|
|
CMP BX,GAMESIZ ; (7n) CHECK FOR LUCKY FIT
|
|
POP BX ; (7w) AND RESTORE ACTUAL #BUFFERS
|
|
JBE SYSD$ ; (7n) IF BX IS GREATER, NO GO
|
|
MOV FITS,1 ; (7n) IT DOES FIT AFTERALL!!!
|
|
SYSD$: MOV BUFFERS,BX ; (6) SAVE THIS NUMBER
|
|
SHL BX,1 ; (6) GET NUMBER OF BYTES IN PAGTBL
|
|
SHL BX,1 ; (6) 4 BYTES WIDE * BX BYTES LONG
|
|
INC BX ; (6) ADD 1 FOR TERMINATOR BYTE
|
|
ADD BX,OFFSET PAGTAB ; (6) CALC TABLE LOCATION
|
|
MOV CX,4 ; (6) REDUCE #BYTES IN TABLE = PARAS
|
|
SHR BX,CL ; (6) TO DYNAMICALLY ALLOCATE SPACE
|
|
MOV AX,DS ; (6) GET A COPY OF CURRENT SEG
|
|
ADD BX,AX ; (6) AND CALCULATE THE NEW SEG
|
|
ADD BX,1 ; (6) ADD ONE PARAGRAPH FOR SAFETY
|
|
MOV GAMESEG,BX ; (6) THIS WILL BE USED FOR ES:GAME
|
|
ADD BX,1000H ; (6) ADD 64K TO CALC 2ND SEG
|
|
MOV SEG1,BX ; (6) THIS IS SEG0+64K
|
|
CALL TBLINI ; (7n) CALL TABLE INITIALIZATION
|
|
CALL SSETUP
|
|
RET
|
|
SYSFTL: FATAL FTL9
|
|
SYSINI ENDP
|
|
|
|
|
|
; THIS ROUTINE INITIALIZES THE PAGE TABLE
|
|
;
|
|
TBLINI PROC
|
|
PUSH SI ; SAVES
|
|
PUSH DI
|
|
PUSH AX
|
|
PUSH BX
|
|
PUSH CX
|
|
MOV DI,OFFSET PAGTAB ; (6) GET BEGINNING ADDR
|
|
MOV CX,WORD PTR BUFFERS ; (6) GET NUMBER OF ENTRIES
|
|
MOV AX,DS ; (7)GET DATA SEG
|
|
MOV ES,AX ; (7) FIX ES
|
|
CLD ;(6) AUTO INCREMENT
|
|
INITLP: MOV SI,OFFSET INITTBL ; (6) POINT TO STRING TO INITIALIZE
|
|
PUSH CX ; (6) SAVE REP COUNT
|
|
MOV CX,4 ; (6) GET INNER LOOP COUNT
|
|
REP MOVSB ; (6) TRANSFER THE STRING TO TBL
|
|
POP CX ; (6) RESTORE COUNT
|
|
LOOP INITLP ; (6) AND FINISH TABLE INITIALIZING
|
|
MOV WORD PTR [DI],-1 ; (6) DEPOSIT A -1 TO INDICATE END
|
|
MOV BX,GAMESEG ;
|
|
MOV ES,BX ; (6) SET THE EXTRA SEG TO GAMESEG
|
|
POP CX ; RESTORES
|
|
POP BX
|
|
POP AX
|
|
POP DI
|
|
POP SI
|
|
RET
|
|
TBLINI ENDP
|
|
|
|
PUBLIC GAMOPEN
|
|
; THIS PROCEDURE OPENS THE GAME FILE AFTER CLOSING ALL FILES.
|
|
; IF THE GAME FILE IS NOT ON THE DISK, IT PROMPTS FOR REINSERTION
|
|
GAMOPEN PROC
|
|
PUSH DX
|
|
MOV DL,DEFDRV ; (7o) GET DRIVE WHERE GAME IS
|
|
MOV AH,CSELDSK ; (7o) TO MAKE OPEN WIN
|
|
INT 21H ; (7o) DO IT
|
|
MOV AH,CFCLOSZ ; (7s) TRY CLOSING INSTEAD OF RESET
|
|
MOV BX,GAMHNDL ; (7s) OF THE GAME FILE
|
|
INT 21H ; (7o) TO MAKE SURE THIS WINS
|
|
GOPEN0: MOV AH,CFOPENZ ; (6) ASCIZ STRINGS
|
|
MOV AL,0 ; (6) OPEN FOR READING
|
|
MOV DX,OFFSET GAMFILE ; (7o) OPEN THE FILE AGAIN
|
|
INT 21H
|
|
JNC GOPEN1 ; (7o) IF SUCCESS, CONTINUE
|
|
PRINT SAV3 ; (7o) OTHERWISE PROMPT
|
|
CALL MCHRI ; (7o) AND WAIT FOR A CHARACTER
|
|
JMP GOPEN0 ; (7o) AND LOOP
|
|
GOPEN1: MOV GAMHNDL,AX ; (7o) SAVE GAME HANDLE
|
|
MOV DL,CURDRV ; (7v) RESTORE SAVE DRIVE
|
|
MOV AH,CSELDSK ; (7v) SO THAT WE ARE NOT CONFUSED
|
|
INT 21H ; (7v) THANKS MAX
|
|
POP DX
|
|
RET
|
|
GAMOPEN ENDP
|
|
|
|
; GIVEN SOURCE PTR IN DS:AX, AND A DEST PTR IN ES:DI, CHK SEARCHES
|
|
; FOR THE STRING POINTED TO BY DS:AX IN THE FIRST (CX) BYTES OF
|
|
; THE STRING POINTED TO BY ES:DI
|
|
PUBLIC CHK
|
|
CHK PROC
|
|
CLD ; (7) CLEAR THE DIRECTION FLAG
|
|
PUSH SI ; (7) SAVE THIS
|
|
PUSH DX ; (7) SAVE THIS FOR RETRIES
|
|
MOV BP,SP ; (7) GET A FRAME POINTER
|
|
MOV SI,AX ; (7) SET UP FIRST OFFSET
|
|
LUP: CMP BYTE PTR [SI],'$' ; (7) END CHAR
|
|
JE MATCH ; (7) REACHING END==MATCH
|
|
CMPSB ; (7) COMPARE TWO BYTES
|
|
JNE RESET ; (7) RESET SOURCE IF MISMATCH
|
|
DEC DX
|
|
LOOP LUP ; (7) DECREMENT COUNTER AND TRY AGAIN
|
|
JMP RTFAIL ; (7) OUT OF CHARS, FAILED
|
|
RESET: MOV SI,AX ; (7) MOVE SOURCE PTR BACK INTO SI
|
|
MOV DX,[BP] ; (7) RESTORE NUMBER OF BYTES IN STR
|
|
LOOP LUP ; (7) TRY AGAIN
|
|
RTFAIL: STC ; (7) FAIL BY RETURNING CARRY SET
|
|
POP DX
|
|
POP SI ; (7) RESTORE SI
|
|
RET
|
|
MATCH: TEST DX,DX ; (7) MATCH OF ENTIRE STRING
|
|
JNZ RTFAIL
|
|
CLC ; (7) GOT A MATCH, RETURN CARRY CLEAR
|
|
POP DX
|
|
POP SI ; (7) RESTORE SI
|
|
RET
|
|
CHK ENDP
|
|
|
|
; THIS ROUTINE CHECKS THE COPY PROTECTION
|
|
CHKCOP PROC
|
|
CLC ; FOR NOW, EVERYTHING WORKS
|
|
RET
|
|
CHKCOP ENDP
|
|
|
|
; THIS ROUTINE SETS SOME VARIABLES ACCORDING TO THE CMD LINE
|
|
; CURRENTLY THE 6 /PARAMETERS ARE SUPPORTED. THE FIRST THREE,
|
|
; /P INITIALIZE PRINTER THROUGH INT 17
|
|
; /M MONOCHROME
|
|
; /C COLOR
|
|
; /W WINDOWED SCROLLING
|
|
; /K<n> AMOUNT OF MEMORY IN K
|
|
; ARE INTENDED FOR THE USER. A FOURTH WILL NOT BE DOCUMENTED IS
|
|
; /G<gamefile.ext> WHICH WILL TEMPORARILY PATCH THE ZIP TO RUN THE
|
|
; GAME SPECIFIED.
|
|
;
|
|
PUBLIC SCANCMD,SCAN,SCAN0,SCAN1,SCAN2,SCAN3,SCAN4
|
|
PUBLIC SCAN5,SCAN6,SCAN7,SCAN8
|
|
SCANCMD PROC
|
|
CLD ; (7) AUTO INCREMENT
|
|
MOV SI,80H ; (7) GET # OF BYTES
|
|
LODSB ; (7) INTO AL
|
|
TEST AL,AL ; (7) ANY?
|
|
JNZ SCAN1
|
|
SCAN0: RET ; (7) NONE THERE
|
|
SCAN1: DEC AL ; (7) CARRIAGE RETURN DOESN'T COUNT
|
|
XOR DX,DX ; (7) ZERO THIS
|
|
MOV DL,AL ; (7) SAVE NUMBER OF BYTES
|
|
ADD DX,82H ; (7) ADDR OF LAST BYTE+1 ON LINE
|
|
INC SI ; (7) SKIP INITIAL SPACE
|
|
SCAN: CMP SI,DX ; (7) END OF CMD LINE?
|
|
LODSB ; (7) GET A DELIMITER
|
|
JZ SCAN0 ; (7) YEP, RETURN
|
|
CMP AL,'/' ; (7) WAS IT THE DELIMITER
|
|
JNZ SCAN ; (7) GET NEXT VALID CHAR
|
|
LODSB ; (7) GOT DELIMITER, GET BYTE
|
|
AND AL,5FH ; (7) UPPERCASIFY
|
|
CMP AL,'M' ; (7) DO THEY WANT MONOCHROME
|
|
JNZ SCAN2 ; (7) NOPE, TRY NEXT
|
|
OR CMDLIN,1 ; (7) SET FLAG IN CMDLIN VARIABLE
|
|
JMP SCAN
|
|
SCAN2: CMP AL,'W' ; (7) WINDOWED SCROLLING?
|
|
JNZ SCAN3
|
|
MOV SCROLL,0 ; (7) TURN ON SCROLLING
|
|
OR CMDLIN,8 ; (7) TURN ON 8 BIT
|
|
JMP SCAN
|
|
SCAN3: CMP AL,'G' ; (7) GAME FILE NAME?
|
|
JNZ SCAN5 ; (7) NOPE, CONTINUE ON...
|
|
MOV DI,OFFSET GAMFILE ; (7) MAKE THIS THE GAME
|
|
SCAN4: MOVSB ; (7) TRANSFER A BYTE
|
|
CMP DX,SI ; (7) THE END?
|
|
JNZ SCAN4
|
|
MOV AL,0 ; (7) DROP IN A NULL
|
|
STOSB ; (7) TO END THE STRING
|
|
RET
|
|
SCAN5: CMP AL,'C' ; (7) DO THEY WANT COLOR
|
|
JNZ SCAN6 ; (7) NOPE, TRY NEXT
|
|
OR CMDLIN,2 ; (7) SET FLAG IN CMDLIN VARIABLE
|
|
JMP SCAN
|
|
SCAN6: CMP AL,'K' ; (7) SET MEMORY SIZE
|
|
JNZ SCAN9 ; (7) NOPE LOOK ONWARD
|
|
MOV BX,0 ; (7) ZERO THIS
|
|
SCAN7: CMP DX,SI ; (7) THE END?
|
|
JNZ SCAN8 ; (7) NOPE
|
|
SCAN7A: OR CMDLIN,4 ; (7) TURN ON MEMORY SET BIT
|
|
MOV CL,6 ; (7w) CONVERT K TO PARAGRAPHS
|
|
SHL BX,CL ; (7) I THINK???
|
|
MOV MEMORY,BX ; (7) SAVE AMOUNT OF K SPECIFIED IN 512 BLKS
|
|
DEC SI ; (7v) BACKUP ONE
|
|
JMP SCAN
|
|
SCAN8: LODSB ; (7) GET FIRST BYTE
|
|
CMP AL,0D ; (7v) CR MEANS END OF STRING
|
|
JZ SCAN7A ; (7v) SO QUIT HERE
|
|
CMP AL,' ' ; (7v) SPACE MEANS NEXT STRING
|
|
JZ SCAN7A ; (7v) SO QUIT
|
|
CMP AL,'/' ; (7v) SLASH MEANS NEXT DELIMITER
|
|
JZ SCAN7A ; (7v) SO QUIT
|
|
XOR AH,AH ; (7) ZERO THIS
|
|
AAA ; (7) SCALE THE NUMBER DOWN
|
|
XCHG AX,BX ; (7) GET NUMBER (BX) INTO AC
|
|
PUSH DX ; (7) SAVE ENDPTR
|
|
MUL RADIX ; (7) MULTIPLY NUMBER BY TEN
|
|
ADD BX,AX ; (7) ADD IN NEW NUMBER
|
|
POP DX ; (7) RESTORE END PTR
|
|
JMP SCAN7
|
|
SCAN9: CMP AL,'P' ; (7w) DO WE NEED TO INITIALIZE THE PRINTER
|
|
JZ SCAN10 ; (7w) YES, DO IT
|
|
JMP SCAN
|
|
SCAN10: PUSH DX ; (7w) SAVE THIS
|
|
MOV DX,0 ; (7w) INITIALIZE FIRST PRINTER
|
|
MOV AH,1 ; (7w) FUNCTION NUMBER FOR INIT
|
|
INT 17H ; (7w) ASSUME IBM PC BECAUSE THEY USED /P
|
|
POP DX ; (7w) RESTORE END POINTER
|
|
JMP SCAN ; (7w) NOW GET BACK TO WORK
|
|
SCANCMD ENDP
|
|
|
|
CLRSCR PROC
|
|
CMP SLFLG,0 ; (7n) ANSI IN PLACE?
|
|
JZ CLR1
|
|
MOV BX,OFFSET CLS
|
|
CMP COLFLG,1 ; (7t) TURN ON COLOR WITH CLEAR SCREEN
|
|
JNZ CLR0
|
|
MOV BX,OFFSET CLSC ; (7t) TURN POINT TO COLOR ANSI CODE
|
|
CLR0: CALL MSPRT
|
|
RET
|
|
CLR1: MOV CL,SLPP ; (7n) GET NUMBER OF LINES
|
|
XOR CH,CH ; (7n) ZERO THE TOP
|
|
CLR2: CALL MCRLF ; (7n) ROLL THE SCREEN IF NO ANSI
|
|
MOV MORLIN,0 ; (7n) RESET TO AVOID MORE
|
|
LOOP CLR2
|
|
RET
|
|
CLRSCR ENDP
|
|
|
|
;GET A GAME FILE BLOCK, BLOCK NUMBER IN AX, CORE LOCATION IN ES:BX
|
|
PUBLIC GETBLK
|
|
GETBLK PROC
|
|
PUSH CX ;SAVE
|
|
MOV CX,1 ;CALL GTBLKS FOR 1 BLOCK ONLY
|
|
CALL GTBLKS
|
|
POP CX ;RESTORE
|
|
RET
|
|
GETBLK ENDP
|
|
|
|
|
|
;GET A SERIES OF GAME FILE BLOCKS,
|
|
;FIRST BLOCK NUMBER IN AX, CORE LOCATION IN ES:BX # OF BLOCKS IN CX
|
|
; GTBLKS UNDERWENT A MAJOR OVERHAUL. IT WAS CHANGED TO SUPPORT 2.0 FILE
|
|
; NAMES AND FILE HANDLES. THE FIRST PASS OF THE OVERHAUL WAS TO SUPPORT
|
|
; FITTING THE WHOLE GAME INTO MEMORY. THIS BASTARDIZATION OF THE ORIGINAL
|
|
; WAS FURTHER CONTORTED WHEN TRYING TO SUPPORT 128K AND LESS MEMORY CONFIG-
|
|
; URATIONS.
|
|
;
|
|
; THE ORIGINAL ARGUMENTS HAVE NOT BEEN LEFT WHOLLY IN TACT. AX IS STILL THE
|
|
; FIRST BLOCK NUMBER AND CX CONTAINS THE NUMBER OF BYTES TO READ IF ALL OF
|
|
; THE GAME IS IN MEMORY OR BLOCKS IF THE GAME DOESN'T ALL FIT. ES:BX NO
|
|
; LONGER HAS THE CORE LOCATION. CALLS TO THIS PROCEDURE MAY STILL PUT THE
|
|
; CORE LOCATION IN BX BUT IT IS IGNORED. CORE LOCATION IS CALCULATED ON THE
|
|
; FLY BASED ON THE ENTRY IN PAGTAB (WHICH IN TURN SETS THE SEGMENT IN WHICH
|
|
; THE READ IS DONE.)
|
|
;
|
|
; THE STARTING BLOCK NUMBER IS USED TO MOVE THE FILE PTR (2.0) FROM THE
|
|
; BEGINNING OF THE FILE TO THE PROPER GAME BLOCK.
|
|
;
|
|
; IN THE CASE OF ALL OF THE GAME IN MEMORY, THE SEGMENT IS CHOSEN BASED ON
|
|
; THE PAGE'S INTENDED BUFFER INDICATED BY THE VARIABLE LPTAB. BUFFER NUMBERS
|
|
; 128 AND ABOVE GO IN TO THE SECOND SEGMENT. THE GAME IS READ IN IN THE
|
|
; BEGINNING IN THREE OR FOUR READS AND THIS ROUTINE IS NOT TOUCHED AGAIN.
|
|
;
|
|
; IN THE CASE OF A SMALL MEMORY SYSTEM, THE SEGMENT TO READ INTO IS CHOSEN
|
|
; BASED ON LPTAB, CURSEG AND SEGEND (SEE GETPAG FOR EXPLANATION).
|
|
;
|
|
PUBLIC GTBLKS,GTBKI$,GTBLP,GETIT,GTBLKB,GTBOUT,GTB2,GTB3
|
|
GTBLKS PROC
|
|
MOV DSKDIR,0 ;READ MODE
|
|
PUSH AX
|
|
MOV AX,GAMHNDL ; (6) GET THIS HANDLE
|
|
MOV HANDLE,AX ; (6) INTO THE GENERAL HANDLE
|
|
POP AX ; (6) AND RESTORE THIS
|
|
GTBKI$: PUSH BP
|
|
PUSH DX
|
|
PUSH BX
|
|
PUSH SI
|
|
GTBLP: MOV DX,CX ; (6) SAVE NUMBER OF BLOCKS
|
|
MOV CX,9 ; (6) MULTIPLY BY 512
|
|
SHL DX,CL ; (6) DO IT
|
|
SHL AX,CL ; (6) CONVERT BLK# TO OFFSET
|
|
MOV CX,0 ; (6) ZERO THIS
|
|
ADC CX,0 ; (6) DID WE CARRY OUT ABOVE
|
|
MOV BX,HANDLE ; (6) GET FILE HANDLE
|
|
MOV SI,DX ; (6) SAVE NUMBER OF BYTES FOR READ
|
|
TEST SEEKF,1 ; (6) SHOULD WE REALLY?
|
|
JZ NOSEEK
|
|
MOV DX,AX ; (6) GET LOW ORDER #BYTES FOR SEEK
|
|
MOV AH,CFSEEK
|
|
MOV AL,0 ; (6) USE OFFSET FROM BEGINNING METHOD
|
|
INT 21H ; (6) SEEK
|
|
NOSEEK: MOV DX,LPTAB ; (6) FIGURE OUT BUFFER NUMBER
|
|
TEST FITS,1 ; (6) DO WE HAVE ALL THE GAME
|
|
JNZ NOFIX ; (6) IF NOT, FIX LPTAB (SCALE IT DOWN)
|
|
CMP DX,0 ; (6) ARE WE JUST STARTING UP
|
|
JZ NOFIX
|
|
SUB DX,OFFSET PAGTAB ; (6) BASIFY THE TABLE NUMBER
|
|
SHR DX,1
|
|
SHR DX,1 ; (6) DIVIDE TABLE ENTRY BY TABLE WIDTH(4)
|
|
MOV CL,9 ; (6) DIVIDE BY 512
|
|
TEST CURSEG,1 ; (6) WHICH SEG ARE WE IN
|
|
JNZ NOFIX ; (6) SKIP PAGE ADDITION
|
|
MOV AX,PAGES ; (6) GET AMOUNT OF PRELOD
|
|
SHR AX,CL ; (6) AND SKIP THAT AMOUNT OF BUFFER SPC
|
|
ADD DX,AX ; (6) ADD THAT INTO BUFFER NUMBER
|
|
NOFIX: MOV CX,SI ; (6) RESTORE #BYTES TO READ
|
|
MOV AH,CRDRNDZ ; (6) READ RANDOM GAME RECORD
|
|
CMP DSKDIR,0 ; (6) ARE WE READING?
|
|
JZ GTREAD
|
|
MOV AH,CWRRNDZ ; (6) NO, DO A WRITE INSTEAD
|
|
GTREAD: TEST FITS,1 ; (6) IS BUFFERING CONTINUOUS
|
|
JNZ GTBLK1$ ; (6) FIGURE BUFFER FROM DX
|
|
TEST CURSEG,1 ; (6) WHAT SEGMENT ARE WE IN
|
|
JZ GETIT ; (6) FUNCTION NORMALLY
|
|
MOV SI,SEGEND ; (6) GET SEGMENT ENDING POINT
|
|
SHR SI,1 ;(6) DIVIDE IT BY WIDTH OF PAGTAB
|
|
SHR SI,1 ; (6) TO USE AS AN INDEX INTO SEG1
|
|
SUB DX,SI ; (6) BASIFY BUFFER NUMBER FOR SEG1
|
|
JMP GTBLK2$ ; (6) USE SEG1 WITH SCALED DX
|
|
GTBLK1$:CMP DX,128
|
|
JL GETIT
|
|
SUB DX,128 ; (6) SUBTRACT TO BASIFY
|
|
GTBLK2$:PUSH DS
|
|
MOV SI,SEG1 ; (6) GET SEG1 INTO DS
|
|
MOV DS,SI ; (6) SET UP DS
|
|
JMP GTBLKB
|
|
GETIT: PUSH DS
|
|
MOV SI,ES
|
|
MOV DS,SI
|
|
GTBLKB: PUSH CX ; (6) SAVE NUMBER OF BLOCKS
|
|
MOV CL,9
|
|
SHL DX,CL ; (6) MAKE A NEW PAGE-PTR
|
|
POP CX ; (6) RESTORE COUNT OF BYTES
|
|
INT 21H ; (6) CALL DOS
|
|
CMP AX,CX ; (6) SET FLAGS
|
|
POP DS
|
|
MOV SEEKF,1 ; (6) RESET SEEK FLAG
|
|
GTBOUT: POP SI
|
|
POP BX
|
|
POP DX
|
|
POP BP
|
|
RET
|
|
GTB2: PUSH AX ; (6) SAVE THIS
|
|
MOV AX,GAMHNDL ; (6) GET HANDLE
|
|
CMP HANDLE,AX ; (6) COMPARE THEM
|
|
JE GTB3
|
|
STC
|
|
JMP GTBOUT
|
|
|
|
GTB3: FATAL FTL7
|
|
GTBLKS ENDP
|
|
|
|
SUBTTL IBMPC SYSTEM ROUTINES
|
|
PAGE +
|
|
|
|
PUBLIC MCHRI,MTTYO,MCRLF,MSOUT,MSPRT,MINIT,MPRNT,MTIME,FINISH
|
|
;READ A CHARACTER INTO AX, WAITING UNTIL ONE IS AVAILABLE, NO ECHO
|
|
|
|
MCHRI PROC
|
|
PUSH CX
|
|
PUSH DX
|
|
CMP CHRFLG,0
|
|
JNZ MCHR1
|
|
MOV CHRFLG,1
|
|
MCHR1: MOV AH,CNOECHO ; (7u) USE NO ECHO
|
|
INT 21H
|
|
SUB AH,AH
|
|
call boss ; check for boss key
|
|
POP DX
|
|
POP CX
|
|
RET
|
|
MCHRI ENDP
|
|
|
|
;PRINT THE CHARACTER IN AL, FOREGROUND IN AH
|
|
MTTYO PROC
|
|
PUSH AX
|
|
PUSH BX ;SAVES
|
|
PUSH CX
|
|
PUSH DX
|
|
PUSH BP
|
|
PUSH AX
|
|
MOV AH,CCONIO
|
|
MOV DL,AL
|
|
INT 21H
|
|
POP AX
|
|
TEST SCRFLG,1 ; (7x) IS SCRIPTING REQUESTED?
|
|
JZ MTYO1 ; (7n) IF NOT THEN DON'T BOTHER
|
|
CMP SCRHLD,1 ; (7n) IS SCRIPTING SUSPENDED?
|
|
JZ MTYO1
|
|
CALL PRTOUT
|
|
MTYO1: POP BP
|
|
POP DX
|
|
POP CX
|
|
POP BX
|
|
POP AX
|
|
RET
|
|
MTTYO ENDP
|
|
|
|
;PRINT A CARRIAGE RETURN/LINE FEED WITH MORE MODE
|
|
MCRLF PROC
|
|
PUSH AX ;SAVES
|
|
PUSH BX
|
|
PUSH CX
|
|
PUSH DX
|
|
PUSH BP
|
|
TEST SCROLL,1 ;(7) WHAT KIND OF SCROLLING
|
|
JNZ MCR$
|
|
TEST SCRNFLG,1 ; (7) ARE WE IN SCREEN #1
|
|
JNZ MCR$ ; (7) YES, USE OLD SCROLL
|
|
MOV AH,SCROLLUP ;(7) USE A VIDEO BIOS SCROLL
|
|
MOV AL,1 ;(7) ONLY 1 LINE
|
|
MOV CX,TOPLIN ;(7) ALWAYS FREEZE TOP LINE
|
|
MOV DH,SLPP ;(7) GET SCREEN LENGTH
|
|
MOV DL,SCPL ;(7) GET THE WIDTH OF THE SCREEN
|
|
DEC DL ; (7v) COORDINATES ARE ZERO BASED
|
|
MOV BH,SCRATR ;(7) GET THE SCREEN ATTRIBUTE
|
|
INT 10H ;(7) CALL THE VIDEO
|
|
MCR$: MOV AH,CCONIO
|
|
MOV DL,13
|
|
INT 21H
|
|
TEST SCRNFLG,1 ; (7) ARE WE WRITING TO WINDOW 1
|
|
JNZ MCRA$
|
|
TEST SCROLL,1 ;(7) NO LINE FEED ON WINDOWED SCROLL
|
|
JZ NOLF
|
|
MCRA$: MOV AH,CCONIO
|
|
MOV DL,10
|
|
INT 21H
|
|
NOLF: TEST SCRNFLG,1 ;(7) NO MORE FOR WINDOW 1
|
|
JNZ MCR1 ;(7) SKIP THIS GARBAGE
|
|
INC MORLIN ;INCREMENT NUMBER OF LINES OUTPUT
|
|
MOV AL,SLPP
|
|
SUB AH,AH
|
|
DEC AX ;(7n) SO THAT STATUS LINE DOESN'T OVERWRITE
|
|
MCRB$: MOV DX,TOPLIN ;(7) GET SCROLLING WINDOW TOPLINE
|
|
XCHG DH,DL ;(7) SCROLL LINE IN DL
|
|
SUB AL,DL ;(7) THIS MANY LINES NOW
|
|
CMP MORLIN,AX
|
|
JL MCR1
|
|
MOV MORLIN,0
|
|
MOV SCRHLD,1 ; (7o) SUSPEND SCRIPT
|
|
PRINT MORE
|
|
CALL MCHRI
|
|
PRINT EMORE
|
|
MOV SCRHLD,0 ; (7o) RESUME SCRIPT
|
|
MCR1: TEST SCRFLG,1 ; (7x) CHANGED TO TEST
|
|
JZ MCR2
|
|
CALL PRTCRL
|
|
MCR2: POP BP
|
|
POP DX
|
|
POP CX
|
|
POP BX
|
|
POP AX
|
|
RET
|
|
MCRLF ENDP
|
|
|
|
;OUTPUT STATUS LINE HERE
|
|
MSOUT PROC
|
|
MOV BX,OFFSET SBLINE
|
|
TEST COLFLG,1 ;(7) ARE WE IN COLOR MODE
|
|
JZ MSOUT1
|
|
MOV BX,OFFSET CBLINE ;(7) USE COLOR THROUGH ANSI
|
|
MSOUT1: CALL MSPRT
|
|
MOV AH,09H
|
|
MOV DX,SLSTR
|
|
INT 21H
|
|
MOV BX,OFFSET SELINE
|
|
TEST COLFLG,1 ;(7) ARE WE IN COLOR MODE
|
|
JZ MSOUT2
|
|
MOV BX,OFFSET CELINE ;(7) USE COLOR THROUGH ANSI
|
|
MSOUT2: CALL MSPRT
|
|
RET
|
|
MSOUT ENDP
|
|
|
|
MSPRT PROC
|
|
MOV CL,BYTE PTR [BX]
|
|
SUB CH,CH
|
|
CMP CL,0
|
|
JE MSPRT1
|
|
MSPLP: INC BX
|
|
MOV DL,BYTE PTR [BX]
|
|
MOV AH,06H
|
|
PUSH BX
|
|
INT 21H
|
|
POP BX
|
|
LOOP MSPLP
|
|
MSPRT1: RET
|
|
MSPRT ENDP
|
|
|
|
MINIT PROC
|
|
CMP SLFLG,0
|
|
JNE MINIT1
|
|
RET
|
|
MINIT1: MOV BX,OFFSET STINIT
|
|
TEST COLFLG,1 ;(7) ARE WE IN COLOR MODE
|
|
JZ MINIT2 ;(7)
|
|
MOV BX,OFFSET CTINIT ;(7)
|
|
MINIT2: CALL MSPRT
|
|
MOV BX,OFFSET SELINE
|
|
TEST COLFLG,1 ;(7) ARE WE IN COLOR MODE
|
|
JZ MINIT3 ;(7)
|
|
MOV BX,OFFSET CELINE ;(7)
|
|
MINIT3: CALL MSPRT
|
|
RET
|
|
MINIT ENDP
|
|
|
|
;PRINT A STRING, POINTER (TO DATA SEGMENT) IN AX, WHITE FOREGROUND
|
|
MPRNT PROC
|
|
CMP GAMEIN,1 ; (7q) DO NOT CHECK THIS UNLESS THE GAME IS IN
|
|
JNZ MPR0
|
|
PUSH AX
|
|
MOV AX,ES:[PFLAGS] ; (7n) SCRIPTING?
|
|
XCHG AH,AL ; (7n) SWAP BYTES
|
|
MOV SCRFLG,AL ; (7n) TURN IT ON, TURN IT ON AGAIN!
|
|
POP AX
|
|
MPR0: PUSH BX ;SAVE BX
|
|
MOV BX,AX ;STRING POINTER
|
|
MPR1: MOV AL,[BX] ;GET NEXT CHARACTER
|
|
CMP AL,0 ;END OF LINE, WITH CRLF?
|
|
JE MPR2 ;YES
|
|
CMP AL,80H ;END OF LINE, NO CRLF?
|
|
JE MPR3 ;YES
|
|
CALL MTTYO ;PRINT CHARACTER
|
|
INC BX ;POINT TO NEXT CHARACTER
|
|
JMP MPR1 ;REPEAT
|
|
MPR2: CALL MCRLF ;PRINT A CRLF
|
|
MPR3: POP BX ;RESTORE BX
|
|
RET
|
|
MPRNT ENDP
|
|
|
|
;GET TIME
|
|
MTIME PROC
|
|
PUSH CX
|
|
PUSH DX
|
|
MOV AH,2CH
|
|
INT 21H
|
|
MOV RSEED1,CX ; HOURS & MINUTES
|
|
MOV RSEED2,DX ; SECONDS & 100THS
|
|
POP DX
|
|
POP CX
|
|
RET
|
|
MTIME ENDP
|
|
|
|
FINISH PROC
|
|
CALL MCRLF
|
|
MOV BX,OFFSET STRESET
|
|
CALL MSPRT
|
|
MOV AH,4CH
|
|
INT 21H
|
|
FINISH ENDP
|
|
|
|
EVEN
|
|
;**********************************************************************
|
|
; DO NOT PLACE ANY VARIABLES OR CODE BEYOND THIS POINT! THE
|
|
; ZIP DYNAMICALLY ALLOCATES A PAGE TABLE AND PAGING SPACE BEYOND
|
|
; THIS LABEL.
|
|
;**********************************************************************
|
|
PUBLIC PAGTAB
|
|
PAGTAB LABEL BYTE
|
|
MSZIP ENDP
|
|
CSEG ENDS
|
|
|
|
END MSZIP
|