/* WORLDS_TO_FILE.P */ section $-worlds => ved_saveworld, textfile_to_world, textfile_to_worldfile, worldfile_to_world; /* SPECIFICATION ------------- This module defines a Ved command for saving worlds, and a routine for loading saved worlds. For details of the format of a world, see HELP EDEN. PUBLIC saveworld(): Defines a Ved command which saves the current Ved buffer in file, in a form readable by worldfile_to_world. The command has the syntax saveworld filename and writes into filename.W Note that this command saves the world in a non-pictorial form (using 'datafile'), so you ought to keep your original picture if you intend to use it again. PUBLIC worldfile_to_world( filename ): Loads a world from filename.W and returns it. It also compiles the world's objects file, so will overwrite previous definitions of the same objects. The name of the objects file will be that in the world definition. If the object file, as named there, had no directory and no disk part, these will be assumed to be the same as in 'filename', if any. */ /* IMPLEMENTATION -------------- See the invidual procedures. */ needs worlds; needs utils; /* Worlds from Ved. ---------------- */ define ved_saveworld(); lvars the_world; vedputmessage( 'Copying world' ); vedbuffer_to_world() -> the_world; vedputmessage( 'Saving world' ); the_world -> datafile( vedargument><'.w' ); vedputmessage( 'World saved in '><'.w' ); enddefine; /* vedbuffer_to_world(): Scans the current Ved buffer and if no errors are detected, returns a world record for it. It works by looking for the bounds of the buffer, skipping header lines, reading and checking the specification line, and copying everything below it into the world's character array. It also checks for the presence of the Bug and food, and works out their coordinates. */ define vedbuffer_to_world() -> result; lvars result; lvars i, yVED_min, yVED_max, xVED_min, xVED_max; lvars first_non_blank; lvars bug_xW, bug_yW, food_xW, food_yW; lvars objects_file, energy, direction; /* Find first non-blank line. */ 1 -> i; while ( vedjumpto(i,1); vedtrimline(); vvedlinesize = 0 or starts_with(vedthisline(), `!` ) ) do 1 + i -> i; endwhile; i -> first_non_blank; /* Get name of objects file, energy, direction. */ vedjumpto( first_non_blank, 1 ); vedmoveitem() -> objects_file; vedmoveitem() -> energy; vedmoveitem() -> direction; if vedline /= first_non_blank then vederror( 'Missing objects-file, energy, or direction' ); endif; if not(objects_file.isword) then vederror( 'Objects-filename not a name' ); endif; if not(energy.isinteger) then vederror( 'Energy not an integer' ); endif; if not(direction.isword) then vederror( 'Direction not a name' ); endif; objects_file >< '.p' -> objects_file; /* Get top line of world. */ first_non_blank + 1 -> yVED_min; /* Get bottom line of world. */ vvedbuffersize -> i; while ( vedjumpto(i,1); vedtrimline(); vvedlinesize = 0 ) do i - 1 -> i; endwhile; i -> yVED_max; /* Find first and last column. */ 999 -> xVED_min; 1 -> xVED_max; for i from yVED_min to yVED_max do vedjumpto(i,1); vedtrimline(); min( xVED_min, first_non_space_pos(vedthisline()) ) -> xVED_min; max( xVED_max, last_non_space_pos(vedthisline()) ) -> xVED_max; endfor; new_world( xVED_max-xVED_min+1, yVED_max-yVED_min+1 ) -> result; /* Copy world from buffer. */ for i from yVED_min to yVED_max do vedjumpto(i,1); vedtrimline(); fit( vedthisline(), xVED_min, xVED_max ) -> (result.world_initial_chars)(yVED_max-i+1); endfor; /* Locate bug. */ if ( locate_in_world( result.world_initial_chars, `B` ) ->> bug_yW ) = false then vederror( 'No bug in world' ) else () -> bug_xW; ` ` -> (result.world_initial_chars)( bug_yW+1 )( bug_xW+1 ); /* We don't actually keep the bug in the picture. */ endif; /* Locate food. */ if ( locate_in_world( result.world_initial_chars, `+` ) ->> food_yW ) = false then vederror( 'No food in world' ) else () -> food_xW; endif; bw_select_bug( result, 1 ); bug_xW -> result.bw_bug.bug_initial_xW; bug_yW -> result.bw_bug.bug_initial_yW; food_xW -> result.world_initial_food_xW; food_yW -> result.world_initial_food_yW; objects_file -> result.world_objects_file; direction -> result.bw_bug.bug_initial_direction; energy -> result.bw_bug.bug_initial_energy; enddefine; define textfile_to_world( textfile ); lvars textfile; vedopen( textfile ).erase; vedbuffer_to_world(); enddefine; define textfile_to_worldfile( textfile, worldfile ); lvars textfile, worldfile; lvars the_world; pr( 'Copying world\n' ); textfile_to_world( textfile ) -> the_world; pr( 'Saving world\n' ); the_world -> datafile( worldfile ); pr( 'World saved in '><'\n' ); enddefine; define global worldfile_to_world( wf ); lvars wf; lvars world, of, fdisk, fdir, odisk, odir; sysfiledisk( wf ) -> fdisk; sysfiledir( wf ) -> fdir; datafile( wf><'.w' ) -> world; world_objects_file(world) -> of; sysfiledisk( of ) -> odisk; sysfiledir( of ) -> odir; if odisk = '' and odir = '' then fdisk >< fdir >< of -> of; endif; compile( of ); world enddefine; /* locate_in_world( chars, c ): Returns the world coordinates of character c in chars (a world's character array. If there's more than one occurrence, which one it finds is undefined. If c not found, returns false. */ define locate_in_world( chars, c ); lvars chars, c; lvars i, m; for i to chars.datalength do if ( locchar( c, 1, chars(i) ) ->> m ) /= false then return( m-1, i-1 ); endif; endfor; false; enddefine; /* String operations for world-building. ------------------------------------- We use this when searching Ved buffers, looking for the bug, and so on. Nothing specifically relating to worlds: it could go into a utilities library. */ /* fit( s, low, high ): That substring of s which begins at low, and extends to high. If s is not that long, the result is padded with spaces. */ define fit( s, low, high ); lvars s, low, high; lvars i, len=datalength(s); for i from low to high do if i > len then ` ` else s(i) endif; endfor; consstring( high-low+1 ); enddefine; endsection;