#include "boot.clh"

object PLAYER
    parents LOCATED_OBJ, DESCRIBED_OBJ;

    name = "Generic Player";

    str		password;
    str		gender;
    num		connected_at, last_cmd_at; 
    obj		home;
    list	creations;
    num		reading;		/* reading flag */
    str		read_input;		/* input so far */
    str		done_reading;		/* what to call when done reading */

      /* nicknames */
    obj		nick_root = ROOT_OBJ;
    obj		nick_desc = DESCRIBED_OBJ;
    obj		nick_loc = LOCATED_OBJ;
    obj		nick_thing = THING;
    obj		nick_cont = CONTAINER;
    obj		nick_room = ROOM;
    obj		nick_exit = EXIT;
    obj		nick_player = PLAYER;
    obj		nick_builder = BUILDER;
    obj		nick_prog = PROGRAMMER;
    obj		nick_wizard = WIZARD;

      /* player commands */
    verb	"dr*op th*row" = drop_cmd;
    verb	"get ta*ke" = get_cmd;
    verb	"help" = help_cmd;
    verb	"home" = gohome_cmd;
    verb	"i inv*entory" = inventory_cmd;
    verb	"l*ook" = look_cmd;
    verb	"news" = news_cmd;
    verb	"pa*ge" = page_cmd;
    verb	"pa*ge" : "with" = page_cmd;
    verb	"@password password" : "to" = password_cmd;
    verb	"@password password" = password_cmd;
    verb	"po*se" = pose_cmd;
    verb	"quit" = quit_cmd;
    verb	"rwho" = rwho_cmd;
    verb	"sa*y" = say_cmd;
    verb	"who" = who_cmd;
    verb	"wh*isper" : "to" = whisper_cmd;
    verb	"wiz*ards" = wizards_cmd;

    method init
	if (this == PLAYER)
	    this.add_owner(WIZARD);
	elseif (PERMS_OK)
	    pass();
	    this.add_owner(this);
	    home = PLAYER_START;
	    this.moveto(home);
	    last_cmd_at = time();
	else
	    raise E_PERM;
	endif
    endmethod /* init */

    method destroy
	var	thing, tid;
	ignore	E_SERVERDN, E_OBJNF, E_METHODNF;

	if (PERMS_OK)
	    for thing in (creations)
		tid = thing.id;
		if (tid == E_OBJNF || tid == E_SERVERDN)
		    continue;
		endif
		if (thing != this) 
		    thing.rm_owner(this);
		    if (!thing.owners)
			thing.destroy();
		    endif
		endif
	    endfor
	    SYS_OBJ.rm_player(this);
	    pass() to LOCATED_OBJ;
	else
	    raise E_PERM;
	endif
    endmethod
	    
    method id
	return pass() to DESCRIBED_OBJ;
    endmethod

    method psub
	var	n, s, o, p, q, r;

	n = name;
	if (gender && gender[1] == "m")
	    s = "he"; o = "him"; p = "his"; q = "his"; r = "himself";
	elseif (gender && gender[1] == "f")
	    s = "she"; o = "her"; p = "her"; q = "hers"; r = "herself";
	else
	    s = "it"; o = "it"; p = "its"; q = "its"; r = "itself";
	endif
	return psub(args[1]);
    endmethod

    method moveto
	var	oldloc;
	ignore	E_METHODNF;

	oldloc = location;
	if (pass(args[1]))
	    if (lengthof(args) > 1 && args[2])
		echo(args[2]);
	    endif
	    if (lengthof(args) > 2 && args[3])
		oldloc.announce(this.psub(args[3]), {this, location});
	    endif
	    oldloc.announce(name + " has left.", {this, location});
	    this.look_around();
	    if (lengthof(args) > 3 && args[4])
		echo(args[4]);
	    endif
	    if (lengthof(args) > 4 && args[5])
		location.announce(this.psub(args[5]), {this, oldloc});
	    endif
	    location.announce(name + " has arrived.", {this, oldloc});
	    return 1;
	else
	    return 0;
	endif
    endmethod

    method drop_cmd
	var	thing;
	ignore	E_SERVERDN, E_METHODNF, E_OBJNF;

	if (caller != this)
	    return 1;
	elseif (args[2] == "all" || args[2] == "everything")
	    if (!contents)
		echo("You are empty-handed.");
	    else
		for thing in (contents)
		    if (thing.drop("all") == E_METHODNF)
			echo(thing.name + ":  You can't drop that.");
		    endif
		endfor
	    endif
	else
	    return 1;
	endif
    endmethod

    method get_cmd
	var	cont, thing;
	ignore	E_SERVERDN, E_METHODNF, E_OBJNF;

	if (caller != this)
	    return 1;
	elseif (args[2] == "all" || args[2] == "everything")
	    cont = location.contents - this;
	    if (!cont)
		echo("There's nothing here to get!");
	    else
		for thing in (cont)
		    if (thing.get("all", "") == E_METHODNF)
			echo(thing.name + ":  You can't get that.");
		    endif
		endfor
	    endif
	else
	    return 1;
	endif
    endmethod

    method input_to
	if (caller != this && !(caller in SYS_OBJ.wizards))
	    raise(E_PERM);
	endif
	reading = 1;
	read_input = "";
	done_reading = args[1];
    endmethod

    method parse
	var	thing, cmd, r;
	ignore	E_SERVERDN;

	if (caller != this && !(caller in SYS_OBJ.wizards))
	    raise(E_PERM);
	endif
	lock("parse");
	last_cmd_at = time();
	cmd = args[1];
	if (reading)
	    if (cmd == ".")
		reading = 0;
		this.(done_reading)(read_input);
		read_input = "";
	    else
		read_input = read_input + cmd + "\n";
	    endif
	    return;
	endif
	if (!cmd)
	    return;
	elseif (cmd[1] == "\"")
	    if (lengthof(cmd) > 1)
		cmd = "say " + cmd[2..];
	    else
		cmd = "say ";
	    endif
	elseif (cmd[1] == ":")
	    if (lengthof(cmd) > 1)
		cmd = "pose " + cmd[2..];
	    else
		cmd = "pose ";
	    endif
	elseif (cmd[1] == ";")
	    if (lengthof(cmd)  > 1)
		cmd = "eval " + cmd[2..];
	    else
		cmd = "eval ";
	    endif
	endif

	if (!this.call_verb(cmd))		/* check player for cmds */
	    return;
	endif
	for thing in (contents)
	    if (thing.call_verb(cmd) == 0) return; endif
	endfor
	if (location)
	    if (location.call_verb(cmd) == 0)	/* check room for cmds */
		return;
	    endif
	    for thing in (location.contents)	/* check room's inv for cmds */
		if (thing != this)
		    if (thing.call_verb(cmd) == 0) return; endif
		endif
	    endfor
	    if (location.go(cmd) == 0) return; endif
	    for thing in (location.exits)	/* check exits for cmds */
		if (thing.call_verb(cmd) == 0)
		    return;
		endif
	    endfor
	endif
	echo("I don't understand that.");
    endmethod /* parse */

    method home
	return home;
    endmethod /* home */

    method match
	if (args[1] == "me" && player == this)
	    return 1;
	else
	    return (pass(args[1]) to DESCRIBED_OBJ);
	endif
    endmethod /* match */

    method match_env
	var	s, what, loc;
	ignore	E_SERVERDN, E_VARNF;

	s = args[1];
	if (!s)
	    return NOTHING;
	elseif (s[1] == "#")
	    return toobj(s);
	elseif (s == "me")
	    return player;
	elseif (s == "here" && location)
	    return location;
	elseif (s == "nowhere")
	    return NOTHING;
	elseif (s[1] == "$" && lengthof(s) > 1)
	    what = getvar("nick_" + s[2..]);
	    if (what == E_VARNF || typeof(what) != OBJ)
		return NOTHING;
	    else
		return what;
	    endif
	endif
	what = this.match_contents(s);
	if (what)
	    return what;
	endif
	if (location)
	    what = location.match_contents(s);
	    if (what)
		return what;
	    endif
	endif
	return NOTHING;
    endmethod /* match_env */

    method disconnect
	location.announce(name + " has disconnected.", {player});
    endmethod /* disconnect */

    method connect
	connected_at = time();
	this.look_around();
	if (location)
	    location.announce(name + " has connected.", {player});
	endif
    endmethod /* connect */

    method connected_at
	return connected_at;
    endmethod /* connected_at */

    method last_cmd_at
	return last_cmd_at;
    endmethod /* last_cmd_at */

    method tell
	echo(args[1]);
    endmethod /* tell */

    method add_creation
	creations = creations + args[1];
    endmethod /* add_creation */

    method rm_creation
	creations = creations - args[1];
    endmethod /* rm_creation */

    method sdesc
	return (name + " is here.");
    endmethod /* sdesc */

    method set_name
	var	existing;

	/* check for duplicate player names */
	existing = SYS_OBJ.find_player(args[1]);
	if (existing && existing != this)
	    raise(E_RANGE);
	elseif (" " in args[1])
	    raise(E_RANGE);
	else
	    pass(args[1]) to DESCRIBED_OBJ;
	endif
    endmethod /* set_name */

    method look
	pass() to DESCRIBED_OBJ;
	if (contents)
	    player.tell("Carrying:");
	    this.inv();
	endif
    endmethod /* look */

    method help_cmd
	var	filename, what;
	ignore	E_FILE, E_METHODNF;

	if (caller != this)
	    return 1;
	endif
	if(args[2])
	    filename = "help/" + args[2] + ".txt";
	else
	    filename = "help/intro.txt";
	endif
	if (echo_file(filename) == 0)
	    return;
	endif
	what = this.match_env(args[2]);
	if (what)
	    if (!what.help())
		echo("There is no help on that object.");
	    endif
	else
	    echo("There is no help on that topic.");
	endif
    endmethod

    method inv
	var	thing, nm;
	ignore	E_SERVERDN;

	for thing in (contents)
	    nm = thing.name;
	    if (nm == E_SERVERDN)
		player.tell("  (Ghost of " + tostr(thing) + ")");
	    else
		player.tell("  " + nm);
	    endif
	endfor
    endmethod /* inv */

    method gohome_cmd
	ignore	E_SERVERDN;

	if (caller != this)
	    return 1;
	endif
	this.moveto(home, "Click click click...", name + " goes home.",
			  "", name + " comes home.");
    endmethod /* gohome_cmd */

    method inventory_cmd
	var	item;

	if (contents)
	    echo("You are carrying:");
	    this.inv();
	else
	    echo("You are empty-handed.");
	endif
    endmethod /* inventory_cmd */

    method look_around
	ignore	E_SERVERDN, E_OBJNF;
	var	r;

	player = this;
	r = location.look();
	if (r == E_SERVERDN)
	    echo("The outlines of the room you are in have suddenly become hazy and indistinct.  Going \"home\" might be useful about now.");
	elseif (r == E_OBJNF)
	    echo("You're absolutely nowhere.  Go home.");
	endif
    endmethod

    method look_cmd	/* verb, can be called by others */
	if (!args[2])
	    this.look_around();
	elseif (this.match(args[2]))
	    this.look();
	else
	    return 1;	/* keep looking for verb on other objects */
	endif
    endmethod /* look_cmd */

    method news_cmd
	var	what;
	ignore	E_FILE;

	if (caller != this)
	    return 1;
	elseif (!args[2])
	    what = "news/intro.txt";
	else
	    what = "news/" + args[2] + ".txt";
	endif
	if (echo_file(what) == E_FILE)
	    echo("There is no news on that topic.");
	endif
    endmethod

    method page_cmd
	var	who, locname;
	ignore	E_SERVERDN, E_METHODNF, E_OBJNF;

	if (caller != this)
	    return 1;
	elseif (!args[2])
	    echo("Usage:  page <player>");
	    echo("        page <player> with <message>");
	endif
	locname = location.name;
	who = SYS_OBJ.find_connected_player(args[2]);
	if (!who)
	    echo("That player is not connected.");
	elseif (args[4])
	    who.tell(name + " pages, \"" + args[4] + "\"");
	    echo("Your message has been sent.");
	elseif (typeof(locname) == STR)
	    who.tell("You sense that " + name + " is looking for you in "
			+ locname + ".");
	    echo("Your message has been sent.");
	else
	    who.tell("You sense that " + name + " is looking for you.");
	    echo("Your message has been sent.");
	endif
    endmethod /* page_cmd */

    method password_cmd		/* verb */
	if (caller != this)
	    return 1;
	elseif (!args[2] || !args[4])
	    echo("Usage:  @password <oldpasswd> to <newpasswd>");
	elseif (crypt(args[2], password[1..2]) != password)
	    echo("Incorrect old password.");
	else
	    password = crypt(args[4]);
	    echo("Password changed.");
	endif
    endmethod /* password_cmd */

    method pose_cmd		/* verb */
	if (caller != this)
	    return 1;
	endif
	location.announce(name + " " + args[2]);
    endmethod /* pose_cmd */

    method rwho_cmd
	var	sysobj, header;
	ignore	E_SERVERDN;

	for sysobj in (servers())
	    header = "Server \"" + servername(sysobj) + "\":  ";
	    if (sysobj.who(header) == E_SERVERDN)
		echo(header + "Server down.");
	    else
		echo("---");
	    endif
	endfor
    endmethod /* rwho_cmd */

    method say_cmd	/* verb */
	if (caller != this)
	    return 1;
	endif
	echo("You say, \"" + args[2] + "\"");
	location.announce(name + " says, \"" + args[2] + "\"", {player});
    endmethod /* say_cmd */

    method teleport_cmd	/* verb */
	var	what, dest;

	what = this.match_env(args[2]);
	dest = this.match_env(args[4]);
	if (!what)
	    echo("Teleport what?");
	elseif (!dest && args[4] != "nowhere")
	    echo("Teleport it where?");
	elseif(!what.moveto(dest, "You feel a wrenching sensation.."))
	    echo("You can't teleport that.");
	else
	    echo("Teleported.");
	endif
    endmethod /* teleport_cmd */

    method quit_cmd /* verb */
	if (caller != this && !(caller in SYS_OBJ.wizards))
	    return 1;
	endif
	quit();
    endmethod /* quit_cmd */

    method wizards_cmd	/* verb */
	var	wiz;

	echo("Your wizards are:");
	for wiz in (SYS_OBJ.wizards)
	    echo("  " + wiz.name);
	endfor
    endmethod /* wizards_cmd */

    method who_cmd		/* verb */
	if (caller != this)
	    return 1;
	endif
	SYS_OBJ.who;
    endmethod /* who_cmd */

    method whisper_cmd
	var	who;
	ignore	E_METHODNF;

	if (caller != this)
	    return 1;
	endif
	who = this.match_env(args[4]);
	if (!who)
	    echo("I don't see that here.");
	elseif (who.tell(name + " whispers, \"" + args[2] + "\"") == 0)
	    echo("You whisper, \"" + args[2] + "\" to " + who.name);
	else
	    echo("You can't whisper to that!");
	endif
    endmethod /* whisper_cmd */

endobject	/* PLAYER */