summaryrefslogtreecommitdiff
path: root/src/map/battle.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/battle.c')
-rw-r--r--src/map/battle.c168
1 files changed, 110 insertions, 58 deletions
diff --git a/src/map/battle.c b/src/map/battle.c
index 945d52c64..544d53a1c 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -252,12 +252,16 @@ int battle_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) {
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] && damage > 0 && skill_id != PA_PRESSURE && skill_id != CR_REFLECTSHIELD )
+ if (sc && sc->data[SC_DEVOTION] && sc->data[SC_DEVOTION]->val1)
+ d_tbl = map->id2bl(sc->data[SC_DEVOTION]->val1);
+
+ if( d_tbl && 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 ) {
@@ -279,7 +283,7 @@ int battle_delay_damage(int64 tick, int amotion, struct block_list *src, struct
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.
+ 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)
@@ -500,8 +504,13 @@ int64 battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, u
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, batk;
struct status_data *st = status->get_status_data(src);
-
- batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->calc_batk(bl, status->get_sc(src), st->batk, false), nk, n_ele, ELE_NEUTRAL, ELE_NEUTRAL, false, flag);
+ struct status_change *sc = status->get_sc(src);
+
+ // 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;
@@ -771,18 +780,18 @@ int64 battle_calc_masteryfix(struct block_list *src, struct block_list *target,
if(sc->data[SC_IMPOSITIO])
damage += sc->data[SC_IMPOSITIO]->val2;
if(sc->data[SC_DRUMBATTLE]){
- if(tstatus->size == SZ_MEDIUM)
+ if(tstatus->size == SZ_SMALL)
damage += sc->data[SC_DRUMBATTLE]->val2;
- else if(tstatus->size == SZ_SMALL)
+ 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_MEDIUM)
+ if(tstatus->size == SZ_SMALL)
damage += 10 * sc->data[SC_GS_GATLINGFEVER]->val1;
- else if(tstatus->size == SZ_SMALL)
+ else if(tstatus->size == SZ_MEDIUM)
damage += -5 * sc->data[SC_GS_GATLINGFEVER]->val1;
else
damage += sc->data[SC_GS_GATLINGFEVER]->val1;
@@ -2197,17 +2206,17 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block
break;
case NC_VULCANARM:
skillratio = 70 * skill_lv + status_get_dex(src);
- RE_LVL_DMOD(100);
+ RE_LVL_DMOD(120);
break;
case NC_FLAMELAUNCHER:
case NC_COLDSLOWER:
- skillratio += 200 + 100 * skill_lv + status_get_str(src);
- RE_LVL_DMOD(100);
+ skillratio += 200 + 300 * skill_lv;
+ RE_LVL_DMOD(150);
break;
case NC_ARMSCANNON:
switch( tst->size ) {
- case SZ_MEDIUM: skillratio = 300 + 350 * skill_lv; break; // Medium
- case SZ_SMALL: skillratio = 300 + 400 * skill_lv; break; // Small
+ case SZ_SMALL: skillratio = 300 + 350 * skill_lv; break; // Medium
+ case SZ_MEDIUM: skillratio = 300 + 400 * skill_lv; break; // Small
case SZ_BIG: skillratio = 300 + 300 * skill_lv; break; // Large
}
RE_LVL_DMOD(120);
@@ -2233,13 +2242,16 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block
skillratio = skillratio * 75 / 100;
break;
case SC_FATALMENACE:
- skillratio = 100 * (skill_lv+1) * status->get_lv(src) / 100;
+ skillratio = 100 * (skill_lv+1);
+ RE_LVL_DMOD(100);
break;
case SC_TRIANGLESHOT:
- skillratio = ( 300 + (skill_lv-1) * status_get_agi(src)/2 ) * status->get_lv(src) / 120;
+ skillratio = ( 300 + (skill_lv-1) * status_get_agi(src)/2 );
+ RE_LVL_DMOD(120);
break;
case SC_FEINTBOMB:
- skillratio = (skill_lv+1) * (st->dex/2) * (sd?sd->status.job_level:50)/10 * status->get_lv(src) / 120;
+ skillratio = (skill_lv+1) * (st->dex/2) * (sd?sd->status.job_level:50)/10;
+ RE_LVL_DMOD(120);
break;
case LG_CANNONSPEAR:
skillratio = (50 + st->str) * skill_lv;
@@ -2283,15 +2295,15 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block
RE_LVL_DMOD(100);
break;
case LG_OVERBRAND:
- skillratio += -100 + 50 * (((sd) ? pc->checkskill(sd,CR_SPEARQUICKEN) : 1) + 8 * skill_lv);
- RE_LVL_DMOD(150);
+ skillratio += -100 + 400 * skill_lv + 50 * ((sd) ? pc->checkskill(sd,CR_SPEARQUICKEN) : 1);
+ RE_LVL_DMOD(100);
break;
case LG_OVERBRAND_BRANDISH:
skillratio += -100 + 300 * skill_lv + status_get_str(src) + status_get_dex(src);
- RE_LVL_DMOD(150);
+ RE_LVL_DMOD(100);
break;
case LG_OVERBRAND_PLUSATK:
- skillratio += -100 + 100 * skill_lv;
+ skillratio = 200 * skill_lv + rnd_value( 10, 100);
RE_LVL_DMOD(100);
break;
case LG_RAYOFGENESIS:
@@ -2307,7 +2319,14 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block
RE_LVL_DMOD(100);
break;
case LG_HESPERUSLIT:
- skillratio += 120 * skill_lv - 100;
+ skillratio = 120 * skill_lv;
+ if( sc && sc->data[SC_BANDING] )
+ skillratio += 200 * sc->data[SC_BANDING]->val2;
+ if( sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 5 )
+ skillratio = skillratio * 150 / 100;
+ if( sc && sc->data[SC_INSPIRATION] )
+ skillratio += 600;
+ RE_LVL_DMOD(100);
break;
case SR_DRAGONCOMBO:
skillratio += 40 * skill_lv;
@@ -2692,22 +2711,11 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
d->dmg_lv = ATK_BLOCK;
return 0;
}
- if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill->get_nk(skill_id)&NK_NO_CARDFIX_ATK) && rnd()%100 < sce->val2 )
- {
+ if ((sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill->get_nk(skill_id)&NK_NO_CARDFIX_ATK) && rnd()%100 < sce->val2) {
int delay;
- struct block_list *d_bl;
- struct status_change_entry *sce_d;
- bool devoted = false;
-
- if ((sce_d = sc->data[SC_DEVOTION]) && (d_bl = map->id2bl(sce_d->val1)) &&
- ((d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == bl->id) || //
- (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce_d->val2] == bl->id))) {
- // if player is target of devotion, show guard effect on the devotion caster rather than the target
- devoted = true;
- clif->skill_nodamage(d_bl, d_bl, CR_AUTOGUARD, sce->val1, 1);
- } else
- clif->skill_nodamage(bl, bl, CR_AUTOGUARD,sce->val1, 1);
-
+ struct block_list *d_bl = NULL;
+ struct status_change_entry *sce_d = sc->data[SC_DEVOTION];
+
// different delay depending on skill level [celest]
if (sce->val1 <= 5)
delay = 300;
@@ -2716,12 +2724,30 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
else
delay = 100;
- unit->set_walkdelay((devoted ? d_bl : bl), timer->gettick(), delay, 1);
+ if (sce_d) {
+ // If the target is too far away from the devotion caster, autoguard has no effect
+ // Autoguard will be disabled later on
+ if ((d_bl = map->id2bl(sce_d->val1)) && check_distance_bl(bl, d_bl, sce_d->val3)
+ && ((d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == bl->id)
+ || (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce_d->val2] == bl->id))
+ ) {
+ // if player is target of devotion, show guard effect on the devotion caster rather than the target
+ clif->skill_nodamage(d_bl, d_bl, CR_AUTOGUARD, sce->val1, 1);
+ unit->set_walkdelay(d_bl, timer->gettick(), delay, 1);
- if(sc->data[SC_CR_SHRINK] && rnd()%100<5*sce->val1)
- skill->blown(bl,src,skill->get_blewcount(CR_SHRINK,1),-1,0);
- d->dmg_lv = ATK_MISS;
- return 0;
+ d->dmg_lv = ATK_MISS;
+ return 0;
+ }
+ } else {
+ clif->skill_nodamage(bl, bl, CR_AUTOGUARD, sce->val1, 1);
+ unit->set_walkdelay(bl, timer->gettick(), delay, 1);
+
+ if(sc->data[SC_CR_SHRINK] && rnd()%100<5*sce->val1)
+ skill->blown(bl,src,skill->get_blewcount(CR_SHRINK,1),-1,0);
+
+ d->dmg_lv = ATK_MISS;
+ return 0;
+ }
}
if( (sce = sc->data[SC_MILLENNIUMSHIELD]) && sce->val2 > 0 && damage > 0 ) {
@@ -2798,7 +2824,11 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
}
//Now damage increasing effects
- if( sc->data[SC_LEXAETERNA] && skill_id != PF_SOULBURN )
+ if( sc->data[SC_LEXAETERNA] && skill_id != PF_SOULBURN
+#ifdef RENEWAL
+ && skill_id != CR_ACIDDEMONSTRATION && skill_id != ASC_BREAKER
+#endif
+ )
{
if( src->type != BL_MER || skill_id == 0 )
damage <<= 1; // Lex Aeterna only doubles damage of regular attacks from mercenaries
@@ -3763,6 +3793,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
md.damage >>= 1;
}
md.damage -= totaldef;
+ if( tsc && tsc->data[SC_LEXAETERNA] ) {
+ md.damage <<= 1;
+ status_change_end(target, SC_LEXAETERNA, INVALID_TIMER);
+ }
}
#else
// updated the formula based on a Japanese formula found to be exact [Reddozen]
@@ -3817,6 +3851,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
ratio >>= 1;
md.damage = (matk + atk) * ratio / 100;
md.damage -= totaldef;
+ if( tsc && tsc->data[SC_LEXAETERNA] ) {
+ md.damage <<= 1;
+ status_change_end(target, SC_LEXAETERNA, INVALID_TIMER);
+ }
#endif
}
break;
@@ -3879,7 +3917,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
md.damage = 100 + 200 * skill_lv + sstatus->int_;
break;
case GN_HELLS_PLANT_ATK:
- md.damage = skill_lv * status->get_lv(src) * 10 + sstatus->int_ * 7 / 2 * (18 + (sd ? sd->status.job_level : 0) / 4) * (5 / (10 - (sd ? pc->checkskill(sd, AM_CANNIBALIZE) : 0)));
+ md.damage = skill_lv * status->get_lv(target) * 10 + sstatus->int_ * 7 / 2 * (18 + (sd ? sd->status.job_level : 0) / 4) * (5 / (10 - (sd ? pc->checkskill(sd, AM_CANNIBALIZE) : 0)));
md.damage = md.damage*(1000 + tstatus->mdef) / (1000 + tstatus->mdef * 10) - tstatus->mdef2;
break;
case KO_HAPPOKUNAI:
@@ -4177,6 +4215,12 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
case LK_SPIRALPIERCE:
if (!sd) wd.flag=(wd.flag&~(BF_RANGEMASK|BF_WEAPONMASK))|BF_LONG|BF_MISC;
break;
+
+ //When in banding, the number of hits is equal to the number of Royal Guards in banding.
+ case LG_HESPERUSLIT:
+ if( sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 3 )
+ wd.div_ = sc->data[SC_BANDING]->val2;
+ break;
case MO_INVESTIGATE:
flag.pdef = flag.pdef2 = 2;
@@ -4228,6 +4272,10 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
case LK_SPIRALPIERCE:
if (!sd) n_ele = false; //forced neutral for monsters
break;
+ case LG_HESPERUSLIT:
+ if ( sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 == 5 )
+ s_ele = ELE_HOLY; // Banding with 5 RGs: change atk element to Holy.
+ break;
}
if (!(nk & NK_NO_ELEFIX) && !n_ele)
@@ -4533,13 +4581,11 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
ATK_ADD(-totaldef);
if( is_boss(target) )
ATK_RATE(50);
- RE_SKILL_REDUCTION();
}
break;
case NJ_SYURIKEN: // [malufett]
GET_NORMAL_ATTACK( (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0) );
wd.damage += battle->calc_masteryfix(src, target, skill_id, skill_lv, 4 * skill_lv + (sd ? sd->bonus.arrow_atk : 0), wd.div_, 0, flag.weapon) - status->get_total_def(target);
- RE_SKILL_REDUCTION();
break;
case MO_EXTREMITYFIST: // [malufett]
{
@@ -4549,7 +4595,6 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
wd.damage = (250 + 150 * skill_lv) + (10 * (status_get_sp(src)+1) * wd.damage / 100) + (8 * wd.damage);
ATK_ADD(-totaldef);
}
- RE_SKILL_REDUCTION();
}
#endif
break;
@@ -4571,10 +4616,10 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
i*=i;
ATK_ADD(i); //Add str bonus.
switch (tstatus->size) { //Size-fix. Is this modified by weapon perfection?
- case SZ_MEDIUM: //Medium: 125%
+ case SZ_SMALL: //Small: 125%
ATK_RATE(125);
break;
- //case SZ_SMALL: //Medium: 100%
+ //case SZ_MEDIUM: //Medium: 100%
case SZ_BIG: //Large: 75%
ATK_RATE(75);
break;
@@ -4688,9 +4733,6 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
#endif
switch(skill_id){
case SR_GATEOFHELL:
- #ifdef RENEWAL
- RE_SKILL_REDUCTION();
- #endif // RENEWAL
if (wd.dmg_lv != ATK_FLEE)
ATK_RATE(battle->calc_skillratio(BF_WEAPON, src, target, skill_id, skill_lv, skillratio, wflag));
else
@@ -4713,7 +4755,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
ATK_ADD(sd->inventory_data[index]->weight * 7 / 100);
switch (tstatus->size) {
- case SZ_MEDIUM: //Medium: 115%
+ case SZ_SMALL: //Small: 115%
ATK_RATE(115);
break;
case SZ_BIG: //Large: 85%
@@ -5063,7 +5105,6 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
}
#endif
-#ifndef RENEWAL
if (sd) {
if (skill_id != CR_SHIELDBOOMERANG) //Only Shield boomerang doesn't takes the Star Crumbs bonus.
ATK_ADD2(wd.div_*sd->right_weapon.star, wd.div_*sd->left_weapon.star);
@@ -5085,11 +5126,11 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list
ATK_ADD(10*sd->status.inventory[index].refine);
}
}
+
//Card Fix, tsd side
if(tsd){ //if player on player then it was already measured above
wd.damage = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage, (flag.lh?1:0), wd.flag);
}
-#endif
if( flag.infdef ) { //Plants receive 1 damage when hit
short class_ = status->get_class(target);
if( flag.hit || wd.damage > 0 )
@@ -5357,8 +5398,7 @@ void battle_reflect_damage(struct block_list *target, struct block_list *src, st
sc = NULL;
if( sc ) {
- if (sc->data[SC_DEVOTION] && !(wd->flag & BF_SKILL))
- return; // No reflect for basic attacks on devoted characters
+
if (wd->flag & BF_SHORT && !(skill->get_inf(skill_id) & (INF_GROUND_SKILL | INF_SELF_SKILL))) {
if( sc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < sc->data[SC_CRESCENTELBOW]->val2 ){
@@ -5425,9 +5465,18 @@ void battle_reflect_damage(struct block_list *target, struct block_list *src, st
if( wd->dmg_lv >= ATK_BLOCK ) {/* yes block still applies, somehow gravity thinks it makes sense. */
if( sc ) {
- if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) {
- NORMALIZE_RDAMAGE(damage * sc->data[SC_REFLECTSHIELD]->val2 / 100);
+ struct status_change_entry *sce_d = sc->data[SC_DEVOTION];
+ struct block_list *d_bl = NULL;
+
+ if (sce_d && sce_d->val1)
+ d_bl = map->id2bl(sce_d->val1);
+
+ if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION && skill_id != GS_DESPERADO
+ && !(d_bl && !(wd->flag&BF_SKILL)) // It should not be a basic attack if the target is under devotion
+ && !(d_bl && sce_d && !check_distance_bl(target, d_bl, sce_d->val3)) // It should not be out of range if the target is under devotion
+ ) {
+ NORMALIZE_RDAMAGE(damage * sc->data[SC_REFLECTSHIELD]->val2 / 100);
#ifndef RENEWAL
rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4);
#else
@@ -6734,6 +6783,7 @@ static const struct battle_data {
{ "mail_show_status", &battle_config.mail_show_status, 0, 0, 2, },
{ "client_limit_unit_lv", &battle_config.client_limit_unit_lv, 0, 0, BL_ALL, },
{ "client_emblem_max_blank_percent", &battle_config.client_emblem_max_blank_percent, 100, 0, 100, },
+
// BattleGround Settings
{ "bg_update_interval", &battle_config.bg_update_interval, 1000, 100, INT_MAX, },
{ "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, },
@@ -6774,6 +6824,8 @@ static const struct battle_data {
{ "case_sensitive_aegisnames", &battle_config.case_sensitive_aegisnames, 1, 0, 1, },
{ "guild_castle_invite", &battle_config.guild_castle_invite, 0, 0, 1, },
{ "guild_castle_expulsion", &battle_config.guild_castle_expulsion, 0, 0, 1, },
+ { "song_timer_reset", &battle_config.song_timer_reset, 0, 0, 1, },
+ { "snap_dodge", &battle_config.snap_dodge, 0, 0, 1, },
};
#ifndef STATS_OPT_OUT
/**