// combatd.c
// optimize by Yu Jue, 1998/3/14
// fixed some small bugs by snowman, 01/12/1998
// added in winner_reward(), by snowman 15/03/1999
// Inflict the damage before call_out ob_hit, by snowman 26/10/1999
// moved messages to combat_msg.h   by snowman 28/10/1999
// added end_fight().  by snowman@SJ 26/11/1999
// Modify...   by snowman@SJ 05/12/1999
// Modified By keinxin@sj2 2003.4 For regulate commbat actions
#pragma optimize

#include <ansi.h>
#include <skill.h>
#include <weapon.h>
#include <combat.h>

inherit F_DBASE;

#include <combat_msg.h>

varargs void report_status(object ob, int effective)
{
	if( effective ) 
		message_vision( "( $N" + eff_status_msg(
			(int)ob->query("eff_qi") * 100 / (int)ob->query("max_qi") ) + " )\n", ob);
	else
		message_vision( "( $N" + status_msg(
			(int)ob->query("qi") * 100 / (int)ob->query("max_qi") ) + " )\n", ob);
}

void announce(object ob, string event)
{
	switch(event) {
		case "dead":
			message_vision("\n$N「啪」的一声倒在地上，挣扎着抽动了几下就死了。\n\n", ob);
			break;
		case "unconcious":
			if(ob->query("race") != "人类")
			     message_vision("\n$N挣扎了几下，一个不稳晕倒过去。\n\n", ob);
			message_vision("\n$N神志迷糊，脚下一个不稳，倒在地上昏了过去。\n\n", ob);
			break;
		case "revive":
		        if(ob->query("blind") || ob->query("race") != "人类")
			     message_vision("\n$N身子一颤，扭动了几下，清醒了过来。\n\n", ob);
			else if(ob->query("mute"))
			     message_vision("\n$N慢慢清醒了过来，睁开眼睛站起来摇了摇头。\n\n", ob);
			else message_vision("\n$N身子动了动，口中呻吟了几声，清醒过来。\n\n", ob);
			break;
	}
}


// added by snowman@SJ 26/11/1999
void end_fight(object me, object victim)
{
	me->remove_enemy(victim);
	victim->set_temp("last_lost_to", me);   
        if (victim) victim->remove_enemy(me);
	if (me->query("race") == "人类") {
		if (!me->query("mute") && victim->query("mute"))
			message_vision( winner_msg[random(sizeof(winner_msg)/2)], me, victim);
		if (me->query("mute") && !victim->query("mute"))
			message_vision(winner_msg[sizeof(winner_msg)/2 + random(sizeof(winner_msg)/2)], me, victim);
		if (!me->query("mute") && !victim->query("mute"))
			message_vision( winner_msg[random(sizeof(winner_msg))], me, victim);
	} 
	else message_vision( winner_animal_msg[random(sizeof(winner_animal_msg))], me, victim);
			
}


void create()
{
        seteuid(getuid());
        set("channel_id", "战斗精灵");
}

// This function calculates the combined skill/combat_exp power of a certain
// skill. This value is used for A/(A+B) probability use.
varargs int skill_power(object ob, string skill, int usage)
{
	int level, power;

	if( !living(ob) ) return 0;

	level = ob->query_skill(skill);

	switch(usage) {
		case SKILL_USAGE_ATTACK:
			level += ob->query_temp("apply/attack");
			break;
		case SKILL_USAGE_DEFENSE:
			level += ob->query_temp("apply/defense");
			if (ob->is_fighting()){
				level = level * (100 + ob->query_temp("fight/dodge")) / 100;
				
				// add parry by snowman.
				level = level * (100 + ob->query_temp("fight/parry")) / 100;
				}
	}

	if( level < 1 ) return (int)ob->query("combat_exp") / 2;

	// here need a modification later
	power = (level*level*level) / 3;

	if (usage == SKILL_USAGE_ATTACK)
		return (power + ob->query("combat_exp")) /30 * ob->query_dex();
	return (power + ob->query("combat_exp"))
		/30 * (skill == "dodge"?ob->query_dex():ob->query_int());
}

string adj_msg(string result, string limb, object weapon, mapping action, string attack_skill)
{
	string wname = "";

	if( objectp(weapon) ) {
		if (weapon->query_amount() && weapon->query("skill_type") != "throwing")
			sscanf(weapon->short(), "%s(%*s", wname);
		else wname = weapon->name();
		result = replace_string(result, "$w", wname);
	}
	if( stringp(action["weapon"]) ) result = replace_string( result, "$w", action["weapon"] );

        if( stringp(action["limb"]) ) result = replace_string( result, "$l", action["limb"] );

	if( attack_skill == "finger" ) result = replace_string( result, "$w", "手指" );
	
	result = replace_string( result, "$l", limb );
	return result;
}

// do_attack()
//
// Perform an attack action. This function is called by fight() or as an
// interface for some special utilize in quests.
//
varargs void do_attack(object me, object victim, object weapon, int attack_type, string attack_msg, string damtype)
{
	mapping my, your, prepare, action;
	string limb, *limbs, result;
	string attack_skill, force_skill, martial_skill, dodge_skill, parry_skill;
	mixed foo;
	int ap, dp, pp, em;
	int damage, damage_bonus, defense_factor;
	int brief;
	int wounded = 0;
	int flag = 0;
	object vweapon = victim->query_temp("weapon");

	if (environment(me) != environment(victim)) return;	// 防止隔山打牛 Yuj@SJ 19990725
	if (!living(me)) return;
// added by snowman@SJ 30/12/1999
        if (me->query_temp("lost_attack") > 0){
                me->add_temp("lost_attack", -1);
                return;
                }
	if (userp(me)) {
		// jingli cost, added by snowman
		em = sizeof(me->query_enemy())+1;
                me->receive_damage("jingli", (2+random(2))*em);
		        if (me->query("jingli") * 100 / me->query("eff_jingli") < 20)
			         tell_object(me, HIR "\n你的体力快消耗完了！\n" NOR);
	}
	if (userp(victim) && living(victim)
	&& 3*me->query("combat_exp") >= 2*victim->query("combat_exp")) {
        victim->receive_damage("jingli", 2+random(2));
		if (victim->query("jingli") * 100 / victim->query("eff_jingli") < 20)
			tell_object(victim, HIR "\n你的体力快消耗完了！\n" NOR);
	}

	if (me->query_skill_mapped("parry") == "douzhuan-xingyi"
	&& ((!weapon && !vweapon) || ((weapon && vweapon)
	&& weapon->query("skill_type") == vweapon->query("skill_type"))))
		flag = 1;

	my = me->query_entire_dbase();
	your = victim->query_entire_dbase();
	if (userp(me) && userp(victim))
		brief=me->query("env/brief") && victim->query("env/brief");
	else
		brief=me->query("env/brief") || victim->query("env/brief");
//
// (0) Choose skills.
//
	if (flag) {
		foo = me;
		me = victim;
	}
	prepare = me->query_skill_prepare();
	if (!prepare) prepare = ([]);

	if ( sizeof(prepare) == 0) attack_skill = "unarmed";
	if ( sizeof(prepare) == 1) attack_skill = (keys(prepare))[0];
	if ( sizeof(prepare) == 2) attack_skill = (keys(prepare))[me->query_temp("action_flag")];
	if ( weapon ) attack_skill = weapon->query("skill_type");
	if (flag && !me->query_skill_mapped(attack_skill)) {
		me = foo;
		flag = 0;
		prepare = me->query_skill_prepare();
		if (!prepare) prepare = ([]);
		if ( sizeof(prepare) == 0) attack_skill = "unarmed";
		if ( sizeof(prepare) == 1) attack_skill = (keys(prepare))[0];
		if ( sizeof(prepare) == 2) attack_skill = (keys(prepare))[me->query_temp("action_flag")];
		if ( weapon ) attack_skill = weapon->query("skill_type");
	}

	//
	// (1) Find out what action the offenser will take.
	//
	me->reset_action();
	action = me->query("actions");
	if( !mapp(action) ) {
		me->reset_action();
		action = me->query("action");
		if( !mapp(action) ) {
			CHANNEL_D->do_channel( this_object(), "sys",
				sprintf("%O(%s): bad action = %O",
				me, me->query("id"), me->query("actions", 1)));
			return 0;
		}
	}
	if (flag) me = foo;

	if (!me->query_temp("action_flag"))
		result = "\n" + action["action"] + "！\n";
	else
		result = "\n" + "紧跟着"+action["action"] + "!\n"; 
		
	if(stringp(attack_msg)) result = "\n" + attack_msg + "\n";	

	//
	// (2) Prepare AP, DP for checking if hit.
	//
	limbs = victim->query("limbs");
	limb = limbs[random(sizeof(limbs))];

	message_vision(adj_msg(result, limb, weapon, action, attack_skill), me, victim);

	if (flag) me->add_temp("apply/attack", me->query_skill("douzhuan-xingyi")/5);
	ap = skill_power(me, flag?"parry":attack_skill, SKILL_USAGE_ATTACK);
	if (flag) me->add_temp("apply/attack", -me->query_skill("douzhuan-xingyi")/5);
	if( ap < 1) ap = 1;
	
	if (userp(me) && intp(action["dodge"]))
		me->set_temp("fight/dodge", action["dodge"]);
	if (userp(me) && intp(action["parry"]))
		me->set_temp("fight/parry", action["parry"]);
	
	dp = skill_power(victim, "dodge", SKILL_USAGE_DEFENSE);
	if( dp < 1 ) dp = 1;
	if( victim->is_busy() ) dp /= 3;
	if( !living(victim)) dp = 1;
	
	// (3) Fight!

        // here added by snowman, fainted object cant dodge :)
	if( random(ap + dp) < dp && living(victim)) {            // Does the victim dodge this hit?
		dodge_skill = victim->query_skill_mapped("dodge");
		if( !dodge_skill ) dodge_skill = "dodge";
		if (!brief) {
			result = SKILL_D(dodge_skill)->query_dodge_msg(victim, attack_type);
			message_vision(adj_msg(result, limb, weapon, action, attack_skill), me, victim);
		}
		if( dp < ap && your["combat_exp"] < my["combat_exp"]*2
		&& (!userp(victim) || !userp(me)) 
		&& random(your["jingli"]*100/(your["eff_jingli"]+1) + your["int"]) > 69 ) {
			your["combat_exp"]++;
			for (foo = 15; foo <= 50; foo+=5)
				if (dp*foo < ap*10) {
//  fight get exp too fast		your["combat_exp"]++;
					if (userp(victim))
						victim->improve_skill("dodge", random(2));
				} else break;
		}

		// This is for NPC only. NPC have chance to get exp when fail to hit.
		if( (ap < dp) && !userp(me) ){
			if( random(my["int"]) > 15 ) my["combat_exp"]++;
			// added by snowman
			if( my["combat_exp"] > 10000 ) my["combat_exp"] += my["combat_exp"]/10000;
		}
		
		damage = RESULT_DODGE;
	} else {

		//
		//      (4) Check if the victim can parry this attack.
		//
		if( vweapon ) {
			pp = skill_power(victim, "parry", SKILL_USAGE_DEFENSE);
			if( !weapon ) pp *= 2;
		} else {
			pp = skill_power(victim, attack_skill, SKILL_USAGE_DEFENSE);
			if( weapon ) pp = 0;
		}

		if( victim->is_busy() ) pp /= 3;
		if( pp < 1 ) pp = 1;

                // added by snowman, fainted object cant parry :)
		if( random(ap + pp) < pp && living(victim)) {
			parry_skill = victim->query_skill_mapped("parry");
			if( !parry_skill ) parry_skill = "parry";
			if (!brief) {
				result = SKILL_D(parry_skill)->query_parry_msg(vweapon, me, attack_type);
				if (!stringp(result))
					result = SKILL_D("parry")->query_parry_msg(vweapon);
				message_vision(adj_msg(result, limb, weapon, action, attack_skill), me, victim);
			}

			if( pp < ap && your["combat_exp"] < my["combat_exp"] * 2
			&& (!userp(victim) || !userp(me))
			&& random(your["jingli"]*100/(your["eff_jingli"]+1) + your["int"]) > 69 ) {
				your["combat_exp"]++;
				for (foo = 15; foo <= 50; foo+=5)
					if (pp*foo < ap*10) {
						if (userp(victim))
							victim->improve_skill("parry", random(2));
					} else break;
			}
			damage = RESULT_PARRY;

		} else {
			//
			//      (5) We hit the victim and the victim failed to parry
			//
			damage = me->query_temp("apply/damage");
			if (damage > 1000) damage = 1000;
			damage = (damage + random(damage)) / 2;
			damage += action["damage"] * damage / 100;
			damage += me->query_skill(flag?"parry":attack_skill) * damage / 100;
			damage_bonus = me->query_str();

			// Let force skill take effect.
			if( my["jiali"] > 0 && (my["neili"] >= my["jiali"]) ) {
				// Modify by snowman@SJ 05/12/1999
				if(!living(victim)){
					 damage_bonus += my["jiali"];
					 me->add("neili", -my["jiali"] );
				}
					
				else if( force_skill = me->query_skill_mapped("force") ) {
					foo = SKILL_D(force_skill)->hit_ob(me, victim, damage_bonus, my["jiali"]);
					if( stringp(foo) )
						message_vision(adj_msg(foo, limb, weapon, action, attack_skill), me, victim);
					else if( intp(foo) ) {
						if (!living(victim) && foo < 0) foo = 0;
						if (weapon) foo /= 3;
						damage_bonus += foo;
					}
				}
			}

			if (weapon) damage_bonus += action["force"] * damage_bonus / 1000;
			else damage_bonus += action["force"] * damage_bonus / 500;

			if (weapon)
				damage_bonus += me->query_skill("force") * damage_bonus /100;
			else
				damage_bonus += (me->query_skill(flag?"parry":attack_skill)
				+ me->query_skill("force")) * damage_bonus / 100;

			if( martial_skill = me->query_skill_mapped(flag?"parry":attack_skill) ) {
				foo = SKILL_D(martial_skill)->hit_ob(me, victim, damage_bonus);
				if( stringp(foo) )
					message_vision(adj_msg(foo, limb, weapon, action, attack_skill), me, victim);
				else if(intp(foo) ) damage_bonus += foo;
			}
			
			// Let weapon or monster have their special damage.
			if( weapon ) {
				foo = weapon->hit_ob(me, victim, damage_bonus);
				if( stringp(foo) )
					message_vision(adj_msg(foo, limb, weapon, action, attack_skill), me, victim);
				else if(intp(foo) ) damage += foo;
			} else {
				foo = me->hit_ob(me, victim, damage_bonus);
				if( stringp(foo) )
					message_vision(adj_msg(foo, limb, weapon, action, attack_skill), me, victim);
				else if(intp(foo) ) damage += foo;
			}
			
			/* 
			i moved this here, so ob_hit returns final damage after all effects. snowman 22/10/99

			6) Inflict the damage.
			*/
			if( damage_bonus > 0 ) damage += (damage_bonus + random(damage_bonus))/2;
			if( damage_bonus < 0 ) damage += (damage_bonus - random(-damage_bonus))/2;
			if( damage < 0 ) damage = 0;
			
			// Let combat exp take effect
			if(living(victim)){
				defense_factor = dp + pp;
				while( random(defense_factor) > ap / 3) {
					damage -= damage / 3;
					defense_factor /= 2;
				}
			}
			
			if (attack_type == TYPE_QUICK) damage /= 2;
                        if (attack_type == TYPE_SUPER) damage *= 2;
                        if (!living(victim)) damage *= 6; // hehehehehehe....
                        
			damage = damage * 20 / (victim->query_con() / 4 + 15);

			// by snowman, added living check to victim for dodge, parry and force.
			if(living(victim) 
			&& !me->query_temp("hit_ob_hit")
			&& !victim->query_temp("no_ob_hit")){
				if( martial_skill = victim->query_skill_mapped("dodge") ) {
					foo = SKILL_D(martial_skill)->ob_hit(me, victim, damage);
					if( stringp(foo) )
						message_vision(adj_msg(foo, limb, weapon, action, attack_skill), me, victim);
					else if(intp(foo) ) damage += foo;
				}

				if( martial_skill = victim->query_skill_mapped("parry") ) {
					foo = SKILL_D(martial_skill)->ob_hit(me, victim, damage);
					if( stringp(foo) )
						message_vision(adj_msg(foo, limb, weapon, action, attack_skill), me, victim);
					else if(intp(foo) ) damage += foo;
				}

                        	if( martial_skill = victim->query_skill_mapped("force") ) {
					foo = SKILL_D(martial_skill)->ob_hit(me, victim, damage);
					if( stringp(foo) )
						message_vision(adj_msg(foo, limb, weapon, action, attack_skill), me, victim);
					else if(intp(foo) ) damage += foo;
				}
			}
			
			if (foo = victim->query_temp("armor/cloth")) {
				foo = foo->ob_hit(me, victim, damage);
				if( stringp(foo) )
					message_vision(adj_msg(foo, limb, weapon, action, attack_skill), me, victim);
				else if(intp(foo) ) damage += foo;
			}

			if( damage < 0 ) damage = 0;
	
			if(damage > 0)
			       victim->receive_damage("qi", damage, me );

			if( random(damage) > victim->query_temp("apply/armor")
			&& ( ( me->is_killing(your["id"])
			&& ( (!weapon && !random(4)) || (weapon && !random(2)) ) )
			|| ( (!weapon && !random(8)) || (weapon && !random(4)) ) ) ) {
				// We are sure that damage is greater than victim's armor here.
				victim->receive_wound("qi", damage - victim->query_temp("apply/armor"), me);
				wounded = 1;
			}

			result = damage_msg(damage, action["damage_type"]);
			message_vision(adj_msg(result, limb, weapon, action, attack_skill), me, victim);

			//
			//      (7) Give experience
			//

			if( !userp(me) || !userp(victim) ) {
				if (living(me))
				if( (ap < dp || ap < pp)
				&& (random(my["jingli"]*100/(my["eff_jingli"]+1) + my["int"]) > 69) ) {
					my["combat_exp"]++;
					if( my["potential"] < my["max_pot"] ) my["potential"]++;
					if (userp(me)) me->improve_skill(flag?"parry":attack_skill, 1);
				}
				if (living(victim))
				if( (ap > dp || ap > pp )
				&& (random(your["jingli"]*100/(your["eff_jingli"]+1) + your["int"]) > 69) ) {
					your["combat_exp"]++;
					if( your["potential"] < your["max_pot"] ) your["potential"]++;
				}
			}
		}
	}

	if( wizardp(me) && (string)me->query("env/combat")=="verbose" ) {
		if( damage > 0 )
			tell_object(me, sprintf( GRN "AP：%d，DP：%d，PP：%d，伤害力：%d\n" NOR,
				ap/100, dp/100, pp/100, damage));
		else
			tell_object(me, sprintf( GRN "AP：%d，DP：%d，PP：%d\n" NOR,
				ap/100, dp/100, pp/100));
	}

	if( wizardp(victim) && (string)victim->query("env/combat")=="verbose" ) {
		if( damage > 0 )
			tell_object(victim, sprintf( GRN "AP：%d，DP：%d，PP：%d，伤害力：%d\n" NOR,
				ap/100, dp/100, pp/100, damage));
		else
			tell_object(victim, sprintf( GRN "AP：%d，DP：%d，PP：%d\n" NOR,
				ap/100, dp/100, pp/100));
	}

	if( damage > 0 ) {
		report_status(victim, wounded);
		if( victim->is_busy() ) victim->interrupt_me(me);
		if( !me->is_killing(your["id"])
		&& !victim->is_killing(my["id"])
		&& !me->query("have_master")   // added by snowman
		&& victim->query("qi")*2 <= victim->query("max_qi")) 
			end_fight(me, victim);
	}

	if( functionp(action["post_action"]) )
		evaluate( action["post_action"], me, victim, weapon, damage);

	// See if the victim can make a riposte.
	if( attack_type == TYPE_REGULAR
	&& damage < 1 && victim->query_temp("guarding") ) {
		victim->delete_temp("guarding");
		if( random(my["dex"]) < 5 ) {
			message_vision("$N一击不中，大惊失色，不觉露出了破绽！\n", me);
			do_attack(victim, me, vweapon, TYPE_QUICK);
		} else {
			message_vision("$N一见$n攻击失误，顿时趁机发动攻击！\n", victim, me);
			do_attack(victim, me, vweapon, TYPE_RIPOSTE);
		}
	}
}

//      fight()
//
//      This is called in the attack() defined in F_ATTACK, which handles fighting
//      in the heart_beat() of all livings. Be sure to optimize it carefully.
//
void fight(object me, object victim)
{
	object weapon = me->query_temp("weapon");

	if( !living(me) || me->query_temp("combat_yield")) return;
	if (me->query_temp("no_fight")) return;

	if (!me->is_killing(victim->query("id"))
	&& member_array(me, victim->query_enemy()) > 4) return;

// If victim is busy or unconcious, always take the chance to make an attack.
	if( victim->is_busy() || !living(victim) ) {
		me->delete_temp("guarding");
		if( !victim->is_fighting(me) ) victim->fight_ob(me);
		do_attack(me, victim, weapon, TYPE_QUICK);

	if( me->is_fighting(victim) && victim->is_fighting(me)) 
		if((!weapon && sizeof(me->query_skill_prepare()) > 1)
		|| (weapon 
		&& weapon->query("skill_type") == "sword"
		&& me->query_skill("pixie-jian", 1) >= 60
		&& me->query_skill_mapped("sword") == "pixie-jian"
		&& me->query("gender") == "无性")
                || (me->query("double_attack") && !me->query_temp("weapon")) 
                || me->query_temp("double_attack")) {
			if (me->query("double_attack") && sizeof(me->query_skill_prepare()) < 2)
				message_vision(CYN"\n$N双手分使，灵活异常，好象变成了两个人似的！"NOR,me);
			me->set_temp("action_flag",1);
			do_attack(me, victim, weapon, TYPE_QUICK);
			me->delete_temp("action_flag");
		}

        // Else, see if we are brave enough to make an aggressive action.
		} else if( me->query_temp("guarding")
		|| random( (int)victim->query_dex() * 3) < (int)me->query_dex()) {
			me->delete_temp("guarding");
			if( !victim->is_fighting(me) ) victim->fight_ob(me);  
			do_attack(me, victim, weapon, TYPE_REGULAR);

			if( me->is_fighting(victim) && victim->is_fighting(me)) 
			if( (!weapon && sizeof(me->query_skill_prepare()) > 1)
			|| (weapon
			&& weapon->query("skill_type") == "sword"
			&& me->query_skill("pixie-jian", 1) >= 60
			&& me->query_skill_mapped("sword") == "pixie-jian"
			&& me->query("gender") == "无性")
                        || (me->query("double_attack") && !me->query_temp("weapon")) 
                        || me->query_temp("double_attack")) {
				if (me->query("double_attack") && sizeof(me->query_skill_prepare()) < 2)
					message_vision(CYN"\n$N双手分使，灵活异常，好象变成了两个人似的！"NOR,me);
				me->set_temp("action_flag",1);
				do_attack(me, victim, weapon, TYPE_REGULAR);
				me->delete_temp("action_flag");
			}

		// Else, we just start guarding.
		} else {
			me->set_temp("guarding", 1);
			message_vision( guard_msg[random(sizeof(guard_msg))], me, victim);
		}
}

//      auto_fight()
//
//      This function is to start an automatically fight. Currently this is
//      used in "aggressive", "vendetta", "hatred", "berserk" fight.
//
void auto_fight(object me, object obj, string type)
{
	// Don't let NPC autofight NPC.
	if( !userp(me) && !userp(obj) ) return;

	// Because most of the cases that we cannot start a fight cannot be checked
	// before we really call the kill_ob(), so we just make sure we have no 
	// aggressive callout wating here.
	if( me->query_temp("looking_for_trouble") ) return;
	me->set_temp("looking_for_trouble", 1);

	// This call_out gives victim a chance to slip trough the fierce guys.
	call_out( "start_" + type, 1, me, obj);
}

void start_berserk(object me, object obj)
{
	int shen;
	string str;
	
	if( !me || !obj ) return;                               // Are we still exist( not becoming a corpse )?

	me->delete_temp("looking_for_trouble");

	if(     me->is_fighting(obj)                            // Are we busy fighting?
	||      !living(me)                                     // Are we capable for a fight?
	||      environment(me)!=environment(obj)       // Are we still in the same room?
	||      environment(me)->query("no_fight")      // Are we in a peace room?
	) return;

	shen = -me->query("shen");
	message_vision("$N用一种异样的眼神扫视着在场的每一个人。\n", me);

	if( wizardp(me) || !userp(me) || (int)me->query("neili") > (random(shen) + shen)/20 ) return;

	if( shen/2 > random((int)me->query("combat_exp"))
	&& !wizardp(obj) ) {
		str = RANK_D->query_self_rude(me)+ "看你实在很不顺眼，去死吧";
		if(stringp(me->query("env/shen_kill")) && strlen(me->query("env/shen_kill")) < 30 )
			str = me->query("env/shen_kill");
		message_vision(CYN"$N对着$n喝道："+str+"！\n"NOR, me, obj);
		me->kill_ob(obj);
	} else {
		message_vision(CYN"$N对着$n喝道：喂！" + RANK_D->query_rude(obj)+ "，" + RANK_D->query_self_rude(me) + "正想找人打架，陪我玩两手吧！\n"NOR,
			me, obj);
		me->fight_ob(obj);
	}
}

void start_hatred(object me, object obj)
{
	if( !me || !obj ) return;                               // Are we still exist( not becoming a corpse )?

	me->delete_temp("looking_for_trouble");

	if( (me->is_killing(obj->query("id")) && me->is_fighting(obj))	// Are we busy fighting?
	||      !living(me)                                                     // Are we capable for a fight?
	||      environment(me)->query("no_fight")      // Are we in a peace room?
	) return;

	// We found our hatred! Charge!
	if (environment(me)==environment(obj)) {
		switch(me->query("race")) {
			case "家畜":
			case "野兽":
				message_vision( catch_hunt_beast_msg[random(sizeof(catch_hunt_beast_msg))], me, obj);
				break;
			case "飞禽":
				message_vision( catch_hunt_bird_msg[random(sizeof(catch_hunt_bird_msg))], me, obj);
				break;
			default:
				message_vision( catch_hunt_human_msg[random(sizeof(catch_hunt_human_msg))], me, obj);
		}
		me->kill_ob(obj);
	} else if (me->query("race")=="人类" && random(4) == 2) {
		tell_object(me, HIW "你冲着远处"+obj->name()+"的背影叫到：下次别让我看到你！\n" NOR);
		tell_room(environment(me), HIW+me->name()+"冲着远处"+obj->name()+"的背影叫到：下次别让我看到你！\n" NOR, ({me}));
		tell_object(obj, HIW+me->name()+"在远处对你叫到：下次别让我看到你！\n" NOR);
		tell_room(environment(obj), HIW+me->name()+"在远处对"+obj->name()+"叫到：下次别让我看到你！\n" NOR, ({obj}));
	}
}

void start_vendetta(object me, object obj)
{
	if( !me || !obj ) return;                               // Are we still exist( not becoming a corpse )?

	me->delete_temp("looking_for_trouble");

	if( (me->is_killing(obj->query("id")) && me->is_fighting(obj))	// Are we busy fighting?
	||      !living(me)                                                     // Are we capable for a fight?
	||      environment(me)!=environment(obj)       // Are we still in the same room?
	||      environment(me)->query("no_fight")      // Are we in a peace room?
	) return;

	// We found our vendetta opponent! Charge!
	message_vision(HIW "$N对$n喝道："+RANK_D->query_rude(obj)+"，竟敢对本门弟子下毒手，受死吧！\n" NOR, me, obj);
	me->kill_ob(obj);
}

void start_aggressive(object me, object obj)
{
	if( !me || !obj ) return;                               // Are we still exist( not becoming a corpse )?

	me->delete_temp("looking_for_trouble");

	if( (me->is_killing(obj->query("id")) && me->is_fighting(obj))	// Are we busy fighting?
	||      !living(me)                                                     // Are we capable for a fight?
	||      environment(me)!=environment(obj)       // Are we still in the same room?
	||      environment(me)->query("no_fight")      // Are we in a peace room?
	) return;

	// We got a nice victim! Kill him/her/it!!!
	me->kill_ob(obj);
}

void winner_reward(object killer, object victim)
{
	victim->set_temp("defeated_by", killer);
	killer->set_temp("defeat_obj", victim->query("id"));
	killer->defeated_enemy(victim);
}

void killer_reward(mixed killer, object victim)
{
	string vmark;

	// Call the mudlib killer apply.
	if (objectp(killer)) killer->killed_enemy(victim);

	if (objectp(killer) && userp(killer) && victim->query("race") == "人类") {
		if (victim->query("combat_exp") < killer->query("combat_exp"))
			killer->add("reputation", (victim->query("combat_exp") - killer->query("combat_exp")) / 100);
		else killer->add("reputation", (victim->query("combat_exp") - killer->query("combat_exp")) / 10);
		if ( (!victim->query_temp("faint_by") || victim->query_temp("faint_by") == killer)
		&& killer->query("combat_exp") < victim->query("combat_exp")
		&& killer->query("combat_exp") > victim->query("combat_exp")/4)
			killer->add("shen", -(int)victim->query("shen") / 10);
	}

	if( userp(victim) ) {
		if (objectp(killer)) {
			killer->add("PKS", 1);
			if (killer->query("combat_exp") < victim->query("combat_exp"))
				victim->add("reputation", (killer->query("combat_exp") - victim->query("combat_exp")) / 20);
		}
                        
		victim->add("death_count", 1);
		if (victim->query("combat_exp") >= 10000 * victim->query("death_times")) victim->add("death_times", 1);
		// Give the death penalty to the dying user.
		victim->add("shen", -(int)victim->query("shen") / 10);
		victim->add("combat_exp", -(int)victim->query("combat_exp") / 100);
		victim->delete("vendetta");
		if( victim->query("thief") ) victim->set("thief", (int)victim->query("thief") / 2);
		victim->add("potential", -(int)victim->query("potential")/4 );
		victim->skill_death_penalty();

		if (objectp(killer)) {
			if (victim->query_condition("killer") && userp(killer)) {
				CHANNEL_D->do_channel(this_object(), "rumor",
					sprintf("通缉犯%s被%s就地正法了。", victim->name(1), killer->name()));
			 } else {
				if (userp(killer)) {
					if (killer->query_temp("kill_other/"+victim->query("id"))) {
						CHANNEL_D->do_channel(this_object(), "rumor",
							sprintf("%s被%s杀害了。", victim->name(1), killer->name()));
						killer->apply_condition("killer",
							180 + killer->query_condition("killer") * 3 / 2);
					} else if (victim->query_temp("kill_other/"+killer->query("id")))
						CHANNEL_D->do_channel(this_object(), "rumor",
							sprintf("%s被%s正当防卫杀死了。",
								victim->name(1), killer->name()));
					else {
						CHANNEL_D->do_channel(this_object(), "rumor",
							sprintf("%s失手把%s杀死了。",
								killer->name(), victim->name(1)));
						killer->apply_condition("killer",
							180 + killer->query_condition("killer") * 3 / 2);
					}
					killer->delete_temp("kill_other/"+victim->query("id"));
					victim->delete_temp("kill_other/"+killer->query("id"));
				} else {
					switch(killer->query("race")) {
						case "家畜": vmark = "踩"; break;
						case "野兽": vmark = "咬"; break;
						case "飞禽": vmark = "啄"; break;
						case "昆虫": vmark = "叮"; break;
						default: vmark = "杀";
					}
					CHANNEL_D->do_channel(this_object(), "rumor",
						sprintf("%s被%s%s死了。", victim->name(1), killer->name(), vmark));
				}
			}
			CHANNEL_D->do_channel(this_object(), "sys", "凶手是："+killer->short(1));
		} else {
			if (killer[<2..<1] != "。")
				CHANNEL_D->do_channel(this_object(), "rumor", sprintf("%s%s死了。", victim->name(1), killer));
			else
				CHANNEL_D->do_channel(this_object(), "rumor", sprintf("%s%s", victim->name(1), killer));
		}
	} else if (objectp(killer) && victim->query("race") == "人类") killer->add("MKS", 1);

	if( stringp(vmark = victim->query("vendetta_mark")) )
	if (objectp(killer)) killer->add("vendetta/" + vmark, 1);
}
