/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/wiz.c,v 1.16 90/09/28 12:25:37 rearl Exp $ */
/*
* $Log: wiz.c,v $
* Revision 1.16 90/09/28 12:25:37 rearl
* Fixed missing newline bug in @newpassword logging.
*
* Revision 1.15 90/09/18 08:02:56 rearl
* Fixed @tel for rooms -- a bug in permissions checking.
*
* Revision 1.14 90/09/16 04:43:20 rearl
* Preparation code added for disk-based MUCK.
*
* Revision 1.13 90/09/15 22:28:34 rearl
* Send inventory of the toad home, not the wizard's!
*
* Revision 1.12 90/09/13 06:30:20 rearl
* @toad modified to chown the victim's items to a recipient player.
*
* Revision 1.11 90/09/10 02:19:06 rearl
* Changed NL line termination to CR/LF pairs.
*
* Revision 1.10 90/09/05 02:32:31 rearl
* Added match_here() for room parent setting.
*
* Revision 1.9 90/09/01 06:00:02 rearl
* Fixed code in @teleport.
*
* Revision 1.8 90/08/27 03:35:41 rearl
* Changed teleport checks...
*
* Revision 1.7 90/08/11 04:12:47 rearl
* *** empty log message ***
*
* Revision 1.6 90/08/06 03:49:14 rearl
* Added logging of @force, @boot, and @toad.
*
* Revision 1.5 90/08/05 03:20:16 rearl
* Redid matching routines.
*
* Revision 1.4 90/08/02 22:07:04 rearl
* Changed one call to a log function, that's it.
*
* Revision 1.3 90/07/29 17:46:28 rearl
* Made @stat command a little cleaner, toaded victims are now
* toaded first, then all their connections are booted from the game.
*
* Revision 1.2 90/07/23 14:48:37 casie
* *** empty log message ***
*
* Revision 1.1 90/07/19 23:04:20 casie
* Initial revision
*
*
*/
#include "copyright.h"
#include "config.h"
/* Wizard-only commands */
#include "db.h"
#include "params.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
void do_teleport(dbref player, const char *arg1, const char *arg2)
{
dbref victim;
dbref destination;
const char *to;
struct match_data md;
/* get victim, destination */
if(*arg2 == '\0') {
victim = player;
to = arg1;
} else {
init_match(player, arg1, NOTYPE, &md);
match_neighbor(&md);
match_possession(&md);
match_me(&md);
match_here(&md);
match_absolute(&md);
match_player(&md);
if((victim = noisy_match_result(&md)) == NOTHING) {
return;
}
to = arg2;
}
/* get destination */
init_match(player, to, TYPE_PLAYER, &md);
match_here(&md);
match_home(&md);
match_absolute(&md);
match_neighbor(&md);
match_me(&md);
match_player(&md);
switch(destination = match_result(&md)) {
case NOTHING:
notify(player, "Send it where?");
break;
case AMBIGUOUS:
notify(player, "I don't know which destination you mean!");
break;
case HOME:
switch (Typeof(victim)) {
case TYPE_PLAYER:
destination = DBFETCH(victim)->link;
break;
case TYPE_THING:
destination = DBFETCH(victim)->link;
break;
case TYPE_ROOM:
destination = GLOBAL_ENVIRONMENT;
break;
case TYPE_PROGRAM:
destination = OWNER(victim);
break;
default:
destination = PLAYER_START; /* caught in the next switch anyway */
break;
}
default:
switch (Typeof(victim)) {
case TYPE_PLAYER:
if (!Arch(player) && (victim != player)) {
notify(player, "Permission denied.");
break;
}
if (Typeof(destination) != TYPE_ROOM
&& Typeof(destination) != TYPE_PLAYER
&& Typeof(destination) != TYPE_THING) {
notify(player, "Bad destination.");
break;
}
if(!Arch(player) &&
!(controls(player,destination)) &&
!((FLAGS(destination)&JUMP_OK)
#ifdef ABODE
|| (FLAGS(destination)&ABODE)
#else
|| (FLAGS(destination)&LINK_OK)
#endif /* ABODE */
)) {
notify(player,"Permission denied!");
break;
}
if(parent_loop_check(victim,destination)) {
notify(player,"Error: would create a loop");
break;
}
enter_room(victim, destination, DBFETCH(victim)->location);
notify(player, "Teleported.");
break;
case TYPE_THING:
case TYPE_PROGRAM:
if (Typeof(destination) != TYPE_ROOM &&
Typeof(destination) != TYPE_PLAYER &&
Typeof(destination) != TYPE_THING) {
notify(player, "Bad destination.");
break;
}
if (!Arch(player)
&& !((controls(player, destination)
#ifdef ABODE
|| (FLAGS(destination)&ABODE)
#else
|| (FLAGS(destination)&LINK_OK)
#endif /* ABODE */
|| (FLAGS(destination)&JUMP_OK))
&& (controls(player, victim)
|| controls(player, DBFETCH(victim)->location)))) {
notify(player, "Permission denied.");
break;
}
/* check for non-sticky dropto */
if (Typeof(destination) == TYPE_ROOM
&& DBFETCH(destination)->link != NOTHING
&& !(FLAGS(destination) & STICKY))
destination = DBFETCH(destination)->link;
if(parent_loop_check(victim,destination)) {
notify(player,"Would create a loop. sorry.");
break;
}
moveto(victim, destination);
notify(player, "Teleported.");
break;
case TYPE_ROOM:
if (Typeof(destination) != TYPE_ROOM) {
notify(player, "Bad destination.");
break;
}
if (!controls(player, victim)
|| !can_link_to(player, NOTYPE, destination)
|| victim == GLOBAL_ENVIRONMENT) {
notify(player, "Permission denied.");
break;
}
if (parent_loop_check(victim, destination)) {
notify(player, "Parent would create a loop.");
break;
}
moveto(victim, destination);
notify(player, "Parent set.");
break;
#ifdef RECYCLE
case TYPE_GARBAGE:
notify(player, "That object is in a place where magic cannot reach it.");
break;
#endif
default:
notify(player, "You can't teleport that.");
break;
}
break;
}
return;
}
void do_force(dbref player, const char *what, char *command)
{
dbref victim;
struct match_data md;
init_match(player,what,TYPE_PLAYER,&md);
match_neighbor(&md);
match_possession(&md);
match_me(&md);
match_absolute(&md);
if(Wizard(player))
match_player(&md);
victim=noisy_match_result(&md);
if(victim==NOTHING) {
return;
}
if(player != OWNER(victim) && !Wizard(player)) {
notify(player,"Permission denied.");
return;
}
#ifdef GOD_PRIV
if (God(victim)) {
notify(player, "You cannot force god to do anything.");
return;
}
#endif /* GOD_PRIV */
if(Typeof(victim)!=TYPE_PLAYER &&
Typeof(victim)!=TYPE_THING) {
notify(player, "Illegal object type.");
return;
}
if(Typeof(victim)==TYPE_PLAYER)
log_status("FORCED: %s(%d) by %s(%d): %s\n", NAME(victim),
victim, NAME(player), player, command);
/* force victim to do command */
process_command(victim, command, player,0);
}
void do_stats(dbref player, const char *name)
{
int breakdown[10];
int total = 0;
dbref i;
dbref owner = 0;
struct match_data md;
char buf[BUFFER_LEN];
if(!payfor(player, LOOKUP_COST)) {
notify(player,"You don't have enough pennies.");
return;
}
if (name != NULL && *name != '\0') {
owner = lookup_player(name);
if (owner == NOTHING) {
init_match(player, name, NOTYPE, &md);
match_me(&md);
match_absolute(&md);
match_player(&md);
if((owner = match_result(&md)) == NOTHING) {
notify(player, "I can't find that player.");
return;
}
}
if(!controls(player,owner)) {
notify(player, "Permission denied.");
return;
}
}
for(i = 0; i < 10; i++)
breakdown[i] = 0;
if(name != NULL || *name != '\0') {
for (i = 0; i < db_top; i++)
if ((*name == '\0') || (OWNER(i) == owner)) {
total++;
breakdown[Typeof(i)]++;
}
} else {
for (i = 0; i < db_top; i++) {
total++;
breakdown[Typeof(i)]++;
}
}
#ifdef RECYCLE
sprintf(buf,
"%d object%s = %d room%s, %d exit%s, %d thing%s, %d program%s, %d player%s, %d garbage.",
total, (total == 1) ? "" : "s",
breakdown[TYPE_ROOM], (breakdown[TYPE_ROOM] == 1) ? "" : "s",
breakdown[TYPE_EXIT], (breakdown[TYPE_EXIT] == 1) ? "" : "s",
breakdown[TYPE_THING], (breakdown[TYPE_THING] == 1) ? "" : "s",
breakdown[TYPE_PROGRAM], (breakdown[TYPE_PROGRAM] == 1) ? "" : "s",
breakdown[TYPE_PLAYER], (breakdown[TYPE_PLAYER] == 1) ? "" : "s",
breakdown[TYPE_GARBAGE]);
#else /* RECYCLE */
sprintf(buf,
"%d object%s = %d room%s, %d exit%s, %d thing%s, %d program%s, %d player%s.",
total, (total == 1) ? "" : "s",
breakdown[TYPE_ROOM], (breakdown[TYPE_ROOM] == 1) ? "" : "s",
breakdown[TYPE_EXIT], (breakdown[TYPE_EXIT] == 1) ? "" : "s",
breakdown[TYPE_THING], (breakdown[TYPE_THING] == 1) ? "" : "s",
breakdown[TYPE_PROGRAM], (breakdown[TYPE_PROGRAM] == 1) ? "" : "s",
breakdown[TYPE_PLAYER], (breakdown[TYPE_PLAYER] == 1) ? "" : "s")
#endif /* RECYCLE */
notify(player, buf);
}
void do_boot(dbref player, const char *name)
{
dbref victim;
char buf[BUFFER_LEN];
if((victim = lookup_player(name)) == NOTHING) {
notify(player, "That player does not exist.");
return;
}
if(Typeof(victim) != TYPE_PLAYER) {
notify(player, "You can only boot players!");
} else if (!Wizard(player) && (OWNER(victim) != player)) {
notify(player, "Permission denied.");
}
#ifdef GOD_PRIV
else if(God(victim)) {
notify(player, "Permission denied.");
}
#endif /* GOD_PRIV */
else {
notify(victim, "You have been booted off the game.");
if (boot_off(victim)) {
log_status("BOOTED: %s(%d) by %s(%d)\n", NAME(victim),
victim, NAME(player), player);
sprintf(buf, "You booted %s off!", NAME(victim));
notify(player, buf);
} else {
sprintf(buf, "%s is not connected.", NAME(victim));
notify(player, buf);
}
}
}
void do_toad(dbref player, const char *name, const char *recip)
{
dbref victim;
dbref recipient;
dbref stuff;
if(Typeof(player) != TYPE_PLAYER) {
notify(player, "Permission denied.");
return;
}
if(!Wizard(player)) {
notify(player, "Only a wizard can destroy a player.");
return;
}
if((victim = lookup_player(name)) == NOTHING) {
notify(player, "That player does not exist.");
return;
}
if (!*recip) {
recipient = GOD;
} else {
if ((recipient = lookup_player(recip)) == NOTHING
|| recipient == victim) {
notify(player, "That recipient does not exist.");
return;
}
}
if(Typeof(victim) != TYPE_PLAYER) {
notify(player, "You can only destroy the living!");
} else if(Wizard(victim) || FLAGS(victim)&WIZARD) { /* don't toad Quell W */
notify(player, "You can't destroy a wizard.");
} else {
/* chown things to recipient, checking for a sane home location */
/* for object. XXX -- if HOME/inventory handling changes, */
/* please check this code.*/
for (stuff = 0; stuff < db_top; stuff++) {
if ((Typeof(stuff) == TYPE_THING)
&& (DBFETCH(stuff)->link == victim)) {
DBSTORE(stuff, link, PLAYER_START);
}
if (OWNER(stuff) == victim) {
OWNER(stuff) = recipient;
DBDIRTY(stuff);
}
}
/* Take them home; things should no longer be homed here, programs */
/* should not be owned by player */
send_contents(victim, HOME);
if(DBFETCH(victim)->sp.player.password) {
free((void *) DBFETCH(victim)->sp.player.password);
DBFETCH(victim)->sp.player.password = NULL;
}
FLAGS(victim) = TYPE_THING;
OWNER(victim) = player; /* you get it */
/* notify people */
notify(victim, "You have been destroyed.");
sprintf(buf, "You destroyed %s!", NAME(victim));
notify(player, buf);
log_status("DESTROYED: %s(%d) by %s(%d)\n", NAME(victim),
victim, NAME(player), player);
delete_player(victim);
DBDIRTY(victim);
while (boot_off(victim))
;
}
}
void do_newpassword(dbref player, const char *name, const char *password)
{
dbref victim;
char buf[BUFFER_LEN];
if(!Wizard(player)) {
notify(player, "Permission denied.");
return;
} else if((victim = lookup_player(name)) == NOTHING) {
notify(player, "No such player.");
} else if(*password != '\0' && !ok_password(password)) {
/* Wiz can set null passwords, but not bad passwords */
notify(player, "Bad password");
#ifdef GOD_PRIV
} else if (God(victim) && !God(player))
{
notify(player, "Permission denied.");
return;
#endif /* GOD_PRIV */
} else {
/* it's ok, do it */
if(DBFETCH(victim)->sp.player.password)
free((void *) DBFETCH(victim)->sp.player.password);
DBSTORE(victim, sp.player.password, alloc_string(password));
sprintf(buf, "%s's password changed to %s.", NAME(victim),password);
notify(player, buf);
sprintf(buf, "Your password has been changed by %s.", NAME(player));
notify(victim, buf);
log_status("NEWPASS'ED: %s(%d) by %s(%d)\n", NAME(victim), (int) victim,
NAME(player), (int) player);
}
}
void do_pcreate(dbref player, const char *user, const char *password)
{
dbref newguy;
char buf[BUFSIZ];
if (!Wizard(player)) {
notify(player, "Permission denied.");
return;
}
newguy = create_player (user, password);
if (newguy == NOTHING) {
notify(player, "Create failed.");
} else {
log_status("PCREATED %s(%d) by %s(%d)\n",
NAME(newguy), (int) newguy, NAME(player), (int) player);
sprintf(buf, "%s created.", unparse_object(player, newguy));
notify(player,buf);
}
}
void swap(dbref r1,dbref r2)
{
dbref lo;
struct object tmpobj;
#define CSWAP(th1) { if((th1) == r1) (th1) = r2; \
else if((th1) == r2) (th1) = r1; }
bcopy(DBFETCH(r1), &tmpobj, sizeof(tmpobj));
bcopy(DBFETCH(r2), DBFETCH(r1), sizeof(tmpobj));
bcopy(&tmpobj, DBFETCH(r2), sizeof(tmpobj));
for(lo = 0; lo < db_top; lo++) {
if(Typeof(lo) == TYPE_ROOM || Typeof(lo) == TYPE_THING
|| Typeof(lo) == TYPE_PLAYER)
CSWAP(DBFETCH(lo)->exits);
if(Typeof(lo) != TYPE_EXIT)
CSWAP(DBFETCH(lo)->link);
CSWAP(DBFETCH(lo)->location);
CSWAP(DBFETCH(lo)->owner);
CSWAP(DBFETCH(lo)->contents);
CSWAP(DBFETCH(lo)->next);
if(Typeof(lo) == TYPE_EXIT && DBFETCH(lo)->sp.exit.ndest) {
int i;
for(i = 0; i < (DBFETCH(lo)->sp.exit.ndest); i++) {
CSWAP(DBFETCH(lo)->sp.exit.dest[i]);
}
}
if(Typeof(lo) == TYPE_PLAYER) {
CSWAP(DBFETCH(lo)->curr_prog);
}
}
}
void do_swap(dbref player, char *t1, char *t2)
{
struct match_data md;
dbref r1, r2;
if(!Wizard(player)) {
notify(player, "Permission denied.");
return;
}
init_match(player,t1,TYPE_THING,&md);
match_all_exits(&md);
match_neighbor(&md);
match_possession(&md);
match_here(&md);
if(Arch(player))
match_absolute(&md);
r1 = noisy_match_result(&md);
if(r1 == NOTHING) {
notify(player,"Bad first argument.");
return;
}
init_match(player, t2, TYPE_THING, &md);
match_all_exits(&md);
match_neighbor(&md);
match_possession(&md);
match_here(&md);
if(Arch(player))
match_absolute(&md);
r2 = noisy_match_result(&md);
if(r2 == NOTHING) {
notify(player,"Bad second argument.");
return;
}
if(r1 < 0 || r2 < 0 || r1 >= db_top || r2 >= db_top) {
notify(player,"Bad arguments.");
return;
}
if(!controls(player, r1) && Typeof(r1) != TYPE_GARBAGE) {
notify(player,"Permission denied.");
return;
}
if(!controls(player, r2) && Typeof(r2) != TYPE_GARBAGE) {
notify(player,"Permission denied.");
return;
}
#ifdef GOD_PRIV
if((Typeof(r1) == TYPE_PROGRAM || Typeof(r2) == TYPE_PROGRAM ||
Typeof(r1) == TYPE_PLAYER || Typeof(r2) == TYPE_PLAYER)
&& !God(player)) { /* very destructive for program calls, */
; /* and players want to keep their numbers */
; /* and regular wizards can't do this. */
notify(player,"Permission denied.");
return;
}
if((God(r1) || God(r2)) && !God(player))
notify(player, "Permission denied.");
#endif /* GOD_PRIV */
notify(r1, "You sense that your identity has changed.");
notify(r2, "You sense that your identity has changed.");
swap(r1, r2);
notify(player,"Swapped...");
}