/*
** 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() */