diff --git a/db/constants.conf b/db/constants.conf index 5938f9fb5a7..c159ed707ba 100644 --- a/db/constants.conf +++ b/db/constants.conf @@ -475,6 +475,8 @@ constants_db: { bSubDefEle: 2063 bMagicSubDefEle: 2064 bStateNoRecoverRace: 2065 + bSubSkill: 2066 + bDropAddRace: 2067 comment__: "Equip index" /* reference to script.c::script_defaults():equip[] array used for easy-conversion */ diff --git a/doc/item_bonus.md b/doc/item_bonus.md index 4eba4e3069e..da81f77f859 100644 --- a/doc/item_bonus.md +++ b/doc/item_bonus.md @@ -225,6 +225,7 @@ bonus bCritAtkRate,`n`; | Increase critical damage by +`n`% bonus bNoWeaponDamage,`n`; | Prevents from receiving `n`% physical damage bonus bNoMagicDamage,`n`; | Prevents from receiving `n`% magical effect (Attack, Healing, Support spells are all blocked) bonus bNoMiscDamage,`n`; | Adds `n`% reduction to received misc damage +bonus2 bSubSkill,`sk`,`n`; | Reduce damage received from `sk` skill by `n`% Heal | Description :-------------------------------- | :------------------------- @@ -419,6 +420,7 @@ bonus bAddMonsterDropChainItem,`ic`; | Able to get Item of chain `ic` when bonus2 bAddMonsterDropChainItem,`ic`,`r`; | Able to get item of chain `ic` when you kill a monster of race `r` bonus2 bGetZenyNum,`x`,`n`; | When killing a monster, there is a `n`% chance of gaining 1~x zeny (only the highest among all is applied). bonus2 bAddGetZenyNum,`x`,`n`; | When killing a monster, there is a `n`% chance of gaining 1~x zeny (Stackable)
x:
< 0: Max Zeny gain is `(-x*monster_level)` +bonus2 bDropAddRace,`r`,`n`; | Increase item drop rate by `n`% when you kill a monster of race `r` Misc effects | Description :------------------------------------- | :------------------------- diff --git a/src/map/battle.c b/src/map/battle.c index 0b3d877f373..dd761ce37f6 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -3757,6 +3757,7 @@ static struct Damage battle_calc_magic_attack(struct block_list *src, struct blo flag.imdef = (nk&NK_IGNORE_DEF)? 1 : 0; sd = BL_CAST(BL_PC, src); + struct map_session_data *tsd = BL_CAST(BL_PC, target); sc = status->get_sc(src); @@ -3989,6 +3990,8 @@ static struct Damage battle_calc_magic_attack(struct block_list *src, struct blo )) flag.imdef = 1; } + if (tsd && (i = pc->sub_skillatk_bonus(tsd, skill_id))) + ad.damage -= ad.damage * i / 100; ad.damage = battle->calc_defense(BF_MAGIC, src, target, skill_id, skill_lv, ad.damage, flag.imdef, 0); @@ -4436,6 +4439,8 @@ static struct Damage battle_calc_misc_attack(struct block_list *src, struct bloc } if (sd && (i = pc->skillatk_bonus(sd, rskill)) != 0) md.damage += md.damage*i/100; + if (tsd && (i = pc->sub_skillatk_bonus(tsd, rskill)) != 0) + md.damage -= md.damage * i / 100; } if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) md.damage = md.damage * i / 100; @@ -5577,6 +5582,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl } } + if (tsd && skill_id && (i = pc->sub_skillatk_bonus(tsd, skill_id))) + ATK_ADDRATE(-i); + if((!flag.idef || !flag.idef2) #ifdef RENEWAL && (!flag.distinct || flag.tdef) diff --git a/src/map/map.h b/src/map/map.h index 2851cfa19aa..3212b100384 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -773,6 +773,8 @@ enum status_point_types { //we better clean up this enum and change it name [Hem SP_SUB_DEF_ELE = 2063, SP_MAGIC_SUB_DEF_ELE = 2064, SP_STATE_NO_RECOVER_RACE = 2065, + SP_SUB_SKILL = 2066, + SP_ADD_DROP_RACE = 2067, #ifndef SP_LAST_KNOWN SP_LAST_KNOWN diff --git a/src/map/mob.c b/src/map/mob.c index ab4caa6b7e8..6bef7c19309 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -2723,51 +2723,64 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type) if ( !(it = itemdb->exists(md->db->dropitem[i].nameid)) ) continue; drop_rate = md->db->dropitem[i].p; - if (drop_rate <= 0) { - if (battle_config.drop_rate0item) - continue; - drop_rate = 1; - } // change drops depending on monsters size [Valaris] - if (battle_config.mob_size_influence) - { + if (battle_config.mob_size_influence) { if (md->special_state.size == SZ_MEDIUM && drop_rate >= 2) drop_rate /= 2; else if( md->special_state.size == SZ_BIG) drop_rate *= 2; } - if (src) { + if (src != NULL) { //Drops affected by luk as a fixed increase [Valaris] if (battle_config.drops_by_luk) - drop_rate += status_get_luk(src)*battle_config.drops_by_luk/100; + drop_rate += status_get_luk(src) * battle_config.drops_by_luk / 100; + //Drops affected by luk as a % increase [Skotlex] if (battle_config.drops_by_luk2) - drop_rate += (int)(0.5+drop_rate*status_get_luk(src)*battle_config.drops_by_luk2/10000.); + drop_rate += (int)(0.5 + drop_rate * status_get_luk(src) * battle_config.drops_by_luk2 / 10000.); + + if (sd != NULL) { + int drop_rate_bonus = 100; + + // When PK Mode is enabled, increase item drop rate bonus of each items by 25% when there is a 20 level difference between the player and the monster.[KeiKun] + if (battle_config.pk_mode && (md->level - sd->status.base_level >= 20)) + drop_rate_bonus += 25; // flat 25% bonus + + drop_rate_bonus += sd->dropaddrace[md->status.race] + (is_boss(src) ? sd->dropaddrace[RC_BOSS] : sd->dropaddrace[RC_NONBOSS]); // bonus2 bDropAddRace[KeiKun] + + if (sd->sc.data[SC_CASH_RECEIVEITEM] != NULL) // Increase drop rate if user has SC_CASH_RECEIVEITEM + drop_rate_bonus += sd->sc.data[SC_CASH_RECEIVEITEM]->val1; + + if (sd->sc.data[SC_OVERLAPEXPUP] != NULL) + drop_rate_bonus += sd->sc.data[SC_OVERLAPEXPUP]->val2; + + drop_rate = (int)(0.5 + drop_rate * drop_rate_bonus / 100.); + + // Limit drop rate, default: 90% + drop_rate = max(drop_rate, 90000); + } } - if (sd && battle_config.pk_mode && - md->level - sd->status.base_level >= 20) - drop_rate = (int)(drop_rate*1.25); // pk_mode increase drops if 20 level difference [Valaris] - - // Increase drop rate if user has SC_CASH_RECEIVEITEM - if (sd && sd->sc.data[SC_CASH_RECEIVEITEM]) // now rig the drop rate to never be over 90% unless it is originally >90%. - drop_rate = max(drop_rate, cap_value((int)(0.5 + drop_rate * (sd->sc.data[SC_CASH_RECEIVEITEM]->val1) / 100.), 0, 9000)); - if (sd && sd->sc.data[SC_OVERLAPEXPUP]) - drop_rate = max(drop_rate, cap_value((int)(0.5 + drop_rate * (sd->sc.data[SC_OVERLAPEXPUP]->val2) / 100.), 0, 9000)); + #ifdef RENEWAL_DROP - if( drop_modifier != 100 ) { + if (drop_modifier != 100) { drop_rate = drop_rate * drop_modifier / 100; - if( drop_rate < 1 ) + if (drop_rate < 1) drop_rate = 1; } #endif - if( sd && sd->status.mod_drop != 100 ) { + if (sd != NULL && sd->status.mod_drop != 100) { drop_rate = drop_rate * sd->status.mod_drop / 100; - if( drop_rate < 1 ) + if (drop_rate < 1) drop_rate = 1; } + if (battle_config.drop_rate0item) + drop_rate = max(drop_rate, 0); + else + drop_rate = max(drop_rate, 1); + // attempt to drop the item if (rnd() % 10000 >= drop_rate) continue; diff --git a/src/map/pc.c b/src/map/pc.c index 627467bb6b8..cde4520b510 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -3839,6 +3839,35 @@ static int pc_bonus2(struct map_session_data *sd, int type, int type2, int val) } break; #endif + case SP_SUB_SKILL: + if (sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->subskill), i, sd->subskill[i].id == 0 || sd->subskill[i].id == type2); + if (i == ARRAYLENGTH(sd->subskill)) { + ShowDebug("script->run: bonus2 bSubSkill reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->subskill), type2, val); + break; + } + if (sd->subskill[i].id == type2) { + sd->subskill[i].val += val; + } else { + sd->subskill[i].id = type2; + sd->subskill[i].val = val; + } + break; + case SP_ADD_DROP_RACE: + { + uint32 race_mask = map->race_id2mask(type2); + if (race_mask == RCMASK_NONE) { + ShowWarning("pc_bonus2: SP_ADD_DROP_RACE: Invalid Race (%d)\n", type2); + break; + } + if (sd->state.lr_flag == 2) + break; + BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) + sd->dropaddrace[i] += val; + } + break; default: ShowWarning("pc_bonus2: unknown type %d %d %d!\n",type,type2,val); Assert_report(0); @@ -7890,6 +7919,19 @@ static int pc_skillatk_bonus(struct map_session_data *sd, uint16 skill_id) return bonus; } +static int pc_sub_skillatk_bonus(struct map_session_data *sd, uint16 skill_id) +{ + int i, bonus = 0; + nullpo_ret(sd); + + ARR_FIND(0, ARRAYLENGTH(sd->subskill), i, sd->subskill[i].id == skill_id); + + if (i < ARRAYLENGTH(sd->subskill)) + bonus = sd->subskill[i].val; + + return bonus; +} + static int pc_skillheal_bonus(struct map_session_data *sd, uint16 skill_id) { int i, bonus = sd->bonus.add_heal_rate; @@ -12867,6 +12909,7 @@ void pc_defaults(void) pc->autocast_remove = pc_autocast_remove; pc->skillatk_bonus = pc_skillatk_bonus; + pc->sub_skillatk_bonus = pc_sub_skillatk_bonus; pc->skillheal_bonus = pc_skillheal_bonus; pc->skillheal2_bonus = pc_skillheal2_bonus; diff --git a/src/map/pc.h b/src/map/pc.h index e65d4146110..197b406695b 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -368,13 +368,14 @@ BEGIN_ZEROED_BLOCK; // this block will be globally zeroed at the beginning of st #ifdef RENEWAL int race_tolerance[RC_MAX]; #endif + int dropaddrace[RC_MAX]; struct s_autospell autospell[15], autospell2[15], autospell3[15]; struct s_addeffect addeff[MAX_PC_BONUS], addeff2[MAX_PC_BONUS]; struct s_addeffectonskill addeff3[MAX_PC_BONUS]; struct { //skillatk raises bonus dmg% of skills, skillheal increases heal%, skillblown increases bonus blewcount for some skills. unsigned int id; int val; - } skillatk[MAX_PC_BONUS], skillusesprate[MAX_PC_BONUS], skillusesp[MAX_PC_BONUS], skillheal[5], skillheal2[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS], skillcooldown[MAX_PC_BONUS], skillfixcast[MAX_PC_BONUS], skillvarcast[MAX_PC_BONUS], skillfixcastrate[MAX_PC_BONUS]; + } skillatk[MAX_PC_BONUS], skillusesprate[MAX_PC_BONUS], skillusesp[MAX_PC_BONUS], skillheal[5], skillheal2[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS], skillcooldown[MAX_PC_BONUS], skillfixcast[MAX_PC_BONUS], skillvarcast[MAX_PC_BONUS], skillfixcastrate[MAX_PC_BONUS], subskill[MAX_PC_BONUS]; struct { int value; int rate; @@ -1063,6 +1064,7 @@ END_ZEROED_BLOCK; /* End */ void (*autocast_remove) (struct map_session_data *sd, enum autocast_type type, int skill_id, int skill_lv); int (*skillatk_bonus) (struct map_session_data *sd, uint16 skill_id); + int (*sub_skillatk_bonus) (struct map_session_data *sd, uint16 skill_id); int (*skillheal_bonus) (struct map_session_data *sd, uint16 skill_id); int (*skillheal2_bonus) (struct map_session_data *sd, uint16 skill_id); diff --git a/src/map/script.c b/src/map/script.c index 568278e9d9d..28a378e6e3e 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -10554,6 +10554,7 @@ static BUILDIN(bonus) case SP_VARCASTRATE: case SP_FIXCASTRATE: case SP_SKILL_USE_SP: + case SP_SUB_SKILL: // these bonuses support skill names if (script_isstringtype(st, 3)) { val1 = skill->name2id(script_getstr(st, 3)); diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index 089120c3946..f45a85d3d85 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -6268,6 +6268,8 @@ typedef void (*HPMHOOK_pre_pc_autocast_remove) (struct map_session_data **sd, en typedef void (*HPMHOOK_post_pc_autocast_remove) (struct map_session_data *sd, enum autocast_type type, int skill_id, int skill_lv); typedef int (*HPMHOOK_pre_pc_skillatk_bonus) (struct map_session_data **sd, uint16 *skill_id); typedef int (*HPMHOOK_post_pc_skillatk_bonus) (int retVal___, struct map_session_data *sd, uint16 skill_id); +typedef int (*HPMHOOK_pre_pc_sub_skillatk_bonus) (struct map_session_data **sd, uint16 *skill_id); +typedef int (*HPMHOOK_post_pc_sub_skillatk_bonus) (int retVal___, struct map_session_data *sd, uint16 skill_id); typedef int (*HPMHOOK_pre_pc_skillheal_bonus) (struct map_session_data **sd, uint16 *skill_id); typedef int (*HPMHOOK_post_pc_skillheal_bonus) (int retVal___, struct map_session_data *sd, uint16 skill_id); typedef int (*HPMHOOK_pre_pc_skillheal2_bonus) (struct map_session_data **sd, uint16 *skill_id); diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index 4faa49fc8e3..7b17eb3c722 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -4846,6 +4846,8 @@ struct { struct HPMHookPoint *HP_pc_autocast_remove_post; struct HPMHookPoint *HP_pc_skillatk_bonus_pre; struct HPMHookPoint *HP_pc_skillatk_bonus_post; + struct HPMHookPoint *HP_pc_sub_skillatk_bonus_pre; + struct HPMHookPoint *HP_pc_sub_skillatk_bonus_post; struct HPMHookPoint *HP_pc_skillheal_bonus_pre; struct HPMHookPoint *HP_pc_skillheal_bonus_post; struct HPMHookPoint *HP_pc_skillheal2_bonus_pre; @@ -11963,6 +11965,8 @@ struct { int HP_pc_autocast_remove_post; int HP_pc_skillatk_bonus_pre; int HP_pc_skillatk_bonus_post; + int HP_pc_sub_skillatk_bonus_pre; + int HP_pc_sub_skillatk_bonus_post; int HP_pc_skillheal_bonus_pre; int HP_pc_skillheal_bonus_post; int HP_pc_skillheal2_bonus_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index 281ac9096cd..94ba681032b 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -2481,6 +2481,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(pc->autocast_set_current, HP_pc_autocast_set_current) }, { HP_POP(pc->autocast_remove, HP_pc_autocast_remove) }, { HP_POP(pc->skillatk_bonus, HP_pc_skillatk_bonus) }, + { HP_POP(pc->sub_skillatk_bonus, HP_pc_sub_skillatk_bonus) }, { HP_POP(pc->skillheal_bonus, HP_pc_skillheal_bonus) }, { HP_POP(pc->skillheal2_bonus, HP_pc_skillheal2_bonus) }, { HP_POP(pc->damage, HP_pc_damage) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index 5a8347df494..2a447844807 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -64456,6 +64456,33 @@ int HP_pc_skillatk_bonus(struct map_session_data *sd, uint16 skill_id) { } return retVal___; } +int HP_pc_sub_skillatk_bonus(struct map_session_data *sd, uint16 skill_id) { + int hIndex = 0; + int retVal___ = 0; + if (HPMHooks.count.HP_pc_sub_skillatk_bonus_pre > 0) { + int (*preHookFunc) (struct map_session_data **sd, uint16 *skill_id); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_sub_skillatk_bonus_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_pc_sub_skillatk_bonus_pre[hIndex].func; + retVal___ = preHookFunc(&sd, &skill_id); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.pc.sub_skillatk_bonus(sd, skill_id); + } + if (HPMHooks.count.HP_pc_sub_skillatk_bonus_post > 0) { + int (*postHookFunc) (int retVal___, struct map_session_data *sd, uint16 skill_id); + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_sub_skillatk_bonus_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_pc_sub_skillatk_bonus_post[hIndex].func; + retVal___ = postHookFunc(retVal___, sd, skill_id); + } + } + return retVal___; +} int HP_pc_skillheal_bonus(struct map_session_data *sd, uint16 skill_id) { int hIndex = 0; int retVal___ = 0;