// File: /std/user.c
// Original Authors: Sulam and Buddha @ The Mud Institute
// Many other people have added to this as well.
//
// This file has a long revision history dating back to the
// hideous mudlib.n and is now probably not at all the same.
// This is the standard user object.
// This file is a part of the TMI distribution mudlib.
// Please keep this header with any code within.

#include <config.h>
#include <money.h>
#include <daemons.h>
#include <move.h>
#include <flags.h>
#include <user.h>
#include <priv.h>
#include <uid.h>

int coins_carried() ;

void get_email(string e) {
   string who, where;
   
   write("\n");
   if( sscanf(e, "%s@%s", who, where) != 2 ) {
      write("Sorry, email must be in the form of user@host\n");
      write("Please reenter your email address: ");
      input_to("get_email");
      return;
   }
   set("email", e);
}

void basic_commands() {
   add_action("quit", "quit");
}

/*
* Move the player to another room. Give the appropriate
* message to on-lookers.
* The optional message describes the message to give when the player
* leaves.
*/
// This one's due for a rewrite. -Buddha
varargs int move_player(mixed dest, string message) {
   object prev;
   int res;
   
   prev = environment( this_object() );
   if( res = move(dest) != MOVE_OK ) {
      write("You remain where you are.\n");
      return res;
   }
   if((int)query("brief") == 2) set("brief", 1);
   if (message == "SNEAK") {
      command("look") ;
      return 0 ;
    }
   if( !query("invisible") )
      if( message == 0 || message == "" )
	  tell_room(prev, query_mmout() + "\n", ({ this_object() }));
	 else tell_room( prev, message + "\n", ({ this_object() }) );
   if( !query("invisible") )
      if( message == 0 || message == "" )
	say( query_mmin() + "\n", ({ this_object() }) );
       else say( query_min() + "\n", ({ this_object() }) );
   command("look");
   if((int)query("brief") == 1) set("brief", 2);
   return 0;
}

void create() {
   set("position", "punk", MASTER_ONLY);
   set("level", 1, MASTER_ONLY);
   set("autosave", 500);
   set("volume", 500);
   set("capacity", 5000);
   set("mass", 7500) ;
   set("bulk", 1000) ;
   set("time_to_heal",10) ;
   set("short", "@@query_short");
   set("ghost", 0);
   set("leader", 0);
   enable_commands();
}

void remove() {
   destroy_autoload_obj();
   this_object()->tsh_cleanup();
   CMWHO_D->remove_user(this_object());
   living::remove();
}

void restore_status() {
   set("cap_name", capitalize((string)query("name")));
   set("short", "@@query_short");
   set("title", "@@query_title");
   set("ghost", 0);
   set("leader", 0);
}

void enable_me() {
	if (geteuid(previous_object()) != ROOT_UID) return ;
	enable_wizard() ;
}

int quit(string str) {

   int i, j ;
   object *stuff ;

   if (str) {
      notify_fail("Quit what ?\n");
      return 0;
   }
   check_team();
   write("See you another time!\n");

// If this is an invisible wizard, we let the invisibility stay on: but
// if it's a player who cast the invisibility spell, then we want him
// to be visible when he reappears.

   if (!wizardp(this_object())) {
      set("invisible",0) ;
   }
   restore_status();
   set("last_on", time());
   save_me();
   ANNOUNCE->announce_user(this_object(), 1);
   say(query("cap_name") + " left the game.\n");
   log_file("ENTER", query("name") +": quit\t\t" +
      ctime(time()) + " from " + query_ip_name(this_object()) + "\n");
   remove();
   return 1;
}


// This procedure is called from the setup() function below.  It is
// basically here to check that existing users get whatever new settings
// they need to function in today's changing mudlib.

void consistency_check() {
   if (!query("short")) set("short", "@@query_short");
   if (!query("cap_name")) set("cap_name", capitalize(query("name")));
   if (!query("title")) set("title", "@@query_title");
   if (!query("shell")) set("shell", "none", MASTER_ONLY);
}

// This function is called when the player logs in. It sets his bulk and
// things appropriately, loads his autoloading objects, etc.
// This function is probably being called on to do too much, we think; it
// is a candidate for large changes in future revisions.

void setup() {
   
   int i;
   string temp, *temp2;
   
   set_living_name( query("name") );
   seteuid(getuid(this_object()));
   set_heart_beat(1);
   set("id", ({ query("name") }), MASTER_ONLY);
   set("ip", query_ip_name(this_object()));

   if (file_size(user_path(geteuid())) == -2) enable_wizard(); // has a dir...
   if (query("wizard")==1) enable_wizard();  // has been promoted to wiz

   init_living();
   basic_commands();
   consistency_check();  /* this is a catch-all function to upgrade old users */

   if(query("inactive"))   delete("inactive");
   if( !query("cwd") ) set("cwd", "/doc");
   i = query("last_on");
/* read the news... if our last_on value is bad, reset it. */
   if (intp(i)) MSG_D->read_news(i);
   else MSG_D->read_news(0); 
   set("last_on", time());
   temp = query("start");

   if(!(temp && stringp(temp) && move(temp) == MOVE_OK))
   move(START);
   call_out("save_me", 1);
   ANNOUNCE->announce_user(this_object(), 0);
   say(query("cap_name") + " enters the game.\n");

   tsh::initialize();
   if(!sizeof(query_aliases())) command("alias -clear");

   set("volume", 500) ;
   set ("capacity", 5000-coins_carried()) ;
   set ("weapon1",0) ;
   set ("weapon2",0) ;
   set ("armor", ([]) ) ;
   load_autoload_obj(); /* Truilkan@TMI 01/18/92 */
   command("look") ;
}

void heart_beat() {
   continue_attack();
   unblock_attack();
   if(query("report") && (query("old_hp") > query("hit_points"))) {
		write("HP: "+query("hit_points")+"("+query("max_hp")+
              ")\tSP: "+query("spell_points")+"("+query("max_sp")+")\n");  
   }
   if(query("report")) set("old_hp", query("hit_points"));
   heal_up();
}

void net_dead() {
   check_team();
   save_me();
   say((string)this_object()->query("cap_name") + " has gone net-dead.\n");
   ANNOUNCE->announce_user(this_object(), 3);
   CMWHO_D->remove_user(this_object());
   set_heart_beat(0);
   log_file("ENTER", this_object()->query("cap_name") + ": net-dead\t\t" + 
      ctime(time()) + " from " + query("ip") + "\n");
}

void restart_heart() {
   say(query("cap_name")+" has reconnected.\n");
   write("Reconnected.\n");
   ANNOUNCE->announce_user(this_object(), 2);
   set_heart_beat(1);
}

void die() {
   object ob;
   object coins ;
   mapping wealth ;
   string *names ;
   object corpse;
   object *stuff;
   int i, res, totcoins ;

   init_attack();
   check_team();
   ob = clone_object("/obj/shadow_death");
   corpse = clone_object("/obj/corpse");
   corpse->set_name(query("cap_name")) ;
   i = query("mass") ;
   if (i>0) corpse->set("mass", i) ;
   i = query("bulk") ;
   if (i>0) corpse ->set("bulk", i) ;
   i = query("capacity") ;
   if (i>0) corpse ->set ("capacity", i) ;
   i = query("volume") ;
   if (i>0) corpse ->set("volume", i) ;
   corpse->move(environment(this_object()));
   stuff = all_inventory(this_object());
   for(i=0;i<sizeof(stuff);i++)
   stuff[i]->move(corpse); 
   wealth = query("wealth") ;
   if (wealth) {
      names=keys(wealth) ;
      for (i=0;i<sizeof(wealth);i++) {
		coins = clone_object(COINS) ;
		coins->set_type(names[i]) ;
		coins->set_number(wealth[names[i]]) ;
		totcoins = totcoins + wealth[names[i]] ;
		if (coins) coins->move(corpse) ;
      }
   }
   set ("wealth", ([])) ;
   res = query("capacity") ;
   set ("capacity", res + totcoins);
   set ("deaths", query("deaths")+1);
   ob->init_shadow(this_object());
}

string query_short() {
   if (interactive(this_object())) return query("title");
   else return (query("title") + " [disconnected]");
}

string query_title() {
   string str, foo, fii;
   str = getenv( "TITLE" );
   if( !str ) str = query("cap_name");
   else if( !sscanf(str, "%s$N%s", foo,fii) )
      str = query("cap_name") + " " + str;
   else str = substr( str, "$N", query("cap_name") );
   return str;
}

string local_commands() { 
   mixed *cmds;
   int i;
   string result;
   if (geteuid(previous_object()) != ROOT_UID)
      return "You aren't authorized to check this information.\n";
   cmds = commands();
   if (!sizeof(cmds)) return "no commands available";
   result = "";
   while (i < sizeof(cmds)) {
      result += (cmds[i][0] + " ");
      i++;
   }
   return result + "\n";
}

mixed *user_commands() { return commands(); }

nomask void receive_message(string class, string msg) {
   object shell;
   string foo ;

   if (getenv("shelltest") == "on") 
   receive("[" + file_name(previous_object()) + "]");
// Invisibility screen. This should catch all tells and says and so forth,
// and all soul commands, and most command messages.

   if (this_player() && this_object()!=this_player()) {
        if ((int)this_player()->query("invisible")==1 &&
            this_object()!=(object)this_player()->query_attacker() &&
            !wizardp(this_object())) {
                return ;
        }
        if ((int)this_player()->query("invisible")==2 &&
            !member_group(geteuid(this_object()),"admin")) {
                return ;
        }
    }

// Check for earmuffs.

   if ((int)this_object()->query("earmuffed")==1) {
      foo = geteuid(previous_object()) ;
      if (foo!=ROOT_UID && !member_group(foo,"admin") && foo!=getuid(this_object())) return ;
   }


   //  Mudlib support for user environment shell
   shell = present("shell", this_object());

   if(shell && previous_object() != shell &&
      base_name(shell) + ".c" == (string) this_object()->query("shell"))
        shell->receive_message(class, msg);
   else receive(msg);
}

// not too sure what this came from.
nomask void catch_msg(object source, string *msg) {
   int i;
   for (i=0;i<sizeof(msg);i++) 
   receive(msg[i]);
}

void hide(int i) {
	set_hide(i);
}

// This procedure returns the total number of coins the player is carrying.
// Mobydick, 10-13-92.

int coins_carried() {

	mapping wealth ;
	string *types ;
	int i, coins ;

	coins = 0 ;
	wealth = query("wealth") ;
	if (!wealth || wealth==([])) return 0 ;
	types = keys(wealth) ;
	for (i=0;i<sizeof(types);i++) {
		coins = coins + wealth[types[i]] ;
	}
	return coins ;
}

// This function returns the player's total wealth in value units.
// Mobydick, 11-5-92.

int total_wealth() {

        mapping wealth ;
        string *types ;
        int i, coins ;

        coins = 0 ;
        wealth = query("wealth") ;
        if (!wealth || wealth==([])) return 0 ;
        types = keys(wealth) ;
        for (i=0;i<sizeof(types);i++) {
		coins = coins + wealth[types[i]]*coinvalue(types[i]) ;
        }
        return coins ;
}

string myname() { return _query("cap_name"); }
/* EOF */