musicmud-2.1.6/data/
musicmud-2.1.6/data/help/
musicmud-2.1.6/data/policy/
musicmud-2.1.6/data/wild/
musicmud-2.1.6/data/world/
musicmud-2.1.6/doc/
musicmud-2.1.6/src/ident/
musicmud-2.1.6/src/lua/
musicmud-2.1.6/src/lua/include/
musicmud-2.1.6/src/lua/src/lib/
musicmud-2.1.6/src/lua/src/lua/
musicmud-2.1.6/src/lua/src/luac/
/*
 * MusicMUD - Wizard module
 * Copyright (C) 1998-2003 Abigail Brady
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 */
#include <stdio.h>
#include <unistd.h>
#include "musicmud.h"
#include "util.h"
#include "verbs.h"
#include "State.h"
#include "Mission.h"
#include "Player.h"
#include "misc.h"
#include "msi.h"
#include "Socket.h"
#include "Library.h"
#include "aberchat.h"
#include "config.h"
#include "flags.h"
#include "pflags.h"
#include "flagnames.h"
#include "rooms.h"
#include "zoneload.h"
#include "pflagnames.h"

#include "units.h"
#include "shared.h"
#include "move.h"
#include "body.h"
#include "nations.h"

#include <list>

#define MODULE "wizard"

static void displace(MudObject *who, MudObject *where)
{
  MudObject *what = who;
  if (who->owner==where)
    return;
  MudObject *old = who->owner;

  if (what->owner) {
    if (is_player(who->owner) || is_mobile(who->owner)) {
      what->owner->printf("%#M %[is/are] displaced from your hand.\n", what);
      what->owner->oprintf(secret(what->owner) && cansee, 
			   "%#M %[is/are] displaced from %Y's hand.\n", what, what->owner);
    } else {
      what->oprintf(secret(what) && cansee, "%#M %[is/are] displaced elsewhere.\n", what);
    }
    
    what->set("!summonedfrom", what->owner->id);
  }

  set_owner(who, where);
  rectify_state(who);

  who->printf("You are displaced %s.\n", 
	      format_roomname(where, who, "^{D", "^}", "to", 
		       IS_COMMANDER(who)).c_str());

  who->interpret("look -");

  if (is_player(where) || is_mobile(where)) {
    where->oprintf(secret(where) && cansee, "%#M %[is/are] displaced into %Y's hand.\n", what, where);
    where->printf("%#M %[is/are] displaced into your hand.\n", what, where);
  } else {
    what->oprintf(secret(what) && cansee, "%#M %[is/are] displaced here.\n", what);
  }
  newplace(what, old);
}

static bool verb_clone(MudObject *player, int argc, const char **argv) {
    if (argc > 4 || argc < 2) {
	player->printf("syntax : clone [howmany] item-to-clone [destination-id].\n");
	return true;
    }

    char *w = 0;
    int howmany = strtol(argv[1], &w, 10);
    if (w && !*w) {
      argv++;
      argc--;
    } else {
      howmany = 1;
    }

    if (howmany>10)
      howmany = 10;

    MudObject * what = planet->get(argv[1]);
    if (!what) {
	player->printf("Cannot find '%s'\n", argv[1]);
	return true;
    }

    if (is_player(what)) {
      player->printf("%#s %|%[is/are] a player. Very funny.\n", he_or_she(player), player);
      return true;
    }

    MudObject *where = player->owner;
    if (argv[2]) {
      where = planet->get(argv[2]);
      if (!where) {
	player->printf("Cannot find '%s'\n", argv[2]);
	return true;
      }
    }

    NewWorld things;

    for (int i=0;i<howmany;i++) {
      MudObject *thing = clone_object(what, where, NULL, 1, "@auto");
      thing->set("$clonedby", player->id);
      thing->set("$clonedat", now);
      rectify_state(thing);
      things.add(thing);
    }

    player->printf("You create %W.\n", &things);

    set_prons(player, things);

    if (where == player->owner) {
      player->oprintf(cansee, "%#P %[creates/create] %W.\n", 
		      player, &things);
    }
    
    return true;
}

static MudObject *copy_object(MudObject *what, MudObject *where, const char *newname) {
    MudObject *thing = new MudObject(newname);
    thing->clone(what);
    planet->add(*thing);    
    set_owner(thing, where);
    return thing;
}

static bool verb_copy(MudObject *player, int argc, const char **argv) {
    if (argc > 3 || argc < 2) {
	player->printf("syntax : copy item-to-clone [destination-id].\n");
	return true;
    }
    int count = 1;
    int use_id = 1;
    if (argc == 3) {
	    char *foo = NULL;
	    long ct = strtol(argv[2], &foo, 10);
	    if (!foo || !*foo) {
		count = ct;
		player->printf("Count : %i\n", count);
                use_id = 0;
	    }
    } else
	use_id = 0;
    if (count > 100 || count < 1) {
	player->printf("No way!\n");
        return true;
    }
    if (argc == 3 && planet->get(argv[2])) {
	player->printf("There already exists a '%s'\n", argv[2]);
	return true;
    }
    MudObject * what = planet->get(argv[1]);
    if (!what) {
	player->printf("Cannot find '%s'\n", argv[1]);
	return true;
    }

    while (count) {
	    char *fish_id = strdup(argv[1]);
	    char *moo = strrchr(fish_id, '_');
	    if (moo) *moo=0;

	    int i = 0;
	    MudObject *q = what;
	    char possible[1024];

	    while (q) {
		i++;
		sprintf(possible, "%s_%i", fish_id, i);
		q = planet->get(possible);
	    }

	    free(fish_id);

	    const char *new_id = 0;

	    if (use_id) {
		new_id = argv[2];
	    } else {
		new_id = possible;
	    }

	    char *zon = strdup(new_id);
	    if (strchr(zon, '_'))
	      *strchr(zon, '_')=0;

	    player->printf("Making %s...\n", new_id);
	    MudObject *thing = copy_object(what, player->owner, new_id);

	    thing->set("zone", zon);
    	    free(zon);

	    player->printf("You copy %Y.\n", thing);
	    player->oprintf(cansee, "%#Y %[is/are] copied before you.\n", thing);

	    thing->set("start", thing->owner->id);

	    count--;
	    rectify_state(thing);
    }

    return true;
}

extern int gid;

static bool verb_rclone(MudObject *player, int argc, const char **argv) 
{
  gid = 1;
  MudObject *sh = player->get_object("$ship");
  if (sh && sh->get_object("$owner")==player) {
    if (sh->get_object("link")) {
      player->printf("You already have a ship : %s.\n", sh->get_object("link")->id);
    }
    player->printf("You already have a ship.\n", sh->get_object("link")->id);
    return true;
  }

  MudObject *tpl = planet->get("template_4");
  if (!tpl) {
    player->printf("Can't find template_4.\n");
    return true;
  }

  string sid = genid(player);
  if (planet->get(sid.c_str())) {
    player->printf("There is already a %s.\n", sid.c_str());
    return true;
  }

  MudObject *r = clone_object(tpl, player->owner, sid.c_str());
  if (!r)
    return true;

  r->set("zone", "@ship");  
  r->set("$owner", player->id);
  recurse_clone(player, tpl, r, r, 0);
  player->set("$ship", r->id);

  r->setf("name", "^MSS %s^M's Ship^n", player->get("name"));

  fixup_exits(r);
  remove_fakeids(tpl);

  r->set_flag(FL_SHIP, 1);
  r->set_flag(FL_TIMER, 1);
  
  set_owner(r, "space");
  r->set(KEY_STATE, 1);

  if (argc > 1) {
    r->setf("plan", "0 dockat %s", argv[1]);
    r->interpret("file_plan");
  } else {
    set_owner(r, "space");
  }

  return true;
}

//! the position and disposition of an object
class ObjectPos {
public:
  MudObject *owner;
  string camefrom;

  int sit:1;
  int sleep:1;
  MudObject *upon;
  int uponn;
  int swim:1;
  int fly:1;

  MudObject *wornby;
  string wornon;
  
  ObjectPos(MudObject *from) {
    owner = from->owner;
    sit = from->get_flag(FL_SITTING);
    sleep = from->get_flag(FL_SLEEPING);
    upon = from->get_object(KEY_SITON);
    uponn = from->get_int(KEY_SITONN, 0);
    swim = from->get_flag(FL_SWIMMING);
    fly = from->get_flag(FL_FLYING);
    camefrom = from->get("$camefrom")?from->get("$camefrom"):"";
    wornby = from->get_object(KEY_WORNBY);
    wornon = from->get("$wornon")?from->get("$wornon"):"";
  }

  void restore(MudObject *to) {
    set_owner(to, owner);
    to->set_flag(FL_SITTING, sit);
    to->set_flag(FL_SLEEPING, sleep);
    to->set_flag(FL_SWIMMING, swim);
    to->set_flag(FL_FLYING, fly);

    if (camefrom.length()) to->set("$camefrom", camefrom);
    if (wornon.length()) to->set("$wornon", camefrom);

    if (upon) {
      to->set(KEY_SITON, upon->id);
      to->set(KEY_SITONN, 0);
    } else {
      to->unset(KEY_SITON);
      to->unset(KEY_SITONN);
    }

    if (wornby) {
      to->set(KEY_WORNBY, wornby->id);
    } else {
      to->unset(KEY_WORNBY);
    }
  }
};

static bool verb_atby(MudObject *player, int argc, const char **argv) {
  if (argc < 3) {
    player->printf("syntax: %s item_id command\n", argv[0]);
    return true;
  }
  string all = the_rest(argc, argv, 2);
	
  MudObject *where = find_object(player, argv[1]);

  if (streq(argv[1], "here"))
    where = player->owner;

  if (streq(argv[1], "me"))
    where = player;

  if (**argv=='b' && where)
    where = where->owner;
  
  int r = player->get_int("remort");

  if (where) {
      
      if (!can_affect(player, where->get("zone"))) {
	  player->printf("You can't do stuff in that zone.\n");
	  return true;
      }
      if (is_in(where, player)) {
	player->printf("It's in you.\n");
	return true;
      }

      ObjectPos oldpos(player);
      set_owner(player, where);
      player->set_flag(FL_SITTING, 0);
      rectify_state(player);
      player->interpret(all.c_str());
      if (player->get_int("remort")!=r) {
	player->printf("Since you've remorted you cannot return.\n");
      } else {
	oldpos.restore(player);
      }
  } else {
    player->printf("Cannot find %s\n", argv[1]);
  }

  return true;
}

static bool verb_punt(MudObject *player, int argc, const char **argv) {
 if (!player->ilc && !IS_CAPTAIN(player)) {
    player->printf ("What do you mean by \"punt\"?\n");
    return true;
 }
 if(argc<2 || argc>3) {
  player->printf("syntax: punt player [room]\n");
  return true;
 }
 MudObject *what = find_object(player, argv[1]);
 MudObject *where=0;
 if (!what) {
    player->printf("Cannot find %s.\n", argv[1]);
    return true;
 }
 if (what == player) {
    player->printf("You can't punt yourself!!\n");
    return true;
 }
 if (!is_player(what) && !is_mobile(what)) {
   player->printf("You can only punt mobiles or players.\nUse ^Wdisplace^n if you want to do something silly like that.\n");
   return true;
 }
 if (!player->ilc && privs_of(what)>=privs_of(player)) {
   player->printf("There will be no dissent in the ranks!\n");
   return true;
 }
 
 if(argc==2) { //punt to a random location
  MudObject *o;
  int i,r,count=0;
  // stolen from verb_rooms in admin.cc
  foreach(planet,o,i) {
   if (!is_exit(o) && o->get_flag(FL_ROOM)) {
    const char *z = o->get("zone");
    if (can_affect(player, z)) {
      count++;
    }
   }
  }
  r = random_number(count);
  //player->printf("Just picked room #%i (from %i rooms)\n",r,count);
  count=0;
  foreach(planet,o,i) {
   if(!is_exit(o) && o->get_flag(FL_ROOM)) {
    const char *z = o->get("zone");
    if (can_affect(player,z)) {
     count++;
     if(count==r) { //then this is our random room!
      //player->printf("That room should be %s (%s)\n",o->id, o->get("name"));
      where=o;
      break;
     }
    }
   }
  }
 }
 else if(argc==3) { //punt to a specified room
  where = find_object(player, argv[2]);
  if(!where) {
   player->printf("Can't find %s.\n",argv[2]);
   return true;
  }
  if(!where->get_flag(FL_ROOM)) {
   player->printf("%M isn't a room. Stop trying to break things.\n", where);
   return true;
  }
 }
 if (where) {
   what->oprintf(secret(what) && cansee, "%s\n", build_setin(what, setmout).c_str());
   what->set("!summonedfrom", what->owner->id);
   set_owner(what, where);
   player->printf("You punt %M %s (%s)\n",what,format_roomname(where,what,"","","to").c_str(),where->id);
   what->printf("%#M punts you %s.\n", player,format_roomname(where,what,"","","to").c_str());
   what->oprintf(secret(what) && cansee, "%s\n",build_setin(what, setmin).c_str());
   what->interpret("look -");
   log(PFL_SEEINFO, 0, "wiz", "punts %s %s (%s)", what->id, format_roomname(where,what,"","","to").c_str(),where->id);
   rectify_state(what);
   return true;
 }
 
 player->printf("punt has broken. feel free to panic.\n");
 return true;
}
 


static bool verb_summon(MudObject *player, int argc, const char **argv) {
  bool restore = streq(argv[0], "restore");

    if (!IS_CAPTAIN(player) && !player->ilc) {
      	player->printf("You can't do that : summon\n");
      	return true;
    }

    if (argc < 2) {
	player->printf("syntax: summon object\n");
	return true;
    }
    
    if (streq(argv[1], "all") && IS_CAPTAIN(player)) {

      if (restore) { player->printf("You can't restore all.\n"); return true; }
      
      MudObject *dest = player->owner;
      if (!dest) {
	player->printf("You can't summon to nowhere.\n");
	return true;
      }

      Player *p;
      int i;
      int s = 0, a = 0;
      foreach(players, p, i) if (p->get_flag(FL_LOGGEDIN)) {
	if (p == player)
	  continue;

	if (is_in(dest, p))
	  continue;
	
	if (!visible_to(player, p))
	  continue;

	if (!spare_people_capacity(dest)) {
	  player->printf("Not enough space for the others.\n");
	  return true;
	}
	
	s++;

	if (p->owner != dest) {
	  a++;

	  displace(p, dest);
	}
      }

      if (!s) {
	player->printf("There is noone else on.\n");
      } else if (!a) {
	player->printf("Everyone is already here.\n");
      }

      return true;
    }

    MudObject *what = find_object(player, argv[1]);
    if (!what)
      what = planet->get(argv[1]);
    if (!what) {
	player->printf("Cannot find %s.\n", argv[1]);
	return true;
    }
    if (what == player) {
	player->printf("Ok, if you say so...\n");
	return true;
    }
    
    if (!IS_CAPTAIN(player) && !player->ilc && !player->get_flag(FL_MOBILE)) {
      player->printf("You can't do that : summon\n");
      return true;
    }

    if (is_player(player) && is_player(what) && privs_of(what)>privs_of(player)) {
      player->printf("You are not powerful enough to summon %M.\n", what);
      return true;
    }

    MudObject *dest = player;
    bool is_object = !(is_mobile(what) || is_player(what));
    if (!is_object) dest = dest->owner;

    if (restore) {
      dest = what->get_object("!summonedfrom");
      if (!dest) {
	player->printf("You can't restore that.\n");
	return true;
      }
    }

    if (!is_player(what) && !can_affect(player, what->get("zone")) && !player->ilc) {
	player->printf("You can't summon stuff from that zone.\n");
	return true;
    }    

    if (what->owner == dest) {
	player->printf("%#Y %s already here.\n", what, is_are(what));
	return true;
    }
    
    if (is_player(what) && !spare_people_capacity(dest)) {
	player->printf("%#s wouldn't fit here!\n", he_or_she(what));
	return true;
    }
    
    if (is_in(dest, what)) {
	player->printf("Too strange.\n");
	return true;
    }

    string owh = owhere(what);

    displace(what, dest);

    if (owh.length()) {
      player->printf("%#P %[was/were] %s.\n", what, owh.c_str());
    }

    return true;
}

static bool verb_trans(MudObject *player, int argc, const char *argv[]) {
  if (argc < 3) {
    player->printf("trans <room> <where>\n");
    return true;
  }
  
  MudObject *what = find_object(player, argv[1]);
  if (!what) {
    player->printf("can't find the %s\n", argv[1]);
    return true;
  }
  
  MudObject *where = find_object(player, argv[2]);
  if (!where) {
    player->printf("can't find the %s\n", argv[2]);
    return true;
  }
  
  MudObject *from = what;
  MudObject *to = where;
  
  MudObject *o;
  int i;
  foreach(from->children, o, i) if (is_player(o) || is_mobile(o)) {
    o->set("owner", to->id);
    o->interpret("look");
    i--;
    rectify_state(o);
  }
  
  return true;
}


static bool verb_displace(MudObject *player, int argc, const char *argv[]) {
	if (argc < 3) {
		player->printf("displace <object> <where>\n");
		return true;
	}
	MudObject *what = find_object(player, argv[1]);
	if (!what) {
		player->printf("can't find the %s\n", argv[1]);
		return true;
	}
	MudObject *where = find_object(player, argv[2]);
	if (!where) {
		player->printf("can't find the %s\n", argv[2]);
		return true;
	}
	if (is_in(where, what)) {
		player->printf("Too strange.");
		return true;
	}

	if (privs_of(what) > privs_of(player)) {
	  player->printf("I don't think so.\n");
	  return true;
	}

	if (where && !can_affect(player, where->get("zone"))) {
	  player->printf("You can't displace to that zone (%s) without remorting.\n", 
			 where->get("zone"));
	  return true;
	}

	if (what->owner != where) {
	  	displace(what, where);
	  	rectify_state(player);	  
	} else {
		player->printf("Nothing changes.\n");
	}

	return true;
}


static bool verb_boot(MudObject *player, int argc, const char **argv) {
	if (argc < 2) {
		player->printf("syntax: boot player\n");
		return true;
	}

	if (streq(argv[1], "ALLCARRIED")) {
	  MudObject *p;
	  int i;
	  foreach(player->children, p, i) {
	    p->interpret2("quit");
	    if (p->owner != player)
	      i--;
	  }
	  return true;
	}

	if (streq(argv[1], "ALLHERE")) {
	  MudObject *p;
	  int i;
	  foreach(player->owner->children, p, i) {
	    if (!is_player(p)) {
	      p->interpret2("quit");
	      if (p->owner != player)
		i--;
	    }
	  }
	  player->owner->interpret2("quit");
	  return true;
	}


	MudObject *what = (MudObject*)planet->get(argv[1]);
	if (!what) {
		player->printf("Cannot find %s\n", argv[1]);
		return true;
	}
	if (what->get_int("privs") > player->get_int("privs")) {
	  player->printf("I don't think so.\n");
	  return true;
	}

	NewWorld exits;
	MudObject *o;
	int i;
	foreach(what->children, o, i) {
	  if (o->get_flag(FL_EXIT) && o->get_object("start")==what) 
	    exits.add(*o);
	}

	what->interpret2("quit");
	if (what->quit || what->nuke_me) {
	  log(PFL_SEEINFO, 0, "wiz", "%s boots %s", player->id, what->id);

	  foreach((&exits), o, i) {
	    o->nuke_me = 1;
	    player->printf("also removed %s.\n", o->id);
	  }

	  what->printf("You have been booted from %s.\n", THE_MUDNAME);
	} else {
	  player->printf("It didn't boot.\n");
	}
	return true;
}

/*
const char *get_host(Player *p) {
  if (p->p) {
    return msi_get_ip(p->p).c_str();
  }
  return "(linkdead)";
}
*/

extern Socket *primary;
extern Socket *secondary;
extern FILE *logfile;

#include "aberchat.h"

static bool verb_status(MudObject *who, int, const char **) {
	who->printf("Mud status:\n");
	who->printf("Process ID        : %i\n", (int)getpid());
	who->printf("Object instances  : %i\n", objects);
	who->printf("Players connected : %i\n", players->getsize());
	who->printf("Verbs available   : %i\n", verbs->getsize());
	who->printf("States available  : %i\n", states->getsize());
	who->printf("Modules loaded    : %i\n", libs->getsize());
	who->printf("Mobiles           : %s\n", 
				(game_mobiles==1) ?
				"on" : "off");
	if (primary)
	who->printf("Port              : %i\n", primary->port);
	if (secondary)
	who->printf("B&W Port          : %i\n", secondary->port);
	who->printf("AberChat          : %s\n", 
				aberchat_isup ? "up" : "down");
	return true;
}

static bool verb_array(MudObject *who, int argc, const char **argv) {
  if (argc < 2) {
      who->printf("array <object> [<which>]\n");
      return true;
  }

  MudObject *what = find_object(who, argv[1]);
  if (!what) {
    who->printf("Cannot find %s\n", argv[1]);
    return 0;
  }

  if (streq(argv[1], "me")) 
    what = who;
  if (streq(argv[1], "here")) 
    what = who->owner;

  if (argc == 2) 
    {
      Object::intit i = what->ints.begin();
      while(i != what->ints.end()) 
	{
	  const char *key = i->first.c_str();
	  if (key && strstr(key, ".count")) {
	    char *q = strdup(key);
	    *strchr(q, '.')=0;
	    who->printf("%12s %i element%s\n", q, what->get_int(key),
			what->get_int(key)==1?"":"s");
	    free(q);
	  }
	  i++;
	}
      return true;
    }

  int size = what->array_size(argv[2]);
  if (!size) {
    who->printf("%s::%s is either empty or nonexistant.\n", what->id, argv[2]);
    return true;
  }

  for (int i=0;i<size;i++) {
    if (const char *a = what->array_get(argv[2], i)) {
      who->printf("[%2i] %s\n", i, a);
    } else {
      int i = what->array_get_int(argv[2], i, -1);
      if (i != -1) {
	who->printf("[%2i] %i\n", i, a);
      }
    }
  }
  return true;
}

static bool verb_show(MudObject *who, int argc, const char **argv) {
  if (argc < 2) {
      who->printf("Show <what>.\n");
      return true;
  }
  MudObject *what = 0;
  NewWorld whatg = match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS);
  if (whatg.getsize()>1) {
    who->printf("You can only show one thing at a time.\n");
    return true;
  }
  if (whatg.getsize()) {
    what = whatg.get_nth(0);
  }
  
  if (streq(argv[1], "here")) what = who->owner;
  if (streq(argv[1], "me")) what = who;
  if (!what) what = find_object(who, argv[1]);

  bool cleanup = false;

  if (!what) {

    what = new MudObject(argv[1]);
    
    FILE *f = xopen(DATA_USERS, argv[1], "r");
    if (!f) {
      delete what;
      what = 0;
    } else {

      cleanup = true;

      string buf = getline(f);
      while (buf != "}" && !feof(f)) {
	buf = getproperty(f);
	what->load(buf.c_str());
      }
      
      xclose(f);
    }
  }
  
  if (!what) {
    who->printf("Cannot locate : %s\n", argv[1]);
    return true;
  }

  if (!can_affect(who, what->get("zone"))) {
    who->printf("You can't look at that zone.\n");
    if (cleanup) delete what;
    return true;
  }    

  const char *type = "Object";
  if (what->get_flag(FL_ROOM)) type = "Room";
  if (what->get_flag(FL_MOBILE)) type = "Mobile";
  if (is_player(what)) type = "Player";
  
  if (const char *zon=what->get("zone"))
    who->printf("%-9s : ^W%s^n (%s)\n", type, what->id, zon);
  else
    who->printf("%-9s : ^W%s^n\n", type, what->id);

  if (what->mission) {
    who->printf("%-9s : %s\n", "Minimission", what->mission->id);
  }
  
  if (MudObject *ln=what->get_object("link")) {
    if (what->get("short"))
      who->printf("Exit name : %s\n", what->get("short"));
    who->printf("Links to  : %(M\n", ln);
    if (MudObject*dor=what->get_object("door"))
      who->printf("Door      : %(M\n", dor);
  } else {	  
    if (what->get("short"))
      who->printf("Short name: %s\n", what->get("short"));
  }
  
  if (MudObject *clo=what->get_object("cloneof")) {
    who->printf("Clone of  : %(M\n", clo);
  } else if (MudObject *clo=what->get_object("treatas")) {
    who->printf("Treat as  : %(M\n", clo);
  }
  
  MudObject *start=what->get_object("start");
  
  if (what->owner) {
    if (start && !what->get_flag(FL_DESTROYONRESET) && start!=what->owner) {
      who->printf("In        : ^W%(M^n (starts in ^W%(M^n)\n", what->owner, start);
    } else {
      who->printf("In        : ^W%(M^n\n", what->owner);
    }
  }
  
  who->printf("State     : %i (%i)\n", what->get_int(KEY_STATE, 0), what->get_int("initstate", 0));
  if (MudObject *oth=what->get_object("other")) {
    who->printf(" shared w/: %(M\n", oth);
  }
  
  if (what->get_flag(FL_ROOM))
    who->printf("Room name : %s\n", format_roomname(what, NULL).c_str());
  
  if (const char *nom=what->get("building"))
    who->printf("Building  : %s\n", nom);
  
  if (what->get("name"))
    if (what->get("name.plural"))
      who->printf("Name      : %s (%s)\n", what->get("name"), what->get("name.plural"));
    else
      who->printf("Name      : %s\n", what->get("name"));
  
  if (const char *nom=what->get("long"))
    if (const char *plu=what->get("long.plural"))
      who->printf("Long name : %s (%s)\n", nom, plu);
    else
      who->printf("Long name : %s\n", nom);
  
  if (is_mobile(what))
    {
      string inf;
      if (get_gender(what)==GENDER_PLURAL || what->get_flag(FL_PLURAL)) inf += "plural";
      if (get_gender(what)==GENDER_MALE) inf += "male";
      if (get_gender(what)==GENDER_FEMALE) inf += "female";
      if (get_gender(what)==GENDER_ANDRO) inf += "andro";
      if (get_gender(what)==GENDER_NEUTRAL) inf += "neuter";
      
      if (const char *b=what->get("body")) { if (inf.length()) inf += " "; inf += b; }
      else { if (inf.length()) inf += " "; inf += "(human)"; }
      
      if (inf.length())
	who->printf("Body      : %-20s  ", inf.c_str());
      
      const char *nat = nation(what);
      who->printf("Nation    : %s\n", nat);
      
      who->printf("Hardness  : %s (skill: %i)\n", 
		  what->get_priv(PFL_IMMORTAL)?"immortal":
		  what->get("hardness")?what->get("hardness"):"(not set)", 
		  what->get_int("skill.combat", 0));
      
      who->printf("Health    : %3i/%3i      ", strength_of(what), what->get_int("maxstrength"));
      who->printf("Dam : %3i  ", what->get_int("damage"));
      who->printf("Dex : %3i  ", what->get_int("att.dex"));
      who->printf("Str : %3i\n", what->get_int("att.str"));
    }
  
  if (what->get_flag(FL_STORE)) {
    const char *stype = what->get("stype");
    if (!stype) stype = "(unspecified)";
    who->printf("Shop sells: %s\n", stype);
    
    MudObject *sm = what->get_object("shopmob");
    if (!sm)
      who->printf("Shopkeeper: Missing!\n");
    else
      who->printf("Shopkeeper: %(M\n", sm);
  }
  
  if (what->get("wornon")) {
    int wl = what->get_int("wornlevel", 0);
    const char *wls = "";
    switch (wl) {
    case 0: wls = "underwear"; break;
    case 1: wls = "midwear"; break;
    case 2: wls = "outerwear"; break;
    case 3: wls = "overwear"; break;
    case 4: wls = "jewelry"; break;
    case 5: wls = "overall"; break;
    }
    who->printf("Worn on   : %s as %s (%i)", what->get("wornon"), wls, wl);
    if (const char *won=what->get("$wornon")) {
      if (what->get_object("$wornby")==what->owner) {
	who->printf(" (presently %s)", won);
      }
    }
    who->printf("\n");
    
  }
  if (what->get_int("heal")!=-1)
    who->printf("Healing   : %i hp\n", what->get_int("heal"));
  if (what->get_int("armour")!=-1)
    who->printf("Armour    : %i\n", what->get_int("armour"));
  if (!what->get_flag(FL_MOBILE)) {
    if (what->get_int("damage")!=-1) {
      int wt = what->get_int("wtype", 1);
      const char *wts = "bashing";
      if (wt == 2) wts = "cutting";
      if (wt == 5) wts = "stabbing";
      who->printf("Weapon    : %s, doing %i dam\n", wts, what->get_int("damage"));
    }
  }
  
  if (what->get_int("cost")!=-1) {
    who->printf("Cost      : %K", what->get_int("cost"));
    if (what->get_int("value")==0) {
      who->printf(" no resale value");
    }
    who->printf("\n");
  }
  
  if (!what->get_flag(FL_FIXED))
    who->printf("Mass      : %ig\n", mass_in_grams(what));
  int maxload=mass_capacity_in_grams(what);
  if (maxload != SIZE_INFINITE)
    who->printf("Maxload   : %ig\n", maxload);
  
  if (what->get_int("food")!=-1)
    who->printf("Food value: %i\n", what->get_int("food"));
  
  int srv = serving(what);
  if (srv!=-1 && srv != what->get_int("volume"))
    who->printf("Serving   : %i ml\n", srv);
  
  if (abv(what)!=0)
    who->printf("ABV       : %i.%02i%\n", abv(what)/100, abv(what)%100);
  
  if (MudObject *emp=what->get_object("empty")) {
    who->printf("Empty     : %(M\n", emp);
  }
  
  if (what->get_int("ovolume")!=-1)
    who->printf("Volume    : %iml\n", what->get_int("ovolume"));
  if (what->get_int("volume")!=-1)
    who->printf("Capacity  : %iml\n", what->get_int("volume"));
  
  who->spec_printf("^dFlags ^n");
  
  bool thing = 0;
  for (Flag i=FL_FIRST;i<FL_MAX;i++) {
    int a = what->get_rflag(i);
    int b = what->get_flag(i);
    
    if (a || b) {
      
      if (a && b) who->printf("^d[^D%s^d]^n ", flag_names[i]);
      if (!a && b) who->printf("+^d[^D%s^d]^n ", flag_names[i]);
      if (a && !b) who->printf("(-%s) ", flag_names[i]);
      thing = 1;
	}
  }
  
  if (thing) {
    who->printf("\n");
  } else {
    who->cancel_printf();
  }
  
  return true;
}

static void oprintf(MudObject *what, int a, int b, const char *foo, PRINT_ARGS) {
  MudObject *o;
  int i;
  foreach(what->owner->children, o, i) {
    if (what !=o && 
	(privs_of(o) >= a) &&
	(privs_of(o) <= b)
	&& cansee(o)) {
      o->real_printf(foo, GET_PARMS());
    }
  }
}

static bool verb_invis(MudObject *who, int argc, const char **argv) {
  int level = privs_of(who);
  if (argc>1) if (streq(argv[1], "max")) {
  } else {
    MudObject *player;
    player = planet->get(argv[1]);
    if (player) {
      level = privs_of(player)+1;
    } else {
      char *a;
      level = strtol(argv[1], &a, 0);
      if (*a) {
	who->printf("Syntax : invis <level>|<player>|max.\n");
	return true;
      }
    }
  } else {
    if (invis(who)) {
      who->printf("You are already invisible.\n");
      return true;
    }
  }
  if (level > privs_of(who)) {
    who->printf("You can't go invisble to people the same or higher than you.\n");
    return true;
  }
  if (level < 0) {
     who->printf("Invisibility level cannot be less than zero,\n");
     who->printf("Setting you to invisibility level 0.\n");
     level = 0;
  }
  oprintf(who, invis(who), level-1, "%s\n", build_setin(who, setvout).c_str()); // EEPNESS
  who->set("invis", level);
  who->printf("OK, you are now invisible to anyone lower than level %i.\n", level);
  return true;
}

static bool verb_fakequit(MudObject *who, int argc, const char **argv) {
  if (invis(who)==privs_of(who)) {
    who->printf("You are already as invisible as you can go.\n");
    return true;
  }

  MudObject *player = who;

  if (player->owner)
    log(PFL_SEEINFO, 0, "comms", "quitting from %s", player->owner->id);
  else
    log(PFL_SEEINFO, 0, "comms", "quitting from nowhere");

  log(PFL_SEEINFO, privs_of(who), "comms", "above was a fakequit");
  
  player->oprintf(secret(player) && cansee, "%s\n", build_setin(player, setqout).c_str());
  player->lprintf(secret(player) && cansee, "%s\n", build_setin(player, setqout).c_str());
  
  who->set("invis", privs_of(who));
  who->printf("You fake quitting, and now have invis %i.\n", invis(who));
  return true;
}

static void announce_entry(MudObject *p) {
  if (invis(p))
    return;

  MudObject *smith = MUD_ANNOUNCER;
  if (!smith)
    return;

  if (const char *dob = p->get("finger.dob")) {
    if (strlen(dob)==strlen("1979-01-01")) {
      dob += 5;
      char today[100];
      struct tm* t = localtime(&now);
      strftime(today, 100, "%m-%d", t);
      if (streq(dob, today)) {
	smith->interpretf("int Happy birthday, %M^i!", p);
	return;
      }
    }
  }

  smith->interpretf("int Welcome, %M^i.", p);
}

static bool verb_fakelogin(MudObject *who, int argc, const char **argv) {
  int ilev = invis(who);
  if (!ilev) {
    who->printf("You can only fakelogin when invisible.\n");
    return true;
  }

  MudObject *player = who;

  who->set("invis", 0);

  log(PFL_SEEINFO, 0, "net", "(level %i) logged into %s", privs_of(player), player->owner->id);
  log(PFL_SEEINFO, ilev, "comms", "above was a fakelogin");

  announce_entry(who);
 
  player->oprintf(secret(player) && cansee, "%s\n", build_setin(player, setqin).c_str());
  player->lprintf(secret(player) && cansee, "%s\n", build_setin(player, setqin).c_str());
  
  who->printf("You fake logging in, and now have invis %i.\n", invis(who));
  return true;
}

#define min(a, b) (a < b ? a : b)

static bool verb_vis(MudObject *who, int argc, const char **argv) {
  if (!invis(who)) {
    who->printf("You're already visible.\n");
    return true;
  }
  int level = 0;
  if (argc>1) {
    MudObject *player = planet->get(argv[1]);
    if (player) {
      level = min(privs_of(player), invis(who));
    } else {
      who->printf("Syntax : vis [<player>]\n");
      return true;
    }
  }
  oprintf(who, 0, invis(who)-1, "%s\n", build_setin(who, setvin).c_str());
  who->set("invis", level);
  who->printf("You are now visible to anyone at or above level %i.\n", level);
  return true;
}

static bool verb_heal(MudObject *who, int argc, const char **argv) {
    if (argc < 2) {
	who->printf("Heal who?\n");
	return true;
    }
    
    if (!streq(argv[1], "all")) {
      MudObject *what = planet->get(argv[1]);
      if (!what) {

	NewWorld whatg = match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS);
	if (whatg.getsize()>1) {
	  who->printf("You can only heal one person at a time.\n");
	  return true;
	}
	if (whatg.getsize()) {
	  what = whatg.get_nth(0);
	}
      }
      if (!what) what = find_object(who, argv[1]);
      if (!what) { 
	who->printf("Cannot find : %s\n", argv[1]);
      } else {
	if (heal(who, what, -1) && is_player(what))
	  log(PFL_SEEINFO, 0, "wiz", "heals %s", what->id);
      }
    } else {
      MudObject *o;
      int i;
      int c = 0;
      foreach(players, o, i) {
	if (heal(who, o, -1))
	  c++;
      }
      if (c)
	log(PFL_SEEINFO, 0, "wiz", "healall healed %i", c);
    }
    return true;
}


static bool verb_blind(MudObject *who, int argc, const char **argv) {
    if (argc < 2) {
	who->printf("Blind who?\n");
	return true;
    }
    MudObject *target = get_player(who, argv[1]);
    if (!target) {
      who->printf("Blind who?\n");
      return true;
    }
    if(privs_of(target)>=privs_of(who)) {
      target = who;
    }
    if (target->get_flag(FL_BLIND)) {
      if (who==target)
	who->printf("You are already blind.\n");
      else
	who->printf("%#s %s already blind.\n", he_or_she(target), is_are(target));
      return true;
    }
    target->set_flag(FL_BLIND, 1);
    if (target==who) {
      target->printf("You scratch your eyes out.\n");
    } else {
      log(PFL_SEEINFO, 0, "wiz", "blinds %s", target->id);
      who->printf("You scratch %M's eyes out.\n", target);
      target->printf("%#Y %[scratches/scratch] your eyes out.\n", who);
    }
    return true;
}

static bool verb_dumbfound(MudObject *who, int argc, const char **argv) {
    if (argc < 2) {
	who->printf("Silence who?\n");
	return true;
    }
    MudObject *target = get_player(who, argv[1]);
    if (!target) {
      who->printf("Silence who?\n");
      return true;
    }
    if(privs_of(target)>=privs_of(who)) {
      target = who;
    }
    if (target->get_flag(FL_DUMB)) {
      if (who==target)
	who->printf("You are already dumb.\n");
      else
	who->printf("%#s %s already dumb.\n", he_or_she(target), is_are(target));
      return true;
    }
    target->set_flag(FL_DUMB, 1);
    if (target==who) {
      target->printf("You cut your tongue off.\n");
    } else {
      log(PFL_SEEINFO, 0, "wiz", "dumbfounds %s", target->id);
      who->printf("You cut %M's tongue off.\n", target);
      target->printf("%#Y %[cuts/cut] your tongue off.\n", who);
    }
    return true;
}

static bool verb_deafen(MudObject *who, int argc, const char **argv) {
    if (argc < 2) {
	who->printf("Deafen who?\n");
	return true;
    }
    MudObject *target = get_player(who, argv[1]);
    if (!target) {
      who->printf("Deafen who?\n");
      return true;
    }
    if(privs_of(target)>=privs_of(who)) {
      target = who;
    }
    if (target->get_flag(FL_DEAF)) {
      if (who==target)
	who->printf("You are already deaf.\n");
      else
	who->printf("%#s %s already deaf.\n", he_or_she(target), is_are(target));
      return true;
    }
    target->set_flag(FL_DEAF, 1);
    if (target==who) {
      target->printf("You impale your ears.\n");
    } else {
      log(PFL_SEEINFO, 0, "wiz", "deafens %s", target->id);
      who->printf("You impale %M's ears.\n", target);
      target->printf("%#Y %[impales/impale] your ears.\n", who);
    }
    return true;
}

//! return either 'an' or 'a' as appropriate for the given noun
static const char *a_an(const char *a) {
  if (isvowel(a[0])) return "an";
  return "a";
}

static bool verb_mog(MudObject *who, int argc, const char **argv) {
    if (argc < 2) {
      int i=0;
      string blah = "You can turn people into any of: ^Z";
      while (animals[i].noun) {
	const char *n = animals[i].noun;
	i++;
	blah += ssprintf(animals[i].noun?"%s, ":"%s.\n", n);
      }
      who->printf("%s", blah.c_str());
      return true;
    }
    MudObject *target = get_player(who, argv[1]);
    if (!target) {
      who->printf("Turn who into what?\n");
      return true;
    }
    if(privs_of(target)>privs_of(who) && who != target) {
      who->printf("You can't mog %s.\n", him_or_her(target));
      return true;
    }

    const char *noun = argv[2];
    if (noun) {
      if (streq(noun, "bowl")) noun = "bowl of petunias";
      if (streq(noun, "petunias")) noun = "bowl of petunias";
      if (streq(noun, "petunia")) noun = "bowl of petunias";
    }

    const char *adj = 0;
    int i=0;
    while (animals[i].noun) {
      if (noun && streq(animals[i].noun, noun))
	adj = animals[i].adj;
      i++;
    }
    if (!noun) {
      i = random_number(i);
      adj = animals[i].adj;
      noun = animals[i].noun;
    }

    if (!adj) {
      who->printf("Can't turn someone into a '%s'\n", noun);
      return true;
    }

    if (target->get_int("$pigged")>0) {
      if (who==target)
	who->printf("You are already %s.\n", who->get("$piggy"));
      else
	who->printf("%#s %s already %s.\n", he_or_she(target), is_are(target), target->get("$piggy"));
      return true;
    }
    target->set("$pigged", now+(60*5));
    target->set("$piggy", adj);
    if (target==who) {
      target->printf("You turn yourself into %s %s for 5 minutes.\n", a_an(noun), noun);
      if (species(target))
	target->oprintf("%#M %[turns/turn] into a %s.\n", target, species(target));
      log(PFL_SEEINFO, 0, "wiz", "mogs self to %s %s", a_an(noun), noun);
    } else {
      log(PFL_SEEINFO, 0, "wiz", "mogs %s to %s %s", target->id, a_an(noun), noun);
      who->printf("You turn %M into %s %s for 5 minutes.\n", target, a_an(noun), noun);
      target->printf("You have been turned into %s %s.\n", a_an(noun), noun);
      if (species(target))
	target->oprintf("%#M %[turns/turn] into a %s.\n", target, species(target));
    }
    return true;
}

static void supply(MudObject *donor, MudObject *who)
{
  NewWorld s;

  int kitsize = mud->array_size("$supplykit");
  for (int i=0;i<kitsize;i++) {
    if (MudObject *w = mud->array_get_object("$supplykit", i)) {
      if (!holds_clone_of(who, w)) {
	w = clone_object(w, who);
	w->set("zone", "@auto");
	w->set("$clonedby", donor->id);
	w->set("$clonedat", now);
	s.add(w);
      }
    }
  }

  if (s.getsize()) {
    if (who==donor) {
      donor->printf("You gift yourself %s.\n", magiclist(s).c_str());
    } else {
      who->printf("%#M %[gifts/gift] you %s.\n", donor, magiclist(s).c_str());
      donor->printf("You gift %M %s.\n", who, magiclist(s).c_str());
    }
  } else {
    if (donor==who)
      donor->printf("You already have all that.\n");
    else
      donor->printf("%#s already %s all that.\n", he_or_she(who), has_have(who));
  }
  return;
}

static bool verb_supply(MudObject *who, int argc, const char **argv)
{
    if (argc < 2) {
	who->printf("Supply who?\n");
	return true;
    }
    
    MudObject *what = planet->get(argv[1]);
    if (!what) {
      
      NewWorld whatg = match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS);
      if (whatg.getsize()>1) {
	who->printf("You can only supply one person at a time.\n");
	return true;
      }
      if (whatg.getsize()) {
	what = whatg.get_nth(0);
      }
    }
    if (!what) what = find_object(who, argv[1]);
    if (!what) { 
      who->printf("Cannot find : %s\n", argv[1]);
    } else {
      supply(who, what);
    }
    return true;
}

#include "verbmodule.h"

void startup() {

AUTO_VERB(fakequit, 5, 0, PFL_INVIS, VFL_DENYEXISTS);
AUTO_VERB(fakelogin, 5, 0, PFL_INVIS, VFL_DENYEXISTS);

AUTO_VERB(invis, 5, 0, PFL_INVIS);
AUTO_VERB(vis, 3, 0, PFL_INVIS);

ADD_VERB("at", 2, verb_atby, 0, PFL_GOTO);
ADD_VERB("by", 2, verb_atby, 0, PFL_GOTO);

#define verb_restore verb_summon

AUTO_VERB(summon, 3, 0, PFL_NONE);
AUTO_VERB(restore, 5, 0, PFL_NONE);
AUTO_VERB(punt, 3, 0, PFL_NONE);
AUTO_VERB(displace, 2, 0, PFL_BEAM);
AUTO_VERB(trans, 5, 0, PFL_BEAM);
AUTO_VERB(boot, 4, 0, PFL_BOOT);
AUTO_VERB(show, 4, 0, PFL_DETAIL);
AUTO_VERB(status, 5, 0, PFL_STATUS);

AUTO_VERB(array, 4, 0, PFL_DETAIL);

AUTO_VERB(rclone, 4, 0, PFL_GOD);

AUTO_VERB(clone, 4, 0, PFL_CLONE);
AUTO_VERB(copy, 4, 0, PFL_MAKE);
AUTO_VERB(heal, 4, 0, PFL_HEAL);

//AUTO_VERB(dump, 4, 0, PFL_GOTO);
//AUTO_VERB(slurp, 4, 0, PFL_GOTO);

//AUTO_VERB(edit, 4, 0, PFL_CODER);

AUTO_VERB(deafen, 4, 0, PFL_HEAL);
AUTO_VERB(dumbfound, 4, 0, PFL_HEAL);
AUTO_VERB(blind, 4, 0, PFL_HEAL);

AUTO_VERB(mog, 3, 0, PFL_HEAL);

AUTO_VERB(supply, 4, 0, PFL_CLONE);

}