Files
erkyrath.infocom-zcode-terps/ibm/objops.ezp
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

268 lines
7.9 KiB
Plaintext

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
PTAWRD ES:[BP].PARENT,D ; (A0) PUT OBJ2 INTO OBJ1'S LOC SLOT
GTAWRD D,ES:[BX].CHILD1 ; (A0) GET CONTENTS OBJ2'S FIRST SLOT
PTAWRD ES:[BX].CHILD1,C ; (A0) MAKE OBJ1 FIRST CONTENT OBJ2
CMP DX,0 ;WERE THERE ANY OTHER CONTENTS?
JE OMV1$ ;NO
PTAWRD ES:[BP].SIBLING,D ; YES, CHAIN ONTO OBJ1'S SIBLING SLOT
OMV1$: RET
OPMOVE ENDP
;REMOVE (OBJ FROM ITS PARENT)
OPREMO PROC
MOV DX,AX ; (A0) SAVE OBJ FOR LATER
CALL OBJLOC ;FIND ITS LOCATION
MOV BX,AX ;MOVE TO BASE
GTAWRD C,ES:[BX].PARENT ; (A0) GET ITS PARENT
CMP CX,0 ;DOES IT HAVE A PARENT?
JE ORM3$ ;IF NOT, WE'RE DONE
MOV AX,CX ; (A0) PARENT
CALL OBJLOC ;FIND PARENT'S LOCATION
MOV BP,AX ;MOVE TO BASE
MOV CX,DX ; (A0) MOVE OBJECT TO CX
GTAWRD D,ES:[BP].CHILD1 ; (A0) GET PARENT'S FIRST CONTENT
CMP DX,CX ; (A0) IS IT OBJ?
JNE ORM1$ ;NO
MOVM ES:[BP].CHILD1,ES:[BX].SIBLING,AX ;YES, CHANGE SLOT TO
;OBJ'S SIBLING
JMP ORM2$ ;AND RETURN
ORM1$: MOV AX,DX ; (A0) CURRENT SIBLING
CALL OBJLOC ;FIND ITS LOCATION
MOV BP,AX ;MOVE TO BASE
GTAWRD D,ES:[BP].SIBLING ; (A0) GET NEXT SIBLING IN CHAIN
CMP DX,CX ; (A0) IS IT OBJ?
JNE ORM1$ ;NO, CONTINUE LOOP
MOVM ES:[BP].SIBLING,ES:[BX].SIBLING,AX ; (A0) 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,32 ; (A0) FIND WHICH WORD TO SET FLAG IN
JL OQF0$ ; (A0) NOT IN THE THIRD
SUB BX,32 ; (A0) YES, IT IS
ADD AX,4 ; (A0) SKIP OTHER FLAG WORDS IN OBJECT
JMP OQF1$ ; (A0) AND SET THE FLAG
OQF0$: 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,32 ; (A0) FIND WHICH WORD TO SET FLAG IN
JL OFS0$ ; (A0) NOT IN THE THIRD
SUB BX,32 ; (A0) YES, IT IS
ADD AX,4 ; (A0) SKIP OTHER FLAG WORDS IN OBJECT
JMP OFS1$ ; (A0) AND SET THE FLAG
OFS0$: 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,32 ; (A0) FIND WHICH FLAG WORD WE WANT
JL OFC0$ ; (A0) MAYBE IN SECOND WORD
ADD AX,4 ; (A0) POINT TO THIRD WORD
SUB BX,32 ; (A0) BASIFY FLAG NUMBER
JMP OFC1$ ; (A0) AND CLEAR FLAG
OFC0$: 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
GTAWRD A,ES:[BX].PARENT ; (A0) GET LOC SLOT
JMP PUTVAL ; (A0) RETURN THE WORD 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
GTAWRD A,ES:[BX].CHILD1 ; (A0) GET FIRST SLOT
PUSH AX ;SAVE IT
CALL PUTVAL ; (A0) RETURN THE BYTE VALUE
POP AX ;RESTORE IT
CMP AX,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
GTAWRD A,ES:[BX].SIBLING ; (A0) GET SIBLING SLOT
PUSH AX ;SAVE IT
CALL PUTVAL ; (A0) RETURN THE BYTE VALUE
POP AX ;RESTORE IT
CMP AX,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
XCHG AH,AL ; (A0) FLOP BYTES
CMP ES:[BX].PARENT,AX ; (A0) IS OBJ1'S PARENT OBJ2?
XCHG AH,AL ; (A0) REFLOP BYTES
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
CALL FSTPRP ; (A0) GET FIRST PROPERTY POINTER
JMP OGP2$ ;SKIP NEXT LINE FIRST TIME THROUGH LOOP
OGP1$: CALL NXTPRP ;POINT TO NEXT PROPERTY
OGP2$: MOV AL,ES:[BX] ; (A0) 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] ; (A0) NOW FIND PROPERTY SIZE
INC BX ; (A0) ADVANCE PROP BYTE POINTER
AND AL,3FH ; (A0) MASK OFF LENGTH BITS
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
CALL FSTPRP ; (A0) GET FIRST PROPERTY
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,3FH ; (A0) MASK OFF LENGTH BITS
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
CALL FSTPRP ; (A0) POINT TO FIRST PROPERTY
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
; GIVEN OBJLOC IN AX, RETURN A PTR TO FIRST PROPERTY IN BX
PUBLIC FSTPRP
FSTPRP PROC
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
XOR AH,AH ; (A0) ZERO THE TOP HALF
SHL AX,1 ;CONVERT TO BYTES
ADD BX,AX ;ADJUST POINTER TO SKIP IT
INC BX ; SKIP LENGTH BYTE
RET
FSTPRP ENDP