/* $Header: wiz.c,v 2.0 90/05/05 12:45:48 lachesis Exp $
 * $Log:	wiz.c,v $
 * Revision 2.0  90/05/05  12:45:48  lachesis
 * Incorporated ABODE and HAVEN flags (remembering to convert FireFoot's
 * usage of those flags to ours).
 * Added Examine of objects that don't belong to you, added GOD_PRIV.
 * 
 * Revision 1.1  90/04/14  14:56:59  lachesis
 * Initial revision
 * 
 */
#include "copyright.h"

/* Wizard-only commands */

#include "config.h"
#include "db.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;

#ifdef RESTRICTED_TELEPORT
    if(!Wizard(player)) {
	notify(player, "Only a Wizard may teleport at will.");
	return;
    }
#endif /* RESTRICTED_TELEPORT */

    /* get victim, destination */
    if(*arg2 == '\0') {
	victim = player;
	to = arg1;
    } else {
	init_match(player, arg1, NOTYPE);
	match_neighbor();
	match_possession();
	match_me();
	match_absolute();
	match_player();

	if((victim = noisy_match_result()) == NOTHING) {
	    return;
	}
	to = arg2;
    }

    /* get destination */
    init_match(player, to, NOTYPE);
    match_here();
    match_absolute();
    if(Wizard(player)) {
	match_me();
        match_home();
	match_neighbor();
	match_player();
    }

    switch(destination = match_result()) {
      case NOTHING:
	notify(player, "Send it where?");
	break;
      case AMBIGUOUS:
	notify(player, "I don't know which destination you mean!");
	break;
      case HOME:
	notify(player, "Sending home without any checks.");
	moveto(victim, destination);
	notify(player, "Teleported.");
	break;
      default:
	/* check victim, destination types, teleport if ok */
	if(Typeof(destination) == TYPE_EXIT
	   || Typeof(destination) == TYPE_THING
	   || Typeof(victim) == TYPE_EXIT
	   || Typeof(victim) == TYPE_ROOM
	   || (Typeof(victim) == TYPE_PLAYER
	       && Typeof(destination) != TYPE_ROOM)) {
	    notify(player, "Bad destination.");
#ifndef RESTRICTED_TELEPORT
	} else if(!Wizard(player)
		  && !(Typeof(victim) == TYPE_THING
		       && Typeof(destination) == TYPE_ROOM
		       && (controls(player, victim)
			   || (Typeof(db[victim].location) == TYPE_ROOM
			       && controls(player, db[victim].location)))
		       && (can_link_to(player, destination)))) {
	    notify(player, "Permission denied.");
#endif /* RESTRICTED_TELEPORT */		  
#ifdef RECYCLE
	} else if(Typeof(victim) == TYPE_GARBAGE) {
	    notify(player, "That object is in a place where magic cannot reach it.");
#endif	    
	} else if(Typeof(victim) == TYPE_PLAYER) {
	    notify(victim, "You feel a wrenching sensation...");
	    enter_room(victim, destination);
	    notify(player, "Teleported.");
	} else {
            /* check for non-sticky dropto */
            if(Typeof(destination) == TYPE_ROOM
               && db[destination].sp.room.dropto != NOTHING
               && !(db[destination].flags & STICKY)) {
                /* destination has immediate dropto */
                destination = db[destination].sp.room.dropto;
            }

            /* do the move */
	    moveto(victim, destination);
	    notify(player, "Teleported.");
	}
    }
}

void do_force(dbref player, const char *what, char *command)
{
    dbref victim;

    if(!Wizard(player)) {
	notify(player, "Only Wizards may use this command.");
	return;
    }

    /* get victim */
    if((victim = lookup_player(what)) == NOTHING) {
	notify(player, "That player does not exist.");
	return;
    }

#ifdef GOD_PRIV
    if (God(victim))
      {
	notify(player, "You cannot force god to do anything.");
	return;
      }
#endif /* GOD_PRIV */

    /* force victim to do command */
    process_command(victim, command);
}

void do_stats(dbref player, const char *name)
{
    dbref rooms;
    dbref exits;
    dbref things;
    dbref players;
#ifdef RECYCLE    
    dbref garbage = 0;
#endif    
    dbref total;
    dbref i;
    dbref owner;
    char buf[BUFFER_LEN];

    if(!Wizard(player)) {
	sprintf(buf, "The universe contains %d objects.", db_top);
	notify(player, buf);
    } else {
	total = rooms = exits = things = players = 0;
	if (name != NULL && *name != '\0') {
	    owner = lookup_player(name);
	    if (owner == NOTHING) {
		notify(player, "I can't find that player.");
		return;
	    }
	    for (i = 0; i < db_top; i++) {
		switch(Typeof(i)) {
		  case TYPE_ROOM:
		    if (db[i].sp.room.owner == owner) {
			total++;
			rooms++;
		    }
		    break;
		  case TYPE_EXIT:
		    if (db[i].sp.exit.owner == owner) {
			total++;
			exits++;
		    }
		    break;
		  case TYPE_THING:
		    if (db[i].sp.thing.owner == owner) {
			total++;
			things++;
		    }
		    break;
		  case TYPE_PLAYER:
		    if (i == owner) {
			total++;
			players++;
		    }
		    break;
		}
	    }
	}
	else {
	    for(i = 0; i < db_top; i++) {
		switch(Typeof(i)) {
		  case TYPE_ROOM:
		    total++;
		    rooms++;
		    break;
		  case TYPE_EXIT:
		    total++;
		    exits++;
		    break;
		  case TYPE_THING:
		    total++;
		    things++;
		    break;
		  case TYPE_PLAYER:
		    total++;
		    players++;
		    break;
#ifdef RECYCLE
		  case TYPE_GARBAGE:
		    total++;
		    garbage++;
		    break;
#endif /* RECYCLE */
		}
	    }
	}
#ifndef RECYCLE
	sprintf(buf,
		"%d object%s = %d room%s, %d exit%s, %d thing%s, %d player%s.",
		total, (total==1) ? "" : "s",
		rooms, (rooms==1) ? "" : "s",
		exits, (exits==1) ? "" : "s",
		things, (things==1) ? "" : "s",
		players, (players==1) ? "" : "s");
#else
	sprintf(buf,
		"%d object%s = %d room%s, %d exit%s, %d thing%s, %d player%s, %d garbage.",
		total, (total==1) ? "" : "s",
		rooms, (rooms==1) ? "" : "s",
		exits, (exits==1) ? "" : "s",
		things, (things==1) ? "" : "s",
		players, (players==1) ? "" : "s",
		garbage);
#endif /* RECYCLE */
	notify(player, buf);
#ifdef TEST_MALLOC
	sprintf(buf, "Malloc count = %d.", malloc_count);
	notify(player, buf);
#endif /* TEST_MALLOC */
    }
}
		
void do_toad(dbref player, const char *name)
{
    dbref victim;
    dbref j;
    dbref next;
    char buf[BUFFER_LEN];

    if(!Wizard(player)) {
	notify(player, "Only a Wizard can turn a person into a toad.");
	return;
    }

    init_match(player, name, TYPE_PLAYER);
    match_neighbor();
    match_absolute();
    match_player();
    if((victim = noisy_match_result()) == NOTHING) return;

    if(Typeof(victim) != TYPE_PLAYER) {
	notify(player, "You can only turn players into toads!");
    } else if(Wizard(victim)) {
	notify(player, "You can't turn a Wizard into a toad.");
    } else {
	/* we're ok */
	/* do it */
      send_contents(victim, HOME);
      for (j = db[victim].contents; j != NOTHING; j = next) {
	/* Heaven forbid anything is still here */
	next = db[j].next;
	if (Typeof(j) == TYPE_THING) {
	  db[j].sp.thing.home = PLAYER_START;
	  moveto(j, PLAYER_START);
	}
      }
      delete_player(victim);
      if(db[victim].sp.player.password) {
	free((void *) db[victim].sp.player.password);
	db[victim].sp.player.password = 0;
      }
      db[victim].flags = TYPE_THING;
      db[victim].sp.thing.owner = player; /* you get it */
      db[victim].sp.thing.value = 1;	/* don't let him keep his immense wealth */

      /* notify people */
      notify(victim, "You have been turned into a toad.");
      sprintf(buf, "You turned %s into a toad!", db[victim].name);
      notify(player, buf);
      
      /* reset name */
      sprintf(buf, "a slimy toad named %s", db[victim].name);
      free((void *) db[victim].name);
      db[victim].name = alloc_string(buf);
    }
}

void do_newpassword(dbref player, const char *name, const char *password)
{
    dbref victim;
    char buf[BUFFER_LEN];

    if(!Wizard(player)) {
	notify(player, "Your delusions of grandeur have been duly noted.");
	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))
	{
	  notify(player, "You can't change God's password!");
	  return;
#endif /* GOD_PRIV */
    } else {
	/* it's ok, do it */
	if(db[victim].sp.player.password) free((void *) db[victim].sp.player.password);
	db[victim].sp.player.password = alloc_string(password);
	notify(player, "Password changed.");
	sprintf(buf, "Your password has been changed by %s.", db[player].name);
	notify(victim, buf);
    }
}

void do_boot(dbref player, const char *name)
{
  dbref victim;
  char buf[BUFFER_LEN];
  
  if(!Wizard(player)) {
    notify(player, "Only a Wizard can boot someone off.");
    return;
  }

  init_match(player, name, TYPE_PLAYER);
  match_player();
  match_neighbor();
  if((victim = noisy_match_result()) == NOTHING) {
    return;
  }
  
  if (player == victim) {
    notify(player, "You can't boot yourself.");
  }
#ifdef GOD_PRIV
  else if(God(victim)) {
    notify(player, "You can't boot God!");
  }
#endif /* GOD_PRIV */
  else {
    notify(victim, "You have been booted off the game.");
    if (boot_off(victim)) {
      fprintf(stderr, "BOOTED: %s(%d) by %s(%d)\n", db[victim].name,
		 victim, db[player].name, player);
      sprintf(buf, "You booted %s off!", db[victim].name);
      notify(player, buf);
    } else {
      sprintf(buf, "%s is not connected.", db[victim].name);
      notify(player, buf);
    }
  }
}

#ifdef REGISTRATION
void do_pcreate(dbref player,char *pname,char *pword) {
	dbref who;
	char buf[BUFSIZ];

	if (!Wizard(player)) {
		notify(player,"Only a Wizard can create players!");
		return;
	}
	who = create_player (pname, pword);
	if (who == NOTHING) {
		notify(player,"Pcreate failed!");
		fprintf (stderr, "%s FAILED CREATE %s\n",db[player].name,pname);
		return;
	} else {
		sprintf(buf,"%s created as player #%d.",pname,who);
		notify(player,buf);
		fprintf (stderr, "%s CREATED %s\n",db[player].name,pname);
	}
}
#endif REGISTRATION

/*
void do_fuckup(dbref player) {
	dbref i,j;

	for (i=0;i<db_top;i++) {
		if (Typeof(i) == TYPE_ROOM) {
			for (j=db[i].sp.room.exits;j!=(dbref)-1;j=db[j].next) {
				db[j].location = i;
			}
		} else if (Typeof(i) == TYPE_PLAYER) {
			for (j=db[i].contents;j!=(dbref)-1;j=db[j].next) {
				db[j].location = i;
			}
		}
	}
	notify(player, "Done.  (Phew.)");
}
*/