lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* Do not remove the headers from this file! see /USAGE for more info. */

//### lots of functions in here need to be autodoc'd

// /std/player.c  Written after login.c 1-12-94
// Rust@ZorkMUD
// with mods by alot of us:
// including:   Nevyn@ZorkMUD (GUE)
//              Peregrin @ZorkMUD (GUE)
// Beek ... Deathblade ... The rest of the Zorkmud staff ...
//
#include <daemons.h>
#include <mudlib.h>
#include <config.h>
#include <security.h>
#include <setbit.h>
#include <playerflags.h>
#include <commands.h>
#include <move.h>
#include <hooks.h>
#include <size.h>
#include <combat.h>
#include <clean_up.h>

// Files we need to inherit --
inherit MONSTER;
inherit M_ACCESS;
inherit M_SMARTMOVE;

#ifndef EVERYTHING_SAVES
private inherit M_SAVE; // don't want people calling load_from_string()
// externally
#endif

inherit __DIR__ "body/quests";
inherit __DIR__ "body/mailbase";
inherit __DIR__ "body/newsdata";
inherit __DIR__ "body/cmd";
inherit __DIR__ "body/help";
inherit __DIR__ "body/wizfuncs";
inherit __DIR__ "body/money";
inherit __DIR__ "body/start";
inherit __DIR__ "body/time";
inherit __DIR__ "body/naming";

#ifdef USE_STATUS_LINE
inherit __DIR__ "body/status_line";
#endif
#ifdef USE_SKILLS
inherit __DIR__ "body/skills";
#endif
#ifdef USE_TITLES
inherit __DIR__ "body/title";
#endif
#ifdef USE_SIMPLE_LEVEL
inherit __DIR__ "body/simple_level";
#endif
#ifdef USE_WIZ_POSITION
inherit __DIR__ "body/wiz_position";
#endif
#ifdef USE_GUILDS
inherit __DIR__ "body/guilds";
#endif
#ifdef USE_STATS
inherit M_BODY_STATS;
#endif

// Global variables --
private string reply;
private string array channel_list = ({ });
private string plan;
private static object link;
private mixed saved_items;

// Spouse, for marriage. Added by Aziz
private string spouse;

// interfaces for other objects to manipulate our global variables

//:FUNCTION query_link
//Return our link object
nomask object query_link()
{
    return link;
}

// Functions to set and query spouse. Added by Aziz.

nomask string query_spouse(){
return spouse;
}

void set_spouse(string new_spouse){
spouse=new_spouse;
save_me();
}

// End Aziz code block. :)

#ifdef EVERYONE_HAS_A_PLAN

//:FUNCTION query_plan
//Returns our plan
nomask string query_plan()
{
    return plan;
}

//:FUNCTION set_plan
//Sets our plan
nomask void set_plan(string new_plan)
{
    if ( this_body() != this_object() )
	error("illegal attempt to set plan\n");

    plan = new_plan;
    save_me();
}

#endif /* EVERYONE_HAS_A_PLAN */

static void update_for_new_body(mapping tmp) {
    /* nothing for now; can be overloaded for races that need it */
}

/* initialize various internal things */
//### needs a new name
private nomask void init_cmd_hook()
{
    object mailbox;
    int idx;

    link = previous_object();

    mailbox = MAILBOX_D->get_mailbox(query_userid());

    idx = mailbox->first_unread_message();
    if ( idx == -1 )
    {
	mailbox->set_message_index(mailbox->query_message_count() - 1);
    }
    else
    {
	mailbox->set_message_index(idx);
	write("\n>>You have new mail<<\n");
    }

    write( "\n" );
    naming_init_ids();

#ifdef USE_MASS
    set_mass(100);
#endif
#ifdef USE_SIZE
    set_size(VERY_LARGE);
#endif
    set_max_capacity(VERY_LARGE);

    if (saved_items) {
	string e;

	if (e = catch(load_from_string(saved_items, 1))) {
	    mapping tmp = restore_variable(saved_items);

	    if (tmp["#base_name#"] != base_name(this_object())) {
		update_for_new_body(tmp);
		tmp["#base_name#"] = base_name(this_object());
		load_from_string(save_variable(tmp), 1);
	    } else
		error("Rethrown: " + e);
	}
	saved_items = 0;
    }
}

nomask void su_enter_game(object where)
{
    init_cmd_hook();

    //### this should go away once we torch the corresponding leave msg for 'su'
    CHANNEL_D->deliver_emote("announce", query_name(),
      sprintf("enters %s.", mud_name()));

    if ( is_visible() )
	simple_action("$N $venter "+mud_name()+".");

    CHANNEL_D->register_channels(channel_list);

    move(where);
}

void enter_game(int state)
{
    switch (state) {
    case 1:
	/* new user */
	if (wizardp(link)) {
	    write("\n"
	      "Hi, new wiz! Tuning you in to all the mud's important channels.\n"
	      "Doing: wiz /on\n"
	      "Doing: chan news /on   (you'll see when new news is posted.)\n"
	      "Doing: gossip /on\n"
	      "Doing: newbie /on\n"
	      "Doing: announce /on\n"
	      "\n");

	    /* these will be registered later */
	    channel_list = ({ "wiz", "news", "gossip",
	      "newbie", "announce" });

	    /* So the hapless new wizard doesn't get spammed. */
	    set_ilog_time(time());
	} else {
	    write("\n"
	      "Tuning in the newbie channel for you.  (newbie /on)\n"
	      "Tuning in the gossip channel for you.  (gossip /on)\n"
	      "\n");

	    /* these will be registered later */
	    channel_list = ({ "gossip", "newbie" });
	}
	/* FALLTHROUGH */   
    case 0:
	/* existing user */
	init_cmd_hook();
	CHANNEL_D->deliver_emote("announce", query_name(),
	  sprintf("enters %s.", mud_name()));
	/* move the body.  make sure this comes before the simple_action */
	if ( !move_to_start() ) {
	    write("Uh-oh, you have no environment.\n");
	} else {
	    /* we don't want other people to get the extra newlines */
	    write("\n");
	    if(is_visible())
		simple_action("$N $venter "+mud_name()+".");
	    write("\n");
	}
	CHANNEL_D->register_channels(channel_list);

	if ( wizardp(link) ) {
	    DID_D->dump_did_info(query_ilog_time(),
	      ({ "",
		"Changes since you last logged in",
		"********************************",
		"" }),
	      0,
	      (: enter_game, 2 :));
	    set_ilog_time(time());
	    return;
	}
	/* FALLTHROUGH */
    case 2:
	do_game_command("look");
    }
}

//:FUNCTION save_me
//Saves us :-)
void save_me()
{
    object shell_ob = link && link->query_shell_ob();
    string userid = query_userid();

    /* save the shell information */
    if ( shell_ob )
	shell_ob->save_me();

    //### This check is bogus.  What should it be?
    // This check also doesn't work for su's -- John
    //    if (previous_object()==this_object())
    saved_items = save_to_string(1); // 1 meaning it is recursive.

    unguarded( 1, (: save_object , USER_PATH(userid) :) );
    saved_items = 0;
}

//:FUNCTION remove
//Handle mailboxes and the last login daemon, as well as the normal stuff
void remove()
{
    object ob;

    if ( !clonep() )
    {
	::remove();
	return;
    }

    save_me();

    MAILBOX_D->unload_mailbox(query_userid());
    unload_mailer();
    LAST_LOGIN_D->register_last(query_userid());

    ::remove();
}

//### This should be protected.
//:FUNCTION quit
//Quit the game.
void quit()
{
    if ( !clonep() )
    {
	::remove();
	return;
    }

    if (is_visible())
	simple_action("$N $vhave left "+mud_name()+".");

    CHANNEL_D->deliver_emote("announce", query_name(),
      sprintf("has left %s.", mud_name()));
    CHANNEL_D->unregister_channels();

#ifdef PLAYERS_START_WHERE_THEY_QUIT
    if (environment() && !wizardp(link))
	set_start_location(file_name(environment()));
#endif

    remove();
}

void do_receive(string msg, int msg_type) {
    if ( link )
	link->do_receive(msg, msg_type);
}

//:FUNCTION set_reply
//set_reply(s) sets the person to whom 'reply' goes to.
void set_reply(string o)
{
    reply = o;
}

//:FUNCTION query_reply
//query the person to whom reply goes to
string query_reply()
{
    return reply;
}

//:FUNCTION net_dead
//This function is called when we lose our link
void net_dead()
{
    //### add security here?

    if ( is_visible() )
	simple_action("$N $vhave gone link-dead.");

    CHANNEL_D->deliver_emote("announce", query_name(),
      sprintf("has gone link-dead.", mud_name()));
}

//:FUNCTION reconnect
//This function is called when we get our link back
void reconnect(object new_link)
{
    //### add security here?

    link = new_link;
    if(is_visible())
	simple_action("$N $vhave reconnected.");

    CHANNEL_D->deliver_emote("announce", query_name(),
      sprintf("has reconnected.", mud_name()));
}

//:FUNCTION die
//This function is called when we die :-)
void die()
{
/* Unavoidable historical problem.  I originally spec'ed die() as the function
 * that got called when you died; i.e. it does whatever else needs to be done
 * that the combat code hasn't already taken care of.
 *
 * Unfortunately, at some later date, someone decided that @ .me->die() should
 * kill you, which is incompatible with the first definition.  Of course, they
 * quickly found out that this leaves you only half dead or so, since only the
 * extra stuff gets done.
 *
 * Some really clever person put a 'set_hp(0)' in here to fix that.  This
 * tells the combat code to kill us.  Unfortunately, that means die() gets
 * called *again*, resulting in this function running twice.
 *
 * In order to be compatible with both abu^H^H^Huses, the following check
 * asks the combat code if it considers use dead already.  If we aren't
 * dead, we ask the combat code to kill us.  If we were called by the
 * combat code, we continue on and do the right thing.
 *
 * This fixes yet ANOTHER problem that klu^H^H^Hfeature introduced, which
 * is that calling die() in dead people isn't a NOP like it should be.
 * In that case, we now call the combat code to kill us, which notices
 * we are already dead, and correctly does nothing.
 */
   if (!query_ghost()) {
       set_hp(0);
       return;
   }

    if ( wizardp(link) )
    {
	if(is_visible())
	    simple_action("If $n $vwere mortal, $n would now no longer be mortal.");
	set_hp(query_max_hp());
	stop_fight();
	return;
    }

    if(is_visible())
	simple_action("$N $vhave kicked the bucket, and $vare now pushing up the daisies.");
    receive_private_msg("\n\n   ****  You have died  ****\n\n"
      "A pity, really.  Way too many people dying these days for me to just patch\n"
      "everyone up.  Oh well, you'll live.\n",0,0);
    rack_up_a_death();

#ifdef DEATH_MESSAGES
    {
	// another option is to choose the message here based on player level
	// or something, instead of just letting action() pick at random.
	// something like: 
	//  action(({ this_object()}),
	//     (MESSAGES_D->get_messages("player_death"))[query_level()/5])[1];
	string msg = action(({this_object()}), 
	  MESSAGES_D->get_messages("player-death"))[1];
	tell( bodies() - ({ this_body() }), msg );
    }
#endif
}

int clean_up() {
    return NEVER_AGAIN;
}

//:FUNCTION id
//id(s) returns 1 if we respond to the name 's'
int id(string arg)
{
    if(!is_visible() && arg == lower_case(query_invis_name()))
	return 1;

    return ::id(arg);
}

string stat_me()
{
    string result = short() + "\n" +
    "Userid: " + query_userid() + "\n" +
    ::stat_me();

    if ( link )
	result += link->stat_me();

    return result;
}

private void create(string userid)
{
    if ( !clonep() )
	return;

    if ( base_name(previous_object()) != USER_OB )
	error("security violation: illegal attempt to change name\n");

    messages = ([]);

    monster::create();
#ifdef USE_STATS
    m_bodystats::create();
#endif

    /*
    ** Make some of the flags non-persistent (they won't be saved).
    */
    configure_set(PLAYER_NP_FLAGS, 1);

    set_long( (: our_description :) );
    naming_create(userid);

    unguarded(1, (: restore_object, USER_PATH(userid), 1 :));

    // up to the player
    set_attack_speed(0);
}


/*
** Listen to channel messages and manipulate the channels
*/
void channel_rcv_string(string channel_name, string message)
{
    receive_private_msg(message);
}

void channel_rcv_soul(string channel_name, array data)
{
    string msg;

    if ( data[0][0] == this_object() )
	msg = data[1][0];
    else if ( sizeof(data[0]) == 2 && data[0][1] != this_object() )
	msg = data[1][2];
    else
	msg = data[1][1];

    receive_private_msg(msg);
}

void channel_add(string which_channel)
{
    channel_list += ({ which_channel });
    CHANNEL_D->register_channels(({ which_channel }));
}
void channel_remove(string which_channel)
{
    channel_list -= ({ which_channel });
    CHANNEL_D->unregister_channels(({ which_channel }));
}
string * query_channel_list()
{
    return channel_list;
}

//### temp hack. be both user and body
nomask object query_body()
{
    return this_object();
}


/* verb interaction */
mixed indirect_give_obj_to_liv(object ob, object liv) {
    return 1;
}

int go_somewhere(string arg)
{
    object env = environment( this_object());
    int    ret;

    if(!(ret=::go_somewhere(arg)) && (env))
	return env->do_go_somewhere(arg);

    return ret;
}

string inventory_header()
{
    return query_name() + " is carrying:\n";
}

int ob_state() 
{
    return -1;
}


void force_look(int force_long_desc)
{
    environment(this_object())->do_looking(force_long_desc, this_object());
}

// Called when our environment destructs.  If we don't move, we get dested too.
void move_or_destruct(object suggested_dest) {
    mixed err;
    object dested_env = environment();
    mixed destination;

    if ( !query_link() )
	return;

    // Might want to add another failsafe room on the end of this list
    // that doesn't inherit room.c and is guaranteed to load/accept people.
    foreach (destination in ({ suggested_dest, VOID_ROOM, this_body()->query_start_location(), START, WIZARD_START  })) {
	err = catch {
	    if (stringp(destination))
		destination = load_object(destination);
	    if (destination != dested_env) {
		err = move(destination);
		if (stringp(err))
		    throw(err);
	    } else
		throw("Being destructed.\n");
	};
	if (destination && !err) {
	    receive_private_msg(dested_env->short() + " being destructed: You have been moved to " + destination->short() + ".\n");
	    return;
	} else {
	    if (destination)
		receive_private_msg("Cannot move to " + destination->short() + ": " + err);
	}
    }
    receive_private_msg("Uh oh..., couldn't move you anywhere.  Goodbye.\n");
    (this_object()->query_link())->remove();
}


#ifdef USE_STATS

int to_hit_base() {
    return 50 - query_agi();
}

int damage_bonus() {
    return fuzzy_divide(query_str(), 10);
}

void refresh_stats() {
    m_bodystats::refresh_stats();
}

#endif /* USE_STATS */

#ifdef USE_SKILLS

int hit_skill()
{
    //### change to something based on skill...
    return fuzzy_divide(query_agi(), 2);
}

#endif /* USE_SKILLS */

/*
** These are overrides from our ancestor (MONSTER)
*/
string query_name() { return naming::query_name(); }
string short() { return query_name(); }
string a_short() { return query_name(); }
string the_short() { return query_name(); }
string in_room_desc() { return base_in_room_desc() + query_idle_string(); }

/* end of naming overrides */

#ifdef USE_SKILLS

class combat_result array negotiate_result(class combat_result array result)
{
    result = (class combat_result array)::negotiate_result(result);

    /*
    ** See if we have disarmed the opponent by using our 'combat/disarm'
    ** skill.  Note that testing the skill will also train it.
    */
    //### where's a better place to put this?
    //### ack. we should be caching our aggregate_skill()
    //### what the heck is the opposing skill?
    //### ... for now, use 5000; eventually, use target's experience

    if ( test_skill("combat/disarm", 5000) )
    {
	result = ({ new(class combat_result,
	    special : RES_DISARM,
	    message : "!disarm") }) + result;
    }

    return result;
}

#endif /* USE_SKILLS */

int allow(string what)
{
    if ( this_body() == this_object() )
    {
	return 1;
    }
    return 0;
}