home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
GAMES
/
infocom_src.lha
/
file.c
< prev
next >
Wrap
Text File
|
1993-07-15
|
13KB
|
563 lines
/*
** File: file.c
**
** (C)opyright 1987-1992 InfoTaskforce.
*/
#include <stdio.h>
#include "infocom.h"
#define NAME_SIZE 80
extern int errno;
char name[NAME_SIZE + 1] ;
FILE *game_file = (FILE *)0 ;
Void
read_header ( head )
header *head ;
{
/*
** Read the Data File Header.
**
** This routine does not read the data-file header
** directly into a header structure because certain
** machines like the VAX 11/780 store integers in
** a different way to machines based on processors
** like the 68000 ( a 68000 stores the high byte
** first, while a VAX stores the low byte first ).
** Consequently, if the header is read directly
** into a structure, the integer values are
** interpreted differently by the two machines.
**
** Note:
** The parameter "head" is of type "header *"
** NOT "header_ptr" - these definitions are
** different for MSDOS Compilers ("header_ptr" is huge).
*/
header buffer ;
if ( fseek ( game_file,0L,0 ) < 0 )
{
display ( "Failed to Seek Start of File\n" ) ;
quit () ;
}
else
{
if ( fread ((char *)(&buffer),sizeof(header),1,game_file ) != 1 )
{
display ( "Failed to read File Header\n" ) ;
quit () ;
}
else
{
assign ( head,(byte_ptr)&buffer ) ;
if (
( head -> z_code_version == 0 )
||
( head -> z_code_version > MAX_VERSION )
)
{
error ( ERR_HEADER ) ;
}
}
}
}
Void
assign ( head,buffer )
header *head ;
byte_ptr buffer ;
{
/*
** Process the raw header data in "buffer" and put
** it into the appropriate fields in "head". This
** processing is required because of the way different
** machines internally represent 'words'.
**
** Note:
** The parameter "head" is of type "header *"
** NOT "header_ptr" - these definitions are
** different for MSDOS Compilers ("header_ptr" is huge).
*/
int i ;
head -> z_code_version = *buffer++ ;
head -> mode_bits = *buffer++ ;
head -> release = make_word ( &buffer ) ;
head -> resident_bytes = make_word ( &buffer ) ;
head -> start = make_word ( &buffer ) ;
head -> vocab = make_word ( &buffer ) ;
head -> object_list = make_word ( &buffer ) ;
head -> globals = make_word ( &buffer ) ;
head -> save_bytes = make_word ( &buffer ) ;
head -> script_status = make_word ( &buffer ) ;
for ( i = 0 ; i < 6 ; i++ )
head -> serial_no[i] = *buffer++ ;
head -> common_word = make_word ( &buffer ) ;
head -> verify_length = make_word ( &buffer ) ;
head -> verify_checksum = make_word ( &buffer ) ;
head -> interpreter_number = *buffer++ ;
head -> interpreter_version = *buffer++ ;
head -> screen_height = *buffer++ ;
head -> screen_width = *buffer++ ;
head -> left = *buffer++ ;
head -> right = *buffer++ ;
head -> top = *buffer++ ;
head -> bottom = *buffer++ ;
head -> unknown1 = *buffer++ ;
head -> unknown2 = *buffer++ ;
for ( i = 0 ; i < 2 ; i++ )
head -> padding1[i] = make_word ( &buffer ) ;
head -> unknown3 = *buffer++ ;
head -> unknown4 = *buffer++ ;
head -> unknown5 = make_word ( &buffer ) ;
for ( i = 0 ; i < 3 ; i++ )
head -> padding2[i] = make_word ( &buffer ) ;
head -> unknown6 = make_word ( &buffer ) ;
for ( i = 0 ; i < 4 ; i++ )
head -> padding3[i] = make_word ( &buffer ) ;
}
word
make_word ( ptr )
byte_ptr *ptr ;
{
/*
** Form a word from two bytes.
** (High byte before Low byte)
*/
word value ;
value = *(*ptr)++ ;
value = ( value << 8 ) + *(*ptr)++ ;
return ( value ) ;
}
int
open_file ( filename )
char *filename ;
{
/*
** Open a File for Reading
*/
if (( game_file = fopen ( filename,READ_STRING )) == (FILE *)0 )
return ( FALSE ) ;
return ( TRUE ) ;
}
Void
close_file ()
{
/*
** Close an Open File
*/
if ( game_file != (FILE *)0 )
{
if ( fclose ( game_file ) )
display ( "Cannot Close Game File\n" ) ;
game_file = (FILE *)0 ;
}
}
Void
load_page ( block,num_blocks,ptr )
word block ;
word num_blocks ;
byte_ptr ptr ;
{
long offset ;
/*
** Read "num_block" blocks from Game File,
** starting with block "block", at the
** location pointed to by "ptr".
*/
offset = (long) block * BLOCK_SIZE ;
if ( fseek ( game_file,offset,0 ) < 0 )
{
display ( "Failed to Seek required Blocks\n" ) ;
quit () ;
}
else
{
if ( (int)fread ((char *)ptr,BLOCK_SIZE,(int)num_blocks,game_file) < 0 )
{
display ( "Failed to Read required Blocks\n" ) ;
quit () ;
}
}
}
boolean
filename ()
{
char ch ;
int i ;
display ( "Filename: " ) ;
i = 0 ;
while (( ch = read_char () ) != '\n' )
{
/* Handle backspaces */
if (( ch == '\b' ) && ( i != 0 ))
--i ;
/* Convert Uppercase to Lowercase */
if (( ch >= 'A' ) && ( ch <= 'Z' ))
ch = ch - 'A' + 'a' ;
/* Handle Alpha-numeric Characters */
if (( ch >= 'a' ) && ( ch <= 'z' ) && ( i < NAME_SIZE ))
name[i++] = ch ;
if (( ch >= '0' ) && ( ch <= '9' ) && ( i < NAME_SIZE ))
name[i++] = ch ;
/* Handle Pathname Characters */
if ((ch == '/' || ch == ':' || ch == '.') && (i < NAME_SIZE))
name[i++] = ch ;
}
name[i] = '\0' ;
if ( i == 0 )
{
display ( "Bad Filename. Try Again...\n" ) ;
return ( FALSE ) ;
}
return ( TRUE ) ;
}
boolean
put_word ( save_file,number )
FILE *save_file ;
word number ;
{
/*
** Returns TRUE if an Error Occurred.
*/
byte c ;
c = MOST_SIGNIFICANT_BYTE ( number ) ;
if ( fwrite ((char *)&c,sizeof(byte),1,save_file) != 1 )
return ( TRUE ) ;
c = LEAST_SIGNIFICANT_BYTE ( number ) ;
if ( fwrite ((char *)&c,sizeof(byte),1,save_file) != 1 )
return ( TRUE ) ;
return ( FALSE ) ;
}
boolean
ld_word ( save_file,number )
FILE *save_file ;
word *number ;
{
/*
** Returns TRUE if an Error Occurred.
*/
byte c ;
if ( fread ((char *)&c,sizeof(byte),1,save_file) != 1 )
return ( TRUE ) ;
*number = c << 8 ;
if ( fread ((char *)&c,sizeof(byte),1,save_file) != 1 )
return ( TRUE ) ;
*number |= c ;
return ( FALSE ) ;
}
Void
save_game ()
{
extern header data_head ;
extern byte_ptr base_ptr ;
extern word *stack_base ;
extern word *stack_var_ptr ;
extern word *stack ;
extern word stack_space[] ;
extern word pc_page ;
extern word pc_offset ;
extern word save_blocks ;
FILE *save_file ;
boolean err = FALSE ;
word s_offset ;
int i ;
/*
** Save a Game.
**
** Swapping Saved Game Files between machines is OK provided the
** macro "STACK_SIZE" in file "infocom.h" is the same on each machine.
**
** For the Standard & Enhanced Interpreters:
** "ret_value ( FALSE )" -> Save/Restore Error.
** "ret_value ( TRUE )" -> Save/Restore was Ok.
**
** For the PLUS Series Interpreter:
** "store ( (word)0 )" -> Save/Restore Error.
** "store ( (word)1 )" -> Save was Ok.
** "store ( (word)2 )" -> Restore was Ok.
*/
while ( ! filename () ) ;
if (( save_file = fopen ( name,WRITE_STRING )) == (FILE *)0 )
{
if ( data_head.z_code_version <= VERSION_3 )
ret_value ( FALSE ) ;
else
store ( (word)0 ) ;
return ;
}
if (fwrite((char *)base_ptr,BLOCK_SIZE,(int)save_blocks,save_file) != save_blocks)
err = TRUE ;
/*
** Save the Stack, Stack Pointers & Program Counter
*/
for ( i = 0 ; i < (int)STACK_SIZE ; i++ )
err |= put_word ( save_file,stack_space[i] ) ;
s_offset = stack_base - stack ;
err |= put_word ( save_file,s_offset ) ;
s_offset = stack_base - stack_var_ptr ;
err |= put_word ( save_file,s_offset ) ;
err |= put_word ( save_file,pc_page ) ;
err |= put_word ( save_file,pc_offset ) ;
if ( fclose ( save_file ) )
err = TRUE ;
if ( data_head.z_code_version <= VERSION_3 )
{
if ( err )
ret_value ( FALSE ) ;
else
ret_value ( TRUE ) ;
}
else
{
if ( err )
store ( (word)0 ) ;
else
store ( (word)1 ) ;
}
}
boolean
check ( info )
header *info ;
{
extern header data_head ;
register int i ;
/*
**
** Note:
** The parameter "info" is of type "header *"
** NOT "header_ptr" - these definitions are
** different for MSDOS Compilers ("header_ptr" is huge).
*/
if ( info -> z_code_version != data_head.z_code_version )
return ( FALSE ) ;
if ( info -> mode_bits != data_head.mode_bits )
return ( FALSE ) ;
if ( info -> release != data_head.release )
return ( FALSE ) ;
for ( i = 0 ; i < 6 ; i++ )
if ( info -> serial_no[i] != data_head.serial_no[i] )
return ( FALSE ) ;
if ( info -> verify_length != data_head.verify_length )
return ( FALSE ) ;
if ( info -> verify_checksum != data_head.verify_checksum )
return ( FALSE ) ;
return ( TRUE ) ;
}
Void
restore_game ()
{
extern header data_head ;
extern byte_ptr base_ptr ;
extern word *stack_base ;
extern word *stack_var_ptr ;
extern word *stack ;
extern word stack_space[] ;
extern word pc_page ;
extern word pc_offset ;
extern word save_blocks ;
FILE *save_file ;
header test ;
boolean err = FALSE ;
word s_offset ;
int i ;
/*
** Restore a Saved Game
**
** Swapping Saved Game Files between machines is OK provided the
** macro "STACK_SIZE" in file "infocom.h" is the same on each machine.
**
** For the Standard & Enhanced Interpreters:
** "ret_value ( FALSE )" -> Save/Restore Error.
** "ret_value ( TRUE )" -> Save/Restore was Ok.
**
** For the PLUS Series Interpreter:
** "store ( (word)0 )" -> Save/Restore Error.
** "store ( (word)1 )" -> Save was Ok.
** "store ( (word)2 )" -> Restore was Ok.
*/
while ( ! filename () ) ;
if (( save_file = fopen ( name,READ_STRING )) == (FILE *)0 )
{
if ( data_head.z_code_version <= VERSION_3 )
ret_value ( FALSE ) ;
else
store ( (word)0 ) ;
return ;
}
if (fread((char *)base_ptr,BLOCK_SIZE,(int)save_blocks,save_file) != save_blocks)
err = TRUE ;
/*
** Restore Stack, Stack Pointers & Program Counter
*/
for ( i = 0 ; i < (int)STACK_SIZE ; i++ )
err |= ld_word ( save_file,&stack_space[i] ) ;
err |= ld_word ( save_file,&s_offset ) ;
stack = stack_base - s_offset ;
err |= ld_word ( save_file,&s_offset ) ;
stack_var_ptr = stack_base - s_offset ;
err |= ld_word ( save_file,&pc_page ) ;
err |= ld_word ( save_file,&pc_offset ) ;
if ( fclose ( save_file ) )
err = TRUE ;
/*
** Check the validity of the restored game file.
*/
assign ( &test,base_ptr ) ;
if (( ! err ) && check ( &test ))
{
init_interpreter ( FALSE ) ;
if ( data_head.z_code_version <= VERSION_3 )
ret_value ( TRUE );
else
store ( (word)2 ) ;
}
else
{
display ( "Wrong Game or Version ...\nRestarting ...\n" ) ;
restart () ;
}
}
/*
** Scripting Routines and Variables.
*/
/* Level 2 patch installed -mlk */
FILE *script_file = (FILE *)0 ;
byte tmp_script_status = 0 ;
byte_ptr script_status_ptr = (byte_ptr)&tmp_script_status ;
Void
init_script ()
{
extern byte_ptr base_ptr ;
extern byte_ptr script_status_ptr ;
extern boolean script_on ;
script_status_ptr = (byte_ptr) &(((header_ptr)base_ptr) -> script_status) ;
script_status_ptr++ ;
script_on = FALSE ;
}
boolean
open_script ()
{
extern char name[] ;
extern FILE *script_file ;
while ( ! filename () ) ;
if (( script_file = fopen ( name,APPEND_STRING )) == (FILE *)0 )
return ( FALSE ) ;
return ( TRUE ) ;
}
Void
close_script ()
{
extern FILE *script_file ;
if ( script_file != (FILE *)0 )
{
if ( fclose ( script_file ) )
display ( "Cannot Close Script File\n" ) ;
script_file = (FILE *)0 ;
}
}
Void
script_char ( c )
char c ;
{
extern header data_head ;
extern FILE *script_file ;
extern boolean disable_script ;
extern boolean script_on ;
extern byte_ptr script_status_ptr ;
if ( data_head.z_code_version <= VERSION_3 )
{
if (( script_on ) && (( *script_status_ptr & SCRIPT_MODE_ON ) == 0 ))
{
script_on = FALSE ;
data_head.script_status &= SCRIPT_MODE_OFF ;
close_script () ;
return ;
}
if (( ! script_on ) && ( *script_status_ptr & SCRIPT_MODE_ON ))
{
/*
** We must temporarily turn off the "SCRIPT_MODE" bit that
** is pointed to by "script_status_ptr" because "script_on"
** must remain "FALSE" until the script file is open and
** "open_script ()" calls "filename ()" which calls
** "read_char ()" which calls this routine which will try to
** open a script file by calling "open_script ()" ...
**
** The "SCRIPT_MODE" bit is turned back on if the script file
** is successfully opened.
*/
*script_status_ptr &= SCRIPT_MODE_OFF ;
if (( script_on = open_script () ) == TRUE )
{
*script_status_ptr |= SCRIPT_MODE_ON ;
data_head.script_status |= SCRIPT_MODE_ON ;
}
}
}
if (( script_on ) && ( ! disable_script ) && ( c >= 6 ))
putc ( c,script_file ) ;
}