#include "copyright.h"

/* Commands that create new objects */

#include "db.h"
#include "config.h"
#include "interface.h"
#include "externs.h"

/* utility for open and link */
static dbref parse_linkable_room(dbref player, object_flag_type thing,
				 const char *room_name)
{
    dbref room;

    /* skip leading NUMBER_TOKEN if any */
    if(*room_name == NUMBER_TOKEN) room_name++;

    /* parse room */
    if(!string_compare(room_name, "here")) {
	room = db[player].location;
    } else if(!string_compare(room_name, "home")) {
	return HOME;		/* HOME is always linkable */
    } else {
	room = parse_dbref(room_name);
    }

    /* check room */
    if(room < 0 || room >= db_top
       || Typeof(room) != TYPE_ROOM) {
	notify(player, "That's not a room!");
	return NOTHING;
    } else if(!can_link_to(player, thing, room)) {
	notify(player, "You can't link to that.");
	return NOTHING;
    } else {
	return room;
    }
}

/* use this to create an exit */
void do_open(dbref player, const char *direction, const char *linkto)
{
    dbref loc;
    dbref exit;

#ifdef RESTRICTED_BUILDING
    if(!Builder(player)) {
	notify(player, "That command is restricted to authorized builders.");
	return;
    }
#endif /* RESTRICTED_BUILDING */

    if((loc = getloc(player)) == NOTHING) return;
    if(!*direction) {
	notify(player, "Open where?");
	return;
    } else if(!ok_name(direction)) {
	notify(player, "That's a strange name for an exit!");
	return;
    }

    if(!controls(player, loc)) {
	notify(player, "Permission denied.");
    } else if(!payfor(player, EXIT_COST)) {
	notify(player,
	       "Sorry, you don't have enough pennies to open an exit.");
    } else {
	/* create the exit */
	exit = new_object();

	/* initialize everything */
	db[exit].name = alloc_string(direction);
	db[exit].owner = player;
	db[exit].flags = TYPE_EXIT;

	/* link it in */
	PUSH(exit, db[loc].exits);

	/* and we're done */
	notify(player, "Opened.");

	/* check second arg to see if we should do a link */
	if(*linkto != '\0') {
	    notify(player, "Trying to link...");
	    if((loc = parse_linkable_room(player, TYPE_EXIT, linkto)) !=
	       NOTHING) {
		if(!payfor(player, LINK_COST)) {
		    notify(player, "You don't have enough pennies to link.");
		} else {
		    /* it's ok, link it */
		    db[exit].location = loc;
		    notify(player, "Linked.");
		}
	    }
	}
    }
}

/* use this to link to a room that you own */
/* it seizes ownership of the exit */
/* costs 1 penny */
/* plus a penny transferred to the exit owner if they aren't you */
/* you must own the linked-to room AND specify it by room number */
void do_link(dbref player, const char *name, const char *room_name)
{
    dbref thing;
    dbref room;

    init_match(player, name, TYPE_EXIT);
    match_exit();
    match_neighbor();
    match_possession();
    match_me();
    match_here();
    if(Wizard(player)) {
	match_absolute();
	match_player();
    }

    if((thing = noisy_match_result()) != NOTHING) {
	if((room = parse_linkable_room(player, Typeof(thing), room_name)) ==
	   NOTHING)
	    return;
	switch(Typeof(thing)) {
	  case TYPE_EXIT:
	    /* we're ok, check the usual stuff */
	    if(db[thing].location != NOTHING) {
		if(controls(player, thing)) {

		    /*
		     * Changed 5/18/90 Fuzzy - exits linked to *home*
		     * break 'Typeof() call'
		     */

		    if(db[thing].location >= 0 &&
		       Typeof(db[thing].location) == TYPE_PLAYER) {
			notify(player, "That exit is being carried.");
		    } else {
			notify(player, "That exit is already linked.");
		    }
		} else {
		    notify(player, "Permission denied.");
		}
	    } else {
		/* handle costs */
		if(db[thing].owner == player) {
		    if(!payfor(player, LINK_COST)) {
			notify(player,
			       "It costs a penny to link this exit.");
			return;
		    }
		} else {
		    if(!payfor(player, LINK_COST + EXIT_COST)) {
			notify(player,
			       "It costs two pennies to link this exit.");
			return;
#ifdef RESTRICTED_BUILDING
		    } else if(!Builder(player)) {
			notify(player,
			       "Only authorized builders may seize exits.");
#endif /* RESTRICTED_BUILDING */			
		    } else {
			/* pay the owner for his loss */
			db[db[thing].owner].pennies += EXIT_COST;
		    }
		}

		/* link has been validated and paid for; do it */
		db[thing].owner = player;
		db[thing].location = room;

		/* notify the player */
		notify(player, "Linked.");
	    }
	    break;
	  case TYPE_PLAYER:
	  case TYPE_THING:
	    if(!controls(player, thing)) {
		notify(player, "Permission denied.");
	    } else if(room == HOME) {
		notify(player, "Can't set home to home.");
	    } else {
		/* do the link */
		db[thing].exits = room; /* home */
		notify(player, "Home set.");
	    }
	    break;
	  case TYPE_ROOM:
	    if(!controls(player, thing)) {
		notify(player, "Permission denied.");
	    } else {
		/* do the link, in location */
		db[thing].location = room; /* dropto */
		notify(player, "Dropto set.");
	    }
	    break;
	  default:
	    notify(player, "Internal error: weird object type.");
	    writelog("PANIC weird object: Typeof(%d) = %d\n",
		    thing, Typeof(thing));
	    break;
	}
    }
}

/* use this to create a room */
void do_dig(dbref player, const char *name)
{
    dbref room;
    char buf[BUFFER_LEN];

#ifdef RESTRICTED_BUILDING
    if(!Builder(player)) {
	notify(player, "That command is restricted to authorized builders.");
	return;
    }
#endif /* RESTRICTED_BUILDING */

    /* we don't need to know player's location!  hooray! */
    if(*name == '\0') {
	notify(player, "Dig what?");
    } else if(!ok_name(name)) {
	notify(player, "That's a silly name for a room!");
    } else if(!payfor(player, ROOM_COST)) {
	notify(player, "Sorry, you don't have enough pennies to dig a room.");
    } else {
	room = new_object();

	/* Initialize everything */
	db[room].name = alloc_string(name);
	db[room].owner = player;
	db[room].flags = TYPE_ROOM;

	sprintf(buf, "%s created with room number %d.", name, room);
	notify(player, buf);
    }
}

/* use this to create an object */
void do_create(dbref player, char *name, int cost)
{
    dbref loc;
    dbref thing;

#ifdef RESTRICTED_BUILDING
    if(!Builder(player)) {
	notify(player, "That command is restricted to authorized builders.");
	return;
    }
#endif /* RESTRICTED_BUILDING */

    if(*name == '\0') {
	notify(player, "Create what?");
	return;
    } else if(!ok_name(name)) {
	notify(player, "That's a silly name for a thing!");
	return;
    } else if(cost < 0) {
	notify(player, "You can't create an object for less than nothing!");
	return;
    } else if(cost < OBJECT_COST) {
	cost = OBJECT_COST;
    }

    if(!payfor(player, cost)) {
	notify(player, "Sorry, you don't have enough pennies.");
    } else {
	/* create the object */
	thing = new_object();

	/* initialize everything */
	db[thing].name = alloc_string(name);
	db[thing].location = player;
	db[thing].owner = player;
	db[thing].pennies = OBJECT_ENDOWMENT(cost);
	db[thing].flags = TYPE_THING;

	/* endow the object */
	if(db[thing].pennies > MAX_OBJECT_ENDOWMENT) {
	    db[thing].pennies = MAX_OBJECT_ENDOWMENT;
	}

	/* home is here (if we can link to it) or player's home */
	if((loc = db[player].location) != NOTHING
	   && controls(player, loc)) {
	    db[thing].exits = loc;	/* home */
	} else {
	    db[thing].exits = db[player].exits;	/* home */
	}

	/* link it in */
	PUSH(thing, db[player].contents);

	/* and we're done */
	notify(player, "Created.");
    }
}

#ifdef REGISTRATION
void do_pcreate (dbref player, char *newplayer, char *newpass)
{
    dbref ptmp;

#ifdef GOD_MODE && GOD_ONLY_PCREATE
    if (!God(player))
#ifndef TINKER
        notify (player, "Only GOD can create a new player.");
#else TINKER
        notify (player, "Only the Master Tinker can create a new player.");
#endif TINKER
#else GOD_MODE && GOD_ONLY_PCREATE
    if (!Wizard(player))
#ifndef TINKER
	notify (player, "Only a Wizard can create a new player.");
#else TINKER
	notify (player, "Only a Tinker can create a new player.");
#endif TINKER
#endif GOD_MODE && GOD_ONLY_PCREATE
    else if (!*newplayer || !*newpass)
	notify (player, "You must specify name and password.");
    else {
        ptmp = create_player (newplayer, newpass);
	if (ptmp == NOTHING) {
	    notify(player, "Either there is already a player with that name, or that name is illegal.");
	    writelog("FAILED CREATE %s by %s\n",newplayer,db[player].name);
	} else {
	    char buf[512];
	    sprintf(buf, "%s created as object #%d.",db[ptmp].name,ptmp);
	    notify(player, buf);
	    writelog("CREATED %s(%d) by %s\n",db[ptmp].name,ptmp,
		     db[player].name);
	}
    }
}
#endif REGISTRATION