/
LIB3/
LIB3/D/ADMIN/
LIB3/D/ADMIN/OBJ/
LIB3/D/ADMIN/ROOM/W/
LIB3/D/HOME/
LIB3/D/HOME/CITY/ARENA/
LIB3/D/HOME/CITY/ITEMS/
LIB3/D/HOME/CITY/POSTOFFI/
LIB3/DOC/
LIB3/GLOBAL/SPECIAL/
LIB3/GLOBAL/VIRTUAL/
LIB3/NET/
LIB3/NET/CONFIG/
LIB3/NET/DAEMON/CHARS/
LIB3/NET/GOPHER/
LIB3/NET/INHERIT/
LIB3/NET/OBJ/
LIB3/NET/SAVE/
LIB3/NET/VIRTUAL/
LIB3/OBJ/B_DAY/
LIB3/OBJ/HANDLERS/TERM_TYP/
LIB3/PLAYERS/B/
LIB3/PLAYERS/N/
LIB3/ROOM/
LIB3/SAVE/
LIB3/SAVE/BOARDS/
LIB3/SAVE/ENVIRON/
LIB3/SAVE/POST/
LIB3/STD/COMMANDS/SHADOWS/
LIB3/STD/CREATOR/
LIB3/STD/DOM/
LIB3/STD/EFFECTS/
LIB3/STD/EFFECTS/HEALING/
LIB3/STD/EFFECTS/OTHER/
LIB3/STD/EFFECTS/POISONS/
LIB3/STD/ENVIRON/
LIB3/STD/GUILDS/
LIB3/STD/LIQUIDS/
LIB3/STD/ROOM/
LIB3/STD/TRIGGER/SHADOW/
LIB3/W/
LIB3/W/BANNOR/
LIB3/W/NEWSTYLE/
#pragma save_binary
/* stuff for the paranoia combat system... */
/* quick summary of the procedures defined in here
* attack()            - called from heart_beat on monsters and players.
* attack_by(object)   - Pretty obvious, we have been attacked by object
* attack_ob(object)   - sets up the arrays for attacking object
* stop_fight(object)  - stop fighting object
* do_death()          - called when your hps reach 0.
* check_stop_fight() is for intenal use only.
*
* Ok guys, hit_player is obsolete...
* The weapons themselves do all the damage and figure out how much to do
* to the player. They then call adjust_hp(num) themselves...
* Have fun etc.
*
*  Added checks on both attacker and attackee in attack_by() and attack_ob()
*  to see if they have the property "players killed" which means they are
   *  registered player killers  --Ted  (26 Oct 93)
*/
inherit "/std/weapon_logic";

static object attackee;
static object *attacker_list,
*call_outed,
weapon,
protector;
static int concentrate, natural;

/* strange varible no one will ever understand...
* Used as a level of the npc during the battle, so we odnt work it
* out every time.
*/
static int att_level, dodging;
#define DIV_NUM 6
#define XP_DIVISION 1000
#include "money.h"

int query_dodging() { return dodging; }
int query_my_att_level() { return att_level; }
void set_my_att_level(int i) {att_level = i; }
void set_concentrate(int i) { concentrate = i; }
int query_concentrate() { return concentrate; }
object set_protector(object ob) { return (protector = ob); }
object query_protector() { return protector; }

void set_natural(int i) { natural = i; }
int query_natural() { return natural; }
void actual_death();

void create() {
   attacker_list = ({ });
   call_outed = ({ });
   weapon_logic::create();
} /* create() */

void combat_commands() {
   add_action("do_protect", "protect");
} /* combat_commands() */

/* This is called when you die. */
int do_death(object killed_by) {
   int i, xp, aln, tot;
   mapping damage_done;
   
   /* stop fighting every one first... */
   damage_done = (mapping)this_object()->query_damage_done();
   if (!damage_done)
      damage_done = ([ ]);
   for (i=0;i<sizeof(attacker_list);i++) {
      attacker_list[i]->stop_fight(this_object());
      tot += damage_done[attacker_list[i]];
   }
   for (i=0;i<sizeof(call_outed);i++)
   call_outed[i]->stop_fight(this_object());
   xp = (int)this_object()->query_xp();
   if (!tot) tot = 1;
   aln = (int)this_object()->query_align();
   for (i=0;i<sizeof(attacker_list);i++) {
      /*
      * calculate percantage of total xp they get based on how much damage
      * they did
      */
      attacker_list[i]->adjust_xp(((xp * damage_done[attacker_list[i]]/tot)
            * att_level) / (DIV_NUM *
            ((int)attacker_list[i]->query_my_att_level())));
      attacker_list[i]->adjust_align(aln);
   }
   if (killed_by) {
      say(killed_by->query_cap_name()+" dealt the death blow to "+
         this_object()->query_cap_name()+".\n");
      tell_object(killed_by,"You killed "+this_object()->query_cap_name()+".\n");
   }
   else
      say(this_object()->query_cap_name()+" died horribly.\n");
   if (environment())
      event(environment(), "death", attacker_list, killed_by);
   actual_death();
   return 0;
} /* do_death() */

object make_corpse() {
   object corpse,
   money,
   *arms,
   *ob;
   int i;
   corpse = clone_object("/obj/corpse");
   corpse->set_owner(this_object()->short(0), this_object());
   corpse->set_race_name(this_object()->query_race());
   corpse->start_decay();
   corpse->add_adjective(this_object()->query_adjectives());
   if (!this_object()->query_race_ob())
      if (file_size("/std/races/"+this_object()->query_race()+".c") >= 0)
      corpse->set_race_ob("/std/races/"+this_object()->query_race());
   else
      corpse->set_race_ob("/std/races/unknown");
   else
      corpse->set_race_ob(this_object()->query_race_ob());
   ob = all_inventory(this_object());
   
   /* this next bit is for formatting corpse inv - not combat :) */
  if(weapon) {
    if(random(2)) {
      tell_room(environment(), capitalize((string)weapon->query_short()) +
        " drops from " + (string)this_object()->query_cap_name() +
        "'s limp grasp.\n", this_object());
      tell_object(this_object(), "You limply release your " +
          capitalize((string)weapon->query_short()) + "...\n");
      ob -= ({ weapon });
      weapon->move(environment());
    } else {
      weapon->set_wield(corpse);
      corpse->set_weapon(weapon);
      /* moved with the other objects */
    }
  }
  arms = (object *)this_object()->query_armours();
  for (i=0;i<sizeof(ob);i++)
    ob[i]->move(corpse);
  corpse->set_armours(arms);
  for(i=0; i<sizeof(arms); i++)
    arms[i]->set_worn_by(corpse);

  corpse->move(environment());
  return corpse;
} /* make_corpse() */

/* shouldnt need to call this... so make it static, just in case */
static void actual_death() {
  object ob, ob2;
/* if second_life returns false... do stupid things... */
if(!( (int)this_object()->second_life() ) )
{
    make_corpse()->move(environment());
/* dest the ones that stick around... */
    ob = first_inventory(this_object());
    while(ob) {
      ob2 = next_inventory(ob);
      ob->dest_me();
      ob = ob2;
    }
    this_object()->dest_me();
  }
} /* actual_death() */

object query_attackee() { return attackee; }

/* I will assume this is called in heart_beat... 
 * This could be used in both a paranoia mud or D&D style mud..
 * This will be called EVERY heart beat garanteed , that is when it is
 * running.... remember to get a garanteed amount of time use call_outs.
 * they are the most precise thing in mud... (which is not that hot)
 */
attack() {
  int i, dam, his_att_lvl;
  string his_name;
  object *obs, ob;

  if (!attacker_list)
   attacker_list = ({ });

  while (i<sizeof(attacker_list)) {
    if (!attacker_list[i]) /* have they died unexpecedaly? */
      attacker_list = delete(attacker_list,i,1);
    else
/*
 * check to make sure our environments are the same,
 * if not, updated them...
 * Hmmmm, Ok I will put all the ones not in the correct environ in a new
 * list.
 */
      if (environment(attacker_list[i]) != environment()) {
        object blue;

        write("You are hunting "+attacker_list[i]->short()+"\n");
        call_out("check_stop_fight",600,attacker_list[i]);
        if (!call_outed)
          call_outed = ({ attacker_list[i] });
        else
          call_outed += ({ attacker_list[i] });
        blue = attacker_list[i];
        attacker_list = delete(attacker_list,i,1);
        event(environment(), "stopped_fighting", blue);
      } else
        i++;
  }
/* check the not correct environ list to see if any one has come back.  */
  i = 0;
  while (i<sizeof(call_outed))
    if (!call_outed[i])
      call_outed = delete(call_outed,i,1);
    else if (environment() == environment(call_outed[i])) {
      attacker_list += ({ call_outed[i] });
      call_outed = delete(call_outed,i,1);
    } else
      i++;
/* not hitting anyone... do spell effects anyway... */
  if (!sizeof(attacker_list)) {
/* Do the spell effects as a seperate call in the heart_beat now.
    this_object()->do_spell_effects(0);
 */
    attackee = 0;
    return ;
  }
/*
 * choose a random person from the attacker list, as they all must be in
 * correct environment...
 */
  if (concentrate)
    attackee = attacker_list[0];
  else
    attackee = attacker_list[random(sizeof(attacker_list))];
/*
 * Check to see if they are being protected.
 * Should we use a skill here?  Hmm....  To slow probably, will make it
 * a fixed 80% chance for now.  First check to make sure that the
 * protector isnt in the attacker list
 */
  if (protector && member_array(protector, attacker_list) != -1) {
    tell_object(this_object(), protector->query_cap_name()+
                " turns against you and starts fighting you.\n");
    tell_object(protector, "You start fighting "+
                this_object()->query_cap_name()+" and stop protecting "+
                "them.\n");
    say(protector->query_cap_name()+" turns against "+
        this_object()->query_cap_name()+" and starts attacking him.\n",
        ({ protector, this_object() }));
  }
  if ((ob = (object)attackee->query_protector()) &&
      environment(ob) == environment(attackee) && random(100) >= 20) {
    tell_object(attackee, ob->query_cap_name()+
                " valiantly protects you.\n");
    tell_object(ob, "You valiantly protect "+attackee->query_cap_name()+".\n");
    say(ob->query_cap_name()+" valiantly protects "+
        attackee->query_cap_name()+".\n", ({ attackee, ob }));
    attackee = ob;
  }
  his_att_lvl = (int)attackee->query_my_att_level();
  his_name = (string)attackee->query_name();
/* if no spells to cast - do normal hitting */
/* Done in the heart_beat....
 * This was a sleeze so monsters didn't attack whilst casting.  They
 * Should not now anyway due to time effects.
  if(!this_object()->do_spell_effects(attackee)) {
 */
    attackee->attack_by(this_object());
/*
 * Ok, do the damage to the person we are attacking.  This has already
 * been wombled to get the attackee to be the right person (ie being
 * protected).
 */
    if (weapon)
      dam = (int)weapon->weapon_attack(attackee,this_object());
    if (!weapon || natural)
      dam = weapon_attack(attackee,this_object());
/*
  }
 */
  if (!attackee) {
/* This wont normally happen, cause death happens in a call_out(0) 
from the target file. Wonder if it ever will happen...hmmm
maybe if the weapon itself dests the monster? */
    tell_object(this_object(),"You killed "+his_name+"\n");
    say(this_object()->query_cap_name()+" killed "+his_name+"\n");
  }
  if (!att_level)
    att_level = 1;
  this_object()->adjust_xp(dam*his_att_lvl/att_level);
  if (environment())
    event(environment(), "fight_in_progress", attackee);
} /* attack() */

int attack_by(object ob) {
  if (ob == this_object())
    return 0;
  if (!attacker_list)
    attacker_list = ({ });
  if (!sizeof(attacker_list)) {
    att_level = (int)this_object()->query_level()+15;
    att_level += (int)this_object()->query_xp()/XP_DIVISION;
    if (att_level <= 0)
      att_level = 1;
    dodging = (int)this_object()->query_skill_bonus("fighting.combat.dodging.melee");
  }
  if (member_array(ob, attacker_list) == -1 &&
      member_array(ob, call_outed) == -1) {
    attacker_list += ({ ob });
  }
  set_heart_beat(1);
/*
if(find_player("newstyle")) tell_object(find_player("newstyle"), "Ret 1 in "+this_object()->query_cap_name()+"\n");
*/
  return 1;
} /* attack_by() */

int attack_ob(object ob) {
if(ob->attack_by(this_object()) )
{
/*
  if(find_player("newstyle"))
    tell_object(find_player("newstyle"), this_object()->query_cap_name()+
     " returning 1 when attacking "+ob->query_cap_name()+".\n");
*/
   return 1;
 }
} /* attack_ob() */

void check_stop_fight(object ob) {
  int i;

  if ((i=member_array(ob,call_outed)) != -1)
    call_outed = delete(call_outed,i,1);
} /* check_stop_fight() */

int stop_fight(object ob) {
  int i;
  if ((i=member_array(ob,call_outed)) != -1) {
    tell_object(this_object(), "You stop hunting "+call_outed[i]->short()+".\n");
    call_outed = delete(call_outed, i, 1);
  } else {
    event(environment(), "stopped_fighting", ob);
  }
  if ((i=member_array(ob,attacker_list)) != -1)
    attacker_list = delete(attacker_list,i,1);
} /* stop_fight() */

mixed *query_attacker_list() { return attacker_list; }
mixed *query_call_outed() { return call_outed; }

int wield(string str, int none) {
  int i;
  object *obs;
  mapping failed;
  mixed tmp;
  string mess, *bits;

  failed = ([ ]);
  if (!str) {
    notify_fail("Usage: wield <weapon>\n");
    return 0;
  }
  if(str == "hands") {
    if(weapon)
    {
      write("You lower your " + (string)weapon->short() + ".\n");
      weapon->set_wield(0);
    }
    write("You are now ready for hand to hand combat.\n");
    weapon = 0;
    return 1;
  }
  obs = find_match(str, this_object());
  if (!sizeof(obs)) {
    notify_fail("Cannot find "+str+".\n");
    return 0;
  }
  for (i=0;i<sizeof(obs);i++)
    if (obs[i]->query_weapon()) {
      if (weapon && (!(tmp = (mixed)weapon->set_wield(0)) || stringp(tmp))) {
        if (!stringp(tmp))
          mess = "You cannot wield $N.\n";
        else
          mess = tmp;
        if (!failed[mess])
          failed[mess] = ({ obs[i] });
        else
          failed[mess] += ({ obs[i] });
        continue;
      }
       if (!(obs[i]->check_wield()))  /* added 9/10/93, Rastafan */
       {
         return 1;
       }  /* end added 9/10/93, Rastafan */
      if (!(tmp = obs[i]->set_wield(this_object()))) {
        mess = "$N is not a weapon.\n";
        if (!failed[mess])
          failed[mess] = ({ obs[i] });
        else
          failed[mess] += ({ obs[i] });
        continue;
      }
      if (stringp(tmp)) {
        mess = tmp;
        if (!failed[mess])
          failed[mess] = ({ obs[i] });
        else
          failed[mess] += ({ obs[i] });
        continue;
      }
      weapon = obs[i];
      if (this_object() != this_player()) return 1;
/* Need to print the failures first... */
      bits = keys(failed);
      for (i=0;i<sizeof(bits);i++)
        write(replace(bits[i], "$N", query_multiple_short(failed[bits[i]])));
      if (!none) {
        say(this_object()->query_cap_name()+" wields "+
            weapon->query_short()+".\n");
        if (this_player() == this_object()) write("You wield "+
          weapon->query_short()+".\n");
      }
      return 1;
    }
  mess = "";
  bits = keys(failed);
  for (i=0;i<sizeof(bits);i++)
    mess += replace(bits[i], "$N", query_multiple_short(failed[bits[i]]));
  notify_fail(mess);
  return 0;
} /* wield() */

int unwield_weapon(object ob) {
  if (ob == weapon) {
    weapon = 0;
    return 1;
  }
  return 0;
} /* unwield_weapon() */

object query_weapon() { return weapon; }
void set_weapon(object weap) { weapon = weap; }

/*
 * Sets up protection matrixes.
 */
int do_protect(string str) {
  object *obs,
         *ok;
  int i;

  if (!str) {
    notify_fail("Syntax: protect <objects>\n");
    return 0;
  }
  obs = find_match(str, environment());
  if(sizeof(obs)) obs -= ({ this_player() });
  if (!sizeof(obs)) {
    notify_fail("Protect what?\n");
    return 0;
  }
  ok = ({ });
  for (i=0;i<sizeof(obs);i++)
    if (obs[i]->set_protector(this_object()))
      ok += ({ obs[i] });
  if (!sizeof(ok)) {
    notify_fail(query_multiple_short(obs)+
                (sizeof(obs)==1?" doesnt":" don't")+" want your protection.\n");
    return 0;
  }
  if (sizeof(obs) != sizeof(ok))
    write("You fail to protect "+query_multiple_short(obs - ok)+".\n");
  write("You protect "+query_multiple_short(ok)+".\n");
  say(this_object()->query_cap_name()+" protects "+query_multiple_short(ok)+
      ".\n", ok);
  for (i=0;i<sizeof(ok);i++)
    tell_object(ok[i], this_object()->query_cap_name()+" protects "+
                query_multiple_short(({ "you" }) + (ok - ok[i..i]))+".\n");
  return 1;
} /* do_protect() */

/* the below line is used by weapon_logic to see how much damage the
 * weapon does.  Is useed like this so that contition and other strange
 * things can be taken into account ;)
 */
int modify_damage(int i) { return i; }

mixed stats() {
  mixed fish;

  if(weapon)
    return ({ ({ "Weapon", weapon->short() }) }) +
      (mixed)weapon->weapon_stats();
  else
    return weapon_logic::stats();
} /* stats() */