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 - Basic Verbs 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 <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>

#include "musicmud.h"
#include "verbs.h"
#include "util.h"
#include "State.h"
#include "flagnames.h"
#include "misc.h"
#include "util.h"
#include "wordwrap.h"
#include "events.h"
#include "trap.h"
#include "pflags.h"
#include "vsprintf.h"
#include "prep.h"
#include "match.h"
#include "msi.h"
#include "levels.h"
#include "move.h"

#include "shared.h"

#include <map>

#define INDENT "  "

#define WIERD get_wierd()

#define MODULE "verbs"



static bool is_canlatch(MudObject *what) 
{
  return what->get_flag(FL_CANLATCH);
}

static char *exitnames[] = {
	"North",
	"East",
	"South",
	"West",
	"Rimwards",
	"Clockwise",
	"Hubwards",
	"Anticlockwise",
	"Fore",
	"Starboard",
	"Aft",
	"Port",
	"Up",
	"Down",
	"In",
	"Out",
	"Other"};


/*
 *
 * "size"     = the actual size of this item. Subitems don't count to the mass
 *
 * "overhead" = the overhead of this item. Subitems DO count to the mass.
 *
 *
 * if neither, then "overhead" = 0
 *
 */


static bool verb_exits(MudObject *player, int argc, const char**) {
    if (!cansee(player)) {
        player->printf("You can't see a thing.\n");
        return true;
    }


    if (!player->owner) {
	player->printf("^WYou are nowhere.\n");
	return true;
    }
    
    player->owner->ref();

    MudObject *obj;
    int i, state=0;
    if (!has_light(player->owner) && !wf_wears_with_flag(player, FL_NIGHTVISION)) {
	player->printf("^WIt's ^Ldark^W!\n");
	return true;
    }

    if (player->owner->get_flag(FL_ONFIRE) && !wf_wears_with_flag(player, FL_NIGHTVISION)) {
        player->printf("^RYou cannot see anything through the smoke and flames.\n");
	return true;
    }
    int clas = 0;
    if (const char *cl=player->get("colours")) {
      if (cl && streq(cl, "classic")) {
	clas = 1;
      }
    }
    player->printf("%sObvious exits are...^n\n",clas?"^r":"^W");


    foreach(player->owner->children, obj, i) {
      obj->set_flag(FL_OBSERVED, 0);
    }

    int had[17] = { 0 };

    for (int j =0; j < 17; j++) {
      foreach(player->owner->children, obj, i) {
        if (obj->get_flag(FL_SECRET)) continue;
	
	MudObject *dest = obj->get_object("link");
	MudObject *door = obj->get_object("door");
	const char *en = obj->get("short");

        if (!en && dest) {
            log (PFL_SEEINFO, 0, "bug",
            "%s has no short",
             obj->id);
           obj->set_flag(FL_OBSERVED, 1);
           continue;
        }
        if (dest && !obj->get_flag(FL_EXIT) && 
                    !obj->get_flag(FL_PARTEXIT)) {
             log (PFL_SEEINFO, 0, "bug",
             "%s apparently an exit but does not have an exit/partexit flag",
             obj->id);
        }
            
	if (obj != player && dest)
	  if ((strcasecmp(en, exitnames[j])==0) || (j==16 && !obj->get_flag(FL_OBSERVED))) {
	    if (!door || (door && !is_closed(door))) {
	      
	      obj->set_flag(FL_OBSERVED, 1);

	      had[j] = 1;

	      if (player->get_flag(FL_NSEW)) {
		if (streq(en, "rimwards") && !had[0]) en = "north";
		if (streq(en, "anticlockwise") && !had[1]) en = "east";
		if (streq(en, "hubwards") && !had[2]) en = "south";
		if (streq(en, "clockwise") && !had[3]) en = "west";
	      }
		
	      string x = ssprintf("\3Ex\4%s\3/Ex\4", en);
	      int i = 14 - strlen(en);
	      while (i>0) {
		x += " ";
		i--;
	      }

	      if (!player->get_priv(PFL_SEESTATS) ||
		  (player->owner->get_flag(FL_MAZE)) &&
		  (!can_affect(player, player->owner->get("zone"))))
		player->printf(INDENT"^d%s : %s%#s^}\n", x.c_str(), 
			       clas?"^{B":"^{D",
			       room_name(dest, player->owner));
	      else { 
		if (argc) 
		  player->printf(INDENT"^d%s : %s%#-30s^} : ^d%s ^d(^D%s^d)^n\n",
				 x.c_str(), 
				 clas?"^{B":"^{D",
				 room_name(dest, player->owner), dest->id, obj->id);
		else
		  player->printf(INDENT"^d%s : %s%#-30s^} : ^d%s^n\n",
				 x.c_str(), 
				 clas?"^{B":"^{D",
				 room_name(dest, player->owner), 
				 dest->id);
	      
	      dest->ref();
	      }
	      state++;
	    }
	  }
      }
    }

    foreach(player->owner->children, obj, i) {
      obj->set_flag(FL_OBSERVED, 0);
    }

    if (!state) {
      player->printf(INDENT"None...\n");
    }
    return true;
}

static bool verb_lookin(MudObject *player, int argc, const char **argv) {
    
    if (argc < 2) {
	player->printf("Look in what?\n");
	return true;
    }
    
    MudObject *what=0;
    NewWorld whatg = match(player, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS);
    if (whatg.getsize()>1) {
      player->printf("You can only look in one thing at a time.\n");
      return true;
    }
    if (whatg.getsize()) {
      what = whatg.get_nth(0);
    }
    
    if (!what) {
	player->printf("Look in what?\n");
	return true;
    }
    
    if (what->array_size("$fill") == 1) {
      describe_liquid_to(player, what);
      return true;
    }

    if (!is_container(what)) {
	player->printf("%#Y^n isn't a container.\n", what);
	return true;
    }
    
    if (is_closed(what) && !what->get_flag(FL_TRANSPARENT)) {
	player->printf("%#Y^n %s closed.\n", what, is_are(what));
	return true;
    }

    MudObject *o;
    int i;
    bool need = true;

    player->spec_printf("%#Y contains : \n", what);

    map<string, NewWorld> m;
    map<string, string> plu;

    foreach(what->children, o, i) {
      if (o->get_flag(FL_EXIT))
	continue;
      
      if (!o->get("name"))
	continue;

      const char *n = name(o);

      if (m.find(n)!=m.end()) {
	m[n].add(o);
      } else {
	NewWorld a;
	a.add(o);
	m[n] = a;
      }

      if (name(o, 1) && plu.find(n)==plu.end()) {
	plu[n] = name(o, 1, 1);
      }
    }
    
    for (map<string, NewWorld>::iterator it=m.begin();it!=m.end();it++) {
      string ph = it->first;
      const char *num = "";
      if (it->second.getsize() != 1) {
	ph = plural_phrase(remove_articles(ph.c_str()));
	if (plu.find(it->first)!=plu.end()) {
	  ph = plu.find(it->first)->second;
	}
	num = numbertostring(it->second.getsize());
      }
      
      if (num[0]) {
	player->printf("  %s %s\n", num, ph.c_str());
      } else {
	if (player->get_priv(PFL_SEESTATS)) {
	  player->printf("  %s (%s)\n", ph.c_str(), it->second.get(0)->id);
	} else {
	  player->printf("  %s\n", ph.c_str());
	}
      }
      need = 0;
    }

    if (need) {
      player->cancel_printf();
      player->printf("%#Y is empty.\n", what);
    }
    
    return true;
}


static bool key_fits(MudObject *key, MudObject *lock) {
	int i_key = key->get_int("key");
	int i_lock = lock->get_int("lock");
	if ((i_key > 0) && ((i_lock % i_key)==0)) return true;
	if (streq(lock->get("key"), key->id)) return true;
	if (streq(lock->id, key->get("lock"))) return true;

	MudObject *ta = key->get_object("treatas");
	if (ta && ta != key)
	  return key_fits(ta, lock);
	
	return false;
}

static void lock_unlock(MudObject *player,MudObject *what, MudObject *with, int to, const char *text, const char *text2=0) {
  if (with) {
    player->printf("You %s %Q with %Y.\n", text, what, with);
    if (!player->get_flag(FL_PLURAL) && text2)
      player->oprintf(cansee, "%#M %s %Q with %P.\n", player, text2, what, with);
    else
      player->oprintf(cansee, "%#M %s%[s/] %Q with %P.\n", player, text, what, with);
  } else {
    player->printf("You %s %Q.\n", text, what, to);
    if (!player->get_flag(FL_PLURAL) && text2)
      player->oprintf(cansee, "%#M %s %Q.\n", player, text2, what);
    else
      player->oprintf(cansee, "%#M %s%[s/] %Q.\n", player, text, what);
  }

  set_locked(what, to);
  
  MudObject *o = what->get_object("other");
  if (o) {
    set_locked(o, to);
    o->oprintf(cansee, "%#Y %s %sed from the other side.\n", o, is_are(what), text);
  }
}

static bool verb_unlock(MudObject *player, int argc, const char *argv[]) {
    if (argc<2) {
	player->printf("Unlock what?\n");
	return true;
    }
    
    MudObject *what=0;
    NewWorld whatg = match(player, argc-1, argv+1, NULL, LOOK_BOTH|FIND_EXITS);
    if (whatg.getsize()>1) {
      player->printf("You can only unlock one thing at a time.\n");
      return true;
    }
    if (whatg.getsize()) {
      what = whatg.get_nth(0);
    }
    
    if (!what) {
	player->printf("Unlock what?\n", argv[1]);
	return true;
    }

    if ((what->get_flag(FL_EXIT)||what->get_flag(FL_PARTEXIT)) && what->get_object("door"))
      what = what->get_object("door");
    
    /* ::: before_try_unlock o1==object we want to lock; return 1 to abort. before everything, including testing that it is locked */
    if (dotrap(E_BEFORETRYUNLOCK, player, what)) 
      return true;

    if (!is_locked(what)) {
      if (!is_canlatch(what)) {
	player->printf("%#Y %s not locked.\n", what, is_are(what));
	return true;
      } else {
	player->printf("%#Y %s not latched.\n", what, is_are(what));
	return true;
      }
    }
        
    if (is_canlatch(what)) {
      if (dotrap(E_BEFOREUNLOCK, player, what)) return true;
      /* ::: before_unlock o1==object to be unlocking, o2==the key (if any); return 1 to abort */
      lock_unlock(player, what, 0, 0, "unlatch", "unlatches");
      set_locked(what, 0);
      return true;
    }

    MudObject *other = what->get_object("other");
    
    if (other && !what->get_flag(FL_CANLOCK) && other->get_flag(FL_CANLATCH)) {
      player->printf("%#Y %[is/are] latched from the other side.\n", what);
      return true;
    }

    int i;
    MudObject *o;
    
    foreach(player->children, o, i) {
      MudObject *oth=o->get_object("other");
      if (key_fits(o, what) || (oth && key_fits(o, oth))) {
	if (dotrap(E_BEFOREUNLOCK, player, what, o)) return true;
	lock_unlock(player, what, o, 0, "unlock");
	set_locked(what, 0);
	return true;
      } 
    }
    
    if (!what->get_flag(FL_CANLOCK)) {
      player->printf("You can't unlock %Y.\n", what);
      return true;
    }
    
    player->printf("You have nothing to unlock %Y with.\n", what);
    return true;
}

static bool verb_close(MudObject *a, int b, const char **c);

static bool verb_lock(MudObject *player, int argc, const char *argv[]) {
  if (argc<2) {
    player->printf("Lock what?\n");
    return true;
  }

    MudObject *what=0;
    NewWorld whatg = match(player, argc-1, argv+1, NULL, LOOK_BOTH|FIND_EXITS);
    if (whatg.getsize()>1) {
      player->printf("You can only lock one thing at a time.\n");
      return true;
    }
    if (whatg.getsize()) {
      what = whatg.get_nth(0);
    }
    
    if (!what) {
	player->printf("Lock what?\n", argv[1]);
	return true;
    }

  if ((what->get_flag(FL_EXIT)||what->get_flag(FL_PARTEXIT)) && what->get_object("door"))
    what = what->get_object("door");

  if (!is_canlock(what) && !is_canlatch(what)) {
    player->printf("%#Y cannot be locked.\n", what);
    return true;
  }

  if (is_locked(what)) {
    player->printf("%#Y %s already locked.\n", what, is_are(what));
    return true;
  }

  if (is_open(what)) {
    verb_close(player, argc, argv);
    if (is_open(what)) {
      return true;
    }
  }
  
  if (is_canlatch(what)) {
    if (dotrap(E_BEFORELOCK, player, what)) return true;
    /* ::: before_lock o1==object to be locking, o2==the key (if any); return 1 to abort */
    lock_unlock(player, what, 0, 1, "latch", "latches");
    return true;
  }

  int i;
  MudObject *o;

  foreach(player->children, o, i) {
    if (key_fits(o, what)) {
      if (dotrap(E_BEFORELOCK, player, what, o)) return true;
      lock_unlock(player, what, o, 1, "lock");
      return true;
    } 
  }
  
  player->printf("You have nothing to lock %M with.\n", what);
  return true;
}


static bool verb_openclose(MudObject *player, int argc, const char *argv[], const char *text, const char * past, int state, const char *already) {
    if (argc<2) {
	player->printf("%#s what?\n", text);
	return true;
    }
    
    MudObject *what=0;
    NewWorld whatg = match(player, argc-1, argv+1, NULL, LOOK_BOTH|FIND_EXITS);
    if (whatg.getsize()>1) {
      player->printf("You can only %s one thing at a time.\n", argv[0]);
      return true;
    }
    if (whatg.getsize()) {
      what = whatg.get_nth(0);
    }
    
    if (!what) {
	player->printf("%#s what?\n", argv[0]);
	return true;
    }

    
    if ((what->get_flag(FL_EXIT)||what->get_flag(FL_PARTEXIT)) && what->get_object("door")) 
      what = what->get_object("door");

    /* ::: before_try_open o1==object we want to lock; return 1 to abort. before everything, including testing that it is closed */
    if (streq(text, "open") && dotrap(E_BEFORETRYOPEN, player, what))
      return true;

    if (!is_canopen(what)) {
	player->printf("You cannot %s %Y.\n", text, what);
	return true;
    }	
    
    if (is_locked(what) && streq(text, "open")) {
	verb_unlock(player, argc, argv);
	if (is_locked(what)) return true;
    }
    
    if (is_open(what)==state) {
	player->printf("%#Y %s already %s.\n", what, is_are(what), already);
	return true;
    }

    if (what && streq(text, "open")) {
	if (dotrap(E_ONOPEN, player, what)) return true;
	/* ::: open o1==object to open; return 1 to abort. if o1=='other' of the object really being opened, o2==the real object, and return 1 doesn't abort. */
    }

    if (what && streq(text, "close")) {
	if (dotrap(E_ONCLOSE, player, what)) return true;
	/* ::: close o1==object to close; return 1 to abort. if o1=='other' of the object really being closed, o2==the real object, and return 1 doesn't abort. */
    }

    MudObject *other = what->get_object("other");

    if(other) {
	    if(streq(text, "open")) {
		    dotrap(E_ONOPEN, player, other, what);
	    } else if(streq(text, "close")) {
		    dotrap(E_ONCLOSE, player, other, what);
	    }
	    set_open(other, state);
	    (other->owner)->aprintf("%#Q %s%[s/].\n", other, text);
    }
    
    set_open(what, state);

    player->printf("You %s %Q.\n", text, what);
    player->oprintf(cansee, "%#M %s%[s/] %Q.\n", player, text, what);
    
    if (what && streq(text, "open")) {
	if (dotrap(E_AFTEROPEN, player, what)) return true;
	/* ::: after_open o1==object opened */
    }

    if (what && streq(text, "close")) {
	if (dotrap(E_AFTERCLOSE, player, what)) return true;
	/* ::: after_close o1==object closed */
    }
    
    if(other) {
	    if(streq(text, "open")) {
		    if (dotrap(E_AFTEROPEN, player, other)) return true;
	    } else if(streq(text, "close")) {
		    if (dotrap(E_AFTERCLOSE, player, other)) return true;
	    }
    }
    
    
    return true;
}

static bool verb_open(MudObject *a, int b, const char **c) {
  return verb_openclose(a, b, c, "open", "opened", 1, "open");
}

static bool verb_close(MudObject *a, int b, const char **c) {
  return verb_openclose(a, b, c, "close", "closed", 0, "closed");
}

static bool names_match(MudObject *what, const char *str)
{
  if (names_match(what->get("name"), str))
    return 1;
  if (names_match(what->get("short"), str))
    return 1;
  if (names_match(what->get("short"), str))
    return 1;
  if (names_match(what->get("altshort"), str))
    return 1;
  return 0;
}


static bool verb_where(MudObject *player, int argc, const char **argv) {
        if (player->get_flag(FL_SLEEPING)) {    
        player->printf("You toss and turn in your sleep.\n");    
        player->oprintf(cansee, "%#M tosses and turns in %s sleep.\n",player, his_or_her(player)); 
        return true;    
    }    

    bool verbose = player->get_priv(PFL_SEESTATS);
    
    if (argc<2) {
	player->printf("Usage: where object\n");
	return true;
    }
    
    if (strlen(argv[1])<2) {
	player->printf("Where is what?\n");
	return true;
    }

    bool noclones = argv[1][0] == '|';
    if (noclones)
      argv[1]++;

    if (!is_player(player))
      return true;

    Divert d(player, "where");
    
    MudObject *o;
    int i;
    int found=0;
    MudObject *empty = planet->get("empty");

    foreach_alpha(planet, o, i) {
      MudObject *owner = o->owner;
      if (noclones && o->get_object("cloneof"))
	continue;
      if (o->get_flag(FL_ROOM))
	continue;
      if (!owner || owner == empty || owner == mud)
	continue;
      if (o->get("link"))
	continue;
      if (!visible_to(player, o))
	continue;
      if (!verbose && o->get_flag(FL_UNLOCATEABLE))
	continue;
      if (!names_match(o, argv[1]))
	continue;
      if (!o->get("name"))
	continue;

      const char *ran = remove_articles(o->get("name"));
      MudObject *room = owner;
      while (!(room->get_flag(FL_ROOM) || room->get_flag(FL_SHIP)) && room->owner) {
	room = room->owner;
      }
      if (!room->get_flag(FL_ROOM) && !room->get_flag(FL_SHIP))
	room = owner;
      
      string rsh = ran;
      
      size_t nonidspace = 35-strlen(o->id);
      int capornot = 0;
      
      string owh = owhere(o, room);
      if (!owh.length())
	continue;
      
      if (colour_strlen(ran, colinfo(player))>=(nonidspace-2)) {
	
	if (o->get_flag(FL_MOBILE)) {
	  rsh = "^P";
	  rsh += o->get("short")?:"???";
	  rsh += "^n";
	  capornot = 1;
	} else {
	  rsh = "^o";
	  rsh += o->get("short")?:"???";
	  rsh += "^n";
	}
      }
      
      char fmt[100];
      sprintf(fmt, "%%s %%%s%is - %%-40s\n", capornot?"#":"", nonidspace);

      player->printf(fmt, o->id, rsh.c_str(), owh.c_str());
      
      found = 1;
    }

    if (found == 0) 
      player->printf("Nothing like that could be located.\n");

    return true;
}

static bool verb_echo(MudObject *player, int argc, const char *argv[]) {
    if (player->get_flag(FL_SLEEPING)) {    
        player->printf("You toss and turn in your sleep.\n");    
        player->oprintf(cansee, "%#M tosses and turns in %s sleep.\n",player,his_or_her(player)); 
        return true;    
    }    
    string buffer = the_rest(argc, argv, 1);
    if (buffer.length()==0) {
      player->printf("Echo what?\n");
      return true;
    }
    string buffer2 = sprinta(0, buffer.c_str(), player, 0, 0);
    MudObject *o; int i;
    if (is_player(player)) 
      log(PFL_ECHO,0,"echo","in %s: '%s'"
	  ,player->get("owner")
	  , buffer2.c_str());
    player->oprintf("%s\n", buffer2.c_str());
    player->printf("You echo : '%s'\n", buffer2.c_str());
    foreach(player->children, o, i) 
      if (is_mobile(o) || is_player(o)) {
	o->printf("%s\n", buffer2.c_str());
      }
    return true;
}

bool is_ininv(const TeleObject &what)
{
  if (is_person(what.where))
    return 1;
  return 0;
}

bool is_person(const TeleObject &what)
{
  return is_person(what.what);
}

static bool verb_inject(MudObject *who, int argc, const char **argv)
{
  if (argc<2) {
    who->printf("Inject what?\n");
    return true;
  }

  TeleWorld prepless = multi_match(who, argc-1, argv+1, is_ininv, LOOK_BOTH|IGNORE_EXITS);
  TeleWorld blank;
  if (prepless.prep) {
    prepless = blank;
  }  

  TeleWorld into = multi_match(who, argc-1, argv+1, is_person, LOOK_BOTH|IGNORE_EXITS, 0, 0, "into");
  TeleWorld with = multi_match(who, argc-1, argv+1, NULL, LOOK_INV|IGNORE_EXITS, 0, 0, "with");

  if (into.prep && with.prep && prepless.txt.length()) {
    who->printf("Inject what into who?\n");
    return true;
  }

  if (!with.prep && !into.prep) {
    with = prepless;
    into.add(who);
  } else if (!with.prep) {
    with = prepless;
  } else if (!into.prep) {
    into = prepless;
    if (prepless.txt=="") {
      into.add(who);
    }
  }

  if (into.getsize()>1) {
    who->printf("You can only inject into one person at a time.\n");
    return true;
  }

  if (with.getsize()>1) {
    who->printf("You can only inject with one implement at a time.\n");
    return true;
  }

  if (into.getsize()==0) {
    who->printf("Inject who?\n");
    return true;
  }

  if (with.getsize()==0) {
    who->printf("Inject with what?\n");
    return true;
  }

  MudObject *needle = with.get(0).what;
  MudObject *victim = into.get(0).what;

  /* ::: before_inject o1==object to inject, o2==thing to inject into; return 1 to not give error */
  if (dotrap(E_BEFOREINJECT, who, needle, victim))
    return true;

  if (victim != who) {
    who->printf("You can't inject into %s.\n", him_or_her(victim));
    return true;
  }

  /* ::: inject o1==object to inject; return 1 to not give error message */
  if (dotrap(E_ONINJECT, who, needle))
    return true;

  who->printf("You can't inject %M.\n", needle);
  return true;
}

static bool verb_hook(MudObject *player , int argc, const char **argv) {
	
  int next = 1;
  TeleWorld w1 = multi_match(player, argc-next, argv+next, NULL, LOOK_BOTH|IGNORE_EXITS, &next, 0, 0);
  TeleWorld w2;
  if (next < argc) {
    w2 = multi_match(player, argc-next, argv+next, NULL, LOOK_BOTH|IGNORE_EXITS, &next, 0, 0);
  }

  MudObject *what=0, *what2=0;
  if (w1.getsize()) { what  = w1.get_nth(0); }
  if (w2.getsize()) { what2 = w2.get_nth(0); }

  if (streq(argv[0], "combine") && w1.getsize()==2 && w2.getsize()==0) {
    what2 = w1.get_nth(1);
  } else if (w1.getsize()>1) {
    if (streq(argv[0], "combine")) {
      player->printf("You can only combine two things at a time.\n", argv[0]);
    } else {
      player->printf("You can only %s one thing at a time.\n", argv[0]);
    }
    return true;
  }

  if (w2.getsize()>1) {
    player->printf("You can only %s %s one thing at a time.\n", argv[0], w2.prep);
    return true;
  }

    // FIXME : HARDCODED SPECIAL
    if (streq(argv[0], "press") || streq(argv[0], "push") && argv[1]) {
      if (dotrap(E_ONPRESSTEXT, player, player->owner, 0, argv[1]))
	/* ::: press_text o1==the room, txt==text after 'press' or 'push'; return 1 to abort */
	return true;
    }
  
    if (what && what->get_flag(FL_PUSHTOGGLE)) {
	if (streq(argv[0], "press") || streq(argv[0], "push") || streq(argv[0], "move") || streq(argv[0], "heave")) {
	    if (state(what)) {
		what->set(KEY_STATE, 0);
	    } else {
		what->set(KEY_STATE, 1);
	    }
	    int nowstate = state(what);
	    if (const char *up=what->get(ssprintf("user.push.%i", nowstate).c_str()))
		player->printf("%s\n", up);
	    else if (what->get("reveal"))
	      player->printf("You push %Y, %s %s.\n", what, nowstate?"blocking":"revealing", what->get("reveal"));
	    else
	      player->printf("You push %Y.\n", what);

	    if (const char *op=what->get(ssprintf("others.push.%i", nowstate).c_str()))
	      player->oprintf(cansee, "%s\n", op);
	    else if (what->get("reveal"))
	      player->oprintf(cansee, "%#M pushes %Y, %s %s.\n", player, what, nowstate?"blocking":"revealing", what->get("reveal"));
	    else
	      player->oprintf(cansee, "%#M pushes %P.\n", player, what);
	    
	    MudObject *o = what->get_object("other");
	    if (o && o->get("reveal")) {
	      o->set(KEY_STATE, nowstate);
	      
	      o->oprintf(cansee, "%#M %[is/are] pushed from the other side, %s %s.\n", nowstate?"blocking":"revealing", o->get("reveal"));
	    }
	
	    if (MudObject *light=what->get_object("light"))  {
	      int lit = !nowstate;
	      light->set_flag(FL_LIT, lit);
	      light->oprintf(cansee, lit ? "%#Y %[illuminates/illuminate].\n" : 
			     "%#Y %[is/are] extinguished.\n", light);
	    }
	    return true;
	}
    }    

    if (what && (streq(argv[0], "push") || streq(argv[0], "press") || streq(argv[0], "move"))) {
	if (dotrap(E_ONPUSH, player, what)) 
	/* ::: push o1==object to push/press/move; return 1 to abort */
	  return true;

        if (dotrap("press", player, what))
          return true;

	/* ::: push_mount o1==object being mounted by someone who has been pushed, o2==the person themself; return 1 to abort */
	if (MudObject *m=mount(what)) {
	  if (dotrap(E_ONPUSHMOUNT, player, m, what))
	    return true;
	}
    }

    if (streq(argv[0], "climb")) {
      if (what) {
        if (MudObject *m=mount(player)) {
	  player->printf("You can't climb whilst you are on %Y.\n", m);
	  return true;
	}

	if (player->get_flag(FL_FLYING)) {
	  player->printf("You are flying and so climbing would be silly.\n");
	  return true;
	}

	if (player->get_flag(FL_SITTING)) {
	  player->printf("Try standing up first.\n");
	  return true;
	}
	
	/* ::: climb o1==object to climb; return 1 to abort */
        if (dotrap(E_ONCLIMB, player, what)) 
	  return true;

	if (what->get("climbto")) {
	  traverse(player, what);
	  return true;
	}
      } else {
	player->interpret("climbs");
	return true;	
      }
    }

    if (what && streq(argv[0], "turn")) {
	/* ::: turn o1==object to turn; return 1 to abort */
	if (dotrap(E_ONTURN, player, what)) return true;
    }

    if (what && streq(argv[0], "combine")) {
      /* ::: combine o1==an object, o2==another object; called both ways; return 1 to abort */
      if (what2) {
	if (dotrap(E_ONCOMBINE, player, what, what2)) return true;
	if (dotrap(E_ONCOMBINE, player, what2, what)) return true;
      } else {
	player->printf("Combine %M with what?\n", what);
	return 1;
      }
    }

    if (streq(argv[0], "tie")) {
      if (what && !what2) {
	player->printf("Tie %P to what?\n", what);
	return true;
      }

      if (what && what2) {
	/* ::: tie o1==object, o2==object to; return 1 to abort */
	if (dotrap(E_ONTIE, player, what, what2)) 
	  return true;
      }
    }

    if (streq(argv[0], "untie")) {
      if (what) {
	/* ::: untie o1==object, o2==object from (if applicable); return 1 to abort */
	if (dotrap(E_ONUNTIE, player, what, what2)) return true;
      }
    }

    if (what && streq(argv[0], "cut")) {
	if (dotrap(E_ONCUT, player, what, what2)) return true;
	/* ::: cut o1==target, o2==tool; return 1 to abort */
    }

    if (what && streq(argv[0], "sign")) {
	if (dotrap(E_ONSIGN, player, what)) return true;
	/* ::: sign o1==target; return 1 to abort */
    }

    if (what && streq(argv[0], "kick")) {
	if (dotrap(E_ONKICK, player, what)) return true;
	/* ::: kick o1==target; return 1 to abort */
	if (what && what->get_flag(FL_FRAGILE)) {
	  player->printf("You kick %P, smashing %s.\n", what,
			 him_or_her(what));
	  player->oprintf(cansee, "%#M %[kicks/kick] %P, smashing %s.\n", 
			 player, what, him_or_her(what));
	  vanish(what);
	  return true;
	}
	player->interpretf("kicks %s", argv[1]);
	return true;
    }

    if (what && streq(argv[0], "lift")) {
	/* ::: lift o1==target; return 1 to abort */
       if (dotrap(E_ONLIFT, player, what)) return true;
    }

    if (what && streq(argv[0], "pull")) {
	/* ::: pull o1==target; return 1 to abort */
	if (dotrap(E_ONPULL, player, what)) return true;
    }

    if (streq(argv[0], "trap")) {
      if (argv[1]) {
	dotrap(ssprintf("trap.%s", argv[1]).c_str(), player, player, 0, argv[1]);
      }
	/* ::: trap o1==target, txt==the text; return 1 to abort */
      dotrap(E_ONTRAP, player, player, 0, argv[1]);
      return true;
    }

    if (streq(argv[0], "swing")) {
      if (!what) {
	player->printf("Swing on what?\n");
	return true;
      }
	/* ::: swing o1==target; return 1 to abort */
      if (dotrap(E_ONSWING, player, what, 0, 0))
	return true;
      player->printf("You cannot swing on that.\n");
      return true;
    }

    if (streq(argv[0], "clean")) {
      /* ::: clean o1==the room/object; return 1 to abort */
      if (what)
	if (dotrap(E_ONCLEAN, player, what, 0, 0)) return true;
      if (!what || what->get_flag(FL_FLOOR)) {
        if (dotrap(E_ONCLEAN, player, player->owner, 0, 0)) return true;
	player->printf("You clean up your act.\n");
	player->oprintf(cansee, "%#M cleans up %s act.\n", player, his_or_her(player));
      } else {
	player->printf("You can't clean that.\n");
      }
      return true;
    }

    if (streq(argv[0], "jump")) {
      if (MudObject *m=mount(player)) {
	/* ::: jump_mount o1==mount; return 1 to abort */
	if (dotrap(E_ONJUMPMOUNT, player, m, 0, 0))
	  return true;
	player->printf("You can't jump when on %M.\n", m);
	return true;
      }

      if (player->get_flag(FL_FLYING)) {
	player->printf("You are flying and cannot jump.\n");
	return true;
      }

      if (player->get_flag(FL_SWIMMING)) {
	player->printf("You are swimming and cannot jump.\n");
	return true;
      }

      if (player->get_flag(FL_SITTING)) {
	player->printf("You are sitting and cannot jump.\n");
	return true;
      }

      if (what) {
	if (dotrap(E_ONJUMPON, player, what)) return true;
	/* ::: jump_on o1==object to jump on; return 1 to abort */
      }

      if (MudObject *o=player->get_object(KEY_SITON)) {
	if (dotrap(E_ONJUMPSTANDING, player, o))
	  /* ::: jump_standing o1==object you are standing on (not floor); return 1 to abort. */
	  return true;
      }

      /* ::: jump o1==room; return 1 to abort */
      if (dotrap(E_ONJUMP, player, player->owner)) return true;
      
      player->printf("You jump.\n");
      player->oprintf(cansee, "%#M %[jumps/jump].\n", player);
      return true;
    }
    
    if (what) {
      if (what2 || !w2.txt.length()) {
	player->printf("Nothing happens when you do that.\n");
      } else {
	player->printf("Cannot find : ^o%s^n.\n", w2.txt.c_str());
      }
    } else {
        if (argc > 1) {
	    player->printf("Cannot find: ^o%s^n.\n", w1.txt.c_str());
        } else {
	    player->printf("What do you want to %s?\n", argv[0]);
        }
    }
    
    return true;
}

static const char *make_id(const char *zone, const char *abbrv) {
  int i = 1;
  static char temp[1024];
  while (1) {
    if (abbrv) sprintf(temp, "%s_%s_%i", zone, abbrv, i); else
    sprintf(temp, "%s_%i", zone, i);
    if (planet->get(temp)==0) return temp;
    i++;
  }
}

static const char *expand_dir(const char *dir) {
  if (streq(dir, "n")) return "north";
  if (streq(dir, "s")) return "south";
  if (streq(dir, "e")) return "east";
  if (streq(dir, "w")) return "west";
  if (streq(dir, "u")) return "up";
  if (streq(dir, "d")) return "down";
  if (streq(dir, "a")) return "anticlockwise";
  if (streq(dir, "r")) return "rimwards";
  if (streq(dir, "h")) return "hubwards";
  if (streq(dir, "c")) return "clockwise";
  if (streq(dir, "i")) return "in";
  if (streq(dir, "o")) return "out";
  return dir;
}

void dig_exit(MudObject *player, const char *z, const char *dir) {
    if (!cantouch_zone(player, z))  {
      player->printf("Sorry, you can't modify %s zone.\n", z);
      return;
    }

    string id = make_id(z, 0);
    MudObject *r = new MudObject(id.c_str());
    planet->add(*r);

    string start = ssprintf("%s_zone", z);
    set_owner(r, start.c_str());
    if (r->owner==NULL) {
      set_owner(r, "@musicmud");
    }
    r->set("start", r->owner->id);
    r->set_bflag(FL_ROOM, 1);
    r->set_bflag(FL_OUTDOORS, player->owner->get_flag(FL_OUTDOORS));
    r->set_bflag(FL_LIT, player->owner->get_flag(FL_LIT));
    r->set_bflag(FL_AIRLESS, player->owner->get_flag(FL_AIRLESS));
    r->set_bflag(FL_NOGRAVITY, player->owner->get_flag(FL_NOGRAVITY));
    r->set("name", "new room");
    r->unreset();

    id = ssprintf("%s_%s", player->owner->id, dir);
    MudObject *x = new MudObject(id.c_str());
    planet->add(*x);

    set_owner(x, player->owner);
    x->set("link", r->id);
    x->set("short", dir);
    x->set("start", player->owner->id);

    id = ssprintf("%s_%s", r->id, other_dir(dir));
    MudObject *x2 = new MudObject(id.c_str());
    planet->add(*x2);

    set_owner(x2, r->id);
    x2->set("link", player->owner->id);
    x2->set("short", other_dir(dir));
    x2->set("start", r->id);

    x->set("zone", z);
    r->set("zone", z);
    x2->set("zone", z);
    
    x->set_bflag(FL_FIXED, 1);
    x2->set_bflag(FL_FIXED, 1);
    x->set_bflag(FL_EXIT, 1);
    x2->set_bflag(FL_EXIT, 1);

    player->printf("You dig ^D%s^n to ^D%s^n.\n", dir, r->id);
    player->set("lastmaderoom", r->id);

    log(PFL_SEEINFO, 0, "make", "new room : %s", r->id);

    return;
}

static bool verb_dig(MudObject *player, int argc, const char **argv) {
  if (argc > 1 && player->get_priv(PFL_MAKE)) {

    argv[1] = expand_dir(argv[1]);
    const char *z = player->owner?player->owner->get("zone"):NULL;
    
    if (other_dir(argv[1]) && z && player->owner) {
      dig_exit(player, z, argv[1]);
      return true;
    }
  }
    
  /* ::: dig o1==room; return 1 to abort */
  if (dotrap(E_ONDIG, player, player->owner)) return true;

  MudObject *where = player->owner;
  MudObject *buried = where->get_object("!buried");
  if (buried) {
    player->printf("You find %P not far below the surface.\n", buried);
    player->oprintf(cansee, "%#M finds %P not far below the surface.\n", player, buried);
    set_owner(buried, where);
    where->unset("!buried");
    return true;
  }

  MudObject *fl = floor(where);

  if (!fl) {
    player->printf("You can't dig here.\n");
    return true;
  }

  if (fl->get_int("candig", 1)==0) {
    player->printf("You cannot dig through %Y.\n", fl);
    return true;
  }

  player->printf("You exert yourself needlessly, and find nothing.\n");
  player->oprintf(cansee, "%#M attempts to dig for something, needlessly.\n",
		  player);
  return true;
}

#include "verbmodule.h"

#define HOOK_VERB(str, p, pfl) ADD_VERB(#str, strlen(#str), verb_hook, p, pfl)

void startup() {
AUTO_VERB(lookin,    5, 0,       PFL_AWAKE);
AUTO_VERB(exits,     3, 0,       PFL_AWAKE);

AUTO_VERB(lock,      3, 0,       PFL_AWAKE);
AUTO_VERB(unlock,    2, 0,       PFL_AWAKE);

ADD_ALIAS(latch, 3, lock);
ADD_ALIAS(unlatch, 4, unlock);

AUTO_VERB(open,      2, 0,       PFL_AWAKE);
AUTO_VERB(close,     4, 0,       PFL_AWAKE);

ADD_ALIAS(shut, 4, close);

HOOK_VERB(climb, 0, PFL_AWAKE);
HOOK_VERB(cut, 0, PFL_AWAKE);
HOOK_VERB(heave, 0, PFL_AWAKE);
HOOK_VERB(press, 0, PFL_AWAKE);
HOOK_VERB(push, 0, PFL_AWAKE);
//HOOK_VERB(inject, 0, PFL_AWAKE);
HOOK_VERB(pull, 0, PFL_AWAKE);
HOOK_VERB(tie, 0, PFL_AWAKE);
HOOK_VERB(turn, 0, PFL_AWAKE);
HOOK_VERB(combine, 0, PFL_AWAKE);
HOOK_VERB(clean, 0, PFL_AWAKE);
HOOK_VERB(untie, 0, PFL_AWAKE);
HOOK_VERB(sign, 0, PFL_AWAKE);
HOOK_VERB(swing, 0, PFL_AWAKE);
HOOK_VERB(move, 0, PFL_AWAKE);
HOOK_VERB(jump, 0, PFL_AWAKE);
HOOK_VERB(kick, 0, PFL_AWAKE);
HOOK_VERB(lift, 0, PFL_AWAKE);
HOOK_VERB(trap, 0, PFL_AWAKE);

 AUTO_VERB(inject, 3, 0, PFL_AWAKE);

AUTO_VERB(where, 3, 0, PFL_WHERE);

AUTO_VERB(dig, 3, 0, PFL_AWAKE);

AUTO_VERB(echo, 4, 0, PFL_ECHO);
}