|
@@ -421,6 +421,8 @@ unsigned short skill_dummy2skill_id(unsigned short skill_id) {
|
|
return RL_R_TRIP;
|
|
return RL_R_TRIP;
|
|
case NPC_MAXPAIN_ATK:
|
|
case NPC_MAXPAIN_ATK:
|
|
return NPC_MAXPAIN;
|
|
return NPC_MAXPAIN;
|
|
|
|
+ case SU_SV_ROOTTWIST_ATK:
|
|
|
|
+ return SU_SV_ROOTTWIST;
|
|
}
|
|
}
|
|
return skill_id;
|
|
return skill_id;
|
|
}
|
|
}
|
|
@@ -483,7 +485,8 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk
|
|
hp *= 2;
|
|
hp *= 2;
|
|
if (sd && ((skill = pc_checkskill(sd, SU_POWEROFSEA)) > 0)) {
|
|
if (sd && ((skill = pc_checkskill(sd, SU_POWEROFSEA)) > 0)) {
|
|
hp += hp * 10 / 100;
|
|
hp += hp * 10 / 100;
|
|
- if (pc_checkskill(sd, SU_TUNABELLY) == 5 && pc_checkskill(sd, SU_TUNAPARTY) == 5 && pc_checkskill(sd, SU_BUNCHOFSHRIMP) == 5 && pc_checkskill(sd, SU_FRESHSHRIMP) == 5)
|
|
|
|
|
|
+ if ((pc_checkskill(sd, SU_TUNABELLY) + pc_checkskill(sd, SU_TUNAPARTY) + pc_checkskill(sd, SU_BUNCHOFSHRIMP) + pc_checkskill(sd, SU_FRESHSHRIMP) +
|
|
|
|
+ pc_checkskill(sd, SU_GROOMING) + pc_checkskill(sd, SU_PURRING) + pc_checkskill(sd, SU_SHRIMPARTY)) > 19)
|
|
hp += hp * 20 / 100;
|
|
hp += hp * 20 / 100;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
@@ -1930,7 +1933,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
|
|
status_change_end(bl, SC_C_MARKER, INVALID_TIMER);
|
|
status_change_end(bl, SC_C_MARKER, INVALID_TIMER);
|
|
break;
|
|
break;
|
|
case SU_SCRATCH:
|
|
case SU_SCRATCH:
|
|
- sc_start2(src, bl, SC_BLEEDING, (skill_lv * 3), skill_lv, src->id, skill_get_time2(skill_id, skill_lv)); // TODO: What's the chance/time?
|
|
|
|
|
|
+ sc_start2(src, bl, SC_BLEEDING, skill_lv * 10 + 70, skill_lv, src->id, skill_get_time(skill_id, skill_lv));
|
|
break;
|
|
break;
|
|
case SU_SV_STEMSPEAR:
|
|
case SU_SV_STEMSPEAR:
|
|
sc_start2(src, bl, SC_BLEEDING, 10, skill_lv, src->id, skill_get_time2(skill_id, skill_lv));
|
|
sc_start2(src, bl, SC_BLEEDING, 10, skill_lv, src->id, skill_get_time2(skill_id, skill_lv));
|
|
@@ -1939,9 +1942,9 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
|
|
if (skill_area_temp[3] == 1)
|
|
if (skill_area_temp[3] == 1)
|
|
sc_start(src, bl, SC_CURSE, 20, skill_lv, skill_get_time2(skill_id, skill_lv));
|
|
sc_start(src, bl, SC_CURSE, 20, skill_lv, skill_get_time2(skill_id, skill_lv));
|
|
break;
|
|
break;
|
|
- //case SU_SCAROFTAROU:
|
|
|
|
- // sc_start(src, bl, SC_STUN, 10, skill_lv, skill_get_time2(skill_id, skill_lv)); // TODO: What's the chance/time?
|
|
|
|
- // break;
|
|
|
|
|
|
+ case SU_SCAROFTAROU:
|
|
|
|
+ sc_start(src, bl, SC_STUN, 10, skill_lv, skill_get_time2(skill_id, skill_lv)); //! TODO: What's the chance/time?
|
|
|
|
+ break;
|
|
case SU_LUNATICCARROTBEAT:
|
|
case SU_LUNATICCARROTBEAT:
|
|
if (skill_area_temp[3] == 1)
|
|
if (skill_area_temp[3] == 1)
|
|
sc_start(src, bl, SC_STUN, 20, skill_lv, skill_get_time2(skill_id, skill_lv));
|
|
sc_start(src, bl, SC_STUN, 20, skill_lv, skill_get_time2(skill_id, skill_lv));
|
|
@@ -2386,6 +2389,13 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (dstsd && !status_isdead(bl) && !(skill_id && skill_get_nk(skill_id)&NK_NO_DAMAGE)) {
|
|
|
|
+ struct status_change *sc = status_get_sc(bl);
|
|
|
|
+
|
|
|
|
+ if (sc && sc->data[SC_DORAM_SVSP] && attack_type&(BF_MAGIC|BF_LONG))
|
|
|
|
+ skill_castend_damage_id(bl, src, SU_SV_STEMSPEAR, (pc_checkskill(dstsd, SU_SV_STEMSPEAR) ? pc_checkskill(dstsd, SU_SV_STEMSPEAR) : 1), tick, 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
// Trigger counter-spells to retaliate against damage causing skills.
|
|
// Trigger counter-spells to retaliate against damage causing skills.
|
|
if(dstsd && !status_isdead(bl) && dstsd->autospell2[0].id &&
|
|
if(dstsd && !status_isdead(bl) && dstsd->autospell2[0].id &&
|
|
!(skill_id && skill_get_nk(skill_id)&NK_NO_DAMAGE))
|
|
!(skill_id && skill_get_nk(skill_id)&NK_NO_DAMAGE))
|
|
@@ -2676,8 +2686,12 @@ short skill_blown(struct block_list* src, struct block_list* target, char count,
|
|
dy = -diry[dir];
|
|
dy = -diry[dir];
|
|
}
|
|
}
|
|
|
|
|
|
- if (tsc && tsc->data[SC_SU_STOOP]) // Any knockback will cancel it.
|
|
|
|
- status_change_end(target, SC_SU_STOOP, INVALID_TIMER);
|
|
|
|
|
|
+ if (tsc) {
|
|
|
|
+ if (tsc->data[SC_SU_STOOP]) // Any knockback will cancel it.
|
|
|
|
+ status_change_end(target, SC_SU_STOOP, INVALID_TIMER);
|
|
|
|
+ if (tsc->data[SC_SV_ROOTTWIST]) // Shouldn't move.
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
|
|
return unit_blown(target, dx, dy, count, flag); // Send over the proper flag
|
|
return unit_blown(target, dx, dy, count, flag); // Send over the proper flag
|
|
}
|
|
}
|
|
@@ -3386,6 +3400,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
|
|
case KO_BAKURETSU:
|
|
case KO_BAKURETSU:
|
|
case GN_CRAZYWEED_ATK:
|
|
case GN_CRAZYWEED_ATK:
|
|
case NC_MAGMA_ERUPTION:
|
|
case NC_MAGMA_ERUPTION:
|
|
|
|
+ case SU_SV_ROOTTWIST_ATK:
|
|
dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,-1,DMG_SPLASH);
|
|
dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,-1,DMG_SPLASH);
|
|
break;
|
|
break;
|
|
case GN_FIRE_EXPANSION_ACID:
|
|
case GN_FIRE_EXPANSION_ACID:
|
|
@@ -4179,6 +4194,16 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
|
|
if (target->type == BL_PC)
|
|
if (target->type == BL_PC)
|
|
sc_start(src, target, SC_SITDOWN_FORCE, 100, skl->skill_lv, skill_get_time(skl->skill_id, skl->skill_lv));
|
|
sc_start(src, target, SC_SITDOWN_FORCE, 100, skl->skill_lv, skill_get_time(skl->skill_id, skl->skill_lv));
|
|
break;
|
|
break;
|
|
|
|
+ case SU_SV_ROOTTWIST_ATK: {
|
|
|
|
+ struct status_change *tsc = status_get_sc(target);
|
|
|
|
+
|
|
|
|
+ if (tsc && tsc->data[SC_SV_ROOTTWIST]) {
|
|
|
|
+ if (check_distance_bl(src, target, 32)) // Only damage if caster is within 32x32 area
|
|
|
|
+ skill_attack(skl->type, src, target, target, skl->skill_id, skl->skill_lv, tick, skl->flag);
|
|
|
|
+ skill_addtimerskill(src, tick + 1000, target->id, 0, 0, skl->skill_id, skl->skill_lv, skl->type, skl->flag);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
|
|
skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
|
|
break;
|
|
break;
|
|
@@ -4857,9 +4882,15 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
|
|
clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
|
|
clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
|
|
case SU_BITE:
|
|
case SU_BITE:
|
|
skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
|
|
skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
|
|
- if (status_get_lv(src) >= 30 && (rnd() % 100 < (int)(status_get_lv(src) / 30) + 10)) // TODO: Need activation chance.
|
|
|
|
|
|
+ if (status_get_lv(src) > 29 && (rnd() % 100 < (int)((status_get_lv(src) / 30) * 10 + 10)))
|
|
skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag);
|
|
skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag);
|
|
break;
|
|
break;
|
|
|
|
+ case SU_SVG_SPIRIT:
|
|
|
|
+ skill_area_temp[1] = bl->id;
|
|
|
|
+ map_foreachinpath(skill_attack_area, src->m, src->x, src->y, bl->x, bl->y,
|
|
|
|
+ skill_get_splash(skill_id, skill_lv), skill_get_maxcount(skill_id, skill_lv), splash_target(src),
|
|
|
|
+ skill_get_type(skill_id), src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY);
|
|
|
|
+ break;
|
|
|
|
|
|
//Splash attack skills.
|
|
//Splash attack skills.
|
|
case AS_GRIMTOOTH:
|
|
case AS_GRIMTOOTH:
|
|
@@ -4941,7 +4972,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
|
|
clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1);
|
|
clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1);
|
|
status_heal(src,heal,0,0);
|
|
status_heal(src,heal,0,0);
|
|
}
|
|
}
|
|
- if (skill_id == SU_SCRATCH && status_get_lv(src) >= 30 && (rnd() % 100 < (int)(status_get_lv(src) / 30) + 10)) // TODO: Need activation chance.
|
|
|
|
|
|
+ if (skill_id == SU_SCRATCH && status_get_lv(src) > 29 && (rnd() % 100 < (int)((status_get_lv(src) / 30) * 10 + 10)))
|
|
skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag);
|
|
skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag);
|
|
} else {
|
|
} else {
|
|
int starget = BL_CHAR|BL_SKILL;
|
|
int starget = BL_CHAR|BL_SKILL;
|
|
@@ -5971,11 +6002,16 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
|
|
break;
|
|
break;
|
|
|
|
|
|
case SU_SCAROFTAROU:
|
|
case SU_SCAROFTAROU:
|
|
- sc_start(src, bl, status_skill2sc(skill_id), 10, skill_lv, skill_get_time(skill_id, skill_lv)); // TODO: What's the activation chance for the Bite effect?
|
|
|
|
case SU_SV_STEMSPEAR:
|
|
case SU_SV_STEMSPEAR:
|
|
|
|
+ if (skill_id == SU_SCAROFTAROU)
|
|
|
|
+ sc_start(src, bl, status_skill2sc(skill_id), 10, skill_lv, skill_get_time(skill_id, skill_lv)); //! TODO: What's the activation chance for the Bite effect?
|
|
|
|
+ else {
|
|
|
|
+ if (sd && pc_checkskill(sd, SU_SPIRITOFLAND))
|
|
|
|
+ sc_start(src, src, SC_DORAM_WALKSPEED, 100, 50, skill_get_time(SU_SPIRITOFLAND, 1));
|
|
|
|
+ }
|
|
skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
|
|
skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
|
|
- if (status_get_lv(src) >= 30 && (rnd() % 100 < (int)(status_get_lv(src) / 30) + 10)) // TODO: Need activation chance.
|
|
|
|
- skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, (skill_id == SU_SV_STEMSPEAR) ? BF_MAGIC : BF_WEAPON, flag);
|
|
|
|
|
|
+ if (status_get_lv(src) > 29 && (rnd() % 100 < (int)((status_get_lv(src) / 30) * 10 + 10)))
|
|
|
|
+ skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, skill_get_type(skill_id), flag);
|
|
break;
|
|
break;
|
|
|
|
|
|
case 0:/* no skill - basic/normal attack */
|
|
case 0:/* no skill - basic/normal attack */
|
|
@@ -6559,6 +6595,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
|
|
case PR_KYRIE:
|
|
case PR_KYRIE:
|
|
case MER_KYRIE:
|
|
case MER_KYRIE:
|
|
case SU_TUNAPARTY:
|
|
case SU_TUNAPARTY:
|
|
|
|
+ case SU_GROOMING:
|
|
|
|
+ case SU_CHATTERING:
|
|
clif_skill_nodamage(bl,bl,skill_id,skill_lv,
|
|
clif_skill_nodamage(bl,bl,skill_id,skill_lv,
|
|
sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)));
|
|
sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)));
|
|
break;
|
|
break;
|
|
@@ -6682,11 +6720,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
|
|
sc_start(src, bl, type, skill_lv*20, skill_lv, skill_get_time2(skill_id, skill_lv)));
|
|
sc_start(src, bl, type, skill_lv*20, skill_lv, skill_get_time2(skill_id, skill_lv)));
|
|
break;
|
|
break;
|
|
|
|
|
|
- case SU_STOOP:
|
|
|
|
- clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
|
|
|
|
- sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
case KN_AUTOCOUNTER:
|
|
case KN_AUTOCOUNTER:
|
|
sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv));
|
|
sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv));
|
|
skill_addtimerskill(src,tick + 100,bl->id,0,0,skill_id,skill_lv,BF_WEAPON,flag);
|
|
skill_addtimerskill(src,tick + 100,bl->id,0,0,skill_id,skill_lv,BF_WEAPON,flag);
|
|
@@ -10806,26 +10839,70 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
|
|
sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
|
sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
+ case SU_STOOP:
|
|
|
|
+ clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
|
|
|
|
+ sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SU_SV_ROOTTWIST:
|
|
|
|
+ clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
|
|
|
|
+ if (sd && status_get_class_(bl) == CLASS_BOSS) {
|
|
|
|
+ clif_skill_fail(sd, skill_id, USESKILL_FAIL_TOTARGET, 0);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (tsc->count && tsc->data[type]) // Refresh the status only if it's already active.
|
|
|
|
+ sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
|
|
|
+ else {
|
|
|
|
+ sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
|
|
|
+ if (sd && pc_checkskill(sd, SU_SPIRITOFLAND))
|
|
|
|
+ sc_start(src, src, SC_DORAM_MATK, 100, sd->status.base_level, skill_get_time(SU_SPIRITOFLAND, 1));
|
|
|
|
+ skill_addtimerskill(src, tick + 1000, bl->id, 0, 0, SU_SV_ROOTTWIST_ATK, skill_lv, skill_get_type(SU_SV_ROOTTWIST_ATK), flag);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
case SU_TUNABELLY:
|
|
case SU_TUNABELLY:
|
|
{
|
|
{
|
|
- unsigned int heal;
|
|
|
|
|
|
+ unsigned int heal = 0;
|
|
|
|
|
|
if (dstmd && (dstmd->mob_id == MOBID_EMPERIUM || status_get_class_(bl) == CLASS_BATTLEFIELD))
|
|
if (dstmd && (dstmd->mob_id == MOBID_EMPERIUM || status_get_class_(bl) == CLASS_BATTLEFIELD))
|
|
heal = 0;
|
|
heal = 0;
|
|
- else {
|
|
|
|
|
|
+ else if (status_get_hp(bl) != status_get_max_hp(bl))
|
|
heal = ((2 * skill_lv - 1) * 10) * status_get_max_hp(bl) / 100;
|
|
heal = ((2 * skill_lv - 1) * 10) * status_get_max_hp(bl) / 100;
|
|
- status_heal(bl, heal, 0, 0);
|
|
|
|
- }
|
|
|
|
|
|
+ status_heal(bl, heal, 0, 1|2|4);
|
|
|
|
|
|
- clif_skill_nodamage(src, bl, skill_id, heal, 1);
|
|
|
|
|
|
+ clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
|
|
|
|
case SU_BUNCHOFSHRIMP:
|
|
case SU_BUNCHOFSHRIMP:
|
|
- if (sd == NULL || sd->status.party_id == 0 || flag&1)
|
|
|
|
- clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)));
|
|
|
|
- else if (sd)
|
|
|
|
|
|
+ case SU_HISS:
|
|
|
|
+ case SU_PURRING:
|
|
|
|
+ case SU_SHRIMPARTY:
|
|
|
|
+ case SU_MEOWMEOW:
|
|
|
|
+ if (sd == NULL || sd->status.party_id == 0 || flag&1) {
|
|
|
|
+ int duration = skill_get_time(skill_id, skill_lv);
|
|
|
|
+
|
|
|
|
+ if (skill_id == SU_BUNCHOFSHRIMP && pc_checkskill(sd, SU_SPIRITOFSEA))
|
|
|
|
+ duration += skill_get_time2(SU_BUNCHOFSHRIMP, skill_lv);
|
|
|
|
+ clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, duration));
|
|
|
|
+ } else if (sd) {
|
|
|
|
+ if (skill_id == SU_SHRIMPARTY)
|
|
|
|
+ sc_start(src, bl, SC_SHRIMPBLESSING, 100, skill_lv, skill_get_time2(skill_id, skill_lv));
|
|
party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
|
|
party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SU_POWEROFFLOCK:
|
|
|
|
+ if (flag&1) {
|
|
|
|
+ sc_start(src, bl, SC_FEAR, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
|
|
|
+ sc_start(src, bl, SC_FREEZE, 100, skill_lv, skill_get_time2(skill_id, skill_lv)); //! TODO: What's the duration?
|
|
|
|
+ } else {
|
|
|
|
+ clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
|
|
|
|
+ if (battle_config.skill_wall_check)
|
|
|
|
+ map_foreachinshootrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
|
|
|
|
+ else
|
|
|
|
+ map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
|
|
|
|
default:
|
|
default:
|
|
@@ -11091,7 +11168,6 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data)
|
|
case GN_WALLOFTHORN:
|
|
case GN_WALLOFTHORN:
|
|
case SC_ESCAPE:
|
|
case SC_ESCAPE:
|
|
case SU_CN_POWDERING:
|
|
case SU_CN_POWDERING:
|
|
- case SU_SV_ROOTTWIST:
|
|
|
|
ud->skillx = target->x;
|
|
ud->skillx = target->x;
|
|
ud->skilly = target->y;
|
|
ud->skilly = target->y;
|
|
ud->skilltimer = tid;
|
|
ud->skilltimer = tid;
|
|
@@ -11647,8 +11723,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
|
|
case MH_XENO_SLASHER:
|
|
case MH_XENO_SLASHER:
|
|
case LG_KINGS_GRACE:
|
|
case LG_KINGS_GRACE:
|
|
case RL_B_TRAP:
|
|
case RL_B_TRAP:
|
|
- case SU_CN_POWDERING:
|
|
|
|
- case SU_SV_ROOTTWIST:
|
|
|
|
flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete).
|
|
flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete).
|
|
case GS_GROUNDDRIFT: //Ammo should be deleted right away.
|
|
case GS_GROUNDDRIFT: //Ammo should be deleted right away.
|
|
case GN_WALLOFTHORN:
|
|
case GN_WALLOFTHORN:
|
|
@@ -11695,16 +11769,31 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
|
|
skill_unitsetting(src,skill_id,skill_lv,x,y,0);
|
|
skill_unitsetting(src,skill_id,skill_lv,x,y,0);
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
+ case SU_CN_POWDERING:
|
|
|
|
+ case SU_NYANGGRASS:
|
|
|
|
+ if (sd && pc_checkskill(sd, SU_SPIRITOFLAND)) {
|
|
|
|
+ if (skill_id == SU_CN_POWDERING)
|
|
|
|
+ sc_start(src, src, SC_DORAM_FLEE2, 100, sd->status.base_level / 12, skill_get_time(SU_SPIRITOFLAND, 1));
|
|
|
|
+ else
|
|
|
|
+ sc_start(src, src, SC_DORAM_MATK, 100, sd->status.base_level, skill_get_time(SU_SPIRITOFLAND, 1));
|
|
|
|
+ }
|
|
|
|
+ flag |= 1;
|
|
|
|
+ skill_unitsetting(src, skill_id, skill_lv, x, y, 0);
|
|
|
|
+ break;
|
|
|
|
+
|
|
case WZ_METEOR:
|
|
case WZ_METEOR:
|
|
case SU_CN_METEOR: {
|
|
case SU_CN_METEOR: {
|
|
int area = skill_get_splash(skill_id, skill_lv);
|
|
int area = skill_get_splash(skill_id, skill_lv);
|
|
short tmpx = 0, tmpy = 0;
|
|
short tmpx = 0, tmpy = 0;
|
|
if (sd && skill_id == SU_CN_METEOR) {
|
|
if (sd && skill_id == SU_CN_METEOR) {
|
|
short item_idx = pc_search_inventory(sd, ITEMID_CATNIP_FRUIT);
|
|
short item_idx = pc_search_inventory(sd, ITEMID_CATNIP_FRUIT);
|
|
|
|
+
|
|
if (item_idx >= 0) {
|
|
if (item_idx >= 0) {
|
|
pc_delitem(sd, item_idx, 1, 0, 1, LOG_TYPE_CONSUME);
|
|
pc_delitem(sd, item_idx, 1, 0, 1, LOG_TYPE_CONSUME);
|
|
flag |= 1;
|
|
flag |= 1;
|
|
}
|
|
}
|
|
|
|
+ if (pc_checkskill(sd, SU_SPIRITOFLAND))
|
|
|
|
+ sc_start(src, src, SC_DORAM_SVSP, 100, 100, skill_get_time(SU_SPIRITOFLAND, 1));
|
|
}
|
|
}
|
|
for (i = 1; i <= skill_get_time(skill_id, skill_lv)/skill_get_unit_interval(skill_id); i++) {
|
|
for (i = 1; i <= skill_get_time(skill_id, skill_lv)/skill_get_unit_interval(skill_id); i++) {
|
|
// Creates a random Cell in the Splash Area
|
|
// Creates a random Cell in the Splash Area
|
|
@@ -12230,16 +12319,25 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
|
|
skill_addtimerskill(src,gettick()+500,0,x,y,skill_id,skill_lv,BF_MISC,flag);
|
|
skill_addtimerskill(src,gettick()+500,0,x,y,skill_id,skill_lv,BF_MISC,flag);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
-
|
|
|
|
case SU_LOPE:
|
|
case SU_LOPE:
|
|
- if (map[src->m].flag.noteleport && !(map[src->m].flag.battleground || map_flag_gvg2(src->m))) {
|
|
|
|
- x = src->x;
|
|
|
|
- y = src->y;
|
|
|
|
- }
|
|
|
|
- clif_skill_nodamage(src, src, SU_LOPE, skill_lv, 1);
|
|
|
|
- if (!map_count_oncell(src->m, x, y, BL_PC|BL_NPC|BL_MOB, 0) && path_search(NULL, src->m, src->x, src->y, x, y, 1, CELL_CHKNOREACH)) {
|
|
|
|
- clif_slide(src, x, y);
|
|
|
|
- unit_movepos(src, x, y, 1, 0);
|
|
|
|
|
|
+ {
|
|
|
|
+ uint8 dir = map_calc_dir(src, x, y);
|
|
|
|
+
|
|
|
|
+ // Fails on noteleport maps, except for GvG and BG maps
|
|
|
|
+ if (map[src->m].flag.noteleport && !(map[src->m].flag.battleground || map_flag_gvg2(src->m))) {
|
|
|
|
+ x = src->x;
|
|
|
|
+ y = src->y;
|
|
|
|
+ } else if (dir%2) { // Diagonal
|
|
|
|
+ x += dirx[dir] * (skill_lv * 4) / 3;
|
|
|
|
+ y += diry[dir] * (skill_lv * 4) / 3;
|
|
|
|
+ } else {
|
|
|
|
+ x += dirx[dir] * skill_lv * 2;
|
|
|
|
+ y += diry[dir] * skill_lv * 2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clif_skill_nodamage(src, src, skill_id, skill_lv, 1);
|
|
|
|
+ if (!map_count_oncell(src->m, x, y, BL_PC|BL_NPC|BL_MOB, 0) && map_getcell(src->m, x, y, CELL_CHKREACH) && unit_movepos(src, x, y, 1, 0))
|
|
|
|
+ clif_blown(src);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -13383,6 +13481,11 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, un
|
|
sc_start(ss, bl, type, 100, sg->skill_lv, skill_get_time(sg->skill_id, sg->skill_lv));
|
|
sc_start(ss, bl, type, 100, sg->skill_lv, skill_get_time(sg->skill_id, sg->skill_lv));
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
+ case UNT_NYANGGRASS:
|
|
|
|
+ if (!sce)
|
|
|
|
+ sc_start(ss, bl, type, 100, sg->skill_lv, skill_get_time(sg->skill_id, sg->skill_lv));
|
|
|
|
+ break;
|
|
|
|
+
|
|
case UNT_GD_LEADERSHIP:
|
|
case UNT_GD_LEADERSHIP:
|
|
case UNT_GD_GLORYWOUNDS:
|
|
case UNT_GD_GLORYWOUNDS:
|
|
case UNT_GD_SOULCOLD:
|
|
case UNT_GD_SOULCOLD:
|
|
@@ -14124,28 +14227,6 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, uns
|
|
skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,SD_ANIMATION|SD_SPLASH),
|
|
skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,SD_ANIMATION|SD_SPLASH),
|
|
1,sg->skill_id,sg->skill_lv,DMG_SKILL);
|
|
1,sg->skill_id,sg->skill_lv,DMG_SKILL);
|
|
break;
|
|
break;
|
|
-
|
|
|
|
- case UNT_SV_ROOTTWIST:
|
|
|
|
- if (status_bl_has_mode(bl,MD_STATUS_IMMUNE))
|
|
|
|
- break;
|
|
|
|
- if (tsc) {
|
|
|
|
- if (!sg->val2) {
|
|
|
|
- int sec = skill_get_time(sg->skill_id, sg->skill_lv);
|
|
|
|
-
|
|
|
|
- if (sc_start2(ss, bl, type, 100, sg->skill_lv, sg->group_id, sec)) {
|
|
|
|
- const struct TimerData* td = tsc->data[type]?get_timer(tsc->data[type]->timer):NULL;
|
|
|
|
-
|
|
|
|
- if(td)
|
|
|
|
- sec = DIFF_TICK(td->tick, tick);
|
|
|
|
- clif_fixpos(bl);
|
|
|
|
- sg->val2 = bl->id;
|
|
|
|
- } else // Couldn't trap it?
|
|
|
|
- sec = 7000;
|
|
|
|
- sg->limit = DIFF_TICK(tick, sg->tick) + sec;
|
|
|
|
- } else if (tsc->data[type] && bl->id == sg->val2)
|
|
|
|
- skill_attack(skill_get_type(SU_SV_ROOTTWIST_ATK), ss, &unit->bl, bl, SU_SV_ROOTTWIST_ATK, sg->skill_lv, tick, SD_LEVEL|SD_ANIMATION);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (bl->type == BL_MOB && ss != bl)
|
|
if (bl->type == BL_MOB && ss != bl)
|
|
@@ -14293,6 +14374,7 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, unsigned int tick)
|
|
case LG_KINGS_GRACE:
|
|
case LG_KINGS_GRACE:
|
|
case NC_STEALTHFIELD:
|
|
case NC_STEALTHFIELD:
|
|
case NC_NEUTRALBARRIER:
|
|
case NC_NEUTRALBARRIER:
|
|
|
|
+ case SU_NYANGGRASS:
|
|
if (sce)
|
|
if (sce)
|
|
status_change_end(bl, type, INVALID_TIMER);
|
|
status_change_end(bl, type, INVALID_TIMER);
|
|
break;
|
|
break;
|
|
@@ -20563,7 +20645,6 @@ int skill_disable_check(struct status_change *sc, uint16 skill_id)
|
|
case KO_YAMIKUMO:
|
|
case KO_YAMIKUMO:
|
|
case RA_WUGDASH:
|
|
case RA_WUGDASH:
|
|
case RA_CAMOUFLAGE:
|
|
case RA_CAMOUFLAGE:
|
|
- case SU_HIDE:
|
|
|
|
if( sc->data[status_skill2sc(skill_id)] )
|
|
if( sc->data[status_skill2sc(skill_id)] )
|
|
return 1;
|
|
return 1;
|
|
break;
|
|
break;
|
|
@@ -20603,6 +20684,8 @@ int skill_get_elemental_type( uint16 skill_id , uint16 skill_lv ) {
|
|
* @return True:If unit can be moved, False:If check on flags are met or unit cannot be moved.
|
|
* @return True:If unit can be moved, False:If check on flags are met or unit cannot be moved.
|
|
**/
|
|
**/
|
|
static bool skill_check_unit_movepos(uint8 check_flag, struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath) {
|
|
static bool skill_check_unit_movepos(uint8 check_flag, struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath) {
|
|
|
|
+ struct status_change *sc;
|
|
|
|
+
|
|
nullpo_retr(false, bl);
|
|
nullpo_retr(false, bl);
|
|
|
|
|
|
if (check_flag&1 && map[bl->m].flag.battleground)
|
|
if (check_flag&1 && map[bl->m].flag.battleground)
|
|
@@ -20612,6 +20695,10 @@ static bool skill_check_unit_movepos(uint8 check_flag, struct block_list *bl, sh
|
|
if (check_flag&4 && map_flag_gvg2(bl->m))
|
|
if (check_flag&4 && map_flag_gvg2(bl->m))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
|
+ sc = status_get_sc(bl);
|
|
|
|
+ if (sc && sc->data[SC_SV_ROOTTWIST])
|
|
|
|
+ return false;
|
|
|
|
+
|
|
return unit_movepos(bl, dst_x, dst_y, easy, checkpath);
|
|
return unit_movepos(bl, dst_x, dst_y, easy, checkpath);
|
|
}
|
|
}
|
|
|
|
|