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 Daemon, version 1.0
 * Copyright (C) 1999-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, writ<e to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 */
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#include "musicmud.h"
#include "misc.h"
#include "util.h"
#include "rooms.h"
#include "Player.h"
#include "events.h"
#include "trap.h"
#include "pflags.h"
#include "death.h"
#include "Mission.h"
#include "zoneload.h"
#include "msi.h"
#include "paths.h"
#include "privs.h"
#include "vsprintf.h"
#include "prep.h"
#include "units.h"
#include "shared.h"
#include "musictok.h"
#include "format.h"
#include "pos.h"
#include "body.h"
#include "levels.h"
#include "nations.h"

void restore_stuff(MudObject *who) {
	string corpseid = "@auto_";
	corpseid += who->id;
	MudObject *what = planet->get(corpseid.c_str());
	if (!what)
	  {
	    return;
	  }
	
	World<MudObject> b = *who->children;
	MudObject *o;
	int i;
	foreach((&b), o, i) {
	  o->reset();
	}

	World<MudObject> a = *what->children;
	foreach((&a), o, i) {
	  set_owner(o, who);
	  if (o->get_object("$unreal_wornby")) {
	    o->set("$wornby", o->get("$unreal_wornby"));
	  }
	  if (MudObject *p=o->get_object("$unreal_wieldby")) {
	    p->set(KEY_WIELD, o->id);
	  }
	}

	moveallcash(what, who);

	set_owner(who, what->owner);

	rectify_state(who);

	vanish(what);
}

int canwalk(MudObject *what) {
  if (what->get_flag(FL_CANTWALK))
    return 0;
  return 1;
}

int canswim(MudObject *what) {
  if (wf_wears_with_flag(what, FL_GILLS) || what->get_flag(FL_CANFLOAT))
    return 1;
  return 0;
}


MudObject *mount(MudObject *who) {
  MudObject *m = who->get_object("$mount");
  if (!m) 
    return 0;
  if (m->owner == who->owner || m->owner == who)
    return m;
  who->unset("$mount");
  return 0;
}

string capitalise(string what)
{
  string what2;
  what2 = what;
  what2[0] = toupper(what2[0]);
  return what;
}

void handle_auto(MudObject *o, int rec);

MudObject *clone_object(MudObject *what, MudObject *where, const char *newname, int flags, const char *zone) {
  if (!what)
    return 0;

    string name = newname?:get_clone_name().c_str();
    
    MudObject *thing = new MudObject(name.c_str());

    thing->clone(what);
    planet->add(*thing);    
    set_owner(thing, where);
    thing->set(KEY_STATE, what->get_int(KEY_STATE, 0));
    if (thing->id[0]=='@')
      thing->set_flag(FL_DESTROYONRESET, 1);
    if (!thing->get("cloneof"))
      thing->set("cloneof", what->id);
    if (!thing->get("treatas"))
      thing->set("treatas", what->id);
    if (!zone) zone = "@auto";
    thing->set("zone", zone);

    if (flags & 1) {
      handle_auto(thing, 1);
    }

    return thing;
}

const char*get_wierd() {
  return "You can't do that.";
}

bool is_in(MudObject *child, MudObject *parent) {
	if (parent==child) return true;
	if (!child->owner) return false;
        if (parent == child->owner) return true;
        if (is_in(child->owner, parent)) return true;
	return false;
}

int isnighthour(int i) {
  if (i >= 20) return 1;
  if (i <= 4) return 1;
  return 0;
}

bool is_dark(MudObject *o) {
  while (o) {
    if (o->get_flag(FL_DARK))
      return 1;
    
    if (o->get_flag(FL_OUTDOORS) && isnighthour(mudtime(o).hour))
      return 1;

    o = o->owner;
  }
  return 0;
}

bool has_light(MudObject *where, bool def) {
    Object *obj;
    int i;

    if (!where)
      return false;

    MudObject *w2 = where->owner;

    if (w2) {
      if (is_lit(w2)) 
	return true;
      
      MudObject *w3 = w2->owner;
      if (w3 && is_lit(w3))
	  return true;
    }
    
    if (is_lit(where)) return true;

    if (where->get_flag(FL_LIT) || where->get_flag(FL_ONFIRE)) return true;
    
    foreach(where->children, obj, i) {
	if (has_light((MudObject *)obj, false)) return true;
    }
    
    if (is_dark(where)) return false;
    
    return def;
}

void set_mass_capacity(MudObject *what, int grams) 
{
  what->unset("capacity");
  what->set("maxload", grams);
}

int mass_in_grams(MudObject *where, bool recurse) {
  int used = 0;
  if (recurse) {
    MudObject *o;
    int i;
    foreach(where->children, o, i) {
      used += mass_in_grams(o, recurse);
    }
  }

  if (where->get_int("mass")!=-1) 
    return where->get_int("mass") + used;

  if (where->get_int("size")!=-1) 
    return where->get_int("size") * HECTOGRAM  + used;

  return used;
}

int mass_used_in_grams(MudObject *where) {
  int used = 0, i;
  MudObject *o;
  foreach(where->children, o, i) {
    used += mass_in_grams(o, 1);
  }
  return used;
}

int mass_capacity_uncorrected_in_grams(MudObject *where, int def) {
  int ml = where->get_int("maxload");
  int cp = where->get_int("capacity");
  if (ml != -1) {
    return ml;
  }
  if (cp != -1) {
    return cp * HECTOGRAM;
  }
  return def==-1?SIZE_INFINITE:def;
}

int mass_capacity_in_grams(MudObject *where, int def)
{
  const char *grav=get_zoneprop(where, "gravity");
  if (!grav)
    grav = "1.0";
  int c = mass_capacity_uncorrected_in_grams(where, def);
  if (c == SIZE_INFINITE)
    return c;

  double d = atof(grav);

  if (d==0)
    return SIZE_INFINITE;

  d = c / d;
  
  return (int)d;
}

int mass_capacity_left_in_grams(MudObject *where) {
  if (mass_capacity_in_grams(where)==-1) return SIZE_INFINITE;

  return mass_capacity_in_grams(where) - mass_used_in_grams(where);
}

int object_value(MudObject *what) {
  int value = what->get_int("value");
  int cost = what->get_int("cost", 0);
  if (value == -1) {
    if (cost > 0 && cost < 10)
      return cost - 1;

    return cost * 9 / 10;
  }
  return value;
}

bool player_exist(const char *name)
{
  if (!name || !*name) return false;
  if (strchr(name, '/')) return false;
  if (strchr(name, '.')) return false;
  struct stat who;
  char buffer[1024];
  sprintf(buffer, DATA_USERS "/%s", name);
  int rval = stat(buffer, &who);
  return rval==0;
}



int parmour( MudObject * which ) {
	int armour = which->get_int("armour");
	if (armour==-1) return 0;
	return armour;
}

bool iswornby(const MudObject *what, const MudObject *who) {
    if (what->owner != who) return false;
    return streq(what->get(KEY_WORNBY), who->id);
}

bool iswieldedby(MudObject *what, MudObject *who) {
    const char *wield = who->get(KEY_WIELD);
    if (!wield) return false;
    MudObject *wielded = planet->get(wield);
    if (!wielded) return false;
    if (wielded->owner != who) return false;
    if (wielded->owner == who && what == wielded) return true;
    return false;
} 


int player_armour(MudObject *who) {
	MudObject *o;
	int i;
	int armour = 0;
	foreach(who->children, o, i) {
		int arm = o->get_int("armour");
		if (iswornby(o, who) && arm > 0)
			armour += arm;
	}
	return armour;
}

MudObject *getzone(const char *zonestr) {
  return planet->get(ssprintf("%s_zone", zonestr).c_str());
}

bool permitted_access(MudObject *who, const char *inwhat) 
{
  if (!inwhat)
    return 1;
  char owners[4096];
  strcpy(owners, inwhat);
  char *user = strtok(owners, ",");
  while (user) {
    if (strcasecmp(user, who->id)==0) {
      return true;
    }
    user = strtok(0, ",");
  }
  return false;
}

bool permitted_access(const char *id, const char *inwhat) 
{
  if (!inwhat)
    return 1;
  char owners[4096];
  strcpy(owners, inwhat);
  char *user = strtok(owners, ",");
  while (user) {
    if (strcasecmp(user, id)==0) {
      return true;
    }
    user = strtok(0, ",");
  }
  return false;
}

const char *uninvite(const char *id, const char *inwhat) 
{
  if (!inwhat)
    return "";
  char owners[4096];
  static char newlist[4096];
  newlist[0] = 0;
  int i = 0;

  strcpy(owners, inwhat);
  char *user = strtok(owners, ",");
  while (user) {
    if (strcasecmp(user, id)!=0) {
      if (i)
	strcat(newlist, ",");
      else
	i = 1;
      strcat(newlist, user);
    }
    user = strtok(0, ",");
  }
  return newlist;
}

MudObject *find_free_quarters(MudObject *q) {
  int l = q->array_size("room");
  int i;
  MudObject *free = 0;
  for (i=0;i<l;i++) {
    MudObject *q2 = q->array_get_object("room", i);
    if (q2) {
      if (q2->get("$player") || q2->get_flag(FL_PRIVATE)) {
      } else {
	if (!free)
	  free = q2;
      }
    }
  }
  return free;
}

MudObject *quarters(MudObject *who) 
{
  MudObject *q = who->get_object("quarters");
  if (!q)
    return 0;
  if (q->get_object("$player") != who) {
    who->unset("quarters");
    return 0;
  }
  return q;
}


bool cantouch_zone(const MudObject *who, const char *zonestr) {
	if (who->get_priv(PFL_EDITALL)) {
		return true;
	}
	if (!zonestr) {
		return who->get_priv(PFL_MAKE);
	}
	
	MudObject *zone = getzone(zonestr);

	if (!zone) {
		return false;
	}
	if (zone) {
		const char *author = zone->get("author");
		if (!author) {
			return who->get_priv(PFL_MAKE);
		}
		char owners[4096];
		strcpy(owners, author);
		char *user = strtok(owners, ",");
		while (user) {
			if (streq(user, who->id)) {
				return true;
			}
			user = strtok(0, ",");
		}
	}
	return false;
}


bool can_affect(const MudObject *who, const char *zonestr) {
    if (privs_of(who)>= LEV_COMMODORE) return true;
    if (!zonestr) return false;

    if (!strncmp(zonestr, "@ship", 5)) {
      return 1;
    }

    char zoneobj_name[256];
    sprintf(zoneobj_name, "%s_zone", zonestr);
    MudObject *zone = planet->get(zoneobj_name);
    if (!zone) {
      if (!strncmp(zonestr, "@auto_", 6))
	return true;
      else
	return false;
    }
    if (zone->get_flag(FL_PRIVATE)) 
      return cantouch_zone(who, zonestr);

    MudObject *q = zone->get_object("quest");
    if (!q) return true;
    const char *quest2 = zone->get("quest2");
    if (quest_done(who, q) && !quest2) return true;
    MudObject *q2 = planet->get(quest2);
    if (!quest_done(who, q) && !quest2) return false;
    if (quest_done(who, q2)) return true;
    return false;
}


string bw_name(MudObject *who) {
  return lose_colour(name(who)?:"");
}

int players_in(MudObject *where) {
    int i;
    MudObject *o;
    int players = 0;
    foreach(where->children, o, i) {
	if (is_player(o)) players++;
    }
    return players;
}

bool player_owns_with(MudObject *who, Flag flag) {
    if (flag==FL_NONE) return true;
    MudObject *o;
    int i;
    foreach(who->children, o, i) {
	if (o->get_flag(flag)) return true;
    }
    return false;
}

bool trigger_mobiles(MudObject *where, MudObject *who, MudObject *which, 
		     int incombat) {
    MudObject *o;
    int i;
    const char *dir = which->get("short");
    foreach(where->children, o, i) {
      if (o!=who && o!=which) {
	int bar = 0;
	if (o->get_flag(FL_REFUSEMOVE))
	  bar = 1;
	
	if (o->get_flag(FL_MOBILE)) {
	  
	  if ((streq(dir, "south") && o->get_flag(FL_BARSOUTH)) ||
	      (streq(dir, "north") && o->get_flag(FL_BARNORTH)) ||
	      (streq(dir, "east") && o->get_flag(FL_BAREAST)) ||
	      (streq(dir, "west") && o->get_flag(FL_BARWEST)) ||
	      (streq(dir, "up") && o->get_flag(FL_BARUP)) ||
	      (streq(dir, "down") && o->get_flag(FL_BARDOWN)))
	    bar =1 ;

	}

	if (!bar)
	  continue;
	    
	if (const char *ap=o->get("allowpast")) {
	  if (streq(ap, who->get("nation")))
	    continue;

	  MudObject *bl = block(who);
	  if (bl && streq(bl->get("nation"), ap))
	    continue;
	}
	
	if (!incombat && dotrap(E_BEFOREBAR, who, o, which->get_object("link")))
	  continue;
	/* ::: before_bar o1==barrer, o2==new room; if return 1 then we won't bar, otherwise we will. */
	
	if (!o->get_object("_fighting") || o->get_object("_fighting")==who) {
	  who->printf("%#M %[stops/stop] you from going ^d%s^n.\n", 
		      o, which->get("short"));
	  who->oprintf(avoid(o) && cansee,  "%#M %[stops/stop] %M from going ^d%s^n.\n",
		       o, who,
		       which->get("short"));
	  
	  dotrap(E_AFTERBAR, who, o, which->get_object("link"));
	  /* ::: after_bar o1==barrer, o2==new room; after the %M stops %m from going %s message. */
	  if (o->get("barwhy")) {
	    o->interpret(o->get("barwhy"));
	  }
	  
	  return false;
	}
      }
    }
    return true;
}


bool spare_people_capacity(MudObject *dest) {
    if (dest->get_flag(FL_ONEPERSON) && players_in(dest)>=1) 
	    return false;
    if (dest->get_flag(FL_TWOPERSON) && players_in(dest)>=2)
	    return false;
    return true;
}


bool dryland(MudObject *where) {
  if (where->get_flag(FL_ONWATER) ||
      where->get_flag(FL_UNDERWATER) ||
      where->get_flag(FL_BYWATER)) 
    return false;
  return true;
}

bool inwater(MudObject *where) {
  if (where->get_flag(FL_ONWATER) ||
      where->get_flag(FL_UNDERWATER))
    return true;
  return false;
}

int level_of(const MudObject *who) {
  int a = who->get_int("privs"), b = who->get_int("level");
  if (a > b) return a;
  return b;
}

int player_rank(const void *first, const void *second) {
  Player *a = *((Player **)first);
  Player *b = *((Player **)second);
  int p1 = level_of(a);
  int p2 = level_of(b);
  if (p1>p2) return -1;
  if (p1==p2) return strcmp(a->id, b->id);
  return 1;
}

const char *is_are(MudObject *w) {
  return w->get_flag(FL_PLURAL) ? "are" : "is";
}

const char *it_them(MudObject *w) {
  return w->get_flag(FL_PLURAL) ? "them" : "it";
}

const char *it_they(MudObject *w) {
  return w->get_flag(FL_PLURAL) ? "they" : "it";
}

bool has_pass(MudObject*who) {
  if (!who) return false;
  if (!who->get_flag(FL_LOGGEDIN)) return false;
  if (who->get_flag(FL_MAGICPASS)) return true;
  MudObject *o;
  int i;
  foreach(who->children, o, i) {
    if (o->get_flag(FL_MAGICPASS)) {
      return true;
    }
  }
  return false;
}

void broadcast(const showto &s, const char *txt, PRINT_PARMS) {
  PARMS p = GET_PARMS();
  iforeach(o, *players)
    if (o->get_flag(FL_LOGGEDIN) && s(o))
      o->real_printf(txt, p);
}

void broadcast(const char *txt, PRINT_PARMS) {
  PARMS p = GET_PARMS();
  iforeach(o, *players)
    if (o->get_flag(FL_LOGGEDIN))
      o->real_printf(txt, p);
}

string get_clone_name() {
  while (1) {
    static int object_id = 0; 
    string name = ssprintf("@auto_%06i", object_id);
    object_id++;
    if (!planet->get(name.c_str())) {
      return name;
    }
  }
}

string random_firstname() {
  return (random_number(2) ? random_male:random_female)();
}

string random_shipname() {
  string buffer;
  switch (random_number(4)) {
    case 0 : buffer += "Pride of "; goto placename; break;
    case 1 : buffer += "Spirit of "; goto placename; break;
    case 2 : buffer += "SS "; goto placename; break;
    case 3 : buffer += "SS Saint "; goto firstname; break;
  }
firstname:
  buffer += random_firstname();
  return buffer;
placename:
  buffer += random_placename();
  return buffer;
}

/* the noun */
/* the adjective noun */

void name_mobile(MudObject *who) {
  bool male = random_number(2);

  string first = (male ? random_male : random_female)();
  string surname = random_surname();

  string full = (string)"^P" + first + " " + surname + "^n";

  who->set("short", first);
  who->set("name", full);
  who->set("forename", first);
  who->set("surname", surname);
  who->set("gender", male ? "male" : "female");
}

void add_storeable_eq(MudObject *what, NewWorld &coll) 
{
  MudObject *o;
  int i;
  foreach(what->children, o, i) {
    if (o->get_flag(FL_QUARTERS))
      continue;

    MudObject *clo = o->get_object("cloneof");

    if (!is_mobile(o) && !is_player(o)) {
      add_storeable_eq(o, coll);
    }

    if (o->get_flag(FL_NOSAVE)) 
      continue;
    if (o->mission)
      continue;
    if (!clo)
      continue;
    coll.add(*o);
  }
}

void save_var_zone(const char *zone);

void save_var_data() {
  MudObject *o;
  int i;
  foreach(zones, o, i) 
    if (o->id[0]!='@') {
      save_var_zone(o->id);
    }
  save_var_zone("@space");
  unlink(VARDATA"/var");

  FILE *f = xopen_tmp(STADATA, "mudconf", "w");
  if (f) {  
    mud->save_var(f);
    xclose_confirm(f, STADATA, "mudconf");
  }
}

void save_var_zone(const char *zone) {
  FILE *f = xopen_tmp(VARVAR, zone, "w");
  if (!f)
    return;

  MudObject *o;
  int i;
  
  NewWorld stuff;

  foreach(zones->get(zone)->children, o, i) {
    if (!is_player(o)) {
      o->save_var(f);
    }
    if (o->get_flag(FL_QUARTERS)) {
      add_storeable_eq(o, stuff);
    }

    MudObject *p;
    int j;
    foreach(o->children, p, j) {
      int la = 0;
      if (MUD_COMATOSE && p->get_object("cloneof") == MUD_COMATOSE) {
	if (!stuff.get(p->id)) {
	  stuff.add(*p);
	  p->set("$keepid", p->id);
	  la = 1;
	}
      }
      if (streq(p->get("cloneof"), "template_4")) {
	if (!stuff.get(p->id)) {
	  stuff.add(*p);
	  la = 1;
	}
	p->set("$keepid", p->id);
	p->set("$keepat", p->get("$lastdock"));
      }
      if (p->get_flag(FL_QUARTERS)) {
	la = 1;
      }
    }
  }

  foreach(&stuff, o, i) {
    o->set("!id", i);
  }

  foreach(&stuff, o, i) {
    fprintf(f, "cloneof %s {\n", o->get("cloneof"));
    fprintf(f, "int !id %i\n", o->get_int("!id"));
    if (streq(o->get("zone"), "@ship")) {
      o->set("$keepid", o->id);
    }
    if (o->owner) {
      int i = o->owner->get_int("!id");
      if (i != -1) {
	fprintf(f, "int !inid %i\n", i);
      } else {
	fprintf(f, "string owner \"%s\"\n", o->owner->id);
      }
    }
    o->save_difference(f, o->get_object("cloneof"));
    fprintf(f, "}\n");
  }

  foreach(&stuff, o, i) {
    o->unset("!id");
  }

  xclose_confirm(f, VARVAR, zone);
}

void load_var_data(FILE *f);

void load_var_data(const char *p, const char *a) {
  FILE *f = xopen(p, a, "r");
  if (!f)
    return;

  load_var_data(f);

  xclose(f);
}

void load_var_data() {
  load_var_data(VARDATA, "var");
  MudObject *o;
  int i;
  foreach(zones, o, i) 
    if (o->id[0]!='@') {
      load_var_data(VARVAR, o->id);
    }
  load_var_data(VARVAR, "@space");

  load_var_data(STADATA, "mudconf");
}

void load_var_data(FILE *f) {
  char buffer[4096];
  if (!f)
    return;
  
  NewWorld eq;

  while (!feof(f)) {
    strcpy(buffer, getline(f).c_str());
    if (feof(f)) break;  
    if (strncmp(buffer, "vardata ", 8)==0) {
      char *ptr = strchr(buffer, '"')+1;
      char *ptr2 = strchr(ptr, '"');
      *ptr2 = 0;
      ptr2++;
      MudObject *ob = planet->get(ptr);
      string buf;
      while (buf != "}") {
	buf = getproperty(f);
	if (feof(f))
	  break;
	if (ob)
	  ob->load(buf.c_str());
      }
    } else if (strncmp(buffer, "cloneof ", 8)==0) {
      char *b = strchr(buffer, ' ');
      if (b) b++;
      {
	char *a = strchr(b, ' ');
	if (a)
	  *a = 0;
      }
      MudObject *k = 0;
      if (b)
	k = clone_object(planet->get(b), mud, NULL);

      if (!k) 
	break;

      k->set("zone", "@auto");
      eq.add(k);

      string buf;
      while (buf != "}") {
	buf = getproperty(f);
	if (feof(f))
	  break;
	k->load(buf.c_str());
      }

      if (k->get_object("$keepat")) {
	  k->set("$lastdock", k->get("$keepat"));
	  set_owner(k, "space");
	  k->unset("$keepat");
      }

      if (const char *ki=k->get("$keepid")) {
	if (planet->get(ki))
	  k->nuke_me = 1;
	else
	  k->set("id", ki);
      }
    }
  }

  MudObject *o;
  int i;
  foreach(&eq, o, i) {
    int i2 = o->get_int("!inid");
    if (i2 != -1) {
      MudObject *m;
      int j;
      foreach(&eq, m, j) {
	if (m->get_int("!id")==i2) {
	  set_owner(o, m);
	  continue;
	}
      }
    }    
  }

  foreach(&eq, o, i) {
    o->unset("!inid");
    o->unset("!id");
  }

  return;
}

int holds_flagged_object(MudObject *who, Flag flag) {
        if (!who) return 0;
        if (who->get_flag(flag)) return 1;
        int i;
        MudObject *o;
        foreach(who->children, o, i) {
                int j = holds_flagged_object(o, flag);
                if (j)
		  return j+1;
        }
        return 0;
}

MudObject *get_flagged_object(MudObject *who, Flag flag) {
        if (!who) return 0;
        if (who->get_flag(flag)) return who;
        MudObject *o;
	int i;
        foreach(who->children, o, i) {
	  MudObject *j = get_flagged_object(o, flag);
	  if (j)
	    return j;
        }
        return 0;
}

MudObject *holds_clone_of(MudObject *who, MudObject *what) {
        if (!who || !what) return 0;
        if (who->get_object("cloneof")==what) return who;
        int i;
        MudObject *o;
        foreach(who->children, o, i) {
                MudObject *j = holds_clone_of(o, what);
                if (j)
		  return j;
        }
        return 0;
}


void holset(MudObject *who, int which, int what) 
{
  int holo = who->get_int("holodone", 0);
  holo &= ~(1 << which);
  if (what)
    holo |= (1 << which);
  who->set("holodone", holo);
}

void vanish(MudObject *what)
{
  if (is_player(what)) {
    set_owner(what, MUD_PLAYERHEAVEN);
    return;
  }
  set_owner(what, "empty");
  if (is_mission(what)) {
    set_owner(what, "@musicmud");
    what->unset(KEY_ACCEPTER);
    return;
  }
  if (what->get("cloneof") || what->get_flag(FL_DESTROYONRESET))
    what->nuke_me = 1;
}

int givelimb(MudObject *who, const char *whichlimb)
{
  int had = who->get_int(ssprintf("b.%s", whichlimb).c_str(), 1);
  who->unset(ssprintf("b.%s", whichlimb).c_str());
  return had;
}

bool heal(MudObject *who, MudObject *what, int healing) {
    int strength = strength_of(what);
    int max = what->get_int("maxstrength");

    if (MudObject *body=what->get_object("corpseof")) {
      set_owner(body, what->owner);
      while (body->owner && body->owner->owner && !body->owner->get_flag(FL_ROOM))
	set_owner(body, body->owner->owner);
      what->nuke_me = 1;

      MudObject *o;
      int i;
      foreach(what->children, o, i) {
	const char *wb = o->get(KEY_WORNBY);
#define KEY_WORNON "$wornon"
	const char *wo = o->get(KEY_WORNON);

	set_owner(o, body);
	i--;
	if (streq(o->get("$lootfrom"), body->id)) {
	  o->nuke_me = 1;
	}
	if (streq(wb, what->id)) {
	  o->set(KEY_WORNBY, body->id);
	  o->set(KEY_WORNON, wo);
	}
      }
      if (MudObject *wpn=what->get_object(KEY_WIELD)) {
	if (wpn->owner == body) {
	  body->set(KEY_WIELD, wpn->id);
	}
      }

      what = body;

      body->set_flag(FL_SLEEPING, 0);
      body->set_flag(FL_SITTING, 0);
      body->set_flag(FL_BLIND, 0);
      body->set_flag(FL_DEAF, 0);
      body->set_flag(FL_DUMB, 0);

      who->printf("You revive %M.\n", what);
      who->oprintf(cansee, "%#M %[revives/revive] %P.\n", who, what);

      max = what->get_int("maxstrength");
      set_strength(what, max);
      what->unset(KEY_PISSED);
      what->unset(KEY_BUNNIED);
      what->unset("$pigged");
      what->unset("$piggy");
      what->unset("$trip");
      what->unset("$blissed");
      set_strength(what, max);
      rectify_state(what);
      
      return 1;
    }

    if ((MUD_CORPSE && what->get_object("cloneof") == MUD_CORPSE) ||
	(MUD_DROID && what->get_object("cloneof") == MUD_DROID)) {
      const char *n = name(what);
      if (!n) n = "a ^ocorpse^n";
      who->printf("You cannot revive this %s.\n", remove_articles(n));
      return 0;
    }

    int healed = 0;
    if (what==who) {
      what->spec_printf("You heal yourself.\n");
    } else {
      what->spec_printf("%#M %[heals/heal] you.\n", who);
      who->spec_printf("You heal %M.\n", what); 
    }

    if (what->get_flag(FL_BLIND)) {
      what->set_flag(FL_BLIND, 0);
      healed = 1;
      what->printf("You can see.\n");
      if (who != what) who->printf("%#s %s blind.\n", he_or_she(what), was_or_were(what));
    }
    if (what->get_flag(FL_DEAF)) {
      what->set_flag(FL_DEAF, 0);
      healed = 1;
      what->printf("You can hear.\n");
      if (who != what) who->printf("%#s %s deaf.\n", he_or_she(what), was_or_were(what));
    }
    if (what->get_flag(FL_DUMB)) {
      what->set_flag(FL_DUMB, 0);
      healed = 1;
      what->printf("You can speak.\n");
      if (who != what) who->printf("%#s %s dumb.\n", he_or_she(what), was_or_were(what));
    }
    if (what->get_int(KEY_PISSED)!=-1) {
      what->unset(KEY_PISSED);
      healed = 1;
      what->printf("You are sober.\n");
      if (who != what) who->printf("%#s %s drunk.\n", he_or_she(what), was_or_were(what));
    }
    if (what->get_int("$trip")!=-1) {
      what->unset("$trip");
      healed = 1;
      what->printf("^nYour vision is back to normal.\n");
      if (who != what) who->printf("%#s %s tripping.\n", he_or_she(what), was_or_were(what));
    }
    if (what->get_int("$blissed")!=-1) {
      what->unset("$blissed");
      healed = 1;
      what->printf("^nYou no longer have delusions of divinty.\n");
      if (who != what) who->printf("%#s %s having delusions of divinity.\n", he_or_she(what), was_or_were(what));
    }
    if (what->get_int("$pigged")!=-1) {
      what->unset("$pigged");
      healed = 1;
      what->printf("You are less %s.\n", what->get("$piggy"));
      if (who != what) who->printf("%#s was %s.\n", he_or_she(what), what->get("$piggy"));
      what->unset("$piggy");

      if (species(what))
	what->oprintf("%#M %[turns/turn] into a %s.\n", what, species(what));
    }
    if (what->get_int(KEY_BUNNIED)!=-1) {
      what->unset(KEY_BUNNIED);
      healed = 1;
      what->printf("You no longer see bunnies.\n");
      if (who != what) who->printf("%#s saw bunnies.\n", he_or_she(what));
    }
    int ll = 0;
    int rl = 0;
    if (!givelimb(what, "head")) {
      ll |= (1 << 8);
      rl |= (1 << 8);
      what->printf("You had no head.\n"); 
      healed = 1;
    }

    for (int i=0;i<pairs_n;i++) {
      if (!givelimb(what, pairs[i].left)) { 
	ll |= 1 << i;
	if (pairs[i].depends==-1 || !(ll & (1 << pairs[i].depends))) {
	  what->printf("You had no left %s.\n", pairs[i].single); 
	  if (who != what) who->printf("%#s had no left %s.\n", 
				       he_or_she(what),
				       pairs[i].single); 
	  healed = 1;
	}
      }
      if (!givelimb(what, pairs[i].right)) 
	{ 
	  rl |= 1 << i;
	  if (pairs[i].depends==-1 || !(rl & (1 << pairs[i].depends))) {
	    what->printf("You had no right %s.\n", pairs[i].single); 
	    if (who != what) who->printf("%#s had no right %s.\n", 
					 he_or_she(what),
					 pairs[i].single);
	    healed = 1;
	  }
	}
      if (pairs[i].depends != -1) {
	if (ll & (i << pairs[i].depends)) ll |= 1 << i;
	if (rl & (i << pairs[i].depends)) rl |= 1 << i;
      }
    }

    int fingers = 0;
    for (int i=0;i<8;i++) {
      if (!givelimb(what, ssprintf("finger.%i", i).c_str())) {
	healed = 1;
	if (!(i & 1) && !(ll & (1 << 2)))
	  fingers++;
	if ((i & 1) && !(rl & (1 << 2)))
	  fingers++;
      }
    }
    if (fingers) {
      who->printf("You had %i missing finger%s.\n", fingers, fingers==1?"":"s");
    }

    if (strength < max) {
      
      int newh = strength + healing;
      if (healing == -1) newh = max;
      if (newh > max) newh = max;
      
      what->set(KEY_STRENGTH, newh);
      what->set("!holostrength", newh);
      if (who != what) {
        if (newh != max) {
           what->cancel_printf();
	   what->printf("%#M %s%[heals/heal] your wounds.\n", who,
	   	        newh==max?"":"partially ");
        }
      }
      
      who->printf("%#P %[was/were] at %i/%i.\n",
		  what,
		  strength, max, newh);
      healed = 1;
    }

    if (!healed) {
      who->cancel_printf();
      what->cancel_printf();
      who->printf("%#P %[is/are] fine.\n", what);
      return 0;
    }
    rectify_state(what);
    return 1;
}

MudObject* choose_random_object_from(MudObject *w, fn_t whether) 
{
	int count = 0;
	if (!w) {
		return 0;
	}

	MudObject *o;
	int i;
	foreach(w->children, o, i)
		if (!is_player(o) && (!whether || whether(o))) 
			count++;

	if (!count) {
		return 0;
	}

	int which = random_number(count);
	
	count = 0;

	MudObject *toclone = 0;
	foreach(w->children, o, i) {
		if (!is_player(o) && (!whether || whether(o))) {
			if (count==which)
				toclone = o;
			count++;
		}
	}

	return toclone;
}

MudObject* choose_random_player_from(MudObject *w) 
{
	int count = 0;
	if (!w) {
		return 0;
	}

	MudObject *o;
	int i;
	foreach(w->children, o, i)
		if (is_player(o)) 
			count++;

	if (!count) {
		return 0;
	}

	int which = random_number(count);
	
	count = 0;

	MudObject *toclone = 0;
	foreach(w->children, o, i) {
		if (is_player(o)) {
			if (count==which)
				toclone = o;
			count++;
		}
	}

	return toclone;
}

MudObject* choose_random_object_from(const char *where) 
{
  if (!where) {
    return 0;
  }
  
  return choose_random_object_from(planet->get(where));
}

const char *lang(const char *msg, MudObject *what) 
{
  return msg;
}

bool strhas(int argc, const char **argv, const char *what) {
    for (int i = 0 ; i < argc ; i++) {
	if (streq(argv[i], what)) return true;
    }
    return false;
}

void rectify_state(MudObject *who) {

  if (!streq(body(who), "avian") && who->get_flag(FL_FLYING)
      && !who->get_rflag(FL_FLYING)) {
    who->printf("You fall to the ground.\n");
    who->oprintf(cansee, "%#M %[falls/fall] to the ground.\n", who);
    who->set_flag(FL_FLYING, 0);
  }

  if (MudObject *upon=who->get_object(KEY_SITON)) {
    MudObject *where = who->owner;
    int found = 0;
    for (int i=0;i<where->array_size("tele");i++) {
      if (where->array_get_object("tele", i)==upon) {
	found = 1;
      }
    }
    if (!found && upon->owner != who->owner) {
      who->printf("You fall to the floor.\n");
      who->oprintf("%#M %[falls/fall] to the floor.\n", who);
      who->unset(KEY_SITON);
      who->unset(KEY_SITONN);
    }
  }

  if (who->get_flag(FL_FLYING))
    return;

  if (is_player(who) || is_mobile(who)) {
    MudObject *loc = who->owner;
    if (!loc)
      return;

    if (inwater(loc)) {
      who->set_flag(FL_SWIMMING, 1);
    }    
    if (dryland(loc)) {
      who->set_flag(FL_SWIMMING, 0);
    }    
  }
}

MudObject *archetype(const MudObject *who) {
  MudObject *a = who->get_object("archetype");
  if (a) return a;

  const char *n = nation(who);
  const char *b = body(who)?:"human";

  const char *role = who->get("role");

  MudObject *p = MUD_ARCHSTORE;

  if (p) {
    MudObject *o;
    int i;
    foreach(p->children, o, i) {
      const char *r = o->get("role");

      if (o->get_flag(FL_MOBILE) && streq(o->get("nation"), n) &&
	  o->get_flag(FL_POLICE)==who->get_flag(FL_POLICE) &&
	  streq(body(o), b) &&
	  (r==role || streq(r, role)) &&
	  get_gender(o) == get_gender(who)) 
	return o;
    }
  }

  if (p) {
    MudObject *o;
    int i;
    foreach(p->children, o, i) {
      const char *r = o->get("role");

      if (o->get_flag(FL_MOBILE) && streq(o->get("nation"), n) &&
	  o->get_flag(FL_POLICE)==who->get_flag(FL_POLICE) &&
	  streq(body(o), b) &&
	  (r==role || streq(r, role))) 
	return o;
    }
  }

  return 0;
}


MudObject *replace_with_empty(MudObject *o) {
  MudObject *no = 0;
  if (MudObject *em=o->get_object("empty")) {
    if (o->get_object("cloneof"))
      no = clone_object(em, o->owner, NULL);
    else {
      no = em;
      set_owner(em, o->owner);
    }
  }
  vanish(o);
  return no;
}


const char *wornon(MudObject *o) {
  const char *c = o->get("$wornon");
  if (c) return c;
  return o->get("wornon");
}

bool is_worn(MudObject *o) {
  return streq(o->get(KEY_WORNBY), o->owner->id);
}

MudObject *worn_on(MudObject *by, const char *what, int wol) {
  MudObject*o;
  int i;

  int hsofar = -1;
  MudObject *best = 0;

  if (!what)
    return 0;

  StrTok r(what);

  what = r.next(",");

  while (what) {

    foreach(by->children, o, i) {
      const char *wo = wornon(o);
      if (!wo) continue;

      StrTok r2(wo);
      
      int eq = 0;
      
      wo = r2.next(",");
      
      while (wo) {

	if (streq(what, "allover")) eq = 1;
	if (streq(wo, "allover")) eq = 1;
	
	if (streq(what, wo)) eq = 1;
	
	for (int p=0;p<pairs_n;p++) {
	  if (streq(what, pairs[p].both) && streq(wo, pairs[p].right)) eq = 1;
	  if (streq(what, pairs[p].both) && streq(wo, pairs[p].left)) eq = 1;
	  if (streq(what, pairs[p].left) && streq(wo, pairs[p].both)) eq = 1;
	  if (streq(what, pairs[p].right) && streq(wo, pairs[p].both)) eq = 1;
	}
	
	wo = r2.next(",");
      }
      
      if (is_worn(o) && (eq) && o->get_int("wornlevel",0)>=wol) {
	if (o->get_int("wornlevel",0)>=hsofar) {
	  hsofar = o->get_int("wornlevel",0);
	  best = o;
	}
      }
    }

    what = r.next(",");
  }
  return best;
}


int is_naked(MudObject *who) {
  if (worn_on(who, "body", 0)==0) return 1;
  if (worn_on(who, "legs", 0)==0) return 1;
  return 0;
}


MudObject *worn_provides(MudObject *who, const char *what) 
{
  MudObject *o;
  int i;
  foreach(who->children, o, i) {
    if (iswornby(o, who)) {
      if (streq(o->get("provides"), what))
	  return o;
    }
  }
  return 0;
}

void fixup_lapels(MudObject *who, NewWorld *what)
{
  MudObject *b = worn_on(who, "body", 0);

  MudObject *o;
  int i;
  
  foreach(who->children, o, i) {
    if (!b && o->get_object(KEY_WORNBY)==who && streq(o->get("wornon"), "lapel")) {
      if (what) what->add(*o);
      o->unset(KEY_WORNBY);
    }
    const char *needs = o->get("needs");
    if (needs) {
      if (!worn_provides(who, needs)) {
	if (what) what->add(*o);
	o->unset(KEY_WORNBY);
      }
    }
  }

  if (MudObject *wd=who->get_object(KEY_WIELD)) {
    if (wd->owner != who)
      who->unset(KEY_WIELD);
  }
}

static int countlimb(MudObject *player, string limb) 
{
  if (strncmp(limb.c_str(), "left", 4) &&
      strncmp(limb.c_str(), "right", 5)) 
    return countlimb(player, ssprintf("left%s", limb.c_str()))+
      countlimb(player, ssprintf("right%s", limb.c_str()));
  return player->get_int(ssprintf("b.%s", limb.c_str()).c_str(), 1);
}

inline int MIN(int a, int b)
{
  if (a<b) return a;
  return b;
}

#ifdef INVSLOTS
int freehands(MudObject *player)
{
  int fh = MIN(countlimb(player, "arm"), countlimb(player, "hand"))*((player->get_int("pockets", 10)))/2;
  /* 5 objects per hand */
  MudObject *o;
  int i;
  MudObject *m = mount(player);
  foreach(player->children,o,i) {
    if (iswornby(o, player)) {
      fh += o->get_int("pockets", 0);
    } else if (o !=m) {
      fh --;
    }
  }
  if (fh < 0) return 0;
  return fh;
}
#endif

int used_volume(MudObject *what) 
{
  int i;
  int sofar = 0;
  for (i=0;i<what->array_size("$fillamt");i++) {
    sofar += what->array_get_int("$fillamt", i, 0);
   }
  MudObject *o;
  foreach(what->children,o,i) {
    sofar += o->get_int("ovolume", 0);
  }
  return sofar;
}

MudObject *find_coproom(MudObject *who)
{
  return get_zonepropobj(who, "coproom");
}


#include "shared.h"
#include "shared.cc"


void setpos(MudObject *what, pos_t pos, MudObject *on, int onn) 
{
  what->unset("$siton");
  what->unset("$sitonn");

  what->set_flag(FL_SITTING, 0);
  what->set_flag(FL_SLEEPING, 0);
  what->set_flag(FL_FLYING, 0);
  what->set_flag(FL_SWIMMING, 0);

  switch (pos) {
  case P_STANDING: break;
  case P_SITTING: what->set_flag(FL_SITTING, 1); break;
  case P_LYING: what->set_flag(FL_SLEEPING, 1); break;
  case P_FLYING: what->set_flag(FL_SITTING, 1); break;
  case P_SWIMMING: what->set_flag(FL_SWIMMING, 1); break;
  }
  
  if (on) {
    what->set("$siton", on->id);
    what->set("$sitonn", onn);
  }
}

const char *other_dir(const char *what) {
  if (streq(what, "in")) return "out";
  if (streq(what, "out")) return "in";
  if (streq(what, "north")) return "south";
  if (streq(what, "south")) return "north";
  if (streq(what, "east")) return "west";
  if (streq(what, "west")) return "east";
  if (streq(what, "up")) return "down";
  if (streq(what, "down")) return "up";
  if (streq(what, "rimwards")) return "hubwards";
  if (streq(what, "hubwards")) return "rimwards";
  if (streq(what, "clockwise")) return "anticlockwise";
  if (streq(what, "anticlockwise")) return "clockwise";
  if (streq(what, "aft")) return "fore";
  if (streq(what, "fore")) return "aft";
  if (streq(what, "starboard")) return "port";
  if (streq(what, "port")) return "starboard";
  return 0;
}

string make_lower(const char *c) {
  string t = "";
  while (*c) {
    t += tolower(*c);
    c++;
  }
  return t;
}

const char *drillid(MudObject *o)
{
  if (o->get_object("cloneof")) 
    return o->get("cloneof");
  return o->id;
}

bool wf_wears_clone_of(MudObject *who, MudObject *c)
{
  TeleWorld w = clothes(who);
  MudObject *o;
  int i;
  foreach(&w, o, i)
    if (o==c || o->get_object("treatas")==c)
      return 1;

  return 0;
}

MudObject *wf_wears_with_flag(MudObject *who, Flag f)
{
  TeleWorld w = clothes(who);
  MudObject *o;
  int i;
  foreach(&w, o, i)
    if (o->get_flag(f))
      return o;

  return 0;
}

NewWorld wf_allwearsflag(MudObject *who, Flag f)
{
  NewWorld ret;

  if (who->get_flag(f))
    ret.add(who);

  TeleWorld w = clothes(who);

  MudObject *o;
  int i;
  foreach(&w, o, i) {
    if (o->get_flag(f))
      ret.add(o);
  }

  return ret;
}