/* $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 "os.h"
#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.)");
}
*/