/
lib/banish/
lib/d/
lib/doc/
lib/doc/domains/
lib/doc/efun/
lib/doc/examples/
lib/doc/examples/armour/
lib/doc/examples/contain/
lib/doc/examples/food/
lib/doc/examples/magic/
lib/doc/examples/monster/
lib/doc/examples/room/
lib/doc/examples/weapons/
lib/function/
lib/include/
lib/include/fn_specs/
lib/include/skills/
lib/info/
lib/inherit/base/
lib/log/
lib/manuals/312/
lib/news/
lib/obj/party/
lib/objects/components/
lib/open/
lib/open/library/
lib/open/party/
lib/players/
lib/players/zilanthius/
lib/room/
lib/room/city/arena/
lib/room/city/creator/
lib/room/city/garden/monst/
lib/room/city/obj/
lib/room/city/shop/
lib/room/death/
lib/room/registry/
lib/secure/
lib/secure/UDP_CMD_DIR/
lib/skills/
lib/skills/fighter/
lib/skills/thief/
lib/usr/
lib/usr/creators/
lib/usr/players/
/* PARTY OBJECT. (c)Angel, March 1994 
 * Original concept of daemon handling by Tamsyn 1993.
 * This object is that which is cloned to players.
 */

#define NAME             (string)this_player()->query_name(0)
#define PARTY_OB	 "obj/party/party_ob"
#define PARTY_FILE	 "obj/party/party_d"
#define MAX_EXP_PER_LEVEL 700

inherit "inherit/base/base_obj";

#include "/obj/party/party.cfg"

string party, leader, *members;
int age;                           /* When the party was originaly formed */
int total_exp;                     /* Total EXP party has ever gained     */
static int total_levels;
static status am_here;

query_object_type() { return "Party"; }

void reset(status arg) {
  if(arg) return;
  members = ({});
  age = time();
  set_name("party_object");
  set_alias("banner");
}

string short(status wiz) {
  return "The banner of '"+party+"'";
}

void long(status wiz) {
  write("A long colourful banner bearing the name '"+party+"'\n"+
     "in grand golden colours along its entire length. \n");
}

status drop(string quit) {
  if(quit) {
    if(environment()) {
      tell_object(environment(), "Saving Party...\n");
    }
    if((string)environment()->query_name(1) == query_leader()) {
      party_leader();
    }
  }
  return 1;
}

status party_save() {
  if(environment()) drop("quit");
  return 0;
}

/**************************************************************************
 * Set Functions.
 */

int  reset_age()              { return age = time();   }
int  set_age(int i)           { return age = i;        }
int  set_total_exp(int i)     { return total_exp = i;  }
string set_party(string str)  { return party = str;    }
string set_leader(string str) { 
  if(sizeof(members)) {
    if(members[0] != str) {
      remove_members(str);
      members = ({ str, }) + members;
      party_update(0);
    }
  }
  add_members(str);
  return leader = str;
}

string *set_members(string *arr) { return members = arr; }

int add_members(string str) {
  if(member_array(str, members) == -1) {
    members += ({ str, });
    party_update(0);
    return 1;
  }
  return 0;
}

int remove_members(string str) {
  int i;
  if((i= member_array(str, members)) != -1) {
    members = members[0..(i-1)] +
                    members[(i+1)..(sizeof(members)-1)];
    party_update(0);
    return 1;
  }
  return 0;
}

/***************************************************************************
 * Query Functions
 */
int query_age()  {  return age = (int)PARTY_FILE->query_age(party); }
int query_exp()  {  return query_total_exp();                       }
int query_rate() {
  int i;
  i = time() - age;
  if(!total_exp) return 0;
  else 
    return (total_exp * 60)/i;
  return (total_exp * 60)/i;
}

int query_total_exp() {  
  return total_exp = (int)PARTY_FILE->query_total_exp(party);
}

string query_party()        { return party;                  }
string query_party_age()    {  return convert_to_time(age);  }
string query_leader() {
  if(party)
    return leader = (string)PARTY_FILE->query_leader(party);
}
string *query_all_members() {
  return members = (string *)PARTY_FILE->query_all_members(party);
}

status query_members(string str) {
  members = query_all_members();
  if(!members || !sizeof(members)) members = ({});
  if(member_array(str, members) != -1) return 1;
  return 0;
}


void init() {
  object obj;
  ::init();


  add_action("party_recruit", "recruit");
  add_action("party_dismiss", "dismiss");
  add_action("party_leave",   "leave"  );
  add_action("party_emote",   "pemote" );
  add_action("party_tell",    "psay"   );
  add_action("party_tell",    "ptell"  );
  add_action("party_who",     "pwho"   );
  add_action("party_save",    "quit"   );
  add_action("party_save",    "Quit"   );
  add_action("party_disband", "disband");

    add_action("party_follow",  "follow" );

  if(!am_here) {
    call_out("party_check_leader", 1);
    am_here = 1;
  }


}

void party_check_leader() {
  if(environment()) {
  if(!find_player(query_leader())) party_leader();
  if((int)find_player(query_leader())->query_level() <
     (int)environment()->query_level()) party_leader();
  }
}

status party_dismiss(string str) {
  object ob, obj;
  if(!str) {
    notify_fail("Dismiss who from the party?\n");
    return 0;
  }
  if((string)this_player()->query_name(1) != query_leader()) {
    notify_fail("Only the leader can dismiss other players.\n");
    return 0;
  }
  if(!query_members(lower_case(str))) {
    notify_fail("That person is not in your party!\n");
    return 0;
  }
  remove_members(str);
  ob = find_player(lower_case(str));
  ob -> set_party(0);
  obj = present("party_object", ob);
  if(obj) destruct(obj);
  party_shout(capitalize(str)+" has been dismissed from the party.\n", 0);
  party_update(0);
  return 1;
}

status party_leave(string str) {
  object ob;
  if(str == party || str == "party") {
    if((string)environment()->query_name(1) == leader) {
      write("You must disband the party to leave it.\n");
      return 1;
    }
    write("You leave the party.\n");
    this_player()->set_party(0);
    remove_members((string)this_player()->query_name(1));
    party_shout((string)this_player()->query_name(1)+" has left "+
                "the party!\n",0 );
    party_update(0);
    destruct(this_object());
    return 1;
  }
  return 0;
}

status party_disband(string str) {
  object obj;
  int i;
  string *all;
  string tmp;
  object who;
  if(str == party || str == "party") {
    if((string)this_player()->query_name(1) != query_leader()) {
      notify_fail("Only the party leader can disband the party.\n");
      return 0;
    }

    party_shout(capitalize(leader)+" has disbanded the party.\n", 0);
    party_shout("Party earned "+query_total_exp()+" in "+show_age()+"\n",1);


    all = query_all_members();
    for(i=0; i<sizeof(all); i++) {
      if(find_living(all[i])) {
        who = find_living(all[i]);
        if(who != environment()) {
          who->set_party(0);
          destruct(present("party_object", who));
        }
      }
    }
    environment()->set_party(0);
    PARTY_FILE->remove_party(party);
    destruct(this_object());
  }
  return 1;
}

status party_recruit(string str) {
  object player, party_ob;

  if(!str) {
    notify_fail("Recruit who into the party?\n");
    return 0;
  }
  if(query_leader() != lower_case(NAME)) {
    notify_fail("Only the leader can recruit people.\n");
    return 0;
  }
  player = present(str, environment(this_player()));
  if(!player) {
    notify_fail(capitalize(str)+" is not here to recruit.\n");
    return 0;
  }
  if(!interactive(player)) {
    notify_fail("You can't do that!\n");
    return 0;
  }
  if(this_player()->query_security_level() && !player->query_security_level()){
    notify_fail("You should know better than to recruit players.\n");
    return 0;
  }
  if(!this_player()->query_security_level() && player->query_security_level()){
    notify_fail("You can't recruit Creators.\n");
    return 0;
  }
  if((string)player->query_party() == party) {
    notify_fail(capitalize(str)+" is already a member of the party!\n");
    return 0;
  }
  if((string)player->query_party()) {
    notify_fail(capitalize(str)+" is already in another party.\n");
    return 0;
  }
  if((int)player->query_level() > (int)this_player()->query_level()) {
    notify_fail("You can't recruit players of higher level than you.\n");
    return 0;
  }
  add_members((string)player->query_name(1));  
  player -> set_party(party);

  party_ob = clone_object(PARTY_OB);
  party_ob -> set_age(query_age());
  party_ob -> set_total_exp(query_exp());
  party_ob -> set_party(party);
  party_ob -> set_members(members);
  party_ob -> set_leader(leader);
  move_object(party_ob, player);

  party_shout((string)player->short()+" joins the party!\n", 0);
  return 1;
}

void party_shout(string message, status quietly) {
  int i;

  for(i=0; i<sizeof(members); i++) {
    if(find_player(members[i])) {
      if(!quietly)
        tell_object(find_player(members[i]), "["+query_party()+"]: ");
      else
        tell_object(find_player(members[i]), "\t");
      tell_object(find_player(members[i]), message+"\n");
    }
  }
}

status party_emote(string str) {
  party_shout(this_player()->query_name()+" "+str, 0);
  return 1;
}


status party_tell(string str) {
  party_shout("\b["+this_player()->query_name()+"]: "+str, 0);
  return 1;
}

void party_update(status arg) {
  PARTY_FILE->remove_party(party);
  PARTY_FILE->add_party(({party,members,age,total_exp}));
  PARTY_FILE->write_best_party();
  if(arg) tell_object(environment(),"Updating party\n");
}

void party_leader() {
  object *who, *ob;
  int i;
  string tmp;
  string temp;

  
  query_all_members();   /* to refresh all those people here */
  tmp = query_leader();
  remove_members(tmp);
  leader = 0;
  party_update(0);
  who = sort_members();
  ob = ({});

  for(i=0; i<sizeof(who); i++) {
    if(find_player((string)who[i]->query_name(1)) &&
       interactive(who[i]))
       ob += ({ who[i], });
  } /* Check for interactive members properly */

  who = ob;
  if(!sizeof(who))       /* nothing in the array now */
    set_leader((string)environment()->query_name(1));
    /* Highest level player just logged out, so get 2nd highest level player */
  else 
    set_leader((string)who[0]->query_name(1));

  party_shout(capitalize(leader)+" is the new leader "+
    "of the party!", 0);
  add_members(tmp);
  party_update(1);
}

static status by_level(object a, object b) { 
  return ((int)a->query_level() > (int)b->query_level()) ? 1 : 0;
}

static status by_interactive(object a, object b) {
  return (interactive(a)) ? 1 : 0;
}

object *sort_members() {
  int i;
  object *who;

  who = ({});
  for(i=0; i<sizeof(query_all_members()); i++) {
    if(find_player(members[i])) who += ({ find_player(members[i]), });
  }
  who = sort_array(who, "by_level", this_object());
  who = sort_array(who, "by_interactive", this_object());
  return who;
}


/* Share the EXP thru the death of a monster, called from living.c */
void share_exp(int xp) {
  object *who;
  int i, share;

  if(!xp) return;
  query_total_levels();

  if((total_levels * MAX_EXP_PER_LEVEL) < xp) 
    xp = total_levels * MAX_EXP_PER_LEVEL;
    total_exp = query_total_exp() + xp;

  party_shout("Sharing: "+ xp +" experience points...", 0);
  who = sort_members();
  for(i=0; i<sizeof(who); i++) {
    share = calc_share((int)who[i]->query_level());
    party_shout(who[i]->query_name()+" received "+share+"% "+
    "of the exp.", 1);
    who[i]->add_exp((share * xp) / 100);
  }
  party_update(0);
}

int query_total_levels() {
  int i;
  object *who;
  total_levels = 0;
  who = sort_members();
  for(i=0; i<sizeof(who); i++) 
      total_levels += (int)who[i]->query_level();
  return total_levels;
}
int calc_share(int level) {
  return ((level*100)/query_total_levels());
}

string convert_to_time(int amount) {
  int tmp;
  string ret;
  ret = "";
  if(tmp =  amount /  (60 * 60 * 24)) {
    ret += tmp + " days ";
    amount -= tmp * 60 * 60 * 24;
  }
  if(tmp = amount / 3600) {
    ret += tmp + " hours ";
    amount -= tmp * 3600;
  }
  if(tmp = amount / 60) {
    ret += tmp + " minutes ";
    amount -= tmp * 60;
  }
  if(amount) ret += amount + " seconds";
  return ret;
}

string show_age() {
  return convert_to_time(time() - age);
}

status party_who() {
  int i;
  object *who;
  string tmp;
  status flag;

  tmp = "";
  who = sort_members();
  write(
  "_____________________________________________________________________\n"+
  ">___________________________________________________________________<\n"+
  " Party Name: "+capitalize(query_party())+"\t"+
  "Party Rating: "+query_rate()+"\n"+
  " Party Age: "+show_age()+"\tParty Exp: "+query_exp()+"\n"+
  " Current Leader: "+capitalize(query_leader())+"\n");

  for(i=0; i<sizeof(members); i++) {
    if(!find_living(members[i])) {
      flag = 1;
      tmp += capitalize(members[i])+" ";
    }
  }
  if(flag) write("Other members include: "+tmp+"\n");
  write(
  " Member  Level  %Share           Classes\n"+
  " ------  -----  ------           -------\n");


  for(i=0; i<sizeof(who); i++) {
    tmp = capitalize((string)who[i]->query_name(1))+"          ";
    tmp = extract(tmp,0,10);
    tmp += "("+(int)who[i]->query_level()+")                  ";
    tmp = extract(tmp,0,15);
    tmp += calc_share((int)who[i]->query_level())+"%           ";
    tmp = extract(tmp,0,25);
    tmp += implode((string *)who[i]->query_classes(), " ");
    tmp = extract(tmp,0,60);
    write(tmp+"\n");
  }
  write(
  "_____________________________________________________________________\n"+
  ">___________________________________________________________________<\n");
  return 1;
}

status party_follow() {
  object obj;

  if(query_leader() == (string)environment()->query_name(1)) {
    write("You can't follow yourself! You're the leader!\n");
    return 1;
  }
  obj = find_player(query_leader());
  if(!obj) {
    write("The leader does not seem to be anywhere close by.\n");
    return 1;
  }
  if(!present(obj, environment(this_player()))) {
    write("The leader needs to be in the same room to follow him.\n");
    return 1;
  }
  if(obj->query_followers(this_player())) {
    write("You are already following "+capitalize(query_leader())+".\n");
    obj->remove_followers(this_player());
    write("You no longer follow "+capitalize(query_leader())+".\n");
    return 1;
  }
  write("You are now following "+(string)obj->query_name(0)+".\n");
  obj -> add_followers(this_player());
  return 1;
}