/*
Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/
/* configure all options BEFORE including system stuff. */
#include "config.h"
#include "mud.h"
#include "match.h"
#include "look.h"
#include "vars.h"
static int player_destroy(char *who, char *aswho, char *ob, int wiz);
static int delete_xit(char *room, char *ex);
static int room_destroy(char *who, char *aswho, char *name, int wiz);
static int exit_destroy(char *who, char *aswho, char *name, int wiz);
static int object_destroy(char *who, char *aswho, char *name, int wiz);
static int home_object(char *who, char *what, char *msg, char *notthere);
/*
Object destruction.
*/
/* ARGSUSED */
int cmd_destroy (int ac, char *av[], char *who, char *aswho)
{
int wiz;
/* do help */
if (ac == 2 && !strcmp (av[1], "help")) {
say (who, av[0], " player player-obj\n", (char *) 0);
say (who, av[0], " exit exit-obj\n", (char *) 0);
say (who, av[0], " room room-obj\n", (char *) 0);
say (who, av[0], " object obj\n", (char *) 0);
return (UERR_NONE);
}
if (ac != 3) {
say (who, "I don't understand that use of \"", av[0], "\"!\n",
(char *) 0);
return (UERR_BADPARM);
}
wiz = ut_flagged (aswho, var_wiz);
if (!strcmp (av[1], "player"))
return (player_destroy (who, aswho, av[2], wiz));
else if (!strcmp (av[1], "exit"))
return (exit_destroy (who, aswho, av[2], wiz));
else if (!strcmp (av[1], "room"))
return (room_destroy (who, aswho, av[2], wiz));
else if (!strcmp (av[1], "object"))
return (object_destroy (who, aswho, av[2], wiz));
say (who, "I don't understand what you want me to destroy!\n", (char *) 0);
return (UERR_BADPARM);
}
/* destroy a player */
static int player_destroy (char *who, char *aswho, char *ob, int wiz)
{
char ply[MAXOID];
char *loc;
char *dp;
char nxtu[MAXOID];
/* start with some checks */
/* must be a wizard! */
if (!wiz) {
say (who, "Only wizards can destroy players\n", (char *) 0);
return (UERR_PERM);
}
/* find the player; unique, exact match required. #num is OK. */
if (matchplayers (who, ob, ut_loc (who), MTCH_UNIQ | MTCH_NONLOC, ply))
return (UERR_NOMATCH);
/* lets make sure its a player! */
if (!ut_flagged (ply, var_isplay)) {
say (who, ut_name (ply), " is not a player\n", (char *) 0);
return (UERR_BADOID);
}
/* can't destroy yourself */
if (!strcmp (ply, aswho))
/*
* gotos are only evil if used indiscriminately or
* if they branch backwards.
* Use for exception handling is kosher.
*/
goto fail;
/* ensure that the player is logged off */
say (ply, ut_name (who), " is destroying you. Goodbye!\n", (char *) 0);
/*
* note that "goodbye" must gracefully handle the
* player object not existing
*/
io_logoff (ply);
/* ok. fire away */
/* remove the player from the player list of its location */
loc = ut_loc (ply);
/* move the objects in the players contents list to their homes */
dp = ut_getatt (ply, 0, typ_list, var_cont, (char *) 0);
if (dp != (char *) 0) {
while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
if (home_object (who, nxtu, (char *) 0, ply)) {
goto fail;
}
}
/* send the "use" object home */
dp = ut_getatt (ply, 0, typ_obj, var_using, (char *) 0);
if (dp != (char *) 0 &&
(dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
/* there is a "use" object */
if (home_object (who, nxtu, (char *) 0, ply))
goto fail;
if (ut_listdel (who, loc, var_ply, ply)) {
plogf ("destroy player %s: can't remove player from room %s\n", ply, loc);
goto fail;
}
/* save the name! */
dp = ut_getatt (ply, 0, typ_str, var_nam, (char *) 0);
if (dp != (char *) 0) {
strncpy (nxtu, dp, MAXOID);
nxtu[MAXOID - 1] = '\0';
} else
strcpy (nxtu, "An unidentifiable player");
/* now delete the player (log and display error) */
switch (cache_del (ply, 0)) {
case 1:
/* DB couldn't delete the object */
plogf ("destroy player %s: couldn't delete the player\n", ply);
goto fail;
case -1:
/* DB not initialized */
plogf ("destroy player %s: no delete. db not initted\n", ply);
say (who, "couldn't delete player ", ply, "\n", (char *) 0);
goto fail;
case 0:
/* either cache not initted, or object deleted ok */
break;
}
plogf ("player %s destroyed by %s\n", ply, who);
/* send a message to all where they were */
ut_roombcast (loc, (char *) 0, nxtu, " disintegrates before you!\n",
(char *) 0);
if (run_level () == 0)
say (who, "You destroyed player ", ply, "\n", (char *) 0);
return (UERR_NONE);
fail:
say (who, "Cannot destroy player ", ply, "\n", (char *) 0);
return (UERR_FATAL);
}
static char ply_mesg[] =
"You've been sent home as the room you were in was being destroyed\n";
/* utility routine to delete the exit */
static int delete_xit (char *room, char *ex)
{
switch (cache_del (ex, 0)) {
case 1:
/* DB couldn't delete the object */
plogf ("destroy room %s: couldn't delete exit %s\n", room, ex);
return (UERR_FATAL);
case 0:
/* no problem */
return (UERR_NONE);
default:
case -1:
/* DB not initialized */
plogf ("destroy room %s: no delete. db not initted\n", room);
return (UERR_FATAL);
}
}
/* destroy a room */
static int room_destroy (char *who, char *aswho, char *name, int wiz)
{
char room[MAXOID];
char *dp;
char nxtu[MAXOID];
char *limbo;
/* start with some checks */
/* find the room; unique, exact match required. #num is OK.
* Actually, #num is the *only* way to refer to a room */
if (matchlocal (who, name, ut_loc (who),
MTCH_UNIQ | MTCH_MEOK | MTCH_NONLOC, room))
return (UERR_NOMATCH);
/* check ownership */
if (!wiz && !ut_isobjown (aswho, room)) {
say (who, "You don't own ", name, "\n", (char *) 0);
return (UERR_PERM);
}
/* ensure the object is a room */
if (!ut_flagged (room, var_isroom)) {
say (who, ut_name (room), " is not a room\n", (char *) 0);
return (UERR_BADOID);
}
limbo = ut_getatt (system_object, 0, typ_obj, var_syslimbo, (char *) 0);
if (limbo == (char *) 0) {
plogf ("destroy room %s: cannot find limbo!\n", room);
goto fail;
} else if (!strcmp (room, limbo)) {
say (who, "You can't destroy the system limbo!\n", (char *) 0);
return (UERR_PERM);
}
/* send the players home */
dp = ut_getatt (room, 0, typ_list, var_ply, (char *) 0);
if (dp != (char *) 0) {
/* there are players */
while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0) {
if (home_object (who, nxtu, ply_mesg, room)) {
goto fail;
}
/* Do some messages, just for Moira */
if (!ut_flagged (nxtu, var_isdark))
ut_roombcast (ut_loc (nxtu), nxtu, ut_name (nxtu),
" has arrived.\n", (char *) 0);
lookat (nxtu, ut_loc (nxtu), LOOK_NAME | LOOK_PLAY | LOOK_CONT);
}
}
/* send the contents home */
dp = ut_getatt (room, 0, typ_list, var_cont, (char *) 0);
if (dp != (char *) 0) {
/* there are contents */
while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
if (home_object (who, nxtu, (char *) 0, room)) {
goto fail;
}
}
/* destroy the exits */
dp = ut_getatt (room, 0, typ_list, var_xit, (char *) 0);
if (dp != (char *) 0) {
/* there are exits */
while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
/* delete the exit (log error) */
if (delete_xit (room, nxtu)) {
goto fail;
} else
/* ignore any error */
(void) ut_listdel (who, room, var_xit, nxtu);
}
/* ignore error */
(void) ut_unset (who, room, var_xit);
/* otherwise, delete the room! */
switch (cache_del (room, 0)) {
case 1:
/* DB couldn't delete the object */
plogf ("destroy room %s: couldn't delete the room\n", room);
goto fail;
case -1:
/* DB not initialized */
plogf ("destroy room %s: no delete. db not initted\n", room);
goto fail;
case 0:
/* either cache not initted, or object deleted ok */
break;
}
if (run_level () == 0)
say (who, "You destroyed room ", room, "\n", (char *) 0);
return (UERR_NONE);
fail:
say (who, "Cannot destroy room ", room, "\n", (char *) 0);
return (UERR_FATAL);
}
/* destroy an exit */
static int exit_destroy (char *who, char *aswho, char *name, int wiz)
{
char ex[MAXOID];
char *loc;
/* start with some checks */
/* find the exit; unique match required. #num is OK. */
if (matchexit (who, name, ut_loc (who), MTCH_UNIQ | MTCH_NONLOC, ex))
return (UERR_NOMATCH);
/* check ownership */
if (!wiz && !ut_isobjown (aswho, ex)) {
say (who, "You don't own ", name, "\n", (char *) 0);
return (UERR_PERM);
}
/* ensure the object is an exit */
if (ut_getatt (ex, 1, typ_obj, var_dest, (char *) 0) == (char *) 0) {
say (who, ut_name (ex), " is not an exit\n", (char *) 0);
return (UERR_BADOID);
}
/* where is the exit? */
loc = ut_loc (ex);
if (ut_listdel (who, loc, var_xit, ex)) {
plogf ("destroy exit %s: can't find in %s's xit list\n", ex, loc);
goto fail;
}
/* now delete the exit (log and display error) */
switch (cache_del (ex, 0)) {
case 1:
/* DB couldn't delete the object */
plogf ("destroy exit %s: couldn't delete the object\n", ex);
goto fail;
case -1:
/* DB not initialized */
plogf ("destroy exit %s: no delete. db not initted\n", ex);
goto fail;
case 0:
/* either cache not initted, or object deleted ok */
break;
}
if (run_level () == 0)
say (who, "You destroyed exit ", ex, "\n", (char *) 0);
return (UERR_NONE);
fail:
say (who, "Cannot destroy exit ", ex, "\n", (char *) 0);
return (UERR_FATAL);
}
/* destroy a thing */
static int object_destroy (char *who, char *aswho, char *name, int wiz)
{
char obj[MAXOID];
char *loc;
char *use;
/* start with some checks */
/* find the object; unique and exact match required. #num is OK. */
if (matchlocal (who, name, ut_loc (who), MTCH_UNIQ | MTCH_NONLOC, obj))
return (UERR_NOMATCH);
/* check ownership */
if (!wiz && !ut_isobjown (aswho, obj)) {
say (who, "You don't own ", name, "\n", (char *) 0);
return (UERR_PERM);
}
/* ensure the object is not a player,room or exit */
if (ut_flagged (obj, var_isplay) || ut_flagged (obj, var_isroom)
|| ut_getatt (obj, 1, typ_obj, var_dest, (char *) 0) != (char *) 0) {
say (who, ut_name (obj), " is not an object\n", (char *) 0);
return (UERR_BADOID);
}
/* where is the thing? */
loc = ut_loc (obj);
if (ut_flagged (loc, var_isplay) &&
(use = ut_getatt (loc, 0, typ_obj, var_using, (char *) 0)) != (char *) 0
&& !strcmp (use, obj)) {
/* if object is used by a player, unset the using attr */
if (ut_unset (who, loc, var_using))
goto fail;
} else if (ut_listdel (who, loc, var_cont, obj))
/* if object is carried by a player or in a room,
* remove from contents */
goto fail;
/*
* if objects can be inside objects, then you have to
* send the contents of this object home.
*
* Not currently implemented.
*/
/* now delete the thing (log and display error) */
switch (cache_del (obj, 0)) {
case 1:
/* DB couldn't delete the object */
plogf ("destroy object %s: couldn't delete the object\n", obj);
goto fail;
case -1:
/* DB not initialized */
plogf ("destroy object %s: no delete. db not initted\n", obj);
goto fail;
case 0:
/* either cache not initted, or object deleted ok */
break;
}
if (run_level () == 0)
say (who, "You destroyed object ", obj, "\n", (char *) 0);
return (UERR_NONE);
fail:
say (who, "Cannot destroy object ", obj, "\n", (char *) 0);
return (UERR_FATAL);
}
static int home_object (char *who, char *what, char *msg, char *notthere)
{
char hm[MAXOID];
char *where;
char *dstlist = NULL;
char *p;
if (!ut_home (what, hm))
return (1);
/* Use limbo if home == notthere */
if (!strcmp (hm, notthere)) {
p = ut_getatt (system_object, 0, typ_obj, var_syslimbo, (char *) 0);
if (p == (char *) 0)
return (1);
strcpy (hm, p);
}
/* Figure out where it is, and get it out of there */
if ((where = ut_loc (what)) != (char *) 0) {
if (ut_flagged (what, var_isplay)) {
/* It's a player */
dstlist = var_ply;
if (ut_listdel (what, where, var_ply, what))
return (1);
} else {
/* It must be an object */
dstlist = var_cont;
if (ut_getatt (where, 0, typ_obj, var_using, (char *) 0) == what) {
/* Used object */
if (ut_unset (who, where, var_using))
return (1);
} else {
/* In contents list */
if (ut_listdel (what, where, var_cont, what))
return (1);
}
}
}
/* Put it where it's supposed to go */
/* ignore return values and hope. */
(void) ut_listadd (who, hm, dstlist, what);
(void) ut_set (who, what, typ_obj, var_loc, hm);
/* Tell the thing */
if (msg != (char *) 0)
say (what, msg, (char *) 0);
return (0);
}