diff --git a/doc/item_bonus.txt b/doc/item_bonus.txt index a12719aeadf..ac0e17ebab7 100644 --- a/doc/item_bonus.txt +++ b/doc/item_bonus.txt @@ -297,6 +297,9 @@ bonus2 bAddEff2,eff,n; Adds a n/100% chance to cause status eff on self w bonus2 bAddEffWhenHit,eff,n; Adds a n/100% chance to cause status eff on the enemy when being hit by physical damage bonus2 bResEff,eff,n; Adds a n/100% tolerance to status eff +bonus2 bResSC,sc,n; Adds a n/100% relative tolerance to status change specified by SC constants. +bonus2 bResSC2,sc,n; Adds a n/100% absolute tolerance to status change specified by SC constants. + bonus3 bAddEff,eff,n,atf; Adds a n/100% chance to cause status eff on the target when attacking bonus4 bAddEff,eff,n,atf,t; Adds a n/100% chance to cause status eff for t milliseconds on the target when attacking bonus3 bAddEffWhenHit,eff,n,atf; Adds a n/100% chance to cause status eff on the target when being hit by physical damage diff --git a/src/map/map.h b/src/map/map.h index fd5a6b0464d..008ea196460 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -488,6 +488,8 @@ enum _sp { SP_STATE_NORECOVER_RACE, SP_CRITICAL_RANGEATK, SP_MAGIC_ADDRACE2, SP_IGNORE_MDEF_RACE2_RATE, // 2079-2082 SP_WEAPON_ATK_RATE, SP_WEAPON_MATK_RATE, SP_DROP_ADDRACE, SP_DROP_ADDCLASS, SP_NO_MADO_FUEL, // 2083-2087 SP_IGNORE_DEF_CLASS_RATE, SP_REGEN_PERCENT_HP, SP_REGEN_PERCENT_SP, //2088-2091 + + SP_RES_SC, SP_RES_SC2, }; enum _look { diff --git a/src/map/pc.c b/src/map/pc.c index 75d1ad6c5cf..f228868831a 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -60,6 +60,8 @@ struct eri *pc_sc_display_ers = NULL; struct eri *pc_itemgrouphealrate_ers = NULL; struct eri *num_reg_ers; struct eri *str_reg_ers; +struct eri *pc_resSC_ers = NULL; +struct eri *pc_resSC2_ers = NULL; int pc_expiration_tid = INVALID_TIMER; struct fame_list smith_fame_list[MAX_FAME_LIST]; @@ -1258,6 +1260,11 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_ sd->qi_display = NULL; sd->qi_count = 0; + sd->resSC = NULL; + sd->resSC_count = 0; + sd->resSC2 = NULL; + sd->resSC2_count = 0; + //warp player if ((i=pc_setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != SETPOS_OK) { ShowError ("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i); @@ -2497,6 +2504,148 @@ void pc_itemgrouphealrate_clear(struct map_session_data *sd) { } } +/** Get bResSC rate from player +* @param sd Player +* @param type SC Type +* @return Resistance rate +* @author Cydh +*/ +short pc_resSC(struct map_session_data *sd, sc_type type) { + uint8 i; + + nullpo_ret(sd); + + if (!sd->resSC || !sd->resSC_count) + return 0; + for (i = 0; i < sd->resSC_count; i++) { + if (sd->resSC[i]->sc == type) + return sd->resSC[i]->rate; + } + return 0; +} + +/** Add bResSC data to player +* @param sd Player +* @param type SC Type +* @param rate +* @author Cydh +*/ +void pc_resSC_add(struct map_session_data *sd, sc_type type, short rate) { + struct s_pc_resSC *entry; + uint8 i; + + for (i = 0; i < sd->resSC_count; i++) { + if (sd->resSC[i]->sc == type) + break; + } + + if (i != sd->resSC_count) { + sd->resSC[i]->rate += rate; + return; + } + + if (i == UINT8_MAX) { + ShowError("pc_resSC_add: Reached max (%d) possible bonuses for this player %d\n", UINT8_MAX); + return; + } + + entry = ers_alloc(pc_resSC_ers, struct s_pc_resSC); + entry->sc = type; + entry->rate = rate; + + RECREATE(sd->resSC, struct s_pc_resSC *, sd->resSC_count+1); + sd->resSC[sd->resSC_count++] = entry; +} + +/** Clear resSC from player +* @param sd Player +* @author Cydh +*/ +void pc_resSC_clear(struct map_session_data *sd) { + if (!sd || !sd->resSC_count) + return; + else { + uint8 i; + for( i = 0; i < sd->resSC_count; i++ ) + ers_free(pc_resSC_ers, sd->resSC[i]); + sd->resSC_count = 0; + aFree(sd->resSC); + sd->resSC = NULL; + } +} + + +/** Get bResSC2 rate from player +* @param sd Player +* @param type SC Type +* @return Resistance rate +* @author Cydh +*/ +short pc_resSC2(struct map_session_data *sd, sc_type type) { + uint8 i; + + nullpo_ret(sd); + + if (!sd->resSC2 || !sd->resSC2_count) + return 0; + + for (i = 0; i < sd->resSC2_count; i++) { + if (sd->resSC2[i]->sc == type) + return sd->resSC2[i]->rate; + } + return 0; +} + +/** Add bResSC2 data to player +* @param sd Player +* @param type SC Type +* @param rate +* @author Cydh +*/ +void pc_resSC2_add(struct map_session_data *sd, sc_type type, short rate) { + struct s_pc_resSC *entry; + uint8 i; + + for (i = 0; i < sd->resSC2_count; i++) { + if (sd->resSC2[i]->sc == type) + break; + } + + if (i != sd->resSC2_count) { + sd->resSC2[i]->rate += rate; + return; + } + + if (i == UINT8_MAX) { + ShowError("pc_resSC2_add: Reached max (%d) possible bonuses for this player %d\n", UINT8_MAX); + return; + } + + entry = ers_alloc(pc_resSC2_ers, struct s_pc_resSC); + entry->sc = type; + entry->rate = rate; + + RECREATE(sd->resSC2, struct s_pc_resSC *, sd->resSC2_count+1); + sd->resSC2[sd->resSC2_count++] = entry; +} + +/** Clear resSC2 from player +* @param sd Player +* @author Cydh +*/ +void pc_resSC2_clear(struct map_session_data *sd) { + if (!sd || !sd->resSC2_count) + return; + else { + uint8 i; + for( i = 0; i < sd->resSC2_count; i++ ) + ers_free(pc_resSC2_ers, sd->resSC2[i]); + sd->resSC2_count = 0; + aFree(sd->resSC2); + sd->resSC2 = NULL; + } +} + /*========================================== * Add a bonus(type) to player sd * format: bonus bBonusName,val; @@ -3807,6 +3956,16 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val) if (sd->state.lr_flag != 2) sd->dropaddclass[type2] += val; break; + case SP_RES_SC: // bonus2 bResSC,sc,n; + PC_BONUS_CHK_SC(type2, SP_RESSC); + if (sd->state.lr_flag != 2) + pc_resSC_add(sd, (sc_type)type2, val); + break; + case SP_RES_SC2: // bonus2 bResSC2,sc,n; + PC_BONUS_CHK_SC(type2, SP_RES_SC2); + if (sd->state.lr_flag != 2) + pc_resSC2_add(sd, (sc_type)type2, val); + break; default: if (running_npc_stat_calc_event) { ShowWarning("pc_bonus2: unknown bonus type %d %d %d in OnPCStatCalcEvent!\n", type, type2, val); @@ -12426,6 +12585,8 @@ void do_final_pc(void) { ers_destroy(pc_sc_display_ers); ers_destroy(pc_itemgrouphealrate_ers); + ers_destroy(pc_resSC_ers); + ers_destroy(pc_resSC2_ers); ers_destroy(num_reg_ers); ers_destroy(str_reg_ers); } @@ -12470,6 +12631,8 @@ void do_init_pc(void) { pc_sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.c:pc_sc_display_ers", ERS_OPT_FLEX_CHUNK); pc_itemgrouphealrate_ers = ers_new(sizeof(struct s_pc_itemgrouphealrate), "pc.c:pc_itemgrouphealrate_ers", ERS_OPT_NONE); + pc_resSC_ers = ers_new(sizeof(struct s_pc_resSC), "pc.c:pc_resSC_ers", ERS_OPT_NONE); + pc_resSC2_ers = ers_new(sizeof(struct s_pc_resSC), "pc.c:pc_resSC2_ers", ERS_OPT_NONE); num_reg_ers = ers_new(sizeof(struct script_reg_num), "pc.c:num_reg_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); str_reg_ers = ers_new(sizeof(struct script_reg_str), "pc.c:str_reg_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); diff --git a/src/map/pc.h b/src/map/pc.h index c8be9459226..17efab70a7f 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -190,6 +190,12 @@ struct s_pc_itemgrouphealrate { short rate; /// Rate }; +/// bResEff2 struct +struct s_pc_resSC { + sc_type sc; + short rate; +}; + ///Timed bonus 'bonus_script' struct [Cydh] struct s_bonus_script_entry { struct script_code *script; @@ -705,6 +711,9 @@ struct map_session_data { struct s_pc_itemgrouphealrate **itemgrouphealrate; /// List of Item Group Heal rate bonus uint8 itemgrouphealrate_count; /// Number of rate bonuses + struct s_pc_resSC **resSC, **resSC2; + unsigned short resSC_count, resSC2_count; + /* Expiration Timer ID */ int expiration_tid; time_t expiration_time; @@ -740,6 +749,8 @@ struct map_session_data { extern struct eri *pc_sc_display_ers; /// Player's SC display table extern struct eri *pc_itemgrouphealrate_ers; /// Player's Item Group Heal Rate table +extern struct eri *pc_resSC_ers; /// Player's bResSC table +extern struct eri *pc_resSC2_ers; /// Player's bResSC2 table /** * ERS for the bulk of pc vars @@ -1326,6 +1337,11 @@ void pc_show_questinfo_reinit(struct map_session_data *sd); bool pc_job_can_entermap(enum e_job jobid, int m, int group_lv); +short pc_resSC(struct map_session_data *sd, sc_type type); +void pc_resSC_clear(struct map_session_data *sd); +short pc_resSC2(struct map_session_data *sd, sc_type type); +void pc_resSC2_clear(struct map_session_data *sd); + #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) int pc_level_penalty_mod(int level_diff, uint32 mob_class, enum e_mode mode, int type); #endif diff --git a/src/map/script_constants.h b/src/map/script_constants.h index 1340111278f..f77f3094856 100644 --- a/src/map/script_constants.h +++ b/src/map/script_constants.h @@ -706,6 +706,8 @@ export_constant2("bIgnoreDefClassRate", SP_IGNORE_DEF_CLASS_RATE); export_constant2("bRegenPercentHP", SP_REGEN_PERCENT_HP); export_constant2("bRegenPercentSP", SP_REGEN_PERCENT_SP); + export_constant2("bResSC", SP_RES_SC); + export_constant2("bResSC2", SP_RES_SC2); /* equip indices */ export_constant(EQI_COMPOUND_ON); diff --git a/src/map/status.c b/src/map/status.c index 3328f95d15f..75d1807e147 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -3448,6 +3448,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true); pc_itemgrouphealrate_clear(sd); + pc_resSC_clear(sd); + pc_resSC2_clear(sd); running_npc_stat_calc_event = true; npc_script_event(sd, NPCE_STATCALC); @@ -8041,6 +8043,12 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ tick_def2 = status->luk * 100; break; default: + if (sd) { // Adjust the rate from bResSC and bResSC2 [Cydh] + if (sd->resSC2 && sd->resSC2_count) + rate -= pc_resSC2(sd, type); + if (sd->resSC && sd->resSC_count) + rate -= rate * pc_resSC(sd, type) / 10000; + } // Effect that cannot be reduced? Likely a buff. if (!(rnd()%10000 < rate)) return 0; @@ -8093,6 +8101,9 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ rate -= rate*sc_def/10000; rate -= sc_def2; + if (sd && sd->resSC2 && sd->resSC2_count) + rate -= pc_resSC2(sd, type); + // Minimum chances switch (type) { case SC_BITE: @@ -8108,6 +8119,9 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ rate -= rate*sd->sc.data[SC_COMMONSC_RESIST]->val1/100; } + if (sd && sd->resSC && sd->resSC_count) + rate -= rate * pc_resSC(sd, type) / 10000; + // Aegis accuracy if(rate > 0 && rate%10 != 0) rate += (10 - rate%10); } diff --git a/src/map/unit.c b/src/map/unit.c index 5e0d66f7b4b..84a053282ca 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -3244,6 +3244,8 @@ int unit_free(struct block_list *bl, clr_type clrtype) pc_bonus_script_clear(sd, BSF_REM_ALL); pc_itemgrouphealrate_clear(sd); + pc_resSC_clear(sd); + pc_resSC2_clear(sd); break; } case BL_PET: {