/* ** area.c - file for creating areas. NOTE: this file isn't used ** by itself. It is included in other files that inherit the ** proper base room. I HATE doing it this way, but I couldn't ** think of a way to make the inheritance work out. **/ /** * This file contains the functions used in rooms that make up "areas", * arbitrary polygons consisting of identical rooms. This is similar * to the terrain system, but with certain advantages: the areas can * be any polygon, even non-convex ones; areas are integrated into the * topology system, which also handles roads through areas.<p> * Although all of the rooms in an area are cloned from the same file, * a number of tricks can be used to add variety (but that's beyond the * scope of this document). * @author Jeremy * @see area * @see topography */ #include <dirs.h> #include <room.h> string topo_handler; mapping look_mess = ([ ]); mapping dirs = ([ "north": ({ 1, 0, 0 }), "south": ({ -1, 0, 0 }), "east": ({ 0, 1, 0 }), "west" : ({ 0, -1, 0 }), "northeast": ({ 1, 1, 0 }), "northwest": ({ 1, -1, 0 }), "southeast": ({ -1, 1, 0 }), "southwest": ({ -1, -1, 0 }), "up": ({ 0, 0, 1 }), "down": ({ 0, 0, -1 }) ]); /** * This method is deprecated. Use set_topo_handler() */ void set_area_handler(string s) { topo_handler = s; } /** * This method sets the topology handler for this area. A simple area * handler can be used rather than a topology handler in limited cases. * @param s pathname of topology handler * @see topology * @see area * @see query_topo_handler() */ void set_topo_handler(string s) { topo_handler = s; } /** * This method returns the topology handler set for this room. * @return the topology handler for the room * @see set_topo_handler() */ string query_topo_handler() { return topo_handler; } /** * This method adds or changes the message printed when looking in a * certain direction. Messages set with modify_exit() have priority. * If neither are set, the room's description is used. * @param m a mapping of messages in the form ([<direc>:<mess>]) */ void add_look_mess(mapping m) { look_mess += m; } mapping query_look_mess() { return look_mess; } /** * This method is called when the player quits, to save the current * room. It uses a little-known alternate form that returns the * room path and the coordinates. * @return the iroom path and coordinates */ mixed query_quit_handler() { string s; s = explode(file_name(ENV(TP)), "#")[0]; return ({ s, query_co_ord() }); } /* query_quit_handler() */ /** * This method is called at login, to move the player to the room. * Since these rooms are always clones, the master has the responsibility * of cloning itself when a player logs in, and moving the player to it. * @param player the player logging in */ void enter(object player) { object new_room; // I used to use clonep() here, but the "parent" of virtual rooms were // coming up as clones. if (sizeof(explode(file_name(TO), "#")) > 1) { // We somehow called enter() from a clone... return; } new_room = (topo_handler)->find_room_at_coord( player->query_saved_co_ords()); if (!objectp(new_room)) { tell_creator("jeremy", "Couldn't find area room for %O at %O...\n", player, player->query_saved_co_ords()); player->move(player->query_start_pos()); return; } tell_creator("jeremy", "Moving %O to %O...\n", player, new_room); player->move(new_room); } /* enter() */ /** * This method masks the standard query_dest_other() function. It calls * the topology handler to find the connecting room (which is usually * cloned on-the-fly). * @param direc room exit name * @return structure describing the exit * @see /std/room */ // This gives us time to clone the connecting room before the player // moves into it. varargs mixed *query_dest_other( string direc ) { object room; mixed ret; //tell_creator("jeremy", "%O:query_dest_other(%s)\n", TO, direc); if (!stringp(direc)) { return ::query_dest_other(direc); } room = (topo_handler)->find_room_at_exit(TO, dirs[direc], direc); if (!objectp(room)) { return 0; } ret = ::query_dest_other(direc); if (!sizeof(ret)) { return 0; } ret[ROOM_DEST] = file_name(room); return ret; } /* query_dest_other() */ /** * This method masks the standard query_look(). If a "look" message has * been set with modify_exit(), it is returned. Next, the look_mess * mapping is checked; if there is an entry for this exit, it is evaluated * and returned. Finally, the room itself is loaded and the description * is returned. * @param direc exit name * @return the description of the adjoining room * @see modify_exit() * @see add_look_mess() */ string query_look(string direc) { int dark; string s, direc_s; mixed dest; direc_s = direc; if (s = ::query_look(direc_s)) { return s; } if (s = look_mess[direc_s]) { return evaluate(s); } dest = query_dest_other(direc_s); if (!dest) { return 0; } dest = dest[ROOM_DEST]; if (!dest) { return 0; } if (query_door_open(direc_s) != 0) { // it mustn't be dark in the destination room. dest->force_load(); TP->set_looked( find_object( dest ) ); dark = (int)TP->check_dark((int)dest->query_light()); s = (string)dest->long( 0, dark ); if (s[<1] == '\n') { // The look command automatically adds a '\n' return s[0..<2]; } return s; } return 0; } /* query_look() */ /** * This method adds exits for the room if they don't already exist. * "compass4" and "compass8" can be specified as exit names to add * exits for all of the normal 4 or 8 compass directions, respectively. * @param e array of exit names * @param type type of exit ("path", "road", etc) */ // A dummy exit name of "/topography" is used to avoid null strings. void add_topo_exits(string *other_exits, string other_types) { string s; foreach (s in other_exits) { if ((s == "compass4") || (s == "compass8")) { if (!query_exit("north")) add_exit("north", "/topography", other_types); if (!query_exit("south")) add_exit("south", "/topography", other_types); if (!query_exit("east")) add_exit("east", "/topography", other_types); if (!query_exit("west")) add_exit("west", "/topography", other_types); if (s == "compass8") { if (!query_exit("northeast")) add_exit("northeast", "/topography", other_types); if (!query_exit("northwest")) add_exit("northwest", "/topography", other_types); if (!query_exit("southeast")) add_exit("southeast", "/topography", other_types); if (!query_exit("southwest")) add_exit("southwest", "/topography", other_types); } } else { add_exit(s, "/topography", other_types); } } } /* add_topo_exits() */