/* wiz.c */

#include <sys.h>
#include <secure.h>
#include <flags.h>
#include <armor.h>

string name;
string low_name;
string password;
string path;
int doing_ls;
int is_invis;
int flags,programmer,special;
object possessing;

force_disconnect() {
  if (!priv(caller_object())) return 0;
  disconnect_device();
  disconnect();
  return 1;
}

stat() {
  if (priv(this_object())) tell_player(this_player(),"Object Type: WIZARD\n");
  else if (programmer)
    tell_player(this_player(),"Object Type: PROGRAMMER\n");
  else tell_player(this_player(),"Object Type: BUILDER\n");
  if (flags) tell_player(this_player(),"Flags:"+make_flags(flags)+"\n");
  if (special) tell_player(this_player(),"Special: "+itoa(special)+"\n");
  tell_player(this_player(),"Name: "+name+"\n");
  if (priv(this_player()) && possessing)
    tell_player(this_player(),"Possessing: "+make_num(possessing)+"\n");
  return 1;
}

static do_stat(arg) {
  if (!arg) {
    write("usage: @stat object\n");
    return 1;
  }
  arg=resolve_object(arg);
  if (!arg) {
    write("@stat: couldn't find object\n");
    return 1;
  }
  if (!call_other(arg,"stat"))
    write("@stat: no stats reported\n");
  return 1;
}

static command_possessed(arg) {
  if (possessing)
    call_other(possessing,"force",arg);
  else
    write("$: You aren't currently possessing anything.\n");
  return 1;
}

static do_possess(arg) {
  if (!arg) {
    if (possessing)
      write("@possess: you are currently possessing "+make_num(possessing)+
            "\n");
    else
      write("@possess: you are not currently possessing anything.\n");
    return 1;
  }
  if (arg=="off") {
    if (possessing) {
      call_other(possessing,"set_possessor",0);
      write("@possess: you are no longer possessing "+make_num(possessing)+
            "\n");
      possessing=0;
    } else
      write("@possess: you are not currently possessing anything.\n");
    return 1;
  }
  if (possessing) {
    write("@possess: you are already possessing "+make_num(possessing)+"\n");
    return 1;
  }
  arg=resolve_object(arg);
  if (!arg) {
    write("@possess: couldn't find object\n");
    return 1;
  }
  if (!programmer && !priv(this_object()) && call_other(arg,"get_owner")!=
      this_object()) {
    write("@possess: you don't own that object\n");
    return 1;
  }
  if (call_other(arg,"set_possessor",this_object())) {
    write("@possess: you are now possessing "+make_num(arg)+"\n");
    possessing=arg;
  } else
    write("@possess: failed\n");
  return 1;
}

possession_report(arg) {
  return listen("%"+arg);
}

get_flags() { return flags; }
get_special() { return special; }
set_special(s) { special=s; return 1; }
set_flags(f) { flags=f; return 1; }


do_create(arg) {
  string arg_type,name;
  int pos;
  object o,dest;

  pos=instr(arg,1," ");
  arg_type=leftstr(arg,pos-1);
  name=rightstr(arg,strlen(arg)-pos);
  if (!arg || !name) {
    write("usage: @create monster|room|exit|weapon|armor|coins|object|shop "+
          "               name [destination (for exits)]\n");
    return 1;
  }
  if (arg_type=="room") {
    o=clone_object("/obj/room");
    call_other(o,"set_owner",this_object());
    call_other(o,"set_short",name);
  } else if (arg_type=="armor") {
    o=clone_object("/obj/armor");
    call_other(o,"set_owner",this_object());
    call_other(o,"set_name",name);
    move_object(o,this_object());
  } else if (arg_type=="shop") {
    o=clone_object("/obj/shop");
    call_other(o,"set_short",name);
    call_other(o,"set_owner",this_object());
  } else if (arg_type=="object") {
    o=clone_object("/obj/object");
    call_other(o,"set_owner",this_object());
    call_other(o,"set_name",name);
    move_object(o,this_object());
  } else if (arg_type=="coins") {
    o=clone_object("/obj/coins");
    call_other(o,"set_owner",this_object());
    call_other(o,"set_value",atoi(name));
    move_object(o,this_object());
  } else if (arg_type=="exit") {
    pos=instr(name,1," ");
    if (pos) {
      dest=rightstr(name,strlen(name)-pos);
      name=leftstr(name,pos-1);
      dest=resolve_object(dest);
      if (!dest) {
        write("@create: couldn't find destination\n");
        return 1;
      }
    }
    o=clone_object("/obj/exit");
    call_other(o,"set_owner",this_object());
    call_other(o,"set_name",name);
    move_object(o,location(this_object()));
    if (dest) call_other(o,"set_dest",dest);
  } else if (arg_type=="weapon") {
    o=clone_object("/obj/weapon");
    call_other(o,"set_owner",this_object());
    call_other(o,"set_name",name);
    move_object(o,this_object());
  } else if (arg_type=="monster") {
    o=clone_object("/obj/monster");
    call_other(o,"set_owner",this_object());
    call_other(o,"set_name",name);
    move_object(o,location(this_object()));
  } else {
    write("@create: unknown object type\n");
    return 1;
  }
  write("@create: created "+make_num(o)+"\n");
  return 1;
}

static do_set(arg) {
  string o,field,value,m1,m2,m3,m4,m5,part1,part2;
  int pos,is_anti,success,f,a,b,c;

  pos=instr(arg,1," ");
  o=leftstr(arg,pos-1);
  field=rightstr(arg,strlen(arg)-pos);
  pos=instr(field,1," ");
  if (pos) {
    value=rightstr(field,strlen(field)-pos);
    field=leftstr(field,pos-1);
  }
  if (leftstr(field,1)=="!") {
    is_anti=1;
    field=rightstr(field,strlen(field)-1);
  }
  if (!field || !o) {
    write("usage: @set object [!]field [value]\n");
    return 1;
  }
  o=resolve_object(o);
  if (!o) {
    write("@set: couldn't find object\n");
    return 1;
  }
  if (!priv(this_object()) && !programmer && call_other(o,"get_owner")!=
      this_object()) {
    write("@set: you don't own that object\n");
    return 1;
  }
  if (field=="protection") f=make_prot_num(value);
  if (field=="owner" || field=="dropto" || field=="dest" ||
      field=="destination" || field=="storeroom" || field=="shopkeeper") {
    if (value) {
      value=resolve_object(value);
      if (!value) {
        write("@set: couldn't find object in value field\n");
        return 1;
      }
    }
  }
  if (field=="programmer" && !value) value=!is_anti;
  if (field=="special" || field=="hitbonus" || field=="level" ||
      field=="xp" || field=="hp" || field=="value" || field=="hitreduce" ||
      field=="damreduce") {
    if (value) {
      f=atoi(value);
      if (!f && value!="0") {
        write("@set: expected integer in value field\n");
        return 1;
      }
    }
  }
  if (field=="damage") {
    if (value) {
      pos=instr(value,1,"d");
      if (pos) {
        a=atoi(leftstr(value,pos-1));
        b=rightstr(value,strlen(value)-pos);
        pos=instr(b,1,"+");
        if (pos) {
          c=atoi(rightstr(b,strlen(b)-pos));
          b=atoi(leftstr(b,pos-1));
        } else
          b=atoi(b);
      } else
        a=atoi(value);
    }
  }
  if (field=="puny" || field=="weak" || field=="poor" || field=="average" ||
      field=="good" || field=="verygood" || field=="massacre") {
    pos=instr(value,1,";");
    part1=leftstr(value,pos-1);
    value=rightstr(value,strlen(value)-pos);
    pos=instr(value,1,";");
    m3=leftstr(value,pos-1);
    part2=rightstr(value,strlen(value)-pos);
    pos=instr(part1,1,"*");
    m1=leftstr(part1,pos-1);
    m2=rightstr(part1,strlen(part1)-pos);
    if (!pos) { m1=part1; m2=0; }
    pos=instr(part2,1,"*");
    m4=leftstr(part2,pos-1);
    m5=rightstr(part2,strlen(part2)-pos);
    if (!pos) { m4=part1; m5=0; }
  }
  if (field=="name") success=(call_other(o,"set_name",value));
  else if (field=="short") success=call_other(o,"set_short",value);
  else if (field=="long") success=call_other(o,"set_long",value);
  else if (field=="owner") success=call_other(o,"set_owner",value);
  else if (field=="programmer") success=call_other(o,"set_programmer",value);
  else if (field=="special") success=call_other(o,"set_special",f);
  else if (field=="hitreduce") success=call_other(o,"set_hitreduce",f);
  else if (field=="damreduce") success=call_other(o,"set_damreduce",f);
  else if (field=="protection") success=call_other(o,"set_protection",f);
  else if (field=="value") success=call_other(o,"set_value",f);
  else if (field=="dropto") success=call_other(o,"set_dropto",value);
  else if (field=="shopkeeper") success=call_other(o,"set_shopkeeper",value);
  else if (field=="storeroom") success=call_other(o,"set_storeroom",value);
  else if (field=="dest") success=call_other(o,"set_dest",value);
  else if (field=="destination") success=call_other(o,"set_dest",value);
  else if (field=="hitbonus") success=call_other(o,"set_hit_bonus",f);
  else if (field=="damage") success=call_other(o,"set_damage_bonus",a,b,c);
  else if (field=="hp") success=call_other(o,"set_hp",f);
  else if (field=="xp") success=call_other(o,"set_xp",f);
  else if (field=="level") success=call_other(o,"set_level",f);
  else if (field=="puny") success=call_other(o,"set_hit_msg",0,m1,m2,m3,m4,m5);
  else if (field=="weak") success=call_other(o,"set_hit_msg",1,m1,m2,m3,m4,m5);
  else if (field=="poor") success=call_other(o,"set_hit_msg",2,m1,m2,m3,m4,m5);
  else if (field=="average") success=call_other(o,"set_hit_msg",3,m1,m2,m3,m4,
                                                m5);
  else if (field=="good") success=call_other(o,"set_hit_msg",4,m1,m2,m3,m4,m5);
  else if (field=="verygood") success=call_other(o,"set_hit_msg",5,m1,m2,m3,m4,
                                                 m5);
  else if (field=="massacre") success=call_other(o,"set_hit_msg",6,m1,m2,m3,m4,
                                                 m5);
  else {
    if (field=="permanent") f=F_PERMANENT;
    else if (field=="forsale") f=F_FORSALE;
    else if (field=="hostile") f=F_HOSTILE;
    else if (field=="temple") f=F_TEMPLE;
    else if (field=="dark") f=F_DARK;
    if (f) {
      if (value) {
        write("@set: flags do not take value fields\n");
        return 1;
      }
      if (is_anti)
        success=call_other(o,"set_flags",call_other(o,"get_flags") & ~f);
      else
        success=call_other(o,"set_flags",call_other(o,"get_flags") | f);
    } else {
      write("@set: field not recognized\n");
      return 1;
    }
  }
  if (success)
    write("Set.\n");
  else
    write("@set: failed\n");
  return 1;
}

get_type() {
  if (priv(this_object())) return TYPE_WIZARD;
  else if (programmer) return TYPE_PROGRAMMER;
  return TYPE_BUILDER;
}

set_programmer(s) {
  if (!priv(caller_object())) return 0;
  programmer=s;
  return 1;
}

static do_get(arg) {
  arg=present(arg,location(this_object()));
  if (!arg) {
    write("You don't see that here.\n");
    return 1;
  }
  if (!call_other(arg,"get")) {
    write("You can't get "+call_other(arg,"get_short")+".\n");
    return 1;
  }
  move_object(arg,this_object());
  write("You get "+call_other(arg,"get_short")+".\n");
  tell_room_except(location(this_object()),this_object(),
                   name+" gets "+call_other(arg,"get_short")+".\n");
  return 1;
}

static do_drop(arg) {
  arg=present(arg,this_object());
  if (!arg) {
    write("You don't have that.\n");
    return 1;
  }
  if (call_other(arg,"drop")) {
    write("You can't drop "+call_other(arg,"get_short")+".\n");
    return 1;
  }
  write("You drop "+call_other(arg,"get_short")+".\n");
  tell_room_except(location(this_object()),this_object(),
                   name+" drops "+call_other(arg,"get_short")+".\n");
  move_object(arg,location(this_object()));
  return 1;
}

static do_inventory(arg) {
  int count;
  object curr;
  string oname;

  count=0;
  curr=contents(this_object());
  while (curr) {
    oname=call_other(curr,"get_short");
    if (oname) {
      if (!count)
        write("You are carrying:\n");
      count++;
      write(oname+"\n");
    }
    curr=next_object(curr);
  }
  if (!count)
    write("You are empty-handed.\n");
  return 1;
}

static look(arg) {
  int contents_printed,curr;
  string oname,t;

  contents_printed=0;
  t=arg;
  if (arg) {
    arg=present(arg,location(this_object()));
    if (!arg) arg=present(t,this_object());
    if (!arg && t=="me") arg=this_object();
    if (!arg && t=="here") arg=location(this_object());
  } else
    if (!location(this_object())) {
      write("You are in the void.\n");
      return 1;
    } else
      arg=location(this_object());
  if (!arg) {
    write("You don't see that here.\n");
    return 1;
  }
  if (arg==location(this_object())) {
    oname=call_other(arg,"get_short");
    if (oname) write(oname+"\n");
  }
  oname=(call_other(arg,"get_long"));
  if (oname) write(oname+"\n");
  curr=contents(arg);
  if (!(call_other(arg,"get_flags") & F_DARK))
    while (curr) {
      if (curr!=this_object()) {
        oname=call_other(curr,"get_short");
        if (oname) {
          if (!contents_printed) {
            write("Contents:\n");
            contents_printed=1;
          }
          write(oname+"\n");
        }
      }
      curr=next_object(curr);
    }
  return 1;
}

get_invis() { return is_invis; }

id(arg) { return arg==name || arg==low_name; }

move_player(dest,direction) {
  if (location(this_object()) && !is_invis)
    tell_room_except(location(this_object()),this_object(),
                     name+" goes "+direction+".\n");
  move_object(this_object(),dest);
  if (dest && !is_invis)
    tell_room_except(dest,this_object(),name+" has arrived.\n");
  look(0);
  return 1;
}

static do_invis(arg) {
  if (arg=="on") {
    is_invis=1;
    write("@invis: invis on\n");
  } else if (arg=="off") {
    is_invis=0;
    write("@invis: invis off\n");
  } else write("usage: @invis on|off\n");
  return 1;
}

listen(arg) {
  string owner,perms,filename,arg2;
  int pos;

  if (!doing_ls) {
    send_device(arg);
    return;
  }
  pos=instr(arg,1," ");
  owner=atoi(leftstr(arg,pos-1));
  arg2=rightstr(arg,strlen(arg)-pos);
  pos=instr(arg2,1," ");
  perms=atoi(leftstr(arg2,pos-1));
  filename=rightstr(arg2,strlen(arg2)-pos);
  arg2=itoo(owner);
  if (!arg2) owner="NULL_OWNER #"+itoa(owner);
  else {
    arg2=call_other(arg2,"get_uid");
    if (arg2) owner=arg2;
    else owner=itoa(owner);
  }
  pos=strlen(owner);
  while (pos++<16) owner+=" ";
  if (perms & DIRECTORY) arg2="d";
  else arg2="-";
  if (perms & READ_OK) arg2+="r";
  else arg2+="-";
  if (perms & WRITE_OK) arg2+="w";
  else arg2+="-";
  send_device(arg2+" "+owner+" "+filename);
}

get_short() {
  object viewer;

  viewer=caller_object();
  if (leftstr(otoa(viewer),9)!="/obj/wiz#" && is_invis &&
      !priv(caller_object())) return NULL;
  if (priv(this_object()))
    if (is_invis)
      return "The wizard "+name+" (invis)";
    else
      return "The wizard "+name;
  else
    if (programmer)
      if (is_invis)
        return "The programmer "+name+" (invis)";
      else
        return "The programmer "+name;
    else
      if (is_invis)
        return "The builder "+name+" (invis)";
      else
        return "The builder "+name;
}

static do_exits(arg) {
  object curr;
  int count,pos;
  string ename;

  if (location(this_object())) curr=contents(location(this_object()));
  while (curr) {
    if (call_other(curr,"get_type")==TYPE_EXIT)
      if (!(call_other(curr,"get_flags") & F_DARK)) {
        if (!count) write("Obvious exits:");
        ename=call_other(curr,"get_name");
        pos=instr(ename,1,";");
        if (pos)
          write(" "+leftstr(ename,pos-1));
        else
          write(" "+ename);
        count++;
      }
    curr=next_object(curr);
  }
  if (!count)
    write("There are no obvious exits here.\n");
  else
    write("\n");
  return 1;
}

static resolve_object(name) {
  object result;

  if (leftstr(name,1)=="/" || leftstr(name,1)=="#")
    if (result=atoo(name))
      return result;
  if (leftstr(name,1)=="*")
    if (result=find_player(rightstr(name,strlen(name)-1)))
      return result;
  if (leftstr(name,1)=="$")
    if (result=find_wiz(rightstr(name,strlen(name)-1)))
      return result;
  if (result=present(name,this_player()))
    return result;
  if (result=present(name,location(this_player())))
    return result;
  if (name=="me") return this_player();
  if (name=="here") return location(this_player());
  if (name=="root") return atoo("/boot");
  return NULL;
}

get_uid() {
  return low_name;
}

get_name() {
  return name;
}

set_name(arg) {
  if (prototype(this_object())) return;
  if (name) return;
  name=arg;
  low_name=downcase(arg);
  return 1;
}

set_password(arg) {
  if (!arg) return;
  if (prototype(this_object())) return;
  if (priv(caller_object()) && !priv(this_object())) password=arg;
  if (password) return;
  password=arg;
  return 1;
}

check_password(arg) {
  if (!priv(caller_object())) return 0;
  return arg==password;
}

static disconnect() {
  if (!is_invis)
    tell_room_except(location(this_object()),this_object(),
                     name+" has disconnected.\n");
}

connect() {
  string s;

  if (!caller_object()) return;
  s=otoa(caller_object());
  if (leftstr(s,11)!="/sys/login#") return;
  alarm(0,"welcome");
}

static do_replicate(arg) {
  if (!arg) {
    write("usage: @replicate object\n");
    return 1;
  }
  arg=resolve_object(arg);
  if (!arg) {
    write("@replicate: couldn't find object\n");
    return 1;
  }
  arg=call_other(arg,"replicate");
  if (arg) {
    call_other(arg,"set_owner",this_object());
    write("@replicate: created "+make_num(arg)+"\n");
  } else
    write("@replicate: couldn't replicate "+call_other(arg,"get_short")+"\n");
  return 1;
}

static do_destroy(arg) {
  if (!arg) {
    write("usage: @destroy object\n");
    return 1;
  }
  arg=resolve_object(arg);
  if (!arg) {
    write("@destroy: couldn't find object\n");
    return 1;
  }
  if (call_other(arg,"self_destruct"))
    write("@destroy: object destroyed\n");
  else
    write("@destroy: failed\n");
  return 1;
}

static do_boot(arg) {
  if (!priv(this_object())) return 0;
  if (!arg) {
    write("usage: @boot player\n");
    return 1;
  }
  arg=resolve_object(arg);
  if (!arg) {
    write("@boot: couldn't find object\n");
    return 1;
  }
  if (call_other(arg,"force_disconnect"))
    write("@boot: player disconnected\n");
  else
    write("@boot: failed\n");
  return 1;
}

static do_force(arg) {
  object o;
  string cmd;
  int pos;

  pos=instr(arg,1," ");
  o=leftstr(arg,pos-1);
  cmd=rightstr(arg,strlen(arg)-pos);
  if (!o) {
    write("usage: @force object [command]\n");
    return 1;
  }
  o=resolve_object(o);
  if (!o) {
    write("@force: couldn't find object\n");
    return 1;
  }
  if (!programmer && !priv(this_object()) && call_other(o,"get_owner")!=
      this_object()) {
    write("@force: you don't own that object\n");
    return 1;
  }
  if (call_other(o,"force",cmd))
    write("Ok.\n");
  else
    write("@force: failed\n");
  return 1;
}

static welcome() {
  look(0);
  if (possessing) write("NOTE: You are currently possessing "
                        +make_num(possessing)+"\n");
  if (is_invis)
    write("NOTE: You are currently invisible.\n");
  else
    tell_room_except(location(this_object()),this_object(),
                     name+" has connected.\n");
}

#define resolve(X) ((X)=resolve_path(X))

static resolve_path(upath) {
  if (!upath) return path;
  if (leftstr(upath,1)=="/") return upath;
  if (path=="/") return path+upath;
  return path+"/"+upath;
}

static do_huh(arg) {
  write(HUH_STRING);
}

static do_pwd(arg) {
  if (!programmer) return 0;
  write("pwd: current path="+path+"\n");
  return 1;
}

static do_cd(arg) {
  if (!programmer) return 0;
  if (!arg)
    write("cd: current path="+path+"\n");
  else {
    resolve(arg);
    path=arg;
  }
  write("Ok.\n");
  return 1;
}

static do_quit(arg) {
  write("Bye!\n");
  disconnect_device();
  disconnect();
  return 1;
}

static do_who(arg) {
  wiz_who_list();
  return 1;
}

static do_compile(arg) {
  object result;

  if (!programmer) return 0;
  resolve(arg);
  if (arg=="/obj/wiz") {
    call_other(atoo("/sys/wizcompile"),"wizcompile");
    return 1;
  }
  result=compile_object(arg);
  if (result)
    write("@load: "+otoa(result)+" compiled\n");
  else
    write("@load: failed\n");
  return 1;
}

static do_edit(arg) {
  if (!programmer) return 0;
  if (arg) resolve(arg);
  edit(arg);
  return 1;
}

static do_cat(arg) {
  if (!programmer) return 0;
  resolve(arg);
  if (cat(arg))
    write("cat: couldn't open "+arg+"\n");
  return 1;
}

static do_ls(arg) {
  if (!programmer) return 0;
  resolve(arg);
  write("ls: listing "+arg+"\n");
  doing_ls=1;
  if (ls(arg)) {
    doing_ls=0;
    write("ls: couldn't open "+arg+"\n");
    return 1;
  }
  doing_ls=0;
  write("ls: done\n");
  return 1;
}

static do_rm(arg) {
  if (!programmer) return 0;
  if (!arg) {
    write("usage: rm filename\n");
    return 1;
  }
  resolve(arg);
  if (rm(arg))
    write("rm: couldn't remove "+arg+"\n");
  else
    write ("Ok.\n");
  return 1;
}

static do_cp(arg) {
  string src,dest;
  int pos;

  if (!programmer) return 0;
  pos=instr(arg,1," ");
  src=leftstr(arg,pos-1);
  dest=rightstr(arg,strlen(arg)-pos);
  if ((!src) || (!dest)) {
    write("usage: cp source destination\n");
    return 1;
  }
  resolve(src);
  resolve(dest);
  if (cp(src,dest))
    write("cp: couldn't copy "+src+" to "+dest+"\n");
  else
    write("Ok.\n");
  return 1;
}

static do_mv(arg) {
  string src,dest;
  int pos;

  if (!programmer) return 0;
  pos=insr(arg,1," ");
  src=leftstr(arg,pos-1);
  dest=rightstr(arg,strlen(arg)-pos);
  if ((!src) || (!dest)) {
    write("usage: mv source destination\n");
    return 1;
  }
  resolve(src);
  resolve(dest);
  if (mv(src,dest))
    write("mv: couldn't move "+src+" to "+dest+"\n");
  else
    write("Ok.\n");
  return 1;
}

static do_mkdir(arg) {
  if (!programmer) return 0;
  if (!arg) {
    write("usage: mkdir directory_name\n");
    return 1;
  }
  resolve(arg);
  if (mkdir(arg))
    write("mkdir: couldn't make directory "+arg+"\n");
  else
    write("Ok.\n");
  return 1;
}

static do_rmdir(arg) {
  if (!programmer) return 0;
  if (!arg) {
    write("usage: rmdir directory_name\n");
    return 1;
  }
  resolve(arg);
  if (rmdir(arg))
    write("rmdir: couldn't remove directory "+arg+"\n");
  else
    write("Ok.\n");
  return 1;
}

static do_hide(arg) {
  if (!programmer) return 0;
  if (!priv(this_object())) return 0;
  if (!arg) {
    write("usage: hide filename\n");
    return 1;
  }
  resolve(arg);
  if (hide(arg))
    write("hide: couldn't hide "+arg+"\n");
  else
    write("Ok.\n");
  return 1;
}

static do_unhide(arg) {
  if (!programmer) return 0;
  if (!priv(this_object())) return 0;
  if (!arg) {
    write("usage: unhide filename\n");
    return 1;
  }
  resolve(arg);
  if (unhide(arg,this_object(),0))
    write("unhide: couldn't unhide "+arg+"\n");
  else
    write("Ok.\n");
  return 1;
}

static do_chown(arg) {
  string file,owner;
  int pos;
  object o;

  if (!programmer) return 0;
  pos=instr(arg,1," ");
  file=leftstr(arg,pos-1);
  owner=rightstr(arg,strlen(arg)-pos);
  if ((!file) || (!owner)) {
    write("usage: chown filename owner\n");
    return 1;
  }
  resolve(file);
  if (!(o=atoo(owner)))
    if (!(o=find_wiz(owner)))
      if (!(o=find_player(owner)))
        if (!(o=(owner=="root" ? atoo("/boot") : 0))) {
          write("couldn't find owner \""+owner+"\"\n");
          return 1;
        }
  if (chown(file,o))
    write("chown: couldn't chown "+file+" to "+owner+"\n");
  else
    write("Ok.\n");
  return 1;
}

static do_save(arg) {
  if (!priv(this_object())) return 0;
  if (sysctl(SYSCTL_SAVE))
    write("@save: failed\n");
  else
    write("@save: completed\n");
  return 1;
}

static do_shutdown(arg) {
  if (!priv(this_object())) return 0;
  if (sysctl(SYSCTL_SHUTDOWN))
    write("@shutdown: failed\n");
  return 1;
}

static do_panic(arg) {
  if (!priv(this_object())) return 0;
  if (sysctl(SYSCTL_PANIC))
    write("@panic: failed\n");
  return 1;
}

static do_priv(arg) {
  object o;

  if (!priv(this_object())) return 0;
  if (!(o=resolve_object(arg))) {
    write("@priv: couldn't find object \""+arg+"\"\n");
    return 1;
  }
  set_priv(o);
  write("Ok.\n");
  return 1;
}

static do_chmod(arg) {
  int pos;
  string modestr,file;
  int mode;

  if (!programmer) return 0;
  pos=instr(arg,1," ");
  modestr=leftstr(arg,pos-1);
  file=rightstr(arg,strlen(arg)-pos);
  if ((!modestr) || (!file)) {
    write("usage: chmod mode file\n");
    return 1;
  }
  mode=atoi(modestr);
  if (!mode && modestr!="0")
    if (modestr=="r")
      mode=READ_OK;
    else if (modestr=="w")
      mode=WRITE_OK;
    else if (modestr=="rw" || modestr=="wr")
      mode=WRITE_OK | READ_OK;
    else {
      write("chmod: illegal mode \""+modestr+"\"\n");
      return 1;
    }
  resolve(file);
  if (chmod(file,mode))
    write("chmod: couldn't change "+file+" to mode "+modestr+"\n");
  write("Ok\n");
  return 1;
}

static do_call(arg) {
  int has_arg,pos;
  string o,func,tmp;
  var pass,x;
  object obj;

  if (!programmer) return 0;
  pos=instr(arg,1," ");
  o=leftstr(arg,pos-1);
  func=rightstr(arg,strlen(arg)-pos);
  pos=instr(func,1,"=");
  if (pos) {
    tmp=func;
    has_arg=1;
    func=leftstr(tmp,pos-1);
    x=rightstr(tmp,strlen(tmp)-pos);
  }
  if (!o || !func) {
    write("usage: @call object func\n");
    write("       @call object func=value\n");
    return 1;
  }
  if (!(obj=resolve_object(o))) {
    write("@call: couldn't find object \""+o+"\"\n");
    return 1;
  }
  if (has_arg) {
    if (strlen(x)>1 && leftstr(x,1)=="\"" && rightstr(x,1)=="\"")
      pass=midstr(x,2,strlen(x)-2);
    else
      if (!(pass=resolve_object(x)))
        if (!(pass=atoi(x)))
          if (x!="0") {
            write("@call: bad parameter \""+x+"\"\n");
            return 1;
          }
  }
  if (has_arg)
    x=call_other(obj,func,pass);
  else
    x=call_other(obj,func);
  write("@call: "+otoa(obj)+" "+func);
  if (has_arg) {
    write("(");
    if (typeof(pass)==STRING)
      write("\""+pass+"\"");
    else if (typeof(pass)==OBJECT)
      write(otoa(pass));
    else write(itoa(pass));
    write(")");
  } else
    write("()");
  write(" returned ");
  if (typeof(x)==STRING)
    write("\""+x+"\"\n");
  else if (typeof(x)==OBJECT)
    write(otoa(x)+"\n");
  else
    write(itoa(x)+"\n");
  return 1;
}

static do_clone(arg) {
  object o;

  if (!programmer) return 0;
  resolve(arg);
  o=clone_object(arg);
  if (o)
    write("@clone: cloned "+otoa(o)+"\n");
  else
    write("@clone: failed to clone \""+arg+"\"\n");
  return 1;
}

static do_exam(arg) {
  object o;
  object curr;
  string name;

  if (!arg) {
    o=location(this_player());
    if (!o) {
      write("You are in the void.\n");
      return 1;
    }
  } else
    o=resolve_object(arg);
  if (!o) {
    write("@exam: couldn't find object \""+arg+"\"\n");
    return 1;
  }
  write(make_num(o)+"\n");
  curr=call_other(o,"get_long");
  if (curr) write(curr+"\n");
  if (location(o))
    write("Location: "+make_num(location(o))+"\n");
  else
    write("Location: void\n");
  curr=contents(o);
  if (curr)
    write("Contents:\n");
    while (curr) {
      name=make_num(curr);
      if (name)
        write(name+"\n");
      curr=next_object(curr);
    }
  return 1;
}

static do_move(arg) {
  object src,dest;
  int pos;
  string ssrc,sdest;

  pos=instr(arg,1," ");
  ssrc=leftstr(arg,pos-1);
  sdest=rightstr(arg,strlen(arg)-pos);
  if (!sdest && ssrc) {
    sdest=ssrc;
    ssrc=NULL;
    src=this_player();
    dest=resolve_object(sdest);
  } else {
    src=resolve_object(ssrc);
    dest=resolve_object(sdest);
  }
  if (!dest && sdest=="void") dest="void";
  if ((!src) || (!dest)) {
    write("usage: @move [item] dest\n");
    return 1;
  }
  if (dest=="void") dest=NULL;
  if (!call_other(src,"move_player",dest,"in a puff of smoke"))
    if (move_object(src,dest)) {
      write("@move: failed\n");
      return 1;
    }
  write("Ok.\n");
  return 1;
}

static do_say(arg) {
  tell_room_except(location(this_player()),this_object(),
                   name+" says \""+arg+"\"\n");
  write("You say \""+arg+"\"\n");
  return 1;
}

static do_pose(arg) {
  tell_room_except(location(this_player()),this_object(),name+" "+arg+"\n");
  write(name+" "+arg+"\n");
  return 1;
}

static do_loadhelp(arg) {
  string o,topic,text,file;
  object curr;
  int pos;

  if (!priv(this_object()) && !prototype(this_object())) return 0;
  if (!arg) {
    write("usage: @loadhelp player|builder|programmer|wizard|manual\n");
    return 1;
  }
  if (arg=="player") { o="/sys/help1"; file="/help/player"; }
  else if (arg=="builder") { o="/sys/help2"; file="/help/builder"; }
  else if (arg=="programmer") { o="/sys/help3"; file="/help/programmer"; }
  else if (arg=="wizard") { o="/sys/help4"; file="/help/wizard"; }
  else if (arg=="manual") { o="/sys/help5"; file="/help/manual"; }
  else {
    write("@loadhelp: help file not recognized\n");
    return 1;
  }
  curr=next_child(atoo(o));
  while (curr) {
    call_other(curr,"self_destruct");
    curr=next_child(curr);
  }
  pos=0;
  text=0;
  topic=0;
  curr=atoo(o);
  while (topic=fread(file,pos)) {
    if (leftstr(topic,1)=="*") {
      call_other(curr,"set_text",text);
      curr=clone_object(o);
      call_other(curr,"set_topic",midstr(topic,2,strlen(topic)-2));
      text=0;
    } else
      text+=topic;
  }
  call_other(curr,"set_text",text);
  write("@loadhelp: new help text loaded\n");
  return 1;
}

static do_man(arg) {
  object curr,found;
  string s;

  if (!programmer) return 0;
  if (arg) {
    curr=next_child(atoo("/sys/help5"));
    while (!found && curr) {
      if (call_other(curr,"get_topic")==arg)
        found=curr;
      curr=next_child(curr);
    }
    if (!found) {
      write("man: couldn't find topic "+arg+"\n");
      return 1;
    }
    s=(call_other(found,"get_text"));
    if (s) write("\n"+s+"\n");
    else write("man: no help entered for that topic\n");
    return 1;
  }
  write("\n");
  write("System Calls:\n");
  write("-------------\n");
  curr=next_child(atoo("/sys/help5"));
  while (curr) {
    write(call_other(curr,"get_topic")+" ");
    curr=next_child(curr);
  }
  write("\n\n");
  return 1;
}

static do_help(arg) {
  object curr,loop,found;
  string s;

  if (arg) {
    loop=2;
    while (!found && loop<=4) {
      if (!((loop==3 && !programmer) || (loop==4 && !priv(this_object())))) {
        curr=next_child(atoo("/sys/help"+itoa(loop)));
        while (curr && !found) {
          if (call_other(curr,"get_topic")==arg) found=curr;
          curr=next_child(curr);
        }
      }
      loop++;
    }
    if (!found) {
      write("help: no help for topic "+arg+" available\n");
      return 1;
    }
    s=(call_other(found,"get_text"));
    if (s) write("\n"+s+"\n");
    else write("help: no help entered for that topic\n");
    return 1;
  }
  write("\n");
  write("Builder Commands:\n");
  write("-----------------\n");
  curr=next_child(atoo("/sys/help2"));
  while (curr) {
    write(call_other(curr,"get_topic")+" ");
    curr=next_child(curr);
  }
  write("\n\n");
  if (programmer) {
    write("Programmer Commands:\n");
    write("--------------------\n");
    curr=next_child(atoo("/sys/help3"));
    while (curr) {
      write(call_other(curr,"get_topic")+" ");
      curr=next_child(curr);
    }
    write("\n\n");
  }
  if (priv(this_object())) {
    write("Wizard Commands:\n");
    write("----------------\n");
    curr=next_child(atoo("/sys/help4"));
    while (curr) {
      write(call_other(curr,"get_topic")+" ");
      curr=next_child(curr);
    }
    write("\n\n");
  }
  return 1;
}

static do_password(arg) {
  int pos;
  string old,new;

  pos=instr(arg,1," ");
  old=leftstr(arg,pos-1);
  new=rightstr(arg,strlen(arg)-pos);
  if ((!old) || (!new)) {
    write("usage: @password old new\n");
    return 1;
  }
  if (old==password) {
    password=new;
    write("@password: password changed\n");
  } else
    write("@password: failed\n");
  return 1;
}

static do_recon(arg) {
  object o;

  if (!priv(this_object())) return 0;
  o=resolve_object(arg);
  if (!o) {
    write("@recon: couldn't find object \""+arg+"\"\n");
    return 1;
  }
  if (reconnect_device(o))
    write("@recon: couldn't reconnect to object "+otoa(o)+"\n");
  return 1;
}

static do_date(arg) {
  write(mktime(time()));
  return 1;
}

static do_wizlist(arg) {
  object curr,type;

  write("List of Wizards\n");
  write("---------------\n");
  curr=atoo("/obj/wiz");
  curr=next_child(curr);
  if (!curr) write ("There are no wizards.\n");
  while (curr) {
    type=call_other(curr,"get_type");
    if (type==TYPE_WIZARD)
      write(call_other(curr,"get_name")+", a wizard\n");
    else if (type==TYPE_PROGRAMMER)
      write(call_other(curr,"get_name")+", a programmer\n");
    else
      write(call_other(curr,"get_name")+"\n");
    curr=next_child(curr);
  }
  return 1;
}

static do_wizcreate(arg) {
  string name, password;
  int pos;
  object wizobj;

  if (!priv(this_object())) return 0;
  pos=instr(arg,1," ");
  name=leftstr(arg,pos-1);
  password=rightstr(arg,strlen(arg)-pos);
  if (!name || !password) {
      write("usage: @wizcreate name password\n");
      return 1;
    }
  if (find_wiz(name)) {
    write("@wizcreate: wizard \""+name+"\" already exists\n");
    return 1;
  }
  if (find_player(name)) {
    write("@wizcreate: player \""+name+"\" already exists\n");
    return 1;
  }
  wizobj=clone_object("/obj/wiz");
  call_other(wizobj,"set_secure");
  call_other(wizobj,"set_name",name);
  call_other(wizobj,"set_password",password);
  write("@wizcreate: created "+otoa(wizobj)+"\n");
  return 1;
}

static do_pcreate(arg) {
  string name, password;
  int pos;
  object pobj;

  if (!priv(this_object())) return 0;
  pos=instr(arg,1," ");
  name=leftstr(arg,pos-1);
  password=rightstr(arg,strlen(arg)-pos);
  if (!name || !password) {
    write("usage: @pcreate name password\n");
    return 1;
  }
  if (find_wiz(name)) {
    write("@pcreate: wizard \""+name+"\" already exists\n");
    return 1;
  }
  if (find_player(name)) {
    write("@pcreate: player \""+name+"\" already exists\n");
    return 1;
  }
  pobj=clone_object("/obj/player");
  call_other(pobj,"set_secure");
  call_other(pobj,"set_name",name);
  call_other(pobj,"set_password",password);
  move_object(pobj,atoo("/obj/room"));
  write("@pcreate: created "+otoa(pobj)+"\n");
  return 1;
}

static do_fry(arg) {
  object o;

  if (!priv(this_object())) return 0;
  if (!arg) {
    write("usage: @fry <object>\n");
    return 1;
  }
  o=resolve_object(arg);
  if (!o) {
    write("@fry: couldn't find "+arg+"\n");
    return 1;
  }
  destruct(o);
  write("Ok.\n");
  return 1;
}

static init() {
  check_secure(SECURE_PRIV,NULL);
  set_interactive();
  path="/";
  if (!prototype(this_object())) {
    move_object(this_object(),atoo("/obj/room"));
    return;
  }
  add_xverb("","do_huh");
  add_verb("look","look");
  add_verb("l","look");
  add_verb("get","do_get");
  add_verb("drop","do_drop");
  add_verb("take","do_get");
  add_verb("inventory","do_inventory");
  add_verb("i","do_inventory");
  add_verb("@replicate","do_replicate");
  add_verb("@create","do_create");
  add_verb("@set","do_set");
  add_verb("@destroy","do_destroy");
  add_verb("@recon","do_recon");
  add_verb("@invis","do_invis");
  add_verb("date","do_date");
  add_verb("time","do_date");
  add_verb("quit","do_quit");
  add_verb("who","do_who");
  add_verb("QUIT","do_quit");
  add_verb("WHO","do_who");
  add_verb("@load","do_compile");
  add_verb("@edit","do_edit");
  add_verb("cat","do_cat");
  add_verb("ls","do_ls");
  add_verb("rm","do_rm");
  add_verb("cp","do_cp");
  add_verb("cd","do_cd");
  add_verb("mv","do_mv");
  add_verb("pwd","do_pwd");
  add_verb("mkdir","do_mkdir");
  add_verb("rmdir","do_rmdir");
  add_verb("hide","do_hide");
  add_verb("unhide","do_unhide");
  add_verb("chown","do_chown");
  add_verb("@save","do_save");
  add_verb("@shutdown","do_shutdown");
  add_verb("@panic","do_panic");
  add_verb("@priv","do_priv");
  add_verb("@call","do_call");
  add_verb("@clone","do_clone");
  add_verb("@exam","do_exam");
  add_verb("@move","do_move");
  add_verb("say","do_say");
  add_xverb("\"","do_say");
  add_xverb(":","do_pose");
  add_verb("pose","do_pose");
  add_verb("help","do_help");
  add_verb("chmod","do_chmod");
  add_verb("?","do_help");
  add_verb("wizlist","do_wizlist");
  add_verb("@password","do_password");
  add_verb("@fry","do_fry");
  add_verb("@wizcreate","do_wizcreate");
  add_verb("@pcreate","do_pcreate");
  add_verb("@boot","do_boot");
  add_verb("@force","do_force");
  add_verb("@possess","do_possess");
  add_verb("@stat","do_stat");
  add_xverb("$","command_possessed");
  add_verb("exits","do_exits");
  add_verb("@loadhelp","do_loadhelp");
  add_verb("man","do_man");
  command("@loadhelp player");
  command("@loadhelp builder");
  command("@loadhelp programmer");
  command("@loadhelp wizard");
  command("@loadhelp manual");
}