Category : A Collection of Games for DOS and Windows
Archive   : EMPIREU.ZIP
Filename : MONITOR.ASM

 
Output of file : MONITOR.ASM contained in archive : EMPIREU.ZIP
TITLE MONITOR
PAGE 44,132
;
; Runs EMPIRE, watches everything EMPIRE has to say, and lets you
; go back and answer the musical question, "How many points does that
; Aircraft Carrier have left?"
; Also tries to keep an idiot without the sense G-d gave my dog
; from staying up until six o'clock in the morning trying to "kill just
; one more ship".
;
; /A -- Allocate; tracing is initialized, allocating its buffer
; so addresses will match what would have happened under /C,
; but tracing is never performed
; /C -- Counts instructions
; /L -- prints logging messages (e.g., nature of patches and
; results of search for reference segment)
; /P -- Patches EMPIRE
;
; When EMPIRE reads keyboard:
;
; Before first read, patches are installed if /P specified;
; tracing begins if /C specified.
; If entered, program enters console mode.
;

PUBLIC CHECK_OPTION
PUBLIC TRUEDOS

DATA SEGMENT PUBLIC

BLANK EQU 32
BS EQU 8
ESC EQU 27

ALLOCATING DB ?

BADERR DB ?
BUF DB ?

COL DW ?
COUNTING DB ? ; PROFILE, or counting instructions, mode
; 0 = not at all
; 1 = supposed to but haven't started
; 2 = started
; 3 = stopped

DBGLRHDR1 DB 'Just finished row '
DBGLRHDR1L EQU $-DBGLRHDR1

DBSPROC LABEL WORD ; table of procedures for each Display
; Byte State
DW DBSPWESC,DBSPWLB,DBSPWROW,DBSPWCOL
DW DBSPSAVE,DBSPWBS,DBSPWRND,DBSPWRESC
DW DBSPWRLB,DBSPWBEE
DBSTATE DW ? ; Display Byte State:
; 0 = waiting for ""
; 1 = got "", expect "["
; 2 = got "[", expect digits or ";"
; 3 = got "[;", expect digits
; or "f"
; 4 = got cursor position, save characters
; 5 = got "[21;78f" or "[B",
; expect ""
; 6 = got "", expect digit of round
; 7 = got digit of round, expect ""
; 8 = got "", expect "["
; 9 = got "[", expect "B"

EMCCLF DB 13,10,'** Can''t create log file',13,10,'$'
EMMCRB DB 13,10,'** Memory corrupted -- try rebooting',13,10,'$'

EOL DB 13,10

LOGHNDL DW ?
LOGNAM DB '@[email protected]',0

OLDRND DW ?

PRGNAM DB 'EMPIRE.EXE',0

PSPFXS DW ? ; Program Segment Prefix segment

RNDMSG DB 'Round # '
RNDMSGL EQU $-RNDMSG

ROUND DW ?
ROW DW ?

SAVLIM EQU 80
SAVBUF DB 3*SAVLIM DUP (?)
SAVCNT DW ?
SAVPT DW ?

SINTSZ EQU 100 ; System Interrupt save table size
SINT DW SINTSZ DUP (?)

TIMCUR DB 8 DUP (?) ; current time-string
TIMDUR LABEL BYTE ; allowed length of play time-string
DB 0,0,0,0,0,45,0,0 ; 45 minutes
;DB 0,0,0,0,1,0,0,0 ; 1 hour
;DB 0,0,0,0,0,1,0,0 ; 1 minute
TIMEND DB 8 DUP (?) ; cut-off time-string
TIMINC LABEL BYTE ; amount in each byte of a time-string
; that is equivalent to 1 in the
; previous byte; i.e., amount by
; which to increment "this" byte if
; borrow 1 from previous byte
DB 255,255,12,31,24,60,60,100
TIMLIM LABEL BYTE ; maximum value of each byte of
; time-string
DB 255,255,12,31,23,59,59,99
TIMOUT DB ? ; time-out flag:
; 0 until time's up
; 1 if want to return 'O' (to cancel
; automove mode)
; 2 if waiting for Orders Mode prompt
; 3 if want to return 'Q' (to quit)
; 4 if want to return 'Y' (to confirm)
; Failure to take varying length months into account means on
; the last day of a short month, I would plan to stop on the next
; day of the same month. At midnight the true time will be the
; first day of the following month, which will be "greater than"
; the target time, so we'll stop just after midnight. For now,
; that's good enough.
; Also, the year won't roll over correctly from 31 December
; 2047 to 1 January 2048. You have been warned.

XQTCL DB 0,13 ; null command line
XQTERR DB 13,10,'Error loading/executing',13,10,'$'
XQTPKT LABEL WORD ; Parameter Block for EXEC function
DW 0 ; default to same environment
DD XQTCL ; command line
DD 5CH ; default FCB
DD 6CH ; default FCB

XQTSP DW ?
XQTSS DW ?

DATA ENDS





CODE SEGMENT PUBLIC

ASSUME CS:CODE
ASSUME DS:DATA
ASSUME SS:STACK

EXTRN CONSOLE_INTERFACE_UNIT : NEAR
EXTRN PATCH : NEAR
EXTRN PROFILE_ALLOCATE_ONLY : NEAR
EXTRN PROFILE_SETUP : NEAR
EXTRN PROFILE_START : NEAR
EXTRN PROFILE_STOP : NEAR

PATCHING DB ?


ACCUMC PROC ; accumulate coordinate
; AX = coordinate so far
; DL = digit
; returns AX = new value of
; coordinate
; changes DBSTATE to 0 if not digit
CMP DL,'0'
JL ACCUMC80
CMP DL,'9'
JG ACCUMC80
PUSH CX
PUSH DX
MOV CH,0
MOV CL,DL
SUB CL,'0'
MOV DX,10
MUL DX
ADD AX,CX
POP DX
POP CX
JMP ACCUMC90
ACCUMC80: ; screwed up, start over
MOV DBSTATE,0
ACCUMC90:
RET
ACCUMC ENDP


ADDTIM PROC ; add two time-strings
; SI = offset to time-string
; DI = offset to 2nd time-string
; (Delta)
; BX = offset to total time-string
PUSH AX
PUSH BX
PUSH CX
PUSH DI
PUSH SI
; add
MOV CX,8
ADDTIM20:
MOV AL,[SI]
ADD AL,[DI]
MOV [BX],AL
INC SI
INC DI
INC BX
LOOP ADDTIM20
; normalize
MOV CX,8
MOV SI,OFFSET TIMLIM+8
MOV DI,OFFSET TIMINC+8
ADDTIM60:
DEC SI
DEC DI
DEC BX
ADDTIM65:
MOV AL,[BX]
CMP AL,[SI]
JBE ADDTIM70
SUB AL,[DI]
MOV [BX],AL
INC BYTE PTR [BX-1]
JMP ADDTIM65
ADDTIM70:
LOOP ADDTIM60
POP SI
POP DI
POP CX
POP BX
POP AX
RET
ADDTIM ENDP


CHECK_OPTION PROC ; Check if option letter (preceded
; by slash) specified on
; command line
; AL = letter
; returns AX = 0 if not found
; 1 if found
; also returns Zero Flag if not found
PUSH CX
PUSH DI
PUSH DS
PUSH ES
; prepare to scan command line
MOV CX,DATA
MOV DS,CX
MOV ES,PSPFXS
MOV DI,80H
MOV CL,ES:[DI]
MOV CH,0
INC DI
; ensure upper case
CALL UPPER
MOV AH,AL
; scan remainder of line for slash
CHECK_OPTION_TRY_AGAIN:
MOV AL,'/'
REPNE SCASB
; if end-of-line, don't care if found
JCXZ CHECK_OPTION_FAILED
; see if specified character follows slash
MOV AL,ES:[DI]
CALL UPPER
CMP AL,AH
JNZ CHECK_OPTION_TRY_AGAIN
; found it
MOV AX,1
JMP CHECK_OPTION_RETURN

CHECK_OPTION_FAILED:
MOV AX,0
CHECK_OPTION_RETURN:
; set Zero Flag appropriately
CMP AX,0
POP ES
POP DS
POP DI
POP CX
RET
CHECK_OPTION ENDP


CKNEWRND PROC ; Check "New" Round number
PUSH AX
MOV AX,ROUND ; see if it's really new
CMP AX,OLDRND
JE CKNEWRND90
MOV OLDRND,AX ; it is
PUSH CX
PUSH DX
MOV CX,RNDMSGL
MOV DX,OFFSET RNDMSG
CALL PUTLOGV
MOV AX,ROUND
CALL PUTLOGN
CALL PUTLOGEOL
POP DX
POP CX
CALL CKTIME ; check elapsed time
CKNEWRND90:
POP AX
RET
CKNEWRND ENDP


CKTIME PROC ; Check elapsed time
PUSH DI
PUSH SI
MOV DI,OFFSET TIMCUR
CALL GETTIM
MOV SI,OFFSET TIMEND
CALL CMPTIM
JA CKTIME90
; time's up
MOV TIMOUT,1
CKTIME90:
POP SI
POP DI
RET
CKTIME ENDP


CLEAR_AND_SHRINK PROC ; Clear memory and Shrink us
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH ES
MOV BX,SEG ENDMEM ; compute our size
SUB BX,PSPFXS
MOV AH,4AH ; reduce us to minimum
MOV ES,PSPFXS
INT 21H
JNC SHRINKOK
MOV DX,OFFSET EMMCRB; failed -- memory must be bad
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
SHRINKOK:
; try to allocate all of memory
MOV AH,48H
MOV BX,0FFFFH
INT 21H
JNC CLEAR_AND_SHRINK_SCARFED_UP
; try again for what's available
MOV AH,48H
INT 21H
JC CLEAR_AND_SHRINK_RELEASED
CLEAR_AND_SHRINK_SCARFED_UP:
; now zero everything to keep it from interfering
; with our efforts to locate a reference
; string in EMPIRE
MOV ES,AX ; segment of beginning of allocated block
PUSH ES
; clear up to 64K at one swell foop
CLEAR_AND_SHRINK_CLEAR_NEXT_HUNK:
MOV DX,1000H ; clear 4K paragraphs
CMP DX,BX ; if there's that much left to clear
JBE CLEAR_AND_SHRINK_HUNK
MOV DX,BX ; else clear what's left
CLEAR_AND_SHRINK_HUNK:
MOV CX,DX ; convert paragraphs to words
SHL CX,1
SHL CX,1
SHL CX,1
MOV AX,0
MOV DI,0
REP STOSW
MOV AX,ES ; update segment
ADD AX,DX
MOV ES,AX
SUB BX,DX ; update remaining paragraph count
JNZ CLEAR_AND_SHRINK_CLEAR_NEXT_HUNK
; now give it all back
POP ES
MOV AH,49H
INT 21H
CLEAR_AND_SHRINK_RELEASED:
POP ES
POP DX
POP CX
POP BX
POP AX
RET
CLEAR_AND_SHRINK ENDP


CLEARRBUF PROC ; Clear Row Buffer
PUSH AX
PUSH CX
PUSH DI
PUSH DX
PUSH ES
MOV DI,OFFSET SAVBUF
MOV AX,SAVLIM ; clear from specified cursor position
MOV DX,ROW
DEC DX
MUL DX
ADD DI,AX
MOV AX,COL
DEC AX
MOV SAVCNT,AX
ADD DI,AX
MOV SAVPT,DI
MOV CX,SAVLIM
SUB CX,AX
MOV AX,DS
MOV ES,AX
MOV AL,BLANK
CLD
REP STOSB
POP ES
POP DX
POP DI
POP CX
POP AX
RET
CLEARRBUF ENDP

CLSLOG PROC ; close log file
PUSH AX
PUSH BX
MOV BX,LOGHNDL
MOV AH,3EH
CALL TRUEDOS
POP BX
POP AX
RET
CLSLOG ENDP


CMPTIM PROC ; compare two time-strings
; SI = offset to 1st time-string
; DI = offset to 2nd time-string
; returns flags pertaining to
; CMP [SI],[DI]
PUSH AX
PUSH CX
PUSH DI
PUSH ES
PUSH SI
MOV AX,DS
MOV ES,AX
MOV CX,8
CLD
REPE CMPSB
POP SI
POP ES
POP DI
POP CX
POP AX
RET
CMPTIM ENDP


CONSOLE PROC ; console interface to MONITOR
PUSH DS
PUSH DX
MOV DX,DATA
MOV DS,DX
; pass log file handle to CIU
MOV BX,LOGHNDL
CALL CONSOLE_INTERFACE_UNIT
; position for further output
CALL POSLOG
POP DX
POP DS
RET
CONSOLE ENDP


DBGDB PROC ; debug display byte
; DL = byte
PUSH AX
CMP DL,27
JNE DBGDB40
MOV AL,13
CALL PUTLOG
MOV AL,10
CALL PUTLOG
DBGDB40:
MOV AL,DL
CALL PUTLOG
POP AX
RET
DBGDB ENDP


DBGLR PROC ; Debug Log Row
PUSH AX
PUSH CX
PUSH DX
MOV CX,DBGLRHDR1L
MOV DX,OFFSET DBGLRHDR1
CALL PUTLOGV
MOV AX,ROW
ADD AL,'0'
CALL PUTLOG
CALL PUTLOGEOL
CALL LOGROW1
CALL LOGROW2
CALL LOGROW3
POP DX
POP CX
POP AX
RET
DBGLR ENDP


DBSPSAVE PROC ; Save characters sent to screen
PUSH AX
PUSH BX
CMP DL,ESC ; until get Escape
JE DBSPSAVE80
MOV AX,SAVCNT ; don't overflow buffer
INC AX
CMP AX,SAVLIM
JG DBSPSAVE90
MOV SAVCNT,AX
MOV BX,SAVPT
MOV [BX],DL
INC SAVPT
JMP DBSPSAVE90
DBSPSAVE80:
MOV DBSTATE,1
CALL LOGSOME
DBSPSAVE90:
POP BX
POP AX
RET
DBSPSAVE ENDP

DBSPWBEE PROC ; Wait for "B" in sequence giving
; Round number
CMP DL,'B'
JNE DBSPWBEE80
; got "B", expect ""
MOV DBSTATE,5
JMP DBSPWBEE90
DBSPWBEE80: ; screwed up, check & start over
CALL CKNEWRND
; we had an "[", so give it a chance
MOV ROW,0
MOV DBSTATE,2
CALL DBSPWROW
DBSPWBEE90:
RET
DBSPWBEE ENDP

DBSPWBS PROC ; Wait for backspace
CMP DL,BS
JNE DBSPWBS80
; got BS, accumulate round
MOV DBSTATE,6
JMP DBSPWBS90
DBSPWBS80: ; screwed up, check round & start over
CALL CKNEWRND
MOV DBSTATE,0
CALL DBSPWESC ; just in case
DBSPWBS90:
RET
DBSPWBS ENDP

DBSPWCOL PROC ; Wait for column coordinate
CMP DL,'f'
JE DBSPWCOL70
CMP DL,'H'
JE DBSPWCOL70
PUSH AX
MOV AX,COL
CALL ACCUMC
MOV COL,AX
POP AX
JMP DBSPWCOL90
DBSPWCOL70: ; got "f" (or "H"), start saving
CMP ROW,1 ; if ROW in 1..3
JL DBSPWCOL80
CMP ROW,3
JG DBSPWCOL80
MOV DBSTATE,4
CALL CLEARRBUF
JMP DBSPWCOL90
DBSPWCOL80: ; if "[21;78f", try to get round
CMP ROW,21
JNE DBSPWCOL85
CMP COL,78
JNE DBSPWCOL85
MOV ROUND,0
MOV DBSTATE,5
JMP DBSPWCOL90
DBSPWCOL85:
MOV DBSTATE,0
DBSPWCOL90:
RET
DBSPWCOL ENDP

DBSPWESC PROC ; Wait for Escape
CMP DL,ESC
JNE DBSPWESC90
MOV DBSTATE,1
DBSPWESC90:
RET
DBSPWESC ENDP

DBSPWLB PROC ; Wait for left bracket
CMP DL,'['
JNE DBSPWLB80
; got "[", accumulate row
; coordinate until get ";"
MOV ROW,0
MOV DBSTATE,2
JMP DBSPWLB90
DBSPWLB80: ; screwed up, start over
MOV DBSTATE,0
DBSPWLB90:
RET
DBSPWLB ENDP

DBSPWRESC PROC ; Wait for Escape in sequence
; giving Round number
CMP DL,ESC
JNE DBSPWRESC80
MOV DBSTATE,8
JMP DBSPWRESC90
DBSPWRESC80: ; that's it, check it and start over
CALL CKNEWRND
MOV DBSTATE,0
DBSPWRESC90:
RET
DBSPWRESC ENDP

DBSPWRLB PROC ; Wait for left bracket in
; sequence giving Round
; number
CMP DL,'['
JNE DBSPWRLB80
; got "[", expect "B"
MOV DBSTATE,9
JMP DBSPWRLB90
DBSPWRLB80: ; screwed up, check & start over
CALL CKNEWRND
MOV DBSTATE,0
DBSPWRLB90:
RET
DBSPWRLB ENDP

DBSPWRND PROC ; Wait for Round number
PUSH AX
MOV AX,ROUND
CALL ACCUMC
CMP DBSTATE,0 ; see if got digit
JZ DBSPWRND60
MOV ROUND,AX
MOV DBSTATE,7 ; start cycle for next digit
JMP DBSPWRND90
DBSPWRND60: ; not digit; see if new round
CALL CKNEWRND
; start all over
MOV DBSTATE,0
CALL DBSPWESC ; just in case
DBSPWRND90:
POP AX
RET
DBSPWRND ENDP

DBSPWROW PROC ; Wait for row coordinate
CMP DL,';'
JE DBSPWROW70
PUSH AX
MOV AX,ROW
CALL ACCUMC
MOV ROW,AX
POP AX
JMP DBSPWROW90
DBSPWROW70: ; got ";", now wait for column
MOV COL,0
MOV DBSTATE,3
DBSPWROW90:
RET
DBSPWROW ENDP





DOSVIA PROC FAR ; DOS-call intercepter
CMP PATCHING,0 ; (first check on patches)
JZ DOSVIA_CKFCN
MOV PATCHING,0 ; don't do it more than once
; (and for goodness' sake don't do it
; recursively)
CALL PATCH
DOSVIA_CKFCN:
CMP AH,2 ; monitor all Fcn 2
JNE DOSVIANOT2

; pay attention to each byte written to the screen

CALL NOTEDB
JMP DOSVIAEXIT

DOSVIANOT2:
CMP AH,7 ; when it's trying to read the keyboard...
JE DOSVIAIS7
JMP DOSVIAEXIT
DOSVIAIS7:
PUSH BP
MOV BP,SP ; point BP to flag word
ADD BP,6
PUSH DS
PUSH AX
MOV AX,DATA
MOV DS,AX
POP AX
; check on PROFILEing
CMP COUNTING,1 ; see if supposed to and haven't
JNZ DOSVIA_CKTIME
CALL PROFILE_START ; BP points to flag word
MOV COUNTING,2 ; don't start it more than once

DOSVIA_CKTIME:
; ...if waiting to return 'O'
CMP TIMOUT,1
JNE DOSVIA_CK3
MOV AL,'O'
JMP DOSVIA_INC_TIMOUT
; ...if waiting to return 'Q'
DOSVIA_CK3:
CMP TIMOUT,3
JNE DOSVIA_CK4
MOV AL,'Q'
JMP DOSVIA_INC_TIMOUT
; ...if waiting to return 'Y'
DOSVIA_CK4:
CMP TIMOUT,4
JNE DOSVIA_REALLY_READ
MOV AL,'Y'
DOSVIA_INC_TIMOUT:
INC TIMOUT
JMP DOSVIA_READ_OR_NOT
DOSVIA_REALLY_READ:
MOV AL,0
DOSVIA_READ_OR_NOT:
POP DS
POP BP
CMP AL,0
JNZ DOSVIA_RETURN
DOSVIA_DO_THE_READ:
; do the read but see what's said
CALL TRUEDOS
CMP AL,ESC ; ESCAPE means he's talking to us
JNZ DOSVIA_RETURN
PUSH BP
MOV BP,SP
ADD BP,6
PUSH DS
PUSH AX
MOV AX,DATA
MOV DS,AX
CMP COUNTING,2 ; but if we started PROFILEing, stop
JNZ DOSVIA_CONSOLE
CALL PROFILE_STOP
MOV COUNTING,3
DOSVIA_CONSOLE:
POP AX
POP DS
POP BP
CALL CONSOLE
; now solicit a response for EMPIRE
MOV AH,7
JMP DOSVIA_DO_THE_READ
DOSVIA_RETURN:
IRET

DOSVIAEXIT:
JMP CS:DOS ; go to true DOS
DOS DD ? ; true address of DOS
DOSVIA ENDP





GETTIM PROC ; get current time
; DI = offset to 8-byte
; time-string buffer
PUSH AX
PUSH CX
PUSH DX
MOV AH,2AH
CALL TRUEDOS
MOV [DI],CH
MOV [DI+1],CL
MOV [DI+2],DH
MOV [DI+3],DL
MOV AH,2CH
CALL TRUEDOS
MOV [DI+4],CH
MOV [DI+5],CL
MOV [DI+6],DH
MOV [DI+7],DL
POP DX
POP CX
POP AX
RET
GETTIM ENDP


INITIM PROC ; initialize elapsed time monitor
PUSH BX
PUSH DI
PUSH SI
MOV DI,OFFSET TIMCUR
CALL GETTIM
MOV SI,OFFSET TIMDUR
MOV BX,OFFSET TIMEND
CALL ADDTIM
MOV TIMOUT,0
POP SI
POP DI
POP BX
RET
INITIM ENDP


LOGROW PROC ; write row to log file
; AX = row number
PUSH AX
PUSH BX
PUSH CX
PUSH DX
DEC AX
MOV CX,SAVLIM
MUL CX
MOV DX,OFFSET SAVBUF
ADD DX,AX
MOV BX,DX ; suppress trailing blanks
ADD BX,CX
LOGROW_LNB:
DEC BX
CMP BYTE PTR [BX],BLANK
JNE LOGROW_GOTLNB
DEC CX
JNZ LOGROW_LNB
JMP LOGROW_EOL
LOGROW_GOTLNB:
CALL PUTLOGV
LOGROW_EOL:
CALL PUTLOGEOL
POP DX
POP CX
POP BX
POP AX
RET
LOGROW ENDP

LOGROW1 PROC ; write row 1 to log file
PUSH AX
MOV AX,1
CALL LOGROW
POP AX
RET
LOGROW1 ENDP

LOGROW2 PROC ; write row 2 to log file
PUSH AX
MOV AX,2
CALL LOGROW
POP AX
RET
LOGROW2 ENDP

LOGROW3 PROC ; write row 3 to log file
PUSH AX
MOV AX,3
CALL LOGROW
POP AX
RET
LOGROW3 ENDP

LOGSOME PROC ; write some messages to log file
PUSH AX
PUSH BX
PUSH DX
; CALL DBGLR
MOV BX,OFFSET SAVBUF
MOV AX,ROW
DEC AX
MOV DX,SAVLIM
MUL DX
ADD BX,AX
CMP ROW,1
JE LOGSOME_ROW1
CMP ROW,2
JE LOGSOME_ROW2
JMP LOGSOME_ROW3
LOGSOME_ROW1:
CMP BYTE PTR [BX],'Y' ; "Your orders?"
JNE LOGSOME_ROW1_CITYCK
CMP BYTE PTR [BX+5],'o'
JNE LOGSOME_ROW1_CITYCK
; if waiting for Orders Mode prompt...
CMP TIMOUT,2
JNE LOGSOME_EXIT
INC TIMOUT ; ...return 'Q' for next read
JMP LOGSOME_EXIT
LOGSOME_ROW1_CITYCK:
CMP BYTE PTR [BX],BLANK ; " City at location: rrcc Pr..."
JNE LOGSOME_EXIT
CMP BYTE PTR [BX+1],'C'
JNE LOGSOME_EXIT
CMP BYTE PTR [BX+40],'H' ; but not if it's a " Huh?"
JE LOGSOME_EXIT
CALL LOGROW1
CALL LOGROW2
JMP LOGSOME_EXIT
LOGSOME_ROW2:

comment |
; to try to get a fix on where he resolves combat...
CMP BYTE PTR [BX],'Y'
JNE END_OF_PATCH
FOUND_IT:
PUBLIC FOUND_IT
INT 3 ; should pop us back to the debugger
END_OF_PATCH:
|

CMP BYTE PTR [BX],'C' ; "City # nn has been subjugat..."
JNE LOGSOME_EXIT
CALL LOGROW1
CALL LOGROW2
JMP LOGSOME_EXIT
LOGSOME_ROW3:
CMP BYTE PTR [BX],'C' ; "City # nn at rrcc has compl..."
; "City at rrcc repelled enemy..."
JE LOGSOME_ROW3_ANY
CMP BYTE PTR [BX],'E' ; "Enemy unit destroyed, Your ..."
JE LOGSOME_ROW3_EY
CMP BYTE PTR [BX],'Y' ; "Your unit destroyed, Enemy ..."
JE LOGSOME_ROW3_EY
CMP BYTE PTR [BX],'T' ; "The scum defending the city..."
JE LOGSOME_ROW3_1AND3
CMP BYTE PTR [BX],'R' ; "Ran out of fuel and crashed."
JE LOGSOME_ROW3_ANY
JMP LOGSOME_EXIT
LOGSOME_ROW3_EY:
CMP SAVBUF+SAVLIM,'Y' ; "Your unit is under attack a..."
JE LOGSOME_ROW3_EY_HE_DID_IT
LOGSOME_ROW3_1AND3:
CALL LOGROW1
JMP LOGSOME_ROW3_ANY
LOGSOME_ROW3_EY_HE_DID_IT:
CALL LOGROW2
LOGSOME_ROW3_ANY:
CALL LOGROW3
LOGSOME_EXIT:
POP DX
POP BX
POP AX
RET
LOGSOME ENDP





MONITOR PROC ; Main Program
MOV AX,DATA ; set data segment
MOV DS,AX
MOV PSPFXS,ES ; save program segment prefix

MOV BADERR,0
MOV DBSTATE,0
MOV OLDRND,0
; see if anything on command line
MOV AL,'A'
CALL CHECK_OPTION
MOV ALLOCATING,AL
MOV AL,'C'
CALL CHECK_OPTION
MOV COUNTING,AL
MOV AL,'P'
CALL CHECK_OPTION
MOV PATCHING,AL

CALL CLEAR_AND_SHRINK

PUSH DS ; save hunk of system interrupt table
MOV AX,DS
MOV ES,AX
MOV DI,OFFSET SINT
MOV CX,SINTSZ
MOV AX,0
MOV DS,AX
MOV SI,AX
CLD
REP MOVSW
POP DS

CMP COUNTING,0 ; if supposed to count instructions...
JZ MONITOR_MAYBE_JUST_ALLOCATE
CALL PROFILE_SETUP ; ...set up for PROFILEing
JMP MONITOR_REPLACE_DOS
MONITOR_MAYBE_JUST_ALLOCATE:
CMP ALLOCATING,0 ; if just allocating buffers...
JZ MONITOR_REPLACE_DOS
CALL PROFILE_ALLOCATE_ONLY ; ...then do that much

MONITOR_REPLACE_DOS:
MOV AH,35H ; get address of DOS handler

MOV AL,21H
INT 21H
MOV WORD PTR DOS,BX
MOV WORD PTR DOS+2,ES

MOV AH,25H ; change INT 21H to come to us
MOV AL,21H
PUSH DS
MOV DX,SEG DOSVIA
MOV DS,DX
MOV DX,OFFSET DOSVIA
INT 21H
POP DS

;MOV AH,1 ; set cursor to half blinking block
;MOV CX,05H
;INT 10H

CALL INITIM ; prepare to monitor elapsed time

CALL OPNLOG ; open log file
CMP BADERR,0
JNZ MONIXIT

CALL XQT ; run EMPIRE

CALL CLSLOG ; close log file

CMP COUNTING,2 ; if started PROFILEing and never stopped
JNZ MONIXIT
PUSHF ; pass flag word
MOV BP,SP
CALL PROFILE_STOP
POPF

; EXIT
MONIXIT:
MOV AX,DATA ; reset data segment since never know
MOV DS,AX ; when being called because of Ctrl-Break
CLI
MOV SI,OFFSET SINT; restore original system interrupt table
MOV CX,SINTSZ
MOV AX,0
MOV ES,AX
MOV DI,AX
CLD
REP MOVSW
STI

MOV AH,4CH ; return to DOS
INT 21H
MONITOR ENDP





NOTEDB PROC ; note displayed byte
; DL = byte
PUSH AX
PUSH BX

PUSH DS
MOV AX,DATA
MOV DS,AX
; CALL DBGDB ; debug: everything to log file
MOV BX,DBSTATE ; branch on Display Byte State
ADD BX,BX
CALL DBSPROC[BX]
POP DS
POP BX
POP AX
RET
NOTEDB ENDP

OPNLOG PROC ; open log file
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV DX,OFFSET LOGNAM ; see if file already exists
MOV AH,3DH
MOV AL,2
CALL TRUEDOS
JC OPNLOG60
MOV LOGHNDL,AX
; position to append
CALL POSLOG
JMP OPNLOG90

public opnlog
OPNLOG60:
MOV DX,OFFSET LOGNAM ; create new log file
MOV CX,0
MOV AH,3CH
CALL TRUEDOS
MOV LOGHNDL,AX
JNC OPNLOG90
MOV DX,OFFSET EMCCLF ; can't create log file
MOV AH,9
CALL TRUEDOS
MOV BADERR,1
OPNLOG90:
POP DX
POP CX
POP BX
POP AX
RET
OPNLOG ENDP

POSLOG PROC ; position log file
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV BX,LOGHNDL ; position to end-of-file - 1
MOV AH,42H
MOV AL,2
MOV CX,0FFFFH
MOV DX,0FFFFH
CALL TRUEDOS
JC POSLOG90
MOV AH,3FH ; read last byte of file
MOV CX,1

MOV DX,OFFSET BUF
CALL TRUEDOS
JC POSLOG90
CMP AX,1 ; see if there was a last byte
JNZ POSLOG70
CMP BUF,26 ; if last byte on file is control-Z...
JNZ POSLOG90
MOV AH,42H ; ...overwrite it
MOV AL,2
MOV CX,0FFFFH
MOV DX,0FFFFH
CALL TRUEDOS
JMP POSLOG90

POSLOG70: ; no last byte -- rewind
MOV AH,42H
MOV AL,0
MOV CX,0
MOV DX,0
CALL TRUEDOS

public POSLOG
POSLOG90:
POP DX
POP CX
POP BX
POP AX
RET
POSLOG ENDP

PUTLOG PROC ; put byte to log file
; AL = byte to put
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV BUF,AL
MOV BX,LOGHNDL
MOV CX,1
MOV DX,OFFSET BUF
MOV AH,40H
CALL TRUEDOS
POP DX
POP CX
POP BX
POP AX
RET
PUTLOG ENDP

PUTLOGEOL PROC ; put end-of-line to log file
PUSH CX
PUSH DX
MOV CX,2
MOV DX,OFFSET EOL
CALL PUTLOGV
POP DX
POP CX
RET
PUTLOGEOL ENDP

PUTLOGN PROC ; put number to log file
; AX = number to put
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV BX,10 ; generate decimal representation
MOV CX,0
PUTLOGN20:
MOV DX,0
DIV BX
PUSH DX
INC CX
CMP AX,0
JNZ PUTLOGN20
PUTLOGN60:
POP AX
ADD AL,'0'
CALL PUTLOG
LOOP PUTLOGN60
POP DX
POP CX
POP BX
POP AX
RET
PUTLOGN ENDP

PUTLOGV PROC ; put string to log file
; CX = number of bytes to put
; DX = offset to string
PUSH AX
PUSH BX
MOV BX,LOGHNDL
MOV AH,40H
CALL TRUEDOS
POP BX
POP AX
RET
PUTLOGV ENDP

TRUEDOS PROC ; call the real DOS
PUSHF ; fake an INT
CALL CS:DOS
RET
TRUEDOS ENDP

UPPER PROC ; ensure upper case
; AL = character
; returns AL = uppercase equivalent
CMP AL,61H
JB UPPER_EXIT
CMP AL,7AH
JA UPPER_EXIT
SUB AL,20H
UPPER_EXIT:
RET
UPPER ENDP

XQT PROC
PUSH AX
PUSH BX
PUSH DX
PUSH ES
; even SS and SP will be destroyed
; we could assume we know what SS is, but why take
; the chance?
MOV XQTSS,SS
MOV XQTSP,SP
; ES:BX points to parameter block
; use the File Control Blocks in our own Program
; Segment Prefix
MOV AX,PSPFXS
MOV XQTPKT+8,AX
MOV XQTPKT+12,AX
MOV BX,SEG XQTPKT
MOV ES,BX
MOV BX,OFFSET XQTPKT
; DS:DX points to file to be loaded
MOV DX,SEG PRGNAM
MOV DS,DX
MOV DX,OFFSET PRGNAM
CLI ; point DOS to spare stack
MOV AX,XSTACK
MOV SS,AX
MOV SP,XSTACKSZ-1
STI
MOV AH,4BH ; load and execute program
MOV AL,0
CALL TRUEDOS
; restore DS, SS, and SP
CLI
MOV BX,DATA
MOV DS,BX
MOV SS,XQTSS
MOV SP,XQTSP
STI
JC XQTERROR
; just for yucks, inquire exit status
MOV AH,4DH
CALL TRUEDOS
CMP AX,0
JZ XQTNOERROR
XQTERROR:
MOV AH,9
MOV DX,OFFSET XQTERR
CALL TRUEDOS
XQTNOERROR:
POP ES
POP DX
POP BX
POP AX
RET
XQT ENDP

CODE ENDS

XSTACK SEGMENT PUBLIC
XSTACKSZ EQU 128
DB XSTACKSZ DUP (?)
XSTACK ENDS

STACK SEGMENT STACK
DB 200H DUP (?)
STACK ENDS

ENDMSEG SEGMENT MEMORY
ENDMEM DB ?
ENDMSEG ENDS

END MONITOR


  3 Responses to “Category : A Collection of Games for DOS and Windows
Archive   : EMPIREU.ZIP
Filename : MONITOR.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/