summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2015-11-21 15:44:24 +0100
committerHaru <haru@dotalux.com>2015-12-06 15:18:59 +0100
commit9fef13d4d2e0eab3376ea95b3cb8783d48d19dda (patch)
treed1d66ac73e72bc18a96b88d202586b1c41b6ff36
parentcea55140cc2b5d1012813f8abc028ba04bd625c6 (diff)
downloadhercules-9fef13d4d2e0eab3376ea95b3cb8783d48d19dda.tar.gz
hercules-9fef13d4d2e0eab3376ea95b3cb8783d48d19dda.tar.bz2
hercules-9fef13d4d2e0eab3376ea95b3cb8783d48d19dda.tar.xz
hercules-9fef13d4d2e0eab3376ea95b3cb8783d48d19dda.zip
Refactored/fixed race handling for bonuses that store it as a bitmask
- The following bonuses now work correctly with RC_DemiPlayer, RC_NonDemiPlayer, RC_NonDemiHuman, RC_Nonplayer: * bIgnoreDefRace * bIgnoreMdefRace * bDefRatioAtkRace * bAddMonsterDropChainItem (bonus3) * bAddMonsterDropItem (bonus3) - A new function (map->race_id2mask) is provided, to easily and efficiently generate a bitmask from a race ID. - The RC_ALL race ID is mapped to RC_BOSS and RC_NONBOSS, for backwards compatibility. Signed-off-by: Haru <haru@dotalux.com>
-rw-r--r--src/map/battle.c32
-rw-r--r--src/map/map.c32
-rw-r--r--src/map/map.h79
-rw-r--r--src/map/mob.c4
-rw-r--r--src/map/pc.c107
5 files changed, 153 insertions, 101 deletions
diff --git a/src/map/battle.c b/src/map/battle.c
index d1cdd19c4..7fbbcd0d5 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -3714,8 +3714,8 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
//Ignore Defense?
if (!flag.imdef && (
sd->bonus.ignore_mdef_ele & ( 1 << tstatus->def_ele ) ||
- sd->bonus.ignore_mdef_race & ( 1 << tstatus->race ) ||
- sd->bonus.ignore_mdef_race & ( is_boss(target) ? 1 << RC_BOSS : 1 << RC_NONBOSS )
+ sd->bonus.ignore_mdef_race & map->race_id2mask(tstatus->race) ||
+ sd->bonus.ignore_mdef_race & map->race_id2mask(is_boss(target) ? RC_BOSS : RC_NONBOSS)
))
flag.imdef = 1;
}
@@ -5195,19 +5195,19 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
if( (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 &&
(tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) )
ATK_ADDRATE(-i);
- if( skill_id != PA_SACRIFICE && skill_id != MO_INVESTIGATE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != PA_SHIELDCHAIN && !flag.cri )
- { //Elemental/Racial adjustments
- if( sd->right_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) ||
- sd->right_weapon.def_ratio_atk_race & (1<<tstatus->race) ||
- sd->right_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS))
+ if (skill_id != PA_SACRIFICE && skill_id != MO_INVESTIGATE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != PA_SHIELDCHAIN && !flag.cri) {
+ //Elemental/Racial adjustments
+ if (sd->right_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele)
+ || sd->right_weapon.def_ratio_atk_race & map->race_id2mask(tstatus->race)
+ || sd->right_weapon.def_ratio_atk_race & map->race_id2mask(is_boss(target) ? RC_BOSS : RC_NONBOSS)
)
flag.pdef = 1;
- if( sd->left_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) ||
- sd->left_weapon.def_ratio_atk_race & (1<<tstatus->race) ||
- sd->left_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS))
- )
- { //Pass effect onto right hand if configured so. [Skotlex]
+ if (sd->left_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele)
+ || sd->left_weapon.def_ratio_atk_race & map->race_id2mask(tstatus->race)
+ || sd->left_weapon.def_ratio_atk_race & map->race_id2mask(is_boss(target) ? RC_BOSS : RC_NONBOSS)
+ ) {
+ //Pass effect onto right hand if configured so. [Skotlex]
if (battle_config.left_cardfix_to_right && flag.rh)
flag.pdef = 1;
else
@@ -5219,15 +5219,15 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
//Ignore Defense?
if (!flag.idef && (
sd->right_weapon.ignore_def_ele & (1<<tstatus->def_ele) ||
- sd->right_weapon.ignore_def_race & (1<<tstatus->race) ||
- sd->right_weapon.ignore_def_race & (is_boss(target)?1<<RC_BOSS:1<<RC_NONBOSS)
+ sd->right_weapon.ignore_def_race & map->race_id2mask(tstatus->race) ||
+ sd->right_weapon.ignore_def_race & map->race_id2mask(is_boss(target) ? RC_BOSS : RC_NONBOSS)
))
flag.idef = 1;
if (!flag.idef2 && (
sd->left_weapon.ignore_def_ele & (1<<tstatus->def_ele) ||
- sd->left_weapon.ignore_def_race & (1<<tstatus->race) ||
- sd->left_weapon.ignore_def_race & (is_boss(target)?1<<RC_BOSS:1<<RC_NONBOSS)
+ sd->left_weapon.ignore_def_race & map->race_id2mask(tstatus->race) ||
+ sd->left_weapon.ignore_def_race & map->race_id2mask(is_boss(target) ? RC_BOSS : RC_NONBOSS)
)) {
if(battle_config.left_cardfix_to_right && flag.rh) //Move effect to right hand. [Skotlex]
flag.idef = 1;
diff --git a/src/map/map.c b/src/map/map.c
index fff1593a4..7a0dde260 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -2040,6 +2040,37 @@ struct mob_data * map_id2boss(int id)
return (struct mob_data*)idb_get(map->bossid_db,id);
}
+/**
+ * Returns the equivalent bitmask to the given race ID.
+ *
+ * @param race A race identifier (@see enum Race)
+ *
+ * @return The equivalent race bitmask.
+ */
+uint32 map_race_id2mask(int race)
+{
+ if (race >= RC_FORMLESS && race < RC_MAX)
+ return 1 << race;
+
+ if (race == RC_ALL)
+ return RCMASK_ALL;
+
+ if (race == RC_NONPLAYER)
+ return RCMASK_NONPLAYER;
+
+ if (race == RC_NONDEMIHUMAN)
+ return RCMASK_NONDEMIHUMAN;
+
+ if (race == RC_DEMIPLAYER)
+ return RCMASK_DEMIPLAYER;
+
+ if (race == RC_NONDEMIPLAYER)
+ return RCMASK_NONDEMIPLAYER;
+
+ ShowWarning("map_race_id2mask: Invalid race: %d\n", race);
+ return RCMASK_NONE;
+}
+
/// Applies func to all the players in the db.
/// Stops iterating if func returns -1.
void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_list args) {
@@ -6127,6 +6158,7 @@ void map_defaults(void) {
map->nick2sd = map_nick2sd;
map->getmob_boss = map_getmob_boss;
map->id2boss = map_id2boss;
+ map->race_id2mask = map_race_id2mask;
// reload config file looking only for npcs
map->reloadnpc = map_reloadnpc;
diff --git a/src/map/map.h b/src/map/map.h
index 974fbc4ba..8f0bbca39 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -251,26 +251,64 @@ enum bl_type {
enum npc_subtype { WARP, SHOP, SCRIPT, CASHSHOP, TOMB };
-enum {
- RC_FORMLESS=0,
- RC_UNDEAD,
- RC_BRUTE,
- RC_PLANT,
- RC_INSECT,
- RC_FISH,
- RC_DEMON,
- RC_DEMIHUMAN,
- RC_ANGEL,
- RC_DRAGON,
- RC_PLAYER,
- RC_BOSS,
- RC_NONBOSS,
- RC_MAX,
- RC_NONDEMIHUMAN,
- RC_NONPLAYER,
- RC_DEMIPLAYER,
- RC_NONDEMIPLAYER,
- RC_ALL = 0xFF
+/**
+ * Race type IDs.
+ *
+ * Mostly used by scripts/bonuses.
+ */
+enum Race {
+ // Base Races
+ RC_FORMLESS = 0, ///< Formless
+ RC_UNDEAD, ///< Undead
+ RC_BRUTE, ///< Beast/Brute
+ RC_PLANT, ///< Plant
+ RC_INSECT, ///< Insect
+ RC_FISH, ///< Fish
+ RC_DEMON, ///< Demon
+ RC_DEMIHUMAN, ///< Demi-Human (not including Player)
+ RC_ANGEL, ///< Angel
+ RC_DRAGON, ///< Dragon
+ RC_PLAYER, ///< Player
+ // Boss
+ RC_BOSS, ///< Boss
+ RC_NONBOSS, ///< Non-boss
+
+ RC_MAX, // Array size delimiter (keep before the combination races)
+
+ // Combination Races
+ RC_NONDEMIHUMAN, ///< Every race except Demi-Human (including Player)
+ RC_NONPLAYER, ///< Every non-player race
+ RC_DEMIPLAYER, ///< Demi-Human (including Player)
+ RC_NONDEMIPLAYER, ///< Every race except Demi-Human (and except Player)
+ RC_ALL = 0xFF, ///< Every race (implemented as equivalent to RC_BOSS and RC_NONBOSS)
+};
+
+/**
+ * Race type bitmasks.
+ *
+ * Used by several bonuses internally, to simplify handling of race combinations.
+ */
+enum RaceMask {
+ RCMASK_NONE = 0,
+ RCMASK_FORMLESS = 1<<RC_FORMLESS,
+ RCMASK_UNDEAD = 1<<RC_UNDEAD,
+ RCMASK_BRUTE = 1<<RC_BRUTE,
+ RCMASK_PLANT = 1<<RC_PLANT,
+ RCMASK_INSECT = 1<<RC_INSECT,
+ RCMASK_FISH = 1<<RC_FISH,
+ RCMASK_DEMON = 1<<RC_DEMON,
+ RCMASK_DEMIHUMAN = 1<<RC_DEMIHUMAN,
+ RCMASK_ANGEL = 1<<RC_ANGEL,
+ RCMASK_DRAGON = 1<<RC_DRAGON,
+ RCMASK_PLAYER = 1<<RC_PLAYER,
+ RCMASK_BOSS = 1<<RC_BOSS,
+ RCMASK_NONBOSS = 1<<RC_NONBOSS,
+ RCMASK_NONDEMIPLAYER = RCMASK_FORMLESS | RCMASK_UNDEAD | RCMASK_BRUTE | RCMASK_PLANT | RCMASK_INSECT | RCMASK_FISH | RCMASK_DEMON | RCMASK_ANGEL | RCMASK_DRAGON,
+ RCMASK_NONDEMIHUMAN = RCMASK_NONDEMIPLAYER | RCMASK_PLAYER,
+ RCMASK_NONPLAYER = RCMASK_NONDEMIPLAYER | RCMASK_DEMIHUMAN,
+ RCMASK_DEMIPLAYER = RCMASK_DEMIHUMAN | RCMASK_PLAYER,
+ RCMASK_ALL = RCMASK_BOSS | RCMASK_NONBOSS,
+ RCMASK_ANY = RCMASK_NONPLAYER | RCMASK_PLAYER,
};
enum {
@@ -1010,6 +1048,7 @@ END_ZEROED_BLOCK;
struct map_session_data * (*nick2sd) (const char *nick);
struct mob_data * (*getmob_boss) (int16 m);
struct mob_data * (*id2boss) (int id);
+ uint32 (*race_id2mask) (int race);
// reload config file looking only for npcs
void (*reloadnpc) (bool clear);
diff --git a/src/map/mob.c b/src/map/mob.c
index 6cbbd3a2a..d9a3f6776 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -2411,8 +2411,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
{
if ( sd->add_drop[i].race == -md->class_ ||
( sd->add_drop[i].race > 0 && (
- sd->add_drop[i].race & (1<<mstatus->race) ||
- sd->add_drop[i].race & (1<<((mstatus->mode&MD_BOSS)?RC_BOSS:RC_NONBOSS))
+ sd->add_drop[i].race & map->race_id2mask(mstatus->race) ||
+ sd->add_drop[i].race & map->race_id2mask((mstatus->mode&MD_BOSS) ? RC_BOSS : RC_NONBOSS)
)))
{
//check if the bonus item drop rate should be multiplied with mob level/10 [Lupus]
diff --git a/src/map/pc.c b/src/map/pc.c
index b0a8ca62f..d721e2a65 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -2455,29 +2455,17 @@ int pc_bonus(struct map_session_data *sd,int type,int val) {
}
break;
case SP_IGNORE_DEF_RACE:
- if (val == RC_MAX || (val > RC_NONDEMIPLAYER && val != RC_ALL) || val < RC_FORMLESS ) {
- ShowWarning("pc_bonus: SP_IGNORE_DEF_RACE: Invalid Race(%d)\n",val);
+ {
+ uint32 race_mask = map->race_id2mask(val);
+ if (race_mask == RCMASK_NONE) {
+ ShowWarning("pc_bonus: SP_IGNORE_DEF_RACE: Invalid Race (%d)\n", val);
break;
}
- if ( val >= RC_MAX ) {
- for ( i = RC_FORMLESS; i < RC_BOSS; i++ ) {
- if ( (val == RC_NONPLAYER && i == RC_PLAYER) ||
- (val == RC_NONDEMIHUMAN && i == RC_DEMIHUMAN) ||
- (val == RC_DEMIPLAYER && (i != RC_PLAYER && i != RC_DEMIHUMAN)) ||
- (val == RC_NONDEMIPLAYER && (i == RC_PLAYER || i == RC_DEMIHUMAN))
- )
- continue;
- if(!sd->state.lr_flag)
- sd->right_weapon.ignore_def_race |= 1<<i;
- else if(sd->state.lr_flag == 1)
- sd->left_weapon.ignore_def_race |= 1<<i;
- }
- } else {
- if(!sd->state.lr_flag)
- sd->right_weapon.ignore_def_race |= 1<<val;
- else if(sd->state.lr_flag == 1)
- sd->left_weapon.ignore_def_race |= 1<<val;
- }
+ if (!sd->state.lr_flag)
+ sd->right_weapon.ignore_def_race |= race_mask;
+ else if (sd->state.lr_flag == 1)
+ sd->left_weapon.ignore_def_race |= race_mask;
+ }
break;
case SP_ATK_RATE:
if(sd->state.lr_flag != 2)
@@ -2513,25 +2501,16 @@ int pc_bonus(struct map_session_data *sd,int type,int val) {
}
break;
case SP_IGNORE_MDEF_RACE:
- if (val == RC_MAX || (val > RC_NONDEMIPLAYER && val != RC_ALL) || val < RC_FORMLESS ) {
- ShowWarning("pc_bonus: SP_IGNORE_MDEF_RACE: Invalid Race(%d)\n",val);
+ {
+ uint32 race_mask = map->race_id2mask(val);
+ if (race_mask == RCMASK_NONE) {
+ ShowWarning("pc_bonus: SP_IGNORE_MDEF_RACE: Invalid Race (%d)\n", val);
break;
}
- if(sd->state.lr_flag != 2) {
- if ( val >= RC_MAX ) {
- for ( i = RC_FORMLESS; i < RC_BOSS; i++ ) {
- if ( (val == RC_NONPLAYER && i == RC_PLAYER) ||
- (val == RC_NONDEMIHUMAN && i == RC_DEMIHUMAN) ||
- (val == RC_DEMIPLAYER && (i != RC_PLAYER && i != RC_DEMIHUMAN)) ||
- (val == RC_NONDEMIPLAYER && (i == RC_PLAYER || i == RC_DEMIHUMAN))
- )
- continue;
- sd->bonus.ignore_mdef_race |= 1<<i;
- }
- } else {
- sd->bonus.ignore_mdef_race |= 1<<val;
- }
+ if (sd->state.lr_flag != 2) {
+ sd->bonus.ignore_mdef_race |= race_mask;
}
+ }
break;
case SP_PERFECT_HIT_RATE:
if(sd->state.lr_flag != 2 && sd->bonus.perfect_hit < val)
@@ -2565,29 +2544,17 @@ int pc_bonus(struct map_session_data *sd,int type,int val) {
}
break;
case SP_DEF_RATIO_ATK_RACE:
- if (val == RC_MAX || (val > RC_NONDEMIPLAYER && val != RC_ALL) || val < RC_FORMLESS ) {
- ShowWarning("pc_bonus: SP_DEF_RATIO_ATK_RACE: Invalid Race(%d)\n",val);
+ {
+ uint32 race_mask = map->race_id2mask(val);
+ if (race_mask == RCMASK_NONE) {
+ ShowWarning("pc_bonus: SP_DEF_RATIO_ATK_RACE: Invalid Race (%d)\n", val);
break;
}
- if ( val >= RC_MAX ) {
- for ( i = RC_FORMLESS; i < RC_BOSS; i++ ) {
- if ( (val == RC_NONPLAYER && i == RC_PLAYER) ||
- (val == RC_NONDEMIHUMAN && i == RC_DEMIHUMAN) ||
- (val == RC_DEMIPLAYER && (i != RC_PLAYER && i != RC_DEMIHUMAN)) ||
- (val == RC_NONDEMIPLAYER && (i == RC_PLAYER || i == RC_DEMIHUMAN))
- )
- continue;
- if(!sd->state.lr_flag)
- sd->right_weapon.def_ratio_atk_race |= 1<<i;
- else if(sd->state.lr_flag == 1)
- sd->left_weapon.def_ratio_atk_race |= 1<<i;
- }
- } else {
- if(!sd->state.lr_flag)
- sd->right_weapon.def_ratio_atk_race |= 1<<val;
- else if(sd->state.lr_flag == 1)
- sd->left_weapon.def_ratio_atk_race |= 1<<val;
- }
+ if (!sd->state.lr_flag)
+ sd->right_weapon.def_ratio_atk_race |= race_mask;
+ else if (sd->state.lr_flag == 1)
+ sd->left_weapon.def_ratio_atk_race |= race_mask;
+ }
break;
case SP_HIT_RATE:
if(sd->state.lr_flag != 2)
@@ -2861,7 +2828,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val) {
#endif
case SP_ADD_MONSTER_DROP_CHAINITEM:
if (sd->state.lr_flag != 2)
- pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, (1<<RC_BOSS)|(1<<RC_NONBOSS), 10000);
+ pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, map->race_id2mask(RC_BOSS)|map->race_id2mask(RC_NONBOSS), 10000);
break;
default:
ShowWarning("pc_bonus: unknown type %d %d !\n",type,val);
@@ -3473,7 +3440,7 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
break;
case SP_ADD_MONSTER_DROP_ITEM:
if (sd->state.lr_flag != 2)
- pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, (1<<RC_BOSS)|(1<<RC_NONBOSS), val);
+ pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, map->race_id2mask(RC_BOSS)|map->race_id2mask(RC_NONBOSS), val);
break;
case SP_SP_LOSS_RATE:
if(sd->state.lr_flag != 2) {
@@ -3694,8 +3661,15 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
}
break;
case SP_ADD_MONSTER_DROP_CHAINITEM:
+ {
+ uint32 race_mask = map->race_id2mask(type2);
+ if (race_mask == RCMASK_NONE) {
+ ShowWarning("pc_bonus2: SP_ADD_MONSTER_DROP_CHAINITEM: Invalid Race (%d)\n", type2);
+ break;
+ }
if (sd->state.lr_flag != 2)
- pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, 1<<type2, 10000);
+ pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, race_mask, 10000);
+ }
break;
#ifdef RENEWAL
case SP_RACE_TOLERANCE:
@@ -3734,8 +3708,15 @@ int pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val)
switch(type){
case SP_ADD_MONSTER_DROP_ITEM:
- if(sd->state.lr_flag != 2)
- pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, 1<<type3, val);
+ {
+ uint32 race_mask = map->race_id2mask(type2);
+ if (race_mask == RCMASK_NONE) {
+ ShowWarning("pc_bonus2: SP_ADD_MONSTER_DROP_ITEM: Invalid Race (%d)\n", type3);
+ break;
+ }
+ if (sd->state.lr_flag != 2)
+ pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, race_mask, val);
+ }
break;
case SP_ADD_CLASS_DROP_ITEM:
if(sd->state.lr_flag != 2)