Procházet zdrojové kódy

- Added battle_get_master which returns the master bl of a given object.
- Recoded battle_check_target to use battle_get_master, the src/target switch has been split into two, so that actual target and master target are seperately treated (same for source).


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

skotlex před 19 roky
rodič
revize
cfe71d744a
2 změnil soubory, kde provedl 133 přidání a 114 odebrání
  1. 5 0
      Changelog-Trunk.txt
  2. 128 114
      src/map/battle.c

+ 5 - 0
Changelog-Trunk.txt

@@ -4,6 +4,11 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2006/07/26
+	* Added battle_get_master which returns the master bl of a given object.
+	  [Skotlex]
+	* Recoded battle_check_target to use battle_get_master, the src/target
+	  switch has been split into two, so that actual target and master target are
+	  seperately treated (same for source). [Skotlex]
 	* Added support for "sc_end -1" which will clear all status changes. Added
 	  the constant SC_ALL so you can use in scripts "sc_end SC_ALL;" instead.
 	  [Skotlex]

+ 128 - 114
src/map/battle.c

@@ -2985,6 +2985,46 @@ int battle_check_undead(int race,int element)
 	return 0;
 }
 
+//Returns the upmost level master starting with the given object
+static struct block_list* battle_get_master(struct block_list *src)
+{
+	do {
+		switch (src->type) {
+			case BL_PET:
+				if (((TBL_PET*)src)->msd)
+					src = (struct block_list*)((TBL_PET*)src)->msd;
+				else
+					return src;
+				break;
+			case BL_MOB:
+				if (((TBL_MOB*)src)->master_id)
+					src = map_id2bl(((TBL_MOB*)src)->master_id);
+				else
+					return src;
+				break;
+			case BL_HOMUNCULUS:
+				if (((TBL_HOMUNCULUS*)src)->master)
+					src = (struct block_list*)((TBL_HOMUNCULUS*)src)->master;
+				else
+					return src;
+				break;
+			case BL_SKILL:
+				if (((TBL_SKILL*)src)->group && ((TBL_SKILL*)src)->group->src_id)
+					src = map_id2bl(((TBL_SKILL*)src)->group->src_id);
+				else
+					return src;
+				break;
+			default:
+				return src;
+		}
+#ifdef RECURSIVE_MASTER_CHECK
+	} while (src);
+#else
+	} while (0); //Single pass check.
+#endif
+	return src;
+}
+
 /*==========================================
  * Checks the state between two targets (rewritten by Skotlex)
  * (enemy, friend, party, guild, etc)
@@ -3013,43 +3053,67 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 			return -1;
 	}
 
-	if (target->type == BL_SKILL) //Needed out of the switch in case the ownership needs to be passed skill->mob->master
-	{
-		struct skill_unit *su = (struct skill_unit *)target;
-		if (!su->group)
-			return 0;
-		if (skill_get_inf2(su->group->skill_id)&INF2_TRAP)
-		{	//Only a few skills can target traps...
-			switch (battle_getcurrentskill(src))
-			{
-				case HT_REMOVETRAP:
-				case AC_SHOWER:
-				case WZ_HEAVENDRIVE:
-					state |= BCT_ENEMY;
-					strip_enemy = 0;
-					break;
-				default:
-					return 0;
+	//t_bl/s_bl hold the 'master' of the attack, while src/target are the actual
+	//objects involved.
+	if ((t_bl = battle_get_master(target)) == NULL)
+		t_bl = target;
+
+	if ((s_bl = battle_get_master(src)) == NULL)
+		s_bl = src;
+
+	switch (target->type)
+	{	//Checks on actual target
+		case BL_PC:
+			if (((TBL_PC*)target)->invincible_timer != -1 || pc_isinvisible((TBL_PC*)target))
+				return -1; //Cannot be targeted yet.
+			break;
+		case BL_MOB:
+			if (((TBL_MOB*)target)->special_state.ai == 2)
+			{	//Mines are sort of universal enemies.
+				state |= BCT_ENEMY;
+				strip_enemy = 0;
 			}
-		} else if (su->group->skill_id==WZ_ICEWALL)
-		{	//Icewall can be hit by anything except skills.
-			if (src->type == BL_SKILL)
+			break;
+		case BL_SKILL:
+		{
+			TBL_SKILL *su = (TBL_SKILL*)target;
+			if (!su->group)
 				return 0;
-			state |= BCT_ENEMY;
-			strip_enemy = 0;
-		} else	//Excepting traps and icewall, you should not be able to target skills.
+			if (skill_get_inf2(su->group->skill_id)&INF2_TRAP)
+			{	//Only a few skills can target traps...
+				switch (battle_getcurrentskill(src))
+				{
+					case HT_REMOVETRAP:
+					case AC_SHOWER:
+					case WZ_HEAVENDRIVE:
+						state |= BCT_ENEMY;
+						strip_enemy = 0;
+						break;
+					default:
+						return 0;
+				}
+			} else if (su->group->skill_id==WZ_ICEWALL)
+			{	//Icewall can be hit by anything except skills.
+				if (src->type == BL_SKILL)
+					return 0;
+				state |= BCT_ENEMY;
+				strip_enemy = 0;
+			} else	//Excepting traps and icewall, you should not be able to target skills.
+				return 0;
+		}
+		//Valid targets with no special checks here.
+		case BL_HOMUNCULUS:
+			break;
+		//All else not specified is an invalid target.
+		default:	
 			return 0;
-		if ((t_bl = map_id2bl(su->group->src_id)) == NULL)
-			t_bl = target; //Fallback on the trap itself, otherwise consider this a "versus caster" scenario.
 	}
 
 	switch (t_bl->type)
-	{
+	{	//Checks on target master
 		case BL_PC:
 		{
 			TBL_PC *sd = (TBL_PC*)t_bl;
-			if (sd->invincible_timer != -1 || pc_isinvisible(sd))
-				return -1; //Cannot be targeted yet.
 			if (sd->state.monster_ignore && t_bl != s_bl && flag&BCT_ENEMY)
 				return 0; //Global inmunity to attacks.
 			if (sd->special_state.killable && t_bl != s_bl)
@@ -3067,57 +3131,47 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 			
 			if (!agit_flag && md->guardian_data && md->guardian_data->guild_id)
 				return 0; //Disable guardians/emperiums owned by Guilds on non-woe times.
-			if (md->special_state.ai == 2)
-			{	//Mines are sort of universal enemies.
-				state |= BCT_ENEMY;
-				strip_enemy = 0;
-			}
-			if (md->master_id && (t_bl = map_id2bl(md->master_id)) == NULL)
-				t_bl = &md->bl; //Fallback on the mob itself, otherwise consider this a "versus master" scenario.
 			break;
 		}
+	}
+
+	switch(src->type)
+  	{	//Checks on actual src type
+		case BL_MOB:
+			if (!agit_flag && ((TBL_MOB*)src)->guardian_data && ((TBL_MOB*)src)->guardian_data->guild_id)
+				return 0; //Disable guardians/emperium owned by Guilds on non-woe times.
+			break;
 		case BL_PET:
+			if (t_bl->type != BL_MOB && flag&BCT_ENEMY)
+				return 0; //Pet may not attack non-mobs.
+			if (t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->guardian_data && flag&BCT_ENEMY)
+				return 0; //pet may not attack Guardians/Emperium
+			break;
+		case BL_SKILL:
 		{
-			return 0; //Pets cannot be targetted.
-		}
-		case BL_HOMUNCULUS:
-		{	
-			 //For some mysterious reason ground-skills can't target homun.
-			if (src->type == BL_SKILL)
-				return 0;
-			//Just fallback on master.
-			t_bl=(struct block_list *)((TBL_HOMUNCULUS*)target)->master;
-			if (((TBL_PC*)t_bl)->state.monster_ignore && t_bl != s_bl && flag&BCT_ENEMY)
+			struct skill_unit *su = (struct skill_unit *)src;
+			if (!su->group)
 				return 0;
-			break;
-		}
-		case BL_SKILL: //Skill with no owner? Kinda odd... but.. let it through.
-			break;
-		default:	//Invalid target
-			return 0;
-	}
 
-	if (src->type == BL_SKILL)
-	{
-		struct skill_unit *su = (struct skill_unit *)src;
-		if (!su->group)
-			return 0;
+			//For some mysterious reason ground-skills can't target homun.
+			if (target->type == BL_HOMUNCULUS)
+				return 0;
 
-		if (su->group->src_id == target->id)
-		{
-			int inf2;
-			inf2 = skill_get_inf2(su->group->skill_id);
-			if (inf2&INF2_NO_TARGET_SELF)
-				return -1;
-			if (inf2&INF2_TARGET_SELF)
-				return 1;
+			if (su->group->src_id == target->id)
+			{
+				int inf2;
+				inf2 = skill_get_inf2(su->group->skill_id);
+				if (inf2&INF2_NO_TARGET_SELF)
+					return -1;
+				if (inf2&INF2_TARGET_SELF)
+					return 1;
+			}
+			break;
 		}
-		if ((s_bl = map_id2bl(su->group->src_id)) == NULL)
-			s_bl = src; //Fallback on the trap itself, otherwise consider this a "caster versus enemy" scenario.
 	}
 
 	switch (s_bl->type)
-	{
+	{	//Checks on source master
 		case BL_PC:
 		{
 			TBL_PC *sd = (TBL_PC*) s_bl;
@@ -3149,24 +3203,8 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 		case BL_MOB:
 		{
 			TBL_MOB*md = (TBL_MOB*)s_bl;
-#ifdef RECURSIVE_MASTER_CHECK
-			struct block_list *tmp_bl = NULL;
-			TBL_MOB *tmp_md = NULL;
-#endif
 			if (!agit_flag && md->guardian_data && md->guardian_data->guild_id)
 				return 0; //Disable guardians/emperium owned by Guilds on non-woe times.
-#ifdef RECURSIVE_MASTER_CHECK
-			tmp_md = md;
-			while(tmp_md->master_id && (tmp_bl = map_id2bl(tmp_md->master_id))){
-				if(t_bl->id == tmp_bl->id){
-					state |= BCT_PARTY;
-					break;
-				}
-				if(tmp_bl->type != BL_MOB)
-					break;
-				tmp_md = (TBL_MOB *)tmp_bl;
-			}
-#endif
 			if(md->state.killer) // Is on a rampage too :D
 				state |= BCT_ENEMY;
 			else if (!md->special_state.ai) { //Normal mobs.
@@ -3178,38 +3216,13 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 				if (t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai)
 					state |= BCT_ENEMY; //Natural enemy for AI mobs are normal mobs.
 			}
-			if (md->master_id && (s_bl = map_id2bl(md->master_id)) == NULL)
-				s_bl = &md->bl; //Fallback on the mob itself, otherwise consider this a "from master" scenario.
-			break;
-		}
-		case BL_HOMUNCULUS:
-		{
-			//[blackhole89] -- check homunculus' targeting by their masters.
-			if (t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai)
-				state |= BCT_ENEMY; //Default enemy. Normal mobs.
-			//Pass on to master.
-			s_bl=(struct block_list *)((struct homun_data*)src)->master;
 			break;
 		}
-		case BL_PET:
-		{
-			TBL_PET *pd = (TBL_PET*)s_bl;
-			if (t_bl->type != BL_MOB && flag&BCT_ENEMY)
-				return 0; //Pet may not attack non-mobs.
-			if (t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->guardian_data && flag&BCT_ENEMY)
-				return 0; //pet may not attack Guardians/Emperium
-			if (t_bl->type != BL_PC)
-				state |= BCT_ENEMY; //Stock enemy type.
-			if (pd->msd)
-				s_bl = &pd->msd->bl; //"My master's enemies are my enemies..."
-			break;
-		}
-		case BL_SKILL: //Skill with no owner? Fishy, but let it through.
-			break;
-		case BL_NPC:	// allows NPC-set skill units to proceed [blackhole89]
+		default:
+		//Need some sort of default behaviour for unhandled types.
+			if (t_bl->type != s_bl->type)
+				state |= BCT_ENEMY;
 			break;
-		default:	//Invalid source of attack?
-			return 0;
 	}
 	
 	if ((flag&BCT_ALL) == BCT_ALL) { //All actually stands for all attackable chars 
@@ -3217,7 +3230,8 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 			return 1;
 		else
 			return -1;
-	} else if (flag == BCT_NOONE) //Why would someone use this? no clue.
+	} else
+	if (flag == BCT_NOONE) //Why would someone use this? no clue.
 		return -1;
 	
 	if (t_bl == s_bl)