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 - Login 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 <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <dirent.h>

#include "musicmud.h"
#include "State.h"
#include "pflags.h"
#include "misc.h"
#include "Verb.h"
#include "verbs.h"
#include "units.h"
#include "msi.h"
#include "mailboard.h"
#include "hooks.h"
#include "trap.h"
#include "nations.h"

#define MODULE "state"

#include "verbmodule.h"

#define ARRAY_SIZE(a) (sizeof(a)/(sizeof((a)[0])))

static bool valid_char(char what) {
    return isalpha(what); 
}

const char *illegal_names[] =
{ "i",  "you", "he",  "she", "they", "it",
  "me",        "him", "her", "them",
  "my", "your","his",        "their",
  "mine","yours",     "hers", "its", 
  "all", "a", "an", "the", "some", "any", "here",
  "this", "that", "those", "these",
  "self", "myself", "someone", "somebody",
  "something",};

static const char *legal_name(const char *who) {
    if (!who) return "is null";
    if (strlen(who)>12) return "too long";
    if (strlen(who)<2) return "too short";
    if (planet->get(who) || verbs->get(who))
	return "used internally";    
    for (size_t i=0;i<ARRAY_SIZE(illegal_names);i++) {
      if (strcasecmp(who, illegal_names[i])==0)
	return "used internally";
    }

    while (*who) {
	if (!valid_char(*who)) {
	    return "Name must comprise solely letters";
	}
	who++;
    }
    return 0;
}

static char rsalt() {
  int r = random_number(64);
  if (r < 26)
    return 'a' + r;
  if (r < 52)
    return 'A' + r - 26;
  if (r < 62)
    return '0' + r - 52;
  if (r == 62)
    return '.';

  return '/';
}

static void state_setname(Player *p, const char *name)
{
  if (!name)
    return;

  if (!*name) {
    p->printf("Ok then.\n");
    p->interpret("quit");
    return;
  }

  string lname = make_lower(name);

  if (lname == "new") {
    p->printf("To create a new character, just enter the name.\n");
    return;
  }

  if (lname == "guest") {
    p->printf("We don't have a guest account.  To create an account, just enter the name you want to use.\n");
    log(PFL_SEEINFO, 0, "net", "%s wanted to log in as guest", p->id);
    return;
  }

  if (lname == "who" || lname == "users") {
    p->interpret(lname.c_str());
    log(PFL_SEEINFO, 0, "net", "%s did '%s'", p->id, lname.c_str());
    return;
  }

  OfflinePlayer ply(0);
  ply.grab(0, lname.c_str());
  if (!!ply) {
    if (level_of(ply) < mud->get_int("levellock")) {
      p->printf("The mud is currently closed. Try again later.\n");
      p->interpret("quit");
      return;
    }
    
    p->set_state("password");
    PersonState *ps = p->get_person_state();
    ps->set("id", lname);
    ps->set("password", ply->get("password"));
    if (!ply->get_priv(PFL_INVIS)) {
      ps->set("maxinvis", 0);
      ps->set("invis", 0);
    }
    else {
      ps->set("maxinvis", privs_of(ply));
      ps->set("invis", invis(ply));
    }
      
    ps->set("attempts", 0);

    p->printf("\nWe already have a '%s'. If this isn't you, just hit return to be prompted for another name.\n\n", ply->get("name"));

    log(PFL_SEEINFO, 0, "net", "logging in as %s", ps->get("id"));

    return;
  }

  if (const char *reason=legal_name(lname.c_str())) {      
    p->printf("You can't use '%s' : %s.\n", name, reason);
    return;
  }

  Player *pl;
  int i;
  foreach(players, pl, i) if (pl != p) {
    PersonState *per = pl->get_person_state();
    if (!pl->get_flag(FL_LOGGEDIN)) {
      if (streq(per->get("id"), lname.c_str())) {
	p->printf("You can't use that name as someone is already creating a character with it.\n");
	return;
      }
    }
  }
  
  if (mud->get_int("levellock")!=-1) {
    p->printf("Creation of new players is temporarily disabled. Try again later.\n");
    p->interpret("quit");
    return;
  }
  
  p->set_state("confirm");
  PersonState *ps = p->get_person_state();
  ps->set("name", ssprintf("^p%#s^n", name));
  ps->set("id", lname);
  
  ps->set("prompt", ssprintf("Did I hear correctly, ^p%s^n? ", ps->get("name")));
  return;
}

static void state_confirm(Player *p, const char *name) {
  if (!name)
    return;

  if (no(name)) {
    p->set_state("name");
    return;
  }

  if (yes(name)) {
    PersonState *ps = p->get_person_state();

    log(PFL_SEEINFO, 0, "net", "creating a new char called %s", ps->get("id"));

    p->set_state("askpwd");
    return;
  }

  p->printf("Yes or no?\n");
}

static void state_askpass(Player *p, const char *w) {
  if (strlen(w)<2) {
    p->printf("Your password is too short.\n");
    return;
  }
  
  char salt[3] = { rsalt(), rsalt(), 0 };
  PersonState *ps = p->get_person_state();
  ps->set("password", crypt(w, salt));
  p->set_state("conpwd");
}

static void state_conpass(Player *p, const char *w)
{
  PersonState *ps = p->get_person_state();
  const char *np = crypt(w, ps->get("password"));
  if (streq(np, ps->get("password"))) {
    p->set_state("sex");
  } else {
    p->printf("Passwords didn't match. Try again.\n");
    p->set_state("askpwd");
  }
}

MudObject *find_nation(const char *str) {
  World<MudObject> nats = nations(true);
  
  MudObject *o;
  int i;

  foreach_alpha(&nats, o, i) {
    if (ssprintf("%i", i)==str)
      return o;

    if (o->get("nation") && strcasecmp(o->get("nation"), str)==0)
      return o;

    if (o->get("name") && strcasecmp(o->get("name"), str)==0)
      return o;

    if (o->get("country") && strcasecmp(o->get("country"), str)==0)
      return o;

    if (o->get("shortcountry") && strcasecmp(o->get("shortcountry"), str)==0)
      return o;
  }
  
  return 0;
}

static void state_nation(Player *p, const char *w)
{
  PersonState *ps = p->get_person_state();

  if (!w) {
    World<MudObject> nats = nations(true);

    if (nats.getsize()==0 || nats.getsize()==1) {
      if (nats.getsize())
	ps->set("nation", nats.get(0)->get("nation"));
      goto nextstate;
    }

    MudObject *o;
    int i;
    p->printf("Available nations : \n");
    foreach_alpha(&nats, o, i) {
      p->printf("  %i) - %s \n", i, o->get("name"));
    }  
    p->set_state("nation");
    return;
  }

  {
    MudObject *n = find_nation(w);
    if (!n) {
      p->printf("Can't find that nation.\n");
      return;
    }
    ps->set("nation", n->get("nation"));
  }
 nextstate:
  if (!p->spewfile(DATA_INFO, "newbiemotd.i", 0)) {
    p->spewfile(DATA_INFO, "motd.i", 0);
  }
  p->set_state("newbiemotd");
  return;
}

static void state_sex(Player *p, const char *w)
{
  if (!w)
    return;

  if (strlen(w)!=1)
    return;
  
  switch (tolower(*w)) {
  case 'm': 
  case 'f':
  case 'n':
  case 'a':
    {
      PersonState *ps = p->get_person_state();
      ps->set("gender", w);
      state_nation(p, 0);
    }
    
    
  default:
    return;
  }
}

static bool bad_place(MudObject *o)
{
  if (!o->owner)
    return 1;
  if (o->owner == mud)
    return 1;
  return 0;
}

static void clone_newbiekit(MudObject *p) {
  int kitsize = mud->array_size("$newbiekit");
  for (int i=0;i<kitsize;i++) {
    if (MudObject *w = mud->array_get_object("$newbiekit", i)) {
      w = clone_object(w, p);
      w->set(KEY_WORNBY, p->id);
    }
  }
}

static void housekeeping(Player *p)
{
  p->set("logincount", p->get_int("logincount", 0)+1);
  p->set("lastlogin", now);
  if (p->p)
    p->set("hostname", p->p->get_ip());
  p->set_bflag(FL_LOGGEDIN, 1);
}

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

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

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

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

static void state_newbiemotd(Player *p, const char *w)
{
  bool frob = 0;

  DIR *d = opendir(DATA_USERS);

  if (d) {
    frob = 1;
    // If there are any FILES in the vardata/users directory, then
    // we don't frob this user to master user.
    while (dirent *de=readdir(d))
      {
	if (de->d_name[0]=='.')      continue;
	if (strchr(de->d_name, '#')) continue;
	if (strchr(de->d_name, '~')) continue;

	struct stat s;
	string f = DATA_USERS;
	f += "/";
	f += de->d_name;

	stat(f.c_str(), &s);

	if (S_ISDIR(s.st_mode)) {
	  continue;
	}

	frob = 0;
      }
    closedir(d);
  }
  
  PersonState *ps = p->get_person_state();

  p->set("short", ps->get("id"));
  p->set("id", ps->get("id"));
  p->set("name", ps->get("name"));
  p->set("password", ps->get("password"));
  p->set("level", 1);
  p->set("gender", ps->get("gender"));
  p->set("nation", ps->get("nation"));
  p->set("created", now);
  p->set("maxstrength", 200);
  p->set(KEY_STRENGTH, 200);
  set_mass_capacity(p, 20 * KILOGRAM);

  p->set("style", 2);
  p->set("colours", "classic");
  if (MUD_NEWBIESTART)
    set_owner(p, MUD_NEWBIESTART);
  if (bad_place(p) && MUD_DEFHOME)
    set_owner(p, MUD_DEFHOME);

  if (frob)
    p->set("privs", LEV_CHIEF);

  MudObject *no = natobj(p);

  if (!no || !dotrap(E_ONNEWBIESTART, p, no)) {
    /* ::: newbie_start o1==their nation; return 1 to not clone default newbie kit for them */
    clone_newbiekit(p);
  }

  log(PFL_SEEINFO, 0, "net", "\a^Mcreated^n (nation:%s) in %s^n", p->get("nation"), p->owner->id);
  announce_entry(p);

  p->oprintf(secret(p) && cansee, "%s\n", build_setin(p, setqin).c_str());
  p->lprintf(secret(p) && cansee, "%s\n", build_setin(p, setqin).c_str());

  housekeeping(p);

  p->interpret("look");
  p->interpret("calc_level");
  p->interpret("save");

  p->pop_state();
  p->push_state("cmd");
}

static void load_player(Player *p, const char *nm) {
  FILE *f = xopen(DATA_USERS, nm, "r");
  
  if (!f) return;
  
  string buf;
  const char *buffer;
  buf = getline(f);
  
  while (buf != "}") {
    if (feof(f))
      break;
    buf = getproperty(f);
    buffer = buf.c_str();
    p->load(buffer);
  }
  
  p->set("id", nm);
  
  NewWorld eq;
  
  while (1) {
    buf = getproperty(f);
    buffer = buf.c_str();
    if (feof(f)) {
      break;
    }
    string cloneof = buf.substr(buf.find(' ')+1);
    cloneof = cloneof.substr(0, cloneof.find(' '));
    MudObject *k = 0;
    if (planet->get(cloneof.c_str()))
      k = clone_object(planet->get(cloneof.c_str()), p, NULL);
    if (k)
      eq.add(*k);
    while (buf != "}") {
      if (feof(f)) {
	break;
      }
      buf = getproperty(f);
      if (k) {
	k->load(buf.c_str());
      }
    }
  }
  
  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) {
    MudObject *r = o->get_object("$rider");
    if (r == p)
      p->set("$mount", o->id);

    o->unset("$rider");
    r = o->get_object("$wielder");
    if (r == p) {
      p->set(KEY_WIELD, o->id);
    } else {
      o->unset("$wielder");
    }
  }
  
  xclose(f);
}

static void verb_buffer(Player *who, int, const char *[]) {
  if (!who->get_flag(FL_NOBUFFER))
    {
      char *s = strdup(who->seenbuffer.c_str()), *s2 = s;
      s = strtok(s, "\n");
      who->printf("\n&=LW-->^n\n");
      while (s) {
	who->printf("%s\n", s);
	s = strtok(NULL, "\n");
      }
      who->seenbuffer = "";
      who->printf("\n^n&=LW<--^n\n");
      free(s2);
    }
}

static void state_password(Player *p, const char *w)
{
  if (!w)
    return;
  
  if (!*w) {
    p->pop_state();
    p->push_state("name");
    return;
  }

  PersonState *ps = p->get_person_state();

  if (!ps->get("password")) {
    p->printf("That's odd, you have no password set? This message should never happen.\n");
    return;
  }

  if (!ps->get("id")) {
    p->printf("That's odd, you have no id set? This message should never happen.\n");
    return;
  }

  const char *np = crypt(w, ps->get("password"));
  if (!streq(np, ps->get("password"))) {
    p->printf("Bad password.\n");
    int sofar = ps->get_int("attempts", 0);
    sofar++;
    ps->set("attempts", sofar);
    if (sofar==3) {
      log(PFL_HOSTS, 0, "net", "third bad password for %s, killing", ps->get("id"));
      p->printf("If you cannot remember your password, try emailing the administrators to get it reset.\n");
      p->interpret("quit");
    } else {
      log(PFL_HOSTS, 0, "net", "bad password for %s", ps->get("id"));
    }
    return;
  }

  if (Player *o=players->get(ps->get("id"))) {
    if (!o->p) {
      p->printf("Welcome back : you were linkdead.\n");
      p->send_data();

      o->p = p->p;
      p->p = 0;
      p->nuke_me = 1;

      o->oprintf(secret(o) && cansee, "%#M %[has/have] reconnected.\n", o);

      o->set("hostname", o->p->get_ip());

      o->time_since = now;
      if (get_charset(o)==CHAR_UNICODE) {
	o->printf("\033%G\2");
      }

      verb_buffer(o, 0, 0);
      log(o, PFL_SEEINFO, 0, "net", "reconnected.");

      return;
    } else {
      p->printf("Someone called that already here. Swapping you.\n");
      p->send_data();
      o->printf("Someone has entered the game as you.\n");
      o->send_data();
      delete o->p;
      o->p = p->p;
      p->p = 0;
      p->nuke_me = 1;

      o->set("hostname", o->p->get_ip());

      if (get_charset(o)==CHAR_UNICODE) {
	o->printf("\033%G\2");
      }
      verb_buffer(o, 0, 0);

      log(o, PFL_SEEINFO, 0, "net", "reconnected.");
      return;
    }
  }

  if (planet->get(ps->get("id"))) {
    return;
  }

  p->interpret("info motd");
  if (ps != p->get_person_state())
    p->pop_state();
  p->printf("\n");
  p->printf("^WTip of the day:^n %s^n\n", random_tip().c_str());
  p->printf("\n");

  if (ps->get_int("maxinvis", 0)!=0) {
    p->set_state("invis");
    p->printf("Enter vis level (^W0-%i^n), '^Wi^n' for full invisibility.\n", 
	      ps->get_int("maxinvis"));
    ps->set("prompt", ssprintf("or press ^W[^CEnter^W]^n to keep vis level (Current : ^W%i^n): ", 
			       ps->get_int("invis")));
  }
  else
    p->set_state("motd");
  return;
}

static time_t dateof(const char *name) {
  struct stat buf;
  if (stat(name, &buf)==-1)
    return 0;
  return buf.st_mtime;
}

void alert_to_newstuff(Player *p)
{
  time_t last = p->get_int("lastlogin");
  
  struct stat buf;
  string f = ssprintf(DATA_MAIL "/%s.new", p->id);
  if (stat(f.c_str(), &buf)==0) {
    p->printf("^YYou have new mail!^n\a\n");
    p->set_bflag(FL_HASMAIL, 1);
    unlink(f.c_str());
  }

  MessageFile msg(DATA_NEWS, MUD_MAINBOARD);
  if (msg.count_new(p)) {
    p->printf("^GThe main board has new postings.^n\n");
  }

  if (last != -1) {
    
    if (dateof(DATA_INFO "/news.i")>=last) {
      p->printf("Info news has been ^Rupdated^n.\n");
    }
    if (privs_of(p)>=LEV_CAPTAIN && dateof(DATA_INFO "/wiznews.i")>=last) {
      p->printf("Info wiznews has been ^Rupdated^n.\n");
    }
    if(BUGWATCH_NEWSTUFF) BUGWATCH_NEWSTUFF(p);
  }
}

void state_motd(Player *p, const char *w)
{
  PersonState *ps = p->get_person_state();

  if (streq(ps->get("state"), "invis") && *w) {
    if (tolower(*w)=='i') {
      ps->set("invis", ps->get_int("maxinvis"));
    } else {
      int i = atoi(w);
      if (i >= 0 && i <= ps->get_int("maxinvis")) {
	ps->set("invis", i);
      }
    }
  }

  if (!ps->get("id")) {
    p->printf("We've lost your id. Argh.\n");
    return;
  }

  load_player(p, ps->get("id"));
  p->set_bflag(FL_LOGGEDIN, 0);

  p->unset("away");
  if (get_charset(p)==CHAR_UNICODE) {
    p->printf("\033%G\2");
  }

  if (!p->get("colours")) {
    p->set("colours", "classic");
  }

  p->set("invis", ps->get_int("invis", 0));
  
  if (MudObject *home=p->get_object("home")) {
    set_owner(p, home);
    p->unset("home");
  } else {
    set_owner(p, MUD_DEFHOME);
  }

  p->set_bflag(FL_LOGGEDIN, 1);
  if (invis(p))
    log(PFL_SEEINFO, invis(p), "net", 
	"(level %i) logged into %s with invis %i", privs_of(p), p->owner ? 
	p->owner->id : "???", invis(p));
  else
    log(PFL_SEEINFO, 0, "net", "(level %i) logged into %s", privs_of(p), 
	p->owner ? p->owner->id : "???");
  p->set_bflag(FL_LOGGEDIN, 0);

  announce_entry(p);

  p->oprintf(secret(p) && cansee, "%s\n", build_setin(p, setqin).c_str());
  p->lprintf(secret(p) && cansee, "%s\n", build_setin(p, setqin).c_str());  

  p->unset("mission");
  p->interpret("calc_level");
  p->set(KEY_STRENGTH, p->get_int("maxstrength"));
  p->set_bflag(FL_LOGGEDIN, 1);

  p->set_bflag(FL_SITTING, 0);
  p->set_bflag(FL_HANDSTIED, 0); 
  p->set_bflag(FL_SLEEPING, 0);
  p->unset(KEY_SITON);
  p->unset(KEY_SITONN);

  p->interpret("look");

  alert_to_newstuff(p);
  housekeeping(p);

  p->pop_state();
  p->push_state("cmd");
}

static bool verb_password(Player *who, int, const char **) {
  who->push_state("chpass1");
  return true;
}

static void state_chpass1(Player *p, const char *w) {
  const char *pwd = p->get("password");
  if (streq(crypt(w, p->get("password")), pwd)) {
    p->set_state("chpass2");
  } else {
    p->printf("Wrong password.\n");
    p->pop_state();
  }
}

static void state_chpass2(Player *p, const char *w) {
  if (!w || !*w) {
    p->pop_state();
    return;
  }
  if (strlen(w)<3) {
    p->printf("New password is too short. Pick a longer one.\n");
    return;
  }
  char salt[3] = { rsalt(), rsalt(), 0 };
  p->set("newpass", crypt(w, salt));
  p->set_state("chpass3");
}

static void state_chpass3(Player *p, const char *w) {
  if (streq(p->get("newpass"), crypt(w, p->get("newpass")))) {
    p->set("password", p->get("newpass"));
    p->pop_state();
  } else {
    p->pop_state();
    p->printf("Passwords didn't match. Try again.\n");
  }
}

static bool verb_klock(Player *who, int, const char **) {
  who->printf("Connection locked, awaiting password.\n");
  who->push_state("unlock");
  return true;
}

static void state_unlock(Player *who, const char *what) {
  const char *pwd = who->get("password");
  if (!pwd) {
    who->printf("OK.\n");
    who->pop_state();
    return ;
  }
  if (streq(crypt(what, who->get("password")), pwd)) {
    who->pop_state();	
    who->printf("OK.\n");
  } else {
    who->printf("^WWrong.\n");
  }
}

static bool verb_possess(Player *who, int argc, const char **argv) {
    MudObject *target = find_object(who, argv[1]);
    if (!target) {
      who->printf("Alias who?\n");
      return true;
    }
    if (is_player(target)) {
      who->printf("You cannot possess players.\n");
      return true;
    }
    who->snoop(target);

    log(PFL_SEEINFO, 0, "admin", "possesses %s (%s)", target->id, target->get("name"));

    PersonState *s = new PersonState("alias");
    char prompt[256];
    sprintf(prompt, "|%s^n|", target->get("name"));
    s->set("prompt", prompt);
    s->set("alias", target->id);
    who->push_state(s);
    return true;
}

static void state_alias(Player *p, const char *w) {
  const char *al = p->get_person_state()->get("alias");
  MudObject *t = al?0:planet->get(al);

  if (streq(w, ".") || streq(w, "**")) {
    p->pop_state();
    if (t) {
      p->desnoop(t);
      log(PFL_SEEINFO, 0, "admin", "unpossesses %s (%s)", t->id, t->get("name"));
    }
    return;
  }

  if (*w == '*') {
    p->interpret(w+1);
    return;
  }

  if (t) {
    t->interpret(w);
  }
}

const char *player_id();
extern int which_player;

static bool verb_become(Player *p, int argc, const char **argv)
{
  Player *np = new Player(player_id(), p->p);
  np->setf("short", "player%i", which_player-1);
  np->setf("name", "[Logging In %I]", which_player-1);
  np->set("desc", "This player has no description");
  set_owner(np, mud);

  if (np->p->thingy_from==1) {
    np->set_bflag(FL_COLOUR, 1);
  }

  if (!argv[1]) {  
    np->spewfile(DATA_INFO, "issue.i");
  } else {
    state_setname(np, argv[1]);
  }

  planet->add(*np);

  p->p = 0;
  p->interpret("quit");

  return true;
}

extern "C" void reboot_recover(Player *p, const char *w)
{
  load_player(p, w);
  p->pop_state();
  p->push_state("cmd");

  MudObject *ho = p->get_object("home");
  p->set("reboothome", ho?ho->id:0);

  p->set_bflag(FL_LOGGEDIN, 1);

  p->set(KEY_STRENGTH, p->get_int("maxstrength"));
}

void startup() {
  ADD_STATE("name",     "By what name shall I call you? ", state_setname, false);

  // creating a new char
  ADD_STATE("confirm",  "Did I hear correctly? ",          state_confirm, false);
  ADD_STATE("askpwd",   "Choose your password: ",          state_askpass, true);
  ADD_STATE("conpwd",   "Confirm your password: ",         state_conpass, true);
  ADD_STATE("sex",      "Sex (m/f/n/a): ",                 state_sex,     false);
  ADD_STATE("newbiemotd","Press ^Benter^n to continue^n : ", state_newbiemotd, false);
  ADD_STATE("nation",   "Nation: ",                        state_nation,  false);

  // logging in
  ADD_STATE("password", "Password: ",                       state_password, true);
  ADD_STATE("motd",     "Press ^Benter^n to continue^n : ", state_motd, false);
  ADD_STATE("invis",    "What invisibility level? : ",      state_motd, false);

  // changing password
  AUTO_VERB(password, 5, 0, PFL_NONE);
  ADD_STATE("chpass1", "Enter the ^ROLD^n password:", state_chpass1,true);
  ADD_STATE("chpass2", "Enter the ^RNEW ^npassword:", state_chpass2,true);
  ADD_STATE("chpass3", "Confirm the ^RNEW ^npassword:", state_chpass3,true);

  // keyboard locking
  AUTO_VERB(klock, 5, 0,    PFL_NONE);
  ADD_STATE("unlock", "Password : ", state_unlock, true);

  // alias
  AUTO_VERB(possess, 5, 0,   PFL_FORCE);
  ADD_STATE("alias", "Aliased...", state_alias, false);

  // become
  AUTO_VERB(become, 5, 0,   PFL_BECOME);
}