diff options
author | Haru <haru@dotalux.com> | 2015-11-21 15:44:24 +0100 |
---|---|---|
committer | Haru <haru@dotalux.com> | 2015-12-06 15:18:59 +0100 |
commit | 9fef13d4d2e0eab3376ea95b3cb8783d48d19dda (patch) | |
tree | d1d66ac73e72bc18a96b88d202586b1c41b6ff36 /src | |
parent | cea55140cc2b5d1012813f8abc028ba04bd625c6 (diff) | |
download | hercules-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>
Diffstat (limited to 'src')
-rw-r--r-- | src/map/battle.c | 32 | ||||
-rw-r--r-- | src/map/map.c | 32 | ||||
-rw-r--r-- | src/map/map.h | 79 | ||||
-rw-r--r-- | src/map/mob.c | 4 | ||||
-rw-r--r-- | src/map/pc.c | 107 |
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) |