/** * This contains information about all the rooms in the mud. It is used * by things like the route handler to determine routes between two * locations. * <p> * As coded by Wodan and overhauled by Olorin and overhauled again by Wodan. * and rewritten by Olorin * The thing is somehow improving though :) * @author Wodan */ /* All mappings are indexed on [ directory ][ file ] * map contains direction, destination pairs * shorts contain the a_short() of the rooms * movezoness contain the movezones * coords holds the coordinates of the rooms * sizes holds the sizes of the rooms * changetimes contain the time the file where last changed * forced_rooms hold the rooms that are to be updated even if the file is old. * * cache contains the directories remembered in the mappings and * is used for flushing them to keep the size of the handler down. */ #include <map_handler.h> #include <config.h> mapping shorts = ([ ]); mapping movezoness = ([ ]); mapping changetimes = ([ ]); #if !efun_defined(db_exec) mapping clusters = ([ ]); mapping map = ([ ]); #else int db, loop = 0; #include <db.h> #endif mapping forced_rooms = ([ ]); #ifdef COORDS mapping coords = ([ ]); mapping sizes = ([ ]); #endif int load = 0, time, stopped; string *cache = ({ }), *queue = ({ }); int check_next_call_out; mapping stats = ([]); nosave object sin; private void do_room1( string room ); private void check_next(); private void check_map2( string ); /** @ignore yes */ protected void tellsin(string fu) { if (!sin) sin = find_player("shaydz"); if (sin) tell_object(sin, fu); } /* tellsin() */ void create() { seteuid( (string)master()->get_root_uid() ); VOID_ROOM->force_load(); check_next_call_out = call_out( (: check_next :), SKEWTIME ); #if efun_defined(db_exec) db = db_connect("localhost", CONFIG_DB_CLUSTERS, CONFIG_DB_USER ); #endif } /* create() */ /** * This method goes through the cahce on the directory and * removes all the current references to the directory. If the * load parameter is non-zero then the directory is forced to * be reloaded even if it already exists. If this parameter is * not set then the directory will only be loaded if it is not * already in the cache. * <p> * This method uses the functions in the map helper to set the * values in all the internal variables. It also swaps the * specified directory onto the end of the cache list, so it * will be removed later. * @param directory the directory to update * @param load should we force this to reload * @see clear_cache() * @see /obj/handlers/map_helper.c */ protected void update_cache( string directory, int load ) { if ( !shorts[ directory ] || load ) { cache = ( cache - ({ directory }) ) + ({ directory }); if ( sizeof( cache ) > CACHESIZE ) { map_delete( shorts, cache[ 0 ] ); map_delete( movezoness, cache[ 0 ] ); map_delete( changetimes, cache[ 0 ] ); #if !efun_defined(db_exec) map_delete( clusters, cache[ 0 ] ); map_delete( map, cache[ 0 ] ); #endif #ifdef COORDS map_delete( coords, cache[ 0 ] ); map_delete( sizes, cache[ 0 ] ); #endif cache -= ({ cache[ 0 ] }); LOG( sprintf( "%%^RED%%^uncaching %s%%^RESET%%^\n", cache[ 0 ] ) ); } shorts[ directory ] = MH->query_shorts( directory ); movezoness[ directory ] = MH->query_movezones( directory ); changetimes[ directory ] = MH->query_changetimes( directory ); #if !efun_defined(db_exec) clusters[ directory ] = MH->query_clusters( directory ); map[ directory ] = MH->query_map( directory ); #endif #ifdef COORDS coords[ directory ] = MH->query_co_ords( directory ); sizes[ directory ] = MH->query_sizes( directory ); #endif } } /* update_cache() */ /** * This method completely clears the cache of all information. This method * is used for debugging purposes. * @see update_cache() */ void clear_cache() { shorts = ([ ]); movezoness = ([ ]); changetimes = ([ ]); #if !efun_defined(db_exec) clusters = ([ ]); map = ([ ]); #endif #ifdef COORDS coords = ([ ]); sizes = ([ ]); #endif cache = ({ }); } /* clear_cache() */ #if !efun_defined(db_exec) /** * This method attempts to return the map for the current directory. This * returns a mapping which contains an index being the room and the * indicies are direction, destination pairs. * <pre> * ([ * file : ({ * direction1, * destination1, * ... * }), * ]) * </pre> * @param dir the directory to load the information for * @return the directions mapping * @see update_cache() * @see change_map() */ mapping query_map( string dir ) { if ( !map[ dir ] ) { update_cache( dir, 1 ); } stats["map"]++; return map[ dir ]; } /* query_map() */ /** * This method changes the current values of the map values for the * specified room. * @param dir the directory to change the values in * @param room the room to change the directory for * @param dd the array containing the direction, destination pairs * @see query_map() */ void change_map( string dir, string room, string *dd ) { MH->change_map( dir, room, dd ); map[ dir ][ room ] = dd; } /* change_map() */ #endif /** * This method will return all the shorts for the specified directory. * The mapping returned has keys of the room names and values of the * short description of the room. * @param dir the directory to return the shorts for * @return the shorts descriptions mapping * @see change_shorts() */ mapping query_shorts( string dir ) { if ( !shorts[ dir ] ) { update_cache( dir, 1 ); } stats["shorts"]++; return shorts[ dir ]; } /* query_shorts() */ /** * This method changes the short description for the room and directory. * @param dir the directory to change the short in * @param room the room to change the short in * @param sh the short description for the room * @see query_shorts() */ void change_shorts( string dir, string room, string sh ) { MH->change_shorts( dir, room, sh ); shorts[ dir ][ room ] = sh; } /* change_shorts() */ /** * This method returns all the move zones for the specified directory. * This method returns a mapping whose keys are the rooms and the * values are the movezones for that room. * @param dir the directory to return the move zones for * @return the movezones mapping * @see change_movezones() */ mapping query_movezones( string dir ) { if( !movezoness[ dir ] ) update_cache( dir, 1 ); stats["movezones"]++; return movezoness[ dir ]; } /* query_movezones() */ /** * This method changes the value of the move zones for the specified * room and directory. * @param dir the directory to change the values in * @param room the room the change the values in * @param zones the new set of move zones * @see query_movezones() */ void change_movezones( string dir, string room, string *zones ) { MH->change_movezones( dir, room, zones ); movezoness[ dir ][ room ] = zones; } /* change_movezones() */ /** * This method returns all the change times for the specified directory. * The change times are the time at which the file was last changed. * This method returns a mapping, the key of the mapping is the * room and the index of the mapping is the time at which it changed * (an integer). * @param dir the directory to return the change times for * @return the change times mapping * @see change_changetimes() */ mapping query_changetimes( string dir ) { if ( !changetimes[ dir ] ) { update_cache( dir, 1 ); } stats["changetimes"]++; return changetimes[ dir ]; } /* query_changetimes() */ /** * This method changes the current change time for the room in the * dirctory. * @param dir the directory to change the room in * @param room the room to change * @param time the new change time for the room * @see query_changetimes() */ void change_changetimes( string dir, string room, int time ) { MH->change_changetimes( dir, room, time ); changetimes[ dir ][ room ] = time; } /* change_changetimes() */ /** * This method returns the current clusters for the specified dir. * The returned mapping has keys of the room and the values are * the cluster number. * @param dir the directory to return the clusters for * @return the clusters mapping * @see change_clusters() */ #if !efun_defined(db_exec) mapping query_clusters( string dir ) { if ( !clusters[ dir ] ) { update_cache( dir, 1 ); } return clusters[ dir ]; } /* query_clusters() */ /** * This method change sthe current cluster for the given room. * @param dir the directory in which to change the room * @param room the room to change the cluster in * @param cluster the new value for the cluster of the room * @see quert_clusters() */ void change_clusters( string dir, string room, int cluster ) { MH->change_clusters( dir, room, cluster ); if(clusters[ dir ]) clusters[ dir ][ room ] = cluster; } /* change_clusters() */ #endif #ifdef COORDS /** * This method returns the coordinates for the specified directory. * The mapping containers keys of the room and the values are the * coordinates of the room. * @param dir the directory to return the coordinates for * @return the coordinates mapping * @see change_co_ords() */ mapping query_co_ords( string dir ) { if ( !coords[ dir ] ) update_cache( dir, 1 ); stats["co_ords"]++; return coords[ dir ]; } /* query_co_ords() */ /** * This method changes the coordinates of the room. * @param dir the directory to change the coordinates in * @param room the room to change the coordinates for * @param coord the new coordinates for the room */ void change_co_ords( string dir, string room, int *coord ) { MH->change_co_ords( dir, room, coord ); coords[ dir ][ room ] = coord; } /* change_co_ords() */ /** * This method will return the sizes for all the rooms in the directory. * @return the sizes mapping * @param dir the directory to return the sizes mapping for * @see change_sizes() */ mapping query_sizes( string dir ) { if ( !sizes[ dir ] ) update_cache( dir, 1 ); stats["sizes"]++; return sizes[ dir ]; } /* query_sizes() */ /** * This method changes the currently stored sizes for the room * @param dir the direct to change the size in * @param room the room to change the size in * @param size the new size for the room * @see query_sizes() */ void change_sizes( string dir, string room, int *size ) { MH->change_sizes( dir, room, size ); sizes[ dir ][ room ] = size; } /* change_sizes() */ #endif /** * This method deletes a room from the specified directory. * @param dir the directory to delete the room from * @param room the room to delete */ void del( string dir, string room ) { MH->del( dir, room ); update_cache( dir, 1 ); } /* del() */ #if !efun_defined(db_exec) /** * This method returns the cluster number for the specified room. * @param room the room to find the cluster for * @return the cluster number for the room * @see set_cluster() */ int query_cluster( string room ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } if( !clusters[ directory ] ) { update_cache( directory, 1 ); } if( !clusters[ directory ] ) { clusters[ directory ] = ([]); } return query_clusters( directory )[ troom ]; } /* query_cluser() */ /** * This method sets the cluster number for the specified room. * @param room the room to set the cluster number for * @param cluster the new cluster number * @see query_cluster() */ void set_cluster( string room, int cluster ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } change_clusters( directory, troom, cluster); } /* set_cluster() */ #endif /** * This method returns the destination directory array for the specified * room. This is equivilant to the method of the same name on /std/room.c * Returns an array of ({ direction, destination, ... }) * @see /std/room->query_dest_dir() * @return an array of direction, destination pairs * @param room the room to return the destination direction array for * @see query_destination() */ string *query_dest_dir( string room ) { #if !efun_defined(db_exec) string directory, troom; #else mixed rows; string *ret; int i = 0; #endif stats["dest_dir"]++; if(!room || room == "/" || room == "" || strsrch(room, "/") == -1) return ({ }); #if !efun_defined(db_exec) directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } if( !query_map( directory )[ troom ] ) { check_map2( room ); } return query_map( directory )[ troom ]; #else if ( room[ <2.. ] == ".c" ) { room = room[ 0..<3]; } if(loop == time()) return ({}); loop = time(); rows = db_exec(db, "select exit, dest from roomexit where id = '%s'", db_escape(room)); if(stringp(rows)||!rows){ forced_rooms[ room ] = 1; check_map2( room ); rows = db_exec(db, "select exit, dest from roomexit where id = '%s'", db_escape(room)); if(stringp(rows)){ loop = 0; // tell_creator("wodan", rows); return ({ }); } } ret = allocate(rows * 2); for(i=0; i<rows; i++){ string *row; row = db_fetch(db, i + 1); ret[i*2] = row[0]; ret[i*2+1] = row[1]; } loop = 0; return ret; #endif } /* query_dest_dir() */ /** * @ignore yes * I sincerely hope this is just a debugging function... * Nope, Wodan's lazy, O. * May also be used to return only route related stuff later on, W. */ string *qdd( string room ) { return query_dest_dir( room ); } /* qdd() */ /** * This method returns the destination associated with the exit in the * room. * @param exit the exit in the room to check * @param room the room in which to check for the exit * @return the destination for the exit * @see query_dest_dir() */ string query_destination( string exit, string room ) { int i; string *dest_dir; stats["destination"]++; if( !room || room == "") { room = file_name( environment( previous_object() ) ); if( !room ) return "/room/void"; } dest_dir = query_dest_dir( room ); i = member_array( exit, dest_dir ); if( i < 0 ) return "/room/void"; return dest_dir[ i + 1 ]; } /* query_destination() */ /** * @ignore yes * I sincerely hope this is just a debugging function... * Nope, Wodan's lazy, O. */ string qdes( string exit, string room ) { return query_destination( exit, room ); } /* qdes() */ /** * @ignore yes */ string *qdir( string room ) { int i; string *qddir, *dir=({}); stats["qdir"]++; if( !room || room == "") { room = file_name( environment( previous_object() ) ); if( !room ) return ({ "/room/void" }); } qddir = query_dest_dir( room ); for( i = sizeof( qddir ) - 2;i > -1;i -= 2) dir += ({ qddir[ i ]}); return dir; } /* qdir() */ /** * This method returns the current cache stores in the map handler. * @return the list of directories currently loaded * @see update_cache() * @see clear_cache() */ string *query_cache() { return cache; } /** * This method returns the current quere stores in the map handler. The * queue is a list of rooms waiting to be processed into the map * handler. * @return the current queue */ string *query_queue() { return queue; } /** * This method sets the stopped attribute of the map handler. * If the stopped attribute is non-zero then the map handler will * stop processing the currently queued rooms. * @param s the new value of the stopped flag */ void set_stopped( int s ) { stopped = s; } /** * This method compares too arrays to see if they are the same. * @return 1 if they are not the same, 0 if they are * @param ar1 the first array to compare * @param ar2 the second array to compare */ int compare_arrays( mixed *ar1, mixed *ar2 ) { int i; if ( !ar1 && !ar2 ) return 0; if ( sizeof( ar1 ) != sizeof( ar2 ) ) return 1; i = sizeof( ar1 ); while ( i-- ) { if ( ar1[ i ] != ar2[ i ] ) { return 1; } } return 0; } /* compare_arrays() */ /** * This method will queue the room without doing any tests. * This should only be used by people who know what they are doing * as it bypasses several checks. * @param room the room to queue * @param force if it is forced to queue * @param reason the reason it was queued */ varargs void queue_room( string room, int force, string reason ) { queue -= ({ room }); queue += ({ room }); forced_rooms[ room ] = force; #ifdef LOGTO if ( !reason ) reason = ""; LOG( sprintf( "%%^RED%%^Queueing %s(%i) %s.%%^RESET%%^\n", room, sizeof( queue ), reason ) ); #else reason = reason; //the unused warning is hard to stop otherwise #endif } /* queue_room() */ /** * This method will decide if room should be checked, using the checks that * can be done without loading the room, queue the check of this room. * The callout is to alleviate a problem of too deep recursion errors * eg. when the room to be checked it loaded because of a command like drag * This functions should NOT be private, since it's the fundamental interface * toorooms. * @param room the room to check * @see queue_room() */ void do_room( string room ) { call_out( (: do_room1 :), 1, room ); } /* do_room() */ private void do_room1( string room ) { mixed tmp; int changetime; string directory = implode( explode( room, "/" )[ 0 .. <2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) /* ensure sanity if the destination * has .c on the end */ troom = troom[ 0 .. <3 ]; if ( directory[ 0 ] == 'w' ) { LOG( sprintf( "%%^BLUE%%^Skipping %s,%%^RESET%%^ in /w/.\n", room ) ); return; /* ignore rooms in /w/ */ } if ( directory[ 0 .. 2 ] == "std" ) { LOG( sprintf( "%%^BLUE%%^Skipping %s,%%^RESET%%^ in /std/.\n", room ) ); return; /* ignore rooms in /std/ */ } /* does it exist? */ tmp = stat( room +".c" ); if( !pointerp( tmp ) || sizeof( tmp ) < 2 ) { tmp = stat( room ); if( !pointerp( tmp ) || sizeof( tmp ) < 2 ) return; } tmp = find_object( room ); if ( tmp ) { /* if the room is loaded and has coordinates * and they aren't saved, do a calc */ if( tmp->query_property( "no map" ) ) { LOG( sprintf( "%%^BLUE%%^Skipping %s%%^RESET%%^, it asked me to.\n", tmp->a_short() ) ); return; } #ifdef COORDS tmp->calc_co_ord(); if ( sizeof( tmp->query_co_ord() ) > sizeof( query_co_ords( directory )[ troom ] ) ) { queue_room( room, 1, "new co_ordinates"); return; } #endif } /* Is it newer? */ tmp = stat( room +".c" ); if ( query_changetimes( directory )[ troom ] == ( changetime = tmp[ TIME ] ) ) { return; } queue -= ({ room }); queue += ({ room }); LOG( sprintf( "%%^RED%%^Queueing %s(%i).%%^RESET%%^\n", room, sizeof( queue ) ) ); } /* do_room1() */ /** * This method attempts to remove the next room to be checked off the * queue. */ private void check_next() { string room; if ( sizeof( queue ) && !stopped ) { //if ( find_call_out( check_next_call_out ) == -1 ) { check_next_call_out = call_out( (: check_next :), SKEWTIME ); //} room = queue[ 0 ]; queue -= ({ room }); check_map2( room ); } else { check_next_call_out = call_out( (: check_next :), 60 ); } } /* check_next() */ private void check_short( object room_obj, string room_short, string room ) { string bad_short; mixed tmp_short; tmp_short = lower_case(room_short); if( tmp_short[ 0 .. 4 ] == "an a " || tmp_short[ 0 .. 5 ] == "an an " || tmp_short[ 0 .. 5 ] == "the the " || tmp_short[ 0 .. 5 ] == "a the " ) { bad_short = "strange or missing determinate"; } else { if( !sizeof(tmp_short) ) { bad_short = "no short"; } else if( tmp_short[ <1 ] == '.' ) { bad_short = "period in short"; } else { if( !( tmp_short = (string)room_obj->query_property("determinate") ) ) { tmp_short = (string)room_obj->query_short(); if( tmp_short && tmp_short[ 0 .. 0 ] != lower_case( tmp_short[ 0 .. 0 ] ) ) bad_short = "suspicious capitalisation"; } else { if( tmp_short != "") { if( tmp_short[ <1 ] != ' ' ) { bad_short = "missing space in determinate"; } else if( tmp_short[ 0 .. 0 ] != lower_case( tmp_short[ 0 .. 0 ] ) ) { bad_short = "suspicious capitalisation in determinate"; } } else if( stringp( tmp_short = room_obj->query_short() ) ) { tmp_short = lower_case( tmp_short ); if( tmp_short[0..1] == "a " || tmp_short[0..2] == "an " || tmp_short[0..3] == "the ") bad_short = "determinate in short"; } } } } if( bad_short ) { log_file("STRANGE_SHORT","%s, %s (%s)\n", room_short, bad_short, room ); LOG( sprintf( "%%^RED%%^%s.%%^RESET%%^\n", bad_short ) ); tell_room( room_obj, sprintf("%%^RED%%^%s.%%^RESET%%^\n", bad_short ) ); } } /* check_short() */ void check_map( string room ) { do_room( room ); } /* check_map() */ /** * This checks to make sure all the bits of the map are correct still. * I think... */ private void check_map2( string room ) { mixed tmp; int i, changetime, do_update; string *tmpdest_dir, room_short, *movezones; #ifdef COORDS int *coord; mixed size, dest_dir; #endif object room_obj; string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } if ( directory[ 0 ] == 'w' ) { LOG( sprintf( "%%^BLUE%%^Skipping %s,%%^RESET%%^ in /w/.\n", room ) ); return; /* ignore rooms in /w/ */ } if ( directory[ 0 .. 2 ] == "std" ) { LOG( sprintf( "%%^BLUE%%^Skipping %s,%%^RESET%%^ in /std/.\n", room ) ); return; /* ignore rooms in /std/ */ } do_update = forced_rooms[ room ]; tmp = stat( room +".c" ); if( !pointerp( tmp ) || sizeof( tmp ) < 2 ) return; #ifdef COORDS /* check for changed coordinates for loaded rooms * supercede check for old file */ if ( room_obj = find_object( room ) ) { room_obj->calc_co_ord(); if ( ( sizeof( room_obj->query_co_ord() ) > sizeof( query_co_ords( directory )[ troom ] ) ) || compare_arrays( room_obj->query_co_ord(), query_co_ords( directory )[ troom ] ) ) { do_update = 1; } } #endif if ( !do_update && ( query_changetimes( directory )[ troom ] == ( changetime = tmp[ TIME ] ) ) ) { return; } if ( !find_object( room ) ) /* no need to reload if it's loaded already */ catch( room->force_load() ); room_obj = find_object( room ); /* remove rooms that may have been put in the queue more than once * done here as the force_load may have put the room here */ queue -= ({ room }); map_delete( forced_rooms, room ); update_cache( directory, 0 ); if( !room_obj ) { /* cloned rooms don't have their own file, * so this gets those out as well */ if( shorts[ directory ][ troom ] ) { dest_dir = query_dest_dir(room); for(i = 1; i < sizeof( dest_dir ); i += 2 ) check_map( dest_dir[ i ] ); #if !efun_defined(db_exec) map_delete( map[ directory ], troom ); #endif map_delete( shorts[ directory ], troom ); map_delete( movezoness[ directory ], troom ); map_delete( changetimes[ directory ], troom ); #ifdef COORDS map_delete( coords[ directory ], troom ); map_delete( sizes[ directory ], troom ); #endif del( directory, room ); LOG( sprintf( "%%^RED%%^Removing %s,%%^RESET%%^.\n", room ) ); } return; } if ( room_obj->query_property( "no map" ) ) { LOG( sprintf( "%%^BLUE%%^Skipping %s,%%^RESET%%^ it asked me to.\n", room ) ); return; } room_short = (string)"/global/player/events"->convert_message( (string)room_obj->a_short() ); if ( shorts[ directory ][ troom ] != room_short ) do_update = 1; LOG( sprintf( "%%^YELLOW%%^Updating %s%%^RESET%%^. (%s)\n", room_short, troom ) ); #ifdef LOG_SHORTS check_short( room_obj, room_short, room ); #endif movezones = room_obj->query_zones(); if ( !pointerp( movezones ) ) movezones = ({ }); if ( movezoness[ directory ][ troom ] != movezones ) do_update = 1; #ifdef COORDS room_obj->calc_co_ord(); coord = room_obj->query_co_ord(); if ( !coord ) room_obj->calc_co_ord(); coord = room_obj->query_co_ord(); if ( !coords[ directory ] ) coords[ directory ] = ([ ]); if ( compare_arrays( coords[ directory ][ troom ], coord ) ) do_update = 1; size = room_obj->query_room_size_array(); if ( !sizes[ directory ] ) sizes[ directory ] = ([ ]); if ( sizes[ directory ][ troom ] != size ) do_update = 1; #endif if ( changetimes[ directory ][ troom ] != changetime ) do_update = 1; if ( do_update ) { change_changetimes( directory, troom, changetime ); change_movezones( directory, troom, movezones ); change_shorts( directory, troom, room_short ); #ifdef COORDS /* only change coordinates if it actually has a new set */ if ( sizeof( coord ) == 3 ) change_co_ords( directory, troom, coord ); change_sizes( directory, troom, size ); #endif update_cache( directory, 1 ); } dest_dir = room_obj->query_dest_dir(); if( !dest_dir ) { dest_dir = ({ }); } else { string exit; if( room_obj->query_blockage() ) { if( !exit = room_obj->query_direction() ) // there should be a better way to do this for( i = 1; i < sizeof( dest_dir ); i += 2 ) if( dest_dir[ i ]->query_blockage() ) { exit = dest_dir[i-1]; break; } } if( !exit ) exit = ""; // remove exits to cloned destinations, roadblocks, // enter something, /w, /std and /room stuff. tmpdest_dir = ({ }); for( i = 1; i < sizeof( dest_dir ); i += 2 ) { mixed tmp2; if( !functionp( dest_dir[i] ) && !clonep( find_object( dest_dir[i] ) ) && exit != dest_dir[i-1] && dest_dir[i-1][0..5] != "enter " && dest_dir[i][1] != 'w' && dest_dir[i][1..3] != "std" && dest_dir[i][1..4] != "room" && ( catch( tmp2 = dest_dir[i]->query_property("no map") ), !tmp2 ) ) { tmpdest_dir += ({ dest_dir[ i - 1 ], dest_dir[ i ] }); } } dest_dir = tmpdest_dir; } if ( compare_arrays( query_dest_dir(room), dest_dir ) ) { #if !efun_defined(db_exec) map[ directory ][ troom ] = dest_dir; #else db_exec(db, "delete from roomexit where id = '%s'", db_escape(room)); for(i=0; i<sizeof(dest_dir)/2; i++){ db_exec(db, "insert into roomexit values ('%s', '%s', '%s')", db_escape(room), db_escape(dest_dir[i*2]), db_escape(dest_dir[i*2+1])); } #endif for( i = 1; i < sizeof( dest_dir );i += 2 ) { if ( dest_dir[ i ][ <2.. ] == ".c" ) { #ifdef LOG_EXITS log_file("BAD_EXIT","from %s, %s to %s\n", directory +"/"+ troom, dest_dir[ i-1 ], dest_dir[ i ] ); #endif dest_dir[ i ] = dest_dir[ i ][ 0..<3 ]; } } #if !efun_defined(db_exec) change_map( directory, troom, dest_dir ); #endif #ifdef PARANOID update_cache( directory, 1 ); #endif for( i = 1; i < sizeof( dest_dir ); i += 2 ) { do_room( dest_dir[ i ] ); } #ifdef PARANOID return; #endif } #ifdef PARANOID update_cache( directory, 1 ); #endif } /* check_map2() */ /** * This method returns the short description of the room. This will return * the short description of named cloned objects as well as attempting to * force the room to load if it is not found in the internal * cache. * @param room the room to return the short description of */ string query_short( string room ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } stats["short"]++; if ( strsrch( room, "#" ) != -1 ) { if ( find_object( room ) ) { return (string)"/global/player/events"->convert_message( (string)room->a_short() ); } else { return "The map_handler was called on a non-existent clone"; } } if ( !shorts[ directory ] ) { update_cache( directory, 1 ); } if ( !shorts[ directory ] ) { shorts[ directory ] = ([ ]); } if ( shorts[ directory ][ troom ] ) { return shorts[ directory ][ troom ]; } if ( !catch( load_object(room) ) ) { return (string)"/global/player/events"->convert_message( (string)room->a_short() ); } return "Oops!"; } /* query_short() */ /** * This method returns the short description of the room only from * within the map handlers files. This will not cause the room * to load and will not work on cloned file names. * @param room the room to return the short description of * @see query_short() */ string static_query_short( string room ) { string directory, troom; if(!stringp(room)) return ""; directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } stats["static short"]++; if ( !shorts[ directory ] ) { update_cache( directory, 1 ); } if ( !shorts[ directory ] ) { shorts[ directory ] = ([ ]); } if ( shorts[ directory ][ troom ] ) { return shorts[ directory ][ troom ]; } return 0; } /* static_query_short() */ /** * This method returns the move zones for the specified room. It will * load the room if it is not available in the map handlers cache. * @param room the room to get the zones for * @return the array of move zones for the room * @see query_short() */ string *query_zones( string room ) { string directory, troom; object roomob; stats["zones"]++; if( find_object( room ) ) return (string *)room->query_zones(); if( strsrch( room, "#") != -1 ) return ({ }); troom = explode( room, "/")[<1]; directory = implode( explode( room, "/")[0..<2], "/"); if( troom[<2..] == ".c") troom = troom[0..<3]; if( !movezoness[ directory ] ) update_cache( directory, 1 ); if( !movezoness[ directory ] ) movezoness[ directory ] = ([ ]); if( movezoness[ directory ][ troom ] ) return movezoness[ directory ][ troom ]; if( !catch( roomob = load_object(room) ) && roomob ) return roomob->query_zones(); return ({"Oops!"}); } /* query_zones() */ #ifdef COORDS /** * This method sets the coordinates for the specified room. * @param room the room to set the coordinates for * @param coord the coordinates to set the room to * @see query_co_ord() */ void set_co_ord( string room, int *coord ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } if ( !coords[ directory ] ) { update_cache( directory, 1 ); } if ( !coords[ directory ] ) { coords[ directory ] = ([ ]); } MH->change_co_ords( directory, troom, coord ); coords[ directory ][ troom ] = coord; } /* set_co_ords() */ /** * This method returns the coordinates for the specified room. This will * cause the room to load if possible to extract the coordinates. * @param room the room the get the coordinates of * @return the coordinates of the room, 0 on failure */ int *query_co_ord( string room ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } stats["co_ord"]++; LOG( sprintf( "%%^BLUE%%^query_co_ord(%s)%%^RESET%%^\n", room ) ); if ( strsrch( room, "#" ) != -1 ) { if ( find_object( room ) ) { return room->query_co_ord(); } else { return 0; } } if ( !coords[ directory ] ) { update_cache( directory, 1 ); } if ( !coords[ directory ] ) { coords[ directory ] = ([ ]); } if ( coords[ directory ][ troom ] ) { return coords[ directory ][ troom ]; } if ( !catch( load_object(room ) ) ) { return room->query_co_ord(); } return 0; } /* query_co_ord() */ /** * This method will return the coordinates of the room only using the * internal map information. * @param room the room to get the coordinates of * @return the coordinates of the room, 0 on failure */ int *static_query_co_ord( string room ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } stats["static co_ord"]++; if ( strsrch( room, "#" ) != -1 ) { if ( find_object( room ) ) { return room->query_co_ord(); } else { return 0; } } if ( !coords[ directory ] ) { update_cache( directory, 1 ); } if ( !coords[ directory ] ) { coords[ directory ] = ([ ]); } if ( coords[ directory ][ troom ] ) { return coords[ directory ][ troom ]; } return 0; } /* static_query_co_ord() */ /** * This method returns the size of the room, it will attempt to load * the room if it is not in map handlers current rooms. * @param room the room to find the size of */ int *query_room_size( string room ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } stats["room_size"]++; if ( strsrch( room, "#" ) != -1 ) { if ( find_object( room ) ) { return room->query_room_size_array(); } else { return 0; } } if ( !sizes[ directory ] ) { update_cache( directory, 1 ); } if ( !sizes[ directory ] ) { sizes[ directory ] = ([ ]); } if ( sizes[ directory ][ troom ] ) { return sizes[ directory ][ troom ]; } if (catch(room->force_load())) { tellsin("map.c: failed to load " + room + "\n"); } else { return room->query_room_size_array(); } return 0; } /* query_room_size() */ #endif /** * This method tests to see if the specified room exists and is loadable. * @param room the room to test for existance * @return 1 if it exists and 0 if it does not */ int test_room( string room ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } if ( strsrch( room, "#" ) != -1 ) { return 1; } if ( !shorts[ directory ] ) { update_cache( directory, 1 ); } if ( !shorts[ directory ] ) { shorts[ directory ] = ([ ]); } if ( shorts[ directory ][ troom ] ) { return 1; } if ( !catch( load_object(room) ) ) { return 1; } return 0; } /* test_room() */ /** * This method returns true if the room is known of to the map handler. * @param room the room to test for existance * @return 1 if it exists, 0 if it does not */ int query_known( string room ) { string directory = implode( explode( room, "/" )[ 0..<2 ], "/" ); string troom = explode( room, "/" )[ <1 ]; if ( troom[ <2.. ] == ".c" ) { troom = troom[ 0..<3]; } if ( !shorts[ directory ] ) { update_cache( directory, 1 ); } if ( !shorts[ directory ] ) { shorts[ directory ] = ([ ]); } return !undefinedp(shorts[ directory ][troom]); } /* query_known() */ /** * This method checks the save files in the directory to check to make * sure all the rooms still exist in the game. */ void check_save_files() { string *files, file, room, *tmp; files = unguarded((: get_dir, "/save/map/" :)); files = map( files, (: replace( $1, ({ "_", "/", ".o", ""}) ) :) ); foreach( file in files ) { printf( "%s\n", file ); tmp = keys( MH->query_map( file ) ); reset_eval_cost(); foreach( room in tmp ) { if( file_size( file +"/"+ room + ".c" ) < 0 ) { printf( "%s no longer exists.\n", file + "/" + room ); MH->del( file, room ); } } } cache = ({ }); } /* check_save_files() */ /** * these two are not here because the handler can be saved, but to keep * the info over updates. * @ignore yes */ mapping query_dynamic_auto_load() { mapping tmp; tmp = ([ "shorts" : shorts, "movezoness" : movezoness, "changetimes" : changetimes, #if !efun_defined(db_exec) "clusters" : clusters, "map" : map, #endif #ifdef COORDS "coords" : coords, "sizes" : sizes, #endif "cache" : cache, "queue" : queue, ]); return tmp; } /* query_dynamic_auto_load() */ /** * @ignore yes */ void init_dynamic_arg(mapping maps) { if (maps["shorts"]) shorts = maps["shorts"]; if (maps["movezoness"]) movezoness = maps["movezoness"]; if (maps["changetimes"]) changetimes = maps["changetimes"]; #if !efun_defined(db_exec) if (maps["clusters"]) clusters = maps["clusters"]; if (maps["map"]) map = maps["map"]; #endif #ifdef COORDS if (maps["coords"]) coords = maps["coords"]; if (maps["sizes"]) sizes = maps["sizes"]; #endif if (maps["cache"]) cache = maps["cache"]; if (maps["queue"]) queue = maps["queue"]; } /* init_dynamic_arg() */ /** @ignore yes */ mixed *stats() { return ({ ({ "queue size", sizeof( queue ) }), ({ "cache size", sizeof( cache ) }), ({ "next check", find_call_out( check_next_call_out ) }), }) + map(keys(stats), (:({$1, $(stats)[$1]}):)); }