Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
- // For more information, see LICENCE in the main folder
- #include "../common/cbasetypes.h"
- #include "../common/timer.h"
- #include "../common/nullpo.h"
- #include "../common/malloc.h"
- #include "../common/showmsg.h"
- #include "../common/ers.h"
- #include "../common/strlib.h"
- #include "../common/utils.h"
- #include "map.h"
- #include "path.h"
- #include "pc.h"
- #include "status.h"
- #include "skill.h"
- #include "homunculus.h"
- #include "mercenary.h"
- #include "elemental.h"
- #include "mob.h"
- #include "itemdb.h"
- #include "clif.h"
- #include "pet.h"
- #include "guild.h"
- #include "party.h"
- #include "battle.h"
- #include "battleground.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- int attr_fix_table[4][ELE_MAX][ELE_MAX];
- struct Battle_Config battle_config;
- static struct eri *delay_damage_ers; //For battle delay damage structures.
- int battle_getcurrentskill(struct block_list *bl)
- { //Returns the current/last skill in use by this bl.
- struct unit_data *ud;
- if( bl->type == BL_SKILL )
- {
- struct skill_unit * su = (struct skill_unit*)bl;
- return su->group?su->group->skill_id:0;
- }
- ud = unit_bl2ud(bl);
- return ud?ud->skillid:0;
- }
- /*==========================================
- * Get random targetting enemy
- *------------------------------------------*/
- static 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;
- 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;
- ud = unit_bl2ud(bl);
- if (!ud) 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_gettargeted_sub, target, AREA_SIZE, BL_CHAR, bl_list, &c, target->id);
- if (c == 0 || c > 24)
- return NULL;
- return bl_list[rand()%c];
- }
- //Returns the id of the current targetted character of the passed bl. [Skotlex]
- int battle_gettarget(struct block_list* bl)
- {
- switch (bl->type)
- {
- case BL_PC: return ((struct map_session_data*)bl)->ud.target;
- case BL_MOB: return ((struct mob_data*)bl)->target_id;
- case BL_PET: return ((struct pet_data*)bl)->target_id;
- case BL_HOM: return ((struct homun_data*)bl)->ud.target;
- case BL_MER: return ((struct mercenary_data*)bl)->ud.target;
- case BL_ELEM: return ((struct elemental_data*)bl)->ud.target;
- }
- return 0;
- }
- static int battle_getenemy_sub(struct block_list *bl, va_list ap)
- {
- struct block_list **bl_list;
- struct block_list *target;
- int *c;
- 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;
- memset(bl_list, 0, sizeof(bl_list));
- map_foreachinrange(battle_getenemy_sub, target, range, type, bl_list, &c, target);
- if (c == 0 || c > 24)
- return NULL;
- return bl_list[rand()%c];
- }
- static int battle_getenemyarea_sub(struct block_list *bl, va_list ap)
- {
- struct block_list **bl_list, *src;
- int *c, ignore_id;
- bl_list = va_arg(ap, struct block_list **);
- c = va_arg(ap, int *);
- 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 >= 24 )
- 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;
- memset(bl_list, 0, sizeof(bl_list));
- map_foreachinarea(battle_getenemyarea_sub, src->m, x - range, y - range, x + range, y + range, type, bl_list, &c, src, ignore_id);
- if( c == 0 || c > 24 )
- return NULL;
- return bl_list[rand()%c];
- }
- // ƒ_??[ƒW‚Ì’x‰„
- struct delay_damage {
- struct block_list *src;
- int target;
- int damage;
- int delay;
- unsigned short distance;
- unsigned short skill_lv;
- unsigned short skill_id;
- enum damage_lv dmg_lv;
- unsigned short attack_type;
- };
- int battle_delay_damage_sub(int tid, unsigned int tick, int id, intptr data)
- {
- struct delay_damage *dat = (struct delay_damage *)data;
- struct block_list *target = map_id2bl(dat->target);
- if (target && dat && map_id2bl(id) == dat->src && target->prev != NULL && !status_isdead(target) &&
- target->m == dat->src->m &&
- (target->type != BL_PC || ((TBL_PC*)target)->invincible_timer == INVALID_TIMER) &&
- check_distance_bl(dat->src, target, dat->distance)) //Check to see if you haven't teleported. [Skotlex]
- {
- map_freeblock_lock();
- status_fix_damage(dat->src, target, dat->damage, dat->delay);
- if( dat->attack_type && !status_isdead(target) )
- skill_additional_effect(dat->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(dat->src,target,dat->skill_id,dat->skill_lv,dat->attack_type,tick);
- map_freeblock_unlock();
- }
- ers_free(delay_damage_ers, dat);
- return 0;
- }
- int battle_delay_damage (unsigned int tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, enum damage_lv dmg_lv, int ddelay)
- {
- struct delay_damage *dat;
- struct status_change *sc;
- nullpo_ret(src);
- nullpo_ret(target);
- sc = status_get_sc(target);
- if( sc && sc->data[SC_DEVOTION] && damage > 0 )
- damage = 0;
- if (!battle_config.delay_battle_damage) {
- map_freeblock_lock();
- status_fix_damage(src, target, damage, ddelay); // We have to seperate here between reflect damage and others [icescope]
- if( attack_type && !status_isdead(target) )
- skill_additional_effect(src, target, skill_id, skill_lv, attack_type, dmg_lv, gettick());
- if( dmg_lv > ATK_BLOCK && attack_type )
- skill_counter_additional_effect(src, target, skill_id, skill_lv, attack_type, gettick());
- map_freeblock_unlock();
- return 0;
- }
- dat = ers_alloc(delay_damage_ers, struct delay_damage);
- dat->src = src;
- dat->target = 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)+10; //Attack should connect regardless unless you teleported.
- if (src->type != BL_PC && amotion > 1000)
- amotion = 1000; //Aegis places a damage-delay cap of 1 sec to non player attacks. [Skotlex]
- add_timer(tick+amotion, battle_delay_damage_sub, src->id, (intptr)dat);
- return 0;
- }
- int battle_attr_ratio(int atk_elem,int def_type, int def_lv)
- {
- if (atk_elem < 0 || atk_elem >= ELE_MAX)
- return 100;
- if (def_type < 0 || def_type > ELE_MAX || def_lv < 1 || def_lv > 4)
- return 100;
- return 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.
- *------------------------------------------*/
- int battle_attr_fix(struct block_list *src, struct block_list *target, int 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 < 0 || atk_elem >= ELE_MAX)
- atk_elem = rand()%ELE_MAX;
- if (def_type < 0 || 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 = attr_fix_table[def_lv-1][atk_elem][def_type];
- if (sc && sc->count)
- {
- if(sc->data[SC_VOLCANO] && atk_elem == ELE_FIRE)
- ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1];
- if(sc->data[SC_VIOLENTGALE] && atk_elem == ELE_WIND)
- ratio += enchant_eff[sc->data[SC_VIOLENTGALE]->val1-1];
- if(sc->data[SC_DELUGE] && atk_elem == ELE_WATER)
- ratio += 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( atk_elem == ELE_FIRE && tsc && tsc->count && 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 && tsc->count )
- {
- if( tsc->data[SC_ORATIO] && atk_elem == ELE_HOLY )
- ratio += tsc->data[SC_ORATIO]->val1 * 2;
- if( tsc->data[SC_VENOMIMPRESS] && atk_elem == ELE_POISON)
- ratio += tsc->data[SC_VENOMIMPRESS]->val2;
- if( atk_elem == ELE_FIRE && tsc->data[SC_THORNSTRAP] )
- status_change_end(target, SC_THORNSTRAP, -1);
- if( tsc->data[SC_FIRE_CLOAK_OPTION] && atk_elem == ELE_FIRE)
- damage -= damage * tsc->data[SC_FIRE_CLOAK_OPTION]->val2 / 100;
- }
- if( target && target->type == BL_SKILL )
- {
- if( atk_elem == ELE_FIRE && battle_getcurrentskill(target) == GN_WALLOFTHORN )
- {
- struct skill_unit *su = (struct skill_unit*)target;
- struct skill_unit_group *sg;
- struct block_list *src;
- int x,y;
- if( !su || !su->alive || (sg = su->group) == NULL || !sg || sg->val3 == -1 ||
- (src = map_id2bl(su->val2)) == NULL || status_isdead(src) )
- return 0;
- if( sg->unit_id != UNT_FIREWALL )
- {
- x = sg->val3 >> 16;
- y = sg->val3 & 0xffff;
- skill_unitsetting(src,su->group->skill_id,su->group->skill_lv,x,y,1);
- sg->val3 = -1;
- sg->limit = DIFF_TICK(gettick(),sg->tick)+300;
- }
- }
- }
- if( atk_elem == ELE_FIRE && tsc && tsc->count && tsc->data[SC_CRYSTALIZE] )
- { //FIXTHIS: is this right to be an accurate way to remove Crystalize status when hitted by fire element? [Jobbie]
- tsc->data[SC_CRYSTALIZE]->val1 = 0;
- if( tsc->data[SC_CRYSTALIZE]->val2 == 0 )
- status_change_end(target,SC_CRYSTALIZE,-1);
- }
- return damage*ratio/100;
- }
- /*==========================================
- * ƒ_??[ƒW??IŒvŽZ
- *------------------------------------------*/
- int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damage *d,int damage,int skill_num,int skill_lv,int element)
- {
- struct map_session_data *sd = NULL;
- struct status_change *sc, *tsc;
- struct status_change_entry *sce;
- int div_ = d->div_, flag = d->flag;
- nullpo_ret(bl);
- // emistry - immune to skills and only receive 1 damage.
- if( ((TBL_MOB*)bl)->class_ == 1084 || ((TBL_MOB*)bl)->class_ == 1085 ){
- return (( flag&BF_SKILL )? 0:1 );
- }
- if( !damage )
- return 0;
- if( mob_ksprotected(src, bl) )
- return 0;
- if (bl->type == BL_PC) {
- sd=(struct map_session_data *)bl;
- //Special no damage states
- if(flag&BF_WEAPON && sd->special_state.no_weapon_damage)
- damage -= damage*sd->special_state.no_weapon_damage/100;
- if(flag&BF_MAGIC && sd->special_state.no_magic_damage)
- damage -= damage*sd->special_state.no_magic_damage/100;
- if(flag&BF_MISC && sd->special_state.no_misc_damage)
- damage -= damage*sd->special_state.no_misc_damage/100;
- if(!damage) return 0;
- }
- sc = status_get_sc(bl);
- tsc = status_get_sc(src);
- if( sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
- return 1;
- if (skill_num == PA_PRESSURE)
- return damage; //This skill bypass everything else.
- if( sc && sc->count )
- {
- //First, sc_*'s that reduce damage to 0.
- if( sc->data[SC_BASILICA] && !(status_get_mode(src)&MD_BOSS) && skill_num != PA_PRESSURE )
- {
- d->dmg_lv = ATK_BLOCK;
- return 0;
- }
- if( sc->data[SC_WHITEIMPRISON] && skill_num != HW_GRAVITATION && skill_num != PA_PRESSURE )
- { // Gravitation and Pressure do damage without removing the effect
- if( skill_num == MG_NAPALMBEAT || skill_num == MG_SOULSTRIKE || skill_num == WL_SOULEXPANSION || element == ELE_GHOST )
- status_change_end(bl,SC_WHITEIMPRISON,-1); // Those skills do damage and removes effect
- else
- {
- d->dmg_lv = ATK_BLOCK;
- return 0;
- }
- }
- if( sc->data[SC_SAFETYWALL] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT )
- {
- struct skill_unit_group* group = skill_id2group(sc->data[SC_SAFETYWALL]->val3);
- if (group) {
- if (--group->val2<=0)
- skill_delunitgroup(group);
- d->dmg_lv = ATK_BLOCK;
- return 0;
- }
- status_change_end(bl, SC_SAFETYWALL, INVALID_TIMER);
- }
- if( (sc->data[SC_PNEUMA] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG) || sc->data[SC__MANHOLE] )
- {
- d->dmg_lv = ATK_BLOCK;
- return 0;
- }
- if( sc->data[SC_ZEPHYR] && ((flag&BF_LONG) || rand()%100 < 10) )
- { // TODO: check if it blocks both, magic and physical ranged damages.
- d->dmg_lv = ATK_BLOCK;
- return 0;
- }
- if( map_getcell(bl->m,bl->x,bl->y,CELL_CHKMAELSTROM) && (flag&BF_MAGIC) && skill_num && (skill_get_inf(skill_num)&INF_GROUND_SKILL) )
- {
- int sp = damage * 20 / 100; // Steel need official value.
- status_heal(bl,0,sp,3);
- d->dmg_lv = ATK_BLOCK;
- return 0;
- }
- if( sc->data[SC_WEAPONBLOCKING] && flag&(BF_SHORT|BF_WEAPON) && rand()%100 < sc->data[SC_WEAPONBLOCKING]->val2 )
- {
- clif_skill_nodamage(bl,src,GC_WEAPONBLOCKING,1,1);
- d->dmg_lv = ATK_NONE;
- sc_start2(bl,SC_COMBO,100,GC_WEAPONBLOCKING,src->id,2000);
- return 0;
- }
- if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill_get_nk(skill_num)&NK_NO_CARDFIX_ATK) && rand()%100 < sce->val2 )
- {
- int delay;
- clif_skill_nodamage(bl,bl,CR_AUTOGUARD,sce->val1,1);
- // different delay depending on skill level [celest]
- if (sce->val1 <= 5)
- delay = 300;
- else if (sce->val1 > 5 && sce->val1 <= 9)
- delay = 200;
- else
- delay = 100;
- unit_set_walkdelay(bl, gettick(), delay, 1);
- if(sc->data[SC_SHRINK] && rand()%100<5*sce->val1)
- skill_blown(bl,src,skill_get_blewcount(CR_SHRINK,1),-1,0);
- return 0;
- }
- if( sd && (sce = sc->data[SC_MILLENNIUMSHIELD]) && sce->val2 > 0 && damage > 0 )
- {
- clif_skill_nodamage(bl, bl, RK_MILLENNIUMSHIELD, 1, 1);
- sce->val3 -= damage; // absorb damage
- d->dmg_lv = ATK_BLOCK;
- sc_start(bl,SC_STUN,15,0,skill_get_time2(RK_MILLENNIUMSHIELD,sce->val1)); // There is a chance to be stuned when one shield is broken.
- if( sce->val3 <= 0 ) // Shield Down
- {
- sce->val2--;
- if( sce->val2 > 0 )
- {
- clif_millenniumshield(sd,sce->val2);
- sce->val3 = 1000; // Next Shield
- }
- else
- status_change_end(bl,SC_MILLENNIUMSHIELD,-1); // All shields down
- }
- return 0;
- }
- if( (sce=sc->data[SC_PARRYING]) && flag&BF_WEAPON && skill_num != WS_CARTTERMINATION && rand()%100 < sce->val2 )
- { // attack blocked by Parrying
- clif_skill_nodamage(bl, bl, LK_PARRYING, sce->val1,1);
- return 0;
- }
- if(sc->data[SC_DODGE] && !sc->opt1 &&
- (flag&BF_LONG || sc->data[SC_SPURT])
- && rand()%100 < 20)
- {
- if (sd && pc_issit(sd) && !sc->data[SC_SITDOWN_FORCE]) pc_setstand(sd); //Stand it to dodge.
- clif_skill_nodamage(bl,bl,TK_DODGE,1,1);
- if (!sc->data[SC_COMBO])
- sc_start4(bl, SC_COMBO, 100, TK_JUMPKICK, src->id, 1, 0, 2000);
- return 0;
- }
- if(sc->data[SC_HERMODE] && flag&BF_MAGIC)
- return 0;
- if(sc->data[SC_TATAMIGAESHI] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG)
- return 0;
- if((sce=sc->data[SC_KAUPE]) && rand()%100 < sce->val2)
- { //Kaupe blocks damage (skill or otherwise) from players, mobs, homuns, mercenaries.
- clif_specialeffect(bl, 462, AREA);
- //Shouldn't end until Breaker's non-weapon part connects.
- if (skill_num != ASC_BREAKER || !(flag&BF_WEAPON))
- if (--(sce->val3) <= 0) //We make it work like Safety Wall, even though it only blocks 1 time.
- status_change_end(bl, SC_KAUPE, INVALID_TIMER);
- return 0;
- }
- if( flag&BF_MAGIC && (sce=sc->data[SC_PRESTIGE]) && rand()%100 < sce->val2)
- {
- clif_specialeffect(bl, 462, AREA); // Still need confirm it.
- return 0;
- }
- if (((sce=sc->data[SC_UTSUSEMI]) || sc->data[SC_BUNSINJYUTSU])
- &&
- flag&BF_WEAPON && !(skill_get_nk(skill_num)&NK_NO_CARDFIX_ATK))
- {
- if (sce) {
- clif_specialeffect(bl, 462, AREA);
- skill_blown(src,bl,sce->val3,-1,0);
- }
- //Both need to be consumed if they are active.
- if (sce && --(sce->val2) <= 0)
- status_change_end(bl, SC_UTSUSEMI, INVALID_TIMER);
- if ((sce=sc->data[SC_BUNSINJYUTSU]) && --(sce->val2) <= 0)
- status_change_end(bl, SC_BUNSINJYUTSU, INVALID_TIMER);
- return 0;
- }
- //Now damage increasing effects
- if( sc->data[SC_AETERNA] && skill_num != PF_SOULBURN )
- {
- if( src->type != BL_MER || skill_num == 0 )
- damage <<= 1; // Lex Aeterna only doubles damage of regular attacks from mercenaries
- if( skill_num != ASC_BREAKER || !(flag&BF_WEAPON) )
- status_change_end(bl, SC_AETERNA, INVALID_TIMER); //Shouldn't end until Breaker's non-weapon part connects.
- }
- if( sc->data[SC_DEEPSLEEP] )
- {
- damage += damage / 2; // 1.5 times more damage while in Deep Sleep.
- status_change_end(bl,SC_DEEPSLEEP,-1);
- }
- if( sc->data[SC_VOICEOFSIREN] && damage > 0)
- status_change_end(bl,SC_VOICEOFSIREN,-1);
- //Finally damage reductions....
- if( sc->data[SC_ASSUMPTIO] )
- {
- if( map_flag_vs(bl->m) )
- damage = damage * 2 / 3; //Receive 66% damage
- else
- damage >>= 1; //Receive 50% damage
- }
- if( sc->data[SC_DEFENDER] && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON) )
- damage = damage * (100 - sc->data[SC_DEFENDER]->val2) / 100;
- if( sc->data[SC_ADJUSTMENT] && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON) )
- damage -= 20 * damage / 100;
- if( sc->data[SC_FOGWALL] )
- {
- if( flag&BF_SKILL ) //25% reduction
- damage -= 25 * damage / 100;
- else if( (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON) )
- damage >>= 2; //75% reduction
- }
- // Compressed code, fixed by map.h [Epoque]
- if( src->type == BL_MOB )
- {
- int i;
- if( sc->data[SC_MANU_DEF] )
- for( i = 0; ARRAYLENGTH(mob_manuk) > i; i++ )
- if( mob_manuk[i] == ((TBL_MOB*)src)->class_ )
- {
- damage -= sc->data[SC_MANU_DEF]->val1 * damage / 100;
- break;
- }
- if( sc->data[SC_SPL_DEF] )
- for (i=0;ARRAYLENGTH(mob_splendide)>i;i++)
- if (mob_splendide[i]==((TBL_MOB*)src)->class_) {
- damage -= sc->data[SC_SPL_DEF]->val1*damage/100;
- break;
- }
- }
- if((sce=sc->data[SC_ARMOR]) && //NPC_DEFENDER
- sce->val3&flag && sce->val4&flag)
- damage -= damage*sc->data[SC_ARMOR]->val2/100;
- if(sc->data[SC_ENERGYCOAT] && flag&BF_WEAPON
- && skill_num != WS_CARTTERMINATION)
- {
- struct status_data *status = status_get_status_data(bl);
- int per = 100*status->sp / status->max_sp -1; //100% should be counted as the 80~99% interval
- per /=20; //Uses 20% SP intervals.
- //SP Cost: 1% + 0.5% per every 20% SP
- if (!status_charge(bl, 0, (10+5*per)*status->max_sp/1000))
- status_change_end(bl, SC_ENERGYCOAT, INVALID_TIMER);
- //Reduction: 6% + 6% every 20%
- damage -= damage * 6 * (1+per) / 100;
- }
- if( (sce = sc->data[SC_STONEHARDSKIN]) && flag&BF_WEAPON && damage > 0 )
- {
- sce->val2 -= damage;
- skill_break_equip(src,EQP_WEAPON,3000,BCT_SELF);// Need to code something that will lower a monster's attack by 25%. [Rytech]
- if( sce->val2 <= 0 ) status_change_end(bl, SC_STONEHARDSKIN, -1);
- }
- // FIXME:
- // So Reject Sword calculates the redirected damage before calculating WoE/BG reduction? This is weird. [Inkfish]
- if((sce=sc->data[SC_REJECTSWORD]) && flag&BF_WEAPON &&
- // Fixed the condition check [Aalye]
- (src->type!=BL_PC || (
- ((TBL_PC *)src)->status.weapon == W_DAGGER ||
- ((TBL_PC *)src)->status.weapon == W_1HSWORD ||
- ((TBL_PC *)src)->status.weapon == W_2HSWORD
- )) &&
- rand()%100 < sce->val2
- ){
- damage = damage*50/100;
- status_fix_damage(bl,src,damage,clif_damage(bl,src,gettick(),0,0,damage,0,0,0));
- clif_skill_nodamage(bl,bl,ST_REJECTSWORD,sce->val1,1);
- if(--(sce->val3)<=0)
- status_change_end(bl, SC_REJECTSWORD, INVALID_TIMER);
- }
- //Finally added to remove the status of immobile when aimedbolt is used. [Jobbie]
- if( skill_num == RA_AIMEDBOLT && (sc->data[SC_BITE] || sc->data[SC_ANKLE] || sc->data[SC_ELECTRICSHOCKER]) )
- {
- status_change_end(bl, SC_BITE, -1);
- status_change_end(bl, SC_ANKLE, -1);
- status_change_end(bl, SC_ELECTRICSHOCKER, -1);
- }
- //Finally Kyrie because it may, or not, reduce damage to 0.
- if((sce = sc->data[SC_KYRIE]) && damage > 0){
- sce->val2-=damage;
- if(flag&BF_WEAPON || skill_num == TF_THROWSTONE){
- if(sce->val2>=0)
- damage=0;
- else
- damage=-sce->val2;
- }
- if((--sce->val3)<=0 || (sce->val2<=0) || skill_num == AL_HOLYLIGHT)
- status_change_end(bl, SC_KYRIE, INVALID_TIMER);
- }
- if( (sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && damage > 0 && rand()%100 < sce->val1 )
- {
- skill_blown(src,bl,distance_bl(src,bl)-1,unit_getdir(src),0);
- d->div_ = ATK_DEF;
- status_change_end(bl, SC_LIGHTNINGWALK, -1);
- return 0;
- }
- if (!damage) return 0;
- //Probably not the most correct place, but it'll do here
- //(since battle_drain is strictly for players currently)
- if ((sce=sc->data[SC_BLOODLUST]) && flag&BF_WEAPON && damage > 0 &&
- rand()%100 < sce->val3)
- status_heal(src, damage*sce->val4/100, 0, 3);
- if( sd && (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rand()%100 < sce->val2 )
- pc_addrageball(sd,skill_get_time(LG_FORCEOFVANGUARD,sce->val1),sce->val3);
- if( (sce = sc->data[SC_GT_ENERGYGAIN]) && flag&BF_WEAPON && rand()%100 < 10 + 5 * sce->val1 )
- {
- int duration = skill_get_time2(MO_CALLSPIRITS, sce->val1);
- if( sd ) pc_addspiritball(sd, duration, sce->val1);
- }
- if( sc->data[SC__DEADLYINFECT] && damage > 0 && rand()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 )
- status_change_spread(bl, src); // Deadly infect attacked side
- }
- if( tsc && tsc->count )
- {
- if( tsc->data[SC_INVINCIBLE] && !tsc->data[SC_INVINCIBLEOFF] )
- damage += damage * 75 / 100;
- // [Epoque]
- if (bl->type == BL_MOB)
- {
- int i;
- if ( ((sce=tsc->data[SC_MANU_ATK]) && (flag&BF_WEAPON)) ||
- ((sce=tsc->data[SC_MANU_MATK]) && (flag&BF_MAGIC))
- )
- for (i=0;ARRAYLENGTH(mob_manuk)>i;i++)
- if (((TBL_MOB*)bl)->class_==mob_manuk[i]) {
- damage += damage*sce->val1/100;
- break;
- }
- if ( ((sce=tsc->data[SC_SPL_ATK]) && (flag&BF_WEAPON)) ||
- ((sce=tsc->data[SC_SPL_MATK]) && (flag&BF_MAGIC))
- )
- for (i=0;ARRAYLENGTH(mob_splendide)>i;i++)
- if (((TBL_MOB*)bl)->class_==mob_splendide[i]) {
- damage += damage*sce->val1/100;
- break;
- }
- }
- if( tsc->data[SC_POISONINGWEAPON] && skill_num != GC_VENOMPRESSURE && (flag&BF_WEAPON) && damage > 0 && rand()%100 < tsc->data[SC_POISONINGWEAPON]->val3 )
- sc_start(bl,tsc->data[SC_POISONINGWEAPON]->val2,100,tsc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON,tsc->data[SC_POISONINGWEAPON]->val1));
- if( tsc->data[SC__DEADLYINFECT] && damage > 0 && rand()%100 < 65 + 5 * tsc->data[SC__DEADLYINFECT]->val1 )
- status_change_spread(src, bl);
- }
- if( battle_config.pk_mode && sd && bl->type == BL_PC && damage )
- {
- if( flag & BF_SKILL )
- { //Skills get a different reduction than non-skills. [Skotlex]
- if( flag&BF_WEAPON )
- damage = damage * battle_config.pk_weapon_damage_rate/100;
- if( flag&BF_MAGIC )
- damage = damage * battle_config.pk_magic_damage_rate/100;
- if( flag&BF_MISC )
- damage = damage * battle_config.pk_misc_damage_rate/100;
- }
- else
- { //Normal attacks get reductions based on range.
- if( flag&BF_SHORT )
- damage = damage * battle_config.pk_short_damage_rate/100;
- if( flag&BF_LONG )
- damage = damage * battle_config.pk_long_damage_rate/100;
- }
- if( !damage ) damage = 1;
- }
- if(battle_config.skill_min_damage && damage > 0 && damage < div_)
- {
- if ((flag&BF_WEAPON && battle_config.skill_min_damage&1)
- || (flag&BF_MAGIC && battle_config.skill_min_damage&2)
- || (flag&BF_MISC && battle_config.skill_min_damage&4)
- )
- damage = div_;
- }
- if( bl->type == BL_MOB && !status_isdead(bl) && src != bl) {
- if (damage > 0 )
- mobskill_event((TBL_MOB*)bl,src,gettick(),flag);
- if (skill_num)
- mobskill_event((TBL_MOB*)bl,src,gettick(),MSC_SKILLUSED|(skill_num<<16));
- }
- if( sd && pc_isriding(sd,OPTION_MADO) && (element == ELE_FIRE || element == ELE_WATER) && rand()%100 < 50 )
- pc_overheat(sd,element == ELE_FIRE ? 1 : -1);
- if( sc && sc->data[SC__SHADOWFORM] )
- {
- struct block_list *s_bl = map_id2bl(sc->data[SC__SHADOWFORM]->val2);
- if( !s_bl )
- { // If the shadow form target is not present remove the sc.
- status_change_end(bl, SC__SHADOWFORM, -1);
- }
- else if( status_isdead(s_bl) || !battle_check_target(src,s_bl,BCT_ENEMY))
- { // If the shadow form target is dead or not your enemy remove the sc in both.
- status_change_end(bl, SC__SHADOWFORM, -1);
- if( s_bl->type == BL_PC )
- ((TBL_PC*)s_bl)->shadowform_id = 0;
- }
- else
- {
- if( (--sc->data[SC__SHADOWFORM]->val3) < 0 )
- { // If you have exceded max hits supported, remove the sc in both.
- status_change_end(bl, SC__SHADOWFORM, -1);
- if( s_bl->type == BL_PC )
- ((TBL_PC*)s_bl)->shadowform_id = 0;
- }
- else
- {
- status_damage(src, s_bl, damage, 0, clif_damage(s_bl, s_bl, gettick(), 500, 500, damage, -1, 0, 0), 0);
- return ATK_NONE;
- }
- }
- }
- return damage;
- }
- /*==========================================
- * Calculates BG related damage adjustments.
- *------------------------------------------*/
- int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int damage, int div_, int skill_num, int skill_lv, int flag)
- {
- if( !damage )
- return 0;
- if( bl->type == BL_MOB )
- {
- struct mob_data* md = BL_CAST(BL_MOB, bl);
- if( map[bl->m].flag.battleground && (md->class_ == 1914 || md->class_ == 1915) && flag&BF_SKILL )
- return 0; // Crystal cannot receive skill damage on battlegrounds
- // emistry - skill immune + 1 damage only
- if(md->class_ == 1084 || md->class_ == 1085){
- return (( flag&BF_SKILL )? 0:1 );
- }
- }
- switch( skill_num )
- {
- case PA_PRESSURE:
- case HW_GRAVITATION:
- case NJ_ZENYNAGE:
- //case RK_DRAGONBREATH:
- //case GN_HELLS_PLANT_ATK:
- //case KO_MUCHANAGE:
- break;
- default:
- if( flag&BF_SKILL )
- { //Skills get a different reduction than non-skills. [Skotlex]
- if( flag&BF_WEAPON )
- damage = damage * battle_config.bg_weapon_damage_rate/100;
- if( flag&BF_MAGIC )
- damage = damage * battle_config.bg_magic_damage_rate/100;
- if( flag&BF_MISC )
- damage = damage * battle_config.bg_misc_damage_rate/100;
- }
- else
- { //Normal attacks get reductions based on range.
- if( flag&BF_SHORT )
- damage = damage * battle_config.bg_short_damage_rate/100;
- if( flag&BF_LONG )
- damage = damage * battle_config.bg_long_damage_rate/100;
- }
- if( !damage ) damage = 1;
- }
- return damage;
- }
- /*==========================================
- * Calculates GVG related damage adjustments.
- *------------------------------------------*/
- int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int damage,int div_,int skill_num,int skill_lv,int flag)
- {
- struct mob_data* md = BL_CAST(BL_MOB, bl);
- int class_ = status_get_class(bl);
- // emistry - immune to skills and only receive 1 damage.
- if( class_ == 1084 || class_ == 1085 ){
- return (( flag&BF_SKILL )? 0:1 );
- }
- if (!damage) //No reductions to make.
- return 0;
- if(md && md->guardian_data) {
- if(class_ == MOBID_EMPERIUM && flag&BF_SKILL)
- //Skill immunity.
- switch (skill_num) {
- case MO_TRIPLEATTACK:
- case HW_GRAVITATION:
- break;
- default:
- return 0;
- }
- if(src->type != BL_MOB) {
- struct guild *g=guild_search(status_get_guild_id(src));
- if (!g) return 0;
- if (class_ == MOBID_EMPERIUM && guild_checkskill(g,GD_APPROVAL) <= 0)
- return 0;
- if (battle_config.guild_max_castles && guild_checkcastles(g)>=battle_config.guild_max_castles)
- return 0; // [MouseJstr]
- }
- }
- switch (skill_num) {
- //Skills with no damage reduction.
- case PA_PRESSURE:
- case HW_GRAVITATION:
- case NJ_ZENYNAGE:
- //case RK_DRAGONBREATH:
- //case GN_HELLS_PLANT_ATK:
- //case KO_MUCHANAGE:
- break;
- default:
- if (md && md->guardian_data) {
- damage -= damage * (md->guardian_data->castle->defense/100) * battle_config.castle_defense_rate/100;
- }
- if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex]
- if (flag&BF_WEAPON)
- damage = damage * battle_config.gvg_weapon_damage_rate/100;
- if (flag&BF_MAGIC)
- damage = damage * battle_config.gvg_magic_damage_rate/100;
- if (flag&BF_MISC)
- damage = damage * battle_config.gvg_misc_damage_rate/100;
- } else { //Normal attacks get reductions based on range.
- if (flag & BF_SHORT)
- damage = damage * battle_config.gvg_short_damage_rate/100;
- if (flag & BF_LONG)
- damage = damage * battle_config.gvg_long_damage_rate/100;
- }
- if(!damage) damage = 1;
- }
- return damage;
- }
- /*==========================================
- * HP/SP‹zŽû‚ÌŒvŽZ
- *------------------------------------------*/
- static int battle_calc_drain(int damage, int rate, int per)
- {
- int diff = 0;
- if (per && rand()%1000 < rate) {
- diff = (damage * per) / 100;
- if (diff == 0) {
- if (per > 0)
- diff = 1;
- else
- diff = -1;
- }
- }
- return diff;
- }
- /*==========================================
- * ?C—ûƒ_??[ƒW
- *------------------------------------------*/
- int battle_addmastery(struct map_session_data *sd,struct block_list *target,int dmg,int type)
- {
- int damage,skill;
- struct status_data *status = status_get_status_data(target);
- int weapon;
- damage = dmg;
- nullpo_ret(sd);
- if((skill = pc_checkskill(sd,AL_DEMONBANE)) > 0 &&
- target->type == BL_MOB && //This bonus doesnt work against players.
- (battle_check_undead(status->race,status->def_ele) || status->race==RC_DEMON) )
- damage += (skill*(int)(3+(sd->status.base_level+1)*0.05)); // submitted by orn
- //damage += (skill * 3);
- if((skill = pc_checkskill(sd,HT_BEASTBANE)) > 0 && (status->race==RC_BRUTE || status->race==RC_INSECT) ) {
- damage += (skill * 4);
- if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_HUNTER)
- damage += sd->status.str;
- }
- if( (skill = pc_checkskill(sd, RA_RANGERMAIN)) > 0 && (status->race == RC_BRUTE || status->race == RC_PLANT || status->race == RC_FISH) )
- damage += (skill * 5);
- if( (skill = pc_checkskill(sd,NC_RESEARCHFE)) > 0 && (status->def_ele == ELE_FIRE || status->def_ele == ELE_EARTH) )
- damage += (skill * 10);
- if( pc_isriding(sd, OPTION_MADO) )
- damage += 15 * pc_checkskill(sd, NC_MADOLICENCE);
- if(type == 0)
- weapon = sd->weapontype1;
- else
- weapon = sd->weapontype2;
- switch(weapon)
- {
- case W_DAGGER:
- case W_1HSWORD:
- if((skill = pc_checkskill(sd,SM_SWORD)) > 0)
- damage += (skill * 4);
- if((skill = pc_checkskill(sd,GN_TRAINING_SWORD)) > 0)
- damage += skill * 10;
- break;
- case W_2HSWORD:
- if((skill = pc_checkskill(sd,SM_TWOHAND)) > 0)
- damage += (skill * 4);
- break;
- case W_1HSPEAR:
- case W_2HSPEAR:
- if((skill = pc_checkskill(sd,KN_SPEARMASTERY)) > 0) {
- if(!pc_isriding(sd, OPTION_RIDING|OPTION_RIDING_DRAGON))
- damage += skill * 4;
- else
- damage += skill * (5 + pc_checkskill(sd,RK_DRAGONTRAINING));//Mastery damage is higher when on a Dragon Mount. [Rytech]
- }
- break;
- case W_1HAXE:
- case W_2HAXE:
- if((skill = pc_checkskill(sd,AM_AXEMASTERY)) > 0)
- damage += (skill * 3);
- if((skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
- damage += (skill * 5);
- break;
- case W_MACE:
- case W_2HMACE:
- if((skill = pc_checkskill(sd,PR_MACEMASTERY)) > 0)
- damage += (skill * 3);
- if((skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
- damage += (skill * 4);
- break;
- case W_FIST:
- if((skill = pc_checkskill(sd,TK_RUN)) > 0)
- damage += (skill * 10);
- // No break, fallthrough to Knuckles
- case W_KNUCKLE:
- if((skill = pc_checkskill(sd,MO_IRONHAND)) > 0)
- damage += (skill * 3);
- break;
- case W_MUSICAL:
- if((skill = pc_checkskill(sd,BA_MUSICALLESSON)) > 0)
- damage += (skill * 3);
- break;
- case W_WHIP:
- if((skill = pc_checkskill(sd,DC_DANCINGLESSON)) > 0)
- damage += (skill * 3);
- break;
- case W_BOOK:
- if((skill = pc_checkskill(sd,SA_ADVANCEDBOOK)) > 0)
- damage += (skill * 3);
- break;
- case W_KATAR:
- if((skill = pc_checkskill(sd,AS_KATAR)) > 0)
- damage += (skill * 3);
- break;
- }
- return damage;
- }
- /*==========================================
- * Calculates the standard damage of a normal attack assuming it hits,
- * it calculates nothing extra fancy, is needed for magnum break's WATK_ELEMENT bonus. [Skotlex]
- *------------------------------------------
- * Pass damage2 as NULL to not calc it.
- * Flag values:
- * &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)
- */
- static int battle_calc_base_damage(struct status_data *status, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag)
- {
- unsigned short atkmin = 0, atkmax = 0;
- short type = 0;
- int damage = 0;
- if( !sd )
- { //Mobs/Pets
- if( flag&4 )
- {
- atkmin = status->matk_min;
- atkmax = status->matk_max;
- } else {
- atkmin = wa->atk;
- atkmax = wa->atk2;
- }
- if (atkmin > atkmax)
- atkmin = atkmax;
- } else { //PCs
- atkmax = wa->atk;
- type = (wa == &status->lhw)?EQI_HAND_L:EQI_HAND_R;
- if (!(flag&1) || (flag&2))
- { //Normal attacks
- atkmin = status->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? rand()%(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->arrow_atk)
- damage += ((flag&1)?sd->arrow_atk:rand()%sd->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 += status->matk_min;
- else
- damage += status->batk;
- //rodatazone says that Overrefine 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 += rand()%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 += rand()%sd->right_weapon.overrefine+1;
- if (sd->weapon_atk_rate[sd->weapontype1])
- damage += damage*sd->weapon_atk_rate[sd->weapontype1]/100;;
- }
- }
- return damage;
- }
- /*==========================================
- * Consumes ammo for the given skill.
- *------------------------------------------*/
- void battle_consume_ammo(TBL_PC*sd, int skill, int lv)
- {
- int qty=1;
- if (!battle_config.arrow_decrement)
- return;
- if (skill)
- {
- qty = skill_get_ammo_qty(skill, lv);
- if (!qty) qty = 1;
- }
- if(sd->equip_index[EQI_AMMO]>=0) //Qty check should have been done in skill_check_condition
- pc_delitem(sd,sd->equip_index[EQI_AMMO],qty,0,1);
- sd->state.arrow_atk = 0;
- }
- static int battle_range_type(
- struct block_list *src, struct block_list *target,
- int skill_num, int skill_lv)
- { //Skill Range Criteria
- if (battle_config.skillrange_by_distance &&
- (src->type&battle_config.skillrange_by_distance)
- ) { //based on distance between src/target [Skotlex]
- if (check_distance_bl(src, target, 5))
- return BF_SHORT;
- return BF_LONG;
- }
- //based on used skill's range
- if (skill_get_range2(src, skill_num, skill_lv) < 5)
- return BF_SHORT;
- return BF_LONG;
- }
- static int battle_blewcount_bonus(struct map_session_data *sd, int skill_num)
- {
- int i;
- if (!sd->skillblown[0].id)
- return 0;
- //Apply the bonus blewcount. [Skotlex]
- for (i = 0; i < ARRAYLENGTH(sd->skillblown) && sd->skillblown[i].id; i++) {
- if (sd->skillblown[i].id == skill_num)
- return sd->skillblown[i].val;
- }
- return 0;
- }
- struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int mflag);
- struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int mflag);
- //For quick div adjustment.
- #define damage_div_fix(dmg, div) { if (div > 1) (dmg)*=div; else if (div < 0) (div)*=-1; }
- /*==========================================
- * battle_calc_weapon_attack (by Skotlex)
- *------------------------------------------*/
- static struct Damage battle_calc_weapon_attack(struct block_list *src, struct block_list *target, int skill_num, int skill_lv, int wflag)
- {
- unsigned int skillratio = 100; //Skill dmg modifiers.
- short skill=0;
- short s_ele, s_ele_, t_class;
- int i, nk, s_level;
- bool n_ele = false; // non-elemental
- char re_baselv_bonus = battle_config.renewal_baselvl_skill_ratio;//BaseLv config for renewal skills.
- int chorusbonus = 0;//Chorus bonus value for chorus skills. Bonus remains 0 unless 3 or more Minstrel's/Wanderer's are in the party.
- struct map_session_data *sd, *tsd;
- struct Damage wd;
- struct status_change *sc = status_get_sc(src);
- struct status_change *tsc = status_get_sc(target);
- struct status_data *sstatus = status_get_status_data(src);
- struct status_data *tstatus = status_get_status_data(target);
- struct {
- unsigned hit : 1; //the attack Hit? (not a miss)
- unsigned cri : 1; //Critical hit
- unsigned idef : 1; //Ignore defense
- unsigned idef2 : 1; //Ignore defense (left weapon)
- unsigned pdef : 2; //Pierces defense (Investigate/Ice Pick)
- unsigned pdef2 : 2; //1: Use def+def2/100, 2: Use def+def2/50
- unsigned infdef : 1; //Infinite defense (plants)
- unsigned arrow : 1; //Attack is arrow-based
- unsigned rh : 1; //Attack considers right hand (wd.damage)
- unsigned lh : 1; //Attack considers left hand (wd.damage2)
- unsigned weapon : 1; //It's a weapon attack (consider VVS, and all that)
- } flag;
- memset(&wd,0,sizeof(wd));
- memset(&flag,0,sizeof(flag));
- if(src==NULL || target==NULL)
- {
- nullpo_info(NLP_MARK);
- return wd;
- }
- s_level = status_get_lv(src);
- if( skill_num >= RK_ENCHANTBLADE && skill_num <= LG_OVERBRAND_PLUSATK &&
- battle_config.max_highlvl_nerf && s_level > battle_config.max_highlvl_nerf )
- s_level = battle_config.max_highlvl_nerf;
- //Initial flag
- flag.rh = 1;
- flag.weapon = 1;
- flag.infdef =(tstatus->mode&MD_PLANT) ? 1 : 0;
- if( !flag.infdef && (target->type == BL_SKILL && ((TBL_SKILL*)target)->group->unit_id == UNT_REVERBERATION) )
- flag.infdef = 1; // Reberberation takes 1 damage
- //Initial Values
- wd.type = 0; //Normal attack
- wd.div_ = skill_num?skill_get_num(skill_num,skill_lv):1;
- wd.amotion = (skill_num && skill_get_inf(skill_num)&INF_GROUND_SKILL)?0:sstatus->amotion; //Amotion should be 0 for ground skills.
- if( skill_num == KN_AUTOCOUNTER )
- wd.amotion >>= 1;
- wd.dmotion = tstatus->dmotion;
- wd.blewcount = skill_get_blewcount(skill_num,skill_lv);
- wd.flag = BF_WEAPON; //Initial Flag
- wd.flag |= (skill_num||wflag)?BF_SKILL:BF_NORMAL; // Baphomet card's splash damage is counted as a skill. [Inkfish]
- wd.dmg_lv = ATK_DEF; //This assumption simplifies the assignation later
- nk = skill_get_nk(skill_num);
- if( !skill_num && wflag ) //If flag, this is splash damage from Baphomet Card and it always hits.
- nk |= NK_NO_CARDFIX_ATK|NK_IGNORE_FLEE;
- flag.hit = nk&NK_IGNORE_FLEE?1:0;
- flag.idef = flag.idef2 = nk&NK_IGNORE_DEF?1:0;
- if (sc && !sc->count)
- sc = NULL; //Skip checking as there are no status changes active.
- if (tsc && !tsc->count)
- tsc = NULL; //Skip checking as there are no status changes active.
- sd = BL_CAST(BL_PC, src);
- tsd = BL_CAST(BL_PC, target);
- // Minstrel/Wanderer number check for chorus skills.
- // Bonus remains 0 unless 3 or more Minstrel's/Wanderer's are in the party.
- if( sd && sd->status.party_id && party_foreachsamemap(party_sub_count_chorus, sd, 0) > 7)
- chorusbonus = 5;//Maximum effect possiable from 7 or more Minstrel's/Wanderer's
- else if( sd && sd->status.party_id && party_foreachsamemap(party_sub_count_chorus, sd, 0) > 2)
- chorusbonus = party_foreachsamemap(party_sub_count_chorus, sd, 0) - 2;//Effect bonus from additional Minstrel's/Wanderer's if not above the max possiable.
- if(sd)
- wd.blewcount += battle_blewcount_bonus(sd, skill_num);
- //Set miscellaneous data that needs be filled regardless of hit/miss
- if(
- (sd && sd->state.arrow_atk) ||
- (!sd && ((skill_num && skill_get_ammotype(skill_num)) || sstatus->rhw.range>3))
- )
- flag.arrow = 1;
- if(skill_num){
- wd.flag |= battle_range_type(src, target, skill_num, skill_lv);
- switch(skill_num)
- {
- case MO_FINGEROFFENSIVE:
- if(sd) {
- if (battle_config.finger_offensive_type)
- wd.div_ = 1;
- else
- wd.div_ = sd->spiritball_old;
- }
- break;
- case HT_PHANTASMIC:
- //Since these do not consume ammo, they need to be explicitly set as arrow attacks.
- flag.arrow = 1;
- break;
- case CR_SHIELDBOOMERANG:
- case PA_SHIELDCHAIN:
- case LG_SHIELDPRESS:
- case LG_EARTHDRIVE:
- flag.weapon = 0;
- break;
- case KN_PIERCE:
- case ML_PIERCE:
- wd.div_= (wd.div_>0?tstatus->size+1:-(tstatus->size+1));
- break;
- case TF_DOUBLE: //For NPC used skill.
- case GS_CHAINACTION:
- wd.type = 0x08;
- break;
- case GS_GROUNDDRIFT:
- case KN_SPEARSTAB:
- case KN_BOWLINGBASH:
- case MS_BOWLINGBASH:
- case MO_BALKYOUNG:
- case TK_TURNKICK:
- wd.blewcount=0;
- break;
- case KN_AUTOCOUNTER:
- wd.flag=(wd.flag&~BF_SKILLMASK)|BF_NORMAL;
- break;
- case NPC_CRITICALSLASH:
- case LG_PINPOINTATTACK:
- flag.cri = 1; //Always critical skill.
- break;
- case LK_SPIRALPIERCE:
- if (!sd) wd.flag=(wd.flag&~(BF_RANGEMASK|BF_WEAPONMASK))|BF_LONG|BF_MISC;
- break;
- case EL_STONE_RAIN:
- if( !(wflag&1) )
- wd.div_ = 1;
- break;
- }
- } else //Range for normal attacks.
- wd.flag |= flag.arrow?BF_LONG:BF_SHORT;
- if ( (!skill_num || skill_num == PA_SACRIFICE) && tstatus->flee2 && rand()%1000 < tstatus->flee2 )
- { //Check for Lucky Dodge
- wd.type=0x0b;
- wd.dmg_lv=ATK_LUCKY;
- if (wd.div_ < 0) wd.div_*=-1;
- return wd;
- }
- t_class = status_get_class(target);
- s_ele = s_ele_ = skill_get_ele(skill_num, skill_lv);
- if( !skill_num || s_ele == -1 )
- { //Take weapon's element
- s_ele = sstatus->rhw.ele;
- s_ele_ = sstatus->lhw.ele;
- if( flag.arrow && sd && sd->arrow_ele )
- s_ele = sd->arrow_ele;
- if( battle_config.attack_attr_none&src->type )
- n_ele = true; //Weapon's element is "not elemental"
- }
- else if( s_ele == -2 ) //Use enchantment's element
- s_ele = s_ele_ = status_get_attack_sc_element(src,sc);
- else if( s_ele == -3 ) //Use random element
- s_ele = s_ele_ = rand()%ELE_MAX;
- switch( skill_num )
- {
- case GS_GROUNDDRIFT:
- s_ele = s_ele_ = wflag; //element comes in flag.
- break;
- case LK_SPIRALPIERCE:
- if (!sd) n_ele = false; //forced neutral for monsters
- break;
- }
- if(!skill_num)
- { //Skills ALWAYS use ONLY your right-hand weapon (tested on Aegis 10.2)
- if (sd && sd->weapontype1 == 0 && sd->weapontype2 > 0)
- {
- flag.rh=0;
- flag.lh=1;
- }
- if (sstatus->lhw.atk)
- flag.lh=1;
- }
- if( sd && !skill_num )
- { //Check for double attack.
- if( ( ( skill_lv = pc_checkskill(sd,TF_DOUBLE) ) > 0 && sd->weapontype1 == W_DAGGER )
- || ( sd->double_rate > 0 && sd->weapontype1 != W_FIST ) ) //Will fail bare-handed
- { //Success chance is not added, the higher one is used [Skotlex]
- if( rand()%100 < ( 5*skill_lv > sd->double_rate ? 5*skill_lv : sd->double_rate ) )
- {
- wd.div_ = skill_get_num(TF_DOUBLE,skill_lv?skill_lv:1);
- wd.type = 0x08;
- }
- }
- else if( sd->weapontype1 == W_REVOLVER && (skill_lv = pc_checkskill(sd,GS_CHAINACTION)) > 0 && rand()%100 < 5*skill_lv )
- {
- wd.div_ = skill_get_num(GS_CHAINACTION,skill_lv);
- wd.type = 0x08;
- }
- else if( sc && sc->data[SC_FEARBREEZE] && sd->weapontype1 == W_BOW && (i = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[i] && sd->status.inventory[i].amount > 1 )
- {
- short rate[] = { 12, 12, 21, 27, 30 };
- if( sc->data[SC_FEARBREEZE]->val1 > 0 && sc->data[SC_FEARBREEZE]->val1 < 6 && rand()%100 < rate[sc->data[SC_FEARBREEZE]->val1 - 1] )
- {
- wd.type = 0x08;
- wd.div_ = 2 + (sc->data[SC_FEARBREEZE]->val1 > 2 ? rand()%(sc->data[SC_FEARBREEZE]->val1 - 2) : 0);
- wd.div_ = min(wd.div_,sd->status.inventory[i].amount); // Reduce number of hits if you don't have enough arrows
- sd->state.fearbreeze = wd.div_ - 1;
- }
- }
- }
- //Check for critical
- if( !flag.cri && !(wd.type&0x08) && sstatus->cri &&
- (!skill_num ||
- skill_num == KN_AUTOCOUNTER ||
- skill_num == SN_SHARPSHOOTING || skill_num == MA_SHARPSHOOTING ||
- skill_num == NJ_KIRIKAGE))
- {
- short cri = sstatus->cri;
- if (sd)
- {
- cri+= sd->critaddrace[tstatus->race];
- if(flag.arrow)
- cri += sd->arrow_cri;
- if(sd->status.weapon == W_KATAR)
- cri <<=1;
- }
- //The official equation is *2, but that only applies when sd's do critical.
- //Therefore, we use the old value 3 on cases when an sd gets attacked by a mob
- cri -= tstatus->luk*(!sd&&tsd?3:2);
- if(tsc)
- {
- if (tsc->data[SC_SLEEP])
- cri <<=1;
- }
- switch (skill_num)
- {
- case KN_AUTOCOUNTER:
- if(battle_config.auto_counter_type &&
- (battle_config.auto_counter_type&src->type))
- flag.cri = 1;
- else
- cri <<= 1;
- break;
- case SN_SHARPSHOOTING:
- case MA_SHARPSHOOTING:
- cri += 200;
- break;
- case NJ_KIRIKAGE:
- cri += 250 + 50*skill_lv;
- break;
- }
- if(tsd && tsd->critical_def)
- cri = cri*(100-tsd->critical_def)/100;
- if (rand()%1000 < cri) // Steel need confirm if critical def reduce it.
- flag.cri= 1;
- }
- if (flag.cri)
- {
- wd.type = 0x0a;
- flag.idef = flag.idef2 = flag.hit = 1;
- } else { //Check for Perfect Hit
- if(sd && sd->perfect_hit > 0 && rand()%100 < sd->perfect_hit)
- flag.hit = 1;
- if (sc && sc->data[SC_FUSION]) {
- flag.hit = 1; //SG_FUSION always hit [Komurka]
- flag.idef = flag.idef2 = 1; //def ignore [Komurka]
- }
- if( !flag.hit )
- switch(skill_num)
- {
- case AS_SPLASHER:
- if( !wflag ) // Always hits the one exploding.
- flag.hit = 1;
- break;
- case CR_SHIELDBOOMERANG:
- if( sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_CRUSADER )
- flag.hit = 1;
- break;
- }
- if (tsc && !flag.hit && tsc->opt1 && tsc->opt1 != OPT1_STONEWAIT)
- flag.hit = 1;
- }
- if (!flag.hit)
- { //Hit/Flee calculation
- short flee = tstatus->flee, hitrate=80; //Default hitrate
- if( tsc && tsc->data[SC_NEUTRALBARRIER] && (wd.flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT )
- hitrate = 5; // Currently Neutral Barrier just do this
- else
- {
- 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,battle_config.agi_penalty_count_lv);
- if(attacker_count >= battle_config.agi_penalty_count)
- {
- 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;
- }
- }
- hitrate+= sstatus->hit - flee;
- if(wd.flag&BF_LONG && !skill_num && //Fogwall's hit penalty is only for normal ranged attacks.
- tsc && tsc->data[SC_FOGWALL])
- hitrate -= 50;
- if(sd && flag.arrow)
- hitrate += sd->arrow_hit;
- if(skill_num)
- switch(skill_num)
- { //Hit skill modifiers
- //It is proven that bonus is applied on final hitrate, not hit.
- case SM_BASH:
- case MS_BASH:
- hitrate += hitrate * 5 * skill_lv / 100;
- break;
- case MS_MAGNUM:
- case SM_MAGNUM:
- hitrate += hitrate * 10 * skill_lv / 100;
- break;
- case KN_AUTOCOUNTER:
- case PA_SHIELDCHAIN:
- case NPC_WATERATTACK:
- case NPC_GROUNDATTACK:
- case NPC_FIREATTACK:
- case NPC_WINDATTACK:
- case NPC_POISONATTACK:
- case NPC_HOLYATTACK:
- case NPC_DARKNESSATTACK:
- case NPC_UNDEADATTACK:
- case NPC_TELEKINESISATTACK:
- case NPC_BLEEDING:
- hitrate += hitrate * 20 / 100;
- break;
- case KN_PIERCE:
- case ML_PIERCE:
- hitrate += hitrate * 5 * skill_lv / 100;
- break;
- case AS_SONICBLOW:
- if( sd && pc_checkskill(sd,AS_SONICACCEL) > 0 )
- hitrate += hitrate * 50 / 100;
- break;
- case MC_CARTREVOLUTION:
- case GN_CART_TORNADO:
- case GN_CARTCANNON:
- if( sd && pc_checkskill(sd, GN_REMODELING_CART) )
- hitrate += pc_checkskill(sd, GN_REMODELING_CART) * 4;
- break;
- case GC_VENOMPRESSURE:
- hitrate += 10 + 4 * skill_lv;
- break;
- case SC_FATALMENACE:
- hitrate -= (35 - skill_lv * 5);
- break;
- case LG_BANISHINGPOINT:
- hitrate += 3 * skill_lv;
- break;
- }
- // Weaponry Research hidden bonus
- if (sd && (skill = pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0)
- hitrate += hitrate * ( 2 * skill ) / 100;
- if( sd && (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DAGGER) &&
- (skill = pc_checkskill(sd, GN_TRAINING_SWORD))>0 )
- hitrate += 3 * skill;
- }
- hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate);
- if(rand()%100 >= hitrate)
- wd.dmg_lv = ATK_FLEE;
- else
- flag.hit = 1;
- } //End hit/miss calculation
- if (flag.hit && !flag.infdef) //No need to do the math for plants
- { //Hitting attack
- //Assuming that 99% of the cases we will not need to check for the flag.rh... we don't.
- //ATK_RATE scales the damage. 100 = no change. 50 is halved, 200 is doubled, etc
- #define ATK_RATE( a ) { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(a)/100; }
- #define ATK_RATE2( a , b ) { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(b)/100; }
- //Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage
- #define ATK_ADDRATE( a ) { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(a)/100; }
- #define ATK_ADDRATE2( a , b ) { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(b)/100; }
- //Adds an absolute value to damage. 100 = +100 damage
- #define ATK_ADD( a ) { wd.damage+= a; if (flag.lh) wd.damage2+= a; }
- #define ATK_ADD2( a , b ) { wd.damage+= a; if (flag.lh) wd.damage2+= b; }
- switch (skill_num)
- { //Calc base damage according to skill
- // Below renewal multi hit Final Strike , MyRO
- case NJ_ISSEN:
- wd.div_ = 1;
- if (sc && sc->data[SC_BUNSINJYUTSU] && sc->data[SC_BUNSINJYUTSU]->val2>0)
- wd.div_ = (sc->data[SC_BUNSINJYUTSU]->val2)+2;
- //[(ATK*40) + (HP*80%)] * (1+(0.25*Mirror illusion))
- //wd.damage = 40*sstatus->batk +(skill_lv*8/100)*sstatus->hp;
- wd.damage = 40*sstatus->batk +skill_lv*(sstatus->hp/10 + 35);
- if(wd.div_!=1)
- wd.damage = wd.damage *(1+sc->data[SC_BUNSINJYUTSU]->val2*25/100);
- wd.damage = (wd.damage/wd.div_)/2;
- // wd.damage = wd.damage/wd.div_;
- wd.damage2 = 0;
- status_set_hp(src, sstatus->max_hp/100, 0);
- break;
- case PA_SACRIFICE:
- wd.damage = sstatus->max_hp* 9/100;
- wd.damage2 = 0;
- break;
- // below edited for MyRO (below orig)
- //case LK_SPIRALPIERCE:
- //case ML_SPIRALPIERCE:
- // if (sd) {
- // short index = sd->equip_index[EQI_HAND_R];
- // if (index >= 0 &&
- // sd->inventory_data[index] &&
- // sd->inventory_data[index]->type == IT_WEAPON)
- // wd.damage = sd->inventory_data[index]->weight*8/100; //80% of weight
- // } else
- // wd.damage = sstatus->rhw.atk2*8/10; //Else use Atk2
- // ATK_ADDRATE(50*skill_lv); //Skill modifier applies to weight only.
- // i = sstatus->str/10;
- // i*=i;
- // ATK_ADD(i); //Add str bonus.
- // if( sc && sc->data[SC_GLOOMYDAY_SK] && skill_num == LK_SPIRALPIERCE )
- // ATK_ADD(50 + 5 * sc->data[SC_GLOOMYDAY_SK]->val1);
- // switch (tstatus->size) { //Size-fix. Is this modified by weapon perfection?
- // case 0: //Small: 125%
- // ATK_RATE(125);
- // break;
- // //case 1: //Medium: 100%
- // case 2: //Large: 75%
- // ATK_RATE(75);
- // break;
- // }
- // break;
- // new spiral pierce formula below (MyRO) (based on wieght) (May 30, 2011)
- case LK_SPIRALPIERCE:
- case ML_SPIRALPIERCE:
- wd.damage = sstatus->batk;
- if (sd) {
- short index = sd->equip_index[EQI_HAND_R];
- if (index >= 0 &&
- sd->inventory_data[index] &&
- sd->inventory_data[index]->type == IT_WEAPON)
- ATK_ADD(sd->inventory_data[index]->weight*5/100*skill_lv); //50% of weight * skill level [ADVENT]
- /*wd.damage = sd->inventory_data[index]->weight*8/100; //80% of weight*/
- } else
- /*wd.damage = sstatus->rhw.atk2*8/10; //Else use Atk2*/
- ATK_ADD((sstatus->rhw.atk2*5/10)*skill_lv);
- skillratio += (150+(40*skill_lv));
- if( sc && sc->data[SC_GLOOMYDAY_SK] && skill_num == LK_SPIRALPIERCE )
- ATK_ADDRATE(100+25*(sc->data[SC_GLOOMYDAY_SK]->val1-1));
- //wd.damage = wd.damage*(2 + (sc->data[SC_GLOOMYDAY_SK]->val1-(sc->data[SC_GLOOMYDAY_SK]->val1-1)));
- //ATK_ADD(50 + 5 * sc->data[SC_GLOOMYDAY_SK]->val1);
- switch (tstatus->size) { //Size-fix. Is this modified by weapon perfection?
- case 0: //Small: 125%
- ATK_RATE(125);
- break;
- //case 1: //Medium: 100%
- case 2: //Large: 75%
- ATK_RATE(75);
- break;
- }
- break;
- case CR_SHIELDBOOMERANG:
- case PA_SHIELDCHAIN:
- wd.damage = sstatus->batk;
- if( sd )
- {
- int damagevalue = 0;
- short index = sd->equip_index[EQI_HAND_L];
- if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR )
- damagevalue = sd->inventory_data[index]->weight/10;
- if( sc && sc->data[SC_GLOOMYDAY_SK] )
- damagevalue += damagevalue * (15 + rand()%sc->data[SC_GLOOMYDAY_SK]->val3) / 100;
- ATK_ADD(damagevalue);
- }
- else
- ATK_ADD(sstatus->rhw.atk2); //Else use Atk2
- break;
- case HFLI_SBR44: //[orn]
- if(src->type == BL_HOM) {
- wd.damage = ((TBL_HOM*)src)->homunculus.intimacy ;
- break;
- }
- default:
- {
- i = (flag.cri?1:0)|
- (flag.arrow?2:0)|
- (skill_num == HW_MAGICCRASHER?4:0)|
- (!skill_num && sc && sc->data[SC_CHANGE]?4:0)|
- (skill_num == MO_EXTREMITYFIST?8:0)|
- (sc && sc->data[SC_WEAPONPERFECTION]?8:0);
- if (flag.arrow && sd)
- switch(sd->status.weapon) {
- case W_BOW:
- case W_REVOLVER:
- case W_GATLING:
- case W_SHOTGUN:
- case W_GRENADE:
- break;
- default:
- i |= 16; // for ex. shuriken must not be influenced by DEX
- }
- wd.damage = battle_calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, i);
- if (flag.lh)
- wd.damage2 = battle_calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, sd, i);
- if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets
- if(wflag>0)
- wd.damage/= wflag;
- else
- ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_num, skill_get_name(skill_num));
- }
- //Add any bonuses that modify the base baseatk+watk (pre-skills)
- if( sd )
- {
- if( sd->atk_rate )
- ATK_ADDRATE(sd->atk_rate);
- if(flag.cri && sd->crit_atk_rate)
- ATK_ADDRATE(sd->crit_atk_rate);
- if( sd->status.party_id && (skill=pc_checkskill(sd,TK_POWER)) > 0 )
- {
- if( (i = party_foreachsamemap(party_sub_count, sd, 0)) > 1 ) // exclude the player himself [Inkfish]
- ATK_ADDRATE(2*skill*i);
- }
- }
- break;
- } //End default case
- } //End switch(skill_num)
- //Skill damage modifiers that stack linearly
- if(sc && skill_num != PA_SACRIFICE)
- {
- if(sc->data[SC_OVERTHRUST])
- skillratio += sc->data[SC_OVERTHRUST]->val3;
- if(sc->data[SC_MAXOVERTHRUST])
- skillratio += sc->data[SC_MAXOVERTHRUST]->val2;
- if(sc->data[SC_BERSERK])
- skillratio += 100;
- }
- if( !skill_num )
- { // Random chance to deal multiplied damage - Consider it as part of skill-based-damage
- if( sd && sd->random_attack_increase_add > 0 && sd->random_attack_increase_per && rand()%100 < sd->random_attack_increase_per )
- skillratio += sd->random_attack_increase_add;
- ATK_RATE(skillratio);
- }
- else
- {
- switch( skill_num )
- {
- case SM_BASH:
- case MS_BASH:
- skillratio += 30*skill_lv;
- break;
- case SM_MAGNUM:
- case MS_MAGNUM:
- skillratio += 20*skill_lv;
- break;
- case MC_MAMMONITE:
- skillratio += 50*skill_lv;
- break;
- case HT_POWER:
- skillratio += -50+8*sstatus->str;
- break;
- case AC_DOUBLE:
- case MA_DOUBLE:
- skillratio += 10*(skill_lv-1);
- break;
- case AC_SHOWER:
- case MA_SHOWER:
- skillratio += 5*skill_lv-25;
- break;
- case AC_CHARGEARROW:
- case MA_CHARGEARROW:
- skillratio += 50;
- break;
- case HT_FREEZINGTRAP:
- case MA_FREEZINGTRAP:
- skillratio += -50+10*skill_lv;
- break;
- case KN_PIERCE:
- case ML_PIERCE:
- skillratio += 10*skill_lv;
- break;
- case MER_CRASH:
- skillratio += 10*skill_lv;
- break;
- case KN_SPEARSTAB:
- skillratio += 15*skill_lv;
- break;
- case KN_SPEARBOOMERANG:
- skillratio += 50*skill_lv;
- break;
- case KN_BRANDISHSPEAR:
- case ML_BRANDISH:
- {
- int ratio = 100+20*skill_lv;
- skillratio += ratio-100;
- if(skill_lv>3 && wflag==1) skillratio += ratio/2;
- if(skill_lv>6 && wflag==1) skillratio += ratio/4;
- if(skill_lv>9 && wflag==1) skillratio += ratio/8;
- if(skill_lv>6 && wflag==2) skillratio += ratio/2;
- if(skill_lv>9 && wflag==2) skillratio += ratio/4;
- if(skill_lv>9 && wflag==3) skillratio += ratio/2;
- if( sc && sc->data[SC_GLOOMYDAY_SK] )
- skillratio += skillratio * (15 + rand()%sc->data[SC_GLOOMYDAY_SK]->val3) / 100;
- break;
- }
- case KN_BOWLINGBASH:
- case MS_BOWLINGBASH:
- skillratio+= 40*skill_lv;
- break;
- case AS_GRIMTOOTH:
- skillratio += 20*skill_lv;
- break;
- case AS_POISONREACT:
- skillratio += 30*skill_lv;
- break;
- case AS_SONICBLOW:
- skillratio += -50+5*skill_lv;
- break;
- case TF_SPRINKLESAND:
- skillratio += 30;
- break;
- case MC_CARTREVOLUTION:
- skillratio += 50;
- if(sd && sd->cart_weight)
- skillratio += 100*sd->cart_weight/battle_config.max_cart_weight; // +1% every 1% weight
- else if (!sd)
- skillratio += 100; //Max damage for non players.
- break;
- case NPC_RANDOMATTACK:
- skillratio += 100 * skill_lv;
- break;
- case NPC_WATERATTACK:
- case NPC_GROUNDATTACK:
- case NPC_FIREATTACK:
- case NPC_WINDATTACK:
- case NPC_POISONATTACK:
- case NPC_HOLYATTACK:
- case NPC_DARKNESSATTACK:
- case NPC_UNDEADATTACK:
- case NPC_TELEKINESISATTACK:
- case NPC_BLOODDRAIN:
- case NPC_ACIDBREATH:
- case NPC_DARKNESSBREATH:
- case NPC_FIREBREATH:
- case NPC_ICEBREATH:
- case NPC_THUNDERBREATH:
- case NPC_HELLJUDGEMENT:
- case NPC_PULSESTRIKE:
- skillratio += 100*(skill_lv-1);
- break;
- case RG_BACKSTAP:
- if(sd && sd->status.weapon == W_BOW && battle_config.backstab_bow_penalty)
- skillratio += (200+40*skill_lv)/2;
- else
- skillratio += 200+40*skill_lv;
- break;
- case RG_RAID:
- skillratio += 40*skill_lv;
- break;
- case RG_INTIMIDATE:
- skillratio += 30*skill_lv;
- break;
- case CR_SHIELDCHARGE:
- skillratio += 20*skill_lv;
- if( sc && sc->data[SC_GLOOMYDAY_SK] )
- skillratio += skillratio * (15 + rand()%sc->data[SC_GLOOMYDAY_SK]->val3) / 100;
- break;
- case CR_SHIELDBOOMERANG:
- skillratio += 30*skill_lv;
- if( sc && sc->data[SC_GLOOMYDAY_SK] )
- skillratio += skillratio * (15 + rand()%sc->data[SC_GLOOMYDAY_SK]->val3) / 100;
- break;
- case NPC_DARKCROSS:
- case CR_HOLYCROSS:
- skillratio += 35*skill_lv;
- break;
- case AM_DEMONSTRATION:
- skillratio += 20*skill_lv;
- break;
- case AM_ACIDTERROR:
- skillratio += 40*skill_lv;
- break;
- case MO_FINGEROFFENSIVE:
- skillratio+= 50 * skill_lv;
- break;
- case MO_INVESTIGATE:
- skillratio += 75*skill_lv;
- flag.pdef = flag.pdef2 = 2;
- break;
- case MO_EXTREMITYFIST:
- { //Overflow check. [Skotlex]
- unsigned int ratio = skillratio + 100*(8 + sstatus->sp/10);
- //You'd need something like 6K SP to reach this max, so should be fine for most purposes.
- if (ratio > 60000) ratio = 60000; //We leave some room here in case skillratio gets further increased.
- skillratio = (unsigned short)ratio;
- status_set_sp(src, 0, 0);
- }
- break;
- case MO_TRIPLEATTACK:
- skillratio += 20*skill_lv;
- break;
- case MO_CHAINCOMBO:
- skillratio += 50+50*skill_lv;
- break;
- case MO_COMBOFINISH:
- skillratio += 140+60*skill_lv;
- break;
- case BA_MUSICALSTRIKE:
- case DC_THROWARROW:
- skillratio += 25+25*skill_lv;
- break;
- case CH_TIGERFIST:
- skillratio += 100*skill_lv-60;
- break;
- case CH_CHAINCRUSH:
- skillratio += 300+100*skill_lv;
- break;
- case CH_PALMSTRIKE:
- skillratio += 100+100*skill_lv;
- break;
- case LK_HEADCRUSH:
- skillratio += 40*skill_lv;
- break;
- case LK_JOINTBEAT:
- i = 10*skill_lv-50;
- // Although not clear, it's being assumed that the 2x damage is only for the break neck ailment.
- if (wflag&BREAK_NECK) i*=2;
- skillratio += i;
- break;
- case ASC_METEORASSAULT:
- skillratio += 40*skill_lv-60;
- break;
- case SN_SHARPSHOOTING:
- case MA_SHARPSHOOTING:
- skillratio += 100 + 50 * skill_lv;
- break;
- case CG_ARROWVULCAN:
- skillratio += 100+100*skill_lv;
- break;
- case AS_SPLASHER:
- skillratio += 400+50*skill_lv;
- if(sd)
- skillratio += 30 * pc_checkskill(sd,AS_POISONREACT);
- break;
- case ASC_BREAKER:
- skillratio += 100*skill_lv-100;
- break;
- case PA_SACRIFICE:
- skillratio += 10*skill_lv-10;
- break;
- case PA_SHIELDCHAIN:
- skillratio += 30*skill_lv;
- if( sc && sc->data[SC_GLOOMYDAY_SK] )
- skillratio += skillratio * (15 + rand()%sc->data[SC_GLOOMYDAY_SK]->val3) / 100;
- break;
- case WS_CARTTERMINATION:
- i = 12 * (16 - skill_lv);
- if (i < 1) i = 1;
- //Preserve damage ratio when max cart weight is changed.
- if(sd && sd->cart_weight)
- skillratio += sd->cart_weight/i * 80000/battle_config.max_cart_weight - 100;
- else if (!sd)
- skillratio += 80000 / i - 100;
- break;
- case TK_DOWNKICK:
- skillratio += 60 + 20*skill_lv;
- break;
- case TK_STORMKICK:
- skillratio += 60 + 20*skill_lv;
- break;
- case TK_TURNKICK:
- skillratio += 90 + 30*skill_lv;
- break;
- case TK_COUNTER:
- skillratio += 90 + 30*skill_lv;
- break;
- case TK_JUMPKICK:
- skillratio += -70 + 10*skill_lv;
- if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_num)
- skillratio += 10*s_level/3; //Tumble bonus
- if (wflag)
- {
- skillratio += 10*s_level/3; //Running bonus (TODO: What is the real bonus?
Advertisement
Add Comment
Please, Sign In to add comment