/*    /lib/room/exits.c
 *    from the Dead Souls LPC Library
 *    handles players exiting from rooms
 *    created by Descartes of Borg 940711
 *    modified for new inheritance structure by Descartes 950208
 *    Version: @(#) exits.c 1.12@(#)
 *    Last Modified: 96/12/23
 */

#include <lib.h>
#include <rooms.h>
#include <position.h>
#include "include/exits.h"

private static string Obvious, GoMessage, EnterMessage, Dir, Sky;
private static mapping Exits, Doors;

static void create() {
    Exits = ([]);
    Doors = ([]);
    Obvious = "";
    Dir = "/" + implode(explode(file_name(), "/")[0..<2], "/");
    GoMessage = "You go nowhere at all.\n";
    EnterMessage = "You can't enter that!\n";
}

mixed CanGo(object who, string str) {
    if( (int)who->GetParalyzed() ) return "You are unable to move.";
    if( !Exits[str] ) return GoMessage;
    else return 1;
}

mixed eventGo(object who, string str) {
    if(query_verb() == "go" && interactive(this_player())){	
	if( who->GetPosition() != POSITION_STANDING ) {
	    if(stringp(hobbled(this_player()))) who->eventStand();
	    if( who->GetPosition() != POSITION_STANDING ) {
		return 0;
	    }
	}
    }
    else if(query_verb() == "crawl") {
	if( who->GetPosition() != POSITION_LYING &&
	  who->GetPosition() != POSITION_SITTING ) {
	    return 0;
	}
    }
    else if(query_verb() == "fly") {
	if( who->GetPosition() != POSITION_FLYING )
	    return 0;
    }

    if( sizeof(Doors) && Doors[str] && (int)Doors[str]->GetClosed() ) {
	message("my_action", "You bump into " + 
	  (string)Doors[str]->GetShort(str) + ".", who);
	return 1;
    }
    if( Exits[str] && Exits[str]["pre"] && 
      !((int)evaluate(Exits[str]["pre"], str)) )
	return 1;
    if(!Exits[str]){
	write("You can't go that way.");
	return 0;
    }
    who->eventMoveLiving(Exits[str]["room"], str);
    if( Exits[str]["post"] ) evaluate(Exits[str]["post"], str);
    return 1;
}

mixed GetDoor(string dir) {
    if(sizeof(Doors)) return Doors[dir];
    else return 0;
}

string array GetDoors() {
    return keys(Doors);
}

string SetDoor(string dir, string file) {
    object ob = GetDummyItem(dir);

    if( ob ) {
	ob->SetDoor(file);
    }

    if(!file_exists(file) && !file_exists(file+".c")){
	return "Door not found.";
    }
    file->eventRegisterSide(dir);
    return (Doors[dir] = file); 
}

varargs string CreateDoor(string dir, string odir, string long, string locked, string key){
    object new_door = new(LIB_DOOR);
    string doorfile = file_name(new_door);
    object ob = GetDummyItem(dir);
    if(!locked) locked = "";
    if( ob ) {
	ob->SetDoor(doorfile);
    }
    new_door->SetSide(dir, ([ "id" : ({"door", dir+" door", long}), "short" : "a door leading "+dir, "long" : long, "lockable" : 1 ]));
    new_door->SetSide(odir, ([ "id" : ({"door", odir+" door", long}), "short" : "a door leading "+odir, "long" : long, "lockable" : 1 ]));
    if(key) new_door->SetKeys(dir, ({ key }) );
    if(key) new_door->SetKeys(odir, ({ key }) );
    new_door->eventRegisterSide(dir);
    return (Doors[dir] = doorfile);
}

string GetDirection(string dest) {

    foreach(string dir, mapping data in Exits) {
	if( data["room"] == dest ) {
	    return "go " + dir;
	}
    }
    foreach(string dir in GetEnters()) {
	mapping data = GetEnterData(dir);

	if(data["room"] && data["room"] == dest ) {
	    return "enter " + dir;
	}
    }
    return 0;
}

object GetDummyItem(mixed id) {
    int i;
    object array dummies,all_inv;

    all_inv=all_inventory();
    dummies = ({});

    for(i=0; i<sizeof(all_inv); i++) {
	if ( (mixed)all_inv[i]->isDummy() )  dummies += ({ all_inv[i] });
    }
    if( stringp(id) ) {
	id = ({ id });
    }
    if(arrayp(id)){
	foreach(object dummy in dummies) {
	    foreach(string element in id){
		if(answers_to(element,dummy)) return dummy;
	    }
	}
    }
    return 0;
}

varargs void AddEnter(string dir, string dest, function pre, function post) {
    object ob = GetDummyItem(dir);

    ob->SetEnter(dest, pre, post);
}

string GetEnter(string dir) {
    object ob = GetDummyItem(dir);

    if( !ob ) {
	return 0;
    }
    else {
	return ob->GetEnter();
    }
}

static mapping GetEnterData(string dir) {
    object ob = GetDummyItem(dir);

    if( !ob ) {
	return 0;
    }
    else {
	return ob->GetEnterData();
    }
}

varargs string array GetEnters(int i) {
    object *obs;
    string *ids;

    obs = ({});
    ids = ({});

    foreach(object item in all_inventory(this_object())){
	if(base_name(item) == LIB_DUMMY){
	    obs += ({ item });
	}
    }

    foreach(object ob in obs) {
	if( ob->GetEnter() ) {
	    if(i) ids += ({ ob->GetId()[0] });
	    else ids += ob->GetId();
	}
    }
    return ids;
}

mapping GetEnterMap(){
    mixed schlussel;
    mapping EnterMap = ([]);
    object *obs = ({});
    foreach(object item in all_inventory(this_object())){
	if(base_name(item) == LIB_DUMMY){
	    obs += ({ item });
	}
    }
    if(!sizeof(obs)) return ([]);
    foreach(object ob in obs) {
	if( ob->GetEnter() ) {
	    schlussel = ob->GetId();
	    EnterMap[schlussel] = ob->GetEnter();
	}
    }
    return copy(EnterMap);
}

void RemoveEnter(string dir) {
    object ob = GetDummyItem(dir);

    ob->SetEnter(0);
}

void SetEnters(mapping mp) {
    foreach(mixed dir, mixed room_or_arr in mp) {
	object ob = GetDummyItem(dir);

	if( arrayp(room_or_arr) ) {
	    ob->SetEnter(room_or_arr...);
	}
	else {
	    ob->SetEnter(room_or_arr);
	}
    }
}

string GetEnterMessage() {
    return EnterMessage[0..<2];
}

string SetEnterMessage(string str) {
    return (EnterMessage = str + "\n");
}

varargs mapping AddExit(string dir, string dest, function pre, function post) {
    if(!stringp(dir)) error("Bad argument 1 to AddExit().\n");
    if(!stringp(dest)) error("Bad argument 2 to AddExit().\n");
    dest = ResolveObjectName(dest);
    Exits[dir] = ([ "room" : dest  ]);
    if( functionp(pre) ) Exits[dir]["pre"] = pre;
    if( functionp(post) ) Exits[dir]["post"] = post;
    return Exits[dir];
}

string GetExit(string str) {
    if(!Exits[str]) return 0;
    else return Exits[str]["room"];
}

mapping GetExitData(string str) {
    return Exits[str];
}

mapping GetFullExitData() {
    return Exits;
}

mapping GetExitMap() {
    mapping ret = ([]);
    foreach(string key in keys(Exits)){
	ret[key] = Exits[key]["room"];
    }  

    return ret;
}

string array GetExits() {
    return keys(Exits);
}

mapping RemoveExit(string dir) {
    if(Exits[dir]) map_delete(Exits, dir);
}

mapping SetExits(mapping mp) {
    mixed room_or_arr, dir;

    Exits = ([]);
    foreach(dir, room_or_arr in mp) {
	if( arrayp(dir) ) {
	    string real_dir;

	    foreach(real_dir in dir) {
		if( arrayp(room_or_arr) ) AddExit(real_dir, room_or_arr...);
		else AddExit(real_dir, room_or_arr);
	    }
	}
	else {
	    if( stringp(room_or_arr) ) AddExit(dir, room_or_arr);
	    else if( arrayp(room_or_arr) ) AddExit(dir, room_or_arr...);
	}
    }
    return Exits;
}

string GetGoMessage() {
    return GoMessage[0..<2];
}

string SetGoMessage(string str) {
    return (GoMessage = str + "\n");
}

string GetObviousExits() {
    return Obvious;
}

string SetObviousExits(string str) {
    return (Obvious = str);
}

string GetSky() {
    return Sky;
}

string SetSky(string str) {
    return (Sky = str);
}

string ResolveObjectName(string file) {
    if( file[<2..] == ".c" ) file = file[0..<3];
    return absolute_path(Dir, file);
}
