/* create.c */
/* Commands that create new objects */
#include "os.h"
#include "config.h"
#include "db.h"
#include "attrib.h"
#include "interface.h"
#include "externs.h"
#include "match.h"
/* utility for open and link */
static dbref parse_linkable_room (dbref player, 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) {
notify (player, "That is not a valid object.");
return NOTHING;
} else if (!can_link_to (player, room)) {
notify (player, "You can't link to that.");
return NOTHING;
} else {
return room;
}
}
/* use this to create an exit */
static int do_real_open (dbref player, const char *direction, const char *linkto, dbref pseudo /* a phony location for a player if a back
* exit is needed */
)
{
dbref loc = (pseudo != NOTHING) ? pseudo : db[player].location;
dbref exit;
if ((loc == NOTHING) || (Typeof (loc) != TYPE_ROOM)) {
notify (player, "Sorry you can only make exits out of rooms.");
return 0;
}
#ifdef RESTRICTED_BUILDING
if (!Builder (player)) {
notify (player, "That command is restricted to authorized builders.");
return 0;
}
#endif /* RESTRICTED_BUILDING */
#ifdef GUEST_RESTRICT
if (Guest (player)) {
notify (player, "Guests are not allowed to build.");
return 0;
}
#endif
if (!*direction) {
notify (player, "Open where?");
return 0;
} else if (!ok_name (direction)) {
notify (player, "That's a strange name for an exit!");
return 0;
}
if (!controls (player, loc)) {
notify (player, "Permission denied.");
} else if (can_pay_fees (player, EXIT_COST)) {
/* create the exit */
exit = new_object ();
/* initialize everything */
SET (db[exit].name, direction);
db[exit].owner = db[player].owner;
db[exit].zone = db[player].zone;
db[exit].flags = TYPE_EXIT;
db[exit].exits = loc;
/* 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 && *linkto != '\0') {
notify (player, "Trying to link...");
if ((loc = parse_linkable_room (player, linkto)) != NOTHING) {
if (!payfor (player, LINK_COST)) {
notify (player, tprintf ("You don't have enough %s to link.",
MONIES));
} else {
/* it's ok, link it */
db[exit].location = loc;
notify (player, "Linked.");
}
}
}
return exit;
}
return 0;
}
void do_open (dbref player, const char *direction, char *links[])
{
do_real_open (player, direction, links[1], NOTHING);
if (links[2]) {
do_real_open (player, links[2], tprintf ("%d", db[player].location),
parse_linkable_room (player, links[1]));
}
}
/* 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;
if (Typeof (db[player].location) == TYPE_EXIT) {
notify (player, "You somehow wound up in a exit. No biscuit.");
return;
}
init_match (player, name, TYPE_EXIT);
match_exit ();
match_neighbor ();
match_possession ();
match_me ();
match_here ();
match_absolute ();
match_player ();
if ((thing = noisy_match_result ()) != NOTHING) {
switch (Typeof (thing)) {
case TYPE_EXIT:
if ((room = parse_linkable_room (player, room_name)) == NOTHING)
return;
if ((room != HOME) &&
!controls (player, room) && !(db[room].flags & LINK_OK)) {
notify (player, "Permission denied.");
break;
}
/* we're ok, check the usual stuff */
if (db[thing].location != NOTHING) {
if (controls (player, thing)) {
if (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 == db[player].owner) {
if (!payfor (player, LINK_COST)) {
notify (player, tprintf ("It costs %d %s to link this exit.",
LINK_COST, ((LINK_COST == 1) ? MONEY : MONIES)));
return;
}
} else {
if (!payfor (player, LINK_COST + EXIT_COST)) {
int a = LINK_COST + EXIT_COST;
notify (player, tprintf ("It costs %d %s to link this exit.",
a, ((a == 1) ? MONEY : MONIES)));
return;
#ifdef RESTRICTED_BUILDING
} else if (!Builder (player)) {
notify (player, "Only authorized builders may seize exits.");
#endif /* RESTRICTED_BUILDING */
#ifdef GUEST_RESTRICT
} else if (Guest (player)) {
notify (player, "Guests are not allowed to build.");
#endif
} else {
/* pay the owner for his loss */
giveto (db[thing].owner, EXIT_COST);
}
}
/* link has been validated and paid for; do it */
db[thing].owner = db[player].owner;
db[thing].zone = db[player].zone;
db[thing].location = room;
/* notify the player */
notify (player, "Linked.");
}
break;
case TYPE_PLAYER:
case TYPE_THING:
init_match (player, room_name, NOTYPE);
match_exit ();
match_neighbor ();
match_possession ();
match_me ();
match_here ();
match_absolute ();
match_player ();
if ((room = noisy_match_result ()) < 0) {
notify (player, "No match.");
return;
}
if (Typeof (room) == TYPE_EXIT) {
notify (player, "That is an exit.");
return;
}
/* abode */
if (!controls (player, room) && !IS (room, TYPE_ROOM, ROOM_ABODE)) {
notify (player, "Permission denied.");
break;
}
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 ((room = parse_linkable_room (player, room_name)) == NOTHING)
return;
if (Typeof (room) != TYPE_ROOM) {
notify (player, "That is not a room!");
return;
}
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.");
fprintf (stderr, "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, char *argv[])
{
dbref room;
#ifdef RESTRICTED_BUILDING
if (!Builder (player)) {
notify (player, "That command is restricted to authorized builders.");
return;
}
#endif /* RESTRICTED_BUILDING */
#ifdef GUEST_RESTRICT
if (Guest (player)) {
notify (player, "Guests are not allowed to build.");
return;
}
#endif
/* 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 (can_pay_fees (player, ROOM_COST)) {
room = new_object ();
/* Initialize everything */
SET (db[room].name, name);
db[room].owner = db[player].owner;
db[room].zone = db[player].zone;
db[room].flags = TYPE_ROOM;
notify (player, tprintf ("%s created with room number %d.", name, room));
if (argv[1] && *argv[1]) {
char nbuff[MAX_COMMAND_LEN];
sprintf (nbuff, "%d", room);
do_real_open (player, argv[1], nbuff, NOTHING);
}
if (argv[2] && *argv[2]) {
char nbuff[MAX_COMMAND_LEN];
sprintf (nbuff, "%d", db[player].location);
do_real_open (player, argv[2], nbuff, room);
}
}
}
/* use this to create an object */
void do_create (dbref player, char *name, int cost)
{
dbref loc;
dbref thing;
#ifndef FREE_OBJECTS
#ifdef RESTRICTED_BUILDING
if (!Builder (db[player].owner)) {
notify (player, "That command is restricted to authorized builders.");
return;
}
#endif /* RESTRICTED_BUILDING */
#endif /* FREE_OBJECTS */
#ifdef GUEST_RESTRICT
if (Guest (player)) {
notify (player, "Guests are not allowed to build.");
return;
}
#endif
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 < OBJECT_COST) {
cost = OBJECT_COST;
}
if (can_pay_fees (player, cost)) {
/* create the object */
thing = new_object ();
/* initialize everything */
SET (db[thing].name, name);
db[thing].location = player;
db[thing].owner = db[player].owner;
db[thing].zone = db[player].zone;
s_Pennies (thing, OBJECT_ENDOWMENT (cost));
db[thing].flags = TYPE_THING;
/* endow the object */
if (Wizard (player)) {
if (Pennies (thing) > MAX_WIZ_OBJECT_ENDOWMENT)
s_Pennies (thing, MAX_WIZ_OBJECT_ENDOWMENT);
} else if (Pennies (thing) > MAX_OBJECT_ENDOWMENT)
s_Pennies (thing, 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) || IS (loc, TYPE_ROOM, ROOM_ABODE))) {
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, tprintf ("Created: Object #%d.", thing));
}
}
void do_clone (dbref player, char *name)
{
dbref clone, thing;
#ifdef GUEST_RESTRICT
if (Guest (player)) {
notify (player, "Guests are not allowed to build.");
return;
}
#endif
init_match (player, name, NOTYPE);
match_everything ();
thing = noisy_match_result ();
if ((thing == NOTHING))
return;
if (!controls (player, thing)) {
notify (player, "Permission denied.");
return;
}
/* don't allow cloning of destructed things */
if (db[thing].flags & GOING) {
notify (player, "There's nothing left of it to clone!");
return;
}
/* make sure owner can afford it */
if (can_pay_fees (player, OBJECT_COST)) {
switch (Typeof (thing)) {
case TYPE_THING:
#ifdef RESTRICTED_BUILDING
#ifndef FREE_OBJECTS
if (!Builder (player)) {
notify (player, "Command is for builders only.");
return;
}
#endif
#endif
clone = new_object ();
memcpy (&db[clone], &db[thing], sizeof (struct object));
db[clone].name = NULL;
SET (db[clone].name, db[thing].name);
s_Pennies (clone, 1);
atr_cpy (clone, thing);
db[clone].key = dup_bool (db[thing].key);
db[clone].contents = db[clone].location = db[clone].next = NOTHING;
db[clone].flags &= ~WIZARD;
#ifdef ROYALTY_FLAG
db[clone].flags &= ~ROYALTY;
#endif
notify (player, tprintf ("Cloned: Object #%d.", clone));
moveto (clone, db[player].location);
did_it (player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING);
break;
case TYPE_EXIT:
#ifdef RESTRICTED_BUILDING
if (!Builder (player)) {
notify (player, "Command is for builders only.");
return;
}
#endif
clone = do_real_open (player, db[thing].name, tprintf ("%d",
db[thing].location), NOTHING);
atr_cpy (clone, thing);
db[clone].key = dup_bool (db[thing].key);
db[clone].flags &= ~WIZARD;
notify (player, "Exit cloned.");
break;
default:
notify (player, "You can only clone things and exits.");
}
}
}