Browse Source

* More mercenary updates.
- Implemented Mercenary Die, Damage, Run Away when master dies.
- Log mercenary damage and gives exp to Master.
- Some little bugs.
* Fixed Bubble Gums effect works on mvp_sd not sd (according to Doddler).

NOTE: Now you can summon a mercenary, make it attack (not skills), follow you even on map change.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@13158 54d463be-8e91-2dee-dedb-b68131a5f0ec

zephyrus 17 years ago
parent
commit
908c3d2e86
8 changed files with 197 additions and 124 deletions
  1. 43 34
      src/map/clif.c
  2. 1 0
      src/map/clif.h
  3. 14 2
      src/map/mercenary.c
  4. 2 0
      src/map/mercenary.h
  5. 72 55
      src/map/mob.c
  6. 23 6
      src/map/pc.c
  7. 4 2
      src/map/status.c
  8. 38 25
      src/map/unit.c

+ 43 - 34
src/map/clif.c

@@ -7881,19 +7881,28 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 	}
 
 	//homunculus [blackhole89]
-	if(merc_is_hom_active(sd->hd)) {
+	if( merc_is_hom_active(sd->hd) )
+	{
 		map_addblock(&sd->hd->bl);
 		clif_spawn(&sd->hd->bl);
 		clif_send_homdata(sd,0,0);
 		clif_hominfo(sd,sd->hd,1);
 		clif_hominfo(sd,sd->hd,0); //for some reason, at least older clients want this sent twice
 		clif_homskillinfoblock(sd);
-		if (battle_config.hom_setting&0x8)
+		if( battle_config.hom_setting&0x8 )
 			status_calc_bl(&sd->hd->bl, SCB_SPEED); //Homunc mimic their master's speed on each map change
-		if (!(battle_config.hom_setting&0x2))
+		if( !(battle_config.hom_setting&0x2) )
 			skill_unit_move(&sd->hd->bl,gettick(),1); // apply land skills immediately
 	}
 
+	if( sd->md )
+	{
+		map_addblock(&sd->md->bl);
+		clif_spawn(&sd->md->bl);
+		clif_mercenary_info(sd);
+		clif_mercenary_skillblock(sd);
+	}
+
 	if(sd->state.connect_new) {
 		int lv;
 		sd->state.connect_new = 0;
@@ -12364,6 +12373,35 @@ void clif_send_quest_status(struct map_session_data * sd, int quest_id, bool act
 /*==========================================
  * Mercenary System
  *==========================================*/
+void clif_mercenary_updatestatus(struct map_session_data *sd, int type)
+{
+	struct mercenary_data *md;
+	int fd;
+	if( sd == NULL || (md = sd->md) == NULL )
+		return;
+
+	fd = sd->fd;
+	WFIFOHEAD(fd,8);
+	WFIFOW(fd,0) = 0x02a2;
+	WFIFOW(fd,2) = type;
+	switch( type )
+	{
+		case SP_HP:
+			WFIFOL(fd,4) = md->battle_status.hp;
+			break;
+		case SP_MAXHP:
+			WFIFOL(fd,4) = md->battle_status.max_hp;
+			break;
+		case SP_SP:
+			WFIFOL(fd,4) = md->battle_status.sp;
+			break;
+		case SP_MAXSP:
+			WFIFOL(fd,4) = md->battle_status.max_sp;
+			break;
+	}
+	WFIFOSET(fd,8);
+}
+
 void clif_mercenary_info(struct map_session_data *sd)
 {
 	int fd;
@@ -12389,7 +12427,7 @@ void clif_mercenary_info(struct map_session_data *sd)
 	WFIFOW(fd,14) = status->def + (status->vit/2);
 	WFIFOW(fd,16) = status->mdef;
 	WFIFOW(fd,18) = status->flee;
-	WFIFOW(fd,20) = status->aspd_rate;
+	WFIFOW(fd,20) = status->amotion;
 	safestrncpy((char*)WFIFOP(fd,22), md->db->name, NAME_LENGTH);
 	WFIFOW(fd,46) = md->db->lv;
 	WFIFOL(fd,48) = status->hp;
@@ -12400,7 +12438,7 @@ void clif_mercenary_info(struct map_session_data *sd)
 	WFIFOW(fd,68) = 0; // Loyalty
 	WFIFOL(fd,70) = 0; // Summon Count
 	WFIFOL(fd,74) = md->mercenary.kill_count;
-	WFIFOW(fd,78) = 0;
+	WFIFOW(fd,78) = md->battle_status.rhw.range;
 	WFIFOSET(fd,80);
 }
 
@@ -12435,35 +12473,6 @@ void clif_mercenary_skillblock(struct map_session_data *sd)
 	WFIFOSET(fd,len);
 }
 
-void clif_mercenary_updatestatus(struct map_session_data *sd, int type)
-{
-	struct mercenary_data *md;
-	int fd;
-	if( sd == NULL || (md = sd->md) == NULL )
-		return;
-
-	fd = sd->fd;
-	WFIFOHEAD(fd,8);
-	WFIFOW(fd,0) = 0x02a2;
-	WFIFOW(fd,2) = type;
-	switch( type )
-	{
-		case SP_HP:
-			WFIFOL(fd,4) = md->battle_status.hp;
-			break;
-		case SP_MAXHP:
-			WFIFOL(fd,4) = md->battle_status.max_hp;
-			break;
-		case SP_SP:
-			WFIFOL(fd,4) = md->battle_status.sp;
-			break;
-		case SP_MAXSP:
-			WFIFOL(fd,4) = md->battle_status.max_sp;
-			break;
-	}
-	WFIFOSET(fd,8);
-}
-
 void clif_parse_mercenary_action(int fd, struct map_session_data* sd)
 {
 	int option = RFIFOB(fd,2);

+ 1 - 0
src/map/clif.h

@@ -443,5 +443,6 @@ void clif_Adopt_reply(struct map_session_data *sd, int type);
 void clif_mercenary_info(struct map_session_data *sd);
 void clif_mercenary_skillblock(struct map_session_data *sd);
 void clif_mercenary_message(int fd, int message);
+void clif_mercenary_updatestatus(struct map_session_data *sd, int type);
 
 #endif /* _CLIF_H_ */

+ 14 - 2
src/map/mercenary.c

@@ -132,10 +132,10 @@ int merc_delete(struct mercenary_data *md, int reply)
 	merc_contract_stop(md);
 
 	if( !sd )
-		return unit_free(&md->bl, 1);
+		return unit_free(&md->bl, 0);
 	clif_mercenary_message(sd->fd, reply);
 	
-	return unit_remove_map(&md->bl, 1);
+	return unit_remove_map(&md->bl, 0);
 }
 
 void merc_contract_stop(struct mercenary_data *md)
@@ -213,6 +213,17 @@ int merc_data_received(struct s_mercenary *merc, bool flag)
 	return 1;
 }
 
+void mercenary_damage(struct mercenary_data *md, struct block_list *src, int hp, int sp)
+{
+	clif_mercenary_updatestatus(md->master, SP_HP);
+}
+
+int mercenary_dead(struct mercenary_data *md, struct block_list *src)
+{
+	merc_delete(md, 1);
+	return 0;
+}
+
 int read_mercenarydb(void)
 {
 	FILE *fp;
@@ -292,6 +303,7 @@ int read_mercenarydb(void)
 			status->ele_lv = 1;
 		}
 
+		status->aspd_rate = 1000;
 		status->speed = atoi(str[22]);
 		status->adelay = atoi(str[23]);
 		status->amotion = atoi(str[24]);

+ 2 - 0
src/map/mercenary.h

@@ -41,6 +41,8 @@ struct view_data * merc_get_viewdata(int class_);
 int merc_create(struct map_session_data *sd, int class_, unsigned int lifetime);
 int merc_data_received(struct s_mercenary *merc, bool flag);
 int mercenary_save(struct mercenary_data *md);
+void mercenary_damage(struct mercenary_data *md, struct block_list *src, int hp, int sp);
+int mercenary_dead(struct mercenary_data *md, struct block_list *src);
 int do_init_mercenary(void);
 int merc_delete(struct mercenary_data *md, int reply);
 void merc_contract_stop(struct mercenary_data *md);

+ 72 - 55
src/map/mob.c

@@ -21,6 +21,7 @@
 #include "status.h"
 #include "mob.h"
 #include "homunculus.h"
+#include "mercenary.h"
 #include "guild.h"
 #include "itemdb.h"
 #include "skill.h"
@@ -1293,9 +1294,9 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
 			}
 		}
 		else
-		if( (abl= map_id2bl(md->attacked_id)) && (!tbl || mob_can_changetarget(md, abl, mode)) )
+		if( (abl = map_id2bl(md->attacked_id)) && (!tbl || mob_can_changetarget(md, abl, mode)) )
 		{
-			if (md->bl.m != abl->m || abl->prev == NULL
+			if( md->bl.m != abl->m || abl->prev == NULL
 			|| (dist = distance_bl(&md->bl, abl)) >= MAX_MINCHASE
 			|| battle_check_target(&md->bl, abl, BCT_ENEMY) <= 0
 			|| (battle_config.mob_ai&0x2 && !status_check_skilluse(&md->bl, abl, 0, 0)) //Retaliate check
@@ -1740,63 +1741,78 @@ int mob_respawn(int tid, unsigned int tick, int id, intptr data)
 void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
 {
 	int char_id = 0, flag = 0;
-	if(damage < 0) return; //Do nothing for absorbed damage.
 
-	if(!damage && !(src->type&DEFAULT_ENEMY_TYPE(md)))
+	if( damage < 0 )
+		return; //Do nothing for absorbed damage.
+	if( !damage && !(src->type&DEFAULT_ENEMY_TYPE(md)) )
 		return; //Do not log non-damaging effects from non-enemies.
 
-	switch (src->type) {
-	case BL_PC: 
+	switch( src->type )
 	{
-		struct map_session_data *sd = (TBL_PC*)src;
-		char_id = sd->status.char_id;
-		if (damage)
-			md->attacked_id = src->id;
-		break;
-	}
-	case BL_HOM:	//[orn]
-	{
-		struct homun_data *hd = (TBL_HOM*)src;
-		flag = 1;
-		if (hd->master)
-			char_id = hd->master->status.char_id;
-		if (damage)
-			md->attacked_id = src->id;
-		break;
-	}
-	case BL_PET:
-	{
-		struct pet_data *pd = (TBL_PET*)src;
-		if (battle_config.pet_attack_exp_to_master && pd->msd) {
-			char_id = pd->msd->status.char_id;
-			damage=(damage*battle_config.pet_attack_exp_rate)/100; //Modify logged damage accordingly.
+		case BL_PC: 
+		{
+			struct map_session_data *sd = (TBL_PC*)src;
+			char_id = sd->status.char_id;
+			if( damage )
+				md->attacked_id = src->id;
+			break;
 		}
-		//Let mobs retaliate against the pet's master [Skotlex]
-		if(pd->msd && damage)
-			md->attacked_id = pd->msd->bl.id;
-		break;
-	}
-	case BL_MOB:
-	{
-		struct mob_data* md2 = (TBL_MOB*)src;
-		if(md2->special_state.ai && md2->master_id) {
-			struct map_session_data* msd = map_id2sd(md2->master_id);
-			if (msd) char_id = msd->status.char_id;
+		case BL_HOM:
+		{
+			struct homun_data *hd = (TBL_HOM*)src;
+			flag = 1;
+			if( hd->master )
+				char_id = hd->master->status.char_id;
+			if( damage )
+				md->attacked_id = src->id;
+			break;
 		}
-		if (!damage)
+		case BL_MER:
+		{
+			struct mercenary_data *mer = (TBL_MER*)src;
+			if( mer->master )
+				char_id = mer->master->status.char_id;
+			if( damage )
+				md->attacked_id = src->id;
 			break;
-		//Let players decide whether to retaliate versus the master or the mob. [Skotlex]
-		if (md2->master_id && battle_config.retaliate_to_master)
-			md->attacked_id = md2->master_id;
-		else
+		}
+		case BL_PET:
+		{
+			struct pet_data *pd = (TBL_PET*)src;
+			if( battle_config.pet_attack_exp_to_master && pd->msd )
+			{
+				char_id = pd->msd->status.char_id;
+				damage = (damage*battle_config.pet_attack_exp_rate)/100; //Modify logged damage accordingly.
+			}
+			//Let mobs retaliate against the pet's master [Skotlex]
+			if( pd->msd && damage )
+				md->attacked_id = pd->msd->bl.id;
+			break;
+		}
+		case BL_MOB:
+		{
+			struct mob_data* md2 = (TBL_MOB*)src;
+			if( md2->special_state.ai && md2->master_id )
+			{
+				struct map_session_data* msd = map_id2sd(md2->master_id);
+				if( msd )
+					char_id = msd->status.char_id;
+			}
+			if( !damage )
+				break;
+			//Let players decide whether to retaliate versus the master or the mob. [Skotlex]
+			if( md2->master_id && battle_config.retaliate_to_master )
+				md->attacked_id = md2->master_id;
+			else
+				md->attacked_id = src->id;
+			break;
+		}
+		default: //For all unhandled types.
 			md->attacked_id = src->id;
-		break;
-	}
-	default: //For all unhandled types.
-		md->attacked_id = src->id;
 	}
-	//Log damage...
-	if(char_id) {
+	
+	if( char_id )
+	{ //Log damage...
 		int i,minpos;
 		unsigned int mindmg;
 		for(i=0,minpos=DAMAGELOG_SIZE-1,mindmg=UINT_MAX;i<DAMAGELOG_SIZE;i++){
@@ -1881,14 +1897,14 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 	unsigned int mvp_damage, tick = gettick();
 	unsigned short flaghom = 1; // [Zephyrus] Does the mob only received damage from homunculus?
 
-	if(src && src->type == BL_PC)
+	status = &md->status;
+
+	if( src && src->type == BL_PC )
 	{
 		sd = (struct map_session_data *)src;
 		mvp_sd = sd;
 	}
 
-	status = &md->status;
-		
 	if( md->guardian_data && md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS )
 		guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
 
@@ -2132,14 +2148,15 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 			// attempt to drop the item
 			if (rand() % 10000 >= drop_rate)
 			{	// Double try by Bubble Gum
-				if (!(sd && sd->sc.data[SC_ITEMBOOST] && rand() % 10000 < drop_rate))
+				if (!(mvp_sd && mvp_sd->sc.data[SC_ITEMBOOST] && rand() % 10000 < drop_rate))
 					continue;
 			}
 
 			ditem = mob_setdropitem(md->db->dropitem[i].nameid, 1);
 
 			//A Rare Drop Global Announce by Lupus
-			if(drop_rate<=battle_config.rare_drop_announce) {
+			if( drop_rate <= battle_config.rare_drop_announce )
+			{
 				struct item_data *i_data;
 				char message[128];
 				i_data = itemdb_search(ditem->item_data.nameid);

+ 23 - 6
src/map/pc.c

@@ -873,7 +873,7 @@ int pc_reg_received(struct map_session_data *sd)
 	sd->cashPoints = pc_readaccountreg(sd,"#CASHPOINTS");
 	sd->kafraPoints = pc_readaccountreg(sd,"#KAFRAPOINTS");
 
-	if ((sd->class_&MAPID_BASEMASK)==MAPID_TAEKWON)
+	if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON )
 	{	//Better check for class rather than skill to prevent "skill resets" from unsetting this
 		sd->mission_mobid = pc_readglobalreg(sd,"TK_MISSION_ID");
 		sd->mission_count = pc_readglobalreg(sd,"TK_MISSION_COUNT");
@@ -3571,32 +3571,42 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
 		//Tag player for rewarping after map-loading is done. [Skotlex]
 		sd->state.rewarp = 1;
 	
-	sd->mapindex =  mapindex;
+	sd->mapindex = mapindex;
 	sd->bl.m = m;
 	sd->bl.x = sd->ud.to_x = x;
 	sd->bl.y = sd->ud.to_y = y;
 
-	if (sd->status.guild_id > 0 && map[m].flag.gvg_castle)
+	if( sd->status.guild_id > 0 && map[m].flag.gvg_castle )
 	{	// Increased guild castle regen [Valaris]
 		struct guild_castle *gc = guild_mapindex2gc(sd->mapindex);
 		if(gc && gc->guild_id == sd->status.guild_id)
 			sd->regen.state.gc = 1;
 	}
 
-	if(sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0) {
+	if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 )
+	{
 		sd->pd->bl.m = m;
 		sd->pd->bl.x = sd->pd->ud.to_x = x;
 		sd->pd->bl.y = sd->pd->ud.to_y = y;
 		sd->pd->ud.dir = sd->ud.dir;
 	}
 
-	if(merc_is_hom_active(sd->hd)) {	//orn
+	if( merc_is_hom_active(sd->hd) )
+	{
 		sd->hd->bl.m = m;
 		sd->hd->bl.x = sd->hd->ud.to_x = x;
 		sd->hd->bl.y = sd->hd->ud.to_y = y;
 		sd->hd->ud.dir = sd->ud.dir;
 	}
 
+	if( sd->md )
+	{
+		sd->md->bl.m = m;
+		sd->md->bl.x = sd->hd->ud.to_x = x;
+		sd->md->bl.y = sd->hd->ud.to_y = y;
+		sd->md->ud.dir = sd->ud.dir;
+	}
+
 	return 0;
 }
 
@@ -4925,9 +4935,12 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 			pet_unlocktarget(sd->pd);
 	}
 
-	if(sd->status.hom_id > 0 && battle_config.homunculus_auto_vapor)	//orn
+	if( sd->status.hom_id > 0 && battle_config.homunculus_auto_vapor )
 		merc_hom_vaporize(sd, 0);
 
+	if( sd->md )
+		merc_delete(sd->md, 3); // Your mercenary soldier has ran away.
+
 	// Leave duel if you die [LuzZza]
 	if(battle_config.duel_autoleave_when_die) {
 		if(sd->duel_group > 0)
@@ -4968,6 +4981,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 			status_calc_mob(md, 0);
 			status_percent_heal(src,10,0);
 		}
+		src = battle_get_master(src); // Maybe Player Summon
 	}
 	break;
 	case BL_PET: //Pass on to master...
@@ -4976,6 +4990,9 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 	case BL_HOM:
 		src = &((TBL_HOM*)src)->master->bl;
 	break;
+	case BL_MER:
+		src = &((TBL_MER*)src)->master->bl;
+	break;
 	}
 
 	if (src && src->type == BL_PC)

+ 4 - 2
src/map/status.c

@@ -698,6 +698,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 		case BL_PC:  pc_damage((TBL_PC*)target,src,hp,sp); break;
 		case BL_MOB: mob_damage((TBL_MOB*)target, src, hp); break;
 		case BL_HOM: merc_damage((TBL_HOM*)target,src,hp,sp); break;
+		case BL_MER: mercenary_damage((TBL_MER*)target,src,hp,sp); break;
 	}
 
 	if (status->hp)
@@ -717,6 +718,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 		case BL_PC:  flag = pc_dead((TBL_PC*)target,src); break;
 		case BL_MOB: flag = mob_dead((TBL_MOB*)target, src, flag&4?3:0); break;
 		case BL_HOM: flag = merc_hom_dead((TBL_HOM*)target,src); break;
+		case BL_MER: flag = mercenary_dead((TBL_MER*)target,src); break;
 		default:	//Unhandled case, do nothing to object.
 			flag = 0;
 			break;
@@ -2394,9 +2396,9 @@ int status_calc_mercenary(struct mercenary_data *md, int first)
 	}
 
 	status_calc_misc(&md->bl, status, md->db->lv);
-	status_cpy(&md->base_status, status);
+	status_cpy(&md->battle_status, status);
 	status_calc_bl(&md->bl, SCB_ALL);
-		
+
 	return 0;
 }
 

+ 38 - 25
src/map/unit.c

@@ -1238,20 +1238,23 @@ int unit_attack(struct block_list *src,int target_id,int continuous)
 
 	nullpo_retr(0, ud = unit_bl2ud(src));
 
-	target=map_id2bl(target_id);
-	if(target==NULL || status_isdead(target)) {
+	target = map_id2bl(target_id);
+	if( target==NULL || status_isdead(target) )
+	{
 		unit_unattackable(src);
 		return 1;
 	}
 
-	if( src->type == BL_PC ){
+	if( src->type == BL_PC )
+	{
 		TBL_PC* sd = (TBL_PC*)src;
 		if( target->type == BL_NPC )
-		{// monster npcs [Valaris]
+		{ // monster npcs [Valaris]
 			npc_click(sd,(TBL_NPC*)target); // submitted by leinsirk10 [Celest]
 			return 0;
-		} else if( pc_is90overweight(sd) )
-		{// overwheight - stop attacking and walking
+		}
+		else if( pc_is90overweight(sd) )
+		{ // overwheight - stop attacking and walking
 			unit_stop_attack(src);
 			unit_stop_walking(src,1);
 			return 0;
@@ -1427,42 +1430,46 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
 	struct mob_data *md = NULL;
 	int range;
 	
-	if((ud=unit_bl2ud(src))==NULL)
+	if( (ud=unit_bl2ud(src))==NULL )
 		return 0;
-	if(ud->attacktimer != tid){
+	if( ud->attacktimer != tid )
+	{
 		ShowError("unit_attack_timer %d != %d\n",ud->attacktimer,tid);
 		return 0;
 	}
+
 	sd = BL_CAST(BL_PC, src);
 	md = BL_CAST(BL_MOB, src);
 	ud->attacktimer = INVALID_TIMER;
 	target=map_id2bl(ud->target);
 
-	if(src == NULL || src->prev == NULL || target==NULL || target->prev == NULL)
+	if( src == NULL || src->prev == NULL || target==NULL || target->prev == NULL )
 		return 0;
 
-	if(status_isdead(src) || status_isdead(target) || !status_check_skilluse(src, target, 0, 0))
+	if( status_isdead(src) || status_isdead(target) || !status_check_skilluse(src, target, 0, 0) )
 		return 0; // can't attack under these conditions
 
-	if (src->m != target->m)
+	if( src->m != target->m )
 	{
-		if (src->type == BL_MOB && mob_warpchase((TBL_MOB*)src, target))
+		if( src->type == BL_MOB && mob_warpchase((TBL_MOB*)src, target) )
 			return 1; // Follow up.
 		return 0;
 	}
 
-	if(ud->skilltimer != -1 && !(sd && pc_checkskill(sd,SA_FREECAST) > 0))
+	if( ud->skilltimer != -1 && !(sd && pc_checkskill(sd,SA_FREECAST) > 0) )
 		return 0; // can't attack while casting
 	
-	if(!battle_config.sdelay_attack_enable && DIFF_TICK(ud->canact_tick,tick) > 0 && !(sd && pc_checkskill(sd,SA_FREECAST) > 0))
-	{	// attacking when under cast delay has restrictions:
-		if (tid == -1) { //requested attack.
+	if( !battle_config.sdelay_attack_enable && DIFF_TICK(ud->canact_tick,tick) > 0 && !(sd && pc_checkskill(sd,SA_FREECAST) > 0) )
+	{ // attacking when under cast delay has restrictions:
+		if( tid == -1 )
+		{ //requested attack.
 			if(sd) clif_skill_fail(sd,1,4,0);
 			return 0;
 		}
 		//Otherwise, we are in a combo-attack, delay this until your canact time is over. [Skotlex]
-		if(ud->state.attack_continue) {
-			if (DIFF_TICK(ud->canact_tick, ud->attackabletime) > 0)
+		if( ud->state.attack_continue )
+		{
+			if( DIFF_TICK(ud->canact_tick, ud->attackabletime) > 0 )
 				ud->attackabletime = ud->canact_tick;
 			ud->attacktimer=add_timer(ud->attackabletime,unit_attack_timer,src->id,0);
 		}
@@ -1472,20 +1479,24 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
 	sstatus = status_get_status_data(src);
 	range = sstatus->rhw.range;
 	
-	if(!sd || sd->status.weapon != W_BOW) range++; //Dunno why everyone but bows gets this extra range...
-	if(unit_is_walking(target)) range++; //Extra range when chasing
+	if( !sd || sd->status.weapon != W_BOW )
+		range++; //Dunno why everyone but bows gets this extra range...
+	if( unit_is_walking(target) )
+		range++; //Extra range when chasing
 
-	if(!check_distance_bl(src,target,range) ) {
-		//Chase if required.
+	if( !check_distance_bl(src,target,range) )
+	{ //Chase if required.
 		if(sd)
 			clif_movetoattack(sd,target);
 		else if(ud->state.attack_continue)
 			unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy|2);
 		return 1;
 	}
-	if(!battle_check_range(src,target,range)) {
+	if( !battle_check_range(src,target,range) )
+	{
 	  	//Within range, but no direct line of attack
-		if(ud->state.attack_continue) {
+		if( ud->state.attack_continue )
+		{
 			if(ud->chaserange > 2) ud->chaserange-=2;
 			unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy|2);
 		}
@@ -1496,7 +1507,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
 	//Non-players use the sync packet on the walk timer. [Skotlex]
 	if (tid == -1 && sd) clif_fixpos(src);
 
-	if(DIFF_TICK(ud->attackabletime,tick) <= 0)
+	if( DIFF_TICK(ud->attackabletime,tick) <= 0 )
 	{
 		if (battle_config.attack_direction_change && (src->type&battle_config.attack_direction_change)) {
 			ud->dir = map_calc_dir(src, target->x,target->y );
@@ -2097,6 +2108,8 @@ int unit_free(struct block_list *bl, int clrtype)
 			}
 			if( sd )
 				sd->md = NULL;
+
+			merc_contract_stop(md);
 			break;
 		}
 	}