PAGE * ---------------------------------------------------------------------- * MACHINE-DEPENDENT ROUTINES * ---------------------------------------------------------------------- * MISC SYSTEM INITIALIZATION SYSINI * LEA _curs_interrupt,A0 * SET UP OUR CURSOR TIMER * MOVE.L A0,_curs_addr BSR OPNGAM * OPEN THE GAME FILE, SET UP GAMFIL(A6) BNE.S SYSIX1 * ERROR, ABORT RTS SYSIX1 LEA MSGOPN,A0 * ERROR CODE IN D0 BRA FATAL * 'Story file open error' SECTION ZDATA MSGOPN DC.B 'Story file open error',0 SECTION ZCODE * ALLOCATE SOME MEMORY (NON-RELOCATABLE), NUMBER OF BYTES REQUESTED IN D0.L * RETURN POINTER IN A0 GETMEM MOVEM.L D1-D7/A1-A5,-(SP) MOVE.L D0,-(SP) * BYTES NEEDED JSR _c_getmem ADDQ.W #4,SP * FLUSH STACK TST.L D0 * GOT IT? BEQ.S GETMX1 * NO MOVE.L D0,A0 * YES, RETURN POINTER MOVEM.L (SP)+,D1-D7/A1-A5 RTS GETMX1 CLR.W D0 LEA MSGGTM,A0 BRA FATAL * 'Memory block allocation error' SECTION ZDATA MSGGTM DC.B 'Memory block allocation error',0 SECTION ZCODE * DETERMINE AVAILABLE MEMORY * GIVEN MAX GAME LENGTH + OVERHEAD (BYTES) IN D0.L * RETURN BYTES AVAILABLE IN D0.L MEMSYS EQU 0 * FUDGE FACTOR FOR RUNTIME OVERHEAD MEMAVAIL MOVEM.L D1-D7/A1-A5,-(SP) MOVE.L D0,-(SP) JSR _c_maxmem ADDQ.W #4,SP MOVEM.L (SP)+,D1-D7/A1-A5 * SUB.L #MEMSYS,D0 * (MOVED INTO HIGH-LEVEL INTERFACE) RTS * HERE IF INIT FINDS TOO LITTLE MEMORY FOR PRELOAD MEMERR CLR.W D0 LEA MSGME1,A0 BRA FATAL * 'Not enough available memory' SECTION ZDATA MSGME1 DC.B 'Not enough available memory',0 SECTION ZCODE * PRODUCE A SOUND DOSOUND MOVEM.L D1-D7/A1-A5,-(SP) MOVE.L D2,-(SP) * VOLUME MOVE.L D1,-(SP) * ACTION MOVE.L D0,-(SP) * ID JSR _md_sound ADDA.W #12,SP MOVEM.L (SP)+,D1-D7/A1-A5 RTS * RETURN A RANDOM NUMBER SEED IN D0, DIFFERENT EACH TIME BOOTED GTSEED MOVEM.L D1-D7/A1-A5,-(SP) JSR _random_seed MOVEM.L (SP)+,D1-D7/A1-A5 RTS * RETURN TIME IN 60THS SECOND SINCE SYSTEM STARTUP TIME60 CLR.L D0 *** EZIP ONLY *** RTS * GIVEN AN ASCII CHAR, RETURN ITS UNIT WIDTH (IN CURRENT FONT) CHSIZ MOVEQ #1,D0 *** ALWAYS ONE, FOR NOW RTS * GET THE CURRENT CURSOR POSITION, RETURN ROW/D0, COLUMN/D1 GETCUR MOVEM.L D1-D7/A1-A6,-(SP) JSR _read_cursor_pos * READ THE CONSOLE DEVICE MOVEM.L (SP)+,D1-D7/A1-A6 MOVE.W _cur_row,D0 * RETRIEVE VALUES FROM GLOBALS MOVE.W _cur_column,D1 RTS * SET THE CURRENT CURSOR POSITION, GIVEN ROW/D0, COLUMN/D1 SETCUR MOVE.W D0,_cur_row * FIRST SET THE GLOBALS MOVE.W D1,_cur_column MOVEM.L D1-D7/A1-A6,-(SP) JSR _write_cursor_pos * INFORM THE CONSOLE DEVICE MOVEM.L (SP)+,D1-D7/A1-A6 RTS * RESTART THE SYSTEM (RETURN TO THE DESKTOP) FINISH MOVEQ #0,D0 * LAST-USED SOUND ID MOVEQ #4,D1 * CLEANUP BSR DOSOUND * MAKE SURE IT'S GONE TST.L GAMFIL(A6) * GAME FILE OPEN? BEQ.S FINIX1 * NO BSR CLSGAM * YES, CLOSE THE GAME FILE BEQ.S FINIX1 * OK IF ZERO LEA MSGCLS,A0 * ERROR, INFORM USER BSR OUTMSG * 'Story file close error' SECTION ZDATA MSGCLS DC.B 'Story file close error',0 SECTION ZCODE FINIX1 TST.W INLAST(A6) * HAS THERE BEEN INPUT SINCE LAST OUTPUT? BNE.S FINIX2 * YES, JUST EXIT BSR PUTNEW * NO, MUST FIRST PAUSE FOR A PROMPT LEA MSGKEY,A0 BSR OUTMSG0 * 'Strike any key to exit ' SECTION ZDATA MSGKEY DC.B 'Strike any key to exit ',0 SECTION ZCODE * OUGHT TO FLUSH TYPED-AHEAD KEYS (IF ANY) ... BSR TTYIN * WAIT FOR A KEY FINIX2 UNLK A6 * FLUSH THE ZIP'S STACK FRAME RTS * RETURN FROM WHENCE WE CAME PAGE * ----------------------------------------------- * SCREEN/KEY I/O * ----------------------------------------------- * CALLS TO TTYIN OR INCHR SHOULD BE BRACKETED BY CALLS TO SETUP_INPUT * IT SHOWS/HIDES THE INPUT CURSOR AND DOES OTHER STUFF * D0 = 1 FOR BEGIN, 0 FOR END SETUPI RTS * OUTPUT THE STATUS LINE, STRINGS IN A0-A1, LENGTHS IN D0-D1 STLINE MOVEM.L D2-D7/A2-A5,-(SP) MOVE.L D1,-(SP) * LEN2, STR2 MOVE.L A1,-(SP) MOVE.L D0,-(SP) * LEN1, STR1 MOVE.L A0,-(SP) JSR _show_status ADDA.W #16,SP * FLUSH STACK (14 ACTUAL) MOVEM.L (SP)+,D2-D7/A2-A5 RTS * INPUT A CHAR AND ECHO IT, RETURN CHAR IN D0 * SPECIAL HANDLING FOR BACKSPACE INCHR BSR TTYIN * GET CHAR TST.W VIECHO(A6) * IS ECHOING TURNED OFF? BEQ.S INCHX2 * YES, JUST EXIT CMPI.B #8,D0 * BACKSPACE? BNE.S INCHX1 * NO, ECHO TST.W CHRTOT(A6) * YES, BUT HAS ALL USER INPUT BEEN DELETED? BEQ.S INCHX2 * YES, JUST EXIT INCHX1 MOVE.W D0,-(SP) BSR TTYOUT * ECHO THE CHAR HERE MOVE.W (SP)+,D0 INCHX2 RTS * INPUT A SINGLE CHAR, NO ECHO (NULL MEANS EDIT OPERATION) TTYIN MOVE.W #1,INLAST(A6) * CURRENT I/O IS INPUT MOVE.W #1,LINES(A6) * RESET COUNTER, ALLOWING FOR THIS LINE MOVEM.L D1-D7/A1-A5,-(SP) TTYX1 JSR _char_in ANDI.W #$00FF,D0 * CLEAR UNWANTED BYTE CMPI.B #$0D,D0 * PASS ALONG THE STANDARD CONTROL CHARS BEQ.S TTYX2 CMPI.B #$08,D0 BEQ.S TTYX2 CMPI.B #$20,D0 * FILTER OUT AND IGNORE OTHER CONTROL CHARS BLT TTYX1 CMPI.B #$7F,D0 BGT TTYX1 CMPI.B #$7F,D0 BNE TTYX2 MOVEQ #8,D0 * MAP "DELETE" TO "BACKSPACE" TTYX2 MOVEM.L (SP)+,D1-D7/A1-A5 RTS * OUTPUT THE CHAR (OR CR) IN D0.B (SCROLLING IF NECESSARY) OUTCHR CLR.W INLAST(A6) * CURRENT I/O IS OUTPUT TTYOUT MOVEM.L D1-D7/A1-A5,-(SP) * *** ANDI.W #$00FF,D0 * CLEAR UNWANTED BYTE MOVE.L D0,-(SP) JSR _char_out ADDQ.W #4,SP * FLUSH STACK (2 ACTUAL) MOVEM.L (SP)+,D1-D7/A1-A5 RTS * CHECK FOR END-OF-PAGE CONDITION [COUNTER IS UPDATED ELSEWHERE] NXTLIN MOVE.W _rows,D0 SUB.W _split_row,D0 * LINES AVAILABLE FOR DISPLAY SUBQ.W #1,D0 * ALLOW SPACE FOR [MORE] CMP.W LINES(A6),D0 * PAGE FULL YET? BNE NXTLX2 * NO MOVEM.L D1-D7/A1-A5,-(SP) IFEQ CZIP BSR OPUSL * YES, UPDATE STATUS LINE NOW ENDC JSR _show_more * DISPLAY A PROMPT AND WAIT MOVEM.L (SP)+,D1-D7/A1-A5 MOVE.W #1,LINES(A6) * RESET COUNTER, ALLOWING FOR ONE PREVIOUS LINE NXTLX2 RTS * OUTPUT A STRING, POINTER IN A0, LENGTH IN D0.W PRINT CLR.W INLAST(A6) * CURRENT I/O IS OUTPUT MOVEM.L D1-D7/A1-A5,-(SP) MOVE.L D0,-(SP) * LENGTH IN BYTES MOVE.L A0,-(SP) * POINTER JSR _line_out ADDQ.W #8,SP * FLUSH STACK (6 ACTUAL) MOVEM.L (SP)+,D1-D7/A1-A5 RTS * OUTPUT THE LINE BUFFER, BEGINNING AND END IN A0, D0 * FIRST CHECK FOR END-OF-SCREEN CONDITION (UNLESS IN WINDOW 1) BUFOUT TST.W WIND1(A6) * IN WINDOW 1? BNE BUFUX1 * YES, SKIP THE SCREEN CHECK MOVEM.L D0/A0,-(SP) BSR NXTLIN * PAUSE FOR [MORE] IF NECESSARY MOVEM.L (SP)+,D0/A0 BUFUX1 SUB.L A0,D0 * CURRENT LENGTH OF BUFFER IN D0.W BLE BUFUX2 * EXIT IF ZERO BSR PRINT * OTHERWISE, DISPLAY IT BUFUX2 RTS * OUTPUT THE LINE BUFFER THEN ADD A CR, BEGINNING AND END IN A0, D0 * ALSO UPDATE THE CUMULATIVE LINE COUNTER LINOUT BSR BUFOUT * DISPLAY IT MOVEQ #13,D0 BSR OUTCHR * AND TACK ON A CR TST.W WIND1(A6) * IN WINDOW 1? BNE LINOX1 * YES, IGNORE COUNTER ADDQ.W #1,LINES(A6) * OTHERWISE UPDATE THE COUNTER LINOX1 BRA RESIZE * CHECK LINE LENGTH * CHECK WHETHER DISPLAY WINDOW WAS RESIZED, AND ADJUST FOLDING ACCORDINGLY RESIZE IFEQ CZIP * (ONLY CZIP WINDOWS CHANGE SIZE) MOVEM.L D1-D7/A1-A5,-(SP) JSR _window_resized * GET WINDOW WIDTH MOVEM.L (SP)+,D1-D7/A1-A5 MOVE.L DQUE(A6),A0 MOVE.W D0,BUFSIZ(A0) * NEW WIDTH (CHANGED OR NOT) ENDC RTS * MAKE SURE GAME SCREEN WAS NOT LEFT HIDDEN BY AN SYSTEM ALERT UNHIDE IFEQ EZIP * (ONLY EZIP USES A SECOND SCREEN) MOVEM.L D1-D7/A1-A5,-(SP) JSR _unhide_screen MOVEM.L (SP)+,D1-D7/A1-A5 ENDC RTS PAGE *---------------------------------------------------------------------------- * ZIP MESSAGES *---------------------------------------------------------------------------- * OUTPUT AN ASCIZ MESSAGE, POINTER IN A0 OUTMSG0 MOVEM.L A1-A2,-(SP) MOVE.L A0,A1 * STRING POINTER OUTMX1 CLR.W D0 MOVE.B (A1)+,D0 * GET NEXT CHAR, END OF STRING? BEQ.S OUTMX2 * YES BSR PUTCHR * NO, DISPLAY/QUEUE IT BRA.S OUTMX1 OUTMX2 TST.W VOBUFF(A6) * ARE WE BUFFERING OUTPUT? BEQ.S OUTMX3 * NO BSR PUTLIN1 * YES, EMPTY THE BUFFER OUTMX3 MOVEM.L (SP)+,A1-A2 RTS * OUTPUT AN ASCIZ MESSAGE, POINTER IN A0 (NULL IF NONE) * THEN APPEND A CR OUTMSG MOVE.L A0,D0 * ANY MESSAGE? BEQ.S OUTMX9 * NO, JUST A CR BSR OUTMSG0 * YES, OUTPUT THE STRING OUTMX9 BRA PUTNEW * PRINT A FATAL ERROR HEADER, CODE NUMBER AND MESSAGE (LAST TWO ARE OPTIONALS) * ERROR CODE IN D0, STRING IN A0, ZERO MEANS NONE FATAL MOVE.L A0,-(SP) MOVE.W D0,-(SP) BSR PUTNEW * NEW LINE LEA MSGFTL,A0 * PRINT A STANDARD ERROR HEADER, NO CR BSR OUTMSG0 * 'Internal Error ' SECTION ZDATA MSGFTL DC.B 'Internal Error ',0 SECTION ZCODE MOVE.W (SP)+,D1 * GOT A NUMBER? BEQ.S FATLX1 * NO MOVE.B #'#',D0 * YES, PRINT A PREFIX BSR PUTCHR MOVE.W D1,D0 * PRINT THE ERROR NUMBER BSR OPPRNN FATLX1 BSR PUTNEW MOVE.L (SP)+,D0 * GOT A MESSAGE? BEQ.S FATLX2 * NO MOVE.L D0,A0 * YES, DISPLAY THE STRING BSR OUTMSG FATLX2 BRA FINISH * GO WAIT FOR A FINAL KEY * -------------------------------------------------------------- * SCRIPTING STUFF * -------------------------------------------------------------- * TEST THE SCRIPT BIT, UPDATE THE SCRIPTING DEVICE AS NEEDED * RETURN WITH FLAGS (NON-ZERO IF ACTIVE) TSTSCR MOVE.L BUFFER(A6),A0 MOVE.B PFLAGS+1(A0),D0 ANDI.W #1,D0 * MASK OFF SCRIPT BIT BNE.S TSCRX1 * 1 MEANS SCRIPT REQUESTED BSR.S SCROPN * 0 MEANS OFF, DEACTIVATE THE SCRIPTING DEVICE BRA.S TSCRX2 * RETURN (FLAGS CAN ONLY BE ZERO ...) TSCRX1 BSR SCROPN * ACTIVATE THE SCRIPTING DEVICE BNE.S TSCRX2 * OK, ACTIVE BSR SCRERR * INACTIVE, MEANS ERROR OCCURRED, UNDO ALL CLR.W D0 * CLEAR FLAGS TSCRX2 RTS * RETURN WITH FLAGS * TEST STATUS OF SCRIPTING DEVICE, RETURN FLAGS (ZERO IF NOT READY) SCRCHK * *** MOVEM.L D1-D7/A1-A5,-(SP) * *** * -1 MEANS PRINTER READY, 0 UNAVAILABLE * *** MOVEM.L (SP)+,D1-D7/A1-A5 RTS * OPEN/CLOSE SCRIPTING DEVICE (D0.W SET FOR OPEN) * RETURN ACTIVE/INACTIVE STATUS (D0.W SET FOR ACTIVE) SCROPN MOVEM.L D1-D7/A1-A5,-(SP) EXT.L D0 * 1 FOR OPEN, ZERO FOR CLOSE MOVE.L D0,-(SP) JSR _script_open ADDQ.W #4,SP TST.W D0 * RETURN ACTIVE/INACTIVE MOVEM.L (SP)+,D1-D7/A1-A5 RTS * SCRIPT ERROR HANDLER * WANT TO TERMINATE SCRIPTING ATTEMPTS (UNTIL NEXT SCRIPT COMMAND) * DE-ACTIVATE PRINTER, ADJUST ZIP INTERNAL VARIABLES SCRERR MOVEM.L D1-D7/A1-A5,-(SP) CLR.W D0 * ZERO FOR CLOSE BSR SCROPN * DEACTIVATE THE DEVICE MOVE.L BUFFER(A6),A0 BCLR #0,PFLAGS+1(A0) * FORCE SCRIPT BIT OFF (ZIP + EZIP) IFEQ EZIP CLR.W VOPRNT(A6) * TURN OFF EZIP'S FLAG ENDC LEA MSGPRR,A0 BSR OUTMSG BSR PUTNEW SECTION ZDATA MSGPRR DC.B '*** Printer not ready, scripting terminated ***',0 SECTION ZCODE MOVEM.L (SP)+,D1-D7/A1-A5 RTS * SCRIPT OUT A LINE, START IN A0, END IN D0, THEN TACK ON A CR/LF SCROUT MOVEM.L D1-D7/A1-A5,-(SP) SUB.L A0,D0 * LENGTH OF STRING MOVE.L D0,-(SP) MOVE.L A0,-(SP) JSR _script_line ADDQ.W #8,SP * FLUSH STACK (6 ACTUAL) TST.W D0 * ERROR? BEQ.S SCOTX1 * NO BSR SCRERR * YES, CLEAN UP AND DEACTIVATE SCOTX1 MOVEM.L (SP)+,D1-D7/A1-A5 RTS * -------------------------------------------------------------- * *** PURE HACKERY *** * -------------------------------------------------------------- * THE FOLLOWING ROUTINES EXIST TO ALLOW MACINTOSH USERS TO RESTORE A SAVED GAME * FROM THE DESKTOP (FINDER) LEVEL, SKIPPING THE NORMAL GAME OPENING. THESE * ROUTINES WILL FUNCTION AT MOST ONE TIME, AS THE GAME BOOTS. * RESTORE A SAVE FILE CHOSEN FROM THE FINDER BOOTSV RTS * FORCE A DISPLAY OF THE VERSION INFORMATION (IGNORE IF SHOWVE IS NULL) * RETURN THE "VERSION" STRING IN D0 (ONE CHAR AT A TIME), CR WHEN DONE * THE STRING IS RETURNED THRU INCHR AND PRETENDS TO BE KEYBOARD INPUT SHOWTX RTS * RETURN WITH FLAGS SET CORRECTLY * DELETE CHARS (THE PROMPT ">") FROM THE OUTPUT BUFFER, IF NECESSARY * THIS IS CALLED JUST BEFORE FAKING THE "VERSION" COMMAND DELPRO RTS PAGE * --------------------------------------------------------------------------- * DISK I/O ROUTINES * --------------------------------------------------------------------------- * GENERAL CONVENTION FOR DISK ROUTINE RESULTS: * IF ROUTINE SUCCEEDS, RETURN WITH FLAGS INDICATING "ZERO" * OTHERWISE, CALLER TRAPS ERRORS WITH A CONDITIONAL BRANCH ("BNE.S ERROR") * OPEN THE GAME FILE, STORE REFNUM, RETURN FLAGS * (THIS ROUTINE CALLED DURING INIT *AND* DURING SAVE/RESTORE) OPNGAM MOVEM.L D1-D7/A1-A5,-(SP) JSR _open_game * OPEN THE GAME FILE TST.L D0 BNE OPNGX1 * ERROR * SUCCESS, SAVE THE GAME FILE REFERENCE NUMBER MOVE.L _temp_channel,GAMFIL(A6) CLR.L D0 * RETURN ZERO FLAG FOR OKAY OPNGX1 MOVEM.L (SP)+,D1-D7/A1-A5 RTS * CLOSE THE GAME FILE, RETURN FLAGS CLSGAM MOVEM.L D1-D7/A1-A5,-(SP) MOVE.L GAMFIL(A6),-(SP) JSR _close_game * CLOSE THE GAME FILE ADDQ.W #4,SP * FLUSH STACK (2 ACTUAL) CLR.L GAMFIL(A6) * ALWAYS ZERO WHEN FILE NOT OPEN TST.L D0 * RETURN THE RESULT CODE MOVEM.L (SP)+,D1-D7/A1-A5 RTS * GET A GAME FILE BLOCK, BLOCK NUMBER IN D0, CORE TARGET LOCATION IN A0 GETBLK MOVEM.L D1,-(SP) MOVEQ #1,D1 * ONE BLOCK BSR GTBLKS MOVEM.L (SP)+,D1 * (MOVEM DOES NOT ALTER FLAGS) RTS * GET A SERIES OF GAME FILE BLOCKS * FIRST BLOCK NUMBER IN D0, CORE TARGET LOCATION IN A0, NUMBER OF BLOCKS IN D1 GTBLKS MOVEM.L D2-D7/A1-A5,-(SP) BSR BLKBYT * CONVERT BLOCKS TO BYTES EXG D1,D0 BSR BLKBYT EXG D1,D0 MOVE.L A0,-(SP) * BUFFER POINTER MOVE.L D1,-(SP) * LENGTH IN BYTES MOVE.L D0,-(SP) * OFFSET IN BYTES MOVE.L GAMFIL(A6),-(SP) JSR _read_file ADDA.W #16,SP * FLUSH STACK (14 ACTUAL) TST.L D0 * ERROR ON READ? BNE.S GTBKX2 * YES, FAIL GTBKX1 MOVEM.L (SP)+,D2-D7/A1-A5 RTS * TST.W DSKERR(A6) * BUT WERE WE ASKED TO RETURN WITH FLAGS? * BNE.S GTBKX1 * YES GTBKX2 LEA MSGREA,A0 * ERROR CODE IN D0 BRA FATAL * 'Game file read error' SECTION ZDATA MSGREA DC.B 'Story file read error',0 SECTION ZCODE PAGE * -------------------------------------------------------------------------- * SAVE FILE DISK I/O ROUTINES * -------------------------------------------------------------------------- * PRELIMINARY DIALOG FOR SAVE/RESTORE * PROMPT USER TO SWAP DISKS AND IDENTIFY DRIVE BEING USED * RETURN LETTER IN D0, ZERO FOR DEFAULT DKSWAP MOVE.W D1,-(SP) CLR.W D1 * DRIVE SELECTED, ASSUME DEFAULT LEA MSGDKS,A0 BSR OUTMSG0 * PROMPT, DON'T ADD A CR SECTION ZDATA MSGDKS DC.B 'Insert your SAVE disk in any drive,' DC.B ' then enter the letter of the drive: ',0 SECTION ZCODE DKSX1 BSR TTYIN * GET A CHAR CMPI.B #13,D0 * USE THE DEFAULT? BEQ.S DKSX3 * YES CMPI.B #$60,D0 * UPPERCASE? BLT DKSX2 * YES SUBI.B #$20,D0 * NO, MAKE IT UPPERCASE DKSX2 CMPI.B #'A',D0 * VALID DRIVE LETTER? BLT DKSX1 * NO CMPI.B #'Z',D0 BGT DKSX1 * NO MOVE.W D0,D1 * YES, SAVE IT AND ECHO IT BSR PUTCHR DKSX3 BSR PUTNEW * FOLLOW WITH A CR MOVE.W D1,D0 * RETURN THE DRIVE LETTER MOVE.W (SP)+,D1 RTS * DUPLICATE FILE NAME DIALOG (SAVE ONLY) * CHECK FOR FILENAME CONFLICT, IF SO, PROMPT USER FOR INSTRUCTIONS * RETURN NON-ZERO TO ABORT DUPNAM MOVEM.L D1-D7/A1-A5,-(SP) JSR _exist_file TST.L D0 * DOES THE FILE ALREADY EXIST? BEQ DUPX3 * NO, PROCEED NORMALLY * DUPLICATE NAME DETECTED, PROMPT USER FOR INSTRUCTIONS LEA MSGDUP,A0 BSR OUTMSG0 * PROMPT, NO CR BSR PUTLIN * *** RESET THE BUFFERING COUNTER *** SECTION ZDATA MSGDUP DC.B 'You are about to write over an existing file. ' DC.B 'Proceed? (Y/N) >',0 YNBUFF DC.B 0,0,0,0 * RESPONSE GOES HERE SECTION ZCODE LEA YNBUFF,A0 MOVEQ #3,D0 * THREE CHAR LIMIT MOVEQ #1,D1 * REQUEST LOWER-CASE CONVERSIONS BSR RDLINE * COLLECT A RESPONSE LEA YNBUFF,A0 MOVE.W D0,D1 * COUNT OF ACTUAL CHARS CLR.W D0 * ASSUME A POSITIVE RESPONSE DUPX1 SUBQ.W #1,D1 * ANY CHARS LEFT TO CHECK? BLT.S DUPX2 * NO, RETURN A NEGATIVE RESPONSE CMPI.B #'y',(A0) * POSITIVE RESPONSE? BEQ.S DUPX3 * YES (IGNORE ANY FOLLOWING CHARS) CMPI.B #' ',(A0)+ * OTHERWISE, LOOK AT NEXT CHAR? BEQ.S DUPX1 * (ONLY IF THIS ONE WAS A BLANK) DUPX2 MOVEQ #1,D0 * ANYTHING ELSE MEANS NEGATIVE DUPX3 TST.W D0 * RETURN FLAGS FOR RESULT MOVEM.L (SP)+,D1-D7/A1-A5 RTS * GET A FILE NAME UNDER WHICH TO SAVE A GAME, LEAVE NAME IN GLOBAL * RETURN WITH FLAGS SET, ZERO IF NO ERROR GETSFL MOVEM.L D1-D7/A1-A5,-(SP) * BSR DKSWAP * PROMPT FOR ID OF SAVE DISK * MOVE.W D0,-(SP) CLR.L -(SP) * *** ALWAYS USE DEFAULT SAVE DISK *** MOVEQ #1,D0 MOVE.L D0,-(SP) * SAVE, NOT RESTORE JSR _file_select ADDQ.W #8,SP * FLUSH STACK (4 ACTUAL) TST.W D0 * NON-ZERO IF CANCEL OR ERROR BNE.S GTSFX1 BSR DUPNAM * CHECK IF GIVEN FILENAME ALREADY EXISTS TST.W D0 * NON-ZERO IF DUPLICATE GTSFX1 MOVEM.L (SP)+,D1-D7/A1-A5 RTS * CREATE (IF NECESSARY) AND OPEN A SAVE FILE, USING GLOBAL FILENAME * RETURN WITH FLAGS SET, ZERO IF NO ERROR NEWSFL MOVEM.L D1-D7/A1-A5,-(SP) JSR _create_file TST.L D0 BNE NEWSX1 * NON-ZERO MEANS ERROR * SUCCESS, SAVE THE REFERENCE NUMBER MOVE.L _temp_channel,SAVFIL(A6) CLR.L D0 * RETURN ZERO FOR OK BRA.S NEWSX2 * CMPI.W #-44,D0 * ERROR, DISK IS WRITE-PROTECTED? (SAY SO) * CMPI.W #-48,D0 * ERROR, NAME EXISTS ALREADY? (IGNORE) NEWSX1 MOVE.L D0,-(SP) BSR WPRCHK * IF WRITE-PROTECT ERROR, INFORM USER MOVE.L (SP)+,D0 * RETURN WITH FLAGS NEWSX2 MOVEM.L (SP)+,D1-D7/A1-A5 RTS * WRITE A SERIES OF SAVE FILE BLOCKS, * FIRST BLOCK OFFSET IN D0, NUMBER OF BLOCKS IN D1, CORE LOCATION IN A0, * FILE REF NUMBER IN SAVFIL(A6) * RETURN WITH FLAGS SET, ZERO IF NO ERROR PTSBKS MOVEM.L D2-D7/A1-A5,-(SP) BSR BLKBYT * CONVERT BLOCKS TO BYTES EXG D1,D0 BSR BLKBYT EXG D1,D0 MOVE.L A0,-(SP) * BUFFER POINTER MOVE.L D1,-(SP) * LENGTH IN BYTES MOVE.L D0,-(SP) * OFFSET IN BYTES MOVE.L SAVFIL(A6),-(SP) JSR _write_file ADDA.W #16,SP * FLUSH STACK MOVE.L D0,-(SP) * ERROR? BEQ.S PTSBX2 * NO CMPI.W #999,D0 * DISK FULL ERROR? BEQ.S PTSBX1 * YES BSR WPRCHK * IF WRITE-PROTECT ERROR, INFORM USER BRA.S PTSBX2 PTSBX1 LEA MSGFUL,A0 BSR OUTMSG * 'Not enough room on disk' SECTION ZDATA MSGFUL DC.B 'Not enough room on disk',0 SECTION ZCODE PTSBX2 MOVE.L (SP)+,D0 * RETURN FLAGS MOVEM.L (SP)+,D2-D7/A1-A5 RTS * CHECK FOR DISK WRITE-PROTECT ERROR (DURING FILE CREATE AND/OR WRITE) WPRCHK * CMPI.W #-13,D0 * ERROR BECAUSE DISK IS WRITE-PROTECTED? * BNE.S WPRCX1 * NO * LEA MSGWPR,A0 * YES, INFORM USER * BSR OUTMSG * 'Disk is write-protected' WPRCX1 RTS SECTION ZDATA MSGWPR DC.B 'Disk is write-protected',0 SECTION ZCODE * CLOSE A SAVE FILE, CHANNEL IN SAVFIL(A6) * RETURN WITH FLAGS SET, ZERO IF NO ERROR CLSSFL MOVEM.L D1-D7/A1-A5,-(SP) MOVE.L SAVFIL(A6),-(SP) JSR _close_file ADDQ.W #4,SP * FLUSH STACK (2 ACTUAL) TST.L D0 * NON-ZERO IF ERROR MOVEM.L (SP)+,D1-D7/A1-A5 RTS * DELETE A BAD SAVE FILE, MUST HAVE BEEN ALREADY CLOSED (OR NOT OPENED) * RETURN WITH FLAGS SET, ZERO IF NO ERROR DELSFL MOVEM.L D1-D7/A1-A5,-(SP) JSR _delete_file TST.L D0 * NON-ZERO IF ERROR MOVEM.L (SP)+,D1-D7/A1-A5 RTS * ---------------------------------------------------------------------------- * *** RESTORE FILE ROUTINES *** * ---------------------------------------------------------------------------- * GET A FILE NAME FROM WHICH TO RESTORE AN OLD SAVE FILE, LEAVE NAME IN GLOBAL * RETURN WITH FLAGS SET, ZERO IF NO ERROR GETRFL MOVEM.L D1-D7/A1-A5,-(SP) * BSR DKSWAP * PROMPT FOR LETTER OF SAVE DRIVE * MOVE.W D0,-(SP) CLR.L -(SP) * *** ALWAYS USE DEFAULT *** CLR.L -(SP) * RESTORE, NOT SAVE JSR _file_select ADDQ.W #8,SP * FLUSH STACK (4 ACTUAL) TST.W D0 * NON-ZERO IF CANCEL OR ERROR MOVEM.L (SP)+,D1-D7/A1-A5 RTS * OPEN AN OLD SAVE FILE, USING GLOBAL FILENAME, LEAVE CHANNEL IN SAVFIL(A6) * RETURN WITH FLAGS SET, ZERO IF NO ERROR OPNSFL MOVEM.L D1-D7/A1-A5,-(SP) JSR _open_file TST.L D0 BNE OPNSX1 * NON-ZERO MEANS ERROR MOVE.L _temp_channel,SAVFIL(A6) CLR.L D0 * OK, RETURN ZERO FLAGS BRA.S OPNSX2 OPNSX1 LEA MSGOSF,A0 * FAILED, INFORM USER BSR OUTMSG SECTION ZDATA MSGOSF DC.B 'Couldn' DC.B $27 DC.B 't locate save file',0 SECTION ZCODE MOVEQ #1,D0 * SET FLAGS FOR ERROR OPNSX2 MOVEM.L (SP)+,D1-D7/A1-A5 RTS * GET A SERIES OF SAVE FILE BLOCKS * FIRST BLOCK NUMBER IN D0, # OF BLOCKS IN D1, CORE TARGET LOCATION IN A0 * RETURN WITH FLAGS SET, ZERO IF NO ERROR GTSBKS MOVEM.L D2-D7/A1-A5,-(SP) BSR BLKBYT * CONVERT BLOCKS TO BYTES EXG D1,D0 BSR BLKBYT EXG D1,D0 MOVE.L A0,-(SP) * BUFFER POINTER MOVE.L D1,-(SP) * LENGTH IN BYTES MOVE.L D0,-(SP) * OFFSET IN BYTES MOVE.L SAVFIL(A6),-(SP) JSR _read_file ADDA.W #16,SP * FLUSH STACK TST.L D0 * ZERO MEANS NO ERROR MOVEM.L (SP)+,D2-D7/A1-A5 RTS DEFOLD CLR.W D0 * RETRIEVE PREVIOUS DEFAULT NAMES BRA.S DEFNX1 DEFNEW MOVEQ #1,D0 * UPDATE PREVIOUS DEFAULT NAMES DEFNX1 MOVEM.L D1-D7/A1-A5,-(SP) MOVE.L D0,-(SP) JSR _new_default * COPY TWO FILE-RELATED STRINGS ADDQ.W #4,SP * FLUSH STACK (2 ACTUAL) MOVEM.L (SP)+,D1-D7/A1-A5 RTS * ASSOCIATE AN ICON WITH A NEWLY-CREATED SAVE FILE MAKEICON MOVEM.L D1-D7/A1-A5,-(SP) JSR _make_icon_file TST.W D0 * IF NON-ZERO, SHOW ERROR MSG BEQ.S MAKIX1 LEA MSGMKI,A0 * (NON-FATAL, SAVE IS STILL GOOD) BSR OUTMSG SECTION ZDATA MSGMKI DC.B '*** Couldn' DC.B $27 DC.B 't create icon file ***',0 SECTION ZCODE MAKIX1 MOVEM.L (SP)+,D1-D7/A1-A5 RTS * CHECK FOR GAME DISK IN DEFAULT DRIVE BEFORE/AFTER SAVE/RESTORE * CLOSE GAME FILE BEFORE, RE-OPEN IT AFTER CHKDSK RTS *** NOT NEEDED UNDER AMIGADOS *** MOVEM.L D1/A1,-(SP) MOVE.W D0,D1 * ZERO MEANS BEFORE CHKDX1 TST.W D1 * STARTING THE SAVE/RESTORE? BNE.S CHKDX2 * NO, ENDING BSR CLSGAM BEQ.S CHKDX4 * OK, FILE CLOSED, PROCEED BRA.S CHKDX3 * ERROR CHKDX2 BSR OPNGAM BEQ.S CHKDX4 * OK IF IT OPENS, CARRY ON CHKDX3 LEA MSGNOD,A0 * FAILED, ASK FOR GAME DISK BSR OUTMSG0 * PROMPT (DON'T ADD A CR) SECTION ZDATA MSGNOD DC.B 'Insert the story disk and strike any key to continue ',0 SECTION ZCODE BSR TTYIN * WAIT FOR A KEY BSR PUTNEW * GO TO NEXT LINE BRA.S CHKDX1 * TRY AGAIN CHKDX4 MOVEM.L (SP)+,D1/A1 RTS * MAXIMUM FILE NAME LENGTH (ACTUALLY ~30, MUST ALLOW FOR ".Info" ICON FILE) FNAMELEN EQU 25 * ALTERNATE FILE-SELECTION ROUTINE (AMIGA -- IGNORES THE STACK PARAMETERS) _file_select MOVEM.L D1-D7/A1-A5,-(SP) LEA MSGIN1,A0 * PROMPT FOR A FILENAME BSR OUTMSG LEA MSGIN2,A0 BSR OUTMSG0 LEA _saveback,A0 * ALREADY ASCIZ BSR OUTMSG0 LEA MSGIN3,A0 BSR OUTMSG0 * problem: buffer is not flushed here ... BSR PUTLIN SECTION ZDATA MSGIN1 DC.B 'Insert your save disk then enter a file name.',0 MSGIN2 DC.B '(Default is "',0 MSGIN3 DC.B '") >',0 SECTION ZCODE LEA _savename,A0 MOVEQ #FNAMELEN,D0 * MAX LENGTH OF NAME (BUFFER LENGTH 64) CLR.W D1 * NO LOWER-CASE CONVERSIONS THIS TIME BSR RDLINE * COLLECT A RESPONSE TST.W D0 * LENGTH OF INPUT BEQ.S FSELX1 * ZERO, MEANS USE DEFAULT LEA _savename,A0 CLR.B 0(A0,D0.W) * MAKE THE STRING ASCIZ BRA.S FSELX2 FSELX1 CLR.L -(SP) * COPY _saveback TO _savename JSR _new_default ADDQ.W #4,SP FSELX2 JSR _drive_default * PREFIX WITH DEFAULT DRIVE (IF NONE GIVEN) MOVEM.L (SP)+,D1-D7/A1-A5 CLR.W D0 * (ALWAYS) RETURN ZERO FOR OKAY RTS PAGE * ---------------------------------------------------------------------------- * 68000 CALLS FROM C (XDEFS ARE REQUIRED) * ---------------------------------------------------------------------------- SECTION ZDATA RTADDR DC.L 0 SECTION ZCODE _trap1 LEA RTADDR,A0 MOVE.L (SP)+,(A0) * SAVE RETURN ADDR TRAP #1 * MAKE A GEMDOS CALL (ARGS ON STACK) MOVE.L RTADDR,-(SP) RTS _trap2 LEA RTADDR,A0 MOVE.L (SP)+,(A0) * SAVE RETURN ADDR TRAP #2 MOVE.L RTADDR,-(SP) RTS _trap13 LEA RTADDR,A0 MOVE.L (SP)+,(A0) * SAVE RETURN ADDR TRAP #13 MOVE.L RTADDR,-(SP) RTS _trap14 LEA RTADDR,A0 MOVE.L (SP)+,(A0) * SAVE RETURN ADDR TRAP #14 MOVE.L RTADDR,-(SP) RTS SECTION ZDATA ZVARS DC.L 0 * ZIP VALUE FOR A6 IS STORED HERE SECTION ZCODE * OPUSL1 NOP * IFEQ CZIP * MOVEM.L D3-D7/A2-A6,-(SP) * PRESERVE PASCAL'S REGISTERS * MOVE.L ZVARS,A6 * SET UP ZIP'S FRAME POINTER * BSR OPUSL * MOVEM.L (SP)+,D3-D7/A2-A6 * ENDC * RTS * PROCEDURE OUTBUFLEN (charCount: INTEGER) -- adjust folding * THIS WILL RESET ENDBUF (WHEN NEXT EMPTIED, TO PREVENT BUGS) * OUTBUFLEN * MOVE.L ZVARS,A0 * SET UP ZIP'S FRAME POINTER * MOVE.W 4(SP),CURSIZ * MOVE.L D0,MACBUF(A0) * RTS