summaryrefslogtreecommitdiff
path: root/src/map/battle.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/battle.c')
-rw-r--r--src/map/battle.c242
1 files changed, 128 insertions, 114 deletions
diff --git a/src/map/battle.c b/src/map/battle.c
index 72d9cddf1..f11e014fc 100644
--- a/src/map/battle.c
+++ b/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)