Job Improvement Project - Guillotine Cross (#4705)

* Fixes #4704.
* kRO Changelog: http://ro.gnjoy.com/news/update/View.asp?seq=243&curpage=1
Thanks to @Angelic234, @nehpetskie, @ecdarreola, @Haydrich, @Badarosk0, and @LordWhiplash!
This commit is contained in:
Aleos 2020-05-18 10:47:21 -04:00 committed by GitHub
parent 341d093802
commit a23c84d345
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 247 additions and 207 deletions

View File

@ -10360,62 +10360,21 @@ Body:
Name: ASC_BREAKER
Description: Soul Destroyer
MaxLevel: 10
Type: Misc
Type: Weapon
TargetType: Attack
DamageFlags:
IgnoreAtkCard: true
IgnoreDefense: true
IgnoreFlee: true
Critical: true
Range: 9
Hit: Single
HitCount: 1
Element: Weapon
CastCancel: true
CastTime: 250
AfterCastActDelay:
- Level: 1
Time: 1000
- Level: 2
Time: 1200
- Level: 3
Time: 1400
- Level: 4
Time: 1600
- Level: 5
Time: 1800
- Level: 6
Time: 2000
- Level: 7
Time: 2200
- Level: 8
Time: 2400
- Level: 9
Time: 2600
- Level: 10
Time: 2800
AfterCastActDelay: 2000
Cooldown: 150
FixedCastTime: 250
Requires:
SpCost:
- Level: 1
Amount: 20
- Level: 2
Amount: 20
- Level: 3
Amount: 20
- Level: 4
Amount: 20
- Level: 5
Amount: 20
- Level: 6
Amount: 30
- Level: 7
Amount: 30
- Level: 8
Amount: 30
- Level: 9
Amount: 30
- Level: 10
Amount: 30
SpCost: 20
- Id: 380
Name: SN_SIGHT
Description: Falcon Eyes
@ -19091,7 +19050,9 @@ Body:
MaxLevel: 5
Type: Weapon
TargetType: Attack
Range: 3
DamageFlags:
Critical: true
Range: 7
Hit: Multi_Hit
HitCount: -7
Element: Weapon
@ -19109,11 +19070,12 @@ Body:
Time: 1000
- Level: 5
Time: 500
Cooldown: 700
FixedCastTime: -1
CastDelayFlags:
IgnoreStatus: true
Requires:
SpCost: 25
SpCost: 40
State: Move_Enable
- Id: 2023
Name: GC_DARKILLUSION
@ -19463,13 +19425,13 @@ Body:
- Level: 2
Area: 1
- Level: 3
Area: 1
- Level: 4
Area: 1
- Level: 5
Area: 2
- Level: 4
Area: 2
- Level: 5
Area: 3
AfterCastActDelay: 200
Duration1: 3000
Duration1: 5000
FixedCastTime: -1
Requires:
SpCost: 5
@ -19495,7 +19457,8 @@ Body:
Hit: Single
HitCount: 1
Element: Weapon
AfterCastActDelay: 1000
AfterCastActDelay: 500
Cooldown: 500
FixedCastTime: -1
Requires:
SpCost:
@ -31587,7 +31550,7 @@ Body:
CopyFlags:
Skill:
Reproduce: true
Duration1: 5000
Duration1: 10000
Cooldown: 60000
FixedCastTime: -1
Requires:

View File

@ -1342,6 +1342,8 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
if (sc->data[SC_SOUNDOFDESTRUCTION])
damage <<= 1;
if (sc->data[SC_DARKCROW] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT)
damage += damage * sc->data[SC_DARKCROW]->val2 / 100;
// Damage reductions
// Assumptio increases DEF on RE mode, otherwise gives a reduction on the final damage. [Igniz]
@ -1438,9 +1440,6 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
damage = i64max(damage, 1);
}
if( sc->data[SC_DARKCROW] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT )
damage += damage * sc->data[SC_DARKCROW]->val2 / 100;
if( (sce=sc->data[SC_MAGMA_FLOW]) && (rnd()%100 <= sce->val2) )
skill_castend_damage_id(bl,src,MH_MAGMA_FLOW,sce->val1,gettick(),0);
@ -1609,10 +1608,11 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
status_change_end(src,SC_SHIELDSPELL_REF,INVALID_TIMER);
}
if( sc->data[SC_POISONINGWEAPON]
&& ((flag&BF_WEAPON) && (!skill_id || skill_id == GC_VENOMPRESSURE)) //check skill type poison_smoke is a unit
&& (damage > 0 && rnd()%100 < sc->data[SC_POISONINGWEAPON]->val3 )) //did some damage and chance ok (why no additional effect ??)
sc_start2(src,bl,(enum sc_type)sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,sc->data[SC_POISONINGWEAPON]->val4,skill_get_time2(GC_POISONINGWEAPON, 1));
if (sc->data[SC_POISONINGWEAPON] && flag&BF_SHORT && (skill_id == 0 || skill_id == GC_VENOMPRESSURE) && damage > 0) {
damage += damage * 10 / 100;
if (rnd() % 100 < sc->data[SC_POISONINGWEAPON]->val3)
sc_start4(src, bl, (sc_type)sc->data[SC_POISONINGWEAPON]->val2, 100, sc->data[SC_POISONINGWEAPON]->val1, 0, 1, 0, skill_get_time2(GC_POISONINGWEAPON, 1));
}
if( sc->data[SC__DEADLYINFECT] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT && damage > 0 && rnd()%100 < 30 + 10 * sc->data[SC__DEADLYINFECT]->val1 )
status_change_spread(src, bl, 0);
@ -2237,6 +2237,10 @@ static int battle_range_type(struct block_list *src, struct block_list *target,
if (src->type == BL_MOB && (skill_id == AC_SHOWER || skill_id == AM_DEMONSTRATION))
return BF_SHORT;
// Cast range is 7 cells and player jumps to target but skill is considered melee
if (skill_id == GC_CROSSIMPACT)
return BF_SHORT;
//Skill Range Criteria
if (battle_config.skillrange_by_distance &&
(src->type&battle_config.skillrange_by_distance)
@ -2568,6 +2572,12 @@ static bool is_attack_critical(struct Damage* wd, struct block_list *src, struct
case NJ_KIRIKAGE:
cri += 250 + 50*skill_lv;
break;
#ifdef RENEWAL
case ASC_BREAKER:
#endif
case GC_CROSSIMPACT:
cri /= 2;
break;
}
if(tsd && tsd->bonus.critical_def)
cri = cri * ( 100 - tsd->bonus.critical_def ) / 100;
@ -2592,13 +2602,12 @@ static int is_attack_piercing(struct Damage* wd, struct block_list *src, struct
if(src != NULL) {
struct map_session_data *sd = BL_CAST(BL_PC, src);
struct status_data *tstatus = status_get_status_data(target);
#ifdef RENEWAL
if( skill_id != PA_SACRIFICE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS
&& skill_id != PA_SHIELDCHAIN && skill_id != KO_HAPPOKUNAI && skill_id != ASC_BREAKER ) // Renewal: Soul Breaker no longer gains ice pick effect and ice pick effect gets crit benefit [helvetica]
#else
if( skill_id != PA_SACRIFICE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS
&& skill_id != PA_SHIELDCHAIN && skill_id != KO_HAPPOKUNAI && !is_attack_critical(wd, src, target, skill_id, skill_lv, false) )
if( skill_id != PA_SACRIFICE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != PA_SHIELDCHAIN && skill_id != KO_HAPPOKUNAI
#ifndef RENEWAL
&& !is_attack_critical(wd, src, target, skill_id, skill_lv, false)
#endif
)
{ //Elemental/Racial adjustments
if( sd && (sd->right_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) || sd->right_weapon.def_ratio_atk_ele & (1<<ELE_ALL) ||
sd->right_weapon.def_ratio_atk_race & (1<<tstatus->race) || sd->right_weapon.def_ratio_atk_race & (1<<RC_ALL) ||
@ -2838,11 +2847,7 @@ static bool attack_ignores_def(struct Damage* wd, struct block_list *src, struct
#endif
if (sc && sc->data[SC_FUSION])
return true;
#ifdef RENEWAL
else if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != ASC_BREAKER) // Renewal: Soul Breaker no longer gains ignore DEF from weapon [helvetica]
#else
else if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS)
#endif
{ //Ignore Defense?
if (sd && (sd->right_weapon.ignore_def_ele & (1<<tstatus->def_ele) || sd->right_weapon.ignore_def_ele & (1<<ELE_ALL) ||
sd->right_weapon.ignore_def_race & (1<<tstatus->race) || sd->right_weapon.ignore_def_race & (1<<RC_ALL) ||
@ -3494,7 +3499,11 @@ static void battle_calc_multi_attack(struct Damage* wd, struct block_list *src,s
if (sc && sc->data[SC_KAGEMUSYA])
max_rate = sc->data[SC_KAGEMUSYA]->val1 * 10; // Same rate as even levels of TF_DOUBLE
else
#ifdef RENEWAL
max_rate = max(7 * skill_lv, sd->bonus.double_rate);
#else
max_rate = max(5 * skill_lv, sd->bonus.double_rate);
#endif
if( rnd()%100 < max_rate ) {
wd->div_ = skill_get_num(TF_DOUBLE,skill_lv?skill_lv:1);
@ -3933,12 +3942,15 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
if(sd)
skillratio += 20 * pc_checkskill(sd,AS_POISONREACT);
break;
#ifndef RENEWAL
// Pre-Renewal: skill ratio for weapon part of damage [helvetica]
case ASC_BREAKER:
#ifdef RENEWAL
skillratio += -100 + 140 * skill_lv + sstatus->str + sstatus->int_; // !TODO: Confirm stat modifier
RE_LVL_DMOD(100);
#else
// Pre-Renewal: skill ratio for weapon part of damage [helvetica]
skillratio += -100 + 100 * skill_lv;
break;
#endif
break;
case PA_SACRIFICE:
skillratio += -10 + 10 * skill_lv;
break;
@ -4128,8 +4140,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
RE_LVL_DMOD(150); // Base level bonus.
break;
case GC_CROSSIMPACT:
skillratio += 900 + 100 * skill_lv;
RE_LVL_DMOD(120);
skillratio += -100 + 1000 + 150 * skill_lv;
RE_LVL_DMOD(100);
break;
case GC_COUNTERSLASH:
//ATK [{(Skill Level x 150) + 300} x Caster's Base Level / 120]% + ATK [(AGI x 2) + (Caster's Job Level x 4)]%
@ -4143,14 +4155,14 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
skillratio += 200;
break;
case GC_ROLLINGCUTTER:
skillratio += -50 + 50 * skill_lv;
skillratio += -100 + 50 + 80 * skill_lv;
RE_LVL_DMOD(100);
break;
case GC_CROSSRIPPERSLASHER:
skillratio += 300 + 80 * skill_lv;
skillratio += -100 + 80 * skill_lv + (sstatus->agi * 3);
RE_LVL_DMOD(100);
if (sc && sc->data[SC_ROLLINGCUTTER])
skillratio += sc->data[SC_ROLLINGCUTTER]->val1 * status_get_agi(src);
skillratio += sc->data[SC_ROLLINGCUTTER]->val1 * 200;
break;
case GC_DARKCROW:
skillratio += 100 * (skill_lv - 1);
@ -4909,6 +4921,11 @@ static void battle_attack_sc_bonus(struct Damage* wd, struct block_list *src, st
RE_ALLATK_ADDRATE(wd, sc->data[SC_GVG_GIANT]->val3);
}
if (sc->data[SC_PYREXIA] && sc->data[SC_PYREXIA]->val3 == 0) {
ATK_ADDRATE(wd->damage, wd->damage2, sc->data[SC_PYREXIA]->val2);
RE_ALLATK_ADDRATE(wd, sc->data[SC_PYREXIA]->val2);
}
if (sc->data[SC_MIRACLE])
anger_id = 2; // Always treat all monsters as star flagged monster when in miracle state
}
@ -5859,7 +5876,6 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
#ifdef RENEWAL
switch(skill_id) {
case NJ_ISSEN:
case ASC_BREAKER:
break; //These skills will do a card fix later
default:
#endif
@ -5938,7 +5954,6 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
#ifdef RENEWAL
switch (skill_id) {
case NJ_ISSEN:
case ASC_BREAKER:
return wd; //These skills will do a GVG fix later
default:
#endif
@ -6602,13 +6617,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
}
}
#ifdef RENEWAL
switch(skill_id) { // These skills will do a card fix later
case ASC_BREAKER:
break;
default:
ad.damage += battle_calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag);
break;
}
ad.damage += battle_calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag);
#endif
if(sd) {
@ -6704,7 +6713,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
}
}
if (!nk[NK_IGNOREELEMENT] && skill_id != ASC_BREAKER) // Soul Breaker's magic portion is non-elemental. [Secret]
if (!nk[NK_IGNOREELEMENT])
ad.damage = battle_attr_fix(src, target, ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv);
//Apply the physical part of the skill's damage. [Skotlex]
@ -6737,13 +6746,6 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
//Apply DAMAGE_DIV_FIX and check for min damage
battle_apply_div_fix(&ad, skill_id);
#ifdef RENEWAL
switch(skill_id) {
case ASC_BREAKER:
return ad; //These skills will do a GVG fix later
}
#endif
struct map_data *mapdata = map_getmapdata(target->m);
ad.damage = battle_calc_damage(src,target,&ad,ad.damage,skill_id,skill_lv);
@ -6887,35 +6889,12 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
case NPC_EVILLAND:
md.damage = skill_calc_heal(src,target,skill_id,skill_lv,false);
break;
#ifndef RENEWAL
case ASC_BREAKER:
#ifdef RENEWAL
// Official Renewal formula [helvetica]
// damage = ((atk + matk) * (3 + (.5 * skill level))) - (edef + sdef + emdef + smdef)
// atk part takes weapon element, matk part is non-elemental
// modified def formula
{
short totaldef, totalmdef;
struct Damage atk, matk;
atk = battle_calc_weapon_attack(src, target, skill_id, skill_lv, 0);
nk.set(NK_IGNOREELEMENT); // atk part takes on weapon element, matk part is non-elemental
matk = battle_calc_magic_attack(src, target, skill_id, skill_lv, 0);
// (atk + matk) * (3 + (.5 * skill level))
md.damage = ((30 + (5 * skill_lv)) * (atk.damage + matk.damage)) / 10;
// modified def reduction, final damage = base damage - (edef + sdef + emdef + smdef)
totaldef = tstatus->def2 + (short)status_get_def(target);
totalmdef = tstatus->mdef + tstatus->mdef2;
md.damage -= totaldef + totalmdef;
}
#else
md.damage = 500 + rnd()%500 + 5 * skill_lv * sstatus->int_;
nk.set(NK_IGNOREFLEE);
nk.set(NK_IGNOREELEMENT); //These two are not properties of the weapon based part.
#endif
break;
#ifndef RENEWAL
case HW_GRAVITATION:
md.damage = 200 + 200 * skill_lv;
md.dmotion = 0; //No flinch animation
@ -7251,8 +7230,11 @@ int64 battle_calc_return_damage(struct block_list* bl, struct block_list *src, i
sc = status_get_sc(bl);
ssc = status_get_sc(src);
if (sc && sc->data[SC_WHITEIMPRISON])
return 0; // White Imprison does not reflect any damage
if (sc) { // These statuses do not reflect any damage (off the target)
if (sc->data[SC_WHITEIMPRISON] || sc->data[SC_DARKCROW] ||
(sc->data[SC_KYOMU] && (!ssc || !ssc->data[SC_SHIELDSPELL_DEF]))) // Nullify reflecting ability except for Shield Spell - Def
return 0;
}
if (ssc && ssc->data[SC_REF_T_POTION])
return 0;
@ -7320,20 +7302,22 @@ int64 battle_calc_return_damage(struct block_list* bl, struct block_list *src, i
}
}
if (ssc && ssc->data[SC_INSPIRATION]) {
rdamage += damage / 100;
if (ssc) {
if (ssc->data[SC_INSPIRATION]) {
rdamage += damage / 100;
#ifdef RENEWAL
rdamage = cap_value(rdamage, 1, max_damage);
rdamage = cap_value(rdamage, 1, max_damage);
#else
rdamage = i64max(rdamage,1);
rdamage = i64max(rdamage, 1);
#endif
}
if (ssc->data[SC_VENOMBLEED] && ssc->data[SC_VENOMBLEED]->val3 == 0)
rdamage -= damage * ssc->data[SC_VENOMBLEED]->val2 / 100;
}
if (sc && sc->data[SC_KYOMU] && (!ssc || !ssc->data[SC_SHIELDSPELL_DEF])) // Nullify reflecting ability except for Shield Spell - Def
rdamage = 0;
if (sc && sc->data[SC_MAXPAIN]) {
rdamage = damage * sc->data[SC_MAXPAIN]->val1 * 10 / 100;
if (sc) {
if (sc->data[SC_MAXPAIN])
rdamage = damage * sc->data[SC_MAXPAIN]->val1 * 10 / 100;
}
return cap_value(min(rdamage,max_damage),INT_MIN,INT_MAX);

View File

@ -8977,7 +8977,7 @@ int pc_itemheal(struct map_session_data *sd, int itemid, int hp, int sp)
if (sd->sc.data[SC_CRITICALWOUND])
penalty += sd->sc.data[SC_CRITICALWOUND]->val2;
if (sd->sc.data[SC_DEATHHURT])
if (sd->sc.data[SC_DEATHHURT] && sd->sc.data[SC_DEATHHURT]->val3 == 1)
penalty += 20;
if (sd->sc.data[SC_NORECOVER_STATE])

View File

@ -740,7 +740,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk
if (tsc->data[SC_CRITICALWOUND])
penalty += tsc->data[SC_CRITICALWOUND]->val2;
if (tsc->data[SC_DEATHHURT])
if (tsc->data[SC_DEATHHURT] && tsc->data[SC_DEATHHURT]->val3 == 1)
penalty += 20;
if (tsc->data[SC_NORECOVER_STATE])
penalty = 100;
@ -1233,7 +1233,11 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
if( sd )
{ // These statuses would be applied anyway even if the damage was blocked by some skills. [Inkfish]
if( skill_id != WS_CARTTERMINATION && skill_id != AM_DEMONSTRATION && skill_id != CR_REFLECTSHIELD && skill_id != MS_REFLECTSHIELD && skill_id != ASC_BREAKER ) {
if( skill_id != WS_CARTTERMINATION && skill_id != AM_DEMONSTRATION && skill_id != CR_REFLECTSHIELD && skill_id != MS_REFLECTSHIELD
#ifndef RENEWAL
&& skill_id != ASC_BREAKER
#endif
) {
// Trigger status effects
enum sc_type type;
unsigned int time;
@ -4818,9 +4822,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case GS_FULLBUSTER:
case NJ_SYURIKEN:
case NJ_KUNAI:
#ifndef RENEWAL
case ASC_BREAKER:
#endif
case HFLI_MOON: //[orn]
case HFLI_SBR44: //[orn]
case NPC_BLEEDING:
@ -4834,7 +4836,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case NC_AXEBOOMERANG:
case NC_POWERSWING:
case NC_MAGMA_ERUPTION:
case GC_CROSSIMPACT:
case GC_WEAPONCRUSH:
case GC_VENOMPRESSURE:
case SC_TRIANGLESHOT:
@ -5518,9 +5519,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case CR_ACIDDEMONSTRATION:
#endif
case TF_THROWSTONE:
#ifdef RENEWAL
case ASC_BREAKER:
#endif
case NPC_SMOKING:
case GS_FLING:
case NJ_ZENYNAGE:
@ -5675,7 +5673,14 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
else
{
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
status_change_end(src,SC_ROLLINGCUTTER,INVALID_TIMER);
}
break;
case GC_CROSSIMPACT: {
uint8 dir = map_calc_dir(bl, src->x, src->y);
if (skill_check_unit_movepos(5, src, bl->x, bl->y, 1, 1))
skill_blown(src, src, 1, (dir + 4) % 8, BLOWN_NONE); // Target position is actually one cell next to the target
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
}
break;
@ -8301,7 +8306,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
}
if (tsc->data[SC_CRITICALWOUND])
penalty += tsc->data[SC_CRITICALWOUND]->val2;
if (tsc->data[SC_DEATHHURT])
if (tsc->data[SC_DEATHHURT] && tsc->data[SC_DEATHHURT]->val3)
penalty += 20;
if (tsc->data[SC_NORECOVER_STATE])
penalty = 100;
@ -8532,6 +8537,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
#ifdef RENEWAL
clif_blown(src); // Always blow, otherwise it shows a casting animation. [Lemongrass]
#endif
status_change_end(src, SC_ROLLINGCUTTER, INVALID_TIMER);
break;
case TK_HIGHJUMP:
@ -9169,7 +9175,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
}
if (tsc->data[SC_CRITICALWOUND])
penalty += tsc->data[SC_CRITICALWOUND]->val2;
if (tsc->data[SC_DEATHHURT])
if (tsc->data[SC_DEATHHURT] && tsc->data[SC_DEATHHURT]->val3 == 1)
penalty += 20;
if (tsc->data[SC_NORECOVER_STATE])
penalty = 100;
@ -17468,16 +17474,18 @@ int skill_delayfix(struct block_list *bl, uint16 skill_id, uint16 skill_lv)
}
}
if (sc && sc->data[SC_SPIRIT]) {
switch (skill_id) {
case CR_SHIELDBOOMERANG:
if (sc->data[SC_SPIRIT]->val2 == SL_CRUSADER)
time /= 2;
break;
case AS_SONICBLOW:
if (!map_flag_gvg2(bl->m) && !map_getmapflag(bl->m, MF_BATTLEGROUND) && sc->data[SC_SPIRIT]->val2 == SL_ASSASIN)
time /= 2;
break;
if (sc && sc->count) {
if (sc->data[SC_SPIRIT]) {
switch (skill_id) {
case CR_SHIELDBOOMERANG:
if (sc->data[SC_SPIRIT]->val2 == SL_CRUSADER)
time /= 2;
break;
case AS_SONICBLOW:
if (!map_flag_gvg2(bl->m) && !map_getmapflag(bl->m, MF_BATTLEGROUND) && sc->data[SC_SPIRIT]->val2 == SL_ASSASIN)
time /= 2;
break;
}
}
}
@ -17487,6 +17495,8 @@ int skill_delayfix(struct block_list *bl, uint16 skill_id, uint16 skill_lv)
time -= time * sc->data[SC_POEMBRAGI]->val3 / 100;
if (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 3 && skill_get_type(skill_id) == BF_MAGIC && skill_get_ele(skill_id, skill_lv) == ELE_WIND)
time /= 2; // After Delay of Wind element spells reduced by 50%.
if (sc->data[SC_MAGICMUSHROOM] && sc->data[SC_MAGICMUSHROOM]->val3 == 0)
time -= time * sc->data[SC_MAGICMUSHROOM]->val2 / 100;
}
}
@ -20477,27 +20487,27 @@ bool skill_arrow_create(struct map_session_data *sd, unsigned short nameid)
*/
int skill_poisoningweapon(struct map_session_data *sd, unsigned short nameid)
{
sc_type type;
int chance, i, val4 = 0;
//uint16 msg = 1443; //Official is using msgstringtable.txt
char output[CHAT_SIZE_MAX];
const char *msg;
nullpo_ret(sd);
if( !nameid || (i = pc_search_inventory(sd,nameid)) < 0 || pc_delitem(sd,i,1,0,0,LOG_TYPE_CONSUME) ) {
if( !nameid || pc_delitem(sd,pc_search_inventory(sd,nameid),1,0,0,LOG_TYPE_CONSUME) ) {
clif_skill_fail(sd,GC_POISONINGWEAPON,USESKILL_FAIL_LEVEL,0);
return 0;
}
switch( nameid ) { // t_lv used to take duration from skill_get_time2
sc_type type;
int chance;
//uint16 msg = 1443; //Official is using msgstringtable.txt
char output[CHAT_SIZE_MAX];
const char *msg;
switch( nameid ) {
case ITEMID_PARALYSE: type = SC_PARALYSE; /*msg = 1444;*/ msg = "Paralyze"; break;
case ITEMID_PYREXIA: type = SC_PYREXIA; /*msg = 1448;*/ msg = "Pyrexia"; break;
case ITEMID_DEATHHURT: type = SC_DEATHHURT; /*msg = 1447;*/ msg = "Deathhurt"; break;
case ITEMID_LEECHESEND: type = SC_LEECHESEND; /*msg = 1450;*/ msg = "Leech End"; val4 = sd->bl.id; break;
case ITEMID_LEECHESEND: type = SC_LEECHESEND; /*msg = 1450;*/ msg = "Leech End"; break;
case ITEMID_VENOMBLEED: type = SC_VENOMBLEED; /*msg = 1445;*/ msg = "Venom Bleed"; break;
case ITEMID_TOXIN: type = SC_TOXIN; /*msg = 1443;*/ msg = "Toxin"; val4 = sd->bl.id; break;
case ITEMID_MAGICMUSHROOM: type = SC_MAGICMUSHROOM; /*msg = 1446;*/ msg = "Magic Mushroom"; val4 = sd->bl.id; break;
case ITEMID_TOXIN: type = SC_TOXIN; /*msg = 1443;*/ msg = "Toxin"; break;
case ITEMID_MAGICMUSHROOM: type = SC_MAGICMUSHROOM; /*msg = 1446;*/ msg = "Magic Mushroom"; break;
case ITEMID_OBLIVIONCURSE: type = SC_OBLIVIONCURSE; /*msg = 1449;*/ msg = "Oblivion Curse"; break;
default:
clif_skill_fail(sd,GC_POISONINGWEAPON,USESKILL_FAIL_LEVEL,0);
@ -20507,7 +20517,8 @@ int skill_poisoningweapon(struct map_session_data *sd, unsigned short nameid)
status_change_end(&sd->bl, SC_POISONINGWEAPON, INVALID_TIMER); // End the status so a new poison can be applied (if changed)
chance = 2 + 2 * sd->menuskill_val; // 2 + 2 * skill_lv
sc_start4(&sd->bl,&sd->bl, SC_POISONINGWEAPON, 100, pc_checkskill(sd, GC_RESEARCHNEWPOISON), //in Aegis it store the level of GC_RESEARCHNEWPOISON in val1
type, chance, val4, skill_get_time(GC_POISONINGWEAPON, sd->menuskill_val));
type, chance, 0, skill_get_time(GC_POISONINGWEAPON, sd->menuskill_val));
status_change_start(&sd->bl, &sd->bl, type, 10000, sd->menuskill_val, 0, 0, 0, skill_get_time(GC_POISONINGWEAPON, sd->menuskill_val), SCSTART_NOAVOID | SCSTART_NOICON); // Apply bonus to caster
sprintf(output, msg_txt(sd,721), msg);
clif_messagecolor(&sd->bl,color_table[COLOR_WHITE],output,false,SELF);

View File

@ -2294,7 +2294,7 @@ public:
}
const std::string getDefaultLocation();
uint64 parseBodyNode(const YAML::Node& node);
uint64 parseBodyNode(const YAML::Node &node);
};
extern MagicMushroomDatabase magic_mushroom_db;

View File

@ -1469,7 +1469,7 @@ void initChangeTables(void)
StatusChangeFlagTable[SC_DEATHHURT] |= SCB_REGEN;
StatusChangeFlagTable[SC_VENOMBLEED] |= SCB_MAXHP;
StatusChangeFlagTable[SC_MAGICMUSHROOM] |= SCB_REGEN;
StatusChangeFlagTable[SC_PYREXIA] |= SCB_HIT|SCB_FLEE;
StatusChangeFlagTable[SC_PYREXIA] |= SCB_ALL;
StatusChangeFlagTable[SC_OBLIVIONCURSE] |= SCB_REGEN;
StatusChangeFlagTable[SC_BANDING_DEFENCE] |= SCB_SPEED;
StatusChangeFlagTable[SC_SHIELDSPELL_DEF] |= SCB_WATK;
@ -1694,7 +1694,7 @@ void initChangeTables(void)
#endif
StatusChangeStateTable[SC__BLOODYLUST] |= SCS_NOCAST;
StatusChangeStateTable[SC_DEATHBOUND] |= SCS_NOCAST;
StatusChangeStateTable[SC_OBLIVIONCURSE] |= SCS_NOCAST;
StatusChangeStateTable[SC_OBLIVIONCURSE] |= SCS_NOCAST|SCS_NOCASTCOND;
StatusChangeStateTable[SC_WHITEIMPRISON] |= SCS_NOCAST;
StatusChangeStateTable[SC__SHADOWFORM] |= SCS_NOCAST;
StatusChangeStateTable[SC__INVISIBILITY] |= SCS_NOCAST;
@ -3415,7 +3415,7 @@ static int status_get_hpbonus(struct block_list *bl, enum e_status_bonus type) {
bonus += sc->data[SC_LUNARSTANCE]->val2;
//Decreasing
if(sc->data[SC_VENOMBLEED])
if (sc->data[SC_VENOMBLEED] && sc->data[SC_VENOMBLEED]->val3 == 1)
bonus -= 15;
if(sc->data[SC_BEYONDOFWARCRY])
bonus -= sc->data[SC_BEYONDOFWARCRY]->val3;
@ -4682,6 +4682,8 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt)
sd->subele[ELE_GHOST] += sc->data[SC_SYMPHONYOFLOVER]->val1 * 3;
sd->subele[ELE_HOLY] += sc->data[SC_SYMPHONYOFLOVER]->val1 * 3;
}
if (sc->data[SC_PYREXIA] && sc->data[SC_PYREXIA]->val3 == 0)
sd->bonus.crit_atk_rate += sc->data[SC_PYREXIA]->val2;
}
status_cpy(&sd->battle_status, base_status);
@ -5098,7 +5100,7 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str
|| sc->data[SC_BERSERK]
|| sc->data[SC_TRICKDEAD]
|| sc->data[SC_BLEEDING]
|| sc->data[SC_MAGICMUSHROOM]
|| (sc->data[SC_MAGICMUSHROOM] && sc->data[SC_MAGICMUSHROOM]->val3 == 1)
|| sc->data[SC_SATURDAYNIGHTFEVER]
|| sc->data[SC_REBOUND])
regen->flag = RGN_NONE;
@ -5115,7 +5117,7 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str
(bl->type == BL_PC && (((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK &&
sc->data[SC_EXTREMITYFIST] && (!sc->data[SC_SPIRIT] || sc->data[SC_SPIRIT]->val2 != SL_MONK)) ||
#endif
sc->data[SC_OBLIVIONCURSE] || sc->data[SC_VITALITYACTIVATION])
(sc->data[SC_OBLIVIONCURSE] && sc->data[SC_OBLIVIONCURSE]->val3 == 1) || sc->data[SC_VITALITYACTIVATION])
regen->flag &= ~RGN_SP;
if (sc->data[SC_TENSIONRELAX]) {
@ -5233,6 +5235,8 @@ void status_calc_state( struct block_list *bl, struct status_change *sc, enum sc
if( flag&SCS_NOCAST ) {
if( !(flag&SCS_NOCASTCOND) )
sc->cant.cast += ( start ? 1 : -1 );
else if (sc->data[SC_OBLIVIONCURSE] && sc->data[SC_OBLIVIONCURSE]->val3 == 1)
sc->cant.cast += (start ? 1 : -1);
}
// Can't chat
@ -6931,7 +6935,7 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
flee -= flee * 25/100;
if(sc->data[SC_FEAR])
flee -= flee * 20 / 100;
if(sc->data[SC_PARALYSE])
if(sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 1)
flee -= flee * 10 / 100;
if(sc->data[SC_INFRAREDSCAN])
flee -= flee * 30 / 100;
@ -7409,6 +7413,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
val = max( val, 75 );
if( sc->data[SC_CLOAKINGEXCEED] )
val = max( val, sc->data[SC_CLOAKINGEXCEED]->val3);
if (sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 0)
val = max(val, 50);
if( sc->data[SC_HOVERING] )
val = max( val, 10 );
if( sc->data[SC_GN_CARTBOOST] )
@ -7441,7 +7447,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
// GetSpeed()
if( sd && pc_iscarton(sd) )
speed += speed * (50 - 5 * pc_checkskill(sd,MC_PUSHCART)) / 100;
if( sc->data[SC_PARALYSE] )
if( sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 1 )
speed += speed * 50 / 100;
if( speed_rate != 100 )
speed = speed * speed_rate / 100;
@ -7542,7 +7548,7 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, b
bonus -= 30;
if (sc->data[SC_HALLUCINATIONWALK_POSTDELAY])
bonus -= 50;
if (sc->data[SC_PARALYSE])
if (sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 1)
bonus -= 10;
if (sc->data[SC__BODYPAINT])
bonus -= 5 * sc->data[SC__BODYPAINT]->val1;
@ -7742,7 +7748,7 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change *
aspd_rate += 300;
if( sc->data[SC_HALLUCINATIONWALK_POSTDELAY] )
aspd_rate += 500;
if( sc->data[SC_PARALYSE] )
if( sc->data[SC_PARALYSE] && sc->data[SC_PARALYSE]->val3 == 1 )
aspd_rate += 100;
if( sc->data[SC__BODYPAINT] )
aspd_rate += 50 * sc->data[SC__BODYPAINT]->val1;
@ -8549,8 +8555,9 @@ static int status_get_sc_interval(enum sc_type type)
{
switch (type) {
case SC_POISON:
case SC_DPOISON:
case SC_LEECHESEND:
case SC_DPOISON:
case SC_DEATHHURT:
return 1000;
case SC_BURNING:
case SC_PYREXIA:
@ -8765,10 +8772,11 @@ t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_
tick_def2 = (status->vit + status->dex)*50;
break;
case SC_OBLIVIONCURSE: // 100% - (100 - 0.8 x INT)
sc_def = status->int_*80;
sc_def = status->int_ * 80;
sc_def = max(sc_def, 500); // minimum of 5% resist
tick_def = 0;
//Fall through
tick_def2 = (status->vit + status->luk) * 500;
break;
case SC_TOXIN:
case SC_PARALYSE:
case SC_VENOMBLEED:
@ -8853,6 +8861,19 @@ t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_
#endif
else if (sc->data[SC_SHIELDSPELL_REF] && sc->data[SC_SHIELDSPELL_REF]->val1 == 2)
sc_def += sc->data[SC_SHIELDSPELL_REF]->val3*100;
else if (sc->data[SC_LEECHESEND] && sc->data[SC_LEECHESEND]->val3 == 0) {
switch (type) {
case SC_BLIND:
case SC_STUN:
return 0; // Immune
}
} else if (sc->data[SC_OBLIVIONCURSE] && sc->data[SC_OBLIVIONCURSE]->val3 == 0) {
switch (type) {
case SC_SILENCE:
case SC_CURSE:
return 0; // Immune
}
}
}
// When tick def not set, reduction is the same for both.
@ -9497,12 +9518,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_PYREXIA:
case SC_OBLIVIONCURSE:
case SC_LEECHESEND:
{ // It doesn't stack or even renew
int i = SC_TOXIN;
for(; i<= SC_LEECHESEND; i++)
if(sc->data[i]) return 0;
for (int32 i = SC_TOXIN; i <= SC_LEECHESEND; i++) {
if (sc->data[i] && sc->data[i]->val3 == 1) // It doesn't stack or even renew on the target
return 0;
else if (sc->data[i] && sc->data[i]->val3 == 0)
status_change_end(bl, static_cast<sc_type>(i), INVALID_TIMER); // End the bonus part on the caster
}
break;
break;
case SC_SATURDAYNIGHTFEVER:
if (sc->data[SC_BERSERK] || sc->data[SC_INSPIRATION])
return 0;
@ -10248,8 +10270,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
#ifndef RENEWAL
val3 = 50*(val1+1); // Damage increase (+50 +50*lv%)
#endif
if( sd )// [Ind] - iROwiki says each level increases its duration by 3 seconds
tick += pc_checkskill(sd,GC_RESEARCHNEWPOISON)*3000;
if (sd) {
uint16 poison_level = pc_checkskill(sd, GC_RESEARCHNEWPOISON);
if (poison_level > 0) {
tick += 30000; // Base of 30 seconds
tick += poison_level * 15 * 1000; // Additional 15 seconds per level
}
}
break;
case SC_POISONREACT:
val2=(val1+1)/2 + val1/10; // Number of counters [Skotlex]
@ -10522,18 +10550,46 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_POISON:
case SC_BLEEDING:
case SC_BURNING:
case SC_TOXIN:
case SC_MAGICMUSHROOM:
case SC_LEECHESEND:
tick_time = status_get_sc_interval(type);
val4 = tick-tick_time; // Remaining time
val4 = tick - tick_time; // Remaining time
break;
case SC_PYREXIA:
//Causes blind for duration of pyrexia, unreducable and unavoidable, but can be healed with e.g. green potion
status_change_start(src,bl,SC_BLIND,10000,val1,0,0,0,tick,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
case SC_TOXIN:
if (val3 == 1) // Target
tick_time = status_get_sc_interval(type);
else // Caster
tick_time = 1000;
val4 = tick - tick_time; // Remaining time
break;
case SC_DEATHHURT:
if (val3 == 1)
break;
tick_time = status_get_sc_interval(type);
val4 = tick-tick_time; // Remaining time
val4 = tick - tick_time; // Remaining time
case SC_LEECHESEND:
if (val3 == 0)
break;
tick_time = status_get_sc_interval(type);
val4 = tick - tick_time; // Remaining time
break;
case SC_PYREXIA:
if (val3 == 1) { // Target
// Causes blind for duration of pyrexia, unreducable and unavoidable, but can be healed with e.g. green potion
status_change_start(src, bl, SC_BLIND, 10000, val1, 0, 0, 0, tick, SCSTART_NOAVOID | SCSTART_NOTICKDEF | SCSTART_NORATEDEF);
tick_time = status_get_sc_interval(type);
val4 = tick - tick_time; // Remaining time
} else // Caster
val2 = 15; // CRIT % and ATK % increase
break;
case SC_VENOMBLEED:
if (val3 == 0) // Caster
val2 = 30; // Reflect damage % reduction
break;
case SC_MAGICMUSHROOM:
if (val3 == 1) { // Target
tick_time = status_get_sc_interval(type);
val4 = tick - tick_time; // Remaining time
} else // Caster
val2 = 10; // After-cast delay % reduction
break;
case SC_CONFUSION:
@ -11175,6 +11231,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
tick_time = 5000; // [GodLesZ] tick time
break;
case SC_OBLIVIONCURSE:
if (val3 == 0)
break;
val4 = tick / 3000;
tick_time = 3000; // [GodLesZ] tick time
break;
@ -11759,7 +11817,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 = 20 * val1 + 20; // atk bonus
break;
case SC_DARKCROW:
val2 = 30 * val1;
val2 = 30 * val1; // ATK bonus
break;
case SC_UNLIMIT:
val2 = 50 * val1;
@ -12098,11 +12156,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_BLEEDING:
case SC_BURNING:
case SC_TOXIN:
tick_time = tick;
tick = tick_time + max(val4, 0);
break;
case SC_DEATHHURT:
if (val3 == 1)
break;
tick_time = tick;
tick = tick_time + max(val4, 0);
case SC_MAGICMUSHROOM:
case SC_PYREXIA:
case SC_LEECHESEND:
if (val3 == 0)
break;
tick_time = tick;
tick = tick_time + max(val4,0);
tick = tick_time + max(val4, 0);
break;
case SC_SWORDCLAN:
case SC_ARCWANDCLAN:
@ -13861,12 +13929,19 @@ TIMER_FUNC(status_change_timer){
status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, 0, 1, damage, 1, DMG_NORMAL, 0, false),0);
}
break;
case SC_TOXIN:
if (sce->val4 >= 0) { // Damage is every 10 seconds including 3%sp drain.
map_freeblock_lock();
dounlock = true;
status_damage(bl, bl, 1, status->max_sp * 3 / 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 1, 1, DMG_NORMAL, 0, false), 0, 0);
if (sce->val3 == 1) { // Target
map_freeblock_lock();
dounlock = true;
status_damage(bl, bl, 1, status->max_sp * 3 / 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 1, 1, DMG_NORMAL, 0, false), 0, 0);
} else { // Caster
interval = 1000; // Assign here since status_get_sc_internval() contains the target interval.
if (status->sp < status->max_sp)
status_heal(bl, 0, (int)status->max_sp * 1 / 100, 1);
}
}
break;
@ -13914,7 +13989,7 @@ TIMER_FUNC(status_change_timer){
}
}
break;
case SC_PYREXIA:
if (sce->val4 >= 0) {
map_freeblock_lock();
@ -13922,7 +13997,7 @@ TIMER_FUNC(status_change_timer){
status_fix_damage(bl, bl, 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 100, 1, DMG_NORMAL, 0, false),0);
}
break;
case SC_LEECHESEND:
if (sce->val4 >= 0) {
int64 damage = status->vit * (sce->val1 - 3) + (int)status->max_hp / 100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100)
@ -13933,6 +14008,13 @@ TIMER_FUNC(status_change_timer){
}
break;
case SC_DEATHHURT:
if (sce->val4 >= 0) {
if (status->hp < status->max_hp)
status_heal(bl, (int)status->max_hp * 1 / 100, 0, 1);
}
break;
case SC_TENSIONRELAX:
if(status->max_hp > status->hp && --(sce->val3) >= 0) {
sc_timer_next(10000 + tick);
@ -14116,7 +14198,7 @@ TIMER_FUNC(status_change_timer){
sc_timer_next(10000+tick);
}
break;
case SC_OBLIVIONCURSE:
if( --(sce->val4) >= 0 ) {
clif_emotion(bl,ET_QUESTION);

View File

@ -89,7 +89,7 @@ std::unordered_map<uint16, s_skill_db> skill_nearnpc;
// Forward declaration of conversion functions
static bool guild_read_guildskill_tree_db( char* split[], int columns, int current );
static bool pet_read_db( const char* file );
static bool skill_parse_row_magicmushroomdb(char* split[], int column, int current);
static bool skill_parse_row_magicmushroomdb(char *split[], int column, int current);
static bool skill_parse_row_abradb(char* split[], int columns, int current);
static bool skill_parse_row_spellbookdb(char* split[], int columns, int current);
static bool mob_readdb_mobavail(char *str[], int columns, int current);
@ -312,7 +312,7 @@ int do_init( int argc, char** argv ){
return 0;
}
if (!process("MAGIC_MUSHROOM_DB", 1, root_paths, "magicmushroom_db", [](const std::string& path, const std::string& name_ext) -> bool {
if (!process("MAGIC_MUSHROOM_DB", 1, root_paths, "magicmushroom_db", [](const std::string &path, const std::string &name_ext) -> bool {
return sv_readdb(path.c_str(), name_ext.c_str(), ',', 1, 1, -1, &skill_parse_row_magicmushroomdb, false);
})) {
return 0;
@ -865,7 +865,7 @@ static bool pet_read_db( const char* file ){
}
// Copied and adjusted from skill.cpp
static bool skill_parse_row_magicmushroomdb(char* split[], int column, int current)
static bool skill_parse_row_magicmushroomdb(char *split[], int column, int current)
{
uint16 skill_id = atoi(split[0]);
std::string *skill_name = util::umap_find(aegis_skillnames, skill_id);