// ----------------------------------------------------------------------------
#pragma strict_types
#define KILL_NEUTRAL_ALIGNMENT 10
#define ADJ_ALIGNMENT(al) ((-al - KILL_NEUTRAL_ALIGNMENT) / 4)
#define NAME_OF_GHOST "some mist"
#define WEAPON_CLASS_OF_HANDS 2
#define ARMOUR_CLASS_OF_BARE 0
#define DEBUG_COMBAT 0
#define BRAWL_IN_COMBAT 1
#if DEBUG_COMBAT
#define EV_COST "w/paldin/combat/ev_d"
#endif
#include <version.h>
#include <combat.h>
#include <daemons.h>
#include <defend.h>
#include <body_part.h>
#include <wizards.h>
#include <tune.h>
#include <regeneration.h>
#include <xfun.h>
// ----------------------------------------------------------------------------
inherit "lib/basic/hooks";
inherit "lib/living/defend_attack";
inherit "lib/living/skills";
inherit "lib/living/stats";
inherit "lib/living/claim";
// ----------------------------------------------------------------------------
void set_to_hit_bonus( int s );
void set_damage_bonus( int s );
void set_damage_modifier( int s );
void set_hit_modifier( int s );
varargs int query_to_hit_modifier(object weapon, int target, string dam_type);
int query_weapon_skill( object weapon );
varargs int query_to_hit_bonus(object weapon, int target, string dam_type);
varargs int query_damage_bonus(object weapon, int target, string dam_type);
int query_to_hit_armour( int target, string weap_type );
int query_to_damage_armour( int target, string weap_type );
varargs int query_to_damage_modifier(object weapon, int target,
string dam_type);
int average_ac( int target );
int query_resistance( int dam, string dam_type );
mapping query_hit_armour();
mapping query_dam_armour();
int query_primary_attack();
int query_penalty( object weapon );
int query_second_attack();
int set_attack_method( string s );
string query_attack_method();
mixed query_no_attack( mixed x );
object query_second_weapon();
mapping query_skill_pts();
void set_skill_pts( string cate, int val );
int query_can_hit( object weapon, int weap_sk, int hit_at, string dam_type,
int penalty, int whit );
int set_hit_messages( string *arr );
varargs int hit_player_damage( int dam, int target, string damage_type );
static void _award_kill_exp( mixed key, int dam, int total_dam );
varargs int hit_player( int dam, int target, string damage_type );
void attacked_by( object ob );
void stop_wielding( object ob );
int check_is_armour( object a );
void apply_armour( object a );
void apply_all_armour();
void wear_armour( object a );
void remove_armour( object a );
void wear_shield( object s );
void remove_shield( object s );
int attack();
int hit_with_weapon( object weapon, int penalty );
int set_defend( string str, int silent );
int fail_wield( object w, int where );
int fail_wear( object w );
void wield( object w );
void second_wield( object w );
void heal_self( int h );
void restore_spell_points( int h );
void reduce_spell_points( int i );
void restore_hit_points( int h );
void attack_object( object ob );
void set_attacker( object ob );
void set_hunted( object ob );
void zap_object( object ob );
void stop_hunter();
void run_away();
void stop_fight();
void set_attack_disabled( int active );
void set_wimpy_disabled( int active );
int reduce_hit_point( int dam );
int pay_spell_points( int arg );
void stop_any_hunt();
int calculate_power();
void set_detect_invisible( status arg );
status see_invisible();
int query_hit_point();
int query_wc();
int query_ac();
int query_head_ac();
int query_body_ac();
int query_arm_ac();
int query_leg_ac();
int query_block_ac();
object query_alt_hunter();
object query_alt_attack();
static void set_wimpy( int w );
int query_wimpy();
#ifdef VERSION_WIMPY_DIR
static void set_wimpy_direction( string direction );
string query_wimpy_direction();
#endif
object query_hunter();
object query_wielded_weapon();
int query_attack_disabled();
static void set_aim_at( int a );
int query_aim_at();
object query_worn_shield();
int query_dead();
object query_hunted();
object query_attack();
int query_parry_ac();
int query_weapon_class();
string query_killed_string();
string query_died_string();
void ks_handle_attack( object who, object attacker, int dam );
void ks_handle_death();
// ----------------------------------------------------------------------------
int query_debug();
string query_name();
string query_real_name();
string query_objective();
int query_body_position();
string query_head_str();
string query_body_str();
string query_arm_str();
string query_leg_str();
string query_hand_str();
string query_foot_str();
int query_level();
string query_real_race();
string query_class();
int query_npc();
int query_is_player();
int query_exp();
void set_exp( int i );
void add_exp( int exp );
int query_ability( string ab );
int query_alignment();
int query_local_weight();
int query_max_carry();
void stop_follow();
varargs void transfer_all_to( object corpse, int flag );
void save_me( int i );
object kill_claimer();
public varargs void message( string mess, object who, object target );
// ----------------------------------------------------------------------------
static string corpsefile; /* Custom corpse */
int whimpy; /* Automatically run when low on HP */
string whimpy_direction; /* Which way to run first when low on HP */
int dead; /* Are we alive or dead? */
static int attack_disabled; /* Disable autoattack - Greyson */
static int wimpy_disabled; /* Disable run_away - Greyson */
static int armour_class; /* What armour class of monster */
static object worn_shield; /* This is the shield we're wearing - Biko */
static object attacker_ob; /* Name of player attacking us */
static int weapon_class; /* How good weapon. Used to calculate damage */
static object head_armour; /* What armour we have */
static int hunting_time; /* How long we will stay in hunting mode */
static string *hit_messages; /* Hit messages */
static object hunted, hunter; /* Used in the hunt mode */
static object alt_hunter; /* Added 19-Nov-93 (Greyson) to stop cheaters */
static object wielded_weapon; /* The weapon we're wielding */
static object alt_attacker_ob; /* Name of other player also attacking us */
static int block_ac; /* How good the shield is at blocking */
static int parry_ac; /* How good your weapon is at parrying */
int aiming_at; /* Limb oriented combat */
static int hit_at; /* Limb oriented combat */
static int power;
static int dex_wc; /* How much a weapon needs you to be dexterous */
static int head_ac, body_ac, arm_ac, leg_ac; /* Limb oriented combat */
static status can_detect_invis; /* True when living detects invisible */
static int alt_hunting_time; /* see alt_hunter */
/* New Combat Variables */
static int weapon_skill,hit_bonus,damage_bonus, hit_modifier, damage_modifier;
static mapping hit_armour; /* Mapping of how hard to hit */
static mapping dam_armour; /* Mapping of how damage gets affected */
static object second_weapon; /* object for weapon in secondary hand */
string attack_method; /* How you are trying to attack */
private static int armour_applied; /* Has armour been applied to an npc */
/* To reduce CPU costs */
#if DEBUG_COMBAT
int cost;
#endif
/* Non static Variables */
mapping skill_pts; /* For how much skill you have */
/*
* The following routines are defined for usage:
* stop_fight Stop a fight.
* hit_player Called when fighting to damage us.
* attacked_by Tells us who is attacking us.
* stop_wielding Called when we unwield a weapon.
* stop_wearing Called when we remove armour.
* attack Should be called from heart_beat. Will maintain attack.
* query_attack Return who we are fighting.
* wield Called by weapons.
* wear Called by armour.
* attack_object Called when starting to attack an object.
* query_spell_points Return how much spell points the character has.
* reduce_hit_point Reduce hit points, but not below 0.
*/
// ----------------------------------------------------------------------------
/* For base combat effects.
hit_bonus - for making it easier/harder to hit
damage_bonus - for dealing more/less damage in a hit
damage_modifier - for changing the damage done to this object
hit_modified - for modifying chance to hit this object
*/
void set_to_hit_bonus( int s ) {
hit_bonus = s;
}
void set_damage_bonus( int s ) {
damage_bonus = s;
}
void set_damage_modifier( int s ) {
damage_modifier = s;
}
void set_hit_modifier( int s ) {
hit_modifier = s;
}
// Queries call hooks, for outside modification
varargs int query_to_hit_modifier(object weapon, int target, string dam_type) {
int ret;
ret = hit_modifier;
if ( attack_defend == (int)BERSERK )
#ifdef VERSION_INCREASED_MORTAL_LEVEL
ret -= random( 3 + ((int)query_level()>MORTAL_MAXIMUM?MORTAL_MAXIMUM:(int)query_level()) / 2 );
#else
ret -= random( 3 + (int)query_level() / 2 );
#endif
ret += hook( "hit_modifier", ({ hit_modifier, weapon, target, dam_type }) );
return ret;
}
int query_weapon_skill( object weapon ) {
string abi;
int ret;
if ( objectp( weapon ) ) {
abi = (string)weapon->query_weapon_type();
} else {
abi = "Unarmed";
}
ret = query_skill( abi );
return ret;
}
varargs int query_to_hit_bonus(object weapon, int target, string dam_type) {
int ret;
ret = hit_bonus;
ret += hook( "hit_bonus", ({ hit_bonus, weapon, target, dam_type }) );
return ret;
}
varargs int query_damage_bonus(object weapon, int target, string dam_type) {
int ret;
ret = damage_bonus;
ret += hook( "damage_bonus", ({ damage_bonus, weapon, target, dam_type }) );
return ret;
}
int query_to_hit_armour( int target, string weap_type ) {
// set armour on npcs now that it's needed
if ( !armour_applied && query_npc() )
apply_all_armour();
if ( !hit_armour )
return 0;
--target;
if ( target < 0 || target > 3 )
return 0;
if ( hit_armour[weap_type] )
return hit_armour[weap_type][target];
return 0;
}
int query_to_damage_armour( int target, string weap_type ) {
if ( !armour_applied && query_npc() )
apply_all_armour();
if ( !dam_armour )
return 0;
--target;
if ( target < 0 || target > 3 )
return 0;
if ( dam_armour[weap_type] )
return dam_armour[weap_type][target];
return 0;
}
varargs int query_to_damage_modifier(object weapon, int target,
string dam_type) {
int ret;
ret = damage_modifier;
ret += hook( "damage_modifier",
({ damage_modifier, weapon, target, dam_type }) );
return ret;
}
int average_ac( int target ) {
int av_ac, i, ac_i;
int tot_ac_pos;
string *indx;
av_ac = 0;
if ( !dam_armour )
apply_all_armour();
indx = m_indices( dam_armour );
if ( sizeof( indx ) ) {
for( i = 0 ; i < sizeof( indx ) ; ++i ) {
if ( (ac_i = query_to_damage_armour( target + 1, indx[i] )) != -1 ) {
++tot_ac_pos;
av_ac += ac_i;
}
}
if ( !tot_ac_pos )
tot_ac_pos = 1;
av_ac = av_ac / tot_ac_pos;
}
return av_ac;
}
int query_resistance( int dam, string dam_type ) {
string d_type;
int amt;
d_type = dam_type;
if ( d_type == "saving" )
d_type = "magic";
if ( d_type == "physical" )
return (dam - random( average_ac( 1 ) ) / 2);
amt = query_ability( d_type +" resistance" );
if ( random( 100 ) < amt ) {
if ( d_type == "magic" )
return 0;
dam -= random( dam );
}
return dam;
}
mapping query_hit_armour() {
return hit_armour ? hit_armour : ([]);
}
mapping query_dam_armour() {
return dam_armour ? dam_armour : ([]);
}
int query_primary_attack() {
int ret;
ret = 1 + hook( "primary_attack", ({}) );
return ret;
}
int query_penalty( object weapon ) {
int pen;
pen = 3 * (int)this_object()->query_intoxination() /
MAX_OB_INTOX( this_object() );
if ( second_weapon && weapon ) {
pen += 2;
pen -= query_skill( "Two Weapon" )/6;
pen -= query_weapon_skill( weapon ) / 10;
pen += 7 * (int)weapon->query_weight();
pen += (2 * (int)weapon->query_difficulty()) / 4;
/* Old Calc for penalty
pen += 2;
pen -= query_skill( "two weapon" ) / 8;
pen -= query_weapon_skill( weapon ) / 13;
pen += 5 * (int)weapon->query_weight();
pen += (3 * (int)weapon->query_difficulty()) / 4;
*/
if ( weapon == wielded_weapon )
pen /= 2;
if ( pen < 0 )
pen = 0;
return pen;
}
return pen;
}
int query_second_attack() {
int ret;
int t_skill;
t_skill = 5 + query_skill( "Two Weapon" ) / 2;
if ( BERSERK == attack_defend )
t_skill += ((int)query_level()>WIZ_ALLOWABLE?WIZ_ALLOWABLE:(int)query_level());
if ( random( 100 ) < t_skill )
ret = 1;
ret += hook( "second_attack", ({ ret }) );
// Old method
// ret = 1 + hook( "second_attack", ({}) );
return ret;
}
int set_attack_method( string s ) {
if ( member_array( s, ATTACKS ) != -1 ) {
if ( s == "none" || s == "random" ) // 'random' option Added Jul 07 by Howitzer
s = "random";
attack_method = s;
write( "You change your attack method to "+ s +".\n" );
return 1;
}
notify_fail( "You do not think you can do that.\n" );
return 0;
}
string query_attack_method() {
return attack_method ? attack_method : "random";
}
mixed query_no_attack( mixed x ) {
mixed ret;
ret = x;
ret += hook( "no_attack", ({ x }) );
return ret;
}
object query_second_weapon() {
return second_weapon;
}
mapping query_skill_pts() {
return skill_pts;
}
void set_skill_pts( string cate, int val ) {
if ( !skill_pts )
skill_pts = ([]);
skill_pts[cate] = val;
if ( val )
set_skill( cate, SKILL_D->calc_skill( this_object(), cate, val ) );
else
remove_skill( cate );
}
int query_can_hit( object weapon, int weap_sk, int hit_at, string dam_type,
int penalty, int whit ) {
int to_hit;
if ( weapon ) {
to_hit = random( 3 * tmp_Dex ) +
(int)weapon->query_to_hit_bonus(hit_at, dam_type) +
3 * ((whit + 1) / 2) +
random( weap_sk / 3 + 5 + weap_sk * weap_sk / 75 ) +
query_to_hit_bonus(weapon, hit_at, dam_type) -
(random( (int)attacker_ob->query_dex() )) -
(int)attacker_ob->query_to_hit_modifier(weapon, hit_at, dam_type) -
random((int)attacker_ob->query_to_hit_armour(hit_at, dam_type)) -
5 * (random( (int)weapon->query_weight() - 1 )) -
(30 * random((int)weapon->query_difficulty())) / 10 - 2 * penalty;
} else {
to_hit = random( 3 * tmp_Dex + weap_sk / 2 ) +
(int)query_to_hit_bonus(0, hit_at, dam_type) -
random( (int)attacker_ob->query_dex() ) -
(int)attacker_ob->query_to_hit_modifier(0, hit_at, dam_type) -
random((int)attacker_ob->query_to_hit_armour(hit_at, dam_type)) +
3 * ((whit + 1) / 2);
}
return to_hit;
}
// End combat queries
// ----------------------------------------------------------------------------
int set_hit_messages( string *arr ) {
if ( arr && sizeof( arr ) != 14 )
return 0;
hit_messages = arr;
return 1;
}
/*
* This function is called from other players when they want to damage us.
* We return how much damage we received, which will change the attacker's
* score. This routine is probably called from heart_beat() from another
* player. Compare this function to reduce_hit_point(dam).
*/
varargs int hit_player_damage(int dam,int target,string damage_type) {
object corpse;
object temp_attack;
mixed dam_key;
object cur_claimer;
int tmp;
if ( !attacker_ob )
set_heart_beat( 1 );
if ( !attacker_ob && this_player() != this_object() ) {
attacker_ob = this_player();
this_object()->start_fight();
}
/* removed 6Jul94 by Dawg, hoping to fix 'friendly fire' bug
else if(!alt_attacker_ob && attacker_ob != this_player() &&
this_player() != this_object()) alt_attacker_ob = this_player();
*/
if ( this_object()->query_is_statue() ) {
if ( this_player() != this_object() ) // not self-inflicted
write( "Time has petrified "+ query_objective() +".\n" );
stop_fight();
this_player()->stop_fight();
return 0;
}
/* Added at Wrath's request on 8-16-95 by Leoz. You can now stop people from
dying. */
if ( dead )
return 0;
if ( !target )
target = BODY;
/* ***********************************
if(target == HEAD) ac = head_ac;
else if(target==BODY) ac = body_ac;
else if(target==ARM ) ac = arm_ac;
else if(target==LEG ) ac = leg_ac;
else log_file("BAD_HIT", this_player()->query_name()+ "\n");
if(attack_defend == BERSERK) ac -= (4 + query_level() / 2 - level / 4);
if((dam -= random(((ac < 0)?0:ac) / 2)) < 0) return 0;
************************************ */
if ( !damage_type )
damage_type = "crush";
// For each 3 con above level npcs gain 2AC (-1 damage) to physical hits.
// +1 in random so even a 1 change can get to random(4)/3 so a chance of +/-1
if (query_npc() && (tmp = query_con() - query_level())) {
if (tmp > 0) // bonus con reduces damage
dam -= random(2 * (tmp+1))/3;
else // low con increases damage
dam += random(2 * (-1 * tmp + 1))/3;
}
dam = query_resistance( dam, damage_type );
dam += hook( "hit_player", ({ dam, target, damage_type, previous_object() }) );
if ( dam >= hit_point && environment() && (temp_attack = attacker_ob) &&
environment()->stop_death( this_object(), attacker_ob ) ) {
catch( log_file( "STOP_DEATH",
get_f_string( ctime() +" : "+ this_object()->query_name() +
" saved from "+ temp_attack->query_name() +" in "+
file_name( environment() ) +".", 0, 20 ) ) );
return 0;
}
if ( query_level() >= APPRENTICE && !query_npc() && dam >= hit_point ) {
tell_object( this_object(), "Your wizardhood protects you from death.\n" );
return 0;
}
ks_handle_attack(this_player(),attacker_ob, dam);
if ( dam <= 0 )
return 0;
if ( dam > hit_point + 1 )
dam = hit_point + 1;
hook("hit_player_damage_taken", ({ dam, target, damage_type, previous_object() }));
if ( this_player() && this_player() != this_object() ) {
int dam_factor;
dam_factor = 100;
if ( this_player()->query_is_player() ) {
dam_key = (string)this_player()->query_real_name();
} else if (dam_key = (string)this_player()->query_xp_conduit() ) {
dam_factor = (int)this_player()->query_xp_conduit_factor();
} else {
dam_key = this_player();
}
add_m_damagers(dam_key, (dam * dam_factor) / 100);
if ( query_m_damagers(dam_key) <= 0 )
del_m_damagers(dam_key);
}
if ( (hit_point -= dam) > query_max_hp() )
hit_point = query_max_hp();
if (hit_point >=0) {
if ( !query_npc() ) // else if ( reporting ) - changed by Greyson
this_object()->report_hp_sp();
return dam;
}
// FROM HERE ON HP < 0, so NPC should be dying.
if ( !query_npc() && !query_ip_number( this_object() ) ) {
write( query_name() +" is not here. You cannot kill a player who is "
"not logged in.\n" );
hit_point = 20;
stop_fight();
this_player()->stop_fight();
return 0;
}
stop_follow();
if ( hunter )
hunter->stop_hunter();
if ( alt_hunter )
alt_hunter->stop_hunter();
hunter = alt_hunter = hunted = 0;
/* Added 10-Jul-94 by Ricochet */
/* this prevents a monster from a plain kill by calling hit_player()
some monster have a coded "suicide" by hit_player(xyz) like greysons
there is no attack_ob in that case.. putting in another if...
03.08.94 Saerdan
*/
if ( attacker_ob ) {
if ( attacker_ob->query_npc() && attacker_ob->query_killer_ob() ) {
if ( attacker_ob->monster_killer( this_object() ) ) {
// place a log file here if desired
hit_point = 10;
attacker_ob->attack_object( 0 );
attacker_ob = 0;
return 1;
}
}
}
dead = 1;
say( query_name() +" "+ (string)this_object()->query_died_string() +".\n");
if ( !query_npc() ) {
"secure/tool"->adm_log( "DIED", query_real_name() +" -> "+
(query_exp() / 3 ) +"["+
((environment()) ? file_name( environment() ) : "???") +"]" );
} else {
"adm/tools/watch"->monster_died( this_object(), attacker_ob );
ks_handle_death();
}
// Cap XP Loss to 10 mill.
// If it comes from Villa, they are leaving rogue class so lose 1/3
if ((int)this_object()->query_npc() ||
extract(file_name(previous_object()),0,25) == "w/greyson/rogue/npc/villa")
this_object()->add_exp( -1 * (int)this_object()->query_exp() / 3 );
else
// sub 20M/pi * atan(exp*pi/60M)
this_object()->add_exp(-1 * (((int)((20000000/3.1415926) * atan((float)((int)this_object()->query_exp()*3.1415926/60000000)))) +
hook("death_xp_loss",
({ ((int)((20000000/3.1415926) * atan((float)((int)this_object()->query_exp()*3.1415926/60000000))))}))) );
hit_point = 10;
if ( attacker_ob && attacker_ob->query_party_name() )
attacker_ob->share_align( ADJ_ALIGNMENT( query_alignment() ) );
// In claim.c
award_exp();
if ( attacker_ob ) {
if ( attacker_ob->query_party_name() ) {
//Mordecai Oct09: Added call to query_killed_string() in this object,
// to allow a monster to specify a string other than "killed", such
// as "defeated".
attacker_ob->party_killed( query_name(), query_killed_string() );
} else {
attacker_ob->add_alignment( ADJ_ALIGNMENT( query_alignment() ) +
(int)attacker_ob->hook("align_bonus", ({ADJ_ALIGNMENT( query_alignment() )})));
tell_object( attacker_ob, "You "+ (string)query_killed_string() +" "+
query_name() +".\n" );
}
say( attacker_ob->query_name() +" "+ (string)query_killed_string() +" "+
query_name() +".\n", attacker_ob );
}
// Who has done the most damage
cur_claimer = kill_claimer();
// If we dont have the highest damager present etc, then set to attacker
if (!cur_claimer) cur_claimer = attacker_ob;
clear_m_damagers();
/* Some undeads vanish when killed - Trixx */
if ( this_object()->query_vanish() ) {
string vanish_msg;
vanish_msg = (string)this_object()->query_vanish_msg();
if ( vanish_msg ) {
if ( ('#' == vanish_msg[0]) && ('#' == vanish_msg[1]) )
call_other( this_object(), vanish_msg[2..] );
else
tell_room( environment(), get_f_string( vanish_msg ) );
}
transfer_all_to(environment());
} else {
if ( corpsefile ) {
corpse = clone_object( corpsefile );
} else {
corpse = clone_object( "obj/corpse" );
if ( !interactive( this_object() ) )
corpse->set_name( query_name() );
else
corpse->set_name( query_real_name() );
corpse->set_str( Str );
corpse->set_int( Int );
corpse->set_con( Con );
corpse->set_dex( Dex );
corpse->set_wis( Wis );
corpse->set_race( query_real_race() );
if((int)this_object()->query_undead())
corpse->set_undead( 1 );
else
corpse->set_undead( 0 );
corpse->set_level( query_level() );
corpse->set_alignment( query_alignment() );
corpse->set_head_str( query_head_str() );
corpse->set_body_str( query_body_str() );
corpse->set_leg_str( query_leg_str() );
corpse->set_arm_str( query_arm_str() );
corpse->set_hand_str( query_hand_str() );
corpse->set_foot_str( query_foot_str() );
corpse->set_exp( query_exp() );
corpse->set_wc( query_wc() );
corpse->set_max_hp( query_max_hp() );
if ((mixed)this_object()->query_spells()) {
corpse->set_spell_damage((mixed)this_object()->query_spells());
}
}
if(corpse) {
transfer_all_to( corpse, 0 );
//Note: Move the corpse before setting claim (init in the corpse will
//reset the claim flag when it comes into contact with the claimer).
corpse->move( environment() );
if (corpse && cur_claimer)
corpse->claimed_by(cur_claimer);
} else {
//Note: Some NPCs use destructing corpses. Let's log it but otherwise
//end peaceably.
log_file("COMBAT", sprintf("Bad corpse file: %s in %s\n",
corpsefile ? corpsefile : "0",
file_name()));
transfer_all_to(environment()); // Behave like with vanish. Fir
}
}
if (cur_claimer && cur_claimer->query_is_player()) {
cur_claimer->set_misc( "kills",
(int)cur_claimer->query_misc( "kills" ) + 1 );
}
if ( cur_claimer ) {
object ok;
// call all versions of owner_killer rather than just the first
map_array(presents("\nowner_killer",cur_claimer),
lambda(({'x}), ({#'call_other, 'x, "owner_killer", this_object() }) )); //'
// if ( ok = present( "\nowner_killer", attacker_ob ) )
// ok->owner_killer( this_object() );
}
if ( !this_object()->second_life() )
destruct( this_object() );
if ( !query_npc() ) {
SKILL_D->reduce_skill( this_object() );
save_me( 0 );
}
return dam;
}
static void _award_kill_exp( mixed key, int dam, int total_dam ) {
if ( query_debug() ) {
log_file( "NEW_EXP", "_award_kill_exp(" + XFUN->variable_to_string( key ) +
", "+ XFUN->variable_to_string( dam ) +", "+
XFUN->variable_to_string( total_dam ) +") in "+ file_name() +" ("+
query_exp() +")\n" );
}
if ( key && (objectp(key) || (stringp(key) && (key = find_player(key)))) ) {
if ( dam > 0 ) {
int exp_share;
// Darn integer overflow with high exp & npcs with high hps.
// Theryn, 4 Nov 2006.
if ( WIZ_ALLOWABLE <= (int)this_object()->query_level() ) {
exp_share = (int)query_exp() / total_dam * dam / XP_FACTOR;
} else {
exp_share = (int)query_exp() * dam;
if ( exp_share < 0 )
exp_share = 0x7FFFFFFF;
exp_share = (exp_share / total_dam) / XP_FACTOR;
}
// to prevent a net gain of xp when players kill each other
if(this_object()->query_is_player())
exp_share = 0;
// Share xp with party, but only if they are part of the party xp share
if ( key->query_party_name() && key->query_party_sharing_xp())
key->share_exp( exp_share );
else
key->add_exp( exp_share );
if ( (1000 < exp_share) && (query_debug() || LOG_D->query_log_exp()) ) {
log_file( "NEW_EXP", ctime()[4..15] +" "+
(string)key->query_real_name() +" "+ exp_share +" for "+
(string)this_object()->query_real_name() +" ["+
dam +"/"+ total_dam +" of "+ query_exp() +"]\n" );
}
}
}
}
varargs int hit_player( int dam, int target, string damage_type ) {
int new_dam;
new_dam = dam - random( average_ac( target ) );
return hit_player_damage( new_dam, target, damage_type );
}
/*
* This routine is called when we are attacked by someone.
*/
void attacked_by(object ob) {
#if 1
if ( attacker_ob ) {
if ( ob && (ob != attacker_ob) ) {
string the_party;
// Obsolete logging ... removed by Adinos - July 2001
//
// if ( (interactive( ob )) && (interactive( attacker_ob )) &&
// (environment( attacker_ob ) == environment()) &&
// ((!(the_party = (string)attacker_ob->query_party_name())) ||
// (the_party != (string)ob->query_party_name())) ) {
// log_file( "KILL_STEALS", ctime()[4..15] +" "+
// (string)ob->query_real_name() +" stole "+
// (string)this_object()->query_name() +" from "+
// (string)attacker_ob->query_real_name() +"\n" );
// }
if ( !alt_attacker_ob )
alt_attacker_ob = ob;
}
} else {
attacker_ob = ob;
set_heart_beat( 1 );
}
#else
if ( !attacker_ob ) {
attacker_ob = ob;
set_heart_beat( 1 );
return;
}
if ( attacker_ob == ob )
return; /* added by Dawg 6Jul94 */
if ( !alt_attacker_ob )
alt_attacker_ob = ob;
#endif
}
void stop_wielding( object ob ) {
#if BRAWL_IN_COMBAT
object brawl;
#endif
if ( !wielded_weapon && !second_weapon )
return;
if ( ob && ob != wielded_weapon && ob!= second_weapon )
return;
if ( !ob ) {
if ( wielded_weapon )
wielded_weapon->un_wield( dead );
wielded_weapon = 0;
return;
}
if ( ob == wielded_weapon ) {
wielded_weapon->un_wield( dead );
wielded_weapon = parry_ac = dex_wc = hit_messages = 0;
#if BRAWL_IN_COMBAT
brawl = present("\nbrawl_skill",this_object());
if (brawl)
hit_messages = (string *)brawl->query_hit_messages();
#endif
if ( query_is_player() )
weapon_class = WEAPON_CLASS_OF_HANDS;
} else {
second_weapon->un_wield( dead );
second_weapon = 0;
}
// calculate_power();
}
int check_is_armour( object a ) {
return a->query_worn() ? 1 : 0;
}
/* Apply the armour values to the object */
void apply_armour( object a ) {
int i, j;
string *idx;
mapping a_hit_arm, a_dam_arm;
a_hit_arm = (mapping)a->query_to_hit_armour();
if ( !a_hit_arm || !mappingp( a_hit_arm ) )
return 0;
a_dam_arm = (mapping)a->query_to_damage_armour();
if ( !a_dam_arm || !mappingp( a_dam_arm ) )
return 0;
if ( !hit_armour )
hit_armour = ([]);
idx = m_indices( a_hit_arm );
for ( i = 0 ; i < sizeof( idx ) ; ++i ) {
for ( j = 0 ; j < sizeof( a_hit_arm[idx[i]] ) ; j += 2 ) {
if ( hit_armour[idx[i]] ) {
hit_armour[idx[i]][j / 2] += (int)a_hit_arm[idx[i]][j];
hit_armour[idx[i]][j / 2] += (int)a_hit_arm[idx[i]][j + 1];
} else {
hit_armour[idx[i]] = ({ 0, 0, 0, 0 });
hit_armour[idx[i]][j / 2] += (int)a_hit_arm[idx[i]][j];
hit_armour[idx[i]][j / 2] += (int)a_hit_arm[idx[i]][j + 1];
}
}
}
if ( !dam_armour )
dam_armour = ([]);
idx = m_indices( a_dam_arm );
for ( i = 0 ; i < sizeof( idx ) ; ++i ) {
for ( j = 0 ; j < sizeof( a_dam_arm[idx[i]] ) ; j += 2 ) {
if ( dam_armour[idx[i]] ) {
dam_armour[idx[i]][j / 2] += a_dam_arm[idx[i]][j];
dam_armour[idx[i]][j / 2] += a_dam_arm[idx[i]][j + 1];
} else {
dam_armour[idx[i]] = ({ 0, 0, 0, 0 });
dam_armour[idx[i]][j / 2] += a_dam_arm[idx[i]][j];
dam_armour[idx[i]][j / 2] += a_dam_arm[idx[i]][j + 1];
}
}
}
}
/* Apply all the armour to the object as well as base effects from
set_<x>_ac()'s */
void apply_all_armour() {
object *arm;
string dam_type;
int i;
arm = filter_array( all_inventory( this_object() ), "check_is_armour",
this_object() );
if ( !hit_armour )
hit_armour = ([]);
if ( !dam_armour )
dam_armour = ([]);
for ( i = 0 ; i < sizeof( DAMAGE_TYPES ) ; ++i ) {
dam_type = DAMAGE_TYPES[i];
if ( !hit_armour[dam_type] )
hit_armour[dam_type] = ({ 0, 0, 0, 0 });
if ( !dam_armour[dam_type] )
dam_armour[dam_type] = ({ 0, 0, 0, 0 });
hit_armour[dam_type][0] = head_ac;
dam_armour[dam_type][0] = head_ac;
hit_armour[dam_type][1] = body_ac;
dam_armour[dam_type][1] = body_ac;
hit_armour[dam_type][2] = arm_ac;
dam_armour[dam_type][2] = arm_ac;
hit_armour[dam_type][3] = leg_ac;
dam_armour[dam_type][3] = leg_ac;
}
for ( i = 0 ; i < sizeof( arm ) ; ++i ) {
apply_armour( arm[i] );
}
armour_applied = 1;
}
void wear_armour( object a ) {
/* Old Backward Compatibility code removed to use less CPU
head_ac += ((int)a->query_head_ac() + (int)a->query_neck_ac());
body_ac += (a->query_lbody_ac() + a->query_hbody_ac());
leg_ac += (a->query_leg_ac() + a->query_foot_ac());
arm_ac += (a->query_arm_ac() + a->query_hand_ac());
head_ac += (int)a->query_special_head_ac();
body_ac += (int)a->query_special_body_ac();
leg_ac += (int)a->query_special_leg_ac();
arm_ac += (int)a->query_special_arm_ac();
*/
/* Ok only apply armour if it's a player. Otherwise use apply_armour()
to get an immediate effect. */
if ( !query_npc() || armour_applied ) {
apply_armour( a );
}
}
void remove_armour( object a ) {
int i, j;
string *idx;
mapping a_hit_arm, a_dam_arm;
/* Old remove coded commented out to save some CPU
head_ac -= (a->query_head_ac() + a->query_neck_ac());
body_ac -= (a->query_lbody_ac() + a->query_hbody_ac());
leg_ac -= (a->query_leg_ac() + a->query_foot_ac());
arm_ac -= (a->query_arm_ac() + a->query_hand_ac());
head_ac -= (int)a->query_special_head_ac();
body_ac -= (int)a->query_special_body_ac();
leg_ac -= (int)a->query_special_leg_ac();
arm_ac -= (int)a->query_special_arm_ac();
*/
if ( !armour_applied && query_npc() )
apply_all_armour();
if ( !hit_armour )
hit_armour = ([]);
a_hit_arm = (mapping)a->query_to_hit_armour();
if ( a_hit_arm && mappingp( a_hit_arm ) ) {
idx = m_indices( a_hit_arm );
for ( i = 0 ; i < sizeof( idx ) ; ++i ) {
for ( j = 0 ; j < sizeof( a_hit_arm[idx[i]] ) ; j += 2 ) {
if ( hit_armour[idx[i]] ) {
hit_armour[idx[i]][j / 2] -= a_hit_arm[idx[i]][j];
hit_armour[idx[i]][j / 2] -= a_hit_arm[idx[i]][j + 1];
} else {
hit_armour[idx[i]] = ({ 0, 0, 0, 0 });
hit_armour[idx[i]][j / 2] -= a_hit_arm[idx[i]][j];
hit_armour[idx[i]][j / 2] -= a_hit_arm[idx[i]][j + 1];
}
}
}
}
if ( !dam_armour )
dam_armour = ([]);
a_dam_arm = (mapping)a->query_to_damage_armour();
if ( a_dam_arm && mappingp( a_dam_arm ) ) {
idx = m_indices( a_dam_arm );
for ( i = 0 ; i < sizeof( idx ) ; ++i ) {
for ( j = 0 ; j < sizeof( a_dam_arm[idx[i]] ) ; j += 2 ) {
if ( dam_armour[idx[i]] ) {
dam_armour[idx[i]][j / 2] -= a_dam_arm[idx[i]][j];
dam_armour[idx[i]][j / 2] -= a_dam_arm[idx[i]][j + 1];
} else {
dam_armour[idx[i]] = ({ 0, 0, 0, 0 });
dam_armour[idx[i]][j / 2] -= a_dam_arm[idx[i]][j];
dam_armour[idx[i]][j / 2] -= a_dam_arm[idx[i]][j + 1];
}
}
}
}
}
void wear_shield( object s ) {
block_ac = (int)s->query_block_ac();
worn_shield = s;
}
void remove_shield( object s ) {
block_ac = worn_shield = 0;
}
/*
* Return true if there still is a fight.
*/
int attack() {
int tmp, penalty, i;
string name_of_attacker;
if ( attacker_ob == this_object() ) // added by Greyson, 13-Feb-95
attacker_ob = 0;
if ( !attacker_ob ) {
if ( !alt_attacker_ob )
return 0;
attacker_ob = alt_attacker_ob;
alt_attacker_ob = 0; /* added by Dawg 6Jul94 */
}
#if DEBUG_COMBAT
cost = get_eval_cost();
#endif
name_of_attacker = (string)attacker_ob->query_name();
if ( !name_of_attacker || name_of_attacker == NAME_OF_GHOST ||
environment( attacker_ob ) != environment() ) {
if ( !hunter && name_of_attacker && !attacker_ob->query_ghost() ) {
set_hunted( attacker_ob );
tell_object( this_object(), "You are now hunting "+ name_of_attacker +
".\n" );
}
attacker_ob = 0;
if ( !alt_attacker_ob )
return 0;
attacker_ob = alt_attacker_ob;
alt_attacker_ob = 0;
if ( attack() ) {
if ( attacker_ob ) {
tell_object( this_object(), "You turn to attack "+
attacker_ob->query_name() +".\n" );
}
return 1;
}
return 0;
}
if ( query_no_attack( attack_disabled ) )
return 1;
#if DEBUG_COMBAT
EV_COST->cost1( cost - get_eval_cost() );
#endif
tmp = query_primary_attack();
penalty = query_penalty( wielded_weapon );
for ( i = 0 ; i < tmp ; ++i ) {
hit_with_weapon( wielded_weapon, penalty );
}
if ( second_weapon ) {
tmp = query_second_attack();
penalty = query_penalty( second_weapon );
for ( i = 0 ; i < tmp ; ++i ) {
hit_with_weapon( second_weapon, penalty );
}
}
#if DEBUG_COMBAT
EV_COST->cost10( cost - get_eval_cost() );
#endif
}
/* Called for each attack with that weapon */
int hit_with_weapon(object weapon, int penalty) {
int tmp;
mixed whit;
string name_of_attacker, dam_type;
mapping weap_type;
int to_hit,i,chce,weap_sk,tmp_int; /* tmp_int will be a reused variable */
string *idx1;
int str_dam,weap_dam,armour_dam;
if ( !attacker_ob )
return 1; /* Must have died on an earlier hit */
name_of_attacker = (string)attacker_ob->query_name();
// Added by Paldin for unarmed attack types
weap_type = hook("unarmed_attack_type");
if ( weapon ) {
whit = (int)weapon->hit( attacker_ob );
weap_type = (mapping)weapon->query_damage_type();
if ( !attacker_ob ) {
/* allow for weapon_hits to do damage
tell_object( this_object(), "CRACK!\nYour weapon broke!\n" );
log_file( "BAD_WEAPON", weapon->short() +", "+ getuid( weapon ) +
" XX!\n" );
destruct( wielded_weapon );
weapon_class = parry_ac = dex_wc = hit_messages = 0;
calculate_power();
*/
return 1;
}
}
#if DEBUG_COMBAT
EV_COST->cost2( cost - get_eval_cost() );
#endif
if ( !mappingp( weap_type ) ) {
/* Unknown weapon or barehanded */
weap_type = ([ "crush" : 100 ]);
}
weap_sk = query_weapon_skill( weapon );
if ( (weap_sk - 20) > random( 100 ) && weap_type[attack_method] ) {
dam_type = attack_method;
} else {
/* attack style is random */
idx1 = m_indices( weap_type );
chce = 0;
tmp_int = random( 100 );
for ( i = sizeof( idx1 ) ; i-- && !dam_type ; ) {
chce += weap_type[idx1[i]];
if ( tmp_int < chce ) {
dam_type = idx1[i];
}
}
}
#if DEBUG_COMBAT
EV_COST->cost3( cost - get_eval_cost() );
#endif
if ( whit != "miss" ) {
if ( aiming_at == RANDOM ) {
hit_at = random( 4 ) + 1;
} else {
if ( random( tmp_Dex ) > 3 )
hit_at = aiming_at;
else
hit_at = (1 + random( 4 ));
}
hit_at += hook("aim_modifier", ({ hit_at }));
if ( (hit_at == (int)HEAD &&
(int)attacker_ob->query_to_hit_armour( HEAD, "crush" ) == -1) ||
(hit_at == (int)ARM &&
(int)attacker_ob->query_to_hit_armour( ARM, "crush" ) == -1) ||
(hit_at == (int)LEG &&
(int)attacker_ob->query_to_hit_armour( LEG, "crush" ) == -1) ) {
if ( aiming_at == hit_at ) {
tell_object( this_object(), attacker_ob->query_name() +
" does not have the body part you were aiming at.\n" );
tell_object( this_object(), "Aiming at: "+
attacker_ob->query_body_str() +"\n" );
aiming_at = BODY;
}
hit_at = BODY;
}
#if DEBUG_COMBAT
EV_COST->cost4( cost - get_eval_cost() );
#endif
to_hit = query_can_hit( weapon, weap_sk, hit_at, dam_type, penalty, whit );
#if DEBUG_COMBAT
EV_COST->cost5( cost - get_eval_cost() );
#endif
tmp_int = (int)query_body_position();
to_hit -= tmp_int * 2;
i = (int)attacker_ob->query_body_position(); /* Ok Overloading var i */
to_hit += i * 2;
if ( to_hit > 0 )
to_hit = (int)attacker_ob->defend_attack( to_hit, hit_at );
else
to_hit = 0;
#if DEBUG_COMBAT
EV_COST->cost6( cost - get_eval_cost() );
#endif
if ( to_hit != 0 ) {
str_dam = random( tmp_Str ) / 2;
if ( weapon ) {
weap_dam = (int)weapon->query_damage( dam_type );
if ( !(int)query_is_player() )
weap_dam /= 2;
armour_dam = 2 *
random((int)attacker_ob->query_to_damage_armour(hit_at, dam_type))/3;
tmp = str_dam +
weap_dam +
(whit / 2) +
random( (int)query_weapon_class() ) +
(int)query_damage_bonus(weapon, hit_at, dam_type) -
armour_dam -
(int)attacker_ob->query_to_damage_modifier(weapon, hit_at, dam_type) -
penalty / 2;
} else {
tmp = random( tmp_Str ) / 2 +
random( (int)query_weapon_class() + 1 ) +
(int)query_damage_bonus(0, hit_at, dam_type) -
random(1*(int)attacker_ob->query_to_damage_armour(hit_at,dam_type)/2) -
(int)attacker_ob->query_to_damage_modifier(0, hit_at, dam_type) +
(whit / 2) -
penalty / 2;
}
#if DEBUG_COMBAT
EV_COST->cost7( cost - get_eval_cost() );
#endif
/* Bonus to damage only from berserk .. for now? */
/* Extra berserk damage if weapon is primary weapon */
if ( attack_defend == BERSERK && weapon==wielded_weapon)
#ifdef VERSION_INCREASED_MORTAL_LEVEL
tmp += random( (1 + ((int)query_level()>WIZ_ALLOWABLE?WIZ_ALLOWABLE:(int)query_level()) / 2 + tmp_Str / 5) );
#else
tmp += random( (1 + (int)query_level() / 2 + tmp_Str / 5) );
#endif
tmp -= tmp_int * 2; /* Body_position */
tmp += i * 2;
if ( tmp < 0 )
tmp = 0;
if ( tmp != 0 ) {
// Need magical weapons on undeads - Trixx
if ( attacker_ob->query_undead() ) {
if ( weapon &&
weapon->query_magical_weapon() ) {
tmp = tmp * 115 / 100;
} else {
tmp = tmp * 85 / 100;
}
}
#if DEBUG_COMBAT
tell_room( environment(), "Damage before defend: "+ tmp +" To hit: "+
to_hit +"\n" );
#endif
// Added by Elfling to support changed defend_attack routine 6/9/98
if ( to_hit != 1 ) // Modifying for partial/bad defending.
tmp = tmp * (100 + to_hit) / 100;
#if DEBUG_COMBAT
tell_room( environment(), "Damage after defend: "+ tmp +"\n" );
#endif
tmp = (int)attacker_ob->hit_player_damage( 3*tmp/4, hit_at, dam_type );
}
}
#if DEBUG_COMBAT
EV_COST->cost8( cost - get_eval_cost() );
#endif
hook( "damage_dealt", ({ tmp, weapon }) );
if ( dead )
return 0; // no need to continue if we died in defend_attack()
} else {
tmp = 0;
}
/*
if ( !query_npc() && weapon && tmp > 20 &&
random( 100 ) < weapon_class - (int)query_level() * 2 / 3 - 14 ) {
tell_object( this_object(), "CRACK!\nYour weapon broke!\n" );
tell_object( this_object(),
"You are too inexperienced for such a weapon.\n" );
log_file( "BAD_WEAPON", weapon->short() +", "+ getuid( weapon ) +"\n" );
destruct( weapon );
weapon_class = parry_ac = dex_wc = hit_messages = 0;
weapon_class = WEAPON_CLASS_OF_HANDS;
// calculate_power();
return 1;
}
*/
if ( tmp == 0 ) {
tell_object( this_object(), "You missed.\n" );
if ( attacker_ob ) {
say( query_name() +" missed "+ name_of_attacker +".\n", attacker_ob );
tell_object( attacker_ob, query_name() +" missed you.\n" );
// This check is in case we have a monster continually missing.
// So that we turn to attack it.
if ( !attacker_ob->query_attack() )
attacker_ob->attacked_by( this_object() );
} else {
say( query_name() +" missed "+ name_of_attacker +".\n" );
}
return 1;
}
#if DEBUG_COMBAT
EV_COST->cost11( cost - get_eval_cost() );
#endif
if ( !query_npc() && attacker_ob ) {
(mapping)SKILL_D->do_learn( skill_pts, weapon, attacker_ob, weap_sk,
Int, Wis, query_real_name(), query_class(), query_level() );
if ( weapon && weapon == second_weapon ) {
(mapping)SKILL_D->do_learn( skill_pts,
"Two Weapon", attacker_ob,
this_object()->query_skill( "Two Weapon" ),
Int, Wis, query_real_name(), query_class(), query_level() );
}
}
#if DEBUG_COMBAT
EV_COST->cost9( cost - get_eval_cost() );
#endif
this_object()->add_exp( (100 * tmp) / XP_FACTOR );
if ( attacker_ob &&
(string)attacker_ob->query_name() != (string)NAME_OF_GHOST ) {
string how, what, where, *how_what;
how_what = (string *)MESSAGE_D->query_messages( tmp, dam_type,
(weapon ? (string *)weapon->query_hit_messages() : hit_messages) );
how = how_what[1];
what = how_what[0];
switch ( hit_at ) {
case HEAD: where = (string)attacker_ob->query_head_str(); break;
case BODY: where = (string)attacker_ob->query_body_str(); break;
case ARM: where = (string)attacker_ob->query_arm_str(); break;
case LEG: where = (string)attacker_ob->query_leg_str(); break;
default: where = "somewhere"; break;
}
message( "# "+ what +" ($ "+ where + how +".", this_object(),
attacker_ob );
#if DEBUG_COMBAT
EV_COST->cost12( cost - get_eval_cost() );
#endif
return 1;
}
attacker_ob = alt_attacker_ob;
alt_attacker_ob = 0;
if ( attacker_ob )
return 1;
}
int fail_wield( object w, int where ) {
return hook( "block_wield", ({ w, where }) );
}
int fail_wear( object w ) {
return hook( "block_wear", ({ w }) );
}
void wield( object w ) {
hook( "wield", ({ w }) );
if ( wielded_weapon )
stop_wielding( wielded_weapon );
wielded_weapon = w;
if ( query_is_player() )
weapon_class = 0;
parry_ac = (int)w->query_parry_ac();
dex_wc = (int)w->query_dex_wc();
// calculate_power();
}
void second_wield( object w ) {
hook( "second_wield", ({ w }) );
if ( second_weapon )
stop_wielding( second_weapon );
second_weapon = w;
}
void heal_self( int h ) {
if ( h > 0 ) {
int hp_healed, sp_healed;
#ifdef LOG_HEAL
if ( HEAL_LOG_CHECK ) {
catch( log_file( "HEAL", "["+ ctime() +"] "+ capitalize( name ) +" ["+
query_level() +"] ("+ h +") by "+
capitalize( this_interactive()->query_real_name() ) +".\n" ) );
}
#endif
if ( (hit_point + h) > query_max_hp() ) {
hp_healed = query_max_hp() - hit_point;
hit_point = query_max_hp();
} else {
hp_healed = h;
hit_point += h;
}
if ( (spell_points + h) > query_max_sp() ) {
sp_healed = query_max_sp() - spell_points;
spell_points = query_max_sp();
} else {
spell_points += h;
sp_healed = h;
}
hook( "heal_self", ({ hp_healed, sp_healed }) );
}
}
void restore_spell_points( int h ) {
if ( h > 0 ) {
#ifdef LOG_HEAL
if ( HEAL_LOG_CHECK ) {
catch( log_file( "HEAL", "["+ ctime() +"] "+ capitalize( name ) +" ["+
query_level() +"] ("+ h +" SP) by "+
capitalize( this_interactive()->query_real_name() ) +".\n" ) );
}
#endif
if ( (spell_points += h) > query_max_sp() )
spell_points = query_max_sp();
}
}
void reduce_spell_points( int i ) {
if ( i > 0 )
spell_points -= i;
hook( "reduce_spell_points", ({ i }) );
}
void restore_hit_points( int h ) {
if ( h > 0 ) {
#ifdef LOG_HEAL
if ( HEAL_LOG_CHECK ) {
catch( log_file( "HEAL", "["+ ctime() +"] "+ capitalize( name ) +" ["+
query_level() +"] ("+ h +" HP) by "+
capitalize( this_interactive()->query_real_name() ) +".\n" ) );
}
#endif
if ( (hit_point += h) > query_max_hp() )
hit_point = query_max_hp();
}
}
void attack_object(object ob) {
// object tp;
/* Fir 27 Apr 2013: ldhit_fix: No attacking if you're a statue. */
if ( !ob || ob->query_ghost() || this_object()->query_is_statue() )
return;
// if ( this_player() != this_object() ) { // bugfix (Greyson)
// tp = this_player();
// set_this_player( this_object() );
// }
set_heart_beat( 1 );
if ( !ob->query_attack() )
ob->start_fight();
if ( attacker_ob == ob ) {
attack();
} else if ( alt_attacker_ob == ob ) {
alt_attacker_ob = attacker_ob;
attacker_ob = ob;
attack();
} else {
alt_attacker_ob = attacker_ob;
attacker_ob = ob;
attacker_ob->attacked_by( this_object() );
attack();
}
// if ( tp ) set_this_player( tp );
}
void set_attacker( object ob ) {
if ( attacker_ob == ob )
;
else if ( alt_attacker_ob == ob ) {
alt_attacker_ob = attacker_ob;
attacker_ob = ob;
} else {
alt_attacker_ob = attacker_ob;
attacker_ob = ob;
}
}
/*
* This is used to set who this living is currently hunting.
* Added by Toshina, 17-Aug-96, for J19.
*/
void set_hunted( object ob ) {
hunted = ob;
if ( hunted ) {
hunting_time = 1000;
} else {
hunting_time = 0;
}
}
void zap_object( object ob ) {
if ( ob ) {
ob->attacked_by( this_object() );
say( query_name() +" summons a flash from the sky.\n" );
write( "You summon a flash from the sky.\n" );
ob->hit_player( 100000 );
write( "There is a big clap of thunder.\n\n" );
}
}
void stop_hunter() {
// added 6Jul94 by Dawg to remove spurious msgs
if ( !hunter && !alt_hunter )
return;
hunter = alt_hunter = 0;
tell_object( this_object(), "You are no longer hunted.\n" );
}
void run_away() {
object here;
mixed dirs;
int i, j;
if ( wimpy_disabled )
return;
if ( !(here = environment()) )
return;
#ifdef VERSION_WIMPY_DIR
if ( whimpy_direction ) {
// If the player has gone considerably lower on hit points than
// their wimpy limit, they are more likely to panic in a lose-control
// way. (What percent of their hit points they still have minus a random
// number between 0 and their wimpy percentage.)
if ( (query_hit_point() * 100 / query_max_hp()) -
random(query_wimpy() * 10) > 0 )
command( whimpy_direction );
else
tell_object( this_object(), "You forget which way to run!\n" );
}
#endif
dirs = (mixed)environment()->query_dest_dir();
if ( dirs && here == environment() )
command( dirs[1 + (random( sizeof( dirs ) ) / 2 * 2 )] );
j = random( 6 );
while ( i < 6 && here == environment() ) {
if ( query_body_position() && !random( 10 ) )
command( "stand" );
i += 1;
j += 1;
if ( j > 6 )
j = 1;
switch ( j ) {
case 1: command( "east" ); break;
case 2: command( "west" ); break;
case 3: command( "north" ); break;
case 4: command( "south" ); break;
case 5: command( "up" ); break;
case 6: command( "down" ); break;
}
}
if ( here == environment() ) {
say( query_name() +" is panicking and trying to flee.\n", this_object() );
if ( this_object() )
tell_object( this_object(), "You panic and try to flee!\n" );
} else if ( this_object() ) {
tell_object( this_object(), "You run away in a panic!\n" );
}
}
void stop_fight() {
attacker_ob = alt_attacker_ob;
alt_attacker_ob = 0;
}
void set_attack_disabled( int active ) {
if ( member( ({ "lib", "greyson", "dawg", }),
geteuid( previous_object() ) ) != -1 ) {
attack_disabled = active;
}
}
void set_wimpy_disabled( int active ) {
wimpy_disabled = active;
}
int reduce_hit_point( int dam ) {
#ifdef LOG_HEAL
if ( this_interactive() && this_interactive() != this_object() ) {
log_file( "REDUCE_HP", (name ? capitalize( name ) : query_name()) +" ("+
dam +") by "+ capitalize(this_interactive()->query_real_name()) +"\n" );
}
#endif
if ( this_player() && this_object()->query_is_statue() ) {
write( "Time has petrified "+ query_objective() +".\n" );
stop_fight();
this_player()->stop_fight();
return 0;
}
if ( dam > hit_point - 1 )
dam = hit_point - 1;
if ( this_player() && this_player() != this_object() ) {
mixed dam_key;
if ( this_player()->query_is_player() ) {
dam_key = (string)this_player()->query_real_name();
} else {
dam_key = this_player();
}
add_m_damagers(dam_key, dam);
if ( query_m_damagers(dam_key) <= 0 )
del_m_damagers(dam_key);
}
// Should not be used to modify amount as usually used for costs
// or specific amount of reduction or healing
hook("reduce_hit_point", ({ dam }) );
ks_handle_attack(this_player(), attacker_ob, dam);
if ( (hit_point -= dam) <= 0 )
hit_point = 1;
this_object()->report_hp_sp();
return hit_point;
}
int pay_spell_points( int arg ) {
if ( spell_points < arg ) {
write( "You are too low on power.\n" );
return 0;
}
reduce_spell_points( arg );
return 1;
}
void stop_any_hunt() {
if ( hunter )
hunter->stop_hunter();
if ( alt_hunter )
alt_hunter->stop_hunter();
hunted = hunter = alt_hunter = 0;
}
int calculate_power() {
#if 1
return 0;
#else
int i, temp_power;
if ( !weapon_class && !dex_wc ) {
temp_power = 100 * (tmp_Str + tmp_Dex) / 2;
} else {
i = weapon_class + dex_wc;
temp_power = weapon_class * 100 + (tmp_Str * weapon_class * 100) / i +
(tmp_Dex * dex_wc * 100) / i;
}
if ( (temp_power % 100) >= 50)
power = (temp_power / 100) + 1;
else
power = temp_power / 100;
return power;
#endif
}
void set_detect_invisible( status arg ) {
can_detect_invis = arg;
}
status see_invisible() {
return can_detect_invis;
}
int query_hit_point() {
return hit_point;
}
int query_wc() {
return weapon_class;
}
int query_ac() {
return armour_class;
}
int query_head_ac() {
return head_ac;
}
int query_body_ac() {
return body_ac;
}
int query_arm_ac() {
return arm_ac;
}
int query_leg_ac() {
return leg_ac;
}
int query_block_ac() {
return block_ac;
}
object query_alt_hunter() {
return alt_hunter;
}
object query_alt_attack() {
return alt_attacker_ob;
}
static void set_wimpy( int w ) {
whimpy = w;
}
int query_wimpy() {
return whimpy;
}
#ifdef VERSION_WIMPY_DIR
static void set_wimpy_direction( string direction ) {
whimpy_direction = direction;
}
string query_wimpy_direction() {
return whimpy_direction;
}
#endif
// int query_power() { return power; }
object query_hunter() {
return hunter;
}
object query_wielded_weapon() {
return wielded_weapon;
}
int query_attack_disabled() {
return attack_disabled;
}
static void set_aim_at( int a ) {
aiming_at = a;
}
int query_aim_at() {
return aiming_at;
}
object query_worn_shield() {
return worn_shield;
}
int query_dead() {
return dead;
}
object query_hunted() {
return hunted;
}
object query_attack() {
return attacker_ob;
}
int query_parry_ac() {
return parry_ac;
}
int query_weapon_class() {
#if BRAWL_IN_COMBAT
object brawl;
int brawl_bonus;
#endif
int ret;
ret = weapon_class;
#if BRAWL_IN_COMBAT
brawl = present("\nbrawl_skill",this_object());
if (brawl && !wielded_weapon && !second_weapon && !worn_shield) {
if (hit_messages == (string *)brawl->query_hit_messages()) {
brawl_bonus = (int)brawl->do_combat();
} else {
brawl_bonus = random((int)brawl->virtual_class());
}
ret += (int)WEAPON_CLASS_OF_HANDS + brawl_bonus;
if (this_object()->query_is_player() && !hit_messages)
hit_messages = (string *)brawl->query_hit_messages();
} else {
if ( (wielded_weapon && !wielded_weapon->query_hit_messages() ) ||
(second_weapon && !second_weapon->query_hit_messages() ) )
hit_messages = 0;
}
#endif
if ( !ret )
ret = (int)WEAPON_CLASS_OF_HANDS;
#if BRAWL_IN_COMBAT
ret += hook( "weapon_class", ({ ret, brawl_bonus }) );
#else
ret += hook( "weapon_class", ({ ret }) );
#endif
return ret;
}
string query_killed_string() {
return "killed";
}
string query_died_string() {
return "died";
}
string *query_hit_messages() {
return hit_messages;
}
// ----------------------------------------------------------------------------