// room.c Modify by Yu Jue 1998-3-16

#pragma save_binary

#include <dbase.h>
#include <room.h>

inherit F_DBASE;
inherit F_CLEAN_UP;

static mapping doors;


int query_max_encumbrance() { return 2000000000; }

object make_inventory(string file)
{
	object ob;

	file = resolve_path(0, file);
	ob = unew(file);
	if (ob) {
		ob->move(this_object());
		ob->set("startroom", base_name(this_object()));
	} else ob = filter_array( children(file), (: clonep :) )[<1];
	return ob;
}

void reset()
{
	mapping ob_list, ob;
	string *list;
	int i,j;
	object *obs;
	//
	// Check loaded objects to match the objects specified in "objects"
	// while query("objects") is 
	// ([ <object filename>: <amount>, ..... ])
	// and query_temp("objects") is
	// ([ <object filename>: ({ob1, ob2, ...}), .... ])
	//
	// 清除垃圾 Designed by Yu Jue 1998-3-16
	obs = all_inventory();
	i = sizeof(obs);
	while (i--)
		if (obs[i] && !obs[i]->query("location") && !obs[i]->is_character()
				&& obs[i]->query("startroom") != base_name(this_object())) {
			message_vision("$N被一阵风卷走了。\n", obs[i]);
			destruct(obs[i]);
		}
	ob_list = query("objects");//先取出一个这个房间初始设定的objects的映射集
	if( !mapp(ob_list) ) return;//如果这个房间初始时就没有设定有生物物品，就说明根本无需要刷新，因此到此返回

	if( !mapp(ob = query_temp("objects")) )
		ob = allocate_mapping(sizeof(ob_list));
	list = keys(ob_list);
	for(i=0; i<sizeof(list); i++) {
		// Allocate an array if we have multiple same object specified.
              //如果房间里曾经定义了要产生物品，并且数量不止一个的话，就要进行ob[list[i]]这个物件数组的内存分配
		if(     undefinedp(ob[list[i]])
				&&      intp(ob_list[list[i]])
				&&      ob_list[list[i]] > 1 )
			ob[list[i]] = allocate(ob_list[list[i]]);

		switch(ob_list[list[i]]) {
			case 1:
				//if( !ob[list[i]] ) ob[list[i]] = make_inventory(list[i]);//如果这一个对象已经不在了（玩家理解的就是被杀死了或被当作任务送掉了，巫师的理解就是被destruct了），就使用make_inventory()函数再重新制造一个放进来
                            if( !ob[list[i]] ) ob[list[i]] = make_inventory(list[i]);
                          //反之如果还存在，但它目前所处之地却不是目前的这个房间,递过去的list[i]就是这一项物品的路径名
				else if( environment(ob[list[i]]) != this_object()
						&& !ob[list[i]]->query("location")
						&& !ob[list[i]]->return_home(this_object())
						&& !ob[list[i]]->is_character()) {
					// 如果 NPC 不在房间也不变新的出来 Yuj 19991115
					ob[list[i]] = make_inventory(list[i]);
				}
				break;
                   //除此之外，也就是物件不止一个的话，举例相当于文件里：set("objects",(["/d/city/npc/bing":2]))或者3,4....这类的情况
			default:
				for(j=0; j<ob_list[list[i]]; j++) {
					// If the object is gone, make another one.
					if( !objectp(ob[list[i]][j]) ) {
						ob[list[i]][j] = make_inventory(list[i]);
						continue;
					}
					// Try to call the wandering npc come back here.
					if( environment(ob[list[i]][j]) != this_object()
							&& !ob[list[i]][j]->query("location")
							&& !ob[list[i]][j]->return_home(this_object())
							&& !ob[list[i]][j]->is_character()) {
						// 如果 NPC 不在房间也不变新的出来 Yuj 19991115
									ob[list[i]][j] = make_inventory(list[i]);
					}
				}
		}
	}
	set_temp("objects", ob);
}

// Redirect item_desc of the door to this function in default.
string look_door(string dir)
{
	if( !mapp(doors) || undefinedp(doors[dir]) )
		return "你要看什么？\n";
	if( doors[dir]["status"] & DOOR_CLOSED )
		return "这个" + doors[dir]["name"] + "是关着的。\n";
	return "这个" + doors[dir]["name"] + "是开着的。\n";
}

varargs int open_door(string dir, int from_other_side)
{
	mapping exits;
	object ob;

	if( !mapp(doors) || undefinedp(doors[dir]) )
		return notify_fail("这个方向没有门。\n");

	if( !(doors[dir]["status"] & DOOR_CLOSED) )
		return notify_fail( doors[dir]["name"] + "已经是开着的了。\n");

	exits = query("exits");
	if( !mapp(exits) || undefinedp(exits[dir]) )
		error("Room: open_door: attempt to open a door with out an exit.\n");

	if( from_other_side )
		message("vision", "有人从另一边将" + doors[dir]["name"] + "打开了。\n", this_object());
	else if( objectp(ob = find_object(exits[dir])) ) {
		if( !ob->open_door(doors[dir]["other_side_dir"], 1) ) return 0;
	}

	doors[dir]["status"] &= (!DOOR_CLOSED);
	return 1;
}

varargs int close_door(string dir, int from_other_side)
{
	mapping exits;
	object ob;

	if( !mapp(doors) || undefinedp(doors[dir]) )
		return notify_fail("这个方向没有门。\n");

	if( (doors[dir]["status"] & DOOR_CLOSED) )
		return notify_fail( doors[dir]["name"] + "已经是关着的了。\n");

	exits = query("exits");
	if( !mapp(exits) || undefinedp(exits[dir]) )
		error("Room: close_door: attempt to open a door with out an exit.\n");

	if( from_other_side )
		message("vision", "有人从另一边将" + doors[dir]["name"] + "关上了。\n", this_object());
	else if( objectp(ob = find_object(exits[dir])) ) {
		if( !ob->close_door(doors[dir]["other_side_dir"], 1) ) return 0;
	}

	doors[dir]["status"] |= DOOR_CLOSED;
	return 1;
}

int check_door(string dir, mapping door)
{
	// If we have no responding door, assume it is correct.
	if( !mapp(doors) || undefinedp(doors[dir]) ) return 1;

	door["status"] = doors[dir]["status"];
	return 1;
}

varargs void create_door(string dir, mixed data, string other_side_dir, int status)
{
	mapping d, exits;
	object ob;

	exits = query("exits");
	if( !mapp(exits) || undefinedp(exits[dir]) )
		error("Room: create_door: attempt to create a door without exit.\n");

	// Compact mode.
	if( stringp(data) ) {
		d = allocate_mapping(4);
		d["name"] = data;
		d["id"] = ({ dir, data, "door" });
		d["other_side_dir"] = other_side_dir;
		d["status"] = status;
	} else if( mapp(data) )
		d = data;
	else
		error("Create_door: Invalid door data, string or mapping expected.\n");

	set("item_desc/" + dir, (: look_door, dir :) );

	if( objectp(ob = find_object(exits[dir])) ) {
		if( !ob->check_door(other_side_dir, d) )
			return;
	}

	if( !mapp(doors) ) doors = ([ dir: d ]);
	else doors[dir] = d;
}

mapping query_doors() { return doors; }

mixed query_door(string dir, string prop)
{
	if( !mapp(doors) || undefinedp(doors[dir]) ) return 0;
	else return doors[dir][prop];
}

int valid_leave(object me, string dir)
{
	if( mapp(doors) && !undefinedp(doors[dir]) ) {
		if( doors[dir]["status"] & DOOR_CLOSED )
			return notify_fail("你必须先把" + doors[dir]["name"] + "打开！\n");
		// if ( door[dir]["status"] & DOOR_HAS_TRAP ) ....
	}
	return 1;
}

void setup()
{
	seteuid(getuid());
	this_object()->reset();
}

