summaryrefslogtreecommitdiff
path: root/src/map/skill.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/skill.c')
-rw-r--r--src/map/skill.c659
1 files changed, 364 insertions, 295 deletions
diff --git a/src/map/skill.c b/src/map/skill.c
index 612b205e9..c744dbde4 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -2,46 +2,48 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
-#include "../common/cbasetypes.h"
-#include "../common/timer.h"
-#include "../common/nullpo.h"
-#include "../common/malloc.h"
-#include "../common/random.h"
-#include "../common/showmsg.h"
-#include "../common/strlib.h"
-#include "../common/utils.h"
-#include "../common/ers.h"
+#define HERCULES_CORE
-#include "map.h"
-#include "path.h"
-#include "clif.h"
-#include "pc.h"
-#include "status.h"
+#include "../config/core.h" // DBPATH, MAGIC_REFLECTION_TYPE, OFFICIAL_WALKPATH, RENEWAL, RENEWAL_CAST, VARCAST_REDUCTION()
#include "skill.h"
-#include "pet.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "battle.h"
+#include "battleground.h"
+#include "chrif.h"
+#include "clif.h"
+#include "date.h"
+#include "elemental.h"
+#include "guild.h"
#include "homunculus.h"
+#include "intif.h"
+#include "itemdb.h"
+#include "log.h"
+#include "map.h"
#include "mercenary.h"
-#include "elemental.h"
#include "mob.h"
#include "npc.h"
-#include "battle.h"
-#include "battleground.h"
#include "party.h"
-#include "itemdb.h"
+#include "path.h"
+#include "pc.h"
+#include "pet.h"
#include "script.h"
-#include "intif.h"
-#include "log.h"
-#include "chrif.h"
-#include "guild.h"
-#include "date.h"
+#include "status.h"
#include "unit.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <math.h>
-
+#include "../common/cbasetypes.h"
+#include "../common/ers.h"
+#include "../common/malloc.h"
+#include "../common/nullpo.h"
+#include "../common/random.h"
+#include "../common/showmsg.h"
+#include "../common/strlib.h"
+#include "../common/timer.h"
+#include "../common/utils.h"
#define SKILLUNITTIMER_INTERVAL 100
@@ -541,23 +543,6 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
return 1;
}
break;
- case BS_GREED:
- case WS_CARTBOOST:
- case BS_HAMMERFALL:
- case BS_ADRENALINE:
- case MC_CARTREVOLUTION:
- case MC_MAMMONITE:
- case WS_MELTDOWN:
- case MG_SIGHT:
- case TF_HIDING:
- /**
- * These skills cannot be used while in mado gear (credits to Xantara)
- **/
- if( pc_ismadogear(sd) ) {
- clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR_RIDE,0);
- return 1;
- }
- break;
case SC_MANHOLE:
case WM_SOUND_OF_DESTRUCTION:
@@ -585,12 +570,12 @@ int skillnotok_hom(uint16 skill_id, struct homun_data *hd)
return 1;
switch(skill_id){
case MH_LIGHT_OF_REGENE:
- if(hd->homunculus.intimacy <= 75000) //if not cordial
- return 1;
- break;
- case MH_OVERED_BOOST:
- if(hd->homunculus.hunger <= 1) //if we starving
- return 1;
+ if( homun->get_intimacy_grade(hd) != 4 ){
+ if( hd->master )
+ clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_RELATIONGRADE, 0);
+ return 1;
+ }
+ break;
case MH_GOLDENE_FERSE: //can be used with angriff
if(hd->sc.data[SC_ANGRIFFS_MODUS])
return 1;
@@ -760,15 +745,18 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
// Chance to trigger Taekwon kicks [Dralnu]
if(sc && !sc->data[SC_COMBOATTACK]) {
if(sc->data[SC_STORMKICK_READY] &&
- sc_start(src,src,SC_COMBOATTACK, 15, TK_STORMKICK,
+ sc_start4(src,src,SC_COMBOATTACK, 15, TK_STORMKICK,
+ bl->id, 2, 0,
(2000 - 4*sstatus->agi - 2*sstatus->dex)))
; //Stance triggered
else if(sc->data[SC_DOWNKICK_READY] &&
- sc_start(src,src,SC_COMBOATTACK, 15, TK_DOWNKICK,
+ sc_start4(src,src,SC_COMBOATTACK, 15, TK_DOWNKICK,
+ bl->id, 2, 0,
(2000 - 4*sstatus->agi - 2*sstatus->dex)))
; //Stance triggered
else if(sc->data[SC_TURNKICK_READY] &&
- sc_start(src,src,SC_COMBOATTACK, 15, TK_TURNKICK,
+ sc_start4(src,src,SC_COMBOATTACK, 15, TK_TURNKICK,
+ bl->id, 2, 0,
(2000 - 4*sstatus->agi - 2*sstatus->dex)))
; //Stance triggered
else if (sc->data[SC_COUNTERKICK_READY]) { //additional chance from SG_FRIEND [Komurka]
@@ -850,7 +838,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
#ifdef RENEWAL
sc_start(src,bl,SC_FREEZE,65-(5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv));
#else
- //Tharis pointed out that this is normal freeze chance with a base of 300%
+ // [Tharis] pointed out that this is normal freeze chance with a base of 300%
if(tsc->sg_counter >= 3 &&
sc_start(src,bl,SC_FREEZE,300,skill_lv,skill->get_time2(skill_id,skill_lv)))
tsc->sg_counter = 0;
@@ -991,7 +979,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
break;
case NPC_MENTALBREAKER:
{
- //Based on observations by Tharis, Mental Breaker should do SP damage
+ //Based on observations by [Tharis], Mental Breaker should do SP damage
//equal to Matk*skLevel.
rate = status->get_matk(src, 2);
rate*=skill_lv;
@@ -1030,7 +1018,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
sc_start(src,bl,SC_BLIND,100,skill_lv,skill->get_time2(skill_id,skill_lv));
break;
- case LK_HEADCRUSH: //Headcrush has chance of causing Bleeding status, except on demon and undead element
+ case LK_HEADCRUSH: // Headcrush has chance of causing Bleeding status, except on demon and undead element
if (!(battle->check_undead(tstatus->race, tstatus->def_ele) || tstatus->race == RC_DEMON))
sc_start2(src, bl, SC_BLOODING,50, skill_lv, src->id, skill->get_time2(skill_id,skill_lv));
break;
@@ -1257,7 +1245,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
sc_start(src, bl, SC_STUN, 1 + skill_lv, skill_lv, skill->get_time(skill_id, skill_lv));
break;
case SR_FALLENEMPIRE:
- sc_start(src, bl, SC_STOP, 100, skill_lv, skill->get_time(skill_id, skill_lv));
+ sc_start(src, bl, SC_FALLENEMPIRE, 100, skill_lv, skill->get_time(skill_id, skill_lv));
break;
case SR_WINDMILL:
if( dstsd )
@@ -1294,11 +1282,11 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
sc_start(src, bl, SC_BLOODING, 100, skill_lv, 10000);
break;
case ITEMID_MELON_BOMB:
- sc_start(src, bl, SC_MELON_BOMB, 100, skill_lv, 60000); // Reduces ASPD and moviment speed
+ sc_start(src, bl, SC_MELON_BOMB, 100, skill_lv, 60000); // Reduces ASPD and movement speed
break;
case ITEMID_BANANA_BOMB:
sc_start(src, bl, SC_BANANA_BOMB, 100, skill_lv, 60000); // Reduces LUK? Needed confirm it, may be it's bugged in kRORE?
- sc_start(src, bl, SC_BANANA_BOMB_SITDOWN_POSTDELAY, (sd? sd->status.job_level:0) + sstatus->dex / 6 + tstatus->agi / 4 - tstatus->luk / 5 - status->get_lv(bl) + status->get_lv(src), skill_lv, 1000); // Sitdown for 3 seconds.
+ sc_start(src, bl, SC_BANANA_BOMB_SITDOWN_POSTDELAY, (sd? sd->status.job_level:0) + sstatus->dex / 6 + tstatus->agi / 4 - tstatus->luk / 5 - status->get_lv(bl) + status->get_lv(src), skill_lv, 1000); // Sit down for 3 seconds.
break;
}
sd->itemid = -1;
@@ -1341,6 +1329,9 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
if( sc_start(src, bl, SC_ILLUSIONDOPING, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)) ) //custom rate.
sc_start(src, bl, SC_ILLUSION, 100, skill_lv, skill->get_time(skill_id, skill_lv));
break;
+ case MH_XENO_SLASHER:
+ sc_start2(src, bl, SC_BLOODING, 10 * skill_lv, skill_lv, src->id, skill->get_time(skill_id,skill_lv));
+ break;
}
if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) {
@@ -1652,7 +1643,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1
return 1;
}
-/* Splitted off from skill->additional_effect, which is never called when the
+/* Split off from skill->additional_effect, which is never called when the
* attack skill kills the enemy. Place in this function counter status effects
* when using skills (eg: Asura's sp regen penalty, or counter-status effects
* from cards) that will take effect on the source, not the target. [Skotlex]
@@ -1668,7 +1659,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b
nullpo_ret(src);
nullpo_ret(bl);
- if(skill_id > 0 && !skill_lv) return 0; // don't forget auto attacks! - celest
+ if(skill_id > 0 && !skill_lv) return 0; // don't forget auto attacks! [celest]
sd = BL_CAST(BL_PC, src);
dstsd = BL_CAST(BL_PC, bl);
@@ -1707,7 +1698,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b
case GS_FULLBUSTER:
sc_start(src,src,SC_BLIND,2*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv));
break;
- case HFLI_SBR44: //[orn]
+ case HFLI_SBR44: // [orn]
case HVAN_EXPLOSION:
if(src->type == BL_HOM){
TBL_HOM *hd = (TBL_HOM*)src;
@@ -1723,15 +1714,15 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b
}
if( sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR
- && rnd()%10000 < battle_config.sg_miracle_skill_ratio) //SG_MIRACLE [Komurka]
+ && rnd()%10000 < battle_config.sg_miracle_skill_ratio) // SG_MIRACLE [Komurka]
sc_start(src,src,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration);
if( sd && skill_id && attack_type&BF_MAGIC && status->isdead(bl)
&& !(skill->get_inf(skill_id)&(INF_GROUND_SKILL|INF_SELF_SKILL))
&& (rate=pc->checkskill(sd,HW_SOULDRAIN)) > 0
) {
- //Soul Drain should only work on targetted spells [Skotlex]
- if( pc_issit(sd) ) pc->setstand(sd); //Character stuck in attacking animation while 'sitting' fix. [Skotlex]
+ // Soul Drain should only work on targeted spells [Skotlex]
+ if( pc_issit(sd) ) pc->setstand(sd); // Character stuck in attacking animation while 'sitting' fix. [Skotlex]
if( skill->get_nk(skill_id)&NK_SPLASH && skill->area_temp[1] != bl->id )
;
else {
@@ -1751,7 +1742,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b
if( attack_type&BF_MAGIC ) {
sp += sd->bonus.magic_sp_gain_value;
hp += sd->bonus.magic_hp_gain_value;
- if( skill_id == WZ_WATERBALL ) {//(bugreport:5303)
+ if( skill_id == WZ_WATERBALL ) {// (bugreport:5303)
struct status_change *sc = NULL;
if( ( sc = status->get_sc(src) ) ) {
if( sc->data[SC_SOULLINK]
@@ -1846,7 +1837,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b
break;
}
dstsd->state.autocast = 0;
- //Set canact delay. [Skotlex]
+ // Set canact delay. [Skotlex]
ud = unit->bl2ud(bl);
if (ud) {
rate = skill->delay_fix(bl, auto_skill_id, auto_skill_lv);
@@ -1984,7 +1975,7 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int
return 0;
sc = status->get_sc(bl);
- if (!sc || sc->option&OPTION_MADOGEAR ) //Mado Gear cannot be divested [Ind]
+ if (!sc || sc->option&OPTION_MADOGEAR ) // Mado Gear cannot be divested [Ind]
return 0;
for (i = 0; i < ARRAYLENGTH(pos); i++) {
@@ -2013,16 +2004,16 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in
nullpo_ret(src);
if (src != target && map->list[src->m].flag.noknockback)
- return 0; //No knocking
+ return 0; // No knocking
if (count == 0)
- return 0; //Actual knockback distance is 0.
+ return 0; // Actual knockback distance is 0.
switch (target->type) {
case BL_MOB: {
struct mob_data* md = BL_CAST(BL_MOB, target);
if( md->class_ == MOBID_EMPERIUM )
return 0;
- if(src != target && is_boss(target)) //Bosses can't be knocked-back
+ if(src != target && is_boss(target)) // Bosses can't be knocked-back
return 0;
}
break;
@@ -2054,11 +2045,13 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in
}
-// Checks if 'bl' should reflect back a spell cast by 'src'.
-// type is the type of magic attack: 0: indirect (aoe), 1: direct (targetted)
-// In case of success returns type of reflection, otherwise 0
-// 1 - Regular reflection (Maya)
-// 2 - SL_KAITE reflection
+/*
+ Checks if 'bl' should reflect back a spell cast by 'src'.
+ type is the type of magic attack: 0: indirect (aoe), 1: direct (targeted)
+ In case of success returns type of reflection, otherwise 0
+ 1 - Regular reflection (Maya)
+ 2 - SL_KAITE reflection
+*/
int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) {
struct status_change *sc = status->get_sc(bl);
struct map_session_data* sd = BL_CAST(BL_PC, bl);
@@ -2117,8 +2110,8 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
if(skill_id > 0 && !skill_lv) return 0;
- nullpo_ret(src); //Source is the master behind the attack (player/mob/pet)
- nullpo_ret(dsrc); //dsrc is the actual originator of the damage, can be the same as src, or a skill casted by src.
+ nullpo_ret(src); // Source is the master behind the attack (player/mob/pet)
+ nullpo_ret(dsrc); // dsrc is the actual originator of the damage, can be the same as src, or a skill casted by src.
nullpo_ret(bl); //Target to be attacked.
if (src != dsrc) {
@@ -2126,7 +2119,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
if (!status->check_skilluse(battle_config.skill_caster_check?src:NULL, bl, skill_id, 2))
return 0;
} else if ((flag&SD_ANIMATION) && skill->get_nk(skill_id)&NK_SPLASH) {
- //Note that splash attacks often only check versus the targetted mob, those around the splash area normally don't get checked for being hidden/cloaked/etc. [Skotlex]
+ //Note that splash attacks often only check versus the targeted mob, those around the splash area normally don't get checked for being hidden/cloaked/etc. [Skotlex]
if (!status->check_skilluse(src, bl, skill_id, 2))
return 0;
}
@@ -2134,6 +2127,14 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
sd = BL_CAST(BL_PC, src);
tsd = BL_CAST(BL_PC, bl);
+ // To block skills that aren't called via battle_check_target [Panikon]
+ // issue: 8203
+ if( sd
+ && ( (bl->type == BL_MOB && pc_has_permission(sd, PC_PERM_DISABLE_PVM))
+ || (bl->type == BL_PC && pc_has_permission(sd, PC_PERM_DISABLE_PVP)) )
+ )
+ return 0;
+
sstatus = status->get_status_data(src);
tstatus = status->get_status_data(bl);
sc = status->get_sc(bl);
@@ -2180,7 +2181,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
sc = NULL; //Don't need it.
/* bugreport:2564 flag&2 disables double casting trigger */
flag |= 2;
- /* bugreport:7859 magical reflect'd zeroes blewcount */
+ /* bugreport:7859 magical reflected zeroes blow count */
dmg.blewcount = 0;
//Spirit of Wizard blocks Kaite's reflection
if( type == 2 && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD )
@@ -2202,11 +2203,11 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
#if MAGIC_REFLECTION_TYPE
#ifdef RENEWAL
- if( dmg.dmg_lv != ATK_MISS ) //Wiz SL cancelled and consumed fragment
+ if( dmg.dmg_lv != ATK_MISS ) // Wiz SL canceled and consumed fragment
#else
// issue:6415 in pre-renewal Kaite reflected the entire damage received
- // regardless of caster's equipament (Aegis 11.1)
- if( dmg.dmg_lv != ATK_MISS && type == 1 ) //Wiz SL cancelled and consumed fragment
+ // regardless of caster's equipment (Aegis 11.1)
+ if( dmg.dmg_lv != ATK_MISS && type == 1 ) //Wiz SL canceled and consumed fragment
#endif
{
short s_ele = skill->get_ele(skill_id, skill_lv);
@@ -2229,7 +2230,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
status_change_end(bl, SC_ENERGYCOAT, INVALID_TIMER);
//Reduction: 6% + 6% every 20%
dmg.damage -= dmg.damage * (6 * (1+per)) / 100;
- }
+ }
}
#endif /* MAGIC_REFLECTION_TYPE */
}
@@ -2324,10 +2325,11 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
combo=1;
break;
case AC_DOUBLE:
- if( (tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT) && pc->checkskill(sd, HT_POWER))
- {
- //TODO: This code was taken from Triple Blows, is this even how it should be? [Skotlex]
- sc_start2(NULL,src,SC_COMBOATTACK,100,HT_POWER,bl->id,2000);
+ // AC_DOUBLE can start the combo with other monster types, but the
+ // monster that's going to be hit by HT_POWER should be RC_BRUTE or RC_INSECT [Panikon]
+ if( pc->checkskill(sd, HT_POWER) )
+ {
+ sc_start4(NULL,src,SC_COMBOATTACK,100,HT_POWER,0,1,0,2000);
clif->combo_delay(src,2000);
}
break;
@@ -2429,6 +2431,8 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
case EL_ROCK_CRUSHER_ATK:
case EL_HURRICANE:
case EL_HURRICANE_ATK:
+ case EL_TYPOON_MIS:
+ case EL_TYPOON_MIS_ATK:
case KO_BAKURETSU:
case NC_MAGMA_ERUPTION:
dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,-1,5);
@@ -2498,7 +2502,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
{ //Updated to not be able to copy skills if the blow will kill you. [Skotlex]
int copy_skill = skill_id, cidx = 0;
/**
- * Copy Referal: dummy skills should point to their source upon copying
+ * Copy Referral: dummy skills should point to their source upon copying
**/
switch( skill_id ) {
case AB_DUPLELIGHT_MELEE:
@@ -2642,7 +2646,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
//blown-specific handling
switch( skill_id ) {
case LG_OVERBRAND_BRANDISH:
- if( skill->blown(dsrc,bl,dmg.blewcount,dir,0) < dmg.blewcount )
+ if( skill->blown(dsrc,bl,dmg.blewcount,dir,0) < dmg.blewcount )
skill->addtimerskill(src, tick + status_get_amotion(src), bl->id, 0, 0, LG_OVERBRAND_PLUSATK, skill_lv, BF_WEAPON, flag|SD_ANIMATION);
break;
case SR_KNUCKLEARROW:
@@ -2730,15 +2734,12 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
* Post-damage effects
**/
switch( skill_id ) {
- case RK_CRUSHSTRIKE:
- skill->break_equip(src,EQP_WEAPON,2000,BCT_SELF); // 20% chance to destroy the weapon.
- break;
case GC_VENOMPRESSURE:
{
struct status_change *ssc = status->get_sc(src);
if( ssc && ssc->data[SC_POISONINGWEAPON] && rnd()%100 < 70 + 5*skill_lv ) {
short rate = 100;
- if ( ssc->data[SC_POISONINGWEAPON]->val1 == 9 )//Oblivion Curse gives a 2nd success chance after the 1st one passes which is reduceable. [Rytech]
+ if ( ssc->data[SC_POISONINGWEAPON]->val1 == 9 )// Oblivion Curse gives a 2nd success chance after the 1st one passes which is reducible. [Rytech]
rate = 100 - tstatus->int_ * 4 / 5;
sc_start(src, bl,ssc->data[SC_POISONINGWEAPON]->val2,rate,ssc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON,1) - (tstatus->vit + tstatus->luk) / 2 * 1000);
status_change_end(src,SC_POISONINGWEAPON,-1);
@@ -2773,8 +2774,8 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr
}
/*==========================================
- * sub fonction for recursive skill call.
- * Checking bl battle flag and display dammage
+ * sub function for recursive skill call.
+ * Checking bl battle flag and display damage
* then call func with source,target,skill_id,skill_lv,tick,flag
*------------------------------------------*/
int skill_area_sub(struct block_list *bl, va_list ap) {
@@ -2965,7 +2966,7 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv,
if( (idx = skill->get_index(skill_id)) == 0 )
return 0;
- // Requeriments
+ // Requirements
for( i = 0; i < ARRAYLENGTH(itemid); i++ )
{
itemid[i] = skill->db[idx].itemid[i];
@@ -2987,7 +2988,7 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv,
else
sp += (st->max_sp * (-sp_rate)) / 100;
- if( bl->type == BL_HOM ) { // Intimacy Requeriments
+ if( bl->type == BL_HOM ) { // Intimacy Requirements
struct homun_data *hd = BL_CAST(BL_HOM, bl);
switch( skill_id ) {
case HFLI_SBR44:
@@ -3095,10 +3096,11 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) {
case WL_TETRAVORTEX_WATER:
case WL_TETRAVORTEX_WIND:
case WL_TETRAVORTEX_GROUND:
- case SR_FLASHCOMBO_ATK_STEP1:
- case SR_FLASHCOMBO_ATK_STEP2:
- case SR_FLASHCOMBO_ATK_STEP3:
- case SR_FLASHCOMBO_ATK_STEP4:
+ // SR_FLASHCOMBO
+ case SR_DRAGONCOMBO:
+ case SR_FALLENEMPIRE:
+ case SR_TIGERCANNON:
+ case SR_SKYNETBLOW:
break;
default:
continue; // Caster is Dead
@@ -3122,6 +3124,9 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) {
map->foreachinarea(skill->frostjoke_scream,skl->map,skl->x-range,skl->y-range,
skl->x+range,skl->y+range,BL_CHAR,src,skl->skill_id,skl->skill_lv,tick);
break;
+ case KN_AUTOCOUNTER:
+ clif->skill_nodamage(src,target,skl->skill_id,skl->skill_lv,1);
+ break;
case NPC_EARTHQUAKE:
if( skl->type > 1 )
skill->addtimerskill(src,tick+250,src->id,0,0,skl->skill_id,skl->skill_lv,skl->type-1,skl->flag);
@@ -3160,7 +3165,7 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) {
BL_CHAR|BL_SKILL, target->id); // Search for a new Target around current one...
if( nbl == NULL)
skl->x++;
- else
+ else
skl->x = 0;
skill->addtimerskill(src, tick + 651, (nbl?nbl:target)->id, skl->x, 0, WL_CHAINLIGHTNING_ATK, skl->skill_lv, skl->type + 1, skl->flag);
@@ -3172,9 +3177,9 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) {
case WL_TETRAVORTEX_WIND:
case WL_TETRAVORTEX_GROUND:
clif->skill_nodamage(src, target, skl->skill_id, skl->skill_lv, 1);
- skill->attack(BF_MAGIC, src, src, target, skl->skill_id, skl->skill_lv, tick, skl->flag);
+ skill->attack(BF_MAGIC, src, src, target, skl->skill_id, skl->skill_lv, tick, skl->flag);
skill->toggle_magicpower(src, skl->skill_id); // only the first hit will be amplify
- if( skl->type == 4 ){
+ if( skl->type == 4 ){
const enum sc_type scs[] = { SC_BURNING, SC_BLOODING, SC_FROSTMISTY, SC_STUN }; // status inflicts are depend on what summoned element is used.
int rate = skl->y, index = skl->x-1;
sc_start2(src,target, scs[index], rate, skl->skill_lv, src->id, skill->get_time(WL_TETRAVORTEX,index+1));
@@ -3211,22 +3216,23 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) {
map->foreachinrange(skill->area_sub, target, skill->get_splash(skl->skill_id, skl->skill_lv), BL_CHAR,
src, skl->skill_id, skl->skill_lv, (int64)0, skl->flag|1|BCT_ENEMY, skill->castend_damage_id);
break;
- case SR_FLASHCOMBO_ATK_STEP1:
- case SR_FLASHCOMBO_ATK_STEP2:
- case SR_FLASHCOMBO_ATK_STEP3:
- case SR_FLASHCOMBO_ATK_STEP4:
- if( src->type == BL_PC ) {
- struct map_session_data *sd = NULL;
- const enum e_skill combos[] = {SR_DRAGONCOMBO, SR_FALLENEMPIRE, SR_TIGERCANNON, SR_SKYNETBLOW};
- if( (sd = ((TBL_PC*)src)) ){
- uint16 cid = combos[skl->skill_id-SR_FLASHCOMBO_ATK_STEP1];
- if( distance_xy(src->x, src->y, target->x, target->y) >= 3 )
- break;
- skill->consume_requirement(sd,cid,pc->checkskill(sd, cid),1);
- skill->castend_damage_id(src, target, cid, pc->checkskill(sd, cid), tick, 0);
- }
+ // SR_FLASHCOMBO
+ case SR_DRAGONCOMBO:
+ case SR_FALLENEMPIRE:
+ case SR_TIGERCANNON:
+ case SR_SKYNETBLOW:
+ {
+ struct map_session_data *sd = NULL;
+
+ if( src->type == BL_PC && (sd = ((TBL_PC*)src)) ) {
+ if( distance_xy(src->x, src->y, target->x, target->y) >= 3 ) // FIXME: Don't combos ignore distance? [Panikon]
+ break;
+
+ skill->consume_requirement(sd, skl->skill_id, pc->checkskill(sd, skl->skill_id),1);
+ skill->castend_damage_id(src, target, skl->skill_id, pc->checkskill(sd, skl->skill_id), tick, 0);
}
break;
+ }
case SC_ESCAPE:
if( skl->type < 4+skl->skill_lv ){
clif->skill_damage(src,src,tick,0,0,-30000,1,skl->skill_id,skl->skill_lv,5);
@@ -3344,10 +3350,11 @@ int skill_cleartimerskill (struct block_list *src)
case WL_TETRAVORTEX_WATER:
case WL_TETRAVORTEX_WIND:
case WL_TETRAVORTEX_GROUND:
- case SR_FLASHCOMBO_ATK_STEP1:
- case SR_FLASHCOMBO_ATK_STEP2:
- case SR_FLASHCOMBO_ATK_STEP3:
- case SR_FLASHCOMBO_ATK_STEP4:
+ // SR_FLASHCOMBO
+ case SR_DRAGONCOMBO:
+ case SR_FALLENEMPIRE:
+ case SR_TIGERCANNON:
+ case SR_SKYNETBLOW:
continue;
}
timer->delete(ud->skilltimerskill[i]->timer, skill->timerskill);
@@ -3409,7 +3416,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
return 1;
if (skill_id && skill->get_type(skill_id) == BF_MAGIC && status->isimmune(bl) == 100) {
- //GTB makes all targetted magic display miss with a single bolt.
+ //GTB makes all targeted magic display miss with a single bolt.
sc_type sct = status->skill2sc(skill_id);
if(sct != SC_NONE)
status_change_end(bl, sct, INVALID_TIMER);
@@ -3492,7 +3499,6 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
case WS_CARTTERMINATION: // Cart Termination
case AS_VENOMKNIFE:
case HT_PHANTASMIC:
- case HT_POWER:
case TK_DOWNKICK:
case TK_COUNTER:
case GS_CHAINACTION:
@@ -3516,7 +3522,6 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
case NPC_HELLPOWER:
case RK_SONICWAVE:
case RK_STORMBLAST:
- case RK_CRUSHSTRIKE:
case AB_DUPLELIGHT_MELEE:
case RA_AIMEDBOLT:
case NC_AXEBOOMERANG:
@@ -3715,6 +3720,11 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
}
break;
+ case HT_POWER:
+ if( tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT )
+ skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
+ break;
+
//Splash attack skills.
case AS_GRIMTOOTH:
case MC_CARTREVOLUTION:
@@ -3769,6 +3779,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
case KO_MUCHANAGE:
case KO_BAKURETSU:
case GN_ILLUSIONDOPING:
+ case MH_XENO_SLASHER:
if( flag&1 ) {//Recursive invocation
// skill->area_temp[0] holds number of targets in area
// skill->area_temp[1] holds the id of the original target
@@ -3796,6 +3807,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
case GC_ROLLINGCUTTER:
flag |= SD_ANIMATION;
case LG_MOONSLASHER:
+ case MH_XENO_SLASHER:
clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6);
break;
case NPC_EARTHQUAKE://FIXME: Isn't EarthQuake a ground skill after all?
@@ -4048,7 +4060,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag);
break;
- // Celest
+ // [Celest]
case PF_SOULBURN:
if (rnd()%100 < (skill_lv < 5 ? 30 + skill_lv * 10 : 70)) {
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
@@ -4133,7 +4145,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
if( unit->movepos(src, bl->x+x, bl->y+y, 1, 1) )
{
clif->slide(src,bl->x+x,bl->y+y);
- clif->fixpos(src); // the official server send these two packts.
+ clif->fixpos(src); // the official server send these two packets.
skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
if( rnd()%100 < 4 * skill_lv )
skill->castend_damage_id(src,bl,GC_CROSSIMPACT,skill_lv,tick,flag);
@@ -4190,7 +4202,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
case WL_TETRAVORTEX:
if( sc ){
int i = SC_SUMMON5, x = 0;
- int types[][2] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
+ int types[][2] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
for(; i >= SC_SUMMON1; i--){
if( sc->data[i] ){
int skillid = WL_TETRAVORTEX_FIRE + (sc->data[i]->val1 - WLS_FIRE) + (sc->data[i]->val1 == WLS_WIND) - (sc->data[i]->val1 == WLS_WATER), sc_index = 0, rate = 0;
@@ -4266,7 +4278,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
if (sd->skillcooldown[i].id == spell_skill_id){
cooldown += sd->skillcooldown[i].val;
break;
- }
+ }
}
if(cooldown)
skill->blockpc_start(sd, spell_skill_id, cooldown);
@@ -4556,9 +4568,8 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
}
break;
- //recursive homon skill
+ // Recursive homun skill
case MH_MAGMA_FLOW:
- case MH_XENO_SLASHER:
case MH_HEILIGE_STANGE:
if(flag & 1)
skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
@@ -4764,10 +4775,10 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) {
inf &= ~BCT_NEUTRAL;
}
- if( sd && (inf2&INF2_CHORUS_SKILL) && skill->check_pc_partner(sd, ud->skill_id, &ud->skill_lv, 1, 0) < 1 ) {
- clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_NEED_HELPER, 0);
- break;
- }
+ if( sd && (inf2&INF2_CHORUS_SKILL) && skill->check_pc_partner(sd, ud->skill_id, &ud->skill_lv, 1, 0) < 1 ) {
+ clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_NEED_HELPER, 0);
+ break;
+ }
if( ud->skill_id >= SL_SKE && ud->skill_id <= SL_SKA && target->type == BL_MOB )
{
@@ -4786,7 +4797,7 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) {
&& (sc = status->get_sc(target)) && sc->data[SC_FOGWALL]
&& rnd() % 100 < 75
) {
- //Fogwall makes all offensive-type targetted skills fail at 75%
+ // Fogwall makes all offensive-type targeted skills fail at 75%
if (sd) clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0);
break;
}
@@ -4837,8 +4848,8 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) {
unit->stop_walking(src,1);
if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
- ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); //Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish]
- if (sd) { //Cooldown application
+ ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); // Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish]
+ if (sd) { // Cooldown application
int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv);
for (i = 0; i < ARRAYLENGTH(sd->skillcooldown) && sd->skillcooldown[i].id; i++) { // Increases/Decreases cooldown of a skill by item/card bonuses.
if (sd->skillcooldown[i].id == ud->skill_id){
@@ -4881,7 +4892,7 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) {
// SC_MAGICPOWER needs to switch states before any damage is actually dealt
skill->toggle_magicpower(src, ud->skill_id);
- /* On aegis damage skills are also increase by camouflage. Need confirmation on kRo.
+ /* On aegis damage skills are also increase by camouflage. Need confirmation on kRO.
if( ud->skill_id != RA_CAMOUFLAGE ) // only normal attack and auto cast skills benefit from its bonuses
status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER);
*/
@@ -4978,7 +4989,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
int element = 0;
enum sc_type type;
- if(skill_id > 0 && !skill_lv) return 0; // celest
+ if(skill_id > 0 && !skill_lv) return 0; // [Celest]
nullpo_retr(1, src);
nullpo_retr(1, bl);
@@ -5014,12 +5025,27 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
}
+ // Supportive skills that can't be cast in users with mado
+ if( sd && dstsd && pc_ismadogear(dstsd) ) {
+ switch( skill_id ) {
+ case AL_HEAL:
+ case AL_INCAGI:
+ case AL_DECAGI:
+ case AB_RENOVATIO:
+ case AB_HIGHNESSHEAL:
+ clif->skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0);
+ return 0;
+ default:
+ break;
+ }
+ }
+
tstatus = status->get_status_data(bl);
sstatus = status->get_status_data(src);
//Check for undead skills that convert a no-damage skill into a damage one. [Skotlex]
switch (skill_id) {
- case HLIF_HEAL: //[orn]
+ case HLIF_HEAL: // [orn]
if (bl->type != BL_HOM) {
if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0) ;
break ;
@@ -5031,11 +5057,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
**/
case AB_RENOVATIO:
case AB_HIGHNESSHEAL:
- case AL_INCAGI:
- if( sd && dstsd && pc_ismadogear(dstsd) ){
- clif->skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0);
- return 0;
- }
+ case AL_INCAGI:
case ALL_RESURRECTION:
case PR_ASPERSIO:
//Apparently only player casted skills can be offensive like this.
@@ -5090,7 +5112,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
struct block_list *s_src = battle->get_master(src);
short ret = 0;
if(!skill->check_unit_range(src, src->x, src->y, skill_id, skill_lv)) //prevent reiteration
- ret = skill->castend_pos2(src,src->x,src->y,skill_id,skill_lv,tick,flag); //cast on homon
+ ret = skill->castend_pos2(src,src->x,src->y,skill_id,skill_lv,tick,flag); //cast on homun
if(s_src && !skill->check_unit_range(s_src, s_src->x, s_src->y, skill_id, skill_lv))
ret |= skill->castend_pos2(s_src,s_src->x,s_src->y,skill_id,skill_lv,tick,flag); //cast on master
if (hd)
@@ -5133,7 +5155,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
map->freeblock_lock();
switch(skill_id) {
- case HLIF_HEAL: //[orn]
+ case HLIF_HEAL: // [orn]
case AL_HEAL:
/**
* Arch Bishop
@@ -5489,7 +5511,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if (dstsd) {
if(dstsd->status.weapon == W_FIST ||
(dstsd->sc.count && !dstsd->sc.data[type] &&
- ( //Allow re-enchanting to lenghten time. [Skotlex]
+ ( //Allow re-enchanting to lengthen time. [Skotlex]
dstsd->sc.data[SC_PROPERTYFIRE] ||
dstsd->sc.data[SC_PROPERTYWATER] ||
dstsd->sc.data[SC_PROPERTYWIND] ||
@@ -5594,7 +5616,6 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
case PR_BENEDICTIO:
case LK_BERSERK:
case MS_BERSERK:
- case KN_AUTOCOUNTER:
case KN_TWOHANDQUICKEN:
case KN_ONEHAND:
case MER_QUICKEN:
@@ -5667,6 +5688,11 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
clif->skill_nodamage(src,bl,skill_id,skill_lv,
sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)));
break;
+
+ case KN_AUTOCOUNTER:
+ 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);
+ break;
case SO_STRIKING:
if (sd) {
@@ -5707,7 +5733,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
{
int duration = skill->get_time(skill_id,skill_lv);
clif->skill_nodamage(bl,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,duration)); // Master
- clif->skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,src,type,100,skill_lv,duration)); // Homunc
+ clif->skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,src,type,100,skill_lv,duration)); // Homun
}
break;
case NJ_BUNSINJYUTSU:
@@ -6041,7 +6067,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY);
break;
- case HVAN_EXPLOSION: //[orn]
+ case HVAN_EXPLOSION: // [orn]
case NPC_SELFDESTRUCTION:
{
//Self Destruction hits everyone in range (allies+enemies)
@@ -6174,7 +6200,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
return 0;
}
clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,bl,type,100,skill_lv,unit->getdir(bl),0,0,0));
- if (sd) // If the client receives a skill-use packet inmediately before a walkok packet, it will discard the walk packet! [Skotlex]
+ if (sd) // If the client receives a skill-use packet immediately before a walkok packet, it will discard the walk packet! [Skotlex]
clif->walkok(sd); // So aegis has to resend the walk ok.
break;
case AS_CLOAKING:
@@ -6410,7 +6436,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
case MC_IDENTIFY:
if(sd) {
clif->item_identify_list(sd);
- if( sd->menuskill_id != MC_IDENTIFY ) {/* failed, dont consume anything, return */
+ if( sd->menuskill_id != MC_IDENTIFY ) {/* failed, don't consume anything, return */
map->freeblock_unlock();
return 1;
}
@@ -6752,7 +6778,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER)
- || (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_ROGUE) //Rogue's spirit defends againt dispel.
+ || (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_ROGUE) //Rogue's spirit defends against dispel.
|| (dstsd && pc_ismadogear(dstsd))
|| rnd()%100 >= 50+10*skill_lv )
{
@@ -7062,7 +7088,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
unit->stop_attack(src);
//Run skillv tiles overriding the can-move check.
if (unit->walktoxy(src, src->x + skill_lv * mask[dir][0], src->y + skill_lv * mask[dir][1], 2) && md)
- md->state.skillstate = MSS_WALK; //Otherwise it isn't updated in the ai.
+ md->state.skillstate = MSS_WALK; //Otherwise it isn't updated in the AI.
}
break;
@@ -7128,14 +7154,14 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
case WE_MALE:
{
int hp_rate = (!skill_lv)? 0:skill->db[skill_id].hp_rate[skill_lv-1];
- int gain_hp = tstatus->max_hp*abs(hp_rate)/100; // The earned is the same % of the target HP than it costed the caster. [Skotlex]
+ int gain_hp = tstatus->max_hp*abs(hp_rate)/100; // The earned is the same % of the target HP than it cost the caster. [Skotlex]
clif->skill_nodamage(src,bl,skill_id,status->heal(bl, gain_hp, 0, 0),1);
}
break;
case WE_FEMALE:
{
int sp_rate = (!skill_lv)? 0:skill->db[skill_id].sp_rate[skill_lv-1];
- int gain_sp = tstatus->max_sp*abs(sp_rate)/100;// The earned is the same % of the target SP than it costed the caster. [Skotlex]
+ int gain_sp = tstatus->max_sp*abs(sp_rate)/100;// The earned is the same % of the target SP than it cost the caster. [Skotlex]
clif->skill_nodamage(src,bl,skill_id,status->heal(bl, 0, gain_sp, 0),1);
}
break;
@@ -7239,7 +7265,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
// if it is already trapping something don't spring it,
// remove trap should be used instead
break;
- // otherwise fallthrough to below
+ // otherwise fall through to below
case UNT_BLASTMINE:
case UNT_SKIDTRAP:
case UNT_LANDMINE:
@@ -7472,7 +7498,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if (count == -1)
count = 3;
else
- count++; //Should not retrigger this one.
+ count++; //Should not re-trigger this one.
break;
case 7: // stop freeze or stoned
{
@@ -7687,7 +7713,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
break;
- case AM_CALLHOMUN: //[orn]
+ case AM_CALLHOMUN: // [orn]
if( sd ) {
if (homun->call(sd))
clif->skill_nodamage(src, bl, skill_id, skill_lv, 1);
@@ -7705,7 +7731,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
break;
- case HAMI_CASTLE: //[orn]
+ case HAMI_CASTLE: // [orn]
if(rnd()%100 < 20*skill_lv && src != bl)
{
int x,y;
@@ -7715,7 +7741,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id,skill_lv));
if (unit->movepos(src,bl->x,bl->y,0,0)) {
- clif->skill_nodamage(src,src,skill_id,skill_lv,1); // Homunc
+ clif->skill_nodamage(src,src,skill_id,skill_lv,1); // Homun
clif->slide(src,bl->x,bl->y) ;
if (unit->movepos(bl,x,y,0,0))
{
@@ -7734,7 +7760,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
else if (sd)
clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0);
break;
- case HVAN_CHAOTIC: //[orn]
+ case HVAN_CHAOTIC: // [orn]
{
static const int per[5][2]={{20,50},{50,60},{25,75},{60,64},{34,67}};
int r = rnd()%100;
@@ -7755,7 +7781,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
status->heal(bl, hp, 0, 0);
}
break;
- //Homun single-target support skills [orn]
+ // Homun single-target support skills [orn]
case HAMI_BLOODLUST:
case HFLI_FLEET:
case HFLI_SPEED:
@@ -8007,7 +8033,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
{ // Every time the skill is casted the status change is reseted adding a counter.
count += (short)tsc->data[SC_ROLLINGCUTTER]->val1;
if( count > 10 )
- count = 10; // Max coounter
+ count = 10; // Max counter
status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER);
}
sc_start(src,bl,SC_ROLLINGCUTTER,100,count,skill->get_time(skill_id,skill_lv));
@@ -8113,15 +8139,12 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if( dstsd && dstsd->special_state.no_magic_damage )
break;
- if ( sd && sd->status.party_id == 0 )
- count = 1;
- else
- count = party->foreachsamemap(party->sub_count, sd, 0);
+ if( sd && sd->status.party_id != 0 )
+ count = party->foreachsamemap(party->sub_count, sd, 0);
- if (count > 0)
- clif->skill_nodamage(bl, bl, skill_id, skill_lv,
- sc_start4(src, bl, type, 100, skill_lv, 0, 0, count, skill->get_time(skill_id, skill_lv)));
- } else
+ clif->skill_nodamage(bl, bl, skill_id, skill_lv,
+ sc_start4(src, bl, type, 100, skill_lv, 0, 0, count, skill->get_time(skill_id, skill_lv)));
+ } else if( sd )
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 AB_CHEAL:
@@ -8526,7 +8549,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
//First we set the success chance based on the caster's build which increases the chance.
rate = 10 * skill_lv + rnd_value( sstatus->dex / 12, sstatus->dex / 4 ) + joblvbonus + status->get_lv(src) / 10;
// We then reduce the success chance based on the target's build.
- rate -= rnd_value( tstatus->agi / 6, tstatus->agi / 3 ) - tstatus->luk / 10 - ( dstsd ? (dstsd->max_weight / 10 - dstsd->weight / 10 ) / 100 : 0 ) - status->get_lv(bl) / 10;
+ rate -= rnd_value( tstatus->agi / 6, tstatus->agi / 3 ) + tstatus->luk / 10 + ( dstsd ? (dstsd->max_weight / 10 - dstsd->weight / 10 ) / 100 : 0 ) + status->get_lv(bl) / 10;
//Finally we set the minimum success chance cap based on the caster's skill level and DEX.
rate = cap_value( rate, skill_lv + sstatus->dex / 20, 100);
clif->skill_nodamage(src,bl,skill_id,0,sc_start(src,bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv)));
@@ -8539,7 +8562,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
if ( tsc && tsc->data[SC__UNLUCKY] && skill_id == SC_UNLUCKY) {
//If the target was successfully inflected with the Unlucky status, give 1 of 3 random status's.
- switch(rnd()%3) {//Targets in the Unlucky status will be affected by one of the 3 random status's reguardless of resistance.
+ switch(rnd()%3) {//Targets in the Unlucky status will be affected by one of the 3 random status's regardless of resistance.
case 0:
status->change_start(src,bl,SC_POISON,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),10);
break;
@@ -8568,9 +8591,11 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
break;
case LG_SHIELDSPELL:
+ if( !sd )
+ break;
if( flag&1 ) {
sc_start(src,bl,SC_SILENCE,100,skill_lv,sd->bonus.shieldmdef * 30000);
- } else if( sd ) {
+ } else {
int opt = 0, val = 0, splashrange = 0;
struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]];
if( !shield_data || shield_data->type != IT_ARMOR ) {
@@ -8607,6 +8632,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
break;
case 2:
+ if( sd->bonus.shieldmdef == 0 )
+ break; // Nothing should happen if the shield has no mdef, not even displaying a message
if ( sd->bonus.shieldmdef >= 1 && sd->bonus.shieldmdef <= 3 )
splashrange = 1;
else if ( sd->bonus.shieldmdef >= 4 && sd->bonus.shieldmdef <= 5 )
@@ -8634,8 +8661,12 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
break;
case 3:
{
- struct item *shield = &sd->status.inventory[sd->equip_index[EQI_HAND_L]];
int rate = 0;
+ struct item *shield = &sd->status.inventory[sd->equip_index[EQI_HAND_L]];
+
+ if( shield->refine == 0 )
+ break; // Nothing should happen if the shield has no refine, not even displaying a message
+
switch( opt ) {
case 1:
sc_start(src,bl,SC_SHIELDSPELL_REF,100,opt,shield->refine * 30000); //Now breaks Armor at 100% rate
@@ -8723,7 +8754,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
} else {
int count = 0;
clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6);
- count = map->forcountinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-charactors
+ count = map->forcountinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-characters
BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id);
if( sd ) pc->delspiritball(sd, count, 0);
clif->skill_nodamage(src, src, skill_id, skill_lv,
@@ -8749,8 +8780,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
{
sp = dstsd->spiritball; //1%sp per spiritball.
pc->delspiritball(dstsd, dstsd->spiritball, 0);
+ status_percent_heal(src, 0, sp);
}
- if( sp ) status_percent_heal(src, 0, sp);
clif->skill_nodamage(src, bl, skill_id, skill_lv, sp ? 1:0);
} else {
clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6);
@@ -8801,16 +8832,23 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
case SR_GENTLETOUCH_CHANGE:
case SR_GENTLETOUCH_REVITALIZE:
clif->skill_nodamage(src,bl,skill_id,skill_lv,
- sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)));
+ sc_start2(src,bl,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv)));
break;
case SR_FLASHCOMBO:
{
+ const int combo[] = {
+ SR_DRAGONCOMBO, SR_FALLENEMPIRE, SR_TIGERCANNON, SR_SKYNETBLOW
+ };
int i;
- clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
- for(i = SR_FLASHCOMBO_ATK_STEP1; i <= SR_FLASHCOMBO_ATK_STEP4; i++)
- skill->addtimerskill(src, tick + 400 * (i - SR_FLASHCOMBO_ATK_STEP1), bl->id, 0, 0, i, skill_lv, BF_WEAPON, flag|SD_LEVEL);
+
+ clif->skill_nodamage(src,bl,skill_id,skill_lv,
+ sc_start2(src,bl,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv)));
+
+ for( i = 0; i < ARRAYLENGTH(combo); i++ )
+ skill->addtimerskill(src, tick + 400 * i, bl->id, 0, 0, combo[i], skill_lv, BF_WEAPON, flag|SD_LEVEL);
+
+ break;
}
- break;
case WA_SWING_DANCE:
case WA_SYMPHONY_OF_LOVER:
case WA_MOONLIT_SERENADE:
@@ -8851,7 +8889,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if ( flag&1 )
sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv));
else if ( sd ) {
- int rate = 4 * skill_lv + 2 * (sd ? pc->checkskill(sd,WM_LESSON) : 1) + status->get_lv(src) / 15 + (sd? sd->status.job_level:0) / 5;
+ int rate = 4 * skill_lv + 2 * pc->checkskill(sd,WM_LESSON) + status->get_lv(src)/15 + sd->status.job_level/5;
if ( rnd()%100 < rate ) {
flag |= BCT_PARTY|BCT_GUILD;
map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_NPC|BL_SKILL, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id);
@@ -8868,7 +8906,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if( flag&1 ) {
sc_start2(src,bl,type,100,skill_lv,(skill_id==WM_VOICEOFSIREN)?src->id:0,skill->get_time(skill_id,skill_lv));
} else if( sd ) {
- int rate = 6 * skill_lv + (sd ? pc->checkskill(sd,WM_LESSON) : 1) + (sd? sd->status.job_level:0) / 2;
+ int rate = 6 * skill_lv + pc->checkskill(sd,WM_LESSON) + sd->status.job_level/2;
if ( rnd()%100 < rate ) {
flag |= BCT_PARTY|BCT_GUILD;
map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),(skill_id==WM_VOICEOFSIREN)?BL_CHAR|BL_NPC|BL_SKILL:BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id);
@@ -8912,7 +8950,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
sc_start(src, bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv));
if ( madnesscheck >= 8 )//The god of madness deals 9999 fixed unreduceable damage when 8 or more enemy players are affected.
status_fix_damage(src, bl, 9999, clif->damage(src, bl, 0, 0, 9999, 0, 0, 0));
- //skill->attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);//To renable when I can confirm it deals damage like this. Data shows its dealed as reflected damage which I dont have it coded like that yet. [Rytech]
+ //skill->attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);//To renable when I can confirm it deals damage like this. Data shows its dealt as reflected damage which I don't have it coded like that yet. [Rytech]
} else if( sd ) {
int rate = sstatus->int_ / 6 + (sd? sd->status.job_level:0) / 5 + skill_lv * 4;
if ( rnd()%100 < rate ) {
@@ -9038,7 +9076,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if( sd ) {
int elemental_class = skill->get_elemental_type(skill_id,skill_lv);
- // Remove previous elemental fisrt.
+ // Remove previous elemental first.
if( sd->ed )
elemental->delete(sd->ed,0);
@@ -9061,7 +9099,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
elemental->delete(sd->ed, 0);
break;
}
- switch( skill_lv ) {// Select mode bassed on skill level used.
+ switch( skill_lv ) {// Select mode based on skill level used.
case 2: mode = EL_MODE_ASSIST; break;
case 3: mode = EL_MODE_AGGRESSIVE; break;
}
@@ -9397,10 +9435,23 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
break;
+ case MH_LIGHT_OF_REGENE:
+ if( hd && battle->get_master(src) ) {
+ hd->homunculus.intimacy = (751 + rnd()%99) * 100; // random between 751 ~ 850
+ clif->send_homdata(hd->master, SP_INTIMATE, hd->homunculus.intimacy / 100); //refresh intimacy info
+ sc_start(src, battle->get_master(src), type, 100, skill_lv, skill->get_time(skill_id, skill_lv));
+ }
+ break;
+
+ case MH_OVERED_BOOST:
+ if ( hd && battle->get_master(src) ) {
+ sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv));
+ sc_start(src, battle->get_master(src), type, 100, skill_lv, skill->get_time(skill_id, skill_lv));
+ }
+ break;
+
case MH_SILENT_BREEZE:
{
- struct status_change *ssc = status->get_sc(src);
- struct block_list *m_bl = battle->get_master(src);
const enum sc_type scs[] = {
SC_MANDRAGORA, SC_HARMONIZE, SC_DEEP_SLEEP, SC_SIREN, SC_SLEEP, SC_CONFUSION, SC_ILLUSION
};
@@ -9410,40 +9461,15 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
for (i = 0; i < ARRAYLENGTH(scs); i++) {
if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER);
}
- if (!tsc->data[SC_SILENCE]) //put inavoidable silence on target
- status->change_start(src, bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8);
}
- heal = status_get_matk_min(src)*4;
- status->heal(bl, heal, 0, 7);
-
- //now inflict silence on everyone
- if(ssc && !ssc->data[SC_SILENCE]) //put inavoidable silence on homun
- status->change_start(src, src, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8);
- if(m_bl){
- struct status_change *msc = status->get_sc(m_bl);
- if(msc && !msc->data[SC_SILENCE]) //put inavoidable silence on master
- status->change_start(src, m_bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8);
- }
- if (hd)
- skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv));
+ heal = 5 * status->get_lv(&hd->bl) + status->base_matk(&hd->battle_status, status->get_lv(&hd->bl));
+ status->heal(bl, heal, 0, 0);
+ clif->skill_nodamage(src, src, skill_id, skill_lv, clif->skill_nodamage(src, bl, AL_HEAL, heal, 1));
+ status->change_start(src, src, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2|8);
+ status->change_start(src, bl, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2|8);
}
break;
- case MH_OVERED_BOOST:
- if (hd) {
- struct block_list *s_bl = battle->get_master(src);
- if(hd->homunculus.hunger>50) //reduce hunger
- hd->homunculus.hunger = hd->homunculus.hunger/2;
- else
- hd->homunculus.hunger = min(1,hd->homunculus.hunger);
- if(s_bl && s_bl->type==BL_PC) {
- status->set_sp(s_bl,status_get_max_sp(s_bl)/2,0); //master drain 50% sp
- clif->send_homdata(((TBL_PC *)s_bl), SP_HUNGRY, hd->homunculus.hunger); //refresh hunger info
- sc_start(src, s_bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); //gene bonus
- }
- sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv));
- skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv));
- }
- break;
+
case MH_GRANITIC_ARMOR:
case MH_PYROCLASTIC:
if( hd ){
@@ -9458,12 +9484,6 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
break;
- case MH_LIGHT_OF_REGENE:
- if(hd) {
- hd->homunculus.intimacy = 25100; //change to neutral (can't be cast if < 750)
- if(sd) clif->send_homdata(sd, SP_INTIMATE, hd->homunculus.intimacy); //refresh intimacy info
- }
- //don't break need to start status and start block timer
case MH_MAGMA_FLOW:
case MH_PAIN_KILLER:
sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv));
@@ -9759,10 +9779,15 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char
switch(skill_id) {
case AL_TELEPORT:
+ // The storage window is closed automatically by the client when there's
+ // any kind of map change, so we need to restore it automatically
+ // issue: 8027
if(strcmp(mapname,"Random")==0)
pc->randomwarp(sd,CLR_TELEPORT);
else if (sd->menuskill_val > 1) //Need lv2 to be able to warp here.
pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
+
+ clif->refresh_storagewindow(sd);
break;
case AL_WARP:
@@ -9852,7 +9877,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
int r;
//if(skill_lv <= 0) return 0;
- if(skill_id > 0 && !skill_lv) return 0; // celest
+ if(skill_id > 0 && !skill_lv) return 0; // [Celest]
nullpo_ret(src);
@@ -10047,10 +10072,10 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case MH_VOLCANIC_ASH:
case MH_POISON_MIST:
case MH_STEINWAND:
- case MH_XENO_SLASHER:
case NC_MAGMA_ERUPTION:
case SO_ELEMENTAL_SHIELD:
case RL_B_TRAP:
+ case MH_XENO_SLASHER:
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.
skill->unitsetting(src,skill_id,skill_lv,x,y,0);
@@ -10158,7 +10183,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
int class_ = skill_id==AM_SPHEREMINE?1142:summons[skill_lv-1];
struct mob_data *md;
- // Correct info, don't change any of this! [celest]
+ // Correct info, don't change any of this! [Celest]
md = mob->once_spawn_sub(src, src->m, x, y, status->get_name(src), class_, "", SZ_MEDIUM, AI_NONE);
if (md) {
md->master_id = src->id;
@@ -10298,7 +10323,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
sc_start(src,src,type,100,skill_lv,skill->get_time2(skill_id,skill_lv));
break;
- case AM_RESURRECTHOMUN: //[orn]
+ case AM_RESURRECTHOMUN: // [orn]
if (sd) {
if (!homun->ressurect(sd, 20*skill_lv, x, y)) {
clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
@@ -10320,7 +10345,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case WM_SOUND_OF_DESTRUCTION:
r = skill->get_splash(skill_id,skill_lv);
map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id);
- break;
+ break;
case WM_LULLABY_DEEPSLEEP:
r = skill->get_splash(skill_id,skill_lv);
@@ -10610,14 +10635,22 @@ int skill_dance_overlap(struct skill_unit* su, int flag) {
return map->foreachincell(skill->dance_overlap_sub, su->bl.m,su->bl.x,su->bl.y,BL_SKILL, su,flag);
}
-/*==========================================
+/**
* Converts this group information so that it is handled as a Dissonance or Ugly Dance cell.
- * Flag: 0 - Convert, 1 - Revert.
- *------------------------------------------*/
+ * This function is safe to call even when the unit or the group were freed by other function
+ * previously.
+ * @param su Skill unit data (from BA_DISSONANCE or DC_UGLYDANCE)
+ * @param flag 0 Convert
+ * @param flag 1 Revert
+ * @retval true success
+ **/
bool skill_dance_switch(struct skill_unit* su, int flag) {
static int prevflag = 1; // by default the backup is empty
static struct skill_unit_group backup;
- struct skill_unit_group* group = su->group;
+ struct skill_unit_group* group;
+
+ if( su == NULL || (group = su->group) == NULL )
+ return false;
// val2&UF_ENSEMBLE is a hack to indicate dissonance
if ( !(group->state.song_dance&0x1 && su->val2&UF_ENSEMBLE) )
@@ -11674,7 +11707,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6
case UNT_FIREPILLAR_ACTIVE:
case UNT_CLAYMORETRAP:
if( sg->unit_id == UNT_FIRINGTRAP || sg->unit_id == UNT_ICEBOUNDTRAP || sg->unit_id == UNT_CLAYMORETRAP )
- map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &src->bl,tick);
+ map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &src->bl,tick);
else
map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick);
if (sg->unit_id != UNT_FIREPILLAR_ACTIVE)
@@ -11876,7 +11909,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6
case UNT_POISONSMOKE:
if( battle->check_target(ss,bl,BCT_ENEMY) > 0 && !(tsc && tsc->data[sg->val2]) && rnd()%100 < 50 ) {
short rate = 100;
- if ( sg->val1 == 9 )//Oblivion Curse gives a 2nd success chance after the 1st one passes which is reduceable. [Rytech]
+ if ( sg->val1 == 9 )//Oblivion Curse gives a 2nd success chance after the 1st one passes which is reducible. [Rytech]
rate = 100 - tstatus->int_ * 4 / 5 ;
sc_start(ss,bl,sg->val2,rate,sg->val1,skill->get_time2(GC_POISONINGWEAPON,1) - (tstatus->vit + tstatus->luk) / 2 * 1000);
}
@@ -11911,7 +11944,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6
case UNT_STEALTHFIELD:
if( bl->id == sg->src_id )
- break; // Dont work on Self (video shows that)
+ break; // Don't work on Self (video shows that)
case UNT_NEUTRALBARRIER:
sc_start(ss,bl,type,100,sg->skill_lv,sg->interval + 100);
break;
@@ -12193,8 +12226,8 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) {
//We don't check for SC_LONGING because someone could always have knocked you back and out of the song/dance.
//FIXME: This code is not perfect, it doesn't checks for the real ensemble's owner,
//it only checks if you are doing the same ensemble. So if there's two chars doing an ensemble
- //which overlaps, by stepping outside of the other parther's ensemble will cause you to cancel
- //your own. Let's pray that scenario is pretty unlikely and noone will complain too much about it.
+ //which overlaps, by stepping outside of the other partner's ensemble will cause you to cancel
+ //your own. Let's pray that scenario is pretty unlikely and none will complain too much about it.
status_change_end(bl, SC_DANCING, INVALID_TIMER);
}
case MH_STEINWAND:
@@ -12240,7 +12273,7 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) {
if (sce) {
status_change_end(bl, type, INVALID_TIMER);
if ((sce=sc->data[SC_BLIND])) {
- if (bl->type == BL_PC) //Players get blind ended inmediately, others have it still for 30 secs. [Skotlex]
+ if (bl->type == BL_PC) //Players get blind ended immediately, others have it still for 30 secs. [Skotlex]
status_change_end(bl, SC_BLIND, INVALID_TIMER);
else {
timer->delete(sce->timer, status->change_timer);
@@ -12646,6 +12679,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
// Check the skills that can be used while mounted on a warg
if( pc_isridingwug(sd) ) {
switch( skill_id ) {
+ // Hunter skills
case HT_SKIDTRAP:
case HT_LANDMINE:
case HT_ANKLESNARE:
@@ -12655,43 +12689,39 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
case HT_FREEZINGTRAP:
case HT_BLASTMINE:
case HT_CLAYMORETRAP:
- case HT_SPRINGTRAP:
+ case HT_TALKIEBOX:
+ // Ranger skills
case RA_DETONATOR:
+ case RA_ELECTRICSHOCKER:
case RA_CLUSTERBOMB:
- case HT_TALKIEBOX:
+ case RA_MAGENTATRAP:
+ case RA_COBALTTRAP:
+ case RA_MAIZETRAP:
+ case RA_VERDURETRAP:
case RA_FIRINGTRAP:
case RA_ICEBOUNDTRAP:
case RA_WUGDASH:
case RA_WUGRIDER:
case RA_WUGSTRIKE:
+ // Other
+ case BS_GREED:
break;
default: // in official there is no message.
return 0;
}
}
+
+ // Check the skills that can be used whiled using mado
if( pc_ismadogear(sd) ) {
- switch( skill_id ) { //None Mado skills are unusable when Mado is equipped. [Jobbie]
- case BS_REPAIRWEAPON:
- case WS_MELTDOWN:
- case BS_HAMMERFALL:
- case WS_CARTBOOST:
- case BS_ADRENALINE:
- case WS_WEAPONREFINE:
- case BS_WEAPONPERFECT:
- case WS_CARTTERMINATION:
- case BS_OVERTHRUST:
- case WS_OVERTHRUSTMAX:
- case BS_MAXIMIZE:
- case BS_ADRENALINE2:
- case BS_UNFAIRLYTRICK:
- case BS_GREED:
- clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR,0);
- return 0;
- default: //Only Mechanic exlcusive skill can be used.
- break;
+ if( !(skill_id > NC_MADOLICENCE && skill_id <= NC_DISJOINT)
+ && skill_id != NC_MAGMA_ERUPTION
+ && skill_id != BS_GREED ) {
+ clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR,0);
+ return 0;
}
}
+
if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL )
return 0;
@@ -13001,7 +13031,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
return 0;
}
break;
- case AM_REST: //Can't vapo homun if you don't have an active homunc or it's hp is < 80%
+ case AM_REST: //Can't vapo homun if you don't have an active homun or it's hp is < 80%
if (!homun_alive(sd->hd) || sd->hd->battle_status.hp < (sd->hd->battle_status.max_hp*80/100))
{
clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
@@ -13042,14 +13072,17 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
case WL_COMET:
{
int idx;
+
+ if( !require.itemid[0] ) // issue: 7935
+ break;
if( skill->check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0 && ((idx = pc->search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[idx].amount < require.amount[0]) )
{
//clif->skill_fail(sd,skill_id,USESKILL_FAIL_NEED_ITEM,require.amount[0],require.itemid[0]);
clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
return 0;
}
- }
break;
+ }
case WL_SUMMONFB:
case WL_SUMMONBL:
case WL_SUMMONWB:
@@ -13059,7 +13092,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
{
int j, i = 0;
for(j = SC_SUMMON1; j <= SC_SUMMON5; j++)
- if( sc && sc->data[j] )
+ if( sc && sc->data[j] )
i++;
switch(skill_id){
@@ -13438,7 +13471,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
// There's no need to check if the skill is part of a combo if it's
// already been checked before, see unit_skilluse_id2 [Panikon]
- // Note that if this check is readded part of issue:8047 will reapear!
+ // Note that if this check is read part of issue:8047 will reappear!
//if( sd->sc.data[SC_COMBOATTACK] && !skill->is_combo(skill_id ) )
// return 0;
@@ -13686,7 +13719,7 @@ int skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, uin
continue;
if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD )
- continue; //Gemstones are checked, but not substracted from inventory.
+ continue; //Gemstones are checked, but not subtracted from inventory.
switch( skill_id ){
case SA_SEISMICWEAPON:
@@ -13881,7 +13914,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16
if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN )
{
if( sd->special_state.no_gemstone )
- { // All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card -helvetica
+ { // All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card [helvetica]
if( skill_id != SA_ABRACADABRA )
req.itemid[i] = req.amount[i] = 0;
else if( --req.amount[i] < 1 )
@@ -14129,9 +14162,9 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16
if( sd->bonus.varcastrate < 0 )
VARCAST_REDUCTION(sd->bonus.varcastrate);
if( sd->bonus.add_varcast != 0 ) // bonus bVariableCast
- time += sd->bonus.add_varcast;
+ time += sd->bonus.add_varcast;
if( sd->bonus.add_fixcast != 0 ) // bonus bFixedCast
- fixed += sd->bonus.add_fixcast;
+ fixed += sd->bonus.add_fixcast;
for (i = 0; i < ARRAYLENGTH(sd->skillfixcast) && sd->skillfixcast[i].id; i++)
if (sd->skillfixcast[i].id == skill_id){ // bonus2 bSkillFixedCast
fixed += sd->skillfixcast[i].val;
@@ -14202,7 +14235,7 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16
fixcast_r = max(fixcast_r, sc->data[SC_DANCE_WITH_WUG]->val4);
if( sc->data[SC_SECRAMENT] )
fixcast_r = max(fixcast_r, sc->data[SC_SECRAMENT]->val2);
- if( sd && ( skill_lv = pc->checkskill(sd, WL_RADIUS) ) && (skill_id >= WL_WHITEIMPRISON && skill_id < WL_FREEZE_SP) )
+ if( sd && ( skill_lv = pc->checkskill(sd, WL_RADIUS) ) && (skill_id >= WL_WHITEIMPRISON && skill_id < WL_FREEZE_SP) )
fixcast_r = max(fixcast_r, (status_get_int(bl) + status->get_lv(bl)) / 15 + skill_lv * 5); // [{(Caster?s INT / 15) + (Caster?s Base Level / 15) + (Radius Skill Level x 5)}] %
// Fixed cast non percentage bonuses
if( sc->data[SC_MANDRAGORA] )
@@ -15038,7 +15071,7 @@ int skill_cell_overlap(struct block_list *bl, va_list ap) {
if( su == NULL || su->group == NULL || (*alive) == 0 )
return 0;
- if( su->group->state.guildaura ) /* guild auras are not cancelled! */
+ if( su->group->state.guildaura ) /* guild auras are not canceled! */
return 0;
switch (skill_id) {
@@ -15290,6 +15323,36 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce
return wall;
}
+
+/**
+ * Verifies if an user can use SC_CLOAKING
+ **/
+bool skill_can_cloak(struct map_session_data *sd) {
+ nullpo_retr(false, sd);
+
+ //Avoid cloaking with no wall and low skill level. [Skotlex]
+ //Due to the cloaking card, we have to check the wall versus to known
+ //skill level rather than the used one. [Skotlex]
+ //if (sd && val1 < 3 && skill_check_cloaking(bl,NULL))
+ if (pc->checkskill(sd, AS_CLOAKING) < 3 && !skill->check_cloaking(&sd->bl,NULL))
+ return false;
+
+ return true;
+}
+
+/**
+ * Verifies if an user can still be cloaked (AS_CLOAKING)
+ * Is called via map->foreachinrange when any kind of wall disapears
+ **/
+int skill_check_cloaking_end(struct block_list *bl, va_list ap) {
+ TBL_PC *sd = BL_CAST(BL_PC, bl);
+
+ if (sd && sd->sc.data[SC_CLOAKING] && !skill->can_cloak(sd))
+ status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
+
+ return 0;
+}
+
bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce)
{
static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1};
@@ -15328,7 +15391,7 @@ bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit){
if( sc && sc->data[SC__SHADOWFORM] && damage ) {
src = map->id2bl(sc->data[SC__SHADOWFORM]->val2);
- if( !src || src->m != bl->m ) {
+ if( !src || src->m != bl->m ) {
status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
return false;
}
@@ -15438,6 +15501,13 @@ int skill_delunit (struct skill_unit* su) {
clif->changemapcell(0,su->bl.m,su->bl.x,su->bl.y,su->val2,ALL_SAMEMAP); // hack to avoid clientside cell bug
skill->unitsetmapcell(su,WZ_ICEWALL,group->skill_lv,CELL_ICEWALL,false);
map->list[su->bl.m].icewall_num--;
+ // AS_CLOAKING in low levels requires a wall to be cast, thus it needs to be
+ // checked again when a wall disapears! issue:8182 [Panikon]
+ map->foreachinarea(skill->check_cloaking_end, su->bl.m,
+ // Use 3x3 area to check for users near cell
+ su->bl.x - 1, su->bl.y - 1,
+ su->bl.x + 1, su->bl.x + 1,
+ BL_PC);
break;
case SA_LANDPROTECTOR:
skill->unitsetmapcell(su,SA_LANDPROTECTOR,group->skill_lv,CELL_LANDPROTECTOR,false);
@@ -15452,7 +15522,7 @@ int skill_delunit (struct skill_unit* su) {
}
break;
case SC_MANHOLE: // Note : Removing the unit don't remove the status (official info)
- if( group->val2 ) { // Someone Traped
+ if( group->val2 ) { // Someone Trapped
struct status_change *tsc = status->get_sc(map->id2bl(group->val2));
if( tsc && tsc->data[SC__MANHOLE] )
tsc->data[SC__MANHOLE]->val4 = 0; // Remove the Unit ID
@@ -15599,7 +15669,7 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin
struct status_change* sc = status->get_sc(src);
if (sc && sc->data[SC_DANCING])
{
- sc->data[SC_DANCING]->val2 = 0 ; //This prevents status_change_end attempting to redelete the group. [Skotlex]
+ sc->data[SC_DANCING]->val2 = 0 ; //This prevents status_change_end attempting to re-delete the group. [Skotlex]
status_change_end(src, SC_DANCING, INVALID_TIMER);
}
}
@@ -15981,7 +16051,7 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) {
return 0;
}
/*==========================================
- * Executes on all skill units every SKILLUNITTIMER_INTERVAL miliseconds.
+ * Executes on all skill units every SKILLUNITTIMER_INTERVAL milliseconds.
*------------------------------------------*/
int skill_unit_timer(int tid, int64 tick, int id, intptr_t data) {
map->freeblock_lock();
@@ -16073,9 +16143,6 @@ int skill_unit_move_sub(struct block_list* bl, va_list ap) {
}
}
- //TODO: Normally, this is dangerous since the unit and group could be freed
- //inside the onout/onplace functions. Currently it is safe because we know song/dance
- //cells do not get deleted within them. [Skotlex]
if( dissonance ) skill->dance_switch(su, 1);
if( flag&4 )
@@ -16388,7 +16455,7 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid,
make_per = 100000; // Star Crumbs are 100% success crafting rate? (made 1000% so it succeeds even after penalties) [Skotlex]
break;
default: // Enchanted Stones
- make_per += 1000+i*500; // Enchantedstone Craft bonus: +15/+20/+25/+30/+35
+ make_per += 1000+i*500; // Enchanted stone Craft bonus: +15/+20/+25/+30/+35
break;
}
break;
@@ -16436,7 +16503,7 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid,
case ITEMID_COATING_BOTTLE:
make_per -= (1+rnd()%100)*10;
break;
- //Common items, recieve no bonus or penalty, listed just because they are commonly produced
+ //Common items, receive no bonus or penalty, listed just because they are commonly produced
case ITEMID_BLUE_POTION:
case ITEMID_RED_SLIM_POTION:
case ITEMID_ANODYNE:
@@ -17339,7 +17406,7 @@ int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick)
return 0;
}
-int skill_blockhomun_end(int tid, int64 tick, int id, intptr_t data) { //[orn]
+int skill_blockhomun_end(int tid, int64 tick, int id, intptr_t data) { // [orn]
struct homun_data *hd = (TBL_HOM*)map->id2bl(id);
if (data <= 0 || data >= MAX_SKILL)
return 0;
@@ -17348,7 +17415,7 @@ int skill_blockhomun_end(int tid, int64 tick, int id, intptr_t data) { //[orn]
return 1;
}
-int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { //[orn]
+int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { // [orn]
uint16 idx = skill->get_index(skill_id);
nullpo_retr (-1, hd);
@@ -17364,7 +17431,7 @@ int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { /
return timer->add(timer->gettick() + tick, skill->blockhomun_end, hd->bl.id, idx);
}
-int skill_blockmerc_end(int tid, int64 tick, int id, intptr_t data) {//[orn]
+int skill_blockmerc_end(int tid, int64 tick, int id, intptr_t data) {// [orn]
struct mercenary_data *md = (TBL_MER*)map->id2bl(id);
if( data <= 0 || data >= MAX_SKILL )
return 0;
@@ -17952,7 +18019,7 @@ bool skill_parse_row_requiredb(char* split[], int columns, int current) {
skill->split_atoi(split[5],skill->db[idx].sp_rate);
skill->split_atoi(split[6],skill->db[idx].zeny);
- //Wich weapon type are required, see doc/item_db for types
+ //Which weapon type are required, see doc/item_db for types
p = split[7];
for( j = 0; j < 32; j++ ) {
int l = atoi(p);
@@ -18449,7 +18516,7 @@ void skill_defaults(void) {
memset(&skill->area_temp,0,sizeof(skill->area_temp));
memset(&skill->unit_temp,0,sizeof(skill->unit_temp));
skill->unit_group_newid = 0;
- /* accesssors */
+ /* accessors */
skill->get_index = skill_get_index;
skill->get_type = skill_get_type;
skill->get_hit = skill_get_hit;
@@ -18520,7 +18587,7 @@ void skill_defaults(void) {
skill->unit_onplace = skill_unit_onplace;
skill->unit_ondamaged = skill_unit_ondamaged;
skill->cast_fix = skill_castfix;
- skill->cast_fix_sc = skill_castfix_sc;
+ skill->cast_fix_sc = skill_castfix_sc;
skill->vf_cast_fix = skill_vfcastfix;
skill->delay_fix = skill_delay_fix;
skill->check_condition_castbegin = skill_check_condition_castbegin;
@@ -18540,6 +18607,8 @@ void skill_defaults(void) {
skill->autospell = skill_autospell;
skill->calc_heal = skill_calc_heal;
skill->check_cloaking = skill_check_cloaking;
+ skill->check_cloaking_end = skill_check_cloaking_end;
+ skill->can_cloak = skill_can_cloak;
skill->enchant_elemental_end = skill_enchant_elemental_end;
skill->not_ok = skillnotok;
skill->not_ok_hom = skillnotok_hom;