diff options
Diffstat (limited to 'src/map/battle.c')
-rw-r--r-- | src/map/battle.c | 1162 |
1 files changed, 631 insertions, 531 deletions
diff --git a/src/map/battle.c b/src/map/battle.c index 5ca54bf82..c8cd71b94 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -2,8 +2,8 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2016 Hercules Dev Team - * Copyright (C) Athena Dev Teams + * Copyright (C) 2012-2020 Hercules Dev Team + * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,11 +20,11 @@ */ #define HERCULES_CORE -#include "config/core.h" // CELL_NOSTACK, CIRCULAR_AREA, CONSOLE_INPUT, HMAP_ZONE_DAMAGE_CAP_TYPE, OFFICIAL_WALKPATH, RENEWAL, RENEWAL_ASPD, RENEWAL_CAST, RENEWAL_DROP, RENEWAL_EDP, RENEWAL_EXP, RENEWAL_LVDMG, RE_LVL_DMOD(), RE_LVL_MDMOD(), RE_LVL_TMDMOD(), RE_SKILL_REDUCTION(), SCRIPT_CALLFUNC_CHECK, SECURE_NPCTIMEOUT, STATS_OPT_OUT +#include "config/core.h" // CELL_NOSTACK, CIRCULAR_AREA, CONSOLE_INPUT, HMAP_ZONE_DAMAGE_CAP_TYPE, OFFICIAL_WALKPATH, RENEWAL, RENEWAL_ASPD, RENEWAL_CAST, RENEWAL_DROP, RENEWAL_EDP, RENEWAL_EXP, RENEWAL_LVDMG, RE_LVL_DMOD(), RE_LVL_MDMOD(), RE_LVL_TMDMOD(), RE_SKILL_REDUCTION(), SCRIPT_CALLFUNC_CHECK, SECURE_NPCTIMEOUT #include "battle.h" #include "map/battleground.h" -#include "map/chrif.h" +#include "map/clan.h" #include "map/clif.h" #include "map/elemental.h" #include "map/guild.h" @@ -41,6 +41,7 @@ #include "map/status.h" #include "common/HPM.h" #include "common/cbasetypes.h" +#include "common/conf.h" #include "common/ers.h" #include "common/memmgr.h" #include "common/nullpo.h" @@ -58,7 +59,7 @@ #include <string.h> struct Battle_Config battle_config; -struct battle_interface battle_s; +static struct battle_interface battle_s; struct battle_interface *battle; /** @@ -67,7 +68,7 @@ struct battle_interface *battle; * @param bl The bl to check. * @return The current/last skill ID. */ -int battle_getcurrentskill(struct block_list *bl) +static int battle_getcurrentskill(struct block_list *bl) { const struct unit_data *ud; @@ -90,7 +91,8 @@ int battle_getcurrentskill(struct block_list *bl) /*========================================== * Get random targeting enemy *------------------------------------------*/ -int battle_gettargeted_sub(struct block_list *bl, va_list ap) { +static int battle_gettargeted_sub(struct block_list *bl, va_list ap) +{ struct block_list **bl_list; struct unit_data *ud; int target_id; @@ -118,7 +120,8 @@ int battle_gettargeted_sub(struct block_list *bl, va_list ap) { return 0; } -struct block_list* battle_gettargeted(struct block_list *target) { +static struct block_list *battle_gettargeted(struct block_list *target) +{ struct block_list *bl_list[24]; int c = 0; nullpo_retr(NULL, target); @@ -133,7 +136,8 @@ struct block_list* battle_gettargeted(struct block_list *target) { } //Returns the id of the current targeted character of the passed bl. [Skotlex] -int battle_gettarget(struct block_list* bl) { +static int battle_gettarget(struct block_list *bl) +{ nullpo_ret(bl); switch (bl->type) { @@ -148,7 +152,8 @@ int battle_gettarget(struct block_list* bl) { return 0; } -int battle_getenemy_sub(struct block_list *bl, va_list ap) { +static int battle_getenemy_sub(struct block_list *bl, va_list ap) +{ struct block_list **bl_list; struct block_list *target; int *c; @@ -176,7 +181,8 @@ int battle_getenemy_sub(struct block_list *bl, va_list ap) { } // Picks a random enemy of the given type (BL_PC, BL_CHAR, etc) within the range given. [Skotlex] -struct block_list* battle_getenemy(struct block_list *target, int type, int range) { +static struct block_list *battle_getenemy(struct block_list *target, int type, int range) +{ struct block_list *bl_list[24]; int c = 0; @@ -192,7 +198,9 @@ struct block_list* battle_getenemy(struct block_list *target, int type, int rang return bl_list[rnd()%c]; } -int battle_getenemyarea_sub(struct block_list *bl, va_list ap) { + +static int battle_getenemyarea_sub(struct block_list *bl, va_list ap) +{ struct block_list **bl_list, *src; int *c, ignore_id; @@ -222,7 +230,8 @@ int battle_getenemyarea_sub(struct block_list *bl, va_list ap) { } // Pick a random enemy -struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int range, int type, int ignore_id) { +static struct block_list *battle_getenemyarea(struct block_list *src, int x, int y, int range, int type, int ignore_id) +{ struct block_list *bl_list[24]; int c = 0; @@ -238,7 +247,8 @@ struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int return bl_list[rnd()%c]; } -int battle_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) { +static int battle_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) +{ struct delay_damage *dat = (struct delay_damage *)data; if ( dat ) { @@ -279,7 +289,8 @@ int battle_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) { return 0; } -int battle_delay_damage(int64 tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int64 damage, enum damage_lv dmg_lv, int ddelay, bool additional_effects) { +static int battle_delay_damage(int64 tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int64 damage, enum damage_lv dmg_lv, int ddelay, bool additional_effects) +{ struct delay_damage *dat; struct status_change *sc; struct block_list *d_tbl = NULL; @@ -327,7 +338,8 @@ int battle_delay_damage(int64 tick, int amotion, struct block_list *src, struct return 0; } -int battle_attr_ratio(int atk_elem,int def_type, int def_lv) + +static int battle_attr_ratio(int atk_elem, int def_type, int def_lv) { if (atk_elem < ELE_NEUTRAL || atk_elem >= ELE_MAX) return 100; @@ -343,7 +355,7 @@ int battle_attr_ratio(int atk_elem,int def_type, int def_lv) * Added passing of the chars so that the status changes can affect it. [Skotlex] * Note: Passing src/target == NULL is perfectly valid, it skips SC_ checks. *------------------------------------------*/ -int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 damage,int atk_elem,int def_type, int def_lv) +static int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 damage, int atk_elem, int def_type, int def_lv) { struct status_change *sc=NULL, *tsc=NULL; int ratio; @@ -437,8 +449,10 @@ int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 d return damage + (damage * (ratio - 100) / 100); } +// [malufett] //FIXME: Missing documentation for flag, flag2 -int64 battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, struct weapon_atk *watk, int nk, bool n_ele, short s_ele, short s_ele_, int size, int type, int flag, int flag2){ // [malufett] +static int64 battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, struct weapon_atk *watk, int nk, bool n_ele, short s_ele, short s_ele_, int size, int type, int flag, int flag2) +{ #ifdef RENEWAL int64 damage, eatk = 0; struct status_change *sc; @@ -510,6 +524,7 @@ int64 battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, u return 0; #endif } + /*========================================== * Calculates the standard damage of a normal attack assuming it hits, * it calculates nothing extra fancy, is needed for magnum breaks WATK_ELEMENT bonus. [Skotlex] @@ -524,7 +539,8 @@ int64 battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, u */ /* 'battle_calc_base_damage' is used on renewal, 'battle_calc_base_damage2' otherwise. */ // FIXME: Missing documentation for flag2 -int64 battle_calc_base_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2) { +static int64 battle_calc_base_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2) +{ int64 damage; struct status_data *st = status->get_status_data(src); struct status_change *sc = status->get_sc(src); @@ -561,7 +577,9 @@ int64 battle_calc_base_damage(struct block_list *src, struct block_list *bl, uin return damage; } -int64 battle_calc_base_damage2(struct status_data *st, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag) { + +static int64 battle_calc_base_damage2(struct status_data *st, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag) +{ unsigned int atkmin=0, atkmax=0; short type = 0; int64 damage = 0; @@ -642,7 +660,8 @@ int64 battle_calc_base_damage2(struct status_data *st, struct weapon_atk *wa, st return damage; } -int64 battle_calc_sizefix(struct map_session_data *sd, int64 damage, int type, int size, bool ignore){ +static int64 battle_calc_sizefix(struct map_session_data *sd, int64 damage, int type, int size, bool ignore) +{ //SizeFix only for players nullpo_retr(damage, sd); if (!(sd->special_state.no_sizefix || (ignore))) @@ -654,7 +673,8 @@ int64 battle_calc_sizefix(struct map_session_data *sd, int64 damage, int type, i * Passive skill damages increases *------------------------------------------*/ // FIXME: type is undocumented -int64 battle_addmastery(struct map_session_data *sd,struct block_list *target,int64 dmg,int type) { +static int64 battle_addmastery(struct map_session_data *sd, struct block_list *target, int64 dmg, int type) +{ int64 damage; struct status_data *st = status->get_status_data(target); int weapon, skill_lv; @@ -692,6 +712,7 @@ int64 battle_addmastery(struct map_session_data *sd,struct block_list *target,in #ifdef RENEWAL if((skill_lv = pc->checkskill(sd,AM_AXEMASTERY)) > 0) damage += (skill_lv * 3); + FALLTHROUGH #endif case W_DAGGER: if((skill_lv = pc->checkskill(sd,SM_SWORD)) > 0) @@ -736,6 +757,7 @@ int64 battle_addmastery(struct map_session_data *sd,struct block_list *target,in if((skill_lv = pc->checkskill(sd,TK_RUN)) > 0) damage += (skill_lv * 10); // No break, fall through to Knuckles + FALLTHROUGH case W_KNUCKLE: if((skill_lv = pc->checkskill(sd,MO_IRONHAND)) > 0) damage += (skill_lv * 3); @@ -764,7 +786,8 @@ int64 battle_addmastery(struct map_session_data *sd,struct block_list *target,in /*========================================== * Calculates ATK masteries. *------------------------------------------*/ -int64 battle_calc_masteryfix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int div, bool left, bool weapon) { +static int64 battle_calc_masteryfix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int div, bool left, bool weapon) +{ int skill2_lv, i; struct status_change *sc; struct map_session_data *sd; @@ -872,7 +895,7 @@ int64 battle_calc_masteryfix(struct block_list *src, struct block_list *target, } #else if( skill_id != ASC_BREAKER && weapon ) // Adv Katar Mastery is does not applies to ASC_BREAKER, but other masteries DO apply >_> - if( sd->status.weapon == W_KATAR && (skill2_lv=pc->checkskill(sd,ASC_KATAR)) > 0 ) + if (sd->weapontype == W_KATAR && (skill2_lv=pc->checkskill(sd,ASC_KATAR)) > 0) damage += damage * (10 + 2 * skill2_lv) / 100; #endif @@ -889,7 +912,7 @@ int64 battle_calc_masteryfix(struct block_list *src, struct block_list *target, damage += damage * ratio / 100; } - if( sd->status.class_ == JOB_ARCH_BISHOP_T || sd->status.class_ == JOB_ARCH_BISHOP ){ + if ((sd->job & MAPID_THIRDMASK) == MAPID_ARCH_BISHOP) { if((skill2_lv = pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) damage += damage * skill2_lv / 100; @@ -898,14 +921,16 @@ int64 battle_calc_masteryfix(struct block_list *src, struct block_list *target, return damage; } -void battle_calc_masteryfix_unknown(struct block_list *src, struct block_list *target, uint16 *skill_id, uint16 *skill_lv, int64 *damage, int *div, bool *left, bool *weapon) { +static void battle_calc_masteryfix_unknown(struct block_list *src, struct block_list *target, uint16 *skill_id, uint16 *skill_lv, int64 *damage, int *div, bool *left, bool *weapon) +{ } /*========================================== * Elemental attribute fix. *------------------------------------------*/ // FIXME: flag is undocumented -int64 battle_calc_elefix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int nk, int n_ele, int s_ele, int s_ele_, bool left, int flag){ +static int64 battle_calc_elefix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int nk, int n_ele, int s_ele, int s_ele_, bool left, int flag) +{ struct status_data *tstatus; nullpo_ret(src); @@ -950,7 +975,8 @@ int64 battle_calc_elefix(struct block_list *src, struct block_list *target, uint #endif return damage; } -int64 battle_calc_cardfix2(struct block_list *src, struct block_list *bl, int64 damage, int s_ele, int nk, int flag) { +static int64 battle_calc_cardfix2(struct block_list *src, struct block_list *bl, int64 damage, int s_ele, int nk, int flag) +{ #ifdef RENEWAL struct map_session_data *tsd; struct status_data *sstatus; @@ -981,6 +1007,7 @@ int64 battle_calc_cardfix2(struct block_list *src, struct block_list *bl, int64 #endif return damage; } + /*========================================== * Calculates card bonuses damage adjustments. * cflag(cardfix flag): @@ -988,14 +1015,11 @@ int64 battle_calc_cardfix2(struct block_list *src, struct block_list *bl, int64 * &2 - atker side cardfix(BF_WEAPON) otherwise target side(BF_WEAPON). *------------------------------------------*/ // FIXME: wflag is undocumented -int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int64 damage, int cflag, int wflag){ +static int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int64 damage, int cflag, int wflag) +{ struct map_session_data *sd, *tsd; -#ifdef RENEWAL - short cardfix = 100; -#else - short cardfix = 1000; -#endif - short t_class, s_class, s_race2, t_race2; + int cardfix = 1000; + int t_class, s_class, s_race2, t_race2; struct status_data *sstatus, *tstatus; int i; @@ -1070,24 +1094,14 @@ int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_ if( tsd->sc.data[SC_PROTECT_MDEF] ) cardfix = cardfix * ( 100 - tsd->sc.data[SC_PROTECT_MDEF]->val1 ) / 100; } -#ifdef RENEWAL - if ( cardfix != 100 ) - damage += damage * (cardfix - 100) / 100; -#else if ( cardfix != 1000 ) damage = damage * cardfix / 1000; -#endif break; case BF_WEAPON: t_race2 = status->get_race2(target); if( cflag&2 ){ if( sd && !(nk&NK_NO_CARDFIX_ATK) ){ - short cardfix_ = -#ifdef RENEWAL - 100; -#else - 1000; -#endif + int cardfix_ = 1000; if( sd->state.arrow_atk ){ cardfix = cardfix * (100 + sd->right_weapon.addrace[tstatus->race] + sd->arrow_addrace[tstatus->race]) / 100; if( !(nk&NK_NO_ELEFIX) ){ @@ -1187,16 +1201,11 @@ int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_ #ifndef RENEWAL if( wflag&BF_LONG ) cardfix = cardfix * (100 + sd->bonus.long_attack_atk_rate) / 100; +#endif if( (cflag&1) && cardfix_ != 1000 ) damage = damage * cardfix_ / 1000; else if( cardfix != 1000 ) damage = damage * cardfix / 1000; -#else - if ((cflag & 1) && cardfix_ != 100) - damage += damage * (cardfix_ - 100) / 100; - else if (cardfix != 100) - damage += damage * (cardfix - 100) / 100; -#endif } }else{ // Target side @@ -1246,13 +1255,8 @@ int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_ #endif if( tsd->sc.data[SC_PROTECT_DEF] ) cardfix = cardfix * (100 - tsd->sc.data[SC_PROTECT_DEF]->val1) / 100; -#ifdef RENEWAL - if ( cardfix != 100 ) - damage += damage * (cardfix - 100) / 100; -#else if( cardfix != 1000 ) damage = damage * cardfix / 1000; -#endif } } break; @@ -1284,13 +1288,8 @@ int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_ cardfix = cardfix*(100 - tsd->subsize[sstatus->size]) / 100; cardfix = cardfix*(100 - tsd->subrace2[s_race2]) / 100; cardfix = cardfix * (100 - tsd->bonus.misc_def_rate) / 100; -#ifdef RENEWAL - if ( cardfix != 100 ) - damage += damage * (cardfix - 100) / 100; -#else if ( cardfix != 1000 ) damage = damage * cardfix / 1000; -#endif } break; } @@ -1306,7 +1305,8 @@ int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_ * &4 - tdef(Total defense reduction) *------------------------------------------*/ // TODO: Add an enum for flag -int64 battle_calc_defense(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int flag, int pdef){ +static int64 battle_calc_defense(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int flag, int pdef) +{ struct status_data *sstatus, *tstatus; struct map_session_data *sd, *tsd; struct status_change *sc, *tsc; @@ -1365,24 +1365,28 @@ int64 battle_calc_defense(int attack_type, struct block_list *src, struct block_ #endif } - if( battle_config.vit_penalty_type && battle_config.vit_penalty_target&target->type ) { - unsigned char target_count; //256 max targets should be a sane max - target_count = unit->counttargeted(target); - if(target_count >= battle_config.vit_penalty_count) { - if(battle_config.vit_penalty_type == 1) { - if( !tsc || !tsc->data[SC_STEELBODY] ) - def1 = (def1 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100; - def2 = (def2 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100; - } else { //Assume type 2 - if( !tsc || !tsc->data[SC_STEELBODY] ) - def1 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num; - def2 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num; + if (battle_config.vit_penalty_type != 0 && (battle_config.vit_penalty_target & target->type) != 0) { + int target_count = unit->counttargeted(target); + if (target_count >= battle_config.vit_penalty_count) { + int penalty = (target_count - (battle_config.vit_penalty_count - 1)) * battle_config.vit_penalty_num; + if (battle_config.vit_penalty_type == 1) { + if (tsc == NULL || tsc->data[SC_STEELBODY] == NULL) + def1 = def1 * (100 - penalty) / 100; + def2 = def2 * (100 - penalty) / 100; + } else { // Assume type 2 + if (tsc == NULL || tsc->data[SC_STEELBODY] == NULL) + def1 -= penalty; + def2 -= penalty; } } #ifndef RENEWAL - if(skill_id == AM_ACIDTERROR) def1 = 0; //Acid Terror ignores only armor defense. [Skotlex] + if (skill_id == AM_ACIDTERROR) + def1 = 0; // Acid Terror ignores only armor defense. [Skotlex] #endif - if(def2 < 1) def2 = 1; + if (def1 < 0) + def1 = 0; + if (def2 < 1) + def2 = 1; } //Vitality reduction from rodatazone: http://rodatazone.simgaming.net/mechanics/substats.php#def if (tsd) { @@ -1494,7 +1498,8 @@ int64 battle_calc_defense(int attack_type, struct block_list *src, struct block_ } // Minstrel/Wanderer number check for chorus skills. -int battle_calc_chorusbonus(struct map_session_data *sd) { +static int battle_calc_chorusbonus(struct map_session_data *sd) +{ int members = 0; if (!sd || !sd->status.party_id) @@ -1510,7 +1515,8 @@ int battle_calc_chorusbonus(struct map_session_data *sd) { } // FIXME: flag is undocumented -int battle_calc_skillratio(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int skillratio, int flag){ +static int battle_calc_skillratio(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int skillratio, int flag) +{ int i; struct status_change *sc, *tsc; struct map_session_data *sd, *tsd; @@ -1663,8 +1669,29 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block break; #endif /** - * Arch Bishop - **/ + * Summoner + **/ + case SU_BITE: + skillratio += 100; + break; + case SU_SCRATCH: + skillratio += -50 + 50 * skill_lv; + break; + case SU_SCAROFTAROU: + skillratio += -100 + 100 * skill_lv; + break; + case SU_PICKYPECK: + case SU_PICKYPECK_DOUBLE_ATK: + skillratio += 100 + 100 * skill_lv; + if ((status_get_max_hp(target) / 100) <= 50) + skillratio *= 2; + break; + case SU_LUNATICCARROTBEAT: + skillratio += 100 + 100 * skill_lv; + break; + /** + * Arch Bishop + **/ case AB_JUDEX: skillratio = 300 + 20 * skill_lv; RE_LVL_DMOD(100); @@ -1883,6 +1910,12 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block pc->del_charm(sd, sd->charm_count, sd->charm_type); } break; + case SU_SV_STEMSPEAR: + skillratio += 600; + break; + case SU_CN_METEOR: + skillratio += 100 + 100 * skill_lv; + break; default: battle->calc_skillratio_magic_unknown(&attack_type, src, target, &skill_id, &skill_lv, &skillratio, &flag); break; @@ -2002,7 +2035,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += 100 + 100 * skill_lv + 100 * (skill_lv / 2); break; case RG_BACKSTAP: - if( sd && sd->status.weapon == W_BOW && battle_config.backstab_bow_penalty ) + if (sd != NULL && sd->weapontype == W_BOW && battle_config.backstab_bow_penalty) skillratio += (200 + 40 * skill_lv) / 2; else skillratio += 200 + 40 * skill_lv; @@ -2023,10 +2056,10 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block case CR_HOLYCROSS: { int ratio = 35 * skill_lv; - #ifdef RENEWAL - if(sd && sd->status.weapon == W_2HSPEAR) - ratio *= 2; - #endif +#ifdef RENEWAL + if (sd != NULL && sd->weapontype == W_2HSPEAR) + ratio *= 2; +#endif skillratio += ratio; break; } @@ -2431,7 +2464,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block RE_LVL_DMOD(100); break; case LG_OVERBRAND_PLUSATK: - skillratio = 200 * skill_lv + rnd_value( 10, 100); + skillratio = 200 * skill_lv + rnd->value(10, 100); RE_LVL_DMOD(100); break; case LG_RAYOFGENESIS: @@ -2684,7 +2717,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += 2*sc->data[SC_TRUESIGHT]->val1; if( sc->data[SC_LKCONCENTRATION] ) skillratio += sc->data[SC_LKCONCENTRATION]->val2; - if( sd && sd->status.weapon == W_KATAR && (i=pc->checkskill(sd,ASC_KATAR)) > 0 ) + if (sd != NULL && sd->weapontype == W_KATAR && (i=pc->checkskill(sd,ASC_KATAR)) > 0) skillratio += skillratio * (10 + 2 * i) / 100; #endif if( (!skill_id || skill_id == KN_AUTOCOUNTER) && sc->data[SC_CRUSHSTRIKE] ){ @@ -2705,10 +2738,12 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block return skillratio; } -void battle_calc_skillratio_magic_unknown(int *attack_type, struct block_list *src, struct block_list *target, uint16 *skill_id, uint16 *skill_lv, int *skillratio, int *flag) { +static void battle_calc_skillratio_magic_unknown(int *attack_type, struct block_list *src, struct block_list *target, uint16 *skill_id, uint16 *skill_lv, int *skillratio, int *flag) +{ } -void battle_calc_skillratio_weapon_unknown(int *attack_type, struct block_list *src, struct block_list *target, uint16 *skill_id, uint16 *skill_lv, int *skillratio, int *flag) { +static void battle_calc_skillratio_weapon_unknown(int *attack_type, struct block_list *src, struct block_list *target, uint16 *skill_id, uint16 *skill_lv, int *skillratio, int *flag) +{ } /*========================================== @@ -2716,7 +2751,8 @@ void battle_calc_skillratio_weapon_unknown(int *attack_type, struct block_list * * ATK may be MISS, BLOCKED FAIL, reduce, increase, end status... * After this we apply bg/gvg reduction *------------------------------------------*/ -int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damage *d,int64 damage,uint16 skill_id,uint16 skill_lv) { +static int64 battle_calc_damage(struct block_list *src, struct block_list *bl, struct Damage *d, int64 damage, uint16 skill_id, uint16 skill_lv) +{ struct map_session_data *s_sd, *t_sd; struct status_change *s_sc, *sc; struct status_change_entry *sce; @@ -2840,7 +2876,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam if( sc->data[SC__MAELSTROM] && (flag&BF_MAGIC) && skill_id && (skill->get_inf(skill_id)&INF_GROUND_SKILL) ) { // {(Maelstrom Skill LevelxAbsorbed Skill Level)+(Caster's Job/5)}/2 int sp = (sc->data[SC__MAELSTROM]->val1 * skill_lv + (t_sd ? t_sd->status.job_level / 5 : 0)) / 2; - status->heal(bl, 0, sp, 3); + status->heal(bl, 0, sp, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); d->dmg_lv = ATK_BLOCK; return 0; } @@ -2993,7 +3029,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam status_change_end(bl,SC_DEEP_SLEEP,INVALID_TIMER); } if( s_sd && t_sd && sc->data[SC_COLD] && flag&BF_WEAPON ){ - switch(s_sd->status.weapon){ + switch (s_sd->weapontype) { case W_MACE: case W_2HMACE: case W_1HAXE: @@ -3004,6 +3040,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam case W_WHIP: if(!t_sd->state.arrow_atk) break; + FALLTHROUGH case W_BOW: case W_REVOLVER: case W_RIFLE: @@ -3064,6 +3101,9 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam damage -= 50 * damage / 100;//50% reduction to physical ranged attacks } + if (sc->data[SC_SU_STOOP]) + damage -= damage * 90 / 100; + // Compressed code, fixed by map.h [Epoque] if (src->type == BL_MOB) { const struct mob_data *md = BL_UCCAST(BL_MOB, src); @@ -3131,7 +3171,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam if( (sce = sc->data[SC_STONEHARDSKIN]) && flag&(BF_SHORT|BF_WEAPON) && damage > 0 ) { sce->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX); if( src->type == BL_PC ) { - if (s_sd && s_sd->status.weapon != W_BOW) + if (s_sd != NULL && s_sd->weapontype != W_BOW) skill->break_equip(src, EQP_WEAPON, 3000, BCT_SELF); } else skill->break_equip(src, EQP_WEAPON, 3000, BCT_SELF); @@ -3172,18 +3212,30 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam status_change_end(bl, SC_KYRIE, INVALID_TIMER); } + if ((sce = sc->data[SC_TUNAPARTY]) != NULL && damage > 0) { + clif->specialeffect(bl, 336, AREA); + sce->val2 -= (int)cap_value(damage, INT_MIN, INT_MAX); + if (sce->val2 >= 0) { + damage = 0; + } else { + damage = -sce->val2; + } + if (sce->val2 <= 0) { + status_change_end(bl, SC_TUNAPARTY, INVALID_TIMER); + } + } + if( sc->data[SC_MEIKYOUSISUI] && rnd()%100 < 40 ) // custom value damage = 0; if (!damage) return 0; if( (sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && rnd()%100 < sce->val1 ) { - int dx[8]={0,-1,-1,-1,0,1,1,1}; - int dy[8]={1,1,0,-1,-1,-1,0,1}; - uint8 dir = map->calc_dir(bl, src->x, src->y); - if( unit->movepos(bl, src->x-dx[dir], src->y-dy[dir], 1, 1) ) { - clif->slide(bl,src->x-dx[dir],src->y-dy[dir]); - unit->setdir(bl, dir); + enum unit_dir dir = map->calc_dir(bl, src->x, src->y); + Assert_ret(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX); + if (unit->movepos(bl, src->x - dirx[dir], src->y - diry[dir], 1, 1)) { + clif->slide(bl, src->x - dirx[dir], src->y - diry[dir]); + unit->set_dir(bl, dir); } d->dmg_lv = ATK_DEF; status_change_end(bl, SC_LIGHTNINGWALK, INVALID_TIMER); @@ -3194,7 +3246,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam //(since battle_drain is strictly for players currently) if ((sce=sc->data[SC_HAMI_BLOODLUST]) && flag&BF_WEAPON && damage > 0 && rnd()%100 < sce->val3) - status->heal(src, damage*sce->val4/100, 0, 3); + status->heal(src, damage*sce->val4/100, 0, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); if( (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 && sc->fv_counter <= sce->val3 ) @@ -3263,30 +3315,8 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam } } /* no data claims these settings affect anything other than players */ - if( damage && t_sd && bl->type == BL_PC ) { - switch( skill_id ) { - //case PA_PRESSURE: /* pressure also belongs to this list but it doesn't reach this area -- so don't worry about it */ - case HW_GRAVITATION: - case NJ_ZENYNAGE: - case KO_MUCHANAGE: - break; - default: - if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex] - if (flag&BF_WEAPON) - damage = damage * map->list[bl->m].weapon_damage_rate / 100; - if (flag&BF_MAGIC) - damage = damage * map->list[bl->m].magic_damage_rate / 100; - if (flag&BF_MISC) - damage = damage * map->list[bl->m].misc_damage_rate / 100; - } else { //Normal attacks get reductions based on range. - if (flag & BF_SHORT) - damage = damage * map->list[bl->m].short_damage_rate / 100; - if (flag & BF_LONG) - damage = damage * map->list[bl->m].long_damage_rate / 100; - } - if(!damage) damage = 1; - break; - } + if (damage && t_sd && bl->type == BL_PC) { + damage = battle->calc_pc_damage(src, bl, d, damage, skill_id, skill_lv); } if(battle_config.skill_min_damage && damage > 0 && damage < div_) @@ -3331,11 +3361,43 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam return damage; } +static int64 battle_calc_pc_damage(struct block_list *src, struct block_list *bl, struct Damage *d, int64 damage, uint16 skill_id, uint16 skill_lv) +{ + int flag = d->flag; + + switch (skill_id) { + //case PA_PRESSURE: /* pressure also belongs to this list but it doesn't reach this area -- so don't worry about it */ + case HW_GRAVITATION: + case NJ_ZENYNAGE: + case KO_MUCHANAGE: + break; + default: + if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex] + if (flag & BF_WEAPON) + damage = damage * map->list[bl->m].weapon_damage_rate / 100; + if (flag & BF_MAGIC) + damage = damage * map->list[bl->m].magic_damage_rate / 100; + if (flag & BF_MISC) + damage = damage * map->list[bl->m].misc_damage_rate / 100; + } else { //Normal attacks get reductions based on range. + if (flag & BF_SHORT) + damage = damage * map->list[bl->m].short_damage_rate / 100; + if (flag & BF_LONG) + damage = damage * map->list[bl->m].long_damage_rate / 100; + } + if (!damage) + damage = 1; + break; + } + return damage; +} + /*========================================== * Calculates BG related damage adjustments. *------------------------------------------*/ // FIXME: flag is undocumented -int64 battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int64 damage, int div_, uint16 skill_id, uint16 skill_lv, int flag) { +static int64 battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int64 damage, int div_, uint16 skill_id, uint16 skill_lv, int flag) +{ if (!damage) return 0; @@ -3355,7 +3417,8 @@ int64 battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int64 * Calculates GVG related damage adjustments. *------------------------------------------*/ // FIXME: flag is undocumented -int64 battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int64 damage,int div_,uint16 skill_id,uint16 skill_lv,int flag) { +static int64 battle_calc_gvg_damage(struct block_list *src, struct block_list *bl, int64 damage, int div_, uint16 skill_id, uint16 skill_lv, int flag) +{ struct mob_data* md = BL_CAST(BL_MOB, bl); int class_ = status->get_class(bl); @@ -3403,11 +3466,6 @@ int64 battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int64 case NC_SELFDESTRUCTION: break; default: - /* Uncomment if you want god-mode Emperiums at 100 defense. [Kisuka] - if (md && md->guardian_data) { - damage -= damage * (md->guardian_data->castle->defense/100) * battle_config.castle_defense_rate/100; - } - */ break; } return damage; @@ -3416,7 +3474,8 @@ int64 battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int64 /*========================================== * HP/SP drain calculation *------------------------------------------*/ -int battle_calc_drain(int64 damage, int rate, int per) { +static int battle_calc_drain(int64 damage, int rate, int per) +{ int64 diff = 0; if (per && rnd()%1000 < rate) { @@ -3434,7 +3493,7 @@ int battle_calc_drain(int64 damage, int rate, int per) { /*========================================== * Consumes ammo for the given skill. *------------------------------------------*/ -void battle_consume_ammo(struct map_session_data *sd, int skill_id, int lv) +static void battle_consume_ammo(struct map_session_data *sd, int skill_id, int lv) { int qty=1; @@ -3454,7 +3513,8 @@ void battle_consume_ammo(struct map_session_data *sd, int skill_id, int lv) } //Skill Range Criteria -int battle_range_type(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv) { +static int battle_range_type(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv) +{ nullpo_retr(BF_SHORT, src); nullpo_retr(BF_SHORT, target); @@ -3478,7 +3538,9 @@ int battle_range_type(struct block_list *src, struct block_list *target, uint16 return BF_SHORT; return BF_LONG; } -int battle_adjust_skill_damage(int m, unsigned short skill_id) { + +static int battle_adjust_skill_damage(int m, unsigned short skill_id) +{ if( map->list[m].skill_count ) { int i; ARR_FIND(0, map->list[m].skill_count, i, map->list[m].skills[i]->skill_id == skill_id ); @@ -3491,7 +3553,8 @@ int battle_adjust_skill_damage(int m, unsigned short skill_id) { return 0; } -int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id) { +static int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id) +{ int i; nullpo_ret(sd); if (!sd->skillblown[0].id) @@ -3503,17 +3566,17 @@ int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id) { } return 0; } + //For quick div adjustment. #define damage_div_fix(dmg, div) do { if ((div) > 1) (dmg)*=(div); else if ((div) < 0) (div)*=-1; } while(0) /*========================================== * battle_calc_magic_attack [DracoRPG] *------------------------------------------*/ // FIXME: mflag is undocumented -struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag) { +static struct Damage battle_calc_magic_attack(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int mflag) +{ int nk; short s_ele = 0; - unsigned int skillratio = 100; //Skill dmg modifiers. - struct map_session_data *sd = NULL; struct status_change *sc; struct Damage ad; @@ -3665,7 +3728,14 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list //Damage calculation from iRO wiki. [Jobbie] ad.damage = status->get_lv(src) * 10 + sstatus->int_; break; + /** + * Summoner + */ + case SU_SV_ROOTTWIST_ATK: + ad.damage = 100; + break; default: { + unsigned int skillratio = 100; //Skill dmg modifiers. MATK_ADD( status->get_matk(src, 2) ); #ifdef RENEWAL ad.damage = battle->calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); @@ -3699,10 +3769,11 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list //Constant/misc additions from skills if (skill_id == WZ_FIREPILLAR) MATK_ADD(100+50*skill_lv); - if( sd && ( sd->status.class_ == JOB_ARCH_BISHOP_T || sd->status.class_ == JOB_ARCH_BISHOP ) && - (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && - (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) - MATK_ADDRATE(i); + if (sd != NULL && (sd->job & MAPID_THIRDMASK) == MAPID_ARCH_BISHOP) { + int eucharistica_level = pc->checkskill(sd,AB_EUCHARISTICA); + if (eucharistica_level > 0 && (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK)) + MATK_ADDRATE(eucharistica_level); + } } } #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE @@ -3840,7 +3911,8 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list * Calculate Misc damage for skill_id *------------------------------------------*/ // FIXME: mflag is undocumented -struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag) { +static struct Damage battle_calc_misc_attack(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int mflag) +{ int temp; short i, nk; short s_ele; @@ -4143,16 +4215,16 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * hitrate = 80; //Default hitrate #endif - if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { - unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit->counttargeted(target); - if(attacker_count >= battle_config.agi_penalty_count) - { + if (battle_config.agi_penalty_type != 0 && (battle_config.agi_penalty_target & target->type) != 0) { + int attacker_count = unit->counttargeted(target); + if (attacker_count >= battle_config.agi_penalty_count) { + int penalty = (attacker_count - (battle_config.agi_penalty_count - 1)) * battle_config.agi_penalty_num; if (battle_config.agi_penalty_type == 1) - flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; + flee = flee * (100 - penalty) / 100; else // assume type 2: absolute reduction - flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; - if(flee < 1) flee = 1; + flee -= penalty; + if (flee < 1) + flee = 1; } } @@ -4240,7 +4312,9 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * switch( skill_id ) { case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: - if( md.damage == 1 ) break; + if (md.damage == 1) + break; + FALLTHROUGH case RA_CLUSTERBOMB: { struct Damage wd; @@ -4257,19 +4331,21 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * break; } + battle->reflect_trap(target, src, &md, skill_id); + return md; } -void battle_calc_misc_attack_unknown(struct block_list *src, struct block_list *target, uint16 *skill_id, uint16 *skill_lv, int *mflag, struct Damage *md) { +static void battle_calc_misc_attack_unknown(struct block_list *src, struct block_list *target, uint16 *skill_id, uint16 *skill_lv, int *mflag, struct Damage *md) +{ } /*========================================== * battle_calc_weapon_attack (by Skotlex) *------------------------------------------*/ // FIXME: wflag is undocumented -struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int wflag) +static struct Damage battle_calc_weapon_attack(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int wflag) { - unsigned int skillratio = 100; //Skill dmg modifiers. short temp=0; short s_ele, s_ele_; int i, nk; @@ -4505,8 +4581,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if(!skill_id) { //Skills ALWAYS use ONLY your right-hand weapon (tested on Aegis 10.2) - if (sd && sd->weapontype1 == 0 && sd->weapontype2 > 0) - { + if (sd && sd->weapontype1 == W_FIST && sd->weapontype2 != W_FIST) { flag.rh=0; flag.lh=1; } @@ -4541,16 +4616,19 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list wd.div_ = 5; break; } + FALLTHROUGH case 4: if( chance < 7){// 6 % chance to attack 4 times. wd.div_ = 4; break; } + FALLTHROUGH case 3: if( chance < 10){// 9 % chance to attack 3 times. wd.div_ = 3; break; } + FALLTHROUGH case 2: case 1: if( chance < 13){// 12 % chance to attack 2 times. @@ -4575,13 +4653,17 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list { short cri = sstatus->cri; if (sd != NULL) { + // Racial crit bonuses are affected by katar's crit bonus. + if (battle_config.show_katar_crit_bonus && sd->weapontype == W_KATAR) + cri += sd->critaddrace[tstatus->race] * 2; + else + cri += sd->critaddrace[tstatus->race]; + // if show_katar_crit_bonus is enabled, it already done the calculation in status.c - if (!battle_config.show_katar_crit_bonus && sd->status.weapon == W_KATAR) { + if (!battle_config.show_katar_crit_bonus && sd->weapontype == W_KATAR) { cri <<= 1; } - cri+= sd->critaddrace[tstatus->race]; - if (flag.arrow) { cri += sd->bonus.arrow_cri; } @@ -4604,6 +4686,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if(!(sc && sc->data[SC_AUTOCOUNTER])) break; status_change_end(src, SC_AUTOCOUNTER, INVALID_TIMER); + FALLTHROUGH case KN_AUTOCOUNTER: if(battle_config.auto_counter_type && (battle_config.auto_counter_type&src->type)) @@ -4663,15 +4746,16 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list short hitrate = 80; //Default hitrate #endif - if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { - unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit->counttargeted(target); - if(attacker_count >= battle_config.agi_penalty_count) { + if (battle_config.agi_penalty_type != 0 && (battle_config.agi_penalty_target & target->type) != 0) { + int attacker_count = unit->counttargeted(target); + if (attacker_count >= battle_config.agi_penalty_count) { + int penalty = (attacker_count - (battle_config.agi_penalty_count - 1)) * battle_config.agi_penalty_num; if (battle_config.agi_penalty_type == 1) - flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; - else //asume type 2: absolute reduction - flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; - if(flee < 1) flee = 1; + flee = flee * (100 - penalty) / 100; + else // asume type 2: absolute reduction + flee -= penalty; + if (flee < 1) + flee = 1; } } @@ -4748,8 +4832,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if ((temp = pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0) hitrate += hitrate * ( 2 * temp ) / 100; - if( (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DAGGER) && - (temp = pc->checkskill(sd, GN_TRAINING_SWORD))>0 ) + if ((sd->weapontype == W_1HSWORD || sd->weapontype == W_DAGGER) && (temp = pc->checkskill(sd, GN_TRAINING_SWORD)) > 0) hitrate += 3 * temp; } @@ -4768,6 +4851,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list } //End hit/miss calculation if (flag.hit && !flag.infdef) { //No need to do the math for plants + unsigned int skillratio = 100; //Skill dmg modifiers. //Hitting attack //Assuming that 99% of the cases we will not need to check for the flag.rh... we don't. @@ -4888,9 +4972,10 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list (!skill_id && sc && sc->data[SC_HLIF_CHANGE]?4:0)| (sc && sc->data[SC_WEAPONPERFECT]?8:0); if (flag.arrow && sd) - switch(sd->status.weapon) { + switch (sd->weapontype) { case W_BOW: case W_REVOLVER: + case W_RIFLE: case W_GATLING: case W_SHOTGUN: case W_GRENADE: @@ -5064,7 +5149,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list wd.damage = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage, wd.div_, 0, flag.weapon); wd.damage = battle->calc_cardfix2(src, target, wd.damage, s_ele, nk, wd.flag); } - /* Fall through */ + FALLTHROUGH #endif default: ATK_RATE(battle->calc_skillratio(BF_WEAPON, src, target, skill_id, skill_lv, skillratio, wflag)); @@ -5180,8 +5265,16 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if (hd != NULL) ATK_ADD(hd->homunculus.spiritball * 3); } + if ((wd.flag&(BF_LONG|BF_MAGIC)) == BF_LONG) { + if (sd != NULL && pc->checkskill(sd, SU_POWEROFLIFE) > 0) { + if (pc->checkskill(sd, SU_SCAROFTAROU) == 5 && pc->checkskill(sd, SU_PICKYPECK) == 5 && pc->checkskill(sd, SU_ARCLOUSEDASH) == 5 && pc->checkskill(sd, SU_LUNATICCARROTBEAT) == 5) { + ATK_ADDRATE(20); + } + } + } } + switch (skill_id) { case AS_SONICBLOW: if (sc && sc->data[SC_SOULLINK] && @@ -5244,6 +5337,9 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if( sc && sc->data[SC_MTF_RANGEATK] ) ATK_ADDRATE(sc->data[SC_MTF_RANGEATK]->val1);// temporary it should be 'bonus.long_attack_atk_rate' #endif + if (sc != NULL && sc->data[SC_ARCLOUSEDASH] != NULL && sc->data[SC_ARCLOUSEDASH]->val4 != 0) { + ATK_ADDRATE(sc->data[SC_ARCLOUSEDASH]->val4); + } if( (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) ATK_ADDRATE(-i); @@ -5454,7 +5550,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list #endif if( flag.infdef ) { //Plants receive 1 damage when hit - short class_ = status->get_class(target); + int class_ = status->get_class(target); if( flag.hit || wd.damage > 0 ) wd.damage = wd.div_; // In some cases, right hand no need to have a weapon to increase damage if( flag.lh && (flag.hit || wd.damage2 > 0) ) @@ -5486,13 +5582,13 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list //Dual-wield if (wd.damage) { temp = pc->checkskill(sd,AS_RIGHT) * 10; - if( (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO ) + if ((sd->job & MAPID_UPPERMASK) == MAPID_KAGEROUOBORO) temp = pc->checkskill(sd,KO_RIGHT) * 10 + 20; ATK_RATER( 50 + temp ); } if (wd.damage2) { temp = pc->checkskill(sd,AS_LEFT) * 10; - if( (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO ) + if ((sd->job & MAPID_UPPERMASK) == MAPID_KAGEROUOBORO) temp = pc->checkskill(sd,KO_LEFT) * 10 + 20; ATK_RATEL( 30 + temp ); } @@ -5503,7 +5599,8 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if(wd.damage < 1) wd.damage = 1; if(wd.damage2 < 1) wd.damage2 = 1; #endif - } else if(sd->status.weapon == W_KATAR && !skill_id) { //Katars (offhand damage only applies to normal attacks, tested on Aegis 10.2) + } else if (sd->weapontype == W_KATAR && skill_id == 0) { + // Katars (offhand damage only applies to normal attacks, tested on Aegis 10.2) temp = pc->checkskill(sd,TF_DOUBLE); wd.damage2 = wd.damage * (1 + (temp * 2))/100; @@ -5622,7 +5719,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list } //Reject Sword bugreport:4493 by Daegaladh if (wd.damage != 0 && tsc != NULL && tsc->data[SC_SWORDREJECT] != NULL - && (sd == NULL || sd->weapontype1 == W_DAGGER || sd->weapontype1 == W_1HSWORD || sd->status.weapon == W_2HSWORD) + && (sd == NULL || sd->weapontype1 == W_DAGGER || sd->weapontype1 == W_1HSWORD || sd->weapontype == W_2HSWORD) && rnd()%100 < tsc->data[SC_SWORDREJECT]->val2 ) { ATK_RATER(50); @@ -5645,7 +5742,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list /*========================================== * Battle main entry, from skill->attack *------------------------------------------*/ -struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct block_list *target,uint16 skill_id,uint16 skill_lv,int count) +static struct Damage battle_calc_attack(int attack_type, struct block_list *bl, struct block_list *target, uint16 skill_id, uint16 skill_lv, int count) { struct Damage d; struct map_session_data *sd=BL_CAST(BL_PC,bl); @@ -5707,7 +5804,8 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl } //Performs reflect damage (magic (maya) is performed over skill.c). -void battle_reflect_damage(struct block_list *target, struct block_list *src, struct Damage *wd,uint16 skill_id) { +static void battle_reflect_damage(struct block_list *target, struct block_list *src, struct Damage *wd, uint16 skill_id) +{ int64 damage, rdamage = 0, trdamage = 0; struct map_session_data *sd, *tsd; struct status_change *sc; @@ -5758,10 +5856,10 @@ void battle_reflect_damage(struct block_list *target, struct block_list *src, st if( wd->flag & BF_SHORT ) { if( !is_boss(src) ) { if( sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION ) { - uint8 dir = map->calc_dir(target,src->x,src->y), - t_dir = unit->getdir(target); + enum unit_dir dir = map->calc_dir(target, src->x, src->y); + enum unit_dir t_dir = unit->getdir(target); - if( !map->check_dir(dir,t_dir) ) { + if (map->check_dir(dir, t_dir) == 0) { int64 rd1 = damage * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage. trdamage += rdamage = rd1 - (damage = rd1 * 30 / 100); // not normalized as intended. @@ -5829,21 +5927,21 @@ void battle_reflect_damage(struct block_list *target, struct block_list *src, st delay += 100;/* gradual increase so the numbers don't clip in the client */ } if( sc->data[SC_LG_REFLECTDAMAGE] && rnd()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) { - bool change = false; - NORMALIZE_RDAMAGE(damage * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100); trdamage -= rdamage;/* wont count towards total */ - if( sd && !sd->state.autocast ) { - change = true; - sd->state.autocast = 1; + enum autocast_type ac_type; + + if (sd != NULL) { + ac_type = sd->autocast.type; + sd->autocast.type = AUTOCAST_TEMP; } map->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,delay,wd->dmotion,rdamage,status_get_race(target)); - if( change ) - sd->state.autocast = 0; + if (sd != NULL) + sd->autocast.type = ac_type; delay += 150;/* gradual increase so the numbers don't clip in the client */ @@ -5915,7 +6013,38 @@ void battle_reflect_damage(struct block_list *target, struct block_list *src, st #undef NORMALIZE_RDAMAGE } -void battle_drain(struct map_session_data *sd, struct block_list *tbl, int64 rdamage, int64 ldamage, int race, int boss) +/** + * Reflects damage from certain traps, if battle_config.trap_reflect is true. + * @param target : Player who triggered the trap + * @param src : Player who set the trap + * @param md : Trap damage structure + * @param skill_id : Trap skill ID + */ +static void battle_reflect_trap(struct block_list *target, struct block_list *src, struct Damage *md, uint16 skill_id) +{ + if (battle_config.trap_reflect == true) { + if (src != target) { // Don't reflect your own damage + switch (skill_id) { + case HT_CLAYMORETRAP: + case HT_LANDMINE: + case HT_FREEZINGTRAP: + case HT_BLASTMINE: + // Needs official info + //case RA_CLUSTERBOMB: + //case RA_FIRINGTRAP: + //case RA_ICEBOUNDTRAP: + //case GN_THORNS_TRAP: + //case KO_MAKIBISHI: + case MA_LANDMINE: + case MA_FREEZINGTRAP: + battle->reflect_damage(target, src, md, skill_id); + break; + } + } + } +} + +static void battle_drain(struct map_session_data *sd, struct block_list *tbl, int64 rdamage, int64 ldamage, int race, int boss) { struct weapon_data *wd; int type, thp = 0, tsp = 0, rhp = 0, rsp = 0, hp, sp, i; @@ -5968,13 +6097,15 @@ void battle_drain(struct map_session_data *sd, struct block_list *tbl, int64 rda if (!thp && !tsp) return; - status->heal(&sd->bl, thp, tsp, battle_config.show_hp_sp_drain ? 3 : 1); + status->heal(&sd->bl, thp, tsp, STATUS_HEAL_FORCED | (battle_config.show_hp_sp_drain ? STATUS_HEAL_SHOWEFFECT : STATUS_HEAL_DEFAULT)); if (rhp || rsp) status_zap(tbl, rhp, rsp); } + // Deals the same damage to targets in area. [pakpil] -int battle_damage_area(struct block_list *bl, va_list ap) { +static int battle_damage_area(struct block_list *bl, va_list ap) +{ int64 tick; int amotion, dmotion, damage; struct block_list *src; @@ -5989,31 +6120,70 @@ int battle_damage_area(struct block_list *bl, va_list ap) { if (bl->type == BL_MOB && BL_UCCAST(BL_MOB, bl)->class_ == MOBID_EMPELIUM) return 0; if( bl != src && battle->check_target(src,bl,BCT_ENEMY) > 0 ) { - struct map_session_data *sd = NULL; nullpo_ret(src); map->freeblock_lock(); - sd = BL_CAST(BL_PC, src); if (src->type == BL_PC) - battle->drain(sd, bl, damage, damage, status_get_race(bl), is_boss(bl)); + battle->drain(BL_UCAST(BL_PC, src), bl, damage, damage, status_get_race(bl), is_boss(bl)); if( amotion ) battle->delay_damage(tick, amotion,src,bl,0,CR_REFLECTSHIELD,0,damage,ATK_DEF,0,true); else status_fix_damage(src,bl,damage,0); clif->damage(bl,bl,amotion,dmotion,damage,1,BDT_ENDURE,0); - if (src->type != BL_PC || !sd->state.autocast) + if (src->type != BL_PC || BL_UCCAST(BL_PC, src)->autocast.type != AUTOCAST_TEMP) skill->additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); map->freeblock_unlock(); } return 0; } + +static bool battle_check_arrows(struct map_session_data *sd) +{ + int index = sd->equip_index[EQI_AMMO]; + if (index < 0) { + if (sd->weapontype1 > W_KATAR && sd->weapontype1 < W_HUUMA) + clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0, 0); + else + clif->arrow_fail(sd, 0); + return false; + } + //Ammo check by Ishizu-chan + if (sd->inventory_data[index]) { + switch (sd->weapontype) { + case W_BOW: + if (sd->inventory_data[index]->subtype != A_ARROW) { + clif->arrow_fail(sd, 0); + return false; + } + break; + case W_REVOLVER: + case W_RIFLE: + case W_GATLING: + case W_SHOTGUN: + if (sd->inventory_data[index]->subtype != A_BULLET) { + clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0, 0); + return false; + } + break; + case W_GRENADE: + if (sd->inventory_data[index]->subtype != A_GRENADE) { + clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0, 0); + return false; + } + break; + } + } + return true; +} + /*========================================== * Do a basic physical attack (call trough unit_attack_timer) *------------------------------------------*/ // FIXME: flag is undocumented -enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* target, int64 tick, int flag) { +static enum damage_lv battle_weapon_attack(struct block_list *src, struct block_list *target, int64 tick, int flag) +{ struct map_session_data *sd = NULL, *tsd = NULL; struct status_data *sstatus, *tstatus; struct status_change *sc, *tsc; @@ -6043,42 +6213,11 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if (sd) { - sd->state.arrow_atk = (sd->status.weapon == W_BOW || (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)); + sd->state.arrow_atk = (sd->weapontype == W_BOW || (sd->weapontype >= W_REVOLVER && sd->weapontype <= W_GRENADE)); if (sd->state.arrow_atk) { - int index = sd->equip_index[EQI_AMMO]; - if (index<0) { - if ( sd->weapontype1 > W_KATAR && sd->weapontype1 < W_HUUMA ) - clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); - else - clif->arrow_fail(sd, 0); + if (battle->check_arrows(sd) == false) return ATK_NONE; - } - //Ammo check by Ishizu-chan - if (sd->inventory_data[index]) - switch (sd->status.weapon) { - case W_BOW: - if (sd->inventory_data[index]->look != A_ARROW) { - clif->arrow_fail(sd,0); - return ATK_NONE; - } - break; - case W_REVOLVER: - case W_RIFLE: - case W_GATLING: - case W_SHOTGUN: - if (sd->inventory_data[index]->look != A_BULLET) { - clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); - return ATK_NONE; - } - break; - case W_GRENADE: - if (sd->inventory_data[index]->look != A_GRENADE) { - clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); - return ATK_NONE; - } - break; - } } } if (sc && sc->count) { @@ -6088,10 +6227,10 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER); } if( tsc && tsc->data[SC_AUTOCOUNTER] && status->check_skilluse(target, src, KN_AUTOCOUNTER, 1) ) { - uint8 dir = map->calc_dir(target,src->x,src->y); - int t_dir = unit->getdir(target); + enum unit_dir dir = map->calc_dir(target, src->x, src->y); + enum unit_dir t_dir = unit->getdir(target); int dist = distance_bl(src, target); - if(dist <= 0 || (!map->check_dir(dir,t_dir) && dist <= tstatus->rhw.range+1)) { + if(dist <= 0 || (map->check_dir(dir, t_dir) == 0 && dist <= tstatus->rhw.range + 1)) { uint16 skill_lv = tsc->data[SC_AUTOCOUNTER]->val1; clif->skillcastcancel(target); //Remove the casting bar. [Skotlex] clif->damage(src, target, sstatus->amotion, 1, 0, 1, BDT_NORMAL, 0); //Display MISS. @@ -6100,7 +6239,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t return ATK_BLOCK; } } - if( tsc && tsc->data[SC_BLADESTOP_WAIT] && !is_boss(src) && (src->type == BL_PC || tsd == NULL || distance_bl(src, target) <= (tsd->status.weapon == W_FIST ? 1 : 2)) ) + if( tsc && tsc->data[SC_BLADESTOP_WAIT] && !is_boss(src) && (src->type == BL_PC || tsd == NULL || distance_bl(src, target) <= (tsd->weapontype == W_FIST ? 1 : 2)) ) { uint16 skill_lv = tsc->data[SC_BLADESTOP_WAIT]->val1; int duration = skill->get_time2(MO_BLADESTOP,skill_lv); @@ -6180,6 +6319,18 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if (sd && sd->state.arrow_atk) //Consume arrow. battle->consume_ammo(sd, 0, 0); + if (target->type == BL_MOB) { + struct mob_data *md = BL_CAST(BL_MOB, target); + if (md != NULL) { + if (md->db->dmg_taken_rate != 100) { + if (wd.damage > 0) + wd.damage = apply_percentrate64(wd.damage, md->db->dmg_taken_rate, 100); + if (wd.damage2 > 0) + wd.damage2 = apply_percentrate64(wd.damage2, md->db->dmg_taken_rate, 100); + } + } + } + damage = wd.damage + wd.damage2; if( damage > 0 && src != target ) { if( sc && sc->data[SC_DUPLELIGHT] && (wd.flag&BF_SHORT) && rnd()%100 <= 10+2*sc->data[SC_DUPLELIGHT]->val1 ){ @@ -6220,7 +6371,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if (d_bl != NULL && ((d_bl->type == BL_MER && d_md->master != NULL && d_md->master->bl.id == target->id) - || (d_bl->type == BL_PC && d_sd->devotion[sce->val2] == target->id) + || (d_sd != NULL && d_bl->type == BL_PC && d_sd->devotion[sce->val2] == target->id) ) && check_distance_bl(target, d_bl, sce->val3) ) { @@ -6260,17 +6411,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t sp = skill->get_sp(skill_id,skill_lv) * 2 / 3; if (status->charge(src, 0, sp)) { - switch (skill->get_casttype(skill_id)) { - case CAST_GROUND: - skill->castend_pos2(src, target->x, target->y, skill_id, skill_lv, tick, flag); - break; - case CAST_NODAMAGE: - skill->castend_nodamage_id(src, target, skill_id, skill_lv, tick, flag); - break; - case CAST_DAMAGE: - skill->castend_damage_id(src, target, skill_id, skill_lv, tick, flag); - break; - } + skill->castend_type(skill->get_casttype(skill_id), src, target, skill_id, skill_lv, tick, flag); } } if (sd) { @@ -6308,29 +6449,18 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } if( type != CAST_GROUND ) { - clif->skill_fail(sd,r_skill,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd, r_skill, USESKILL_FAIL_LEVEL, 0, 0); map->freeblock_unlock(); return wd.dmg_lv; } } - sd->state.autocast = 1; + sd->autocast.type = AUTOCAST_TEMP; skill->consume_requirement(sd,r_skill,r_lv,3); - switch( type ) { - case CAST_GROUND: - skill->castend_pos2(src, target->x, target->y, r_skill, r_lv, tick, flag); - break; - case CAST_NODAMAGE: - skill->castend_nodamage_id(src, target, r_skill, r_lv, tick, flag); - break; - case CAST_DAMAGE: - skill->castend_damage_id(src, target, r_skill, r_lv, tick, flag); - break; - } - sd->state.autocast = 0; - + skill->castend_type(type, src, target, r_skill, r_lv, tick, flag); + sd->autocast.type = AUTOCAST_NONE; sd->ud.canact_tick = tick + skill->delay_fix(src, r_skill, r_lv); - clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, r_skill, r_lv), 0, 0, 1); + clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, skill->delay_fix(src, r_skill, r_lv), 0, 0, 1); } } @@ -6375,7 +6505,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t #undef GET_NORMAL_ATTACK #undef GET_NORMAL_ATTACK2 -bool battle_check_undead(int race,int element) +static bool battle_check_undead(int race, int element) { if(battle_config.undead_detect_type == 0) { if(element == ELE_UNDEAD) @@ -6393,7 +6523,7 @@ bool battle_check_undead(int race,int element) } //Returns the upmost level master starting with the given object -struct block_list *battle_get_master(struct block_list *src) +static struct block_list *battle_get_master(struct block_list *src) { struct block_list *prev = NULL; //Used for infinite loop check (master of yourself?) nullpo_retr(NULL, src); @@ -6457,7 +6587,7 @@ struct block_list *battle_get_master(struct block_list *src) * -1: flag fails * 0: Invalid target (non-targetable ever) *------------------------------------------*/ -int battle_check_target( struct block_list *src, struct block_list *target,int flag) +static int battle_check_target(struct block_list *src, struct block_list *target, int flag) { int16 m; //map int state = 0; //Initial state none @@ -6469,10 +6599,6 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f m = target->m; - if (flag & BCT_ENEMY && (map->getcell(m, src, src->x, src->y, CELL_CHKBASILICA) || map->getcell(m, src, target->x, target->y, CELL_CHKBASILICA))) { - return -1; - } - //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 ) @@ -6481,6 +6607,11 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if( (s_bl = battle->get_master(src)) == NULL ) s_bl = src; + if ((flag & BCT_ENEMY) != 0 && (status_get_mode(s_bl) & MD_BOSS) == 0 && (map->getcell(m, src, src->x, src->y, CELL_CHKBASILICA) != 0 + || map->getcell(m, src, target->x, target->y, CELL_CHKBASILICA) != 0)) { + return -1; + } + if (s_bl->type == BL_PC) { const struct map_session_data *s_sd = BL_UCCAST(BL_PC, s_bl); switch (t_bl->type) { @@ -6548,6 +6679,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case RK_DRAGONBREATH_WATER: if( !map->list[m].flag.pvp && !map->list[m].flag.gvg ) break; + FALLTHROUGH case 0://you can hit them without skills case MA_REMOVETRAP: case HT_REMOVETRAP: @@ -6612,7 +6744,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if (t_bl == s_bl) break; - if( sd->state.monster_ignore && flag&BCT_ENEMY ) + if (sd->block_action.immune && flag&BCT_ENEMY) return 0; // Global immunity only to Attacks if (sd->status.karma && s_bl->type == BL_PC && BL_UCCAST(BL_PC, s_bl)->status.karma) state |= BCT_ENEMY; // Characters with bad karma may fight amongst them @@ -6737,37 +6869,55 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f return (flag&state)?1:-1; } - if( map_flag_vs(m) ) { + if (map_flag_vs(m)) { //Check rivalry settings. - int sbg_id = 0, tbg_id = 0; - if( map->list[m].flag.battleground ) { + int sbg_id = 0, tbg_id = 0, s_clan = 0, t_clan = 0; + if (map->list[m].flag.battleground) { sbg_id = bg->team_get_id(s_bl); tbg_id = bg->team_get_id(t_bl); + } else if (map->list[m].flag.cvc) { + s_clan = clan->get_id(s_bl); + t_clan = clan->get_id(t_bl); } - if( flag&(BCT_PARTY|BCT_ENEMY) ) { + if (flag & (BCT_PARTY | BCT_ENEMY)) { int s_party = status->get_party_id(s_bl); int s_guild = status->get_guild_id(s_bl); + int t_guild = status->get_guild_id(t_bl); - if( s_party && s_party == status->get_party_id(t_bl) - && !(map->list[m].flag.pvp && map->list[m].flag.pvp_noparty) - && !(map_flag_gvg(m) && map->list[m].flag.gvg_noparty && !( s_guild && s_guild == status->get_guild_id(t_bl) )) - && (!map->list[m].flag.battleground || sbg_id == tbg_id) ) - state |= BCT_PARTY; - else + if (s_party != 0 && s_party == status->get_party_id(t_bl)) { + if (map_flag_gvg(m) && map->list[m].flag.gvg_noparty) { + if (s_guild != 0 && t_guild != 0 && (s_guild == t_guild || guild->isallied(s_guild, t_guild))) + state |= BCT_PARTY; + else + state |= flag & BCT_ENEMY ? BCT_ENEMY : BCT_PARTY; + } else if (!(map->list[m].flag.pvp && map->list[m].flag.pvp_noparty) + && (!map->list[m].flag.battleground || sbg_id == tbg_id)) { + state |= BCT_PARTY; + } else if (!map->list[m].flag.cvc || s_clan == t_clan) { + state |= BCT_PARTY; + } else { + state |= BCT_ENEMY; + } + } else { state |= BCT_ENEMY; + } } - if( flag&(BCT_GUILD|BCT_ENEMY) ) { + if (flag & (BCT_GUILD | BCT_ENEMY)) { int s_guild = status->get_guild_id(s_bl); int t_guild = status->get_guild_id(t_bl); - if( !(map->list[m].flag.pvp && map->list[m].flag.pvp_noguild) + if (!(map->list[m].flag.pvp && map->list[m].flag.pvp_noguild) && s_guild && t_guild - && (s_guild == t_guild || (!(flag&BCT_SAMEGUILD) && guild->isallied(s_guild, t_guild))) - && (!map->list[m].flag.battleground || sbg_id == tbg_id) ) + && (s_guild == t_guild || (!(flag & BCT_SAMEGUILD) && guild->isallied(s_guild, t_guild))) + && (!map->list[m].flag.battleground || sbg_id == tbg_id) + && (!map->list[m].flag.cvc || s_clan == t_clan) + ) { state |= BCT_GUILD; - else + } else { state |= BCT_ENEMY; + } } - if( state&BCT_ENEMY && map->list[m].flag.battleground && sbg_id && sbg_id == tbg_id ) + + if (state & BCT_ENEMY && ((map->list[m].flag.battleground && sbg_id && sbg_id == tbg_id) || (map->list[m].flag.cvc && s_clan && s_clan == t_clan))) state &= ~BCT_ENEMY; if (state&BCT_ENEMY && battle_config.pk_mode && !map_flag_gvg(m) && s_bl->type == BL_PC && t_bl->type == BL_PC) { @@ -6775,11 +6925,11 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f const struct map_session_data *s_sd = BL_UCCAST(BL_PC, s_bl); const struct map_session_data *t_sd = BL_UCCAST(BL_PC, t_bl); if ( - (s_sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE || - (t_sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE || - (int)s_sd->status.base_level < battle_config.pk_min_level || - (int)t_sd->status.base_level < battle_config.pk_min_level || - (battle_config.pk_level_range && abs((int)s_sd->status.base_level - (int)t_sd->status.base_level) > battle_config.pk_level_range) + (s_sd->job & MAPID_UPPERMASK) == MAPID_NOVICE || + (t_sd->job & MAPID_UPPERMASK) == MAPID_NOVICE || + s_sd->status.base_level < battle_config.pk_min_level || + t_sd->status.base_level < battle_config.pk_min_level || + (battle_config.pk_level_range && abs(s_sd->status.base_level - t_sd->status.base_level) > battle_config.pk_level_range) ) state &= ~BCT_ENEMY; } @@ -6807,11 +6957,12 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f return (flag&state)?1:-1; } + /*========================================== * Check if can attack from this range * Basic check then calling path->search for obstacle etc.. *------------------------------------------*/ -bool battle_check_range(struct block_list *src, struct block_list *bl, int range) +static bool battle_check_range(struct block_list *src, struct block_list *bl, int range) { int d; nullpo_retr(false, src); @@ -6864,7 +7015,8 @@ static const struct battle_data { { "player_damage_delay_rate", &battle_config.pc_damage_delay_rate, 100, 0, INT_MAX, }, { "defunit_not_enemy", &battle_config.defnotenemy, 0, 0, 1, }, { "gvg_traps_target_all", &battle_config.vs_traps_bctall, BL_PC, BL_NUL, BL_ALL, }, - { "traps_setting", &battle_config.traps_setting, 0, 0, 1, }, + { "trap_options/visibility", &battle_config.trap_visibility, 2, 0, 2, }, + { "trap_options/display_on_trigger", &battle_config.trap_trigger, 1, 0, 1, }, { "summon_flora_setting", &battle_config.summon_flora, 1|2, 0, 1|2, }, { "clear_skills_on_death", &battle_config.clear_unit_ondeath, BL_NUL, BL_NUL, BL_ALL, }, { "clear_skills_on_warp", &battle_config.clear_unit_onwarp, BL_ALL, BL_NUL, BL_ALL, }, @@ -6899,7 +7051,7 @@ static const struct battle_data { { "chase_range_rate", &battle_config.chase_range_rate, 100, 0, INT_MAX, }, { "gtb_sc_immunity", &battle_config.gtb_sc_immunity, 50, 0, INT_MAX, }, { "guild_max_castles", &battle_config.guild_max_castles, 0, 0, INT_MAX, }, - { "guild_skill_relog_delay", &battle_config.guild_skill_relog_delay, 0, 0, 1, }, + { "guild_skill_relog_delay", &battle_config.guild_skill_relog_delay, 0, 0, 2, }, { "emergency_call", &battle_config.emergency_call, 11, 0, 31, }, { "atcommand_spawn_quantity_limit", &battle_config.atc_spawn_quantity_limit, 100, 0, INT_MAX, }, { "atcommand_slave_clone_limit", &battle_config.atc_slave_clone_limit, 25, 0, INT_MAX, }, @@ -6932,16 +7084,15 @@ static const struct battle_data { { "guild_emperium_check", &battle_config.guild_emperium_check, 1, 0, 1, }, { "guild_exp_limit", &battle_config.guild_exp_limit, 50, 0, 99, }, { "player_invincible_time", &battle_config.pc_invincible_time, 5000, 0, INT_MAX, }, + { "pet_catch_rate_official_formula", &battle_config.pet_catch_rate_official_formula, 1, 0, 1, }, { "pet_catch_rate", &battle_config.pet_catch_rate, 100, 0, INT_MAX, }, { "pet_rename", &battle_config.pet_rename, 0, 0, 1, }, { "pet_friendly_rate", &battle_config.pet_friendly_rate, 100, 0, INT_MAX, }, { "pet_hungry_delay_rate", &battle_config.pet_hungry_delay_rate, 100, 10, INT_MAX, }, - { "pet_hungry_friendly_decrease", &battle_config.pet_hungry_friendly_decrease, 5, 0, INT_MAX, }, { "pet_status_support", &battle_config.pet_status_support, 0, 0, 1, }, { "pet_attack_support", &battle_config.pet_attack_support, 0, 0, 1, }, { "pet_damage_support", &battle_config.pet_damage_support, 0, 0, 1, }, { "pet_support_min_friendly", &battle_config.pet_support_min_friendly, 900, 0, 950, }, - { "pet_equip_min_friendly", &battle_config.pet_equip_min_friendly, 900, 0, 950, }, { "pet_support_rate", &battle_config.pet_support_rate, 100, 0, INT_MAX, }, { "pet_attack_exp_to_master", &battle_config.pet_attack_exp_to_master, 0, 0, 1, }, { "pet_attack_exp_rate", &battle_config.pet_attack_exp_rate, 100, 0, INT_MAX, }, @@ -6958,14 +7109,15 @@ static const struct battle_data { { "max_heal_lv", &battle_config.max_heal_lv, 11, 1, INT_MAX, }, { "max_heal", &battle_config.max_heal, 9999, 0, INT_MAX, }, { "combo_delay_rate", &battle_config.combo_delay_rate, 100, 0, INT_MAX, }, - { "item_check", &battle_config.item_check, 0, 0, 1, }, + { "item_check", &battle_config.item_check, 0, 0, 0xF, }, { "item_use_interval", &battle_config.item_use_interval, 100, 0, INT_MAX, }, - { "cashfood_use_interval", &battle_config.cashfood_use_interval, 60000, 0, INT_MAX, }, { "wedding_modifydisplay", &battle_config.wedding_modifydisplay, 0, 0, 1, }, { "wedding_ignorepalette", &battle_config.wedding_ignorepalette, 0, 0, 1, }, { "xmas_ignorepalette", &battle_config.xmas_ignorepalette, 0, 0, 1, }, { "summer_ignorepalette", &battle_config.summer_ignorepalette, 0, 0, 1, }, { "hanbok_ignorepalette", &battle_config.hanbok_ignorepalette, 0, 0, 1, }, + { "oktoberfest_ignorepalette", &battle_config.oktoberfest_ignorepalette, 0, 0, 1, }, + { "summer2_ignorepalette", &battle_config.summer2_ignorepalette, 0, 0, 1, }, { "natural_healhp_interval", &battle_config.natural_healhp_interval, 6000, NATURAL_HEAL_INTERVAL, INT_MAX, }, { "natural_healsp_interval", &battle_config.natural_healsp_interval, 8000, NATURAL_HEAL_INTERVAL, INT_MAX, }, { "natural_heal_skill_interval", &battle_config.natural_heal_skill_interval, 10000, NATURAL_HEAL_INTERVAL, INT_MAX, }, @@ -7020,8 +7172,9 @@ static const struct battle_data { { "vending_over_max", &battle_config.vending_over_max, 1, 0, 1, }, { "show_steal_in_same_party", &battle_config.show_steal_in_same_party, 0, 0, 1, }, { "party_hp_mode", &battle_config.party_hp_mode, 0, 0, 1, }, + { "party_change_leader_same_map", &battle_config.party_change_leader_same_map, 0, 0, 1, }, { "show_party_share_picker", &battle_config.party_show_share_picker, 1, 0, 1, }, - { "show_picker.item_type", &battle_config.show_picker_item_type, 112, 0, INT_MAX, }, + { "show_picker_item_type", &battle_config.show_picker_item_type, 112, 0, INT_MAX, }, { "party_update_interval", &battle_config.party_update_interval, 1000, 100, INT_MAX, }, { "party_item_share_type", &battle_config.party_share_type, 0, 0, 1|2|3, }, { "attack_attr_none", &battle_config.attack_attr_none, ~BL_PC, BL_NUL, BL_ALL, }, @@ -7033,7 +7186,6 @@ static const struct battle_data { { "skill_removetrap_type", &battle_config.skill_removetrap_type, 0, 0, 1, }, { "disp_experience", &battle_config.disp_experience, 0, 0, 1, }, { "disp_zeny", &battle_config.disp_zeny, 0, 0, 1, }, - { "castle_defense_rate", &battle_config.castle_defense_rate, 100, 0, 100, }, { "bone_drop", &battle_config.bone_drop, 0, 0, 2, }, { "buyer_name", &battle_config.buyer_name, 1, 0, 1, }, { "skill_wall_check", &battle_config.skill_wall_check, 1, 0, 1, }, @@ -7100,6 +7252,8 @@ static const struct battle_data { { "castrate_dex_scale", &battle_config.castrate_dex_scale, 150, 1, INT_MAX, }, { "vcast_stat_scale", &battle_config.vcast_stat_scale, 530, 1, INT_MAX, }, { "area_size", &battle_config.area_size, 14, 0, INT_MAX, }, + { "chat_area_size", &battle_config.chat_area_size, 9, 0, INT_MAX, }, + { "dead_area_size", &battle_config.dead_area_size, 32, 0, INT_MAX, }, { "zeny_from_mobs", &battle_config.zeny_from_mobs, 0, 0, 1, }, { "mobs_level_up", &battle_config.mobs_level_up, 0, 0, 1, }, { "mobs_level_up_exp_rate", &battle_config.mobs_level_up_exp_rate, 1, 1, INT_MAX, }, @@ -7133,7 +7287,6 @@ static const struct battle_data { { "mob_npc_event_type", &battle_config.mob_npc_event_type, 1, 0, 1, }, { "character_size", &battle_config.character_size, 1|2, 0, 1|2, }, { "retaliate_to_master", &battle_config.retaliate_to_master, 1, 0, 1, }, - { "rare_drop_announce", &battle_config.rare_drop_announce, 0, 0, 10000, }, { "duel_allow_pvp", &battle_config.duel_allow_pvp, 0, 0, 1, }, { "duel_allow_gvg", &battle_config.duel_allow_gvg, 0, 0, 1, }, { "duel_allow_teleport", &battle_config.duel_allow_teleport, 0, 0, 1, }, @@ -7165,6 +7318,7 @@ static const struct battle_data { { "mob_remove_delay", &battle_config.mob_remove_delay, 60000, 1000, INT_MAX, }, { "mob_active_time", &battle_config.mob_active_time, 0, 0, INT_MAX, }, { "boss_active_time", &battle_config.boss_active_time, 0, 0, INT_MAX, }, + { "slave_chase_masters_chasetarget", &battle_config.slave_chase_masters_chasetarget, 1, 0, 1, }, { "sg_miracle_skill_duration", &battle_config.sg_miracle_skill_duration, 3600000, 0, INT_MAX, }, { "hvan_explosion_intimate", &battle_config.hvan_explosion_intimate, 45000, 0, 100000, }, { "quest_exp_rate", &battle_config.quest_exp_rate, 100, 0, INT_MAX, }, @@ -7180,14 +7334,14 @@ static const struct battle_data { { "display_status_timers", &battle_config.display_status_timers, 1, 0, 1, }, { "skill_add_heal_rate", &battle_config.skill_add_heal_rate, 7, 0, INT_MAX, }, { "eq_single_target_reflectable", &battle_config.eq_single_target_reflectable, 1, 0, 1, }, - { "invincible.nodamage", &battle_config.invincible_nodamage, 0, 0, 1, }, + { "invincible_nodamage", &battle_config.invincible_nodamage, 0, 0, 1, }, { "mob_slave_keep_target", &battle_config.mob_slave_keep_target, 0, 0, 1, }, { "autospell_check_range", &battle_config.autospell_check_range, 0, 0, 1, }, { "knockback_left", &battle_config.knockback_left, 1, 0, 1, }, { "client_reshuffle_dice", &battle_config.client_reshuffle_dice, 0, 0, 1, }, { "client_sort_storage", &battle_config.client_sort_storage, 0, 0, 1, }, - { "feature.buying_store", &battle_config.feature_buying_store, 1, 0, 1, }, - { "feature.search_stores", &battle_config.feature_search_stores, 1, 0, 1, }, + { "features/buying_store", &battle_config.feature_buying_store, 1, 0, 1, }, + { "features/search_stores", &battle_config.feature_search_stores, 1, 0, 1, }, { "searchstore_querydelay", &battle_config.searchstore_querydelay, 10, 0, INT_MAX, }, { "searchstore_maxresults", &battle_config.searchstore_maxresults, 30, 1, INT_MAX, }, { "display_party_name", &battle_config.display_party_name, 0, 0, 1, }, @@ -7207,7 +7361,8 @@ static const struct battle_data { { "atcommand_max_stat_bypass", &battle_config.atcommand_max_stat_bypass, 0, 0, 100, }, { "skill_amotion_leniency", &battle_config.skill_amotion_leniency, 90, 0, 300 }, { "mvp_tomb_enabled", &battle_config.mvp_tomb_enabled, 1, 0, 1 }, - { "feature.atcommand_suggestions", &battle_config.atcommand_suggestions_enabled, 0, 0, 1 }, + { "mvp_tomb_spawn_delay", &battle_config.mvp_tomb_spawn_delay, 10000, 0, INT_MAX }, + { "features/atcommand_suggestions", &battle_config.atcommand_suggestions_enabled, 0, 0, 1 }, { "min_npc_vendchat_distance", &battle_config.min_npc_vendchat_distance, 3, 0, 100 }, { "vendchat_near_hiddennpc", &battle_config.vendchat_near_hiddennpc, 0, 0, 1 }, { "atcommand_mobinfo_type", &battle_config.atcommand_mobinfo_type, 0, 0, 1 }, @@ -7219,6 +7374,7 @@ static const struct battle_data { * Hercules **/ { "skill_trap_type", &battle_config.skill_trap_type, 0, 0, 1, }, + { "trap_reflect", &battle_config.trap_reflect, 1, 0, 1, }, { "item_restricted_consumption_type", &battle_config.item_restricted_consumption_type,1, 0, 1, }, { "unequip_restricted_equipment", &battle_config.unequip_restricted_equipment, 0, 0, 3, }, { "max_walk_path", &battle_config.max_walk_path, 17, 1, MAX_WALKPATH, }, @@ -7228,8 +7384,8 @@ static const struct battle_data { { "client_accept_chatdori", &battle_config.client_accept_chatdori, 0, 0, INT_MAX, }, { "snovice_call_type", &battle_config.snovice_call_type, 0, 0, 1, }, { "guild_notice_changemap", &battle_config.guild_notice_changemap, 2, 0, 2, }, - { "feature.banking", &battle_config.feature_banking, 1, 0, 1, }, - { "feature.auction", &battle_config.feature_auction, 0, 0, 2, }, + { "features/banking", &battle_config.feature_banking, 1, 0, 1, }, + { "features/auction", &battle_config.feature_auction, 0, 0, 2, }, { "idletime_criteria", &battle_config.idletime_criteria, 0x25, 1, INT_MAX, }, { "mon_trans_disable_in_gvg", &battle_config.mon_trans_disable_in_gvg, 0, 0, 1, }, { "case_sensitive_aegisnames", &battle_config.case_sensitive_aegisnames, 1, 0, 1, }, @@ -7241,7 +7397,7 @@ static const struct battle_data { { "monster_chase_refresh", &battle_config.mob_chase_refresh, 1, 0, 30, }, { "mob_icewall_walk_block", &battle_config.mob_icewall_walk_block, 75, 0, 255, }, { "boss_icewall_walk_block", &battle_config.boss_icewall_walk_block, 0, 0, 255, }, - { "feature.roulette", &battle_config.feature_roulette, 1, 0, 1, }, + { "features/roulette", &battle_config.feature_roulette, 1, 0, 1, }, { "show_monster_hp_bar", &battle_config.show_monster_hp_bar, 1, 0, 1, }, { "fix_warp_hit_delay_abuse", &battle_config.fix_warp_hit_delay_abuse, 0, 0, 1, }, { "costume_refine_def", &battle_config.costume_refine_def, 1, 0, 1, }, @@ -7250,195 +7406,83 @@ static const struct battle_data { { "min_body_style", &battle_config.min_body_style, 0, 0, SHRT_MAX, }, { "max_body_style", &battle_config.max_body_style, 4, 0, SHRT_MAX, }, { "save_body_style", &battle_config.save_body_style, 0, 0, 1, }, + { "player_warp_keep_direction", &battle_config.player_warp_keep_direction, 0, 0, 1, }, + { "atcommand_levelup_events", &battle_config.atcommand_levelup_events, 0, 0, 1, }, + { "bow_unequip_arrow", &battle_config.bow_unequip_arrow, 1, 0, 1, }, + { "max_summoner_parameter", &battle_config.max_summoner_parameter, 120, 10, 10000, }, + { "mvp_exp_reward_message", &battle_config.mvp_exp_reward_message, 0, 0, 1, }, + { "monster_eye_range_bonus", &battle_config.mob_eye_range_bonus, 0, 0, 10, }, + { "prevent_logout_trigger", &battle_config.prevent_logout_trigger, 0xE, 0, 0xF, }, + { "boarding_halter_speed", &battle_config.boarding_halter_speed, 25, 0, 100, }, + { "features/rodex", &battle_config.feature_rodex, 1, 0, 1, }, + { "features/rodex_use_accountmail", &battle_config.feature_rodex_use_accountmail, 0, 0, 1, }, + { "features/enable_homun_autofeed", &battle_config.feature_enable_homun_autofeed, 1, 0, 1, }, + { "features/enable_pet_autofeed", &battle_config.feature_enable_pet_autofeed, 1, 0, 1, }, + { "storage_use_item", &battle_config.storage_use_item, 0, 0, 1, }, + { "features/enable_attendance_system", &battle_config.feature_enable_attendance_system,1, 0, 1, }, + { "features/feature_attendance_endtime",&battle_config.feature_attendance_endtime, 1, 0, 99999999, }, + { "min_item_buy_price", &battle_config.min_item_buy_price, 1, 0, INT_MAX, }, + { "min_item_sell_price", &battle_config.min_item_sell_price, 0, 0, INT_MAX, }, + { "display_fake_hp_when_dead", &battle_config.display_fake_hp_when_dead, 1, 0, 1, }, + { "magicrod_type", &battle_config.magicrod_type, 0, 0, 1, }, + { "features/enable_achievement_system", &battle_config.feature_enable_achievement, 1, 0, 1, }, + { "ping_timer_inverval", &battle_config.ping_timer_interval, 30, 0, 99999999, }, + { "ping_time", &battle_config.ping_time, 20, 0, 99999999, }, + { "option_drop_max_loop", &battle_config.option_drop_max_loop, 10, 1, 100000, }, + { "drop_connection_on_quit", &battle_config.drop_connection_on_quit, 0, 0, 1, }, + { "features/enable_refinery_ui", &battle_config.enable_refinery_ui, 1, 0, 1, }, + { "features/replace_refine_npcs", &battle_config.replace_refine_npcs, 1, 0, 1, }, + { "batk_min_limit", &battle_config.batk_min, 0, 0, INT_MAX, }, + { "batk_max_limit", &battle_config.batk_max, USHRT_MAX, 1, INT_MAX, }, + { "matk_min_limit", &battle_config.matk_min, 0, 0, INT_MAX, }, + { "matk_max_limit", &battle_config.matk_max, USHRT_MAX, 1, INT_MAX, }, + { "watk_min_limit", &battle_config.watk_min, 0, 0, INT_MAX, }, + { "watk_max_limit", &battle_config.watk_max, USHRT_MAX, 1, INT_MAX, }, + { "flee_min_limit", &battle_config.flee_min, 1, 1, INT_MAX, }, + { "flee_max_limit", &battle_config.flee_max, SHRT_MAX, 1, INT_MAX, }, + { "flee2_min_limit", &battle_config.flee2_min, 10, 1, INT_MAX, }, + { "flee2_max_limit", &battle_config.flee2_max, SHRT_MAX, 1, INT_MAX, }, + { "critical_min_limit", &battle_config.critical_min, 10, 1, INT_MAX, }, + { "critical_max_limit", &battle_config.critical_max, SHRT_MAX, 1, INT_MAX, }, + { "hit_min_limit", &battle_config.hit_min, 1, 1, INT_MAX, }, + { "hit_max_limit", &battle_config.hit_max, SHRT_MAX, 1, INT_MAX, }, + { "autoloot_adjust", &battle_config.autoloot_adjust, 0, 0, 1, }, + { "hom_bonus_exp_from_master", &battle_config.hom_bonus_exp_from_master, 10, 0, 100, }, }; -#ifndef STATS_OPT_OUT -/** - * Hercules anonymous statistic usage report -- packet is built here, and sent to char server to report. - **/ -void Hercules_report(char* date, char *time_c) { - int i, bd_size = ARRAYLENGTH(battle_data); - unsigned int config = 0; - char timestring[25]; - time_t curtime; - char* buf; - - enum config_table { - C_CIRCULAR_AREA = 0x0001, - C_CELLNOSTACK = 0x0002, - C_CONSOLE_INPUT = 0x0004, - C_SCRIPT_CALLFUNC_CHECK = 0x0008, - C_OFFICIAL_WALKPATH = 0x0010, - C_RENEWAL = 0x0020, - C_RENEWAL_CAST = 0x0040, - C_RENEWAL_DROP = 0x0080, - C_RENEWAL_EXP = 0x0100, - C_RENEWAL_LVDMG = 0x0200, - C_RENEWAL_EDP = 0x0400, - C_RENEWAL_ASPD = 0x0800, - C_SECURE_NPCTIMEOUT = 0x1000, - //C_SQL_DB_ITEM = 0x2000, - C_SQL_LOGS = 0x4000, - C_MEMWATCH = 0x8000, - C_DMALLOC = 0x10000, - C_GCOLLECT = 0x20000, - C_SEND_SHORTLIST = 0x40000, - //C_SQL_DB_MOB = 0x80000, - //C_SQL_DB_MOBSKILL = 0x100000, - C_PACKETVER_RE = 0x200000, - }; - - /* we get the current time */ - time(&curtime); - strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", localtime(&curtime)); - -#ifdef CIRCULAR_AREA - config |= C_CIRCULAR_AREA; -#endif - -#ifdef CELL_NOSTACK - config |= C_CELLNOSTACK; -#endif - -#ifdef CONSOLE_INPUT - config |= C_CONSOLE_INPUT; -#endif - -#ifdef SCRIPT_CALLFUNC_CHECK - config |= C_SCRIPT_CALLFUNC_CHECK; -#endif - -#ifdef OFFICIAL_WALKPATH - config |= C_OFFICIAL_WALKPATH; -#endif -#ifdef RENEWAL - config |= C_RENEWAL; -#endif - -#ifdef RENEWAL_CAST - config |= C_RENEWAL_CAST; -#endif - -#ifdef RENEWAL_DROP - config |= C_RENEWAL_DROP; -#endif - -#ifdef RENEWAL_EXP - config |= C_RENEWAL_EXP; -#endif - -#ifdef RENEWAL_LVDMG - config |= C_RENEWAL_LVDMG; -#endif - -#ifdef RENEWAL_EDP - config |= C_RENEWAL_EDP; -#endif - -#ifdef RENEWAL_ASPD - config |= C_RENEWAL_ASPD; -#endif - -#ifdef SECURE_NPCTIMEOUT - config |= C_SECURE_NPCTIMEOUT; -#endif - -#ifdef PACKETVER_RE - config |= C_PACKETVER_RE; -#endif - - /* non-define part */ - if( logs->config.sql_logs ) - config |= C_SQL_LOGS; - -#ifdef MEMWATCH - config |= C_MEMWATCH; -#endif -#ifdef DMALLOC - config |= C_DMALLOC; -#endif -#ifdef GCOLLECT - config |= C_GCOLLECT; -#endif - -#ifdef SEND_SHORTLIST - config |= C_SEND_SHORTLIST; -#endif - -#define BFLAG_LENGTH 35 - - CREATE(buf, char, 262 + ( bd_size * ( BFLAG_LENGTH + 4 ) ) + 1 ); - - /* build packet */ - - WBUFW(buf,0) = 0x3000; - WBUFW(buf,2) = 262 + ( bd_size * ( BFLAG_LENGTH + 4 ) ); - WBUFW(buf,4) = 0x9f; - - safestrncpy(WBUFP(buf,6), date, 12); - safestrncpy(WBUFP(buf,18), time_c, 9); - safestrncpy(WBUFP(buf,27), timestring, 24); - - safestrncpy(WBUFP(buf,51), sysinfo->platform(), 16); - safestrncpy(WBUFP(buf,67), sysinfo->osversion(), 50); - safestrncpy(WBUFP(buf,117), sysinfo->cpu(), 32); - WBUFL(buf,149) = sysinfo->cpucores(); - safestrncpy(WBUFP(buf,153), sysinfo->arch(), 8); - WBUFB(buf,161) = sysinfo->vcstypeid(); - WBUFB(buf,162) = sysinfo->is64bit(); - safestrncpy(WBUFP(buf,163), sysinfo->vcsrevision_src(), 41); - safestrncpy(WBUFP(buf,204), sysinfo->vcsrevision_scripts(), 41); - WBUFB(buf,245) = (sysinfo->is_superuser()? 1 : 0); - WBUFL(buf,246) = map->getusers(); - - WBUFL(buf,250) = config; - WBUFL(buf,254) = PACKETVER; - - WBUFL(buf,258) = bd_size; - for( i = 0; i < bd_size; i++ ) { - safestrncpy(WBUFP(buf,262 + ( i * ( BFLAG_LENGTH + 4 ) ) ), battle_data[i].str, BFLAG_LENGTH); - WBUFL(buf,262 + BFLAG_LENGTH + ( i * ( BFLAG_LENGTH + 4 ) ) ) = *battle_data[i].val; - } - - chrif->send_report(buf, 262 + ( bd_size * ( BFLAG_LENGTH + 4 ) ) ); - - aFree(buf); - -#undef BFLAG_LENGTH -} -static int Hercules_report_timer(int tid, int64 tick, int id, intptr_t data) { - if( chrif->isconnected() ) {/* char server relays it, so it must be online. */ - Hercules_report(__DATE__,__TIME__); +static bool battle_set_value_sub(int index, int value) +{ + Assert_retr(false, index >= 0); + if (value < battle_data[index].min || value > battle_data[index].max) { + ShowWarning("Value for setting '%s': %d is invalid (min:%d max:%d)! Defaulting to %d...\n", + battle_data[index].str, value, battle_data[index].min, battle_data[index].max, battle_data[index].defval); + value = battle_data[index].defval; } - return 0; + *battle_data[index].val = value; + return true; } -#endif -int battle_set_value(const char* w1, const char* w2) +static bool battle_set_value(const char *param, const char *value) { - int val = config_switch(w2); + int val; int i; - nullpo_retr(1, w1); - nullpo_retr(1, w2); - ARR_FIND(0, ARRAYLENGTH(battle_data), i, strcmpi(w1, battle_data[i].str) == 0); - if (i == ARRAYLENGTH(battle_data)) { - if( HPM->parseConf(w1,w2,HPCT_BATTLE) ) /* if plugin-owned, succeed */ - return 1; - return 0; // not found - } + nullpo_retr(false, param); + nullpo_retr(false, value); - if (val < battle_data[i].min || val > battle_data[i].max) - { - ShowWarning("Value for setting '%s': %s is invalid (min:%i max:%i)! Defaulting to %i...\n", w1, w2, battle_data[i].min, battle_data[i].max, battle_data[i].defval); - val = battle_data[i].defval; + val = config_switch(value); + + ARR_FIND(0, ARRAYLENGTH(battle_data), i, strcmpi(param, battle_data[i].str) == 0); + if (i == ARRAYLENGTH(battle_data)) { + if (HPM->parse_conf_entry(param, value, HPCT_BATTLE)) /* if plugin-owned, succeed */ + return true; + return false; // not found } - *battle_data[i].val = val; - return 1; + return battle->config_set_value_sub(i, val); } -bool battle_get_value(const char *w1, int *value) +static bool battle_get_value(const char *w1, int *value) { int i; @@ -7457,13 +7501,15 @@ bool battle_get_value(const char *w1, int *value) return false; } -void battle_set_defaults(void) { +static void battle_set_defaults(void) +{ int i; for (i = 0; i < ARRAYLENGTH(battle_data); i++) *battle_data[i].val = battle_data[i].defval; } -void battle_adjust_conf(void) { +static void battle_adjust_conf(void) +{ battle_config.monster_max_aspd = 2000 - battle_config.monster_max_aspd*10; battle_config.max_aspd = 2000 - battle_config.max_aspd*10; battle_config.max_third_aspd = 2000 - battle_config.max_third_aspd*10; @@ -7486,110 +7532,160 @@ void battle_adjust_conf(void) { #if PACKETVER < 20100427 if( battle_config.feature_buying_store ) { - ShowWarning("conf/battle/feature.conf buying_store is enabled but it requires PACKETVER 2010-04-27 or newer, disabling...\n"); + ShowWarning("conf/map/battle/feature.conf buying_store is enabled but it requires PACKETVER 2010-04-27 or newer, disabling...\n"); battle_config.feature_buying_store = 0; } #endif #if PACKETVER < 20100803 if( battle_config.feature_search_stores ) { - ShowWarning("conf/battle/feature.conf search_stores is enabled but it requires PACKETVER 2010-08-03 or newer, disabling...\n"); + ShowWarning("conf/map/battle/feature.conf search_stores is enabled but it requires PACKETVER 2010-08-03 or newer, disabling...\n"); battle_config.feature_search_stores = 0; } #endif #if PACKETVER < 20130724 if( battle_config.feature_banking ) { - ShowWarning("conf/battle/feature.conf banking is enabled but it requires PACKETVER 2013-07-24 or newer, disabling...\n"); + ShowWarning("conf/map/battle/feature.conf banking is enabled but it requires PACKETVER 2013-07-24 or newer, disabling...\n"); battle_config.feature_banking = 0; } #endif #if PACKETVER < 20141022 if( battle_config.feature_roulette ) { - ShowWarning("conf/battle/feature.conf roulette is enabled but it requires PACKETVER 2014-10-22 or newer, disabling...\n"); + ShowWarning("conf/map/battle/feature.conf roulette is enabled but it requires PACKETVER 2014-10-22 or newer, disabling...\n"); battle_config.feature_roulette = 0; } #endif #if PACKETVER > 20120000 && PACKETVER < 20130515 /* exact date (when it started) not known */ if( battle_config.feature_auction == 1 ) { - ShowWarning("conf/battle/feature.conf:feature.auction is enabled but it is not stable on PACKETVER "EXPAND_AND_QUOTE(PACKETVER)", disabling...\n"); - ShowWarning("conf/battle/feature.conf:feature.auction change value to '2' to silence this warning and maintain it enabled\n"); + ShowWarning("conf/map/battle/feature.conf:features/auction is enabled but it is not stable on PACKETVER "EXPAND_AND_QUOTE(PACKETVER)", disabling...\n"); + ShowWarning("conf/map/battle/feature.conf:features/auction change value to '2' to silence this warning and maintain it enabled\n"); battle_config.feature_auction = 0; } #endif +#if PACKETVER < 20131223 + if (battle_config.mvp_exp_reward_message) { + ShowWarning("conf/map/battle/client.conf MVP EXP reward message is enabled but it requires PACKETVER 2013-12-23 or newer, disabling...\n"); + battle_config.mvp_exp_reward_message = 0; + } +#endif + +#if !(PACKETVER_MAIN_NUM >= 20161130 || PACKETVER_RE_NUM >= 20161109 || defined(PACKETVER_ZERO)) + if (battle_config.enable_refinery_ui == 1) { + ShowWarning("conf/map/battle/feature.conf refinery ui is enabled but it requires PACKETVER 2016-11-09 RagexeRE/2016-11-30 Ragexe or newer, disabling...\n"); + battle_config.enable_refinery_ui = 0; + } + + if (battle_config.replace_refine_npcs == 1) { + ShowWarning("conf/map/battle/feature.conf replace refine npcs is enabled but it requires PACKETVER 2016-11-09 RagexeRE/2016-11-30 Ragexe or newer, disabling...\n"); + battle_config.replace_refine_npcs = 0; + } +#endif + #ifndef CELL_NOSTACK if (battle_config.custom_cell_stack_limit != 1) ShowWarning("Battle setting 'custom_cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n"); #endif } -int battle_config_read(const char* cfgName) +/** + * Dynamically reads battle configuration and initializes required variables. + * + * @param filename Path to configuration file. + * @param imported Whether the current config is imported from another file. + * @retval false in case of error. + */ +static bool battle_config_read(const char *filename, bool imported) { - FILE* fp; - static int count = 0; + struct config_t config; + const struct config_setting_t *setting = NULL; + int i; + const char *import = NULL; + bool retval = true; - nullpo_ret(cfgName); + nullpo_retr(false, filename); - if (count == 0) + if (!libconfig->load_file(&config, filename)) + return false; // Error message is already shown by libconfig->load_file() + + if (!imported) battle->config_set_defaults(); - count++; + if (libconfig->lookup(&config, "battle_configuration/traps_setting") != NULL) { + ShowError("The `traps_setting` battle conf option has been replaced by `trap_visibility`. Please see conf/map/battle/skill.conf.\n"); + } - fp = fopen(cfgName,"r"); - if (fp == NULL) - ShowError("File not found: %s\n", cfgName); - else - { - char line[1024], w1[1024], w2[1024]; - while(fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2) - continue; - if (strcmpi(w1, "import") == 0) - battle->config_read(w2); - else - if (battle->config_set_value(w1, w2) == 0) - ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + for (i = 0; i < ARRAYLENGTH(battle_data); i++) { + int type, val; + char config_name[256]; + safesnprintf(config_name, sizeof config_name, "battle_configuration/%s", battle_data[i].str); + + if ((setting = libconfig->lookup(&config, config_name)) == NULL) { + if (!imported) { + ShowWarning("Missing configuration '%s' in file %s!\n", config_name, filename); + retval = false; + } + continue; + } + + switch ((type = config_setting_type(setting))) { + case CONFIG_TYPE_INT: + val = libconfig->setting_get_int(setting); + break; + case CONFIG_TYPE_BOOL: + val = libconfig->setting_get_bool(setting); + break; + default: // Unsupported type + ShowWarning("Setting %s has unsupported type %d, ignoring...\n", config_name, type); + retval = false; + continue; } - fclose(fp); + if (!battle->config_set_value_sub(i, val)) + retval = false; } - count--; + if (!HPM->parse_battle_conf(&config, filename, imported)) + retval = false; - if (count == 0) { + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + if (strcmp(import, filename) == 0 || strcmp(import, map->BATTLE_CONF_FILENAME) == 0) { + ShowWarning("battle_config_read: Loop detected! Skipping 'import'...\n"); + } else { + if (!battle->config_read(import, true)) + retval = false; + } + } + + libconfig->destroy(&config); + if (!imported) { battle->config_adjust(); clif->bc_ready(); } - - return 0; + return retval; } -void do_init_battle(bool minimal) { +static void do_init_battle(bool minimal) +{ if (minimal) return; battle->delay_damage_ers = ers_new(sizeof(struct delay_damage),"battle.c::delay_damage_ers",ERS_OPT_CLEAR); timer->add_func_list(battle->delay_damage_sub, "battle_delay_damage_sub"); - -#ifndef STATS_OPT_OUT - timer->add_func_list(Hercules_report_timer, "Hercules_report_timer"); - timer->add_interval(timer->gettick()+30000, Hercules_report_timer, 0, 0, 60000 * 30); -#endif - } -void do_final_battle(void) { +static void do_final_battle(void) +{ ers_destroy(battle->delay_damage_ers); } /* initialize the interface */ -void battle_defaults(void) { +void battle_defaults(void) +{ battle = &battle_s; battle->bc = &battle_config; @@ -7602,13 +7698,16 @@ void battle_defaults(void) { battle->calc_attack = battle_calc_attack; battle->calc_damage = battle_calc_damage; + battle->calc_pc_damage = battle_calc_pc_damage; battle->calc_gvg_damage = battle_calc_gvg_damage; battle->calc_bg_damage = battle_calc_bg_damage; battle->weapon_attack = battle_weapon_attack; + battle->check_arrows = battle_check_arrows; battle->calc_weapon_attack = battle_calc_weapon_attack; battle->delay_damage = battle_delay_damage; battle->drain = battle_drain; battle->reflect_damage = battle_reflect_damage; + battle->reflect_trap = battle_reflect_trap; battle->attr_ratio = battle_attr_ratio; battle->attr_fix = battle_attr_fix; battle->calc_cardfix = battle_calc_cardfix; @@ -7644,6 +7743,7 @@ void battle_defaults(void) { battle->calc_drain = battle_calc_drain; battle->config_read = battle_config_read; battle->config_set_defaults = battle_set_defaults; + battle->config_set_value_sub = battle_set_value_sub; battle->config_set_value = battle_set_value; battle->config_get_value = battle_get_value; battle->config_adjust = battle_adjust_conf; |