/**
* The overall room inherit for a 'mapped area'
* all mapped area rooms should inherit from this.
* <p>
* MUST OVERRIDE:
* <p>
* query_map_file()
* @author Dek
* @started March 2001
*/
#include <room.h>
#include <login_handler.h>
private int _x_coord = -1;
private int _y_coord = -1;
private int _installed = 0;
private string _extra_long = "";
private object _map_handler;
private mapping _features = ([ ]);
private string _outside_types;
string query_feature_item_desc(string title);
int do_gocoords(int x, int y);
void add_extra_look(object ob);
void setup_room_chat();
object query_chatter();
varargs void room_chat(mixed* args, object chatob);
void add_item(mixed type, mixed desc);
void remove_item(string name);
/**
* This method returns the co-ordinates of this room.
*/
mixed *query_coords() { return ({ _x_coord, _y_coord }); }
// We set the coords to -1 -1 here, to account for rooms that are
// not virtual. Rooms that adjoin map areas need to inherit this
// file, hence the need to do this.
void create()
{
_x_coord = -1;
_y_coord = -1;
}
/**
* This needs to be called by the upper inherit to set us to womble.
*/
void setup_room() {
add_extra_look(this_object());
setup_room_chat();
} /* setup_room() */
/**
* Setup the main coordinates for this room. Please note that these
* are not DW coords, but local ones for the use of the handler.
*/
void set_coords(int x, int y)
{
_x_coord = x;
_y_coord = y;
}
void init()
{
tell_creator(this_player(), "Coords: (%d, %d)\n", _x_coord, _y_coord);
if (this_player()->query_creator()) {
add_command("gocoords", "<number'x'> <number'y'>", (: do_gocoords($4[0], $4[1]) :));
}
}
/**
* This method returns the map handler associated with this room.
*/
object query_map_handler()
{
return _map_handler;
}
/**
* This is a command used by creators to go to specific locations in the grid.
*/
int do_gocoords(int x, int y)
{
object room = query_map_handler()->load_room_at(x, y);
string msgin = this_player()->query_mmsgin();
string msgout = this_player()->query_mmsgout();
if (!room) {
this_player()->add_failed_mess(this_object(),
"No room at those coordinates.\n", ({ }));
return 0;
}
msgin = replace(msgin, ({ "$N", this_player()->a_short() }) );
msgout = replace(msgout, ({ "$N", this_player()->a_short() }) );
if (!this_player()->move_with_look(room, msgin, msgout))
add_succeeded_mess("Move attempt failed.\n");
return 1;
}
/**
* Added for convenience. BEWARE! When called, this will dest every single
* room in this terrain, dumping everything in the void. When I think of
* a decent way to handle this, I will.
*/
void reset_handler()
{
if (query_map_handler())
query_map_handler()->reset_handler();
}
/**
* Receive messages from the handler.
* @Param mess_class the class of the message
* @param message the actual message
*/
void receive_message(string mess_class, string message)
{
string *bits = explode(mess_class, ":");
mapping feature;
int range = -1;
if (bits[0] == "feature") {
feature = _features[bits[1]];
if (!feature)
return;
if (sizeof(bits) >= 3)
range = to_int(bits[2]);
if ((range >= 0) && (range != feature["range"]))
return;
message = replace(message, ({ "$D", feature["direc"] }));
}
tell_creator("dek", "receive_message\n");
tell_room(this_object(), message);
}
/**
* This makes one of the features in the terrain send us a chat.
*/
void do_a_feature_chat()
{
string *chats = ({ });
string feature_chat;
string title;
mapping feature;
object handler = query_map_handler();
foreach(title, feature in _features) {
feature_chat = handler->get_a_feature_chat(title, feature["range"],
feature["direc"]);
if (feature_chat) {
chats += ({ feature_chat });
}
}
if (sizeof(chats)) {
tell_room(this_object(), chats[random(sizeof(chats))] + "\n");
}
}
/**
* This method will print an outside chat.
*/
void do_an_outside_chat()
{
string chat = query_map_handler()->get_an_outside_chat(_outside_types);
if (chat && strlen(chat))
tell_room(this_object(), chat + "\n");
}
/**
* This sets the map handler, OBSOLETE. This should be done by overriding query_map_handler()
* in the main inherited file. It doesn't get set fast enough otherwise.
* @param handler the new handler
*/
void set_map_handler(mixed handler)
{
if (objectp(handler))
_map_handler = handler;
else
_map_handler = load_object(handler);
}
/**
* Checks to see if the feature can be viewed or not.
* @param type the type of the feature
* @return 1 if it can be seen
*/
int can_view_feature(string type)
{
return 1;
}
/**
* Can we go to rooms of type x? Override if you want to use it -
* 1 means yes.
* @param type the type of room to check
*/
int can_exit_to(string type)
{
return 1;
}
/**
* Can we enter from rooms of type x? Override if you want to use it -
* 1 means yes.
* @param type the type of room to check
*/
int can_enter_from(string type)
{
return 1;
}
/**
* Do we *want* outside and feature chats? Override if you want to use
* 1 means yes.
*/
int do_outside_chats()
{
return 1;
}
/**
* Setup the feature chats and basic room chats.
*/
varargs void setup_room_chat(mixed *args, object chatobj)
{
if (do_outside_chats() && !query_chatter()) {
room_chat(({ 60, 120, ({ "#do_a_feature_chat",
"#do_an_outside_chat" }) }) );
}
// For some reason, the chatting won't start if we don't kick-start it.
call_out("make_chat", 10);
}
// Kick-start the bloody chatter. Damn' thing won't do anything else.
/** @ignore yes */
void make_chat()
{
if (query_chatter()) {
query_chatter()->make_chat();
}
}
// override to generate modify_exits between rooms of various types.
/** @ignore yes */
mixed *query_to_same(string type) { return 0; }
/** @ignore yes */
mixed *query_to_other(string type) { return 0; }
/** @ignore yes */
mixed *query_from_other(string type) { return 0; }
// The next three are prettification functions for the above, and should
// never be called directly.
/** @ignore yes */
mixed *get_to_same(string from, string to, string type)
{
mixed *result = query_to_same(type);
if (arrayp(result))
return map(result, (: replace($1, ({ "$T", $2, "$F", $3 }) ) :), to, from);
return 0;
}
/** @ignore yes */
mixed *get_to_other(string from, string to, string type)
{
mixed *result = query_to_other(type);
if (arrayp(result))
return map(result, (: replace($1, ({ "$T", $2, "$F", $3 }) ) :), to, from);
return 0;
}
/** @ignore yes */
mixed *get_from_other(string from, string to, string type)
{
mixed *result = query_from_other(type);
if (arrayp(result))
return map(result, (: replace($1, ({ "$T", $2, "$F", $3 }) ) :), to, from);
return 0;
}
/**
* Called by the handler to set our extra_look strings.
*/
void set_extra_long(string extra)
{
_extra_long = extra;
}
void set_outside_types(string types)
{
_outside_types = types;
}
// This handles all the extra parts of the room desc which are
// inserted by the handler.
/** @ignore yes */
string extra_look()
{
string result = _extra_long;
string title;
mapping feature;
foreach (title, feature in _features) {
result += query_map_handler()->query_feature_desc(title, feature["range"],
feature["direc"]) + "\n";
}
return result;
}
// For internal use. Talks to the handler to convert a pathname of type:
// /w/dek/map.c:3:4 to something useable.
/** @ignore yes */
mixed query_room(string room_path)
{
string *bits = explode(room_path, ":");
object room;
object handler;
if (sizeof(bits) < 3)
return room_path;
room = load_object(bits[0]);
handler = room->query_map_handler();
return handler->query_room(room_path);
}
/**
* Add a new visible feature to the room, so it knows to query the handler
* for descriptions and so on. The zone info is needed as an easy way for
* the handler to get access to which rooms see which features.
* @param title the title of the feature
* @param direc the direction of the feature
* @param range the range to the feature
* @param items any add_items associated with the feature
*/
void add_feature(string title, string direc, int range, mixed items)
{
_features[title] = (["direc":direc, "range":range, "items":items]);
add_item(items, (: query_feature_item_desc($(title)) :));
}
/**
* Removes the specified feature.
* @param title the feature to remove
*/
void remove_feature(string title)
{
mapping feature = _features[title];
mixed items;
if (!feature)
return;
map_delete(_features, title);
items = feature["items"];
if (stringp(items))
remove_item(items);
else
remove_item(items[0]);
}
/**
* This figures out the range to the specified feature.
* @param title the name of the feature
*/
int query_feature_range(string title)
{
mapping feature = _features[title];
if (!feature)
return -1;
return feature["range"];
}
/**
* This method returns the item description for the feature.
* @param title the feature to look up
* @return the description of the feature
*/
string query_feature_item_desc(string title)
{
return query_map_handler()->query_feature_item_desc(title);
}
/**
* This method returns all of our features.
*/
mapping query_features() { return _features; }
// When someone logs into the room, see if they were previously in a
// virtual. If they were, put them back in the same location.
// coords are stored as a property, so remove it when done for neatness' sake.
/** @ignore yes */
void login_restore( string name, string l_event)
{
object player;
string path = explode(file_name(this_object()), "#")[0];
int *coords, x, y;
if (l_event != LOGIN)
return;
player = find_player(name);
if (!player)
return;
coords = player->query_property("area_map_coords");
player->remove_property("area_map_coords");
if (!coords)
return;
x = coords[0];
y = coords[1];
LOGIN_HANDLER->remove_static_login_call(name, "login_restore", path);
player->move(query_map_handler()->load_room_at(x, y));
}
// If someone quits here, and this is a virtual, store their coords in a
// property, and flag the login handler so it knows to talk to us when
// they return.
/** @ignore yes */
void event_quit(object player)
{
string name;
string path = explode(file_name(this_object()), "#")[0];
if (!player)
return;
if (!interactive(player))
return;
if ((_x_coord < 0) || (_y_coord < 0))
return;
name = player->query_name();
player->add_property("area_map_coords", query_coords());
LOGIN_HANDLER->add_static_login_call(name, "login_restore", path);
}
int query_installed() { return _installed; }
void set_installed() { _installed = 1; }