/src/map/battle.c
C | 7664 lines | 6652 code | 592 blank | 420 comment | 2604 complexity | e182503114f24bba27284fff9fc670df MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- /**
- * 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
- *
- * Hercules is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #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 "battle.h"
- #include "map/battleground.h"
- #include "map/chrif.h"
- #include "map/clif.h"
- #include "map/elemental.h"
- #include "map/guild.h"
- #include "map/homunculus.h"
- #include "map/itemdb.h"
- #include "map/map.h"
- #include "map/mercenary.h"
- #include "map/mob.h"
- #include "map/party.h"
- #include "map/path.h"
- #include "map/pc.h"
- #include "map/pet.h"
- #include "map/skill.h"
- #include "map/status.h"
- #include "common/HPM.h"
- #include "common/cbasetypes.h"
- #include "common/ers.h"
- #include "common/memmgr.h"
- #include "common/nullpo.h"
- #include "common/random.h"
- #include "common/showmsg.h"
- #include "common/socket.h"
- #include "common/strlib.h"
- #include "common/sysinfo.h"
- #include "common/timer.h"
- #include "common/utils.h"
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- struct Battle_Config battle_config;
- struct battle_interface battle_s;
- struct battle_interface *battle;
- /**
- * Returns the current/last skill in use by this bl.
- *
- * @param bl The bl to check.
- * @return The current/last skill ID.
- */
- int battle_getcurrentskill(struct block_list *bl)
- {
- const struct unit_data *ud;
- nullpo_ret(bl);
- if (bl->type == BL_SKILL) {
- const struct skill_unit *su = BL_UCCAST(BL_SKILL, bl);
- if (su->group == NULL)
- return 0;
- return su->group->skill_id;
- }
- ud = unit->bl2ud(bl);
- if (ud == NULL)
- return 0;
- return ud->skill_id;
- }
- /*==========================================
- * Get random targeting enemy
- *------------------------------------------*/
- int battle_gettargeted_sub(struct block_list *bl, va_list ap) {
- struct block_list **bl_list;
- struct unit_data *ud;
- int target_id;
- int *c;
- nullpo_ret(bl);
- bl_list = va_arg(ap, struct block_list **);
- c = va_arg(ap, int *);
- target_id = va_arg(ap, int);
- if (bl->id == target_id)
- return 0;
- if (*c >= 24)
- return 0;
- if (!(ud = unit->bl2ud(bl)))
- return 0;
- if (ud->target == target_id || ud->skilltarget == target_id) {
- bl_list[(*c)++] = bl;
- return 1;
- }
- return 0;
- }
- struct block_list* battle_gettargeted(struct block_list *target) {
- struct block_list *bl_list[24];
- int c = 0;
- nullpo_retr(NULL, target);
- memset(bl_list, 0, sizeof(bl_list));
- map->foreachinrange(battle->get_targeted_sub, target, AREA_SIZE, BL_CHAR, bl_list, &c, target->id);
- if ( c == 0 )
- return NULL;
- if( c > 24 )
- c = 24;
- return bl_list[rnd()%c];
- }
- //Returns the id of the current targeted character of the passed bl. [Skotlex]
- int battle_gettarget(struct block_list* bl) {
- nullpo_ret(bl);
- switch (bl->type) {
- case BL_PC: return BL_UCCAST(BL_PC, bl)->ud.target;
- case BL_MOB: return BL_UCCAST(BL_MOB, bl)->target_id;
- case BL_PET: return BL_UCCAST(BL_PET, bl)->target_id;
- case BL_HOM: return BL_UCCAST(BL_HOM, bl)->ud.target;
- case BL_MER: return BL_UCCAST(BL_MER, bl)->ud.target;
- case BL_ELEM: return BL_UCCAST(BL_ELEM, bl)->ud.target;
- }
- return 0;
- }
- int battle_getenemy_sub(struct block_list *bl, va_list ap) {
- struct block_list **bl_list;
- struct block_list *target;
- int *c;
- nullpo_ret(bl);
- bl_list = va_arg(ap, struct block_list **);
- c = va_arg(ap, int *);
- target = va_arg(ap, struct block_list *);
- if (bl->id == target->id)
- return 0;
- if (*c >= 24)
- return 0;
- if (status->isdead(bl))
- return 0;
- if (battle->check_target(target, bl, BCT_ENEMY) > 0) {
- bl_list[(*c)++] = bl;
- return 1;
- }
- return 0;
- }
- // 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) {
- struct block_list *bl_list[24];
- int c = 0;
- nullpo_retr(NULL, target);
- memset(bl_list, 0, sizeof(bl_list));
- map->foreachinrange(battle->get_enemy_sub, target, range, type, bl_list, &c, target);
- if ( c == 0 )
- return NULL;
- if( c > 24 )
- c = 24;
- return bl_list[rnd()%c];
- }
- int battle_getenemyarea_sub(struct block_list *bl, va_list ap) {
- struct block_list **bl_list, *src;
- int *c, ignore_id;
- nullpo_ret(bl);
- bl_list = va_arg(ap, struct block_list **);
- nullpo_ret(bl_list);
- c = va_arg(ap, int *);
- nullpo_ret(c);
- src = va_arg(ap, struct block_list *);
- ignore_id = va_arg(ap, int);
- if( bl->id == src->id || bl->id == ignore_id )
- return 0; // Ignores Caster and a possible pre-target
- if( *c >= 23 )
- return 0;
- if( status->isdead(bl) )
- return 0;
- if( battle->check_target(src, bl, BCT_ENEMY) > 0 ) {// Is Enemy!...
- bl_list[(*c)++] = bl;
- return 1;
- }
- return 0;
- }
- // Pick a random enemy
- 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;
- nullpo_retr(NULL, src);
- memset(bl_list, 0, sizeof(bl_list));
- map->foreachinarea(battle->get_enemy_area_sub, src->m, x - range, y - range, x + range, y + range, type, bl_list, &c, src, ignore_id);
- if( c == 0 )
- return NULL;
- if( c >= 24 )
- c = 23;
- return bl_list[rnd()%c];
- }
- int battle_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) {
- struct delay_damage *dat = (struct delay_damage *)data;
- if ( dat ) {
- struct block_list *src = map->id2bl(dat->src_id);
- struct map_session_data *sd = BL_CAST(BL_PC, src);
- struct block_list *target = map->id2bl(dat->target_id);
- if (target != NULL && !status->isdead(target)) {
- //Check to see if you haven't teleported. [Skotlex]
- if (src != NULL && (
- battle_config.fix_warp_hit_delay_abuse ?
- (dat->skill_id == MO_EXTREMITYFIST || target->m != src->m || check_distance_bl(src, target, dat->distance))
- :
- ((target->type != BL_PC || BL_UCAST(BL_PC, target)->invincible_timer == INVALID_TIMER)
- && (dat->skill_id == MO_EXTREMITYFIST || (target->m == src->m && check_distance_bl(src, target, dat->distance))))
- )) {
- map->freeblock_lock();
- status_fix_damage(src, target, dat->damage, dat->delay);
- if (dat->attack_type && !status->isdead(target) && dat->additional_effects)
- skill->additional_effect(src,target,dat->skill_id,dat->skill_lv,dat->attack_type,dat->dmg_lv,tick);
- if (dat->dmg_lv > ATK_BLOCK && dat->attack_type)
- skill->counter_additional_effect(src,target,dat->skill_id,dat->skill_lv,dat->attack_type,tick);
- map->freeblock_unlock();
- } else if (src == NULL && dat->skill_id == CR_REFLECTSHIELD) {
- // it was monster reflected damage, and the monster died, we pass the damage to the character as expected
- map->freeblock_lock();
- status_fix_damage(target, target, dat->damage, dat->delay);
- map->freeblock_unlock();
- }
- }
- if (sd != NULL && --sd->delayed_damage == 0 && sd->state.hold_recalc) {
- sd->state.hold_recalc = 0;
- status_calc_pc(sd, SCO_FORCE);
- }
- }
- ers_free(battle->delay_damage_ers, dat);
- 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) {
- struct delay_damage *dat;
- struct status_change *sc;
- struct block_list *d_tbl = NULL;
- nullpo_ret(src);
- nullpo_ret(target);
- sc = status->get_sc(target);
- if (sc && sc->data[SC_DEVOTION] && sc->data[SC_DEVOTION]->val1)
- d_tbl = map->id2bl(sc->data[SC_DEVOTION]->val1);
- if (d_tbl && sc && check_distance_bl(target, d_tbl, sc->data[SC_DEVOTION]->val3) && damage > 0 && skill_id != PA_PRESSURE && skill_id != CR_REFLECTSHIELD)
- damage = 0;
- if ( !battle_config.delay_battle_damage || amotion <= 1 ) {
- map->freeblock_lock();
- status_fix_damage(src, target, damage, ddelay); // We have to separate here between reflect damage and others [icescope]
- if( attack_type && !status->isdead(target) && additional_effects )
- skill->additional_effect(src, target, skill_id, skill_lv, attack_type, dmg_lv, timer->gettick());
- if( dmg_lv > ATK_BLOCK && attack_type )
- skill->counter_additional_effect(src, target, skill_id, skill_lv, attack_type, timer->gettick());
- map->freeblock_unlock();
- return 0;
- }
- dat = ers_alloc(battle->delay_damage_ers, struct delay_damage);
- dat->src_id = src->id;
- dat->target_id = target->id;
- dat->skill_id = skill_id;
- dat->skill_lv = skill_lv;
- dat->attack_type = attack_type;
- dat->damage = damage;
- dat->dmg_lv = dmg_lv;
- dat->delay = ddelay;
- dat->distance = distance_bl(src, target) + (battle_config.snap_dodge ? 10 : battle_config.area_size);
- dat->additional_effects = additional_effects;
- dat->src_type = src->type;
- if (src->type != BL_PC && amotion > 1000)
- amotion = 1000; //Aegis places a damage-delay cap of 1 sec to non player attacks. [Skotlex]
- if (src->type == BL_PC) {
- BL_UCAST(BL_PC, src)->delayed_damage++;
- }
- timer->add(tick+amotion, battle->delay_damage_sub, 0, (intptr_t)dat);
- return 0;
- }
- int battle_attr_ratio(int atk_elem,int def_type, int def_lv)
- {
- if (atk_elem < ELE_NEUTRAL || atk_elem >= ELE_MAX)
- return 100;
- if (def_type < ELE_NEUTRAL || def_type >= ELE_MAX || def_lv < 1 || def_lv > 4)
- return 100;
- return battle->attr_fix_table[def_lv-1][atk_elem][def_type];
- }
- /*==========================================
- * Does attribute fix modifiers.
- * 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)
- {
- struct status_change *sc=NULL, *tsc=NULL;
- int ratio;
- if (src) sc = status->get_sc(src);
- if (target) tsc = status->get_sc(target);
- if (atk_elem < ELE_NEUTRAL || atk_elem >= ELE_MAX)
- atk_elem = rnd()%ELE_MAX;
- if (def_type < ELE_NEUTRAL || def_type >= ELE_MAX ||
- def_lv < 1 || def_lv > 4) {
- ShowError("battle_attr_fix: unknown attr type: atk=%d def_type=%d def_lv=%d\n",atk_elem,def_type,def_lv);
- return damage;
- }
- ratio = battle->attr_fix_table[def_lv-1][atk_elem][def_type];
- if (sc && sc->count) {
- if(sc->data[SC_VOLCANO] && atk_elem == ELE_FIRE)
- ratio += skill->enchant_eff[sc->data[SC_VOLCANO]->val1-1];
- if(sc->data[SC_VIOLENTGALE] && atk_elem == ELE_WIND)
- ratio += skill->enchant_eff[sc->data[SC_VIOLENTGALE]->val1-1];
- if(sc->data[SC_DELUGE] && atk_elem == ELE_WATER)
- ratio += skill->enchant_eff[sc->data[SC_DELUGE]->val1-1];
- if(sc->data[SC_FIRE_CLOAK_OPTION] && atk_elem == ELE_FIRE)
- damage += damage * sc->data[SC_FIRE_CLOAK_OPTION]->val2 / 100;
- }
- if( target && target->type == BL_SKILL ) {
- if( atk_elem == ELE_FIRE && battle->get_current_skill(target) == GN_WALLOFTHORN ) {
- struct skill_unit *su = BL_UCAST(BL_SKILL, target);
- struct skill_unit_group *sg;
- struct block_list *sgsrc;
- if(!su->alive
- || (sg = su->group) == NULL || sg->val3 == -1
- || (sgsrc = map->id2bl(sg->src_id)) == NULL || status->isdead(sgsrc)
- )
- return 0;
- if( sg->unit_id != UNT_FIREWALL ) {
- int x,y;
- x = sg->val3 >> 16;
- y = sg->val3 & 0xffff;
- skill->unitsetting(sgsrc,su->group->skill_id,su->group->skill_lv,x,y,1);
- sg->val3 = -1;
- sg->limit = DIFF_TICK32(timer->gettick(),sg->tick)+300;
- }
- }
- }
- if( tsc && tsc->count ) { //since an atk can only have one type let's optimize this a bit
- switch(atk_elem){
- case ELE_FIRE:
- if( tsc->data[SC_SPIDERWEB]) {
- tsc->data[SC_SPIDERWEB]->val1 = 0; // free to move now
- if( tsc->data[SC_SPIDERWEB]->val2-- > 0 )
- damage <<= 1; // double damage
- if( tsc->data[SC_SPIDERWEB]->val2 == 0 )
- status_change_end(target, SC_SPIDERWEB, INVALID_TIMER);
- }
- if( tsc->data[SC_THORNS_TRAP])
- status_change_end(target, SC_THORNS_TRAP, INVALID_TIMER);
- if( tsc->data[SC_COLD] && target->type != BL_MOB)
- status_change_end(target, SC_COLD, INVALID_TIMER);
- if( tsc->data[SC_EARTH_INSIGNIA]) damage += damage/2;
- if( tsc->data[SC_FIRE_CLOAK_OPTION])
- damage -= damage * tsc->data[SC_FIRE_CLOAK_OPTION]->val2 / 100;
- if( tsc->data[SC_VOLCANIC_ASH]) damage += damage/2; //150%
- break;
- case ELE_HOLY:
- if( tsc->data[SC_ORATIO]) ratio += tsc->data[SC_ORATIO]->val1 * 2;
- break;
- case ELE_POISON:
- if( tsc->data[SC_VENOMIMPRESS] && atk_elem == ELE_POISON ) ratio += tsc->data[SC_VENOMIMPRESS]->val2;
- break;
- case ELE_WIND:
- if( tsc->data[SC_COLD] && target->type != BL_MOB) damage += damage/2;
- if( tsc->data[SC_WATER_INSIGNIA]) damage += damage/2;
- break;
- case ELE_WATER:
- if( tsc->data[SC_FIRE_INSIGNIA]) damage += damage/2;
- break;
- case ELE_EARTH:
- if( tsc->data[SC_WIND_INSIGNIA]) damage += damage/2;
- break;
- }
- } //end tsc check
- if( ratio < 100 )
- return damage - (damage * (100 - ratio) / 100);
- else
- return damage + (damage * (ratio - 100) / 100);
- }
- //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]
- #ifdef RENEWAL
- int64 damage, eatk = 0;
- struct status_change *sc;
- struct map_session_data *sd;
- if( !src || !bl )
- return 0;
- sc = status->get_sc(src);
- sd = BL_CAST(BL_PC, src);
- damage = status->get_weapon_atk(src, watk, flag);
- if ( sd ) {
- if ( type == EQI_HAND_R )
- damage = battle->calc_sizefix(sd, damage, EQI_HAND_R, size, flag & 8);
- else
- damage = battle->calc_sizefix(sd, damage, EQI_HAND_L, size, flag & 8);
- if ( flag & 2 && sd->bonus.arrow_atk && skill_id != GN_CARTCANNON )
- damage += sd->bonus.arrow_atk;
- if ( sd->battle_status.equip_atk != 0 )
- eatk = sd->base_status.equip_atk;
- if ( sd->bonus.atk_rate )
- damage += damage * sd->bonus.atk_rate / 100;
- }
- if ( skill_id == TF_POISON )
- eatk += 15 * skill_lv;
- if ( skill_id != ASC_METEORASSAULT ) {
- if ( sc && sc->data[SC_SUB_WEAPONPROPERTY] ) // Temporary. [malufett]
- damage += damage * sc->data[SC_SUB_WEAPONPROPERTY]->val2 / 100;
- }
- if( sc && sc->count ){
- if( sc->data[SC_ZENKAI] && watk->ele == sc->data[SC_ZENKAI]->val2 )
- eatk += 200;
- }
- #ifdef RENEWAL_EDP
- if ( sc && sc->data[SC_EDP] && skill_id != AS_GRIMTOOTH && skill_id != AS_VENOMKNIFE && skill_id != ASC_BREAKER ) {
- struct status_data *tstatus;
- tstatus = status->get_status_data(bl);
- eatk += damage * 0x19 * battle->attr_fix_table[tstatus->ele_lv - 1][ELE_POISON][tstatus->def_ele] / 10000;
- damage += (eatk + damage) * sc->data[SC_EDP]->val3 / 100 + eatk;
- } else /* fall through */
- #endif
- damage += eatk;
- damage = battle->calc_elefix(src, bl, skill_id, skill_lv, damage, nk, n_ele, s_ele, s_ele_, type == EQI_HAND_L, flag);
- /**
- * In RE Shield Boomerang takes weapon element only for damage calculation,
- * - resist calculation is always against neutral
- **/
- if ( skill_id == CR_SHIELDBOOMERANG )
- s_ele = s_ele_ = ELE_NEUTRAL;
- // attacker side
- damage = battle->calc_cardfix(BF_WEAPON, src, bl, nk, s_ele, s_ele_, damage, 2|(type == EQI_HAND_L), flag2);
- // target side
- damage = battle->calc_cardfix(BF_WEAPON, src, bl, nk, s_ele, s_ele_, damage, 0, flag2);
- return damage;
- #else
- 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]
- *------------------------------------------
- * Pass damage2 as NULL to not calc it.
- * Flag values: // TODO: Check whether these values are correct (the flag parameter seems to be passed through to other functions), and replace them with an enum.
- * &1: Critical hit
- * &2: Arrow attack
- * &4: Skill is Magic Crasher
- * &8: Skip target size adjustment (Extremity Fist?)
- *&16: Arrow attack but BOW, REVOLVER, RIFLE, SHOTGUN, GATLING or GRENADE type weapon not equipped (i.e. shuriken, kunai and venom knives not affected by DEX)
- */
- /* '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) {
- int64 damage;
- struct status_data *st = status->get_status_data(src);
- struct status_change *sc = status->get_sc(src);
- const struct map_session_data *sd = NULL;
- nullpo_retr(0, src);
- sd = BL_CCAST(BL_PC, src);
- if ( !skill_id ) {
- s_ele = st->rhw.ele;
- s_ele_ = st->lhw.ele;
- if (sd != NULL) {
- if (sd->charm_type != CHARM_TYPE_NONE && sd->charm_count >= MAX_SPIRITCHARM) {
- s_ele = s_ele_ = sd->charm_type;
- }
- if (flag&2 && sd->bonus.arrow_ele != 0)
- s_ele = sd->bonus.arrow_ele;
- }
- }
- if (src->type == BL_PC) {
- int64 batk;
- // Property from mild wind bypasses it
- if (sc && sc->data[SC_TK_SEVENWIND])
- batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->calc_batk(bl, sc, st->batk, false), nk, n_ele, s_ele, s_ele_, false, flag);
- else
- batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->calc_batk(bl, sc, st->batk, false), nk, n_ele, ELE_NEUTRAL, ELE_NEUTRAL, false, flag);
- if (type == EQI_HAND_L)
- damage = batk + 3 * battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &st->lhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2) / 4;
- else
- damage = (batk << 1) + battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &st->rhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2);
- } else {
- damage = st->batk + battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &st->rhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2);
- }
- 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) {
- unsigned int atkmin=0, atkmax=0;
- short type = 0;
- int64 damage = 0;
- nullpo_retr(damage, st);
- nullpo_retr(damage, wa);
- if (!sd) { //Mobs/Pets
- if(flag&4) {
- atkmin = st->matk_min;
- atkmax = st->matk_max;
- } else {
- atkmin = wa->atk;
- atkmax = wa->atk2;
- }
- if (atkmin > atkmax)
- atkmin = atkmax;
- } else { //PCs
- atkmax = wa->atk;
- type = (wa == &st->lhw)?EQI_HAND_L:EQI_HAND_R;
- if (!(flag&1) || (flag&2)) { //Normal attacks
- atkmin = st->dex;
- if (sd->equip_index[type] >= 0 && sd->inventory_data[sd->equip_index[type]])
- atkmin = atkmin*(80 + sd->inventory_data[sd->equip_index[type]]->wlv*20)/100;
- if (atkmin > atkmax)
- atkmin = atkmax;
- if(flag&2 && !(flag&16)) { //Bows
- atkmin = atkmin*atkmax/100;
- if (atkmin > atkmax)
- atkmax = atkmin;
- }
- }
- }
- if (sc && sc->data[SC_MAXIMIZEPOWER])
- atkmin = atkmax;
- //Weapon Damage calculation
- if (!(flag&1))
- damage = (atkmax>atkmin? rnd()%(atkmax-atkmin):0)+atkmin;
- else
- damage = atkmax;
- if (sd) {
- //rodatazone says the range is 0~arrow_atk-1 for non crit
- if (flag&2 && sd->bonus.arrow_atk)
- damage += ( (flag&1) ? sd->bonus.arrow_atk : rnd()%sd->bonus.arrow_atk );
- //SizeFix only for players
- if (!(sd->special_state.no_sizefix || (flag&8)))
- damage = damage * ( type == EQI_HAND_L ? sd->left_weapon.atkmods[t_size] : sd->right_weapon.atkmods[t_size] ) / 100;
- }
- //Finally, add baseatk
- if(flag&4)
- damage += st->matk_min;
- else
- damage += st->batk;
- //rodatazone says that Overrefined bonuses are part of baseatk
- //Here we also apply the weapon_atk_rate bonus so it is correctly applied on left/right hands.
- if(sd) {
- if (type == EQI_HAND_L) {
- if(sd->left_weapon.overrefine)
- damage += rnd()%sd->left_weapon.overrefine+1;
- if (sd->weapon_atk_rate[sd->weapontype2])
- damage += damage * sd->weapon_atk_rate[sd->weapontype2] / 100;
- } else { //Right hand
- if(sd->right_weapon.overrefine)
- damage += rnd()%sd->right_weapon.overrefine+1;
- if (sd->weapon_atk_rate[sd->weapontype1])
- damage += damage * sd->weapon_atk_rate[sd->weapontype1] / 100;
- }
- }
- return damage;
- }
- 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)))
- damage = damage * ( type == EQI_HAND_L ? sd->left_weapon.atkmods[size] : sd->right_weapon.atkmods[size] ) / 100;
- return damage;
- }
- /*==========================================
- * Passive skill damages increases
- *------------------------------------------*/
- // FIXME: type is undocumented
- 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;
- damage = dmg;
- nullpo_retr(damage, sd);
- nullpo_retr(damage, target);
- if((skill_lv = pc->checkskill(sd,AL_DEMONBANE)) > 0 &&
- target->type == BL_MOB && //This bonus doesn't work against players.
- (battle->check_undead(st->race,st->def_ele) || st->race==RC_DEMON) )
- damage += (int)(skill_lv*(3+sd->status.base_level/20.0));
- //damage += (skill_lv * 3);
- if( (skill_lv = pc->checkskill(sd, RA_RANGERMAIN)) > 0 && (st->race == RC_BRUTE || st->race == RC_PLANT || st->race == RC_FISH) )
- damage += (skill_lv * 5);
- if( (skill_lv = pc->checkskill(sd,NC_RESEARCHFE)) > 0 && (st->def_ele == ELE_FIRE || st->def_ele == ELE_EARTH) )
- damage += (skill_lv * 10);
- if( pc_ismadogear(sd) )
- damage += 15 * pc->checkskill(sd, NC_MADOLICENCE);
- #ifdef RENEWAL
- if( (skill_lv = pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0 )
- damage += (skill_lv * 2);
- #endif
- if((skill_lv = pc->checkskill(sd,HT_BEASTBANE)) > 0 && (st->race==RC_BRUTE || st->race==RC_INSECT) ) {
- damage += (skill_lv * 4);
- if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_HUNTER)
- damage += sd->status.str;
- }
- if(type == 0)
- weapon = sd->weapontype1;
- else
- weapon = sd->weapontype2;
- switch(weapon) {
- case W_1HSWORD:
- #ifdef RENEWAL
- if((skill_lv = pc->checkskill(sd,AM_AXEMASTERY)) > 0)
- damage += (skill_lv * 3);
- #endif
- case W_DAGGER:
- if((skill_lv = pc->checkskill(sd,SM_SWORD)) > 0)
- damage += (skill_lv * 4);
- if((skill_lv = pc->checkskill(sd,GN_TRAINING_SWORD)) > 0)
- damage += skill_lv * 10;
- break;
- case W_2HSWORD:
- #ifdef RENEWAL
- if((skill_lv = pc->checkskill(sd,AM_AXEMASTERY)) > 0)
- damage += (skill_lv * 3);
- #endif
- if((skill_lv = pc->checkskill(sd,SM_TWOHAND)) > 0)
- damage += (skill_lv * 4);
- break;
- case W_1HSPEAR:
- case W_2HSPEAR:
- if ((skill_lv = pc->checkskill(sd,KN_SPEARMASTERY)) > 0) {
- if (pc_isridingdragon(sd))
- damage += (skill_lv * 10);
- else if (pc_isridingpeco(sd))
- damage += (skill_lv * 5);
- else
- damage += (skill_lv * 4);
- }
- break;
- case W_1HAXE:
- case W_2HAXE:
- if((skill_lv = pc->checkskill(sd,AM_AXEMASTERY)) > 0)
- damage += (skill_lv * 3);
- if((skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0)
- damage += (skill_lv * 5);
- break;
- case W_MACE:
- case W_2HMACE:
- if((skill_lv = pc->checkskill(sd,PR_MACEMASTERY)) > 0)
- damage += (skill_lv * 3);
- if((skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0)
- damage += (skill_lv * 5);
- break;
- case W_FIST:
- if((skill_lv = pc->checkskill(sd,TK_RUN)) > 0)
- damage += (skill_lv * 10);
- // No break, fall through to Knuckles
- case W_KNUCKLE:
- if((skill_lv = pc->checkskill(sd,MO_IRONHAND)) > 0)
- damage += (skill_lv * 3);
- break;
- case W_MUSICAL:
- if((skill_lv = pc->checkskill(sd,BA_MUSICALLESSON)) > 0)
- damage += (skill_lv * 3);
- break;
- case W_WHIP:
- if((skill_lv = pc->checkskill(sd,DC_DANCINGLESSON)) > 0)
- damage += (skill_lv * 3);
- break;
- case W_BOOK:
- if((skill_lv = pc->checkskill(sd,SA_ADVANCEDBOOK)) > 0)
- damage += (skill_lv * 3);
- break;
- case W_KATAR:
- if((skill_lv = pc->checkskill(sd,AS_KATAR)) > 0)
- damage += (skill_lv * 3);
- break;
- }
- return damage;
- }
- /*==========================================
- * 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) {
- int skill2_lv, i;
- struct status_change *sc;
- struct map_session_data *sd;
- struct status_data *tstatus;
- nullpo_ret(src);
- nullpo_ret(target);
- sc = status->get_sc(src);
- sd = BL_CAST(BL_PC, src);
- tstatus = status->get_status_data(target);
- if ( !sd )
- return damage;
- damage = battle->add_mastery(sd, target, damage, left);
- switch( skill_id ){ // specific skill masteries
- case MO_INVESTIGATE:
- case MO_EXTREMITYFIST:
- case CR_GRANDCROSS:
- case NJ_ISSEN:
- case CR_ACIDDEMONSTRATION:
- return damage;
- case NJ_SYURIKEN:
- if( (skill2_lv = pc->checkskill(sd,NJ_TOBIDOUGU)) > 0
- #ifndef RENEWAL
- && weapon
- #endif
- )
- damage += 3 * skill2_lv;
- break;
- #ifndef RENEWAL
- case NJ_KUNAI:
- if( weapon )
- damage += 60;
- break;
- #endif
- case RA_WUGDASH://(Caster Current Weight x 10 / 8)
- if( sd->weight )
- damage += sd->weight / 8;
- /* Fall through */
- case RA_WUGSTRIKE:
- case RA_WUGBITE:
- damage += 30*pc->checkskill(sd, RA_TOOTHOFWUG);
- break;
- case HT_FREEZINGTRAP:
- damage += 40 * pc->checkskill(sd, RA_RESEARCHTRAP);
- break;
- default:
- battle->calc_masteryfix_unknown(src, target, &skill_id, &skill_lv, &damage, &div, &left, &weapon);
- break;
- }
- if( sc ){ // sc considered as masteries
- if(sc->data[SC_GN_CARTBOOST])
- damage += 10 * sc->data[SC_GN_CARTBOOST]->val1;
- if(sc->data[SC_CAMOUFLAGE])
- damage += 30 * ( 10 - sc->data[SC_CAMOUFLAGE]->val4 );
- #ifdef RENEWAL
- if(sc->data[SC_NIBELUNGEN] && weapon)
- damage += sc->data[SC_NIBELUNGEN]->val2;
- if(sc->data[SC_IMPOSITIO])
- damage += sc->data[SC_IMPOSITIO]->val2;
- if(sc->data[SC_DRUMBATTLE]){
- if(tstatus->size == SZ_SMALL)
- damage += sc->data[SC_DRUMBATTLE]->val2;
- else if(tstatus->size == SZ_MEDIUM)
- damage += 10 * sc->data[SC_DRUMBATTLE]->val1;
- //else no bonus for large target
- }
- if(sc->data[SC_GS_MADNESSCANCEL])
- damage += 100;
- if(sc->data[SC_GS_GATLINGFEVER]){
- if(tstatus->size == SZ_SMALL)
- damage += 10 * sc->data[SC_GS_GATLINGFEVER]->val1;
- else if(tstatus->size == SZ_MEDIUM)
- damage += -5 * sc->data[SC_GS_GATLINGFEVER]->val1;
- else
- damage += sc->data[SC_GS_GATLINGFEVER]->val1;
- }
- #if 0
- if(sc->data[SC_SPECIALZONE])
- damage += sc->data[SC_SPECIALZONE]->val2 >> 4;
- #endif // 0
- #endif // RENEWAL
- }
- // general skill masteries
- #ifdef RENEWAL
- if( div < 0 ) // div fix
- div = 1;
- if( skill_id == MO_FINGEROFFENSIVE )//The finger offensive spheres on moment of attack do count. [Skotlex]
- damage += div * sd->spiritball_old * 3;
- else
- damage += div * sd->spiritball * 3;
- if( skill_id != CR_SHIELDBOOMERANG ) // Only Shield boomerang doesn't takes the Star Crumbs bonus.
- damage += div * (left ? sd->left_weapon.star : sd->right_weapon.star);
- if( skill_id != MC_CARTREVOLUTION && (skill2_lv=pc->checkskill(sd,BS_HILTBINDING)) > 0 )
- damage += 4;
- if(sd->status.party_id && (skill2_lv=pc->checkskill(sd,TK_POWER)) > 0) {
- if( (i = party->foreachsamemap(party->sub_count, sd, 0)) > 1 )
- damage += 2 * skill2_lv * i * (damage /*+ unknown value*/) / 100 /*+ unknown value*/;
- }
- #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 )
- damage += damage * (10 + 2 * skill2_lv) / 100;
- #endif
- // percentage factor masteries
- if ( sc && sc->data[SC_MIRACLE] )
- i = 2; //Star anger
- else
- ARR_FIND(0, MAX_PC_FEELHATE, i, status->get_class(target) == sd->hate_mob[i]);
- if (i < MAX_PC_FEELHATE && (skill2_lv=pc->checkskill(sd,pc->sg_info[i].anger_id)) > 0 && weapon) {
- int ratio = sd->status.base_level + status_get_dex(src) + status_get_luk(src);
- if ( i == 2 ) ratio += status_get_str(src); //Star Anger
- if (skill2_lv < 4 )
- ratio /= (12 - 3 * skill2_lv);
- damage += damage * ratio / 100;
- }
- if( sd->status.class_ == JOB_ARCH_BISHOP_T || sd->status.class_ == JOB_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;
- }
- 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) {
- }
- /*==========================================
- * 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){
- struct status_data *tstatus;
- nullpo_ret(src);
- nullpo_ret(target);
- tstatus = status->get_status_data(target);
- if( (nk&NK_NO_ELEFIX) || n_ele )
- return damage;
- if( damage > 0 ) {
- if( left )
- damage = battle->attr_fix(src, target, damage, s_ele_, tstatus->def_ele, tstatus->ele_lv);
- else{
- damage=battle->attr_fix(src, target, damage, s_ele, tstatus->def_ele, tstatus->ele_lv);
- if( skill_id == MC_CARTREVOLUTION ) //Cart Revolution applies the element fix once more with neutral element
- damage = battle->attr_fix(src,target,damage,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv);
- if( skill_id == NC_ARMSCANNON )
- damage = battle->attr_fix(src,target,damage,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv);
- if( skill_id == GS_GROUNDDRIFT ) //Additional 50*lv Neutral damage.
- damage += battle->attr_fix(src,target,50*skill_lv,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv);
- }
- }
- #ifndef RENEWAL
- {
- struct status_data *sstatus;
- struct status_change *sc;
- sstatus = status->get_status_data(src);
- sc = status->get_sc(src);
- if( sc && sc->data[SC_SUB_WEAPONPROPERTY] ) { // Descriptions indicate this means adding a percent of a normal attack in another element. [Skotlex]
- int64 temp = battle->calc_base_damage2(sstatus, &sstatus->rhw, sc, tstatus->size, BL_CAST(BL_PC, src), (flag?2:0)) * sc->data[SC_SUB_WEAPONPROPERTY]->val2 / 100;
- damage += battle->attr_fix(src, target, temp, sc->data[SC_SUB_WEAPONPROPERTY]->val1, tstatus->def_ele, tstatus->ele_lv);
- if( left ) {
- temp = battle->calc_base_damage2(sstatus, &sstatus->lhw, sc, tstatus->size, BL_CAST(BL_PC, src), (flag?2:0)) * sc->data[SC_SUB_WEAPONPROPERTY]->val2 / 100;
- damage += battle->attr_fix(src, target, temp, sc->data[SC_SUB_WEAPONPROPERTY]->val1, tstatus->def_ele, tstatus->ele_lv);
- }
- }
- }
- #endif
- return damage;
- }
- 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;
- if ( !damage )
- return 0;
- nullpo_ret(bl);
- nullpo_ret(src);
- tsd = BL_CAST(BL_PC, bl);
- sstatus = status->get_status_data(src);
- if ( tsd ) {
- if ( !(nk&NK_NO_CARDFIX_DEF) ) {
- // RaceAddTolerance
- damage -= damage * tsd->race_tolerance[sstatus->race] / 100;
- damage -= damage * tsd->race_tolerance[is_boss(src) ? RC_BOSS : RC_NONBOSS] / 100;
- if ( flag&BF_SHORT )
- damage -= damage * tsd->bonus.near_attack_def_rate / 100;
- else // SubRangeAttackDamage or bLongAtkDef
- damage -= damage * tsd->bonus.long_attack_def_rate / 100;
- }
- if ( flag&BF_LONG && tsd->sc.data[SC_GS_ADJUSTMENT] ) {
- damage -= 20 * damage / 100;
- }
- }
- #endif
- return damage;
- }
- /*==========================================
- * Calculates card bonuses damage adjustments.
- * cflag(cardfix flag):
- * &1 - calc for left hand.
- * &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){
- 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;
- struct status_data *sstatus, *tstatus;
- int i;
- if( !damage )
- return 0;
- nullpo_ret(src);
- nullpo_ret(target);
- sd = BL_CAST(BL_PC, src);
- tsd = BL_CAST(BL_PC, target);
- t_class = status->get_class(target);
- s_class = status->get_class(src);
- sstatus = status->get_status_data(src);
- tstatus = status->get_status_data(target);
- s_race2 = status->get_race2(src);
- switch(attack_type){
- case BF_MAGIC:
- if ( sd && !(nk&NK_NO_CARDFIX_ATK) ) {
- cardfix = cardfix * (100 + sd->magic_addrace[tstatus->race]) / 100;
- if (!(nk&NK_NO_ELEFIX))
- cardfix = cardfix*(100+sd->magic_addele[tstatus->def_ele]) / 100;
- cardfix = cardfix * (100 + sd->magic_addsize[tstatus->size]) / 100;
- cardfix = cardfix * (100 + sd->magic_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100;
- cardfix = cardfix * (100 + sd->magic_atk_ele[s_ele])/100;
- for(i=0; i< ARRAYLENGTH(sd->add_mdmg) && sd->add_mdmg[i].rate; i++) {
- if(sd->add_mdmg[i].class_ == t_class) {
- cardfix = cardfix * (100 + sd->add_mdmg[i].rate) / 100;
- break;
- }
- }
- }
- if( tsd && !(nk&NK_NO_CARDFIX_DEF) )
- { // Target cards.
- if (!(nk&NK_NO_ELEFIX))
- {
- int ele_fix = tsd->subele[s_ele];
- for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++)
- {
- if(tsd->subele2[i].ele != s_ele) continue;
- if(!(tsd->subele2[i].flag&wflag&BF_WEAPONMASK &&
- tsd->subele2[i].flag&wflag&BF_RANGEMASK &&
- tsd->subele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix += tsd->subele2[i].rate;
- }
- cardfix = cardfix * (100 - ele_fix) / 100;
- }
- cardfix = cardfix * (100 - tsd->subsize[sstatus->size]) / 100;
- cardfix = cardfix * (100 - tsd->subrace2[s_race2]) / 100;
- cardfix = cardfix * (100 - tsd->subrace[sstatus->race]) / 100;
- cardfix = cardfix * (100 - tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS]) / 100;
- for(i=0; i < ARRAYLENGTH(tsd->add_mdef) && tsd->add_mdef[i].rate;i++) {
- if(tsd->add_mdef[i].class_ == s_class) {
- cardfix = cardfix * (100-tsd->add_mdef[i].rate) / 100;
- break;
- }
- }
- #ifndef RENEWAL
- //It was discovered that ranged defense also counts vs magic! [Skotlex]
- if ( wflag&BF_SHORT )
- cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100;
- else
- cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100;
- #endif
- cardfix = cardfix * ( 100 - tsd->bonus.magic_def_rate ) / 100;
- 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
- 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) ){
- int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->arrow_addele[tstatus->def_ele];
- for(i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++){
- if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue;
- if(!(sd->right_weapon.addele2[i].flag&wflag&BF_WEAPONMASK &&
- sd->right_weapon.addele2[i].flag&wflag&BF_RANGEMASK &&
- sd->right_weapon.addele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix += sd->right_weapon.addele2[i].rate;
- }
- cardfix = cardfix * (100 + ele_fix) / 100;
- }
- cardfix = cardfix * (100 + sd->right_weapon.addsize[tstatus->size]+sd->arrow_addsize[tstatus->size]) / 100;
- cardfix = cardfix * (100 + sd->right_weapon.addrace2[t_race2]) / 100;
- cardfix = cardfix * (100 + sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS] + sd->arrow_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100;
- }else{ // Melee attack
- if( !battle_config.left_cardfix_to_right ){
- cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race])/100;
- if( !(nk&NK_NO_ELEFIX) ){
- int ele_fix = sd->right_weapon.addele[tstatus->def_ele];
- for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) {
- if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue;
- if(!(sd->right_weapon.addele2[i].flag&wflag&BF_WEAPONMASK &&
- sd->right_weapon.addele2[i].flag&wflag&BF_RANGEMASK &&
- sd->right_weapon.addele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix += sd->right_weapon.addele2[i].rate;
- }
- cardfix = cardfix * (100+ele_fix) / 100;
- }
- cardfix = cardfix * (100+sd->right_weapon.addsize[tstatus->size]) / 100;
- cardfix = cardfix * (100+sd->right_weapon.addrace2[t_race2]) / 100;
- cardfix = cardfix * (100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100;
- if( cflag&1 ){
- cardfix_ = cardfix_*(100+sd->left_weapon.addrace[tstatus->race])/100;
- if (!(nk&NK_NO_ELEFIX)){
- int ele_fix_lh = sd->left_weapon.addele[tstatus->def_ele];
- for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) {
- if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue;
- if(!(sd->left_weapon.addele2[i].flag&wflag&BF_WEAPONMASK &&
- sd->left_weapon.addele2[i].flag&wflag&BF_RANGEMASK &&
- sd->left_weapon.addele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix_lh += sd->left_weapon.addele2[i].rate;
- }
- cardfix = cardfix * (100+ele_fix_lh) / 100;
- }
- cardfix_ = cardfix_ * (100+sd->left_weapon.addsize[tstatus->size]) / 100;
- cardfix_ = cardfix_ * (100+sd->left_weapon.addrace2[t_race2]) / 100;
- cardfix_ = cardfix_ * (100+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100;
- }
- }else{
- int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->left_weapon.addele[tstatus->def_ele];
- for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++){
- if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue;
- if(!(sd->right_weapon.addele2[i].flag&wflag&BF_WEAPONMASK &&
- sd->right_weapon.addele2[i].flag&wflag&BF_RANGEMASK &&
- sd->right_weapon.addele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix += sd->right_weapon.addele2[i].rate;
- }
- for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++){
- if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue;
- if(!(sd->left_weapon.addele2[i].flag&wflag&BF_WEAPONMASK &&
- sd->left_weapon.addele2[i].flag&wflag&BF_RANGEMASK &&
- sd->left_weapon.addele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix += sd->left_weapon.addele2[i].rate;
- }
- cardfix = cardfix * (100 + sd->right_weapon.addrace[tstatus->race] + sd->left_weapon.addrace[tstatus->race]) / 100;
- cardfix = cardfix * (100 + ele_fix) / 100;
- cardfix = cardfix * (100 + sd->right_weapon.addsize[tstatus->size] + sd->left_weapon.addsize[tstatus->size])/100;
- cardfix = cardfix * (100 + sd->right_weapon.addrace2[t_race2] + sd->left_weapon.addrace2[t_race2])/100;
- cardfix = cardfix * (100 + sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS] + sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100;
- }
- }
- for( i = 0; i < ARRAYLENGTH(sd->right_weapon.add_dmg) && sd->right_weapon.add_dmg[i].rate; i++ ){
- if( sd->right_weapon.add_dmg[i].class_ == t_class ){
- cardfix = cardfix * (100 + sd->right_weapon.add_dmg[i].rate) / 100;
- break;
- }
- }
- if( cflag&1 ){
- for( i = 0; i < ARRAYLENGTH(sd->left_weapon.add_dmg) && sd->left_weapon.add_dmg[i].rate; i++ ){
- if( sd->left_weapon.add_dmg[i].class_ == t_class ){
- cardfix_ = cardfix_ * (100 + sd->left_weapon.add_dmg[i].rate) / 100;
- break;
- }
- }
- }
- #ifndef RENEWAL
- if( wflag&BF_LONG )
- cardfix = cardfix * (100 + sd->bonus.long_attack_atk_rate) / 100;
- 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
- if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){
- if( !(nk&NK_NO_ELEFIX) ){
- int ele_fix = tsd->subele[s_ele];
- for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++)
- {
- if(tsd->subele2[i].ele != s_ele) continue;
- if(!(tsd->subele2[i].flag&wflag&BF_WEAPONMASK &&
- tsd->subele2[i].flag&wflag&BF_RANGEMASK &&
- tsd->subele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix += tsd->subele2[i].rate;
- }
- cardfix = cardfix * (100-ele_fix) / 100;
- if( cflag&1 && s_ele_ != s_ele ){
- int ele_fix_lh = tsd->subele[s_ele_];
- for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++){
- if(tsd->subele2[i].ele != s_ele_) continue;
- if(!(tsd->subele2[i].flag&wflag&BF_WEAPONMASK &&
- tsd->subele2[i].flag&wflag&BF_RANGEMASK &&
- tsd->subele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix_lh += tsd->subele2[i].rate;
- }
- cardfix = cardfix * (100 - ele_fix_lh) / 100;
- }
- }
- cardfix = cardfix * (100-tsd->subsize[sstatus->size]) / 100;
- cardfix = cardfix * (100-tsd->subrace2[s_race2]) / 100;
- cardfix = cardfix * (100-tsd->subrace[sstatus->race]) / 100;
- cardfix = cardfix * (100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS]) / 100;
- for( i = 0; i < ARRAYLENGTH(tsd->add_def) && tsd->add_def[i].rate;i++ ){
- if( tsd->add_def[i].class_ == s_class )
- {
- cardfix = cardfix * (100 - tsd->add_def[i].rate) / 100;
- break;
- }
- }
- #ifndef RENEWAL
- if( wflag&BF_SHORT )
- cardfix = cardfix * (100 - tsd->bonus.near_attack_def_rate) / 100;
- else // BF_LONG (there's no other choice)
- cardfix = cardfix * (100 - tsd->bonus.long_attack_def_rate) / 100;
- #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;
- case BF_MISC:
- if ( tsd && !(nk&NK_NO_CARDFIX_DEF) ) {
- // misc damage reduction from equipment
- #ifndef RENEWAL
- if ( !(nk&NK_NO_ELEFIX) )
- {
- int ele_fix = tsd->subele[s_ele];
- for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++)
- {
- if(tsd->subele2[i].ele != s_ele) continue;
- if(!(tsd->subele2[i].flag&wflag&BF_WEAPONMASK &&
- tsd->subele2[i].flag&wflag&BF_RANGEMASK &&
- tsd->subele2[i].flag&wflag&BF_SKILLMASK))
- continue;
- ele_fix += tsd->subele2[i].rate;
- }
- cardfix = cardfix * (100 - ele_fix) / 100;
- }
- cardfix = cardfix*(100-tsd->subrace[sstatus->race]) / 100;
- cardfix = cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS]) / 100;
- if( wflag&BF_SHORT )
- cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100;
- else // BF_LONG (there's no other choice)
- cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100;
- #endif
- 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;
- }
- return damage;
- }
- /*==========================================
- * Calculates defense reduction. [malufett]
- * flag:
- * &1 - idef/imdef(Ignore defense)
- * &2 - pdef(Pierce defense)
- * &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){
- struct status_data *sstatus, *tstatus;
- struct map_session_data *sd, *tsd;
- struct status_change *sc, *tsc;
- int i;
- if( !damage )
- return 0;
- nullpo_ret(src);
- nullpo_ret(target);
- sd = BL_CAST(BL_PC, src);
- tsd = BL_CAST(BL_PC, target);
- sstatus = status->get_status_data(src);
- tstatus = status->get_status_data(target);
- sc = status->get_sc(src);
- tsc = status->get_sc(target);
- switch(attack_type){
- case BF_WEAPON:
- {
- /* Take note in RE
- * def1 = equip def
- * def2 = status def
- */
- defType def1 = status->get_def(target); //Don't use tstatus->def1 due to skill timer reductions.
- short def2 = tstatus->def2, vit_def;
- #ifdef RENEWAL
- def1 = status->calc_def2(target, tsc, def1, false); // equip def(RE)
- def2 = status->calc_def(target, tsc, def2, false); // status def(RE)
- #else
- def1 = status->calc_def(target, tsc, def1, false); // equip def(RE)
- def2 = status->calc_def2(target, tsc, def2, false); // status def(RE)
- #endif
- if ( sd ) {
- if ( sd->charm_type == CHARM_TYPE_LAND && sd->charm_count > 0 ) // hidden from status window
- def1 += 10 * def1 * sd->charm_count / 100;
- i = sd->ignore_def[is_boss(target) ? RC_BOSS : RC_NONBOSS];
- i += sd->ignore_def[tstatus->race];
- if ( i ) {
- if ( i > 100 ) i = 100;
- def1 -= def1 * i / 100;
- #ifndef RENEWAL
- def2 -= def2 * i / 100;
- #endif
- }
- }
- if( sc && sc->data[SC_EXPIATIO] ){
- i = 5 * sc->data[SC_EXPIATIO]->val1; // 5% per level
- def1 -= def1 * i / 100;
- #ifndef RENEWAL
- def2 -= def2 * i / 100;
- #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;
- }
- }
- #ifndef RENEWAL
- if(skill_id == AM_ACIDTERROR) def1 = 0; //Acid Terror ignores only armor defense. [Skotlex]
- #endif
- if(def2 < 1) def2 = 1;
- }
- //Vitality reduction from rodatazone: http://rodatazone.simgaming.net/mechanics/substats.php#def
- if (tsd) {
- //Sd vit-eq
- #ifndef RENEWAL
- //[VIT*0.5] + rnd([VIT*0.3], max([VIT*0.3],[VIT^2/150]-1))
- vit_def = def2*(def2-15)/150;
- vit_def = def2/2 + (vit_def>0?rnd()%vit_def:0);
- #else
- vit_def = def2;
- #endif
- if((battle->check_undead(sstatus->race,sstatus->def_ele) || sstatus->race==RC_DEMON) && //This bonus already doesn't work vs players
- src->type == BL_MOB && (i=pc->checkskill(tsd,AL_DP)) > 0)
- vit_def += i*(int)(3 +(tsd->status.base_level+1)*0.04); // [orn]
- if( src->type == BL_MOB && (i=pc->checkskill(tsd,RA_RANGERMAIN))>0 &&
- (sstatus->race == RC_BRUTE || sstatus->race == RC_FISH || sstatus->race == RC_PLANT) )
- vit_def += i*5;
- }
- else { //Mob-Pet vit-eq
- #ifndef RENEWAL
- //VIT + rnd(0,[VIT/20]^2-1)
- vit_def = (def2/20)*(def2/20);
- vit_def = def2 + (vit_def>0?rnd()%vit_def:0);
- #else
- vit_def = def2;
- #endif
- }
- if (battle_config.weapon_defense_type) {
- vit_def += def1*battle_config.weapon_defense_type;
- def1 = 0;
- }
- #ifdef RENEWAL
- /**
- * RE DEF Reduction
- * Pierce defense gains 1 atk per def/2
- **/
- if( def1 < -399 ) // it stops at -399
- def1 = 399; // in aegis it set to 1 but in our case it may lead to exploitation so limit it to 399
- //return 1;
- if( flag&2 )
- damage += def1 >> 1;
- if( !(flag&1) && !(flag&2) ) {
- if( flag&4 )
- damage -= (def1 + vit_def);
- else
- damage = (int)((100.0f - de…
Large files files are truncated, but you can click here to view the full file