diff options
Diffstat (limited to 'src/map/status.c')
-rw-r--r-- | src/map/status.c | 8168 |
1 files changed, 4317 insertions, 3851 deletions
diff --git a/src/map/status.c b/src/map/status.c index 497d02bbf..f4991cff2 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -96,16 +96,12 @@ int status_type2relevant_bl_types(int type) { if( type < 0 || type >= SI_MAX ) { ShowError("status_type2relevant_bl_types: Unsupported type %d\n", type); - return SI_BLANK; + return BL_NUL; } return status->RelevantBLTypes[type]; } -#define add_sc(skill,sc) set_sc(skill,sc,SI_BLANK,SCB_NONE) -// indicates that the status displays a visual effect for the affected unit, and should be sent to the client for all supported units -#define set_sc_with_vfx(skill, sc, icon, flag) set_sc((skill), (sc), (icon), (flag)); if((icon) < SI_MAX) status->RelevantBLTypes[(icon)] |= BL_SCEFFECT - static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) { uint16 idx; if( (idx = skill->get_index(skill_id)) == 0 ) { @@ -128,6 +124,10 @@ static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) { } void initChangeTables(void) { +#define add_sc(skill,sc) set_sc((skill),(sc),SI_BLANK,SCB_NONE) +// indicates that the status displays a visual effect for the affected unit, and should be sent to the client for all supported units +#define set_sc_with_vfx(skill, sc, icon, flag) do { set_sc((skill), (sc), (icon), (flag)); if((icon) < SI_MAX) status->RelevantBLTypes[(icon)] |= BL_SCEFFECT; } while(0) + int i; for (i = 0; i < SC_MAX; i++) @@ -593,21 +593,19 @@ void initChangeTables(void) { set_sc( NC_INFRAREDSCAN , SC_INFRAREDSCAN , SI_INFRAREDSCAN , SCB_FLEE ); set_sc( NC_ANALYZE , SC_ANALYZE , SI_ANALYZE , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 ); set_sc( NC_MAGNETICFIELD , SC_MAGNETICFIELD , SI_MAGNETICFIELD , SCB_NONE ); - set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SI_NEUTRALBARRIER , SCB_NONE ); + set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SI_NEUTRALBARRIER , SCB_DEF|SCB_MDEF ); set_sc( NC_STEALTHFIELD , SC_STEALTHFIELD , SI_STEALTHFIELD , SCB_NONE ); /** * Royal Guard **/ set_sc( LG_REFLECTDAMAGE , SC_LG_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE ); - set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP|SCB_DEF ); + set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP ); set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , SI_EXEEDBREAK , SCB_NONE ); set_sc( LG_PRESTIGE , SC_PRESTIGE , SI_PRESTIGE , SCB_DEF ); set_sc( LG_BANDING , SC_BANDING , SI_BANDING , SCB_DEF2|SCB_WATK );// Renewal: atk2 & def2 set_sc( LG_PIETY , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE ); set_sc( LG_EARTHDRIVE , SC_EARTHDRIVE , SI_EARTHDRIVE , SCB_DEF|SCB_ASPD ); set_sc( LG_INSPIRATION , SC_INSPIRATION , SI_INSPIRATION , SCB_MAXHP|SCB_WATK|SCB_HIT|SCB_VIT|SCB_AGI|SCB_STR|SCB_DEX|SCB_INT|SCB_LUK); - set_sc( LG_SHIELDSPELL , SC_SHIELDSPELL_DEF , SI_SHIELDSPELL_DEF , SCB_WATK ); - set_sc( LG_SHIELDSPELL , SC_SHIELDSPELL_REF , SI_SHIELDSPELL_REF , SCB_DEF ); set_sc( LG_KINGS_GRACE , SC_KINGS_GRACE , SI_KINGS_GRACE , SCB_NONE ); /** * Shadow Chaser @@ -626,8 +624,10 @@ void initChangeTables(void) { set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP ); set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSARY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK ); set_sc_with_vfx( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); - add_sc( SC_CHAOSPANIC , SC_CONFUSION ); - add_sc( SC_BLOODYLUST , SC_BERSERK ); + add_sc( SC_CHAOSPANIC , SC__CHAOS ); + add_sc( SC_MAELSTROM , SC__MAELSTROM ); + add_sc( SC_BLOODYLUST , SC_BERSERK ); + /** * Sura **/ @@ -646,10 +646,10 @@ void initChangeTables(void) { set_sc( WA_SWING_DANCE , SC_SWING , SI_SWINGDANCE , SCB_SPEED|SCB_ASPD ); set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONY_LOVE , SI_SYMPHONYOFLOVERS , SCB_MDEF ); set_sc( WA_MOONLIT_SERENADE , SC_MOONLIT_SERENADE , SI_MOONLITSERENADE , SCB_MATK ); - set_sc( MI_RUSH_WINDMILL , SC_RUSH_WINDMILL , SI_RUSHWINDMILL , SCB_BATK ); + set_sc( MI_RUSH_WINDMILL , SC_RUSH_WINDMILL , SI_RUSHWINDMILL , SCB_WATK ); set_sc( MI_ECHOSONG , SC_ECHOSONG , SI_ECHOSONG , SCB_DEF2 ); set_sc( MI_HARMONIZE , SC_HARMONIZE , SI_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); - set_sc_with_vfx( WM_POEMOFNETHERWORLD , SC_NETHERWORLD , SI_NETHERWORLD , SCB_NONE ); + set_sc( WM_POEMOFNETHERWORLD , SC_STOP , SI_NETHERWORLD , SCB_NONE ); set_sc_with_vfx( WM_VOICEOFSIREN , SC_SIREN , SI_SIREN , SCB_NONE ); set_sc_with_vfx( WM_LULLABY_DEEPSLEEP , SC_DEEP_SLEEP , SI_DEEPSLEEP , SCB_NONE ); set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SI_SIRCLEOFNATURE , SCB_NONE ); @@ -658,8 +658,8 @@ void initChangeTables(void) { set_sc( WM_DANCE_WITH_WUG , SC_DANCE_WITH_WUG , SI_DANCEWITHWUG , SCB_ASPD ); set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAY_NIGHT_FEVER , SI_SATURDAYNIGHTFEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN ); set_sc( WM_LERADS_DEW , SC_LERADS_DEW , SI_LERADSDEW , SCB_MAXHP ); - set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_BATK|SCB_MATK ); - set_sc( WM_BEYOND_OF_WARCRY , SC_BEYOND_OF_WARCRY , SI_WARCRYOFBEYOND , SCB_BATK|SCB_MATK ); + set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_INT ); + set_sc( WM_BEYOND_OF_WARCRY , SC_BEYOND_OF_WARCRY , SI_WARCRYOFBEYOND , SCB_STR|SCB_CRI|SCB_MAXHP ); set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITED_HUMMING_VOICE, SI_UNLIMITEDHUMMINGVOICE, SCB_NONE ); set_sc( WM_FRIGG_SONG , SC_FRIGG_SONG , SI_FRIGG_SONG , SCB_MAXHP ); @@ -670,7 +670,7 @@ void initChangeTables(void) { set_sc( SO_ELECTRICWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE ); set_sc( SO_SPELLFIST , SC_SPELLFIST , SI_SPELLFIST , SCB_NONE ); set_sc_with_vfx( SO_DIAMONDDUST , SC_COLD , SI_COLD , SCB_NONE ); // it does show the snow icon on mobs but doesn't affect it. - add_sc( SO_CLOUD_KILL , SC_POISON ); + set_sc( SO_CLOUD_KILL , SC_POISON , SI_CLOUDKILL , SCB_NONE ); set_sc( SO_STRIKING , SC_STRIKING , SI_STRIKING , SCB_WATK|SCB_CRI ); set_sc( SO_WARMER , SC_WARMER , SI_WARMER , SCB_NONE ); set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SI_VACUUM_EXTREME , SCB_NONE ); @@ -679,6 +679,7 @@ void initChangeTables(void) { set_sc( SO_WATER_INSIGNIA , SC_WATER_INSIGNIA , SI_WATER_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); set_sc( SO_WIND_INSIGNIA , SC_WIND_INSIGNIA , SI_WIND_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); set_sc( SO_EARTH_INSIGNIA , SC_EARTH_INSIGNIA , SI_EARTH_INSIGNIA , SCB_MDEF|SCB_DEF|SCB_MAXHP|SCB_MAXSP|SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); + add_sc( SO_ELEMENTAL_SHIELD , SC_SAFETYWALL ); /** * Genetic **/ @@ -712,8 +713,8 @@ void initChangeTables(void) { set_sc( EL_BLAST , SC_BLAST_OPTION , SI_BLAST_OPTION , SCB_ASPD ); set_sc( EL_WILD_STORM , SC_WILD_STORM_OPTION , SI_WILD_STORM_OPTION , SCB_ASPD ); set_sc( EL_PETROLOGY , SC_PETROLOGY_OPTION , SI_PETROLOGY_OPTION , SCB_MAXHP ); - set_sc( EL_CURSED_SOIL , SC_CURSED_SOIL_OPTION , SI_CURSED_SOIL_OPTION , SCB_NONE ); - set_sc( EL_UPHEAVAL , SC_UPHEAVAL_OPTION , SI_UPHEAVAL_OPTION , SCB_NONE ); + set_sc( EL_CURSED_SOIL , SC_CURSED_SOIL_OPTION , SI_CURSED_SOIL_OPTION , SCB_MAXHP ); + set_sc( EL_UPHEAVAL , SC_UPHEAVAL_OPTION , SI_UPHEAVAL_OPTION , SCB_MAXHP ); set_sc( EL_TIDAL_WEAPON , SC_TIDAL_WEAPON_OPTION , SI_TIDAL_WEAPON_OPTION , SCB_ALL ); set_sc( EL_ROCK_CRUSHER , SC_ROCK_CRUSHER , SI_ROCK_CRUSHER , SCB_DEF ); set_sc( EL_ROCK_CRUSHER_ATK, SC_ROCK_CRUSHER_ATK , SI_ROCK_CRUSHER_ATK , SCB_SPEED ); @@ -854,8 +855,6 @@ void initChangeTables(void) { status->IconChangeTable[SC_SHIELDSPELL_REF] = SI_SHIELDSPELL_REF; status->IconChangeTable[SC_BANDING_DEFENCE] = SI_BANDING_DEFENCE; - status->IconChangeTable[SC_GLOOMYDAY_SK] = SI_GLOOMYDAY; - status->IconChangeTable[SC_CURSEDCIRCLE_ATKER] = SI_CURSEDCIRCLE_ATKER; status->IconChangeTable[SC_STOMACHACHE] = SI_STOMACHACHE; @@ -906,6 +905,10 @@ void initChangeTables(void) { status->IconChangeTable[SC_REBOUND] = SI_REBOUND; status->IconChangeTable[SC_ALL_RIDING] = SI_ALL_RIDING; status->IconChangeTable[SC_MONSTER_TRANSFORM] = SI_MONSTER_TRANSFORM; + status->IconChangeTable[SC_MOONSTAR] = SI_MOONSTAR; + status->IconChangeTable[SC_SUPER_STAR] = SI_SUPER_STAR; + status->IconChangeTable[SC_STRANGELIGHTS] = SI_STRANGELIGHTS; + status->IconChangeTable[SC_DECORATION_OF_MUSIC] = SI_DECORATION_OF_MUSIC; //Other SC which are not necessarily associated to skills. status->ChangeFlagTable[SC_ATTHASTE_POTION1] = SCB_ASPD; @@ -967,10 +970,17 @@ void initChangeTables(void) { status->ChangeFlagTable[SC_MER_SP] |= SCB_MAXSP; status->ChangeFlagTable[SC_MER_HIT] |= SCB_HIT; // Guillotine Cross Poison Effects - status->ChangeFlagTable[SC_PARALYSE] |= SCB_ASPD|SCB_FLEE|SCB_SPEED; - status->ChangeFlagTable[SC_DEATHHURT] |= SCB_REGEN; + status->ChangeFlagTable[SC_PARALYSE] |= SCB_FLEE|SCB_SPEED|SCB_ASPD; status->ChangeFlagTable[SC_VENOMBLEED] |= SCB_MAXHP; + status->ChangeFlagTable[SC_MAGICMUSHROOM] |= SCB_REGEN; + status->ChangeFlagTable[SC_DEATHHURT] |= SCB_REGEN; + status->ChangeFlagTable[SC_PYREXIA] |= SCB_HIT|SCB_FLEE; status->ChangeFlagTable[SC_OBLIVIONCURSE] |= SCB_REGEN; + // RG status + status->ChangeFlagTable[SC_SHIELDSPELL_DEF] |= SCB_WATK; + status->ChangeFlagTable[SC_SHIELDSPELL_REF] |= SCB_DEF; + // Meca status + status->ChangeFlagTable[SC_STEALTHFIELD_MASTER] |= SCB_SPEED; status->ChangeFlagTable[SC_SAVAGE_STEAK] |= SCB_STR; status->ChangeFlagTable[SC_COCKTAIL_WARG_BLOOD] |= SCB_INT; @@ -991,6 +1001,14 @@ void initChangeTables(void) { status->ChangeFlagTable[SC_ALL_RIDING] = SCB_SPEED; status->ChangeFlagTable[SC_WEDDING] = SCB_SPEED; + status->ChangeFlagTable[SC_MTF_ASPD] = SCB_ASPD|SCB_HIT; + status->ChangeFlagTable[SC_MTF_MATK] = SCB_MATK; + status->ChangeFlagTable[SC_MTF_MLEATKED] |= SCB_ALL; + + status->ChangeFlagTable[SC_MOONSTAR] |= SCB_NONE; + status->ChangeFlagTable[SC_SUPER_STAR] |= SCB_NONE; + status->ChangeFlagTable[SC_STRANGELIGHTS] |= SCB_NONE; + status->ChangeFlagTable[SC_DECORATION_OF_MUSIC] |= SCB_NONE; /* status->DisplayType Table [Ind/Hercules] */ status->DisplayType[SC_ALL_RIDING] = true; @@ -1014,8 +1032,11 @@ void initChangeTables(void) { status->DisplayType[SC_CURSEDCIRCLE_TARGET]= true; status->DisplayType[SC_BLOOD_SUCKER] = true; status->DisplayType[SC__SHADOWFORM] = true; - status->DisplayType[SC__MANHOLE] = true; status->DisplayType[SC_MONSTER_TRANSFORM] = true; + status->DisplayType[SC_MOONSTAR] = true; + status->DisplayType[SC_SUPER_STAR] = true; + status->DisplayType[SC_STRANGELIGHTS] = true; + status->DisplayType[SC_DECORATION_OF_MUSIC] = true; #ifdef RENEWAL_EDP // renewal EDP increases your weapon atk @@ -1024,6 +1045,8 @@ void initChangeTables(void) { if( !battle_config.display_hallucination ) //Disable Hallucination. status->IconChangeTable[SC_ILLUSION] = SI_BLANK; +#undef add_sc +#undef set_sc_with_vfx } void initDummyData(void) @@ -1156,6 +1179,21 @@ int status_damage(struct block_list *src,struct block_list *target,int64 in_hp, if( hp && !(flag&1) ) { if( sc ) { struct status_change_entry *sce; + +#ifdef DEVOTION_REFLECT_DAMAGE + if(src && (sce = sc->data[SC_DEVOTION])) { + struct block_list *d_bl = map->id2bl(sce->val1); + + if(d_bl &&((d_bl->type == BL_MER && ((TBL_MER *)d_bl)->master && ((TBL_MER *)d_bl)->master->bl.id == target->id) + || (d_bl->type == BL_PC && ((TBL_PC *)d_bl)->devotion[sce->val2] == target->id)) && check_distance_bl(target, d_bl, sce->val3)) { + clif->damage(d_bl, d_bl, 0, 0, hp, 0, 0, 0); + status_fix_damage(NULL, d_bl, hp, 0); + return 0; + } + status_change_end(target, SC_DEVOTION, INVALID_TIMER); + } +#endif + if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) status_change_end(target, SC_STONE, INVALID_TIMER); status_change_end(target, SC_FREEZE, INVALID_TIMER); @@ -1167,8 +1205,6 @@ int status_damage(struct block_list *src,struct block_list *target,int64 in_hp, status_change_end(target, SC_CLOAKING, INVALID_TIMER); status_change_end(target, SC_CHASEWALK, INVALID_TIMER); status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER); - status_change_end(target, SC__INVISIBILITY, INVALID_TIMER); - status_change_end(target, SC_DEEP_SLEEP, INVALID_TIMER); if ((sce=sc->data[SC_ENDURE]) && !sce->val4 && !sc->data[SC_LKCONCENTRATION]) { //Endure count is only reduced by non-players on non-gvg maps. //val4 signals infinite endure. [Skotlex] @@ -1200,7 +1236,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 in_hp, if (sc->data[SC_AUTOBERSERK] && (!sc->data[SC_PROVOKE] || !sc->data[SC_PROVOKE]->val2) && st->hp < st->max_hp>>2) - sc_start4(target,SC_PROVOKE,100,10,1,0,0,0); + sc_start4(src,target,SC_PROVOKE,100,10,1,0,0,0); if (sc->data[SC_BERSERK] && st->hp <= 100) status_change_end(target, SC_BERSERK, INVALID_TIMER); if( sc->data[SC_RAISINGDRAGON] && st->hp <= 1000 ) @@ -1276,7 +1312,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 in_hp, status->revive(target, sc->data[SC_KAIZEL]->val2, 0); status->change_clear(target,0); clif->skill_nodamage(target,target,ALL_RESURRECTION,1,1); - sc_start(target,status->skill2sc(PR_KYRIE),100,10,time); + sc_start(target,target,status->skill2sc(PR_KYRIE),100,10,time); if( target->type == BL_MOB ) ((TBL_MOB*)target)->state.rebirth = 1; @@ -1406,34 +1442,28 @@ int status_percent_change(struct block_list *src,struct block_list *target,signe st = status->get_status_data(target); - - //It's safe now [MarkZD] - if (hp_rate > 99) - hp = st->hp; - else if (hp_rate > 0) - hp = st->hp>10000? - hp_rate*(st->hp/100): - ((int64)hp_rate*st->hp)/100; - else if (hp_rate < -99) - hp = st->max_hp; - else if (hp_rate < 0) - hp = st->max_hp>10000? - (-hp_rate)*(st->max_hp/100): - ((int64)-hp_rate*st->max_hp)/100; + if (hp_rate > 100) + hp_rate = 100; + else if (hp_rate < -100) + hp_rate = -100; + if (hp_rate > 0) + hp = APPLY_RATE(st->hp, hp_rate); + else + hp = APPLY_RATE(st->max_hp, -hp_rate); if (hp_rate && !hp) hp = 1; if (flag == 2 && hp >= st->hp) hp = st->hp-1; //Must not kill target. - if (sp_rate > 99) - sp = st->sp; - else if (sp_rate > 0) - sp = ((int64)sp_rate*st->sp)/100; - else if (sp_rate < -99) - sp = st->max_sp; - else if (sp_rate < 0) - sp = ((int64)-sp_rate)*st->max_sp/100; + if (sp_rate > 100) + sp_rate = 100; + else if (sp_rate < -100) + sp_rate = -100; + if (sp_rate > 0) + sp = APPLY_RATE(st->sp, sp_rate); + else + sp = APPLY_RATE(st->max_sp, -sp_rate); if (sp_rate && !sp) sp = 1; @@ -1467,8 +1497,8 @@ int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per if (st == &status->dummy) return 0; //Invalid target. - hp = (int64)st->max_hp * per_hp/100; - sp = (int64)st->max_sp * per_sp/100; + hp = APPLY_RATE(st->max_hp, per_hp); + sp = APPLY_RATE(st->max_sp, per_sp); if(hp > st->max_hp - st->hp) hp = st->max_hp - st->hp; @@ -1495,6 +1525,41 @@ int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per return 1; } +int status_fixed_revive(struct block_list *bl, unsigned int per_hp, unsigned int per_sp) { + struct status_data *st; + unsigned int hp, sp; + if (!status->isdead(bl)) return 0; + + st = status->get_status_data(bl); + if (st == &status->dummy) + return 0; //Invalid target. + + hp = per_hp; + sp = per_sp; + + if(hp > st->max_hp - st->hp) + hp = st->max_hp - st->hp; + else if (per_hp && !hp) + hp = 1; + + if(sp > st->max_sp - st->sp) + sp = st->max_sp - st->sp; + else if (per_sp && !sp) + sp = 1; + + st->hp += hp; + st->sp += sp; + + if (bl->prev) //Animation only if character is already on a map. + clif->resurrection(bl, 1); + switch (bl->type) { + case BL_PC: pc->revive((TBL_PC*)bl, hp, sp); break; + case BL_MOB: mob->revive((TBL_MOB*)bl, hp); break; + case BL_HOM: homun->revive((TBL_HOM*)bl, hp, sp); break; + } + return 1; +} + /*========================================== * Checks whether the src can use the skill on the target, * taking into account status/option of both source/target. [Skotlex] @@ -1667,7 +1732,6 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin switch(skill_id) {//##TODO## make this a flag in skill_db? // Skills that can be used even under Man Hole effects. case SC_SHADOWFORM: - case SC_STRIPACCESSARY: break; default: return 0; @@ -1694,8 +1758,13 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin return 0; } } - if (sc->option&OPTION_CHASEWALK && skill_id != ST_CHASEWALK) - return 0; + if ( sc->option&OPTION_CHASEWALK ) { + if ( sc->data[SC__INVISIBILITY] ) { + if ( skill_id != 0 && skill_id != SC_INVISIBILITY ) + return 0; + } else if ( skill_id != ST_CHASEWALK ) + return 0; + } if( sc->data[SC_ALL_RIDING] ) return 0;//New mounts can't attack nor use skills in the client; this check makes it cheat-safe [Ind] } @@ -1716,6 +1785,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin return 0; if(skill_id == PR_LEXAETERNA && (tsc->data[SC_FREEZE] || (tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE))) return 0; + if( ( tsc->data[SC_STEALTHFIELD] || tsc->data[SC_CAMOUFLAGE] ) && !(st->mode&(MD_BOSS|MD_DETECTOR)) && flag == 4 ) + return 0; } //If targetting, cloak+hide protect you, otherwise only hiding does. hide_flag = flag?OPTION_HIDE:(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK); @@ -1725,10 +1796,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin hide_flag &= ~OPTION_HIDE; else { switch ( skill_id ) { - case LG_OVERBRAND: - case LG_OVERBRAND_BRANDISH: - case LG_OVERBRAND_PLUSATK: - hide_flag &=~ OPTION_CLOAK|OPTION_CHASEWALK; + case MO_ABSORBSPIRITS: // it works when already casted and target suddenly hides. + hide_flag &= ~OPTION_HIDE; break; } } @@ -1740,14 +1809,16 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin bool is_detect = ((st->mode&MD_DETECTOR)?true:false);//god-knows-why gcc doesn't shut up until this happens if (pc_isinvisible(sd)) return 0; - if (tsc->option&hide_flag && !is_boss && - ((sd->special_state.perfect_hiding || !is_detect) || - (tsc->data[SC_CLOAKINGEXCEED] && is_detect))) - return 0; - if( tsc->data[SC_CAMOUFLAGE] && !(is_boss || is_detect) && !skill_id ) - return 0; - if( tsc->data[SC_STEALTHFIELD] && !is_boss ) - return 0; + if( tsc ) { + if (tsc->option&hide_flag && !is_boss && + ((sd->special_state.perfect_hiding || !is_detect) || + (tsc->data[SC_CLOAKINGEXCEED] && is_detect))) + return 0; + if( tsc->data[SC_CAMOUFLAGE] && !(is_boss || is_detect) && (!skill_id || (flag == 0 && src && src->type != BL_PC)) ) + return 0; + if( tsc->data[SC_STEALTHFIELD] && !is_boss ) + return 0; + } } break; case BL_ITEM: //Allow targetting of items to pick'em up (or in the case of mobs, to loot them). @@ -1780,38 +1851,38 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin //Checks whether the source can see and chase target. int status_check_visibility(struct block_list *src, struct block_list *target) { int view_range; - struct status_data *st = status->get_status_data(src); - struct status_change *tsc = status->get_sc(target); + struct status_change *tsc = NULL; + switch (src->type) { - case BL_MOB: - view_range = ((TBL_MOB*)src)->min_chase; - break; - case BL_PET: - view_range = ((TBL_PET*)src)->db->range2; - break; - default: - view_range = AREA_SIZE; + case BL_MOB: + view_range = ((TBL_MOB*)src)->min_chase; + break; + case BL_PET: + view_range = ((TBL_PET*)src)->db->range2; + break; + default: + view_range = AREA_SIZE; } if (src->m != target->m || !check_distance_bl(src, target, view_range)) return 0; - if( tsc && tsc->data[SC_STEALTHFIELD] ) - return 0; + if( ( tsc = status->get_sc(target) ) ) { + struct status_data *st = status->get_status_data(src); - switch (target->type) - { //Check for chase-walk/hiding/cloaking opponents. - case BL_PC: - if ( tsc->data[SC_CLOAKINGEXCEED] && !(st->mode&MD_BOSS) ) - return 0; - if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY] || tsc->data[SC_CAMOUFLAGE]) && !(st->mode&MD_BOSS) && - ( ((TBL_PC*)target)->special_state.perfect_hiding || !(st->mode&MD_DETECTOR) ) ) - return 0; - break; - default: - if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY] || tsc->data[SC_CAMOUFLAGE]) && !(st->mode&(MD_BOSS|MD_DETECTOR)) ) - return 0; + switch (target->type) { //Check for chase-walk/hiding/cloaking opponents. + case BL_PC: + if ( tsc->data[SC_CLOAKINGEXCEED] && !(st->mode&MD_BOSS) ) + return 0; + if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_STEALTHFIELD] || tsc->data[SC__INVISIBILITY] || tsc->data[SC_CAMOUFLAGE]) && !(st->mode&MD_BOSS) && + ( ((TBL_PC*)target)->special_state.perfect_hiding || !(st->mode&MD_DETECTOR) ) ) + return 0; + break; + default: + if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_CAMOUFLAGE]) && !(st->mode&(MD_BOSS|MD_DETECTOR)) ) + return 0; + } } return 1; @@ -1824,11 +1895,11 @@ int status_base_amotion_pc(struct map_session_data *sd, struct status_data *st) short mod = -1; switch( sd->weapontype2 ){ // adjustment for dual weilding - case W_DAGGER: mod = 0; break; // 0, 1, 1 - case W_1HSWORD: - case W_1HAXE: mod = 1; - if( (sd->class_&MAPID_THIRDMASK) == MAPID_GUILLOTINE_CROSS ) // 0, 2, 3 - mod = sd->weapontype2 / W_1HSWORD + W_1HSWORD / sd->weapontype2 ; + case W_DAGGER: mod = 0; break; // 0, 1, 1 + case W_1HSWORD: + case W_1HAXE: mod = 1; + if( (sd->class_&MAPID_THIRDMASK) == MAPID_GUILLOTINE_CROSS ) // 0, 2, 3 + mod = sd->weapontype2 / W_1HSWORD + W_1HSWORD / sd->weapontype2 ; } amotion = ( sd->status.weapon < MAX_WEAPON_TYPE && mod < 0 ) @@ -1851,9 +1922,14 @@ int status_base_amotion_pc(struct map_session_data *sd, struct status_data *st) // percentual delay reduction from stats amotion -= amotion * (4*st->agi + st->dex)/1000; #endif + // raw delay adjustment from bAspd bonus amotion += sd->bonus.aspd_add; + /* angra manyu disregards aspd_base and similar */ + if( sd->equip_index[EQI_HAND_R] >= 0 && sd->status.inventory[sd->equip_index[EQI_HAND_R]].nameid == ITEMID_ANGRA_MANYU ) + return 0; + return amotion; } @@ -1989,13 +2065,12 @@ void status_calc_misc(struct block_list *bl, struct status_data *st, int level) //Skotlex: Calculates the initial status for the given mob //first will only be false when the mob leveled up or got a GuardUp level. -int status_calc_mob_(struct mob_data* md, bool first) { +int status_calc_mob_(struct mob_data* md, enum e_status_calc_opt opt) { struct status_data *mstatus; struct block_list *mbl = NULL; int flag=0; - if(first) - { //Set basic level on respawn. + if(opt&SCO_FIRST) { //Set basic level on respawn. if (md->level > 0 && md->level <= MAX_LEVEL && md->level != md->db->lv) ; else @@ -2011,8 +2086,6 @@ int status_calc_mob_(struct mob_data* md, bool first) { if (md->guardian_data && md->guardian_data->guardup_lv) flag|=4; - if (md->class_ == MOBID_EMPERIUM) - flag|=4; if (battle_config.slaves_inherit_speed && md->master_id) flag|=8; @@ -2026,7 +2099,7 @@ int status_calc_mob_(struct mob_data* md, bool first) { aFree(md->base_status); md->base_status = NULL; } - if(first) + if(opt&SCO_FIRST) memcpy(&md->status, &md->db->status, sizeof(struct status_data)); return 0; } @@ -2040,12 +2113,13 @@ int status_calc_mob_(struct mob_data* md, bool first) { mbl = map->id2bl(md->master_id); if (flag&8 && mbl) { - struct status_data *mstatus = status->get_base_status(mbl); - if (mstatus && - battle_config.slaves_inherit_speed&(mstatus->mode&MD_CANMOVE?1:2)) - mstatus->speed = mstatus->speed; - if( mstatus->speed < 2 ) /* minimum for the unit to function properly */ - mstatus->speed = 2; + struct status_data *masterstatus = status->get_base_status(mbl); + if ( masterstatus ) { + if (battle_config.slaves_inherit_speed&(masterstatus->mode&MD_CANMOVE ? 1 : 2)) + mstatus->speed = masterstatus->speed; + if (mstatus->speed < 2) /* minimum for the unit to function properly */ + mstatus->speed = 2; + } } if (flag&16 && mbl) { @@ -2065,6 +2139,8 @@ int status_calc_mob_(struct mob_data* md, bool first) { mstatus->mode|= MD_CANATTACK|MD_AGGRESSIVE; } mstatus->hp = mstatus->max_hp; + if( ud->skill_id == NC_SILVERSNIPER ) + mstatus->rhw.atk = mstatus->rhw.atk2 = 200 * ud->skill_lv; } } @@ -2087,7 +2163,7 @@ int status_calc_mob_(struct mob_data* md, bool first) { if (flag&2 && battle_config.mob_size_influence) { // change for sized monsters [Valaris] - if (md->special_state.size==SZ_MEDIUM) { + if (md->special_state.size==SZ_SMALL) { mstatus->max_hp>>=1; mstatus->max_sp>>=1; if (!mstatus->max_hp) mstatus->max_hp = 1; @@ -2150,18 +2226,18 @@ int status_calc_mob_(struct mob_data* md, bool first) { } } - if( first ) //Initial battle status + if( opt&SCO_FIRST ) //Initial battle status memcpy(&md->status, mstatus, sizeof(struct status_data)); return 1; } //Skotlex: Calculates the stats of the given pet. -int status_calc_pet_(struct pet_data *pd, bool first) +int status_calc_pet_(struct pet_data *pd, enum e_status_calc_opt opt) { nullpo_ret(pd); - if (first) { + if (opt&SCO_FIRST) { memcpy(&pd->status, &pd->db->status, sizeof(struct status_data)); pd->status.mode = MD_CANMOVE; // pets discard all modes, except walking pd->status.speed = pd->petDB->speed; @@ -2179,10 +2255,10 @@ int status_calc_pet_(struct pet_data *pd, bool first) lv =sd->status.base_level*battle_config.pet_lv_rate/100; if (lv < 0) lv = 1; - if (lv != pd->pet.level || first) { + if (lv != pd->pet.level || opt&SCO_FIRST) { struct status_data *bstat = &pd->db->status, *pstatus = &pd->status; pd->pet.level = lv; - if (!first) //Lv Up animation + if (! (opt&SCO_FIRST) ) //Lv Up animation clif->misceffect(&pd->bl, 0); pstatus->rhw.atk = (bstat->rhw.atk*lv)/pd->db->lv; pstatus->rhw.atk2 = (bstat->rhw.atk2*lv)/pd->db->lv; @@ -2204,10 +2280,10 @@ int status_calc_pet_(struct pet_data *pd, bool first) status->calc_misc(&pd->bl, &pd->status, lv); - if (!first) //Not done the first time because the pet is not visible yet + if (! (opt&SCO_FIRST) ) //Not done the first time because the pet is not visible yet clif->send_petstatus(sd); } - } else if (first) { + } else if ( opt&SCO_FIRST ) { status->calc_misc(&pd->bl, &pd->status, pd->db->lv); if (!battle_config.pet_lv_rate && pd->pet.level != pd->db->lv) pd->pet.level = pd->db->lv; @@ -2285,7 +2361,7 @@ unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct status_dat //Calculates player data from scratch without counting SC adjustments. //Should be invoked whenever players raise stats, learn passive skills or change equipment. -int status_calc_pc_(struct map_session_data* sd, bool first) { +int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) { static int calculating = 0; //Check for recursive call preemption. [Skotlex] struct status_data *bstatus; // pointer to the player's base status const struct status_change *sc = &sd->sc; @@ -2307,7 +2383,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { sd->max_weight = status->max_weight_base[pc->class2idx(sd->status.class_)]+sd->status.str*300; - if(first) { + if(opt&SCO_FIRST) { //Load Hp/SP from char-received data. sd->battle_status.hp = sd->status.hp; sd->battle_status.sp = sd->status.sp; @@ -2379,21 +2455,27 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_CLAIRVOYANCE); memset(&sd->special_state,0,sizeof(sd->special_state)); - memset(&bstatus->max_hp, 0, sizeof(struct status_data)-(sizeof(bstatus->hp)+sizeof(bstatus->sp))); - - //FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex] - if (!sd->state.permanent_speed) + + if (!sd->state.permanent_speed) { + memset(&bstatus->max_hp, 0, sizeof(struct status_data)-(sizeof(bstatus->hp)+sizeof(bstatus->sp))); bstatus->speed = DEFAULT_WALK_SPEED; + } else { + int pSpeed = bstatus->speed; + memset(&bstatus->max_hp, 0, sizeof(struct status_data)-(sizeof(bstatus->hp)+sizeof(bstatus->sp))); + bstatus->speed = pSpeed; + } + + //FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex] //Give them all modes except these (useful for clones) bstatus->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK); - bstatus->size = (sd->class_&JOBL_BABY)?SZ_SMALL:SZ_MEDIUM; + bstatus->size = (sd->class_&JOBL_BABY)?SZ_MEDIUM:SZ_SMALL; if (battle_config.character_size && (pc_isriding(sd) || pc_isridingdragon(sd)) ) { //[Lupus] if (sd->class_&JOBL_BABY) { if (battle_config.character_size&SZ_BIG) bstatus->size++; } else - if(battle_config.character_size&SZ_MEDIUM) + if(battle_config.character_size&SZ_SMALL) bstatus->size++; } bstatus->aspd_rate = 1000; @@ -2438,10 +2520,11 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { pc->delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true); // Parse equipment. - for(i=0;i<EQI_MAX-1;i++) { + for(i=0;i<EQI_MAX;i++) { status->current_equip_item_index = index = sd->equip_index[i]; //We pass INDEX to status->current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus] if(index < 0) continue; + if(i == EQI_AMMO) continue;/* ammo has special handler down there */ if(i == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue; if(i == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) @@ -2466,7 +2549,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { bstatus->def += sd->inventory_data[index]->def; - if(first && sd->inventory_data[index]->equip_script) + if(opt&SCO_FIRST && sd->inventory_data[index]->equip_script) { //Execute equip-script on login script->run(sd->inventory_data[index]->equip_script,0,sd->bl.id,0); if (!calculating) @@ -2558,12 +2641,29 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { } /* we've got combos to process */ - if( sd->combos.count ) { - for( i = 0; i < sd->combos.count; i++ ) { - script->run(sd->combos.bonus[i],0,sd->bl.id,0); - if (!calculating) //Abort, script->run retriggered this. - return 1; + for( i = 0; i < sd->combo_count; i++ ) { + struct item_combo *combo = itemdb->id2combo(sd->combos[i].id); + unsigned char j; + + /** + * ensure combo usage is allowed at this location + **/ + for(j = 0; j < combo->count; j++) { + for(k = 0; k < map->list[sd->bl.m].zone->disabled_items_count; k++) { + if( map->list[sd->bl.m].zone->disabled_items[k] == combo->nameid[j] ) { + break; + } + } + if( k != map->list[sd->bl.m].zone->disabled_items_count ) + break; } + + if( j != combo->count ) + continue; + + script->run(sd->combos[i].bonus,0,sd->bl.id,0); + if (!calculating) //Abort, script->run retriggered this. + return 1; } //Store equipment script bonuses @@ -2573,10 +2673,11 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { bstatus->def += (refinedef+50)/100; //Parse Cards - for(i=0;i<EQI_MAX-1;i++) { + for(i=0;i<EQI_MAX;i++) { status->current_equip_item_index = index = sd->equip_index[i]; //We pass INDEX to status->current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus] if(index < 0) continue; + if(i == EQI_AMMO) continue;/* ammo doesn't have cards */ if(i == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue; if(i == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) @@ -2609,7 +2710,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { if( k < map->list[sd->bl.m].zone->disabled_items_count ) continue; - if(first && data->equip_script) {//Execute equip-script on login + if(opt&SCO_FIRST && data->equip_script) {//Execute equip-script on login script->run(data->equip_script,0,sd->bl.id,0); if (!calculating) return 1; @@ -2750,9 +2851,9 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { if(sd->hprate < 0) sd->hprate = 0; if(sd->hprate!=100) - bstatus->max_hp = (int64)bstatus->max_hp * sd->hprate/100; + bstatus->max_hp = APPLY_RATE(bstatus->max_hp, sd->hprate); if(battle_config.hp_rate != 100) - bstatus->max_hp = (int64)bstatus->max_hp * battle_config.hp_rate/100; + bstatus->max_hp = APPLY_RATE(bstatus->max_hp, battle_config.hp_rate); if(bstatus->max_hp > (unsigned int)battle_config.max_hp) bstatus->max_hp = battle_config.max_hp; @@ -2784,9 +2885,9 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { if(sd->sprate < 0) sd->sprate = 0; if(sd->sprate!=100) - bstatus->max_sp = (int64)bstatus->max_sp * sd->sprate/100; + bstatus->max_sp = APPLY_RATE(bstatus->max_sp, sd->sprate); if(battle_config.sp_rate != 100) - bstatus->max_sp = (int64)bstatus->max_sp * battle_config.sp_rate/100; + bstatus->max_sp = APPLY_RATE(bstatus->max_sp, battle_config.sp_rate); if(bstatus->max_sp > (unsigned int)battle_config.max_sp) bstatus->max_sp = battle_config.max_sp; @@ -2805,11 +2906,11 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { && battle_config.restart_hp_rate < 50) bstatus->hp = bstatus->max_hp>>1; else - bstatus->hp = (int64)bstatus->max_hp * battle_config.restart_hp_rate/100; + bstatus->hp = APPLY_RATE(bstatus->max_hp, battle_config.restart_hp_rate); if(!bstatus->hp) bstatus->hp = 1; - bstatus->sp = (int64)bstatus->max_sp * battle_config.restart_sp_rate /100; + bstatus->sp = APPLY_RATE(bstatus->max_sp, battle_config.restart_sp_rate); if( !bstatus->sp ) /* the minimum for the respawn setting is SP:1 */ bstatus->sp = 1; @@ -2879,6 +2980,10 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { bstatus->rhw.range += skill_lv; } } + if( (sd->status.weapon == W_1HAXE || sd->status.weapon == W_2HAXE) && (skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0 ) + bstatus->hit += 3*skill_lv; + if((sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE) && ((skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0)) + bstatus->hit += 2*skill_lv; // ----- FLEE CALCULATION ----- @@ -2897,6 +3002,9 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { bstatus->def = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX); } + if( pc_ismadogear(sd) && (skill_lv = pc->checkskill(sd,NC_MAINFRAME)) > 0 ) + bstatus->def += 20 + 20 * skill_lv; + #ifndef RENEWAL if (!battle_config.weapon_defense_type && bstatus->def > battle_config.max_def) { bstatus->def2 += battle_config.over_def_bonus*(bstatus->def -battle_config.max_def); @@ -3030,6 +3138,17 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { sd->subrace[RC_DRAGON]+=skill_lv; } + if( (skill_lv = pc->checkskill(sd, AB_EUCHARISTICA)) > 0 ) { + sd->right_weapon.addrace[RC_DEMON] += skill_lv; + sd->right_weapon.addele[ELE_DARK] += skill_lv; + sd->left_weapon.addrace[RC_DEMON] += skill_lv; + sd->left_weapon.addele[ELE_DARK] += skill_lv; + sd->magic_addrace[RC_DEMON] += skill_lv; + sd->magic_addele[ELE_DARK] += skill_lv; + sd->subrace[RC_DEMON] += skill_lv; + sd->subele[ELE_DARK] += skill_lv; + } + if(sc->count) { if(sc->data[SC_CONCENTRATION]) { //Update the card-bonus data sc->data[SC_CONCENTRATION]->val3 = sd->param_bonus[1]; //Agi @@ -3083,6 +3202,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { sd->subele[ELE_EARTH] += i; sd->subele[ELE_FIRE] -= i; } + if( sc->data[SC_MTF_MLEATKED] ) + sd->subele[ELE_NEUTRAL] += 2; if( sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3 ) sd->magic_addele[ELE_FIRE] += 25; if( sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 3 ) @@ -3117,11 +3238,11 @@ int status_calc_pc_(struct map_session_data* sd, bool first) { return 0; } -int status_calc_mercenary_(struct mercenary_data *md, bool first) { +int status_calc_mercenary_(struct mercenary_data *md, enum e_status_calc_opt opt) { struct status_data *mstatus = &md->base_status; struct s_mercenary *merc = &md->mercenary; - if( first ) { + if( opt&SCO_FIRST ) { memcpy(mstatus, &md->db->status, sizeof(struct status_data)); mstatus->mode = MD_CANMOVE|MD_CANATTACK; mstatus->hp = mstatus->max_hp; @@ -3136,7 +3257,7 @@ int status_calc_mercenary_(struct mercenary_data *md, bool first) { return 0; } -int status_calc_homunculus_(struct homun_data *hd, bool first) { +int status_calc_homunculus_(struct homun_data *hd, enum e_status_calc_opt opt) { struct status_data *hstatus = &hd->base_status; struct s_homunculus *hom = &hd->homunculus; int skill_lv; @@ -3149,7 +3270,7 @@ int status_calc_homunculus_(struct homun_data *hd, bool first) { hstatus->int_ = hom->int_ / 10; hstatus->luk = hom->luk / 10; - if (first) { //[orn] + if ( opt&SCO_FIRST ) { //[orn] const struct s_homunculus_db *db = hd->homunculusDB; hstatus->def_ele = db->element; hstatus->ele_lv = 1; @@ -3189,7 +3310,7 @@ int status_calc_homunculus_(struct homun_data *hd, bool first) { if((skill_lv = homun->checkskill(hd,HLIF_BRAIN)) > 0) hstatus->max_sp += (1 +skill_lv/2 -skill_lv/4 +skill_lv/5) * hstatus->max_sp / 100; - if (first) { + if ( opt&SCO_FIRST ) { hd->battle_status.hp = hom->hp; hd->battle_status.sp = hom->sp; } @@ -3213,7 +3334,7 @@ int status_calc_homunculus_(struct homun_data *hd, bool first) { return 1; } -int status_calc_elemental_(struct elemental_data *ed, bool first) { +int status_calc_elemental_(struct elemental_data *ed, enum e_status_calc_opt opt) { struct status_data *estatus = &ed->base_status; struct s_elemental *ele = &ed->elemental; struct map_session_data *sd = ed->master; @@ -3221,7 +3342,7 @@ int status_calc_elemental_(struct elemental_data *ed, bool first) { if( !sd ) return 0; - if( first ) { + if( opt&SCO_FIRST ) { memcpy(estatus, &ed->db->status, sizeof(struct status_data)); if( !ele->mode ) estatus->mode = EL_MODE_PASSIVE; @@ -3252,13 +3373,13 @@ int status_calc_elemental_(struct elemental_data *ed, bool first) { return 0; } -int status_calc_npc_(struct npc_data *nd, bool first) { +int status_calc_npc_(struct npc_data *nd, enum e_status_calc_opt opt) { struct status_data *nstatus = &nd->status; if (!nd) return 0; - if (first) { + if ( opt&SCO_FIRST ) { nstatus->hp = 1; nstatus->sp = 1; nstatus->max_hp = 1; @@ -3334,7 +3455,7 @@ void status_calc_regen(struct block_list *bl, struct status_data *st, struct reg if( (skill_lv=pc->checkskill(sd,NJ_NINPOU)) > 0 ) val += skill_lv*3 + skill_lv*st->max_sp/500; if( (skill_lv=pc->checkskill(sd,WM_LESSON)) > 0 ) - val += 3 + 3 * skill_lv; + val += skill_lv*3 + skill_lv*st->max_sp/500; sregen->sp = cap_value(val, 0, SHRT_MAX); @@ -3415,50 +3536,43 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str if (!sc || !sc->count) return; - if ( - (sc->data[SC_POISON] && !sc->data[SC_SLOWPOISON]) - || (sc->data[SC_DPOISON] && !sc->data[SC_SLOWPOISON]) - || sc->data[SC_BERSERK] - || sc->data[SC_TRICKDEAD] - || sc->data[SC_BLOODING] - || sc->data[SC_MAGICMUSHROOM] - || sc->data[SC_RAISINGDRAGON] - || sc->data[SC_SATURDAY_NIGHT_FEVER] + if ((sc->data[SC_POISON] && !sc->data[SC_SLOWPOISON]) + || (sc->data[SC_DPOISON] && !sc->data[SC_SLOWPOISON]) + || sc->data[SC_BERSERK] + || sc->data[SC_TRICKDEAD] + || sc->data[SC_BLOODING] + || sc->data[SC_MAGICMUSHROOM] + || sc->data[SC_RAISINGDRAGON] + || sc->data[SC_SATURDAY_NIGHT_FEVER] ) //No regen regen->flag = 0; - if ( - sc->data[SC_DANCING] || sc->data[SC_OBLIVIONCURSE] || sc->data[SC_MAXIMIZEPOWER] || sc->data[SC_REBOUND] - || ( - (bl->type == BL_PC && ((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK && - (sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SOULLINK] || sc->data[SC_SOULLINK]->val2 != SL_MONK))) - ) - ) //No natural SP regen - regen->flag &=~RGN_SP; - - if( - sc->data[SC_TENSIONRELAX] + if ( sc->data[SC_DANCING] || sc->data[SC_OBLIVIONCURSE] || sc->data[SC_MAXIMIZEPOWER] || sc->data[SC_REBOUND] + || ( bl->type == BL_PC && (((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK + && (sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SOULLINK] || sc->data[SC_SOULLINK]->val2 != SL_MONK))) + ) ) { + regen->flag &=~RGN_SP; //No natural SP regen + } + + if (sc->data[SC_TENSIONRELAX]) { regen->rate.hp += 2; if (regen->sregen) regen->sregen->rate.hp += 3; } - if (sc->data[SC_MAGNIFICAT]) - { + if (sc->data[SC_MAGNIFICAT]) { regen->rate.hp += 1; regen->rate.sp += 1; } - if (sc->data[SC_GDSKILL_REGENERATION]) - { + if (sc->data[SC_GDSKILL_REGENERATION]) { const struct status_change_entry *sce = sc->data[SC_GDSKILL_REGENERATION]; - if (!sce->val4) - { + if (!sce->val4) { regen->rate.hp += sce->val2; regen->rate.sp += sce->val3; } else regen->flag&=~sce->val4; //Remove regen as specified by val4 } - if(sc->data[SC_GENTLETOUCH_REVITALIZE]){ + if(sc->data[SC_GENTLETOUCH_REVITALIZE]) { regen->hp = cap_value(regen->hp*sc->data[SC_GENTLETOUCH_REVITALIZE]->val3/100, 1, SHRT_MAX); regen->state.walk= 1; } @@ -3467,7 +3581,12 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 1) || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 1)) regen->rate.hp *= 2; - + if( sc->data[SC_VITALITYACTIVATION] ) + regen->flag &=~RGN_SP; + if(sc->data[SC_EXTRACT_WHITE_POTION_Z]) + regen->rate.hp += regen->rate.hp * sc->data[SC_EXTRACT_WHITE_POTION_Z]->val1/100; + if(sc->data[SC_VITATA_500]) + regen->rate.sp += regen->rate.sp * sc->data[SC_VITATA_500]->val1/100; } /// Recalculates parts of an object's battle status according to the specified flags. /// @param flag bitfield of values from enum scb_flag @@ -3658,6 +3777,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) { if(flag&SCB_SPEED) { struct unit_data *ud = unit->bl2ud(bl); + st->speed = status->calc_speed(bl, sc, bst->speed); //Re-walk to adjust speed (we do not check if walktimer != INVALID_TIMER @@ -3666,13 +3786,11 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) { if (ud) ud->state.change_walk_target = ud->state.speed_changed = 1; - if( bl->type&BL_PC && st->speed < battle_config.max_walk_speed ) + if( bl->type&BL_PC && !(sd && sd->state.permanent_speed) && st->speed < battle_config.max_walk_speed ) st->speed = battle_config.max_walk_speed; if( bl->type&BL_HOM && battle_config.hom_setting&0x8 && ((TBL_HOM*)bl)->master) st->speed = status->get_speed(&((TBL_HOM*)bl)->master->bl); - - } if(flag&SCB_CRI && bst->cri) { @@ -3846,13 +3964,17 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) { /// Also sends updates to the client wherever applicable. /// @param flag bitfield of values from enum scb_flag /// @param first if true, will cause status_calc_* functions to run their base status initialization code -void status_calc_bl_(struct block_list *bl, enum scb_flag flag, bool first) { +void status_calc_bl_(struct block_list *bl, enum scb_flag flag, enum e_status_calc_opt opt) { struct status_data bst; // previous battle status struct status_data *st; // pointer to current battle status if( bl->type == BL_PC && ((TBL_PC*)bl)->delayed_damage != 0 ) { - ((TBL_PC*)bl)->state.hold_recalc = 1; - return; + if( opt&SCO_FORCE ) + ((TBL_PC*)bl)->state.hold_recalc = 0;/* clear and move on */ + else { + ((TBL_PC*)bl)->state.hold_recalc = 1;/* flag and stop */ + return; + } } // remember previous values @@ -3861,25 +3983,25 @@ void status_calc_bl_(struct block_list *bl, enum scb_flag flag, bool first) { if( flag&SCB_BASE ) {// calculate the object's base status too switch( bl->type ) { - case BL_PC: status->calc_pc_(BL_CAST(BL_PC,bl), first); break; - case BL_MOB: status->calc_mob_(BL_CAST(BL_MOB,bl), first); break; - case BL_PET: status->calc_pet_(BL_CAST(BL_PET,bl), first); break; - case BL_HOM: status->calc_homunculus_(BL_CAST(BL_HOM,bl), first); break; - case BL_MER: status->calc_mercenary_(BL_CAST(BL_MER,bl), first); break; - case BL_ELEM: status->calc_elemental_(BL_CAST(BL_ELEM,bl), first); break; - case BL_NPC: status->calc_npc_(BL_CAST(BL_NPC,bl), first); break; + case BL_PC: status->calc_pc_(BL_CAST(BL_PC,bl), opt); break; + case BL_MOB: status->calc_mob_(BL_CAST(BL_MOB,bl), opt); break; + case BL_PET: status->calc_pet_(BL_CAST(BL_PET,bl), opt); break; + case BL_HOM: status->calc_homunculus_(BL_CAST(BL_HOM,bl), opt); break; + case BL_MER: status->calc_mercenary_(BL_CAST(BL_MER,bl), opt); break; + case BL_ELEM: status->calc_elemental_(BL_CAST(BL_ELEM,bl), opt); break; + case BL_NPC: status->calc_npc_(BL_CAST(BL_NPC,bl), opt); break; } } if( bl->type == BL_PET ) return; // pets are not affected by statuses - if( first && bl->type == BL_MOB ) + if( opt&SCO_FIRST && bl->type == BL_MOB ) return; // assume there will be no statuses active status->calc_bl_main(bl, flag); - if( first && bl->type == BL_HOM ) + if( opt&SCO_FIRST && bl->type == BL_HOM ) return; // client update handled by caller // compare against new values and send client updates @@ -4029,6 +4151,8 @@ unsigned short status_calc_str(struct block_list *bl, struct status_change *sc, str -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(str,0,USHRT_MAX); } + if(sc->data[SC_BEYOND_OF_WARCRY]) + str += sc->data[SC_BEYOND_OF_WARCRY]->val3; if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && str < 50) return 50; if(sc->data[SC_INCALLSTATUS]) @@ -4192,6 +4316,8 @@ unsigned short status_calc_int(struct block_list *bl, struct status_change *sc, int_ -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(int_,0,USHRT_MAX); } + if(sc->data[SC_MELODYOFSINK]) + int_ -= sc->data[SC_MELODYOFSINK]->val3; if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && int_ < 50) return 50; if(sc->data[SC_INCALLSTATUS]) @@ -4231,10 +4357,12 @@ unsigned short status_calc_int(struct block_list *bl, struct status_change *sc, if(sc->data[SC_KYOUGAKU]) int_ -= sc->data[SC_KYOUGAKU]->val2; - if(sc->data[SC_NOEQUIPHELM]) - int_ -= int_ * sc->data[SC_NOEQUIPHELM]->val2/100; - if(sc->data[SC__STRIPACCESSARY]) - int_ -= int_ * sc->data[SC__STRIPACCESSARY]->val2 / 100; + if(bl->type != BL_PC){ + if(sc->data[SC_NOEQUIPHELM]) + int_ -= int_ * sc->data[SC_NOEQUIPHELM]->val2/100; + if(sc->data[SC__STRIPACCESSARY]) + int_ -= int_ * sc->data[SC__STRIPACCESSARY]->val2 / 100; + } if(sc->data[SC_FULL_THROTTLE]) int_ += int_ * 20 / 100; @@ -4293,7 +4421,7 @@ unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc, if(sc->data[SC_MARSHOFABYSS]) dex -= dex * sc->data[SC_MARSHOFABYSS]->val2 / 100; - if(sc->data[SC__STRIPACCESSARY]) + if(sc->data[SC__STRIPACCESSARY] && bl->type != BL_PC) dex -= dex * sc->data[SC__STRIPACCESSARY]->val2 / 100; if(sc->data[SC_FULL_THROTTLE]) dex += dex * 20 / 100; @@ -4341,7 +4469,7 @@ unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc, if(sc->data[SC_LAUDARAMUS]) luk += 4 + sc->data[SC_LAUDARAMUS]->val1; - if(sc->data[SC__STRIPACCESSARY]) + if(sc->data[SC__STRIPACCESSARY] && bl->type != BL_PC) luk -= luk * sc->data[SC__STRIPACCESSARY]->val2 / 100; if(sc->data[SC_BANANA_BOMB]) luk -= luk * sc->data[SC_BANANA_BOMB]->val1 / 100; @@ -4383,7 +4511,7 @@ unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, if(sc->data[SC_FULL_SWING_K]) batk += sc->data[SC_FULL_SWING_K]->val1; if(sc->data[SC_ODINS_POWER]) - batk += 70; + batk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ if(status_get_element(bl) == ELE_WATER) //water type batk /= 2; @@ -4418,14 +4546,8 @@ unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, batk += batk * sc->data[SC_HLIF_FLEET]->val3/100; if(sc->data[SC__ENERVATION]) batk -= batk * sc->data[SC__ENERVATION]->val2 / 100; - if(sc->data[SC_RUSH_WINDMILL]) - batk += batk * sc->data[SC_RUSH_WINDMILL]->val2/100; if(sc->data[SC_SATURDAY_NIGHT_FEVER]) batk += 100 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1; - if(sc->data[SC_MELODYOFSINK]) - batk -= batk * sc->data[SC_MELODYOFSINK]->val3/100; - if(sc->data[SC_BEYOND_OF_WARCRY]) - batk += batk * sc->data[SC_BEYOND_OF_WARCRY]->val3/100; return (unsigned short)cap_value(batk,0,USHRT_MAX); } @@ -4496,16 +4618,16 @@ unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, watk += watk * sc->data[SC_PROVOKE]->val3/100; if(sc->data[SC_SKE]) watk += watk * 3; - if(sc->data[SC__ENERVATION]) - watk -= watk * sc->data[SC__ENERVATION]->val2 / 100; if(sc->data[SC_HLIF_FLEET]) watk += watk * sc->data[SC_HLIF_FLEET]->val3/100; if(sc->data[SC_CURSE]) watk -= watk * 25/100; - if(sc->data[SC_NOEQUIPWEAPON]) + if(sc->data[SC_NOEQUIPWEAPON] && bl->type != BL_PC) watk -= watk * sc->data[SC_NOEQUIPWEAPON]->val2/100; if(sc->data[SC__ENERVATION]) watk -= watk * sc->data[SC__ENERVATION]->val2 / 100; + if(sc->data[SC_RUSH_WINDMILL]) + watk += sc->data[SC_RUSH_WINDMILL]->val2; if((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2) @@ -4534,6 +4656,8 @@ unsigned short status_calc_ematk(struct block_list *bl, struct status_change *sc matk += sc->data[SC_AQUAPLAY_OPTION]->val2; if(sc->data[SC_CHILLY_AIR_OPTION]) matk += sc->data[SC_CHILLY_AIR_OPTION]->val2; + if(sc->data[SC_COOLER_OPTION]) + matk += sc->data[SC_COOLER_OPTION]->val2; if(sc->data[SC_WATER_BARRIER]) matk -= sc->data[SC_WATER_BARRIER]->val3; if(sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3) @@ -4569,6 +4693,8 @@ unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, matk += sc->data[SC_AQUAPLAY_OPTION]->val2; if (sc->data[SC_CHILLY_AIR_OPTION]) matk += sc->data[SC_CHILLY_AIR_OPTION]->val2; + if(sc->data[SC_COOLER_OPTION]) + matk += sc->data[SC_COOLER_OPTION]->val2; if (sc->data[SC_WATER_BARRIER]) matk -= sc->data[SC_WATER_BARRIER]->val3; if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3) @@ -4588,10 +4714,8 @@ unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, matk += matk * sc->data[SC_INCMATKRATE]->val1/100; if (sc->data[SC_MOONLIT_SERENADE]) matk += matk * sc->data[SC_MOONLIT_SERENADE]->val2/100; - if (sc->data[SC_MELODYOFSINK]) - matk += matk * sc->data[SC_MELODYOFSINK]->val3/100; - if (sc->data[SC_BEYOND_OF_WARCRY]) - matk -= matk * sc->data[SC_BEYOND_OF_WARCRY]->val3/100; + if (sc->data[SC_MTF_MATK]) + matk += matk * 25 / 100; return (unsigned short)cap_value(matk,0,USHRT_MAX); } @@ -4624,9 +4748,11 @@ signed short status_calc_critical(struct block_list *bl, struct status_change *s #endif if(sc->data[SC__INVISIBILITY]) - critical += critical * sc->data[SC__INVISIBILITY]->val3 / 100; + critical += sc->data[SC__INVISIBILITY]->val3; if(sc->data[SC__UNLUCKY]) critical -= critical * sc->data[SC__UNLUCKY]->val2 / 100; + if(sc->data[SC_BEYOND_OF_WARCRY]) + critical += 10 * sc->data[SC_BEYOND_OF_WARCRY]->val3; return (short)cap_value(critical,10,SHRT_MAX); } @@ -4639,6 +4765,8 @@ signed short status_calc_hit(struct block_list *bl, struct status_change *sc, in if( !viewable ){ /* some statuses that are hidden in the status window */ + if(sc->data[SC_MTF_ASPD]) + hit += 5; return (short)cap_value(hit,1,SHRT_MAX); } @@ -4653,7 +4781,7 @@ signed short status_calc_hit(struct block_list *bl, struct status_change *sc, in if(sc->data[SC_LKCONCENTRATION]) hit += sc->data[SC_LKCONCENTRATION]->val3; if(sc->data[SC_INSPIRATION]) - hit += 5 * sc->data[SC_INSPIRATION]->val1; + hit += 5 * sc->data[SC_INSPIRATION]->val1 + 25; if(sc->data[SC_GS_ADJUSTMENT]) hit -= 30; if(sc->data[SC_GS_ACCURACY]) @@ -4741,19 +4869,19 @@ signed short status_calc_flee(struct block_list *bl, struct status_change *sc, i if(sc->data[SC_FEAR]) flee -= flee * 20 / 100; if(sc->data[SC_PARALYSE]) - flee -= flee * 10 / 100; // 10% Flee reduction + flee -= flee / 10; // 10% Flee reduction if(sc->data[SC_INFRAREDSCAN]) flee -= flee * 30 / 100; if( sc->data[SC__LAZINESS] ) flee -= flee * sc->data[SC__LAZINESS]->val3 / 100; if( sc->data[SC_GLOOMYDAY] ) - flee -= flee * sc->data[SC_GLOOMYDAY]->val2 / 100; + flee -= flee * ( 20 + 5 * sc->data[SC_GLOOMYDAY]->val1 ) / 100; if( sc->data[SC_SATURDAY_NIGHT_FEVER] ) flee -= flee * (40 + 10 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1) / 100; if( sc->data[SC_WIND_STEP_OPTION] ) flee += flee * sc->data[SC_WIND_STEP_OPTION]->val2 / 100; if( sc->data[SC_ZEPHYR] ) - flee += flee * sc->data[SC_ZEPHYR]->val2 / 100; + flee += sc->data[SC_ZEPHYR]->val2; if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ //mob if(status_get_element(bl) == ELE_WATER) //water type flee /= 2; @@ -4792,6 +4920,8 @@ defType status_calc_def(struct block_list *bl, struct status_change *sc, int def def -= def * 5 * (10-sc->data[SC_CAMOUFLAGE]->val4) / 100; if( sc && sc->data[SC_GENTLETOUCH_REVITALIZE] && sc->data[SC_GENTLETOUCH_REVITALIZE]->val4 ) def += 2 * sc->data[SC_GENTLETOUCH_REVITALIZE]->val4; + if( sc->data[SC_FORCEOFVANGUARD] ) + def += def * 2 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); } @@ -4836,24 +4966,28 @@ defType status_calc_def(struct block_list *bl, struct status_change *sc, int def def >>=1; if(sc->data[SC_PROVOKE] && bl->type != BL_PC) // Provoke doesn't alter player defense-> def -= def * sc->data[SC_PROVOKE]->val4/100; - if(sc->data[SC_NOEQUIPSHIELD]) + if(sc->data[SC_NOEQUIPSHIELD] && bl->type != BL_PC) def -= def * sc->data[SC_NOEQUIPSHIELD]->val2/100; if (sc->data[SC_FLING]) def -= def * (sc->data[SC_FLING]->val2)/100; if( sc->data[SC_ANALYZE] ) def -= def * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; - if( sc->data[SC_FORCEOFVANGUARD] ) - def += def * 2 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; if(sc->data[SC_SATURDAY_NIGHT_FEVER]) def -= def * (10 + 10 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1) / 100; if(sc->data[SC_EARTHDRIVE]) def -= def * 25 / 100; + if(sc->data[SC_SOLID_SKIN_OPTION]) + def += def * sc->data[SC_SOLID_SKIN_OPTION]->val2 / 100; if( sc->data[SC_ROCK_CRUSHER] ) def -= def * sc->data[SC_ROCK_CRUSHER]->val2 / 100; if( sc->data[SC_POWER_OF_GAIA] ) def += def * sc->data[SC_POWER_OF_GAIA]->val2 / 100; + if( sc->data[SC_NEUTRALBARRIER] ) + def += def * (5 * sc->data[SC_NEUTRALBARRIER]->val1 + 10) / 100; + if( sc->data[SC_SHIELDSPELL_REF] && sc->data[SC_SHIELDSPELL_REF]->val1 == 2 ) + def += sc->data[SC_SHIELDSPELL_REF]->val2; if( sc->data[SC_PRESTIGE] ) - def += def * sc->data[SC_PRESTIGE]->val1 / 100; + def += sc->data[SC_PRESTIGE]->val1; if( sc->data[SC_FROSTMISTY] ) def -= def * 10 / 100; if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ @@ -4894,11 +5028,8 @@ signed short status_calc_def2(struct block_list *bl, struct status_change *sc, i return 0; if(sc->data[SC_SUN_COMFORT]) def2 += sc->data[SC_SUN_COMFORT]->val2; - if( sc->data[SC_SHIELDSPELL_REF] && sc->data[SC_SHIELDSPELL_REF]->val1 == 1 ) - def2 += sc->data[SC_SHIELDSPELL_REF]->val2; if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 0 ) def2 += (5 + sc->data[SC_BANDING]->val1) * (sc->data[SC_BANDING]->val2); - if(sc->data[SC_ANGELUS]) #ifdef RENEWAL //in renewal only the VIT stat bonus is boosted by angelus def2 += status_get_vit(bl) / 2 * sc->data[SC_ANGELUS]->val2/100; @@ -4923,7 +5054,7 @@ signed short status_calc_def2(struct block_list *bl, struct status_change *sc, i if(sc->data[SC_ANALYZE]) def2 -= def2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; if( sc->data[SC_ECHOSONG] ) - def2 += def2 * sc->data[SC_ECHOSONG]->val2/100; + def2 += def2 * sc->data[SC_ECHOSONG]->val3/100; if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ if(status_get_race(bl)==RC_PLANT) def2 /= 2; @@ -4979,8 +5110,10 @@ defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int md mdef += mdef * sc->data[SC_SYMPHONY_LOVE]->val2 / 100; if(sc->data[SC_GENTLETOUCH_CHANGE] && sc->data[SC_GENTLETOUCH_CHANGE]->val4) mdef -= mdef * sc->data[SC_GENTLETOUCH_CHANGE]->val4 / 100; + if(sc->data[SC_NEUTRALBARRIER] ) + mdef += mdef * (5 * sc->data[SC_NEUTRALBARRIER]->val1 + 10) / 100; if (sc->data[SC_ODINS_POWER]) - mdef -= 20 * sc->data[SC_ODINS_POWER]->val1; + mdef -= 20; if(sc->data[SC_BURNING]) mdef -= mdef *25 / 100; @@ -5028,16 +5161,13 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc TBL_PC* sd = BL_CAST(BL_PC, bl); int speed_rate; - if( sc == NULL ) - return cap_value(speed,10,USHRT_MAX); - - if (sd && sd->state.permanent_speed) - return (short)cap_value(speed,10,USHRT_MAX); + if( sc == NULL || ( sd && sd->state.permanent_speed ) ) + return (unsigned short)cap_value(speed,MIN_WALK_SPEED,MAX_WALK_SPEED); if( sd && sd->ud.skilltimer != INVALID_TIMER && (pc->checkskill(sd,SA_FREECAST) > 0 || sd->ud.skill_id == LG_EXEEDBREAK) ) { if( sd->ud.skill_id == LG_EXEEDBREAK ) - speed_rate = 100 + 60 - (sd->ud.skill_lv * 10); + speed_rate = 160 - 10 * sd->ud.skill_lv; else speed_rate = 175 - 5 * pc->checkskill(sd,SA_FREECAST); } @@ -5086,7 +5216,7 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc if( sc->data[SC_DEC_AGI] ) val = max( val, 25 ); - if( sc->data[SC_QUAGMIRE] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY] || (sc->data[SC_GLOOMYDAY] && sc->data[SC_GLOOMYDAY]->val4) ) + if( sc->data[SC_QUAGMIRE] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY] ) val = max( val, 50 ); if( sc->data[SC_DONTFORGETME] ) val = max( val, sc->data[SC_DONTFORGETME]->val3 ); @@ -5116,6 +5246,8 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 0 : 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) ); if( sc->data[SC__GROOMY] ) val = max( val, sc->data[SC__GROOMY]->val2); + if( sc->data[SC_GLOOMYDAY] ) + val = max( val, sc->data[SC_GLOOMYDAY]->val3 ); // Should be 50 (-50% speed) if( sc->data[SC_STEALTHFIELD_MASTER] ) val = max( val, 30 ); if( sc->data[SC_BANDING_DEFENCE] ) @@ -5168,7 +5300,7 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc if( sc->data[SC_GN_CARTBOOST] ) val = max( val, sc->data[SC_GN_CARTBOOST]->val2 ); if( sc->data[SC_SWING] ) - val = max( val, sc->data[SC_SWING]->val2 ); + val = max( val, sc->data[SC_SWING]->val3 ); if( sc->data[SC_WIND_STEP_OPTION] ) val = max( val, sc->data[SC_WIND_STEP_OPTION]->val2 ); if( sc->data[SC_FULL_THROTTLE] ) @@ -5205,7 +5337,7 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc } - return (short)cap_value(speed,10,USHRT_MAX); + return (unsigned short)cap_value(speed,MIN_WALK_SPEED,MAX_WALK_SPEED); } // flag&1 - fixed value [malufett] @@ -5277,20 +5409,20 @@ short status_calc_aspd(struct block_list *bl, struct status_change *sc, short fl if( sc->data[SC_PARALYSE] ) skills2 -= 10; if( sc->data[SC__BODYPAINT] ) - skills2 -= 2 + 5 * sc->data[SC__BODYPAINT]->val1; + skills2 -= sc->data[SC__BODYPAINT]->val1; if( sc->data[SC__INVISIBILITY] ) skills2 -= sc->data[SC__INVISIBILITY]->val2 ; if( sc->data[SC__GROOMY] ) skills2 -= sc->data[SC__GROOMY]->val2; if( sc->data[SC_GLOOMYDAY] ) - skills2 -= sc->data[SC_GLOOMYDAY]->val3; + skills2 -= ( 15 + 5 * sc->data[SC_GLOOMYDAY]->val1 ); if( sc->data[SC_EARTHDRIVE] ) skills2 -= 25; if( sc->data[SC_MELON_BOMB] ) skills2 -= sc->data[SC_MELON_BOMB]->val1; if( sc->data[SC_SWING] ) - skills2 += sc->data[SC_SWING]->val2; + skills2 += sc->data[SC_SWING]->val3; if( sc->data[SC_DANCE_WITH_WUG] ) skills2 += sc->data[SC_DANCE_WITH_WUG]->val3; if( sc->data[SC_GENTLETOUCH_CHANGE] ) @@ -5342,6 +5474,8 @@ short status_calc_fix_aspd(struct block_list *bl, struct status_change *sc, int aspd -= 50; // +5 ASPD if( sc && sc->data[SC_FIGHTINGSPIRIT] && sc->data[SC_FIGHTINGSPIRIT]->val2 ) aspd -= (bl->type==BL_PC?pc->checkskill((TBL_PC *)bl, RK_RUNEMASTERY):10) / 10 * 40; + if( sc && sc->data[SC_MTF_ASPD] ) + aspd -= 10; return cap_value(aspd, 0, 2000); // will be recap for proper bl anyway } @@ -5454,17 +5588,17 @@ short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int if( sc->data[SC_PARALYSE] ) aspd_rate += 100; if( sc->data[SC__BODYPAINT] ) - aspd_rate += 200 + 50 * sc->data[SC__BODYPAINT]->val1; + aspd_rate += 10 * 5 * sc->data[SC__BODYPAINT]->val1; if( sc->data[SC__INVISIBILITY] ) aspd_rate += sc->data[SC__INVISIBILITY]->val2 * 10 ; if( sc->data[SC__GROOMY] ) aspd_rate += sc->data[SC__GROOMY]->val2 * 10; if( sc->data[SC_SWING] ) - aspd_rate -= sc->data[SC_SWING]->val2 * 10; + aspd_rate -= sc->data[SC_SWING]->val3 * 10; if( sc->data[SC_DANCE_WITH_WUG] ) aspd_rate -= sc->data[SC_DANCE_WITH_WUG]->val3 * 10; if( sc->data[SC_GLOOMYDAY] ) - aspd_rate += sc->data[SC_GLOOMYDAY]->val3 * 10; + aspd_rate += ( 15 + 5 * sc->data[SC_GLOOMYDAY]->val1 ); if( sc->data[SC_EARTHDRIVE] ) aspd_rate += 250; if( sc->data[SC_GENTLETOUCH_CHANGE] ) @@ -5486,12 +5620,14 @@ short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int } unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion) { + // It has been confirmed on official servers that MvP mobs have no dmotion even without endure + if( bl->type == BL_MOB && (((TBL_MOB*)bl)->status.mode&MD_BOSS) ) + return 0; + if( !sc || !sc->count || map_flag_gvg2(bl->m) || map->list[bl->m].flag.battleground ) return cap_value(dmotion,0,USHRT_MAX); - /** - * It has been confirmed on official servers that MvP mobs have no dmotion even without endure - **/ - if( sc->data[SC_ENDURE] || ( bl->type == BL_MOB && (((TBL_MOB*)bl)->status.mode&MD_BOSS) ) ) + + if( sc->data[SC_ENDURE] ) return 0; if( sc->data[SC_RUN] || sc->data[SC_WUGDASH] ) return 0; @@ -5533,11 +5669,13 @@ unsigned int status_calc_maxhp(struct block_list *bl, struct status_change *sc, if(sc->data[SC__WEAKNESS]) maxhp -= maxhp * sc->data[SC__WEAKNESS]->val2 / 100; if(sc->data[SC_LERADS_DEW]) - maxhp += maxhp * sc->data[SC_LERADS_DEW]->val3 / 100; + maxhp += sc->data[SC_LERADS_DEW]->val3; + if(sc->data[SC_BEYOND_OF_WARCRY]) + maxhp -= maxhp * sc->data[SC_BEYOND_OF_WARCRY]->val4 / 100; if(sc->data[SC_FORCEOFVANGUARD]) maxhp += maxhp * 3 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; - if(sc->data[SC_INSPIRATION]) //Custom value. - maxhp += maxhp * 3 * sc->data[SC_INSPIRATION]->val1 / 100; + if(sc->data[SC_INSPIRATION]) + maxhp += maxhp * 5 * sc->data[SC_INSPIRATION]->val1 / 100 + 600 * sc->data[SC_INSPIRATION]->val1; if(sc->data[SC_RAISINGDRAGON]) maxhp += maxhp * (2 + sc->data[SC_RAISINGDRAGON]->val1) / 100; if(sc->data[SC_GENTLETOUCH_CHANGE]) // Max HP decrease: [Skill Level x 4] % @@ -5550,6 +5688,10 @@ unsigned int status_calc_maxhp(struct block_list *bl, struct status_change *sc, maxhp -= sc->data[SC_MYSTERIOUS_POWDER]->val1 / 100; if(sc->data[SC_PETROLOGY_OPTION]) maxhp += maxhp * sc->data[SC_PETROLOGY_OPTION]->val2 / 100; + if(sc->data[SC_CURSED_SOIL_OPTION]) + maxhp += maxhp * sc->data[SC_CURSED_SOIL_OPTION]->val2 / 100; + if(sc->data[SC_UPHEAVAL_OPTION]) + maxhp += maxhp * sc->data[SC_UPHEAVAL_OPTION]->val3 / 100; if (sc->data[SC_ANGRIFFS_MODUS]) maxhp += maxhp * 5 * sc->data[SC_ANGRIFFS_MODUS]->val1 /100; if (sc->data[SC_GOLDENE_FERSE]) @@ -6021,6 +6163,8 @@ void status_set_viewdata(struct block_list *bl, int class_) sd->vd.cloth_color = 0; if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) sd->vd.cloth_color = 0; + if( sd->sc.option&OPTION_OKTOBERFEST /* TODO: config? */ ) + sd->vd.cloth_color = 0; } } else if (vd) memcpy(&sd->vd, vd, sizeof(struct view_data)); @@ -6117,18 +6261,33 @@ void status_change_init(struct block_list *bl) { //Applies SC defense to a given status change. //Returns the adjusted duration based on flag values. //the flag values are the same as in status->change_start. -int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int tick, int flag) { +int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, int flag) { //Percentual resistance: 10000 = 100% Resist //Example: 50% -> sc_def=5000 -> 25%; 5000ms -> tick_def=5000 -> 2500ms int sc_def = 0, tick_def = -1; //-1 = use sc_def //Linear resistance substracted from rate and tick after percentual resistance was applied //Example: 25% -> sc_def2=2000 -> 5%; 2500ms -> tick_def2=2000 -> 500ms - int sc_def2 = 0, tick_def2 = -1; //-1 = use sc_def2 + int sc_def2 = 0, tick_def2 = -1; //-1 = use sc_def2 (pre-re only) + struct status_data *st; struct status_change *sc; struct map_session_data *sd; nullpo_ret(bl); + + if(!src) + return tick ? tick : 1; // If no source, it can't be resisted (NPC given) + +/// Returns the 'bl's level, capped to 'cap' +#define SCDEF_LVL_CAP(bl, cap) ( (bl) ? (status->get_lv(bl) > (cap) ? (cap) : status->get_lv(bl)) : 0 ) +/// Renewal level modifier. +/// In renewal, returns the difference between the levels of 'bl' and 'src', both capped to 'maxlv', multiplied by 'factor' +/// In pre-renewal, returns zero. +#ifdef RENEWAL +#define SCDEF_LVL_DIFF(bl, src, maxlv, factor) ( ( SCDEF_LVL_CAP((bl), (maxlv)) - SCDEF_LVL_CAP((src), (maxlv)) ) * (factor) ) +#else +#define SCDEF_LVL_DIFF(bl, src, maxlv, factor) 0 +#endif //Status that are blocked by Golden Thief Bug card or Wand of Hermod if (status->isimmune(bl)) @@ -6170,53 +6329,145 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti sc = status->get_sc(bl); if( sc && !sc->count ) sc = NULL; + + if (sc && sc->data[SC_KINGS_GRACE]) { + // Protects against status effects + switch (type) { + case SC_POISON: + case SC_BLIND: + case SC_FREEZE: + case SC_STONE: + case SC_STUN: + case SC_SLEEP: + case SC_BLOODING: + case SC_CURSE: + case SC_CONFUSION: + case SC_ILLUSION: + case SC_SILENCE: + case SC_BURNING: + case SC_COLD: + case SC_FROSTMISTY: + case SC_DEEP_SLEEP: + case SC_FEAR: + case SC_MANDRAGORA: + case SC__CHAOS: + return 0; + } + } + switch (type) { case SC_STUN: + sc_def = st->vit*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + tick_def2 = st->luk*10; +#endif + break; case SC_POISON: - if( sc && sc->data[SC__UNLUCKY] ) - return tick; case SC_DPOISON: + sc_def = st->vit*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + if (sd) { + //For players: 60000 - 450*vit - 100*luk + tick_def = st->vit*75; + tick_def2 = st->luk*100; + } else { + //For monsters: 30000 - 200*vit + tick>>=1; + tick_def = (st->vit*200)/3; + } +#endif + break; case SC_SILENCE: +#ifdef RENEWAL + sc_def = st->int_*100; + sc_def2 = (st->vit + st->luk) * 5 + SCDEF_LVL_DIFF(bl, src, 99, 10); + tick_def2 = st->luk * 10; +#else + sc_def = st->vit*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#endif + break; case SC_BLOODING: +#ifdef RENEWAL + sc_def = st->agi*100; + tick_def2 = st->luk*10; +#else sc_def = st->vit*100; - sc_def2 = st->luk*10; +#endif + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); break; case SC_SLEEP: sc_def = st->int_*100; - sc_def2 = st->luk*10; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + tick_def2 = st->luk*10; +#endif break; case SC_DEEP_SLEEP: sc_def = st->int_*50; - tick_def = st->int_*10 + status->get_lv(bl) * 65 / 10; //Seems to be -1 sec every 10 int and -5% chance every 10 int. + tick_def = 0; // Linear reduction instead + tick_def2 = st->int_ * 50 + SCDEF_LVL_CAP(bl, 150) * 50; // kRO balance update lists this formula break; case SC_DEC_AGI: - case SC_ADORAMUS: //Arch Bishop - if (sd) tick>>=1; //Half duration for players. + case SC_ADORAMUS: + if (sd) tick >>= 1; //Half duration for players. + sc_def = st->mdef*100; +#ifndef RENEWAL + sc_def2 = st->luk*10; + tick_def2 = 0; //No duration reduction +#endif + tick_def = 0; //No duration reduction + break; case SC_STONE: - //Impossible to reduce duration with stats - tick_def = 0; - tick_def2 = 0; + sc_def = st->mdef*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); + tick_def = 0; //No duration reduction +#ifndef RENEWAL + tick_def2 = 0; //No duration reduction +#endif + break; case SC_FREEZE: sc_def = st->mdef*100; - sc_def2 = st->luk*10; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); + tick_def = 0; //No duration reduction +#ifdef RENEWAL + tick_def2 = status_get_luk(src) * -10; //Caster can increase final duration with luk +#else + tick_def2 = 0; //No duration reduction +#endif break; case SC_CURSE: - //Special property: inmunity when luk is greater than level or zero - if (st->luk > status->get_lv(bl) || st->luk == 0) + // Special property: immunity when luk is zero + if (st->luk == 0) + return 0; +#ifndef RENEWAL + // Special property: immunity when luk is greater than level + if (st->luk > status->get_lv(bl)) return 0; +#endif sc_def = st->luk*100; - sc_def2 = st->luk*10; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(NULL, src, 99, 10); // Curse only has a level penalty and no resistance tick_def = st->vit*100; +#ifdef RENEWAL + tick_def2 = st->luk*10; +#endif break; case SC_BLIND: - if( sc && sc->data[SC__UNLUCKY] ) - return tick; sc_def = (st->vit + st->int_)*50; - sc_def2 = st->luk*10; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + tick_def2 = st->luk*10; +#endif break; case SC_CONFUSION: sc_def = (st->str + st->int_)*50; - sc_def2 = st->luk*10; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + sc_def2 = -sc_def2; // Reversed sc_def2 + tick_def2 = st->luk*10; +#endif break; case SC_ANKLESNARE: if(st->mode&MD_BOSS) // Lasts 5 times less on bosses @@ -6227,7 +6478,7 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti case SC_STONESKIN: if (sd) //Duration greatly reduced for players. tick /= 15; - sc_def2 = status->get_lv(bl)*20 + st->vit*25 + st->agi*10; // Lineal Reduction of Rate + sc_def2 = st->vit*25 + st->agi*10 + SCDEF_LVL_CAP(bl, 99) * 20; // Linear Reduction of Rate tick_def2 = 0; //No duration reduction break; case SC_MARSHOFABYSS: @@ -6238,49 +6489,60 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //5 second (fixed) + { Stasis Skill level * 5 - (Target's VIT + DEX) / 20 } tick_def2 = (st->vit + st->dex)*50; break; - if( bl->type == BL_PC ) - tick -= (status->get_lv(bl) / 5 + st->vit / 4 + st->agi / 10)*100; + case SC_WHITEIMPRISON: + if( tick == 5000 ) // 100% on caster + break; + if (bl->type == BL_PC) + tick_def2 = st->vit*25 + st->agi*10 + SCDEF_LVL_CAP(bl, 150) * 20; else - tick -= (st->vit + st->luk) / 20 * 1000; + tick_def2 = (st->vit + st->luk)*50; break; case SC_BURNING: - tick -= 75 * st->luk + 125 * st->agi; - tick = max(tick,5000); // Minimum Duration 5s. + tick_def2 = 75*st->luk + 125*st->agi; break; case SC_FROSTMISTY: - tick -= 1000 * ((st->vit + st->dex) / 20); - tick = max(tick,6000); // Minimum Duration 6s. + tick_def2 = (st->vit + st->dex)*50; break; case SC_OBLIVIONCURSE: // 100% - (100 - 0.8 x INT) - sc_def = 100 - ( 100 - st->int_* 8 / 10 ); - sc_def = max(sc_def, 5); // minimum of 5% + sc_def = st->int_*80; + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_LEECHESEND: + tick_def2 = (st->vit + st->luk) * 500; break; case SC_WUGBITE: // {(Base Success chance) - (Target's AGI / 4)} - rate -= st->agi*100/4; - rate = max(rate,5000); // minimum of 50% + sc_def2 = st->agi*25; break; case SC_ELECTRICSHOCKER: - if( bl->type == BL_MOB ) - tick -= 1000 * (st->agi/10); + tick_def2 = (st->vit + st->agi) * 70; break; case SC_COLD: - tick -= (1000*(st->vit/10))+(status->get_lv(bl)/50); + tick_def2 = st->vit*100 + status->get_lv(bl)*20; + break; + case SC_VACUUM_EXTREME: + tick_def2 = st->str*50; + break; + case SC_MANDRAGORA: + sc_def = (st->vit + st->luk)*20; break; case SC_SIREN: - tick -= 1000 * ((status->get_lv(bl) / 10) + ((sd?sd->status.job_level:0) / 5)); - tick = max(tick,10000); + tick_def2 = (status->get_lv(bl) * 100) + ((bl->type == BL_PC)?((TBL_PC*)bl)->status.job_level : 0); break; case SC_KYOUGAKU: - tick -= 1000 * status_get_int(bl) / 20; + tick_def2 = st->int_ * 50; break; case SC_NEEDLE_OF_PARALYZE: - tick -= 50 * (st->vit + st->luk); //(1000/20); + tick_def2 = (st->vit + st->luk) * 50; break; default: //Effect that cannot be reduced? Likely a buff. if (!(rnd()%10000 < rate)) return 0; - return tick?tick:1; + return tick ? tick : 1; } if (sd) { @@ -6320,11 +6582,16 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti sc_def += sc->data[SC_SIEGFRIED]->val3*100; //Status resistance. } - //When no tick def, reduction is the same for both. - if(tick_def < 0) + //When tick def not set, reduction is the same for both. + if(tick_def == -1) tick_def = sc_def; - if(tick_def2 < 0) + if(tick_def2 == -1) { +#ifdef RENEWAL + tick_def2 = 0; +#else tick_def2 = sc_def2; +#endif + } //Natural resistance if (!(flag&8)) { @@ -6333,8 +6600,11 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //Minimum chances switch (type) { + case SC_OBLIVIONCURSE: + rate = max(rate,500); //Minimum of 5% + break; case SC_WUGBITE: - rate = max(rate, 5000); //Minimum of 50% + rate = max(rate,5000); //Minimum of 50% break; } @@ -6346,6 +6616,9 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti if( sd->sc.data[SC_TARGET_BLOOD] ) rate -= rate*sd->sc.data[SC_TARGET_BLOOD]->val1/100; } + + //Aegis accuracy + if(rate > 0 && rate%10 != 0) rate += (10 - rate%10); } if (!(rnd()%10000 < rate)) @@ -6364,13 +6637,14 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //Minimum durations switch (type) { case SC_ANKLESNARE: + case SC_BURNING: case SC_MARSHOFABYSS: case SC_STASIS: + case SC_DEEP_SLEEP: tick = max(tick, 5000); //Minimum duration 5s break; - case SC_BURNING: case SC_FROSTMISTY: - tick = max(tick, 10000); //Minimum duration 10s + tick = max(tick, 6000); break; default: //Skills need to trigger even if the duration is reduced below 1ms @@ -6379,6 +6653,8 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti } return tick; +#undef SCDEF_LVL_CAP +#undef SCDEF_LVL_DIFF } /* [Ind/Hercules] fast-checkin sc-display array */ void status_display_add(struct map_session_data *sd, enum sc_type type, int dval1, int dval2, int dval3) { @@ -6450,7 +6726,7 @@ void status_display_remove(struct map_session_data *sd, enum sc_type type) { * &4: sc_data loaded, no value has to be altered. * &8: rate should not be reduced *------------------------------------------*/ -int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,int tick,int flag) { +int status_change_start(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int flag) { struct map_session_data *sd = NULL; struct status_change* sc; struct status_change_entry* sce; @@ -6485,46 +6761,67 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX) // Confirmed. return 0; // Immune to status ailements switch( type ) { - case SC_QUAGMIRE://Tester said it protects against this and decrease agi. - case SC_DEC_AGI: - case SC_BURNING: - case SC_FROSTMISTY: - //case SC_WHITEIMPRISON://Need confirm. Protected against this in the past. [Rytech] - case SC_MARSHOFABYSS: - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_DEATHHURT: - case SC_PYREXIA: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - case SC_COLD: ////08/31/2011 - Class Balance Changes - case SC_DEEP_SLEEP: - case SC_MANDRAGORA: - return 0; + case SC_DEEP_SLEEP: + case SC__CHAOS: + case SC_BURNING: + case SC_STUN: + case SC_SLEEP: + case SC_CURSE: + case SC_STONE: + case SC_POISON: + case SC_BLIND: + case SC_SILENCE: + case SC_BLOODING: + case SC_FREEZE: + case SC_FROSTMISTY: + case SC_COLD: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_MARSHOFABYSS: + case SC_MANDRAGORA: + return 0; } } else if( sc->data[SC_INSPIRATION] ) { if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX ) return 0; // Immune to status ailements switch( type ) { - case SC_DEEP_SLEEP: - case SC_SATURDAY_NIGHT_FEVER: - case SC_PYREXIA: - case SC_DEATHHURT: - case SC_MAGICMUSHROOM: - case SC_VENOMBLEED: - case SC_TOXIN: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - case SC__ENERVATION: - case SC__GROOMY: - case SC__LAZINESS: - case SC__UNLUCKY: - case SC__WEAKNESS: - case SC__BODYPAINT: - case SC__IGNORANCE: - return 0; + case SC_POISON: + case SC_BLIND: + case SC_STUN: + case SC_SILENCE: + case SC__CHAOS: + case SC_STONE: + case SC_SLEEP: + case SC_BLOODING: + case SC_CURSE: + case SC_BURNING: + case SC_FROSTMISTY: + case SC_FREEZE: + case SC_COLD: + case SC_FEAR: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + case SC_DEEP_SLEEP: + case SC_SATURDAY_NIGHT_FEVER: + case SC__BODYPAINT: + case SC__ENERVATION: + case SC__GROOMY: + case SC__IGNORANCE: + case SC__LAZINESS: + case SC__UNLUCKY: + case SC__WEAKNESS: + return 0; } } @@ -6532,1874 +6829,2233 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val //Adjust tick according to status resistances if( !(flag&(1|4)) ) { - tick = status->get_sc_def(bl, type, rate, tick, flag); + tick = status->get_sc_def(src, bl, type, rate, tick, flag); if( !tick ) return 0; } undead_flag = battle->check_undead(st->race,st->def_ele); //Check for inmunities / sc fails switch (type) { - case SC_DRUMBATTLE: - case SC_NIBELUNGEN: - case SC_INTOABYSS: - case SC_SIEGFRIED: - if( bl->type == BL_PC) { - struct map_session_data *sd = BL_CAST(BL_PC,bl); - if (!sd->status.party_id) return 0; - } - break; - case SC_ANGRIFFS_MODUS: - case SC_GOLDENE_FERSE: - if ((type==SC_GOLDENE_FERSE && sc->data[SC_ANGRIFFS_MODUS]) - || (type==SC_ANGRIFFS_MODUS && sc->data[SC_GOLDENE_FERSE]) - ) - return 0; - case SC_STONE: - if(sc->data[SC_POWER_OF_GAIA]) - return 0; - case SC_FREEZE: - //Undead are immune to Freeze/Stone - if (undead_flag && !(flag&1)) - return 0; - case SC_DEEP_SLEEP: - case SC_SLEEP: - case SC_STUN: - case SC_FROSTMISTY: - case SC_COLD: - if (sc->opt1) - return 0; //Cannot override other opt1 status changes. [Skotlex] - if((type == SC_FREEZE || type == SC_FROSTMISTY || type == SC_COLD) && sc->data[SC_WARMER]) - return 0; //Immune to Frozen and Freezing status if under Warmer status. [Jobbie] - break; + case SC_DRUMBATTLE: + case SC_NIBELUNGEN: + case SC_INTOABYSS: + case SC_SIEGFRIED: + if( sd && !sd->status.party_id ) + return 0; + break; + case SC_ANGRIFFS_MODUS: + case SC_GOLDENE_FERSE: + if ((type==SC_GOLDENE_FERSE && sc->data[SC_ANGRIFFS_MODUS]) + || (type==SC_ANGRIFFS_MODUS && sc->data[SC_GOLDENE_FERSE]) + ) + return 0; + case SC_VACUUM_EXTREME: + if(sc->data[SC_HALLUCINATIONWALK] || sc->data[SC_HOVERING]) + return 0; + break; + case SC_STONE: + if(sc->data[SC_POWER_OF_GAIA]) + return 0; + case SC_FREEZE: + //Undead are immune to Freeze/Stone + if (undead_flag && !(flag&1)) + return 0; + case SC_SLEEP: + case SC_STUN: + case SC_FROSTMISTY: + case SC_COLD: + if (sc->opt1) + return 0; //Cannot override other opt1 status changes. [Skotlex] + if((type == SC_FREEZE || type == SC_FROSTMISTY || type == SC_COLD) && sc->data[SC_WARMER]) + return 0; //Immune to Frozen and Freezing status if under Warmer status. [Jobbie] + break; - //There all like berserk, do not everlap each other - case SC_BERSERK: - if( sc->data[SC__BLOODYLUST] || sc->data[SC_SATURDAY_NIGHT_FEVER] ) - return 0; - break; + //There all like berserk, do not everlap each other + case SC_BERSERK: + if( sc->data[SC__BLOODYLUST] ) + return 0; + break; - case SC_BURNING: - if(sc->opt1 || sc->data[SC_FROSTMISTY]) - return 0; - break; + case SC_BURNING: + if(sc->opt1 || sc->data[SC_FROSTMISTY]) + return 0; + break; - case SC_CRUCIS: - //Only affects demons and undead element (but not players) - if((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) - return 0; - break; - case SC_LEXAETERNA: - if( (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) || sc->data[SC_FREEZE] ) - return 0; - break; - case SC_KYRIE: - if (bl->type == BL_MOB) - return 0; - break; - case SC_OVERTHRUST: - if (sc->data[SC_OVERTHRUSTMAX]) - return 0; //Overthrust can't take effect if under Max Overthrust. [Skotlex] - case SC_OVERTHRUSTMAX: - if( sc->option&OPTION_MADOGEAR ) - return 0;//Overthrust and Overthrust Max cannot be used on Mado Gear [Ind] - break; - case SC_ADRENALINE: - if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE))) - return 0; - if (sc->data[SC_QUAGMIRE] || - sc->data[SC_DEC_AGI] || - sc->option&OPTION_MADOGEAR //Adrenaline doesn't affect Mado Gear [Ind] + case SC_CRUCIS: + //Only affects demons and undead element (but not players) + if((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) + return 0; + break; + case SC_LEXAETERNA: + if( (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) || sc->data[SC_FREEZE] ) + return 0; + break; + case SC_KYRIE: + if (bl->type == BL_MOB) + return 0; + break; + case SC_OVERTHRUST: + if (sc->data[SC_OVERTHRUSTMAX]) + return 0; //Overthrust can't take effect if under Max Overthrust. [Skotlex] + case SC_OVERTHRUSTMAX: + if( sc->option&OPTION_MADOGEAR ) + return 0;//Overthrust and Overthrust Max cannot be used on Mado Gear [Ind] + break; + case SC_ADRENALINE: + if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE))) + return 0; + if (sc->data[SC_QUAGMIRE] || + sc->data[SC_DEC_AGI] || + sc->option&OPTION_MADOGEAR //Adrenaline doesn't affect Mado Gear [Ind] + ) + return 0; + break; + case SC_ADRENALINE2: + if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE2))) + return 0; + if (sc->data[SC_QUAGMIRE] || + sc->data[SC_DEC_AGI] ) - return 0; - break; - case SC_ADRENALINE2: - if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE2))) - return 0; - if (sc->data[SC_QUAGMIRE] || - sc->data[SC_DEC_AGI] - ) - return 0; - break; - case SC_MAGNIFICAT: - if( sc->data[SC_OFFERTORIUM] || sc->option&OPTION_MADOGEAR ) //Mado is immune to magnificat - return 0; - break; - case SC_ONEHANDQUICKEN: - case SC_MER_QUICKEN: - case SC_TWOHANDQUICKEN: - if(sc->data[SC_DEC_AGI]) - return 0; + return 0; + break; + case SC_MAGNIFICAT: + if( sc->data[SC_OFFERTORIUM] || sc->option&OPTION_MADOGEAR ) //Mado is immune to magnificat + return 0; + break; + case SC_ONEHANDQUICKEN: + case SC_MER_QUICKEN: + case SC_TWOHANDQUICKEN: + if(sc->data[SC_DEC_AGI]) + return 0; - case SC_CONCENTRATION: - case SC_SPEARQUICKEN: - case SC_TRUESIGHT: - case SC_WINDWALK: - case SC_CARTBOOST: - case SC_ASSNCROS: - if(sc->option&OPTION_MADOGEAR) - return 0;//Mado is immune to wind walk, cart boost, etc (others above) [Ind] - case SC_INC_AGI: - if (sc->data[SC_QUAGMIRE]) - return 0; - break; - case SC_CLOAKING: - //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( sd && pc->checkskill(sd, AS_CLOAKING) < 3 && !skill->check_cloaking(bl,NULL) ) - return 0; - break; - case SC_MODECHANGE: - { - int mode; - struct status_data *bst = status->get_base_status(bl); - if (!bst) return 0; - if (sc->data[type]) { - //Pile up with previous values. - if(!val2) val2 = sc->data[type]->val2; - val3 |= sc->data[type]->val3; - val4 |= sc->data[type]->val4; - } - mode = val2 ? val2 : bst->mode; //Base mode - if (val4) mode&=~val4; //Del mode - if (val3) mode|= val3; //Add mode - if (mode == bst->mode) { //No change. - if (sc->data[type]) //Abort previous status - return status_change_end(bl, type, INVALID_TIMER); - return 0; - } - } - break; - //Strip skills, need to divest something or it fails. - case SC_NOEQUIPWEAPON: - if (sd && !(flag&4)) { //apply sc anyway if loading saved sc_data - int i; - opt_flag = 0; //Reuse to check success condition. - if(sd->bonus.unstripable_equip&EQP_WEAPON) + case SC_CONCENTRATION: + case SC_SPEARQUICKEN: + case SC_TRUESIGHT: + case SC_WINDWALK: + case SC_CARTBOOST: + case SC_ASSNCROS: + if(sc->option&OPTION_MADOGEAR) + return 0;//Mado is immune to wind walk, cart boost, etc (others above) [Ind] + case SC_INC_AGI: + if (sc->data[SC_QUAGMIRE]) + return 0; + break; + case SC_CLOAKING: + //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( sd && pc->checkskill(sd, AS_CLOAKING) < 3 && !skill->check_cloaking(bl,NULL) ) return 0; + break; + case SC_MODECHANGE: + { + int mode; + struct status_data *bst = status->get_base_status(bl); + if (!bst) return 0; + if (sc->data[type]) { + //Pile up with previous values. + if(!val2) val2 = sc->data[type]->val2; + val3 |= sc->data[type]->val3; + val4 |= sc->data[type]->val4; + } + mode = val2 ? val2 : bst->mode; //Base mode + if (val4) mode&=~val4; //Del mode + if (val3) mode|= val3; //Add mode + if (mode == bst->mode) { //No change. + if (sc->data[type]) //Abort previous status + return status_change_end(bl, type, INVALID_TIMER); + return 0; + } + } + break; + //Strip skills, need to divest something or it fails. + case SC_NOEQUIPWEAPON: + if (sd && !(flag&4)) { //apply sc anyway if loading saved sc_data + int i; + opt_flag = 0; //Reuse to check success condition. + if(sd->bonus.unstripable_equip&EQP_WEAPON) + return 0; - i = sd->equip_index[EQI_HAND_R]; - if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) { - opt_flag|=2; + i = sd->equip_index[EQI_HAND_R]; + if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) { + opt_flag|=2; + pc->unequipitem(sd,i,3); + } + if (!opt_flag) return 0; + } + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC + break; + case SC_NOEQUIPSHIELD: + if( val2 == 1 ) val2 = 0; //GX effect. Do not take shield off.. + else + if (sd && !(flag&4)) { + int i; + if(sd->bonus.unstripable_equip&EQP_SHIELD) + return 0; + i = sd->equip_index[EQI_HAND_L]; + if ( i < 0 || !sd->inventory_data[i] || sd->inventory_data[i]->type != IT_ARMOR ) + return 0; + pc->unequipitem(sd,i,3); + } + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC + break; + case SC_NOEQUIPARMOR: + if (sd && !(flag&4)) { + int i; + if(sd->bonus.unstripable_equip&EQP_ARMOR) + return 0; + i = sd->equip_index[EQI_ARMOR]; + if ( i < 0 || !sd->inventory_data[i] ) + return 0; pc->unequipitem(sd,i,3); } - if (!opt_flag) return 0; - } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; - case SC_NOEQUIPSHIELD: - if( val2 == 1 ) val2 = 0; //GX effect. Do not take shield off.. - else + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC + break; + case SC_NOEQUIPHELM: if (sd && !(flag&4)) { int i; - if(sd->bonus.unstripable_equip&EQP_SHIELD) + if(sd->bonus.unstripable_equip&EQP_HELM) return 0; - i = sd->equip_index[EQI_HAND_L]; - if ( i < 0 || !sd->inventory_data[i] || sd->inventory_data[i]->type != IT_ARMOR ) + i = sd->equip_index[EQI_HEAD_TOP]; + if ( i < 0 || !sd->inventory_data[i] ) return 0; pc->unequipitem(sd,i,3); } if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC break; - case SC_NOEQUIPARMOR: - if (sd && !(flag&4)) { - int i; - if(sd->bonus.unstripable_equip&EQP_ARMOR) + case SC_MER_FLEE: + case SC_MER_ATK: + case SC_MER_HP: + case SC_MER_SP: + case SC_MER_HIT: + if( bl->type != BL_MER ) + return 0; // Stats only for Mercenaries + break; + case SC_FOOD_STR: + if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > val1) return 0; - i = sd->equip_index[EQI_ARMOR]; - if ( i < 0 || !sd->inventory_data[i] ) + break; + case SC_FOOD_AGI: + if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > val1) return 0; - pc->unequipitem(sd,i,3); - } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; - case SC_NOEQUIPHELM: - if (sd && !(flag&4)) { - int i; - if(sd->bonus.unstripable_equip&EQP_HELM) + break; + case SC_FOOD_VIT: + if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > val1) return 0; - i = sd->equip_index[EQI_HEAD_TOP]; - if ( i < 0 || !sd->inventory_data[i] ) + break; + case SC_FOOD_INT: + if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > val1) return 0; - pc->unequipitem(sd,i,3); - } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; - case SC_MER_FLEE: - case SC_MER_ATK: - case SC_MER_HP: - case SC_MER_SP: - case SC_MER_HIT: - if( bl->type != BL_MER ) - return 0; // Stats only for Mercenaries - break; - case SC_FOOD_STR: - if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_AGI: - if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_VIT: - if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_INT: - if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_DEX: - if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_LUK: - if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_STR_CASH: - if (sc->data[SC_FOOD_STR] && sc->data[SC_FOOD_STR]->val1 > val1) - return 0; - break; - case SC_FOOD_AGI_CASH: - if (sc->data[SC_FOOD_AGI] && sc->data[SC_FOOD_AGI]->val1 > val1) - return 0; - break; - case SC_FOOD_VIT_CASH: - if (sc->data[SC_FOOD_VIT] && sc->data[SC_FOOD_VIT]->val1 > val1) - return 0; - break; - case SC_FOOD_INT_CASH: - if (sc->data[SC_FOOD_INT] && sc->data[SC_FOOD_INT]->val1 > val1) - return 0; - break; - case SC_FOOD_DEX_CASH: - if (sc->data[SC_FOOD_DEX] && sc->data[SC_FOOD_DEX]->val1 > val1) - return 0; - break; - case SC_FOOD_LUK_CASH: - if (sc->data[SC_FOOD_LUK] && sc->data[SC_FOOD_LUK]->val1 > val1) - return 0; - break; - case SC_CAMOUFLAGE: - if( sd && pc->checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill->check_camouflage(bl,NULL) ) - return 0; - break; - case SC__STRIPACCESSARY: - if( sd ) { - int i = -1; - if( !(sd->bonus.unstripable_equip&EQP_ACC_L) ) { - i = sd->equip_index[EQI_ACC_L]; - if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) - pc->unequipitem(sd,i,3); //L-Accessory - } if( !(sd->bonus.unstripable_equip&EQP_ACC_R) ) { - i = sd->equip_index[EQI_ACC_R]; - if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) - pc->unequipitem(sd,i,3); //R-Accessory - } - if( i < 0 ) + break; + case SC_FOOD_DEX: + if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > val1) return 0; - } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_DEATHHURT: - case SC_PYREXIA: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - { // it doesn't stack or even renewed - int i = SC_TOXIN; - for(; i<= SC_LEECHESEND; i++) - if(sc->data[i]) return 0; - } - break; - case SC_SATURDAY_NIGHT_FEVER: - if (sc->data[SC_BERSERK] || sc->data[SC_INSPIRATION]) - return 0; - break; - case SC_OFFERTORIUM: - if (sc->data[SC_MAGNIFICAT]) - return 0; - break; - } - - //Check for BOSS resistances - if(st->mode&MD_BOSS && !(flag&1)) { - if (type>=SC_COMMON_MIN && type <= SC_COMMON_MAX) - return 0; - switch (type) { - case SC_BLESSING: - case SC_DEC_AGI: - case SC_PROVOKE: - case SC_COMA: - case SC_GRAVITATION: - case SC_NJ_SUITON: - case SC_RICHMANKIM: - case SC_ROKISWEIL: - case SC_FOGWALL: - case SC_FROSTMISTY: - case SC_BURNING: - case SC_MARSHOFABYSS: - case SC_ADORAMUS: - case SC_NEEDLE_OF_PARALYZE: - case SC_DEEP_SLEEP: - case SC_COLD: - - // Exploit prevention - kRO Fix - case SC_PYREXIA: - case SC_DEATHHURT: - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - - // Ranger Effects - case SC_WUGBITE: - case SC_ELECTRICSHOCKER: - case SC_MAGNETICFIELD: - - // Masquerades - case SC__ENERVATION: - case SC__GROOMY: - case SC__LAZINESS: - case SC__UNLUCKY: - case SC__WEAKNESS: - case SC__IGNORANCE: - - return 0; - } - } - - //Before overlapping fail, one must check for status cured. - switch (type) { - case SC_BLESSING: - //TO-DO Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM - //but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm] - if ((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) { - status_change_end(bl, SC_CURSE, INVALID_TIMER); - if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) - status_change_end(bl, SC_STONE, INVALID_TIMER); - } - break; - case SC_INC_AGI: - status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); - break; - case SC_QUAGMIRE: - status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); - status_change_end(bl, SC_TRUESIGHT, INVALID_TIMER); - status_change_end(bl, SC_WINDWALK, INVALID_TIMER); - //Also blocks the ones below... - case SC_DEC_AGI: - status_change_end(bl, SC_CARTBOOST, INVALID_TIMER); - //Also blocks the ones below... - case SC_DONTFORGETME: - status_change_end(bl, SC_INC_AGI, INVALID_TIMER); - status_change_end(bl, SC_ADRENALINE, INVALID_TIMER); - status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); - status_change_end(bl, SC_SPEARQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); - status_change_end(bl, SC_ACCELERATION, INVALID_TIMER); - break; - case SC_ONEHANDQUICKEN: - //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] - status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); - break; - case SC_OVERTHRUSTMAX: - //Cancels Normal Overthrust. [Skotlex] - status_change_end(bl, SC_OVERTHRUST, INVALID_TIMER); - break; - case SC_KYRIE: - //Cancels Assumptio - status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); - break; - case SC_DELUGE: - if (sc->data[SC_FOGWALL] && sc->data[SC_BLIND]) - status_change_end(bl, SC_BLIND, INVALID_TIMER); - break; - case SC_SILENCE: - if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) - status_change_end(bl, SC_GOSPEL, INVALID_TIMER); - break; - case SC_HIDING: - status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); - status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); - break; - case SC_BERSERK: - if( val3 == SC__BLOODYLUST ) break; - if(battle_config.berserk_cancels_buffs) { - status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); - status_change_end(bl, SC_PARRYING, INVALID_TIMER); - status_change_end(bl, SC_AURABLADE, INVALID_TIMER); - status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); - } -#ifdef RENEWAL - else { - status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - } -#endif - break; - case SC_ASSUMPTIO: - status_change_end(bl, SC_KYRIE, INVALID_TIMER); - status_change_end(bl, SC_KAITE, INVALID_TIMER); - break; - case SC_KAITE: - status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); - break; - case SC_CARTBOOST: - if(sc->data[SC_DEC_AGI]) - { //Cancel Decrease Agi, but take no further effect [Skotlex] - status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); - return 0; - } - break; - case SC_FUSION: - status_change_end(bl, SC_SOULLINK, INVALID_TIMER); - break; - case SC_GS_ADJUSTMENT: - status_change_end(bl, SC_GS_MADNESSCANCEL, INVALID_TIMER); - break; - case SC_GS_MADNESSCANCEL: - status_change_end(bl, SC_GS_ADJUSTMENT, INVALID_TIMER); - break; - //NPC_CHANGEUNDEAD will debuff Blessing and Agi Up - case SC_PROPERTYUNDEAD: - status_change_end(bl, SC_BLESSING, INVALID_TIMER); - status_change_end(bl, SC_INC_AGI, INVALID_TIMER); - break; - case SC_FOOD_STR: - status_change_end(bl, SC_FOOD_STR_CASH, INVALID_TIMER); - break; - case SC_FOOD_AGI: - status_change_end(bl, SC_FOOD_AGI_CASH, INVALID_TIMER); - break; - case SC_FOOD_VIT: - status_change_end(bl, SC_FOOD_VIT_CASH, INVALID_TIMER); - break; - case SC_FOOD_INT: - status_change_end(bl, SC_FOOD_INT_CASH, INVALID_TIMER); - break; - case SC_FOOD_DEX: - status_change_end(bl, SC_FOOD_DEX_CASH, INVALID_TIMER); - break; - case SC_FOOD_LUK: - status_change_end(bl, SC_FOOD_LUK_CASH, INVALID_TIMER); - break; - case SC_FOOD_STR_CASH: - status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); - break; - case SC_FOOD_AGI_CASH: - status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); - break; - case SC_FOOD_VIT_CASH: - status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); - break; - case SC_FOOD_INT_CASH: - status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); - break; - case SC_FOOD_DEX_CASH: - status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); - break; - case SC_FOOD_LUK_CASH: - status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); - break; - case SC_ENDURE: - if( val4 ) - status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); - break; - case SC_FIGHTINGSPIRIT: - status_change_end(bl, type, INVALID_TIMER); // Remove previous one. - break; - case SC_MARSHOFABYSS: - status_change_end(bl, SC_INCAGI, INVALID_TIMER); - status_change_end(bl, SC_WINDWALK, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); - break; - case SC_SWING: - case SC_SYMPHONY_LOVE: - case SC_MOONLIT_SERENADE: - case SC_RUSH_WINDMILL: - case SC_ECHOSONG: - case SC_HARMONIZE: //group A doesn't overlap - if (type != SC_SWING) status_change_end(bl, SC_SWING, INVALID_TIMER); - if (type != SC_SYMPHONY_LOVE) status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); - if (type != SC_MOONLIT_SERENADE) status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); - if (type != SC_RUSH_WINDMILL) status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); - if (type != SC_ECHOSONG) status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); - if (type != SC_HARMONIZE) status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); - break; - case SC_SIREN: - case SC_DEEP_SLEEP: - case SC_GLOOMYDAY: - case SC_SONG_OF_MANA: - case SC_DANCE_WITH_WUG: - case SC_SATURDAY_NIGHT_FEVER: - case SC_LERADS_DEW: - case SC_MELODYOFSINK: - case SC_BEYOND_OF_WARCRY: - case SC_UNLIMITED_HUMMING_VOICE: //group B - if (type != SC_SIREN) status_change_end(bl, SC_SIREN, INVALID_TIMER); - if (type != SC_DEEP_SLEEP) status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); - if (type != SC_LERADS_DEW) status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); - if (type != SC_MELODYOFSINK) status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); - if (type != SC_BEYOND_OF_WARCRY) status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); - if (type != SC_UNLIMITED_HUMMING_VOICE) status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); - if (type != SC_GLOOMYDAY) { - status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); - status_change_end(bl, SC_GLOOMYDAY_SK, INVALID_TIMER); - } - if (type != SC_SONG_OF_MANA) status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); - if (type != SC_DANCE_WITH_WUG) status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); - if (type != SC_SATURDAY_NIGHT_FEVER) { - if (sc->data[SC_SATURDAY_NIGHT_FEVER]) { - sc->data[SC_SATURDAY_NIGHT_FEVER]->val2 = 0; //mark to not lose hp - status_change_end(bl, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); - } - } - break; - case SC_REFLECTSHIELD: - status_change_end(bl, SC_LG_REFLECTDAMAGE, INVALID_TIMER); - break; - case SC_LG_REFLECTDAMAGE: - status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); - break; - case SC_SHIELDSPELL_DEF: - case SC_SHIELDSPELL_MDEF: - case SC_SHIELDSPELL_REF: - status_change_end(bl, SC_MAGNIFICAT, INVALID_TIMER); - if( type != SC_SHIELDSPELL_DEF ) - status_change_end(bl, SC_SHIELDSPELL_DEF, INVALID_TIMER); - if( type != SC_SHIELDSPELL_MDEF ) - status_change_end(bl, SC_SHIELDSPELL_MDEF, INVALID_TIMER); - if( type != SC_SHIELDSPELL_REF ) - status_change_end(bl, SC_SHIELDSPELL_REF, INVALID_TIMER); - break; - case SC_GENTLETOUCH_ENERGYGAIN: - case SC_GENTLETOUCH_CHANGE: - case SC_GENTLETOUCH_REVITALIZE: - if( type != SC_GENTLETOUCH_REVITALIZE ) - status_change_end(bl, SC_GENTLETOUCH_REVITALIZE, INVALID_TIMER); - if( type != SC_GENTLETOUCH_ENERGYGAIN ) - status_change_end(bl, SC_GENTLETOUCH_ENERGYGAIN, INVALID_TIMER); - if( type != SC_GENTLETOUCH_CHANGE ) - status_change_end(bl, SC_GENTLETOUCH_CHANGE, INVALID_TIMER); - break; - case SC_INVINCIBLE: - status_change_end(bl, SC_INVINCIBLEOFF, INVALID_TIMER); - break; - case SC_INVINCIBLEOFF: - status_change_end(bl, SC_INVINCIBLE, INVALID_TIMER); - break; - case SC_MAGICPOWER: - status_change_end(bl, type, INVALID_TIMER); - break; - } - - //Check for overlapping fails - if( (sce = sc->data[type]) ) { - switch( type ) { - case SC_MER_FLEE: - case SC_MER_ATK: - case SC_MER_HP: - case SC_MER_SP: - case SC_MER_HIT: - if( sce->val1 > val1 ) - val1 = sce->val1; + case SC_FOOD_LUK: + if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > val1) + return 0; break; - case SC_ADRENALINE: - case SC_ADRENALINE2: - case SC_WEAPONPERFECT: - case SC_OVERTHRUST: - if (sce->val2 > val2) + case SC_FOOD_STR_CASH: + if (sc->data[SC_FOOD_STR] && sc->data[SC_FOOD_STR]->val1 > val1) return 0; break; - case SC_S_LIFEPOTION: - case SC_L_LIFEPOTION: - case SC_CASH_BOSS_ALARM: - case SC_STUN: - case SC_SLEEP: - case SC_POISON: - case SC_CURSE: - case SC_SILENCE: - case SC_CONFUSION: - case SC_BLIND: - case SC_BLOODING: - case SC_DPOISON: - case SC_RG_CCONFINE_S: //Can't be re-closed in. - case SC_MARIONETTE_MASTER: - case SC_MARIONETTE: - case SC_NOCHAT: - case SC_HLIF_CHANGE: //Otherwise your Hp/Sp would get refilled while still within effect of the last invocation. - case SC__INVISIBILITY: - case SC__ENERVATION: - case SC__GROOMY: - case SC__IGNORANCE: - case SC__LAZINESS: - case SC__WEAKNESS: - case SC__UNLUCKY: - return 0; - case SC_COMBOATTACK: - case SC_DANCING: - case SC_DEVOTION: - case SC_ATTHASTE_POTION1: - case SC_ATTHASTE_POTION2: - case SC_ATTHASTE_POTION3: - case SC_ATTHASTE_INFINITY: - case SC_PLUSATTACKPOWER: - case SC_PLUSMAGICPOWER: - case SC_ENCHANTARMS: - case SC_ARMORPROPERTY: - case SC_ARMOR_RESIST: + case SC_FOOD_AGI_CASH: + if (sc->data[SC_FOOD_AGI] && sc->data[SC_FOOD_AGI]->val1 > val1) + return 0; break; - case SC_GOSPEL: - //Must not override a casting gospel char. - if(sce->val4 == BCT_SELF) + case SC_FOOD_VIT_CASH: + if (sc->data[SC_FOOD_VIT] && sc->data[SC_FOOD_VIT]->val1 > val1) return 0; - if(sce->val1 > val1) - return 1; break; - case SC_ENDURE: - if(sce->val4 && !val4) - return 1; //Don't let you override infinite endure. - if(sce->val1 > val1) - return 1; + case SC_FOOD_INT_CASH: + if (sc->data[SC_FOOD_INT] && sc->data[SC_FOOD_INT]->val1 > val1) + return 0; break; - case SC_KAAHI: - //Kaahi overwrites previous level regardless of existing level. - //Delete timer if it exists. - if (sce->val4 != INVALID_TIMER) { - timer->delete(sce->val4,status->kaahi_heal_timer); - sce->val4 = INVALID_TIMER; + case SC_FOOD_DEX_CASH: + if (sc->data[SC_FOOD_DEX] && sc->data[SC_FOOD_DEX]->val1 > val1) + return 0; + break; + case SC_FOOD_LUK_CASH: + if (sc->data[SC_FOOD_LUK] && sc->data[SC_FOOD_LUK]->val1 > val1) + return 0; + break; + case SC_CAMOUFLAGE: + if( sd && pc->checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill->check_camouflage(bl,NULL) ) + return 0; + break; + case SC__STRIPACCESSARY: + if( sd ) { + int i = -1; + if( !(sd->bonus.unstripable_equip&EQP_ACC_L) ) { + i = sd->equip_index[EQI_ACC_L]; + if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) + pc->unequipitem(sd,i,3); //L-Accessory + } if( !(sd->bonus.unstripable_equip&EQP_ACC_R) ) { + i = sd->equip_index[EQI_ACC_R]; + if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) + pc->unequipitem(sd,i,3); //R-Accessory + } + if( i < 0 ) + return 0; } + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC break; - case SC_JAILED: - //When a player is already jailed, do not edit the jail data. - val2 = sce->val2; - val3 = sce->val3; - val4 = sce->val4; + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + { // it doesn't stack or even renewed + int i = SC_TOXIN; + for(; i<= SC_LEECHESEND; i++) + if(sc->data[i]) return 0; + } break; - case SC_LERADS_DEW: - if (sc && sc->data[SC_BERSERK]) + case SC_MAGNETICFIELD: + if(sc->data[SC_HOVERING]) return 0; - case SC_SHAPESHIFT: - case SC_PROPERTYWALK: break; - case SC_LEADERSHIP: - case SC_GLORYWOUNDS: - case SC_SOULCOLD: - case SC_HAWKEYES: - if( sce->val4 && !val4 )//you cannot override master guild aura + case SC_OFFERTORIUM: + if (sc->data[SC_MAGNIFICAT]) return 0; break; - case SC_JOINTBEAT: - val2 |= sce->val2; // stackable ailments - default: - if(sce->val1 > val1) - return 1; //Return true to not mess up skill animations. [Skotlex] + } + + //Check for BOSS resistances + if(st->mode&MD_BOSS && !(flag&1)) { + if (type>=SC_COMMON_MIN && type <= SC_COMMON_MAX) + return 0; + switch (type) { + case SC_BLESSING: + case SC_DEC_AGI: + case SC_PROVOKE: + case SC_COMA: + case SC_GRAVITATION: + case SC_NJ_SUITON: + case SC_RICHMANKIM: + case SC_ROKISWEIL: + case SC_FOGWALL: + case SC_FROSTMISTY: + case SC_BURNING: + case SC_MARSHOFABYSS: + case SC_ADORAMUS: + case SC_NEEDLE_OF_PARALYZE: + case SC_DEEP_SLEEP: + case SC_COLD: + + // Exploit prevention - kRO Fix + case SC_PYREXIA: + case SC_DEATHHURT: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + + // Ranger Effects + case SC_WUGBITE: + case SC_ELECTRICSHOCKER: + case SC_MAGNETICFIELD: + + // Masquerades + case SC__ENERVATION: + case SC__GROOMY: + case SC__LAZINESS: + case SC__UNLUCKY: + case SC__WEAKNESS: + case SC__IGNORANCE: + + // Other Effects + case SC_VACUUM_EXTREME: + + return 0; } } - vd = status->get_viewdata(bl); - calc_flag = status->ChangeFlagTable[type]; - if(!(flag&4)) { //&4 - Do not parse val settings when loading SCs - switch(type) { - case SC_DEC_AGI: - case SC_INC_AGI: - val2 = 2 + val1; //Agi change - break; - case SC_ENDURE: - val2 = 7; // Hit-count [Celest] - if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map->list[bl->m].flag.battleground && !val4 ) { - struct map_session_data *tsd; - if( sd ) { - int i; - for( i = 0; i < 5; i++ ) { - if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) - status->change_start(&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); - } - } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status->change_start(&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); + //Before overlapping fail, one must check for status cured. + switch (type) { + case SC_BLESSING: + //TO-DO Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM + //but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm] + if ((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) { + status_change_end(bl, SC_CURSE, INVALID_TIMER); + if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) + status_change_end(bl, SC_STONE, INVALID_TIMER); } - //val4 signals infinite endure (if val4 == 2 it is infinite endure from Berserk) - if( val4 ) - tick = -1; break; - case SC_AUTOBERSERK: - if (st->hp < st->max_hp>>2 && - (!sc->data[SC_PROVOKE] || sc->data[SC_PROVOKE]->val2==0)) - sc_start4(bl,SC_PROVOKE,100,10,1,0,0,60000); - tick = -1; - break; - case SC_CRUCIS: - val2 = 10 + 4*val1; //Def reduction - tick = -1; - clif->emotion(bl,E_SWT); - break; - case SC_MAXIMIZEPOWER: - tick_time = val2 = tick>0?tick:60000; - tick = -1; // duration sent to the client should be infinite + case SC_INC_AGI: + status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); break; - case SC_EDP: // [Celest] - val2 = val1 + 2; //Chance to Poison enemies. - val3 = 50*(val1+1); //Damage increase (+50 +50*lv%) -#ifdef RENEWAL_EDP - val4 = 100 * ((val1 + 1)/2 + 2); -#endif - if( sd )//[Ind] - iROwiki says each level increases its duration by 3 seconds - tick += pc->checkskill(sd,GC_RESEARCHNEWPOISON)*3000; + case SC_QUAGMIRE: + status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); + status_change_end(bl, SC_TRUESIGHT, INVALID_TIMER); + status_change_end(bl, SC_WINDWALK, INVALID_TIMER); + //Also blocks the ones below... + case SC_DEC_AGI: + case SC_ADORAMUS: + status_change_end(bl, SC_CARTBOOST, INVALID_TIMER); + //Also blocks the ones below... + case SC_DONTFORGETME: + status_change_end(bl, SC_INC_AGI, INVALID_TIMER); + status_change_end(bl, SC_ADRENALINE, INVALID_TIMER); + status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); + status_change_end(bl, SC_SPEARQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); + status_change_end(bl, SC_ACCELERATION, INVALID_TIMER); break; - case SC_POISONREACT: - val2=(val1+1)/2 + val1/10; // Number of counters [Skotlex] - val3=50; // + 5*val1; //Chance to counter. [Skotlex] + case SC_ONEHANDQUICKEN: + //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] + status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); break; - case SC_MAGICROD: - val2 = val1*20; //SP gained + case SC_OVERTHRUSTMAX: + //Cancels Normal Overthrust. [Skotlex] + status_change_end(bl, SC_OVERTHRUST, INVALID_TIMER); break; case SC_KYRIE: - val2 = (int64)st->max_hp * (val1 * 2 + 10) / 100; //%Max HP to absorb - val3 = (val1 / 2 + 5); //Hits + //Cancels Assumptio + status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); break; - case SC_MAGICPOWER: - //val1: Skill lv - val2 = 1; //Lasts 1 invocation - val3 = 5*val1; //Matk% increase - val4 = 0; // 0 = ready to be used, 1 = activated and running - break; - case SC_SACRIFICE: - val2 = 5; //Lasts 5 hits - tick = -1; - break; - case SC_ENCHANTPOISON: - val2= 250+50*val1; //Poisoning Chance (2.5+0.5%) in 1/10000 rate - case SC_ASPERSIO: - case SC_PROPERTYFIRE: - case SC_PROPERTYWATER: - case SC_PROPERTYWIND: - case SC_PROPERTYGROUND: - case SC_PROPERTYDARK: - case SC_PROPERTYTELEKINESIS: - skill->enchant_elemental_end(bl,type); - break; - case SC_ARMOR_PROPERTY: - // val1 : Element Lvl (if called by skill lvl 1, takes random value between 1 and 4) - // val2 : Element (When no element, random one is picked) - // val3 : 0 = called by skill 1 = called by script (fixed level) - if( !val2 ) val2 = rnd()%ELE_MAX; - - if( val1 == 1 && val3 == 0 ) - val1 = 1 + rnd()%4; - else if( val1 > 4 ) - val1 = 4; // Max Level - val3 = 0; // Not need to keep this info. + case SC_DELUGE: + if (sc->data[SC_FOGWALL] && sc->data[SC_BLIND]) + status_change_end(bl, SC_BLIND, INVALID_TIMER); break; - case SC_PROVIDENCE: - val2=val1*5; //Race/Ele resist + case SC_SILENCE: + if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) + status_change_end(bl, SC_GOSPEL, INVALID_TIMER); break; - case SC_REFLECTSHIELD: - val2=10+val1*3; // %Dmg reflected - if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) ) { - struct map_session_data *tsd; - if( sd ) { - int i; - for( i = 0; i < 5; i++ ) { - if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) - status->change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); - } - } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status->change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + case SC_HIDING: + status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); + break; + case SC_BERSERK: + if( val3 == SC__BLOODYLUST ) + break; + if(battle_config.berserk_cancels_buffs) { + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); + status_change_end(bl, SC_PARRYING, INVALID_TIMER); + status_change_end(bl, SC_AURABLADE, INVALID_TIMER); + status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); } + #ifdef RENEWAL + else { + status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); + } + #endif break; - case SC_NOEQUIPWEAPON: - if (!sd) //Watk reduction - val2 = 25; + case SC_ASSUMPTIO: + status_change_end(bl, SC_KYRIE, INVALID_TIMER); + status_change_end(bl, SC_KAITE, INVALID_TIMER); break; - case SC_NOEQUIPSHIELD: - if (!sd) //Def reduction - val2 = 15; + case SC_KAITE: + status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); break; - case SC_NOEQUIPARMOR: - if (!sd) //Vit reduction - val2 = 40; + case SC_CARTBOOST: + if(sc->data[SC_DEC_AGI] || sc->data[SC_ADORAMUS]) + { //Cancel Decrease Agi, but take no further effect [Skotlex] + status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); + status_change_end(bl, SC_ADORAMUS, INVALID_TIMER); + return 0; + } break; - case SC_NOEQUIPHELM: - if (!sd) //Int reduction - val2 = 40; + case SC_FUSION: + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); break; - case SC_AUTOSPELL: - //Val1 Skill LV of Autospell - //Val2 Skill ID to cast - //Val3 Max Lv to cast - val4 = 5 + val1*2; //Chance of casting + case SC_GS_ADJUSTMENT: + status_change_end(bl, SC_GS_MADNESSCANCEL, INVALID_TIMER); break; - case SC_VOLCANO: - val2 = val1*10; //Watk increase -#ifndef RENEWAL - if (st->def_ele != ELE_FIRE) - val2 = 0; -#endif + case SC_GS_MADNESSCANCEL: + status_change_end(bl, SC_GS_ADJUSTMENT, INVALID_TIMER); break; - case SC_VIOLENTGALE: - val2 = val1*3; //Flee increase -#ifndef RENEWAL - if (st->def_ele != ELE_WIND) - val2 = 0; -#endif + //NPC_CHANGEUNDEAD will debuff Blessing and Agi Up + case SC_PROPERTYUNDEAD: + status_change_end(bl, SC_BLESSING, INVALID_TIMER); + status_change_end(bl, SC_INC_AGI, INVALID_TIMER); break; - case SC_DELUGE: - val2 = skill->deluge_eff[val1-1]; //HP increase -#ifndef RENEWAL - if(st->def_ele != ELE_WATER) - val2 = 0; -#endif + case SC_FOOD_STR: + status_change_end(bl, SC_FOOD_STR_CASH, INVALID_TIMER); break; - case SC_NJ_SUITON: - if (!val2 || (sd && (sd->class_&MAPID_BASEMASK) == MAPID_NINJA)) { - //No penalties. - val2 = 0; //Agi penalty - val3 = 0; //Walk speed penalty - break; - } - val3 = 50; - val2 = 3*((val1+1)/3); - if (val1 > 4) val2--; + case SC_FOOD_AGI: + status_change_end(bl, SC_FOOD_AGI_CASH, INVALID_TIMER); break; - case SC_ONEHANDQUICKEN: - case SC_TWOHANDQUICKEN: - val2 = 300; - if (val1 > 10) //For boss casted skills [Skotlex] - val2 += 20*(val1-10); + case SC_FOOD_VIT: + status_change_end(bl, SC_FOOD_VIT_CASH, INVALID_TIMER); break; - case SC_MER_QUICKEN: - val2 = 300; + case SC_FOOD_INT: + status_change_end(bl, SC_FOOD_INT_CASH, INVALID_TIMER); break; -#ifndef RENEWAL_ASPD - case SC_SPEARQUICKEN: - val2 = 200+10*val1; + case SC_FOOD_DEX: + status_change_end(bl, SC_FOOD_DEX_CASH, INVALID_TIMER); break; -#endif - case SC_DANCING: - //val1 : Skill ID + LV - //val2 : Skill Group of the Dance. - //val3 : Brings the skill_lv (merged into val1 here) - //val4 : Partner - if (val1 == CG_MOONLIT) - clif->status_change(bl,SI_MOON,1,tick,0, 0, 0); - val1|= (val3<<16); - val3 = tick/1000; //Tick duration - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_LONGING: -#ifdef RENEWAL - val2 = 50 + 10 * val1; -#else - val2 = 500-100*val1; //Aspd penalty. -#endif + case SC_FOOD_LUK: + status_change_end(bl, SC_FOOD_LUK_CASH, INVALID_TIMER); break; - case SC_EXPLOSIONSPIRITS: - val2 = 75 + 25*val1; //Cri bonus + case SC_FOOD_STR_CASH: + status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); break; - - case SC_ATTHASTE_POTION1: - case SC_ATTHASTE_POTION2: - case SC_ATTHASTE_POTION3: - case SC_ATTHASTE_INFINITY: - val2 = 50*(2+type-SC_ATTHASTE_POTION1); + case SC_FOOD_AGI_CASH: + status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); break; - - case SC_WEDDING: - case SC_XMAS: - case SC_SUMMER: - case SC_HANBOK: - if (!vd) return 0; - //Store previous values as they could be removed. - unit->stop_attack(bl); + case SC_FOOD_VIT_CASH: + status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); break; - case SC_NOCHAT: - // [GodLesZ] FIXME: is this correct? a hardcoded interval of 60sec? what about configuration ?_? - tick = 60000; - val1 = battle_config.manner_system; //Mute filters. - if (sd) - { - clif->changestatus(sd,SP_MANNER,sd->status.manner); - clif->updatestatus(sd,SP_MANNER); - } + case SC_FOOD_INT_CASH: + status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); break; - - case SC_STONE: - val3 = tick/1000; //Petrified HP-damage iterations. - if(val3 < 1) val3 = 1; - tick = val4; //Petrifying time. - if(val4 > 500) // not with WL_SIENNAEXECRATE - tick = max(tick, 1000); //Min time - calc_flag = 0; //Actual status changes take effect on petrified state. + case SC_FOOD_DEX_CASH: + status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); break; - - case SC_DPOISON: - //Lose 10/15% of your life as long as it doesn't brings life below 25% - if (st->hp > st->max_hp>>2) { - int diff = st->max_hp*(bl->type==BL_PC?10:15)/100; - if (st->hp - diff < st->max_hp>>2) - diff = st->hp - (st->max_hp>>2); - if( val2 && bl->type == BL_MOB ) { - struct block_list* src = map->id2bl(val2); - if( src ) - mob->log_damage((TBL_MOB*)bl,src,diff); - } - status_zap(bl, diff, 0); - } - // fall through - case SC_POISON: - val3 = tick/1000; //Damage iterations - if(val3 < 1) val3 = 1; - tick_time = 1000; // [GodLesZ] tick time - //val4: HP damage - if (bl->type == BL_PC) - val4 = (type == SC_DPOISON) ? 3 + st->max_hp/50 : 3 + st->max_hp*3/200; - else - val4 = (type == SC_DPOISON) ? 3 + st->max_hp/100 : 3 + st->max_hp/200; - + case SC_FOOD_LUK_CASH: + status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); break; - case SC_CONFUSION: - clif->emotion(bl,E_WHAT); + case SC_ENDURE: + if( val4 ) + status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); break; - case SC_BLOODING: - val4 = tick/10000; - if (!val4) val4 = 1; - tick_time = 10000; // [GodLesZ] tick time + case SC_FIGHTINGSPIRIT: + status_change_end(bl, type, INVALID_TIMER); // Remove previous one. break; - case SC_S_LIFEPOTION: - case SC_L_LIFEPOTION: - if( val1 == 0 ) return 0; - // val1 = heal percent/amout - // val2 = seconds between heals - // val4 = total of heals - if( val2 < 1 ) val2 = 1; - if( (val4 = tick/(val2 * 1000)) < 1 ) - val4 = 1; - tick_time = val2 * 1000; // [GodLesZ] tick time + case SC_MARSHOFABYSS: + status_change_end(bl, SC_INCAGI, INVALID_TIMER); + status_change_end(bl, SC_WINDWALK, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); + break; + //Group A Status (doesn't overlap) + case SC_SWING: + case SC_SYMPHONY_LOVE: + case SC_MOONLIT_SERENADE: + case SC_RUSH_WINDMILL: + case SC_ECHOSONG: + case SC_HARMONIZE: + case SC_FRIGG_SONG: + if (type != SC_SWING) status_change_end(bl, SC_SWING, INVALID_TIMER); + if (type != SC_SYMPHONY_LOVE) status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); + if (type != SC_MOONLIT_SERENADE) status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); + if (type != SC_RUSH_WINDMILL) status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); + if (type != SC_ECHOSONG) status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); + if (type != SC_HARMONIZE) status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); + if (type != SC_FRIGG_SONG) status_change_end(bl, SC_FRIGG_SONG, INVALID_TIMER); + break; + //Group B Status + case SC_SIREN: + case SC_DEEP_SLEEP: + case SC_SIRCLEOFNATURE: + case SC_LERADS_DEW: + case SC_MELODYOFSINK: + case SC_BEYOND_OF_WARCRY: + case SC_UNLIMITED_HUMMING_VOICE: + case SC_GLOOMYDAY: + case SC_SONG_OF_MANA: + case SC_DANCE_WITH_WUG: + if (type != SC_SIREN) status_change_end(bl, SC_SIREN, INVALID_TIMER); + if (type != SC_DEEP_SLEEP) status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); + if (type != SC_SIRCLEOFNATURE) status_change_end(bl, SC_SIRCLEOFNATURE, INVALID_TIMER); + if (type != SC_LERADS_DEW) status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); + if (type != SC_MELODYOFSINK) status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); + if (type != SC_BEYOND_OF_WARCRY) status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); + if (type != SC_UNLIMITED_HUMMING_VOICE) status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); + if (type != SC_GLOOMYDAY) status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); + if (type != SC_SONG_OF_MANA) status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); + if (type != SC_DANCE_WITH_WUG) status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); break; - case SC_CASH_BOSS_ALARM: - if( sd != NULL ) { - struct mob_data *boss_md = map->getmob_boss(bl->m); // Search for Boss on this Map - if( boss_md == NULL || boss_md->bl.prev == NULL ) { - // No MVP on this map - MVP is dead - clif->bossmapinfo(sd->fd, boss_md, 1); - return 0; // No need to start SC - } - val1 = boss_md->bl.id; - if( (val4 = tick/1000) < 1 ) - val4 = 1; - tick_time = 1000; // [GodLesZ] tick time - } + case SC_REFLECTSHIELD: + status_change_end(bl, SC_LG_REFLECTDAMAGE, INVALID_TIMER); break; - case SC_HIDING: - val2 = tick/1000; - tick_time = 1000; // [GodLesZ] tick time - val3 = 0; // unused, previously speed adjustment - val4 = val1+3; //Seconds before SP substraction happen. + case SC_LG_REFLECTDAMAGE: + status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); break; - case SC_CHASEWALK: - val2 = tick>0?tick:10000; //Interval at which SP is drained. - val3 = 35 - 5 * val1; //Speed adjustment. - if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE) - val3 -= 40; - val4 = 10+val1*2; //SP cost. - if (map_flag_gvg(bl->m) || map->list[bl->m].flag.battleground) val4 *= 5; + case SC_SHIELDSPELL_DEF: + case SC_SHIELDSPELL_MDEF: + case SC_SHIELDSPELL_REF: + status_change_end(bl, SC_MAGNIFICAT, INVALID_TIMER); + status_change_end(bl, SC_SHIELDSPELL_DEF, INVALID_TIMER); + status_change_end(bl, SC_SHIELDSPELL_MDEF, INVALID_TIMER); + status_change_end(bl, SC_SHIELDSPELL_REF, INVALID_TIMER); break; - case SC_CLOAKING: - if (!sd) //Monsters should be able to walk with no penalties. [Skotlex] - val1 = 10; - tick_time = val2 = tick>0?tick:60000; //SP consumption rate. - tick = -1; // duration sent to the client should be infinite - val3 = 0; // unused, previously walk speed adjustment - //val4&1 signals the presence of a wall. - //val4&2 makes cloak not end on normal attacks [Skotlex] - //val4&4 makes cloak not end on using skills - if (bl->type == BL_PC || (bl->type == BL_MOB && ((TBL_MOB*)bl)->special_state.clone) ) //Standard cloaking. - val4 |= battle_config.pc_cloak_check_type&7; - else - val4 |= battle_config.monster_cloak_check_type&7; + case SC_GENTLETOUCH_ENERGYGAIN: + case SC_GENTLETOUCH_CHANGE: + case SC_GENTLETOUCH_REVITALIZE: + if( type != SC_GENTLETOUCH_REVITALIZE ) + status_change_end(bl, SC_GENTLETOUCH_REVITALIZE, INVALID_TIMER); + if( type != SC_GENTLETOUCH_ENERGYGAIN ) + status_change_end(bl, SC_GENTLETOUCH_ENERGYGAIN, INVALID_TIMER); + if( type != SC_GENTLETOUCH_CHANGE ) + status_change_end(bl, SC_GENTLETOUCH_CHANGE, INVALID_TIMER); break; - case SC_SIGHT: /* splash status */ - case SC_RUWACH: - case SC_WZ_SIGHTBLASTER: - val3 = skill->get_splash(val2, val1); //Val2 should bring the skill-id. - val2 = tick/250; - tick_time = 10; // [GodLesZ] tick time + case SC_INVINCIBLE: + status_change_end(bl, SC_INVINCIBLEOFF, INVALID_TIMER); break; - - //Permanent effects. - case SC_LEXAETERNA: - case SC_MODECHANGE: - case SC_WEIGHTOVER50: - case SC_WEIGHTOVER90: - case SC_BROKENWEAPON: - case SC_BROKENARMOR: - case SC_STORMKICK_READY: - case SC_DOWNKICK_READY: - case SC_COUNTERKICK_READY: - case SC_TURNKICK_READY: - case SC_DODGE_READY: - case SC_PUSH_CART: - case SC_ALL_RIDING: - tick = -1; + case SC_INVINCIBLEOFF: + status_change_end(bl, SC_INVINCIBLE, INVALID_TIMER); + break; + case SC_MAGICPOWER: + status_change_end(bl, type, INVALID_TIMER); break; + } - case SC_AUTOGUARD: - if( !(flag&1) ) { - struct map_session_data *tsd; - int i,t; - for( i = val2 = 0; i < val1; i++) { - t = 5-(i>>1); - val2 += (t < 0)? 1:t; + //Check for overlapping fails + if( (sce = sc->data[type]) ) { + switch( type ) { + case SC_MER_FLEE: + case SC_MER_ATK: + case SC_MER_HP: + case SC_MER_SP: + case SC_MER_HIT: + if( sce->val1 > val1 ) + val1 = sce->val1; + break; + case SC_ADRENALINE: + case SC_ADRENALINE2: + case SC_WEAPONPERFECT: + case SC_OVERTHRUST: + if (sce->val2 > val2) + return 0; + break; + case SC_S_LIFEPOTION: + case SC_L_LIFEPOTION: + case SC_CASH_BOSS_ALARM: + case SC_STUN: + case SC_SLEEP: + case SC_POISON: + case SC_CURSE: + case SC_SILENCE: + case SC_CONFUSION: + case SC_BLIND: + case SC_BLOODING: + case SC_DPOISON: + case SC_RG_CCONFINE_S: //Can't be re-closed in. + case SC_MARIONETTE_MASTER: + case SC_MARIONETTE: + case SC_NOCHAT: + case SC_HLIF_CHANGE: //Otherwise your Hp/Sp would get refilled while still within effect of the last invocation. + case SC_ABUNDANCE: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + case SC__INVISIBILITY: + case SC__ENERVATION: + case SC__GROOMY: + case SC__IGNORANCE: + case SC__LAZINESS: + case SC__WEAKNESS: + case SC__UNLUCKY: + case SC__CHAOS: + return 0; + case SC_COMBOATTACK: + case SC_DANCING: + case SC_DEVOTION: + case SC_ATTHASTE_POTION1: + case SC_ATTHASTE_POTION2: + case SC_ATTHASTE_POTION3: + case SC_ATTHASTE_INFINITY: + case SC_PLUSATTACKPOWER: + case SC_PLUSMAGICPOWER: + case SC_ENCHANTARMS: + case SC_ARMORPROPERTY: + case SC_ARMOR_RESIST: + break; + case SC_GOSPEL: + //Must not override a casting gospel char. + if(sce->val4 == BCT_SELF) + return 0; + if(sce->val1 > val1) + return 1; + break; + case SC_ENDURE: + if(sce->val4 && !val4) + return 1; //Don't let you override infinite endure. + if(sce->val1 > val1) + return 1; + break; + case SC_KAAHI: + //Kaahi overwrites previous level regardless of existing level. + //Delete timer if it exists. + if (sce->val4 != INVALID_TIMER) { + timer->delete(sce->val4,status->kaahi_heal_timer); + sce->val4 = INVALID_TIMER; } + break; + case SC_JAILED: + //When a player is already jailed, do not edit the jail data. + val2 = sce->val2; + val3 = sce->val3; + val4 = sce->val4; + break; + case SC_LERADS_DEW: + if (sc && sc->data[SC_BERSERK]) + return 0; + case SC_SHAPESHIFT: + case SC_PROPERTYWALK: + break; + case SC_LEADERSHIP: + case SC_GLORYWOUNDS: + case SC_SOULCOLD: + case SC_HAWKEYES: + if( sce->val4 && !val4 )//you cannot override master guild aura + return 0; + break; + case SC_JOINTBEAT: + val2 |= sce->val2; // stackable ailments + default: + if(sce->val1 > val1) + return 1; //Return true to not mess up skill animations. [Skotlex] + } + } - if( bl->type&(BL_PC|BL_MER) ) { + vd = status->get_viewdata(bl); + calc_flag = status->ChangeFlagTable[type]; + if(!(flag&4)) { //&4 - Do not parse val settings when loading SCs + switch(type) { + case SC_ADORAMUS: + sc_start(src,bl,SC_BLIND,100,val1,skill->get_time(status->sc2skill(type),val1)); + // Fall through to SC_INC_AGI + case SC_DEC_AGI: + case SC_INC_AGI: + val2 = 2 + val1; //Agi change + break; + case SC_ENDURE: + val2 = 7; // Hit-count [Celest] + if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map->list[bl->m].flag.battleground && !val4 ) { + struct map_session_data *tsd; + if( sd ) { + int i; + for( i = 0; i < 5; i++ ) { + if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); + } + } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); + } + //val4 signals infinite endure (if val4 == 2 it is infinite endure from Berserk) + if( val4 ) + tick = -1; + break; + case SC_AUTOBERSERK: + if (st->hp < st->max_hp>>2 && + (!sc->data[SC_PROVOKE] || sc->data[SC_PROVOKE]->val2==0)) + sc_start4(src,bl,SC_PROVOKE,100,10,1,0,0,60000); + tick = -1; + break; + case SC_CRUCIS: + val2 = 10 + 4*val1; //Def reduction + tick = -1; + clif->emotion(bl,E_SWT); + break; + case SC_MAXIMIZEPOWER: + tick_time = val2 = tick>0?tick:60000; + tick = -1; // duration sent to the client should be infinite + break; + case SC_EDP: // [Celest] + val2 = val1 + 2; //Chance to Poison enemies. + val3 = 50*(val1+1); //Damage increase (+50 +50*lv%) + #ifdef RENEWAL_EDP + val4 = 100 * ((val1 + 1)/2 + 2); + #endif + if( sd )//[Ind] - iROwiki says each level increases its duration by 3 seconds + tick += pc->checkskill(sd,GC_RESEARCHNEWPOISON)*3000; + break; + case SC_POISONREACT: + val2=(val1+1)/2 + val1/10; // Number of counters [Skotlex] + val3=50; // + 5*val1; //Chance to counter. [Skotlex] + break; + case SC_MAGICROD: + val2 = val1*20; //SP gained + break; + case SC_KYRIE: + val2 = APPLY_RATE(st->max_hp, (val1 * 2 + 10)); //%Max HP to absorb + // val4 holds current about of party memebers when casting AB_PRAEFATIO, + // as Praefatio's barrier has more health and blocks more hits than Kyrie Elesion. + if( val4 < 1 ) //== PR_KYRIE + val3 = (val1 / 2 + 5); // Hits + else { //== AB_PRAEFATIO + val2 += val4 * 2; //Increase barrier strength per party member. + val3 = 6 + val1; + } + if( sd ) + val1 = min(val1,pc->checkskill(sd,PR_KYRIE)); // use skill level to determine barrier health. + break; + case SC_MAGICPOWER: + //val1: Skill lv + val2 = 1; //Lasts 1 invocation + val3 = 5*val1; //Matk% increase + val4 = 0; // 0 = ready to be used, 1 = activated and running + break; + case SC_SACRIFICE: + val2 = 5; //Lasts 5 hits + tick = -1; + break; + case SC_ENCHANTPOISON: + val2= 250+50*val1; //Poisoning Chance (2.5+0.5%) in 1/10000 rate + case SC_ASPERSIO: + case SC_PROPERTYFIRE: + case SC_PROPERTYWATER: + case SC_PROPERTYWIND: + case SC_PROPERTYGROUND: + case SC_PROPERTYDARK: + case SC_PROPERTYTELEKINESIS: + skill->enchant_elemental_end(bl,type); + break; + case SC_ARMOR_PROPERTY: + // val1 : Element Lvl (if called by skill lvl 1, takes random value between 1 and 4) + // val2 : Element (When no element, random one is picked) + // val3 : 0 = called by skill 1 = called by script (fixed level) + if( !val2 ) val2 = rnd()%ELE_MAX; + + if( val1 == 1 && val3 == 0 ) + val1 = 1 + rnd()%4; + else if( val1 > 4 ) + val1 = 4; // Max Level + val3 = 0; // Not need to keep this info. + break; + case SC_PROVIDENCE: + val2=val1*5; //Race/Ele resist + break; + case SC_REFLECTSHIELD: + val2=10+val1*3; // %Dmg reflected + if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) ) { + struct map_session_data *tsd; if( sd ) { + int i; for( i = 0; i < 5; i++ ) { if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) - status->change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } + } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + } + break; + case SC_NOEQUIPWEAPON: + if (!sd) //Watk reduction + val2 = 25; + break; + case SC_NOEQUIPSHIELD: + if (!sd) //Def reduction + val2 = 15; + break; + case SC_NOEQUIPARMOR: + if (!sd) //Vit reduction + val2 = 40; + break; + case SC_NOEQUIPHELM: + if (!sd) //Int reduction + val2 = 40; + break; + case SC_AUTOSPELL: + //Val1 Skill LV of Autospell + //Val2 Skill ID to cast + //Val3 Max Lv to cast + val4 = 5 + val1*2; //Chance of casting + break; + case SC_VOLCANO: + val2 = val1*10; //Watk increase + #ifndef RENEWAL + if (st->def_ele != ELE_FIRE) + val2 = 0; + #endif + break; + case SC_VIOLENTGALE: + val2 = val1*3; //Flee increase + #ifndef RENEWAL + if (st->def_ele != ELE_WIND) + val2 = 0; + #endif + break; + case SC_DELUGE: + val2 = skill->deluge_eff[val1-1]; //HP increase + #ifndef RENEWAL + if(st->def_ele != ELE_WATER) + val2 = 0; + #endif + break; + case SC_NJ_SUITON: + if (!val2 || (sd && (sd->class_&MAPID_BASEMASK) == MAPID_NINJA)) { + //No penalties. + val2 = 0; //Agi penalty + val3 = 0; //Walk speed penalty + break; + } + val3 = 50; + val2 = 3*((val1+1)/3); + if (val1 > 4) val2--; + break; + case SC_ONEHANDQUICKEN: + case SC_TWOHANDQUICKEN: + val2 = 300; + if (val1 > 10) //For boss casted skills [Skotlex] + val2 += 20*(val1-10); + break; + case SC_MER_QUICKEN: + val2 = 300; + break; + #ifndef RENEWAL_ASPD + case SC_SPEARQUICKEN: + val2 = 200+10*val1; + break; + #endif + case SC_DANCING: + //val1 : Skill ID + LV + //val2 : Skill Group of the Dance. + //val3 : Brings the skill_lv (merged into val1 here) + //val4 : Partner + if (val1 == CG_MOONLIT) + clif->status_change(bl,SI_MOON,1,tick,0, 0, 0); + val1|= (val3<<16); + val3 = tick/1000; //Tick duration + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_LONGING: + #ifdef RENEWAL + val2 = 50 + 10 * val1; + #else + val2 = 500-100*val1; //Aspd penalty. + #endif + break; + case SC_EXPLOSIONSPIRITS: + val2 = 75 + 25*val1; //Cri bonus + break; + + case SC_ATTHASTE_POTION1: + case SC_ATTHASTE_POTION2: + case SC_ATTHASTE_POTION3: + case SC_ATTHASTE_INFINITY: + val2 = 50*(2+type-SC_ATTHASTE_POTION1); + break; + + case SC_WEDDING: + case SC_XMAS: + case SC_SUMMER: + case SC_HANBOK: + case SC_OKTOBERFEST: + if (!vd) return 0; + //Store previous values as they could be removed. + unit->stop_attack(bl); + break; + case SC_NOCHAT: + // [GodLesZ] FIXME: is this correct? a hardcoded interval of 60sec? what about configuration ?_? + tick = 60000; + val1 = battle_config.manner_system; //Mute filters. + if (sd) + { + clif->changestatus(sd,SP_MANNER,sd->status.manner); + clif->updatestatus(sd,SP_MANNER); + } + break; + + case SC_STONE: + val3 = tick/1000; //Petrified HP-damage iterations. + if(val3 < 1) val3 = 1; + tick = val4; //Petrifying time. + if(val4 > 500) // not with WL_SIENNAEXECRATE + tick = max(tick, 1000); //Min time + calc_flag = 0; //Actual status changes take effect on petrified state. + break; + + case SC_DPOISON: + //Lose 10/15% of your life as long as it doesn't brings life below 25% + if (st->hp > st->max_hp>>2) { + int diff = st->max_hp*(bl->type==BL_PC?10:15)/100; + if (st->hp - diff < st->max_hp>>2) + diff = st->hp - (st->max_hp>>2); + if( val2 && bl->type == BL_MOB ) { + struct block_list* src2 = map->id2bl(val2); + if( src2 ) + mob->log_damage((TBL_MOB*)bl,src2,diff); } - else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status->change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + status_zap(bl, diff, 0); } - } - break; + // fall through + case SC_POISON: + val3 = tick/1000; //Damage iterations + if(val3 < 1) val3 = 1; + tick_time = 1000; // [GodLesZ] tick time + //val4: HP damage + if (bl->type == BL_PC) + val4 = (type == SC_DPOISON) ? 3 + st->max_hp/50 : 3 + st->max_hp*3/200; + else + val4 = (type == SC_DPOISON) ? 3 + st->max_hp/100 : 3 + st->max_hp/200; - case SC_DEFENDER: - if (!(flag&1)) { - val2 = 5 + 15*val1; //Damage reduction + break; + case SC_CONFUSION: + clif->emotion(bl,E_WHAT); + break; + case SC_BLOODING: + val4 = tick/10000; + if (!val4) val4 = 1; + tick_time = 10000; // [GodLesZ] tick time + break; + case SC_S_LIFEPOTION: + case SC_L_LIFEPOTION: + if( val1 == 0 ) return 0; + // val1 = heal percent/amout + // val2 = seconds between heals + // val4 = total of heals + if( val2 < 1 ) val2 = 1; + if( (val4 = tick/(val2 * 1000)) < 1 ) + val4 = 1; + tick_time = val2 * 1000; // [GodLesZ] tick time + break; + case SC_CASH_BOSS_ALARM: + if( sd != NULL ) { + struct mob_data *boss_md = map->getmob_boss(bl->m); // Search for Boss on this Map + if( boss_md == NULL || boss_md->bl.prev == NULL ) { + // No MVP on this map - MVP is dead + clif->bossmapinfo(sd->fd, boss_md, 1); + return 0; // No need to start SC + } + val1 = boss_md->bl.id; + if( (val4 = tick/1000) < 1 ) + val4 = 1; + tick_time = 1000; // [GodLesZ] tick time + } + break; + case SC_HIDING: + val2 = tick/1000; + tick_time = 1000; // [GodLesZ] tick time val3 = 0; // unused, previously speed adjustment - val4 = 250 - 50*val1; //Aspd adjustment + val4 = val1+3; //Seconds before SP substraction happen. + break; + case SC_CHASEWALK: + val2 = tick>0?tick:10000; //Interval at which SP is drained. + val3 = 35 - 5 * val1; //Speed adjustment. + if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE) + val3 -= 40; + val4 = 10+val1*2; //SP cost. + if (map_flag_gvg(bl->m) || map->list[bl->m].flag.battleground) val4 *= 5; + break; + case SC_CLOAKING: + if (!sd) //Monsters should be able to walk with no penalties. [Skotlex] + val1 = 10; + tick_time = val2 = tick>0?tick:60000; //SP consumption rate. + tick = -1; // duration sent to the client should be infinite + val3 = 0; // unused, previously walk speed adjustment + //val4&1 signals the presence of a wall. + //val4&2 makes cloak not end on normal attacks [Skotlex] + //val4&4 makes cloak not end on using skills + if (bl->type == BL_PC || (bl->type == BL_MOB && ((TBL_MOB*)bl)->special_state.clone) ) //Standard cloaking. + val4 |= battle_config.pc_cloak_check_type&7; + else + val4 |= battle_config.monster_cloak_check_type&7; + break; + case SC_SIGHT: /* splash status */ + case SC_RUWACH: + case SC_WZ_SIGHTBLASTER: + val3 = skill->get_splash(val2, val1); //Val2 should bring the skill-id. + val2 = tick/250; + tick_time = 10; // [GodLesZ] tick time + break; - if (sd) { + //Permanent effects. + case SC_LEXAETERNA: + case SC_MODECHANGE: + case SC_WEIGHTOVER50: + case SC_WEIGHTOVER90: + case SC_BROKENWEAPON: + case SC_BROKENARMOR: + case SC_STORMKICK_READY: + case SC_DOWNKICK_READY: + case SC_COUNTERKICK_READY: + case SC_TURNKICK_READY: + case SC_DODGE_READY: + case SC_PUSH_CART: + case SC_ALL_RIDING: + tick = -1; + break; + + case SC_AUTOGUARD: + if( !(flag&1) ) { struct map_session_data *tsd; - int i; - for (i = 0; i < 5; i++) { - //See if there are devoted characters, and pass the status to them. [Skotlex] - if (sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i]))) - status->change_start(&tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,1); + int i,t; + for( i = val2 = 0; i < val1; i++) { + t = 5-(i>>1); + val2 += (t < 0)? 1:t; + } + + if( bl->type&(BL_PC|BL_MER) ) { + if( sd ) { + for( i = 0; i < 5; i++ ) { + if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + } + } + else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } } - } - break; + break; - case SC_TENSIONRELAX: - if (sd) { - pc_setsit(sd); - clif->sitting(&sd->bl); - } - val2 = 12; //SP cost - val4 = 10000; //Decrease at 10secs intervals. - val3 = tick/val4; - tick = -1; // duration sent to the client should be infinite - tick_time = val4; // [GodLesZ] tick time - break; - case SC_PARRYING: - val2 = 20 + val1*3; //Block Chance - break; + case SC_DEFENDER: + if (!(flag&1)) { + val2 = 5 + 15*val1; //Damage reduction + val3 = 0; // unused, previously speed adjustment + val4 = 250 - 50*val1; //Aspd adjustment + + if (sd) { + struct map_session_data *tsd; + int i; + for (i = 0; i < 5; i++) { + //See if there are devoted characters, and pass the status to them. [Skotlex] + if (sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i]))) + status->change_start(bl, &tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,1); + } + } + } + break; - case SC_WINDWALK: - val2 = (val1+1)/2; // Flee bonus is 1/1/2/2/3/3/4/4/5/5 - break; + case SC_TENSIONRELAX: + if (sd) { + pc_setsit(sd); + clif->sitting(&sd->bl); + } + val2 = 12; //SP cost + val4 = 10000; //Decrease at 10secs intervals. + val3 = tick/val4; + tick = -1; // duration sent to the client should be infinite + tick_time = val4; // [GodLesZ] tick time + break; + case SC_PARRYING: + val2 = 20 + val1*3; //Block Chance + break; - case SC_JOINTBEAT: - if( val2&BREAK_NECK ) - sc_start2(bl,SC_BLOODING,100,val1,val3,skill->get_time2(status->sc2skill(type),val1)); - break; + case SC_WINDWALK: + val2 = (val1+1)/2; // Flee bonus is 1/1/2/2/3/3/4/4/5/5 + break; - case SC_BERSERK: - if( val3 == SC__BLOODYLUST ) - sc_start(bl,(sc_type)val3,100,val1,tick); - if( !val3 && !(!sc->data[SC_ENDURE] || !sc->data[SC_ENDURE]->val4) ) - sc_start4(bl, SC_ENDURE, 100,10,0,0,2, tick); - //HP healing is performing after the calc_status call. - //Val2 holds HP penalty - if (!val4) val4 = skill->get_time2(status->sc2skill(type),val1); - if (!val4) val4 = 10000; //Val4 holds damage interval - val3 = tick/val4; //val3 holds skill duration - tick_time = val4; // [GodLesZ] tick time - break; + case SC_JOINTBEAT: + if( val2&BREAK_NECK ) + sc_start2(src,bl,SC_BLOODING,100,val1,val3,skill->get_time2(status->sc2skill(type),val1)); + break; - case SC_GOSPEL: - if(val4 == BCT_SELF) { - // self effect - val2 = tick/10000; - tick_time = 10000; // [GodLesZ] tick time - status->change_clear_buffs(bl,3); //Remove buffs/debuffs - } - break; + case SC_BERSERK: + if( val3 == SC__BLOODYLUST ) + sc_start(src,bl,(sc_type)val3,100,val1,tick); + if( !val3 && !(!sc->data[SC_ENDURE] || !sc->data[SC_ENDURE]->val4) ) + sc_start4(src, bl, SC_ENDURE, 100,10,0,0,2, tick); + //HP healing is performing after the calc_status call. + //Val2 holds HP penalty + if (!val4) val4 = skill->get_time2(status->sc2skill(type),val1); + if (!val4) val4 = 10000; //Val4 holds damage interval + val3 = tick/val4; //val3 holds skill duration + tick_time = val4; // [GodLesZ] tick time + break; - case SC_MARIONETTE_MASTER: - { - int stat; - - val3 = 0; - val4 = 0; - stat = ( sd ? sd->status.str : status->get_base_status(bl)->str ) / 2; val3 |= cap_value(stat,0,0xFF)<<16; - stat = ( sd ? sd->status.agi : status->get_base_status(bl)->agi ) / 2; val3 |= cap_value(stat,0,0xFF)<<8; - stat = ( sd ? sd->status.vit : status->get_base_status(bl)->vit ) / 2; val3 |= cap_value(stat,0,0xFF); - stat = ( sd ? sd->status.int_: status->get_base_status(bl)->int_) / 2; val4 |= cap_value(stat,0,0xFF)<<16; - stat = ( sd ? sd->status.dex : status->get_base_status(bl)->dex ) / 2; val4 |= cap_value(stat,0,0xFF)<<8; - stat = ( sd ? sd->status.luk : status->get_base_status(bl)->luk ) / 2; val4 |= cap_value(stat,0,0xFF); - } - break; - case SC_MARIONETTE: - { - int stat,max_stat; - // fetch caster information - struct block_list *pbl = map->id2bl(val1); - struct status_change *psc = pbl ? status->get_sc(pbl) : NULL; - struct status_change_entry *psce = psc ? psc->data[SC_MARIONETTE_MASTER] : NULL; - // fetch target's stats - struct status_data* tst = status->get_status_data(bl); // battle status - - if (!psce) - return 0; + case SC_GOSPEL: + if(val4 == BCT_SELF) { + // self effect + val2 = tick/10000; + tick_time = 10000; // [GodLesZ] tick time + status->change_clear_buffs(bl,3); //Remove buffs/debuffs + } + break; - val3 = 0; - val4 = 0; - max_stat = battle_config.max_parameter; //Cap to 99 (default) - stat = (psce->val3 >>16)&0xFF; stat = min(stat, max_stat - tst->str ); val3 |= cap_value(stat,0,0xFF)<<16; - stat = (psce->val3 >> 8)&0xFF; stat = min(stat, max_stat - tst->agi ); val3 |= cap_value(stat,0,0xFF)<<8; - stat = (psce->val3 >> 0)&0xFF; stat = min(stat, max_stat - tst->vit ); val3 |= cap_value(stat,0,0xFF); - stat = (psce->val4 >>16)&0xFF; stat = min(stat, max_stat - tst->int_); val4 |= cap_value(stat,0,0xFF)<<16; - stat = (psce->val4 >> 8)&0xFF; stat = min(stat, max_stat - tst->dex ); val4 |= cap_value(stat,0,0xFF)<<8; - stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - tst->luk ); val4 |= cap_value(stat,0,0xFF); - } - break; - case SC_SWORDREJECT: - val2 = 15*val1; //Reflect chance - val3 = 3; //Reflections - tick = -1; - break; + case SC_MARIONETTE_MASTER: + { + int stat; + + val3 = 0; + val4 = 0; + stat = ( sd ? sd->status.str : status->get_base_status(bl)->str ) / 2; val3 |= cap_value(stat,0,0xFF)<<16; + stat = ( sd ? sd->status.agi : status->get_base_status(bl)->agi ) / 2; val3 |= cap_value(stat,0,0xFF)<<8; + stat = ( sd ? sd->status.vit : status->get_base_status(bl)->vit ) / 2; val3 |= cap_value(stat,0,0xFF); + stat = ( sd ? sd->status.int_: status->get_base_status(bl)->int_) / 2; val4 |= cap_value(stat,0,0xFF)<<16; + stat = ( sd ? sd->status.dex : status->get_base_status(bl)->dex ) / 2; val4 |= cap_value(stat,0,0xFF)<<8; + stat = ( sd ? sd->status.luk : status->get_base_status(bl)->luk ) / 2; val4 |= cap_value(stat,0,0xFF); + } + break; + case SC_MARIONETTE: + { + int stat,max_stat; + // fetch caster information + struct block_list *pbl = map->id2bl(val1); + struct status_change *psc = pbl ? status->get_sc(pbl) : NULL; + struct status_change_entry *psce = psc ? psc->data[SC_MARIONETTE_MASTER] : NULL; + // fetch target's stats + struct status_data* tst = status->get_status_data(bl); // battle status + + if (!psce) + return 0; - case SC_MEMORIZE: - val2 = 5; //Memorized casts. - tick = -1; - break; + val3 = 0; + val4 = 0; + max_stat = battle_config.max_parameter; //Cap to 99 (default) + stat = (psce->val3 >>16)&0xFF; stat = min(stat, max_stat - tst->str ); val3 |= cap_value(stat,0,0xFF)<<16; + stat = (psce->val3 >> 8)&0xFF; stat = min(stat, max_stat - tst->agi ); val3 |= cap_value(stat,0,0xFF)<<8; + stat = (psce->val3 >> 0)&0xFF; stat = min(stat, max_stat - tst->vit ); val3 |= cap_value(stat,0,0xFF); + stat = (psce->val4 >>16)&0xFF; stat = min(stat, max_stat - tst->int_); val4 |= cap_value(stat,0,0xFF)<<16; + stat = (psce->val4 >> 8)&0xFF; stat = min(stat, max_stat - tst->dex ); val4 |= cap_value(stat,0,0xFF)<<8; + stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - tst->luk ); val4 |= cap_value(stat,0,0xFF); + } + break; + case SC_SWORDREJECT: + val2 = 15*val1; //Reflect chance + val3 = 3; //Reflections + tick = -1; + break; - case SC_GRAVITATION: - val2 = 50*val1; //aspd reduction - break; + case SC_MEMORIZE: + val2 = 5; //Memorized casts. + tick = -1; + break; - case SC_GDSKILL_REGENERATION: - if (val1 == 1) - val2 = 2; - else - val2 = val1; //HP Regerenation rate: 200% 200% 300% - val3 = val1; //SP Regeneration Rate: 100% 200% 300% - //if val4 comes set, this blocks regen rather than increase it. - break; + case SC_GRAVITATION: + val2 = 50*val1; //aspd reduction + break; - case SC_DEVOTION: - { - struct block_list *d_bl; - struct status_change *d_sc; - - if( (d_bl = map->id2bl(val1)) && (d_sc = status->get_sc(d_bl)) && d_sc->count ) { - // Inherits Status From Source - const enum sc_type types[] = { SC_AUTOGUARD, SC_DEFENDER, SC_REFLECTSHIELD, SC_ENDURE }; - enum sc_type type2; - int i = (map_flag_gvg(bl->m) || map->list[bl->m].flag.battleground)?2:3; - while( i >= 0 ) { - type2 = types[i]; - if( d_sc->data[type2] ) - sc_start(bl, type2, 100, d_sc->data[type2]->val1, skill->get_time(status->sc2skill(type2),d_sc->data[type2]->val1)); - i--; + case SC_GDSKILL_REGENERATION: + if (val1 == 1) + val2 = 2; + else + val2 = val1; //HP Regerenation rate: 200% 200% 300% + val3 = val1; //SP Regeneration Rate: 100% 200% 300% + //if val4 comes set, this blocks regen rather than increase it. + break; + + case SC_DEVOTION: + { + struct block_list *d_bl; + struct status_change *d_sc; + + if( (d_bl = map->id2bl(val1)) && (d_sc = status->get_sc(d_bl)) && d_sc->count ) { + // Inherits Status From Source + const enum sc_type types[] = { SC_AUTOGUARD, SC_DEFENDER, SC_REFLECTSHIELD, SC_ENDURE }; + enum sc_type type2; + int i = (map_flag_gvg(bl->m) || map->list[bl->m].flag.battleground)?2:3; + while( i >= 0 ) { + type2 = types[i]; + if( d_sc->data[type2] ) + sc_start(bl, bl, type2, 100, d_sc->data[type2]->val1, skill->get_time(status->sc2skill(type2),d_sc->data[type2]->val1)); + i--; + } } + break; } - break; - } - case SC_COMA: //Coma. Sends a char to 1HP. If val2, do not zap sp - if( val3 && bl->type == BL_MOB ) { - struct block_list* src = map->id2bl(val3); - if( src ) - mob->log_damage((TBL_MOB*)bl,src,st->hp - 1); + case SC_COMA: //Coma. Sends a char to 1HP. If val2, do not zap sp + if( val3 && bl->type == BL_MOB ) { + struct block_list* src2 = map->id2bl(val3); + if( src2 ) + mob->log_damage((TBL_MOB*)bl,src2,st->hp - 1); + } + status_zap(bl, st->hp-1, val2 ? 0 : st->sp); + return 1; + break; + case SC_RG_CCONFINE_S: + { + struct block_list *src2 = val2 ? map->id2bl(val2) : NULL; + struct status_change *sc2 = src ? status->get_sc(src2) : NULL; + struct status_change_entry *sce2 = sc2 ? sc2->data[SC_RG_CCONFINE_M] : NULL; + if (src2 && sc2) { + if (!sce2) //Start lock on caster. + sc_start4(src,src2,SC_RG_CCONFINE_M,100,val1,1,0,0,tick+1000); + else { //Increase count of locked enemies and refresh time. + (sce2->val2)++; + timer->delete(sce2->timer, status->change_timer); + sce2->timer = timer->add(timer->gettick()+tick+1000, status->change_timer, src2->id, SC_RG_CCONFINE_M); + } + } else //Status failed. + return 0; } - status_zap(bl, st->hp-1, val2 ? 0 : st->sp); - return 1; - break; - case SC_RG_CCONFINE_S: - { - struct block_list *src = val2 ? map->id2bl(val2) : NULL; - struct status_change *sc2 = src ? status->get_sc(src) : NULL; - struct status_change_entry *sce2 = sc2 ? sc2->data[SC_RG_CCONFINE_M] : NULL; - if (src && sc2) { - if (!sce2) //Start lock on caster. - sc_start4(src,SC_RG_CCONFINE_M,100,val1,1,0,0,tick+1000); - else { //Increase count of locked enemies and refresh time. - (sce2->val2)++; - timer->delete(sce2->timer, status->change_timer); - sce2->timer = timer->add(timer->gettick()+tick+1000, status->change_timer, src->id, SC_RG_CCONFINE_M); + break; + case SC_KAITE: + val2 = 1+val1/5; //Number of bounces: 1 + skill_lv/5 + break; + case SC_KAUPE: + switch (val1) { + case 3: //33*3 + 1 -> 100% + val2++; + case 1: + case 2: //33, 66% + val2 += 33*val1; + val3 = 1; //Dodge 1 attack total. + break; + default: //Custom. For high level mob usage, higher level means more blocks. [Skotlex] + val2 = 100; + val3 = val1-2; + break; } - } else //Status failed. - return 0; - } - break; - case SC_KAITE: - val2 = 1+val1/5; //Number of bounces: 1 + skill_lv/5 - break; - case SC_KAUPE: - switch (val1) { - case 3: //33*3 + 1 -> 100% - val2++; - case 1: - case 2: //33, 66% - val2 += 33*val1; - val3 = 1; //Dodge 1 attack total. - break; - default: //Custom. For high level mob usage, higher level means more blocks. [Skotlex] - val2 = 100; - val3 = val1-2; - break; - } - break; - - case SC_COMBOATTACK: { - //val1: Skill ID - //val2: When given, target (for autotargetting skills) - //val3: When set, this combo time should NOT delay attack/movement - //val3: TK: Last used kick - //val4: TK: Combo time - struct unit_data *ud = unit->bl2ud(bl); - if (ud && !val3) { - tick += 300 * battle_config.combo_delay_rate/100; - ud->attackabletime = timer->gettick()+tick; - unit->set_walkdelay(bl, timer->gettick(), tick, 1); - } - val3 = 0; - val4 = tick; - } - break; - case SC_EARTHSCROLL: - val2 = 11-val1; //Chance to consume: 11-skill_lv% - break; - case SC_RUN: - val4 = timer->gettick(); //Store time at which you started running. - tick = -1; - break; - case SC_KAAHI: - val2 = 200*val1; //HP heal - val3 = 5*val1; //SP cost - val4 = INVALID_TIMER; //Kaahi Timer. - break; - case SC_BLESSING: - if ((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) - val2 = val1; - else - val2 = 0; //0 -> Half stat. - break; - case SC_TRICKDEAD: - if (vd) vd->dead_sit = 1; - tick = -1; - break; - case SC_CONCENTRATION: - val2 = 2 + val1; - if (sd) { //Store the card-bonus data that should not count in the % - val3 = sd->param_bonus[1]; //Agi - val4 = sd->param_bonus[4]; //Dex - } else { - val3 = val4 = 0; + break; + + case SC_COMBOATTACK: { + //val1: Skill ID + //val2: When given, target (for autotargetting skills) + //val3: When set, this combo time should NOT delay attack/movement + //val3: TK: Last used kick + //val4: TK: Combo time + struct unit_data *ud = unit->bl2ud(bl); + if (ud && !val3) { + tick += 300 * battle_config.combo_delay_rate/100; + ud->attackabletime = timer->gettick()+tick; + unit->set_walkdelay(bl, timer->gettick(), tick, 1); + } + val3 = 0; + val4 = tick; + } + break; + case SC_EARTHSCROLL: + val2 = 11-val1; //Chance to consume: 11-skill_lv% + break; + case SC_RUN: + { + //Store time at which you started running. + int64 currenttick = timer->gettick(); + // Note: this int64 value is stored in two separate int32 variables (FIXME) + val3 = (int)(currenttick&0x00000000ffffffffLL); + val4 = (int)((currenttick&0xffffffff00000000LL)>>32); } - break; - case SC_OVERTHRUSTMAX: - val2 = 20*val1; //Power increase - break; - case SC_OVERTHRUST: - //val2 holds if it was casted on self, or is bonus received from others - val3 = 5*val1; //Power increase - if(sd && pc->checkskill(sd,BS_HILTBINDING)>0) - tick += tick / 10; - break; - case SC_ADRENALINE2: - case SC_ADRENALINE: - val3 = (val2) ? 300 : 200; // aspd increase - case SC_WEAPONPERFECT: - if(sd && pc->checkskill(sd,BS_HILTBINDING)>0) - tick += tick / 10; - break; - case SC_LKCONCENTRATION: - val2 = 5*val1; //Batk/Watk Increase - val3 = 10*val1; //Hit Increase - val4 = 5*val1; //Def reduction - sc_start(bl, SC_ENDURE, 100, 1, tick); //Endure effect - break; - case SC_ANGELUS: - val2 = 5*val1; //def increase - break; - case SC_IMPOSITIO: - val2 = 5*val1; //watk increase - break; - case SC_MELTDOWN: - val2 = 100*val1; //Chance to break weapon - val3 = 70*val1; //Change to break armor - break; - case SC_TRUESIGHT: - val2 = 10*val1; //Critical increase - val3 = 3*val1; //Hit increase - break; - case SC_SUN_COMFORT: - val2 = (status->get_lv(bl) + st->dex + st->luk)/2; //def increase - break; - case SC_MOON_COMFORT: - val2 = (status->get_lv(bl) + st->dex + st->luk)/10; //flee increase - break; - case SC_STAR_COMFORT: - val2 = (status->get_lv(bl) + st->dex + st->luk); //Aspd increase - break; - case SC_QUAGMIRE: - val2 = (sd?5:10)*val1; //Agi/Dex decrease. - break; + tick = -1; + break; + case SC_KAAHI: + val2 = 200*val1; //HP heal + val3 = 5*val1; //SP cost + val4 = INVALID_TIMER; //Kaahi Timer. + break; + case SC_BLESSING: + if ((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) + val2 = val1; + else + val2 = 0; //0 -> Half stat. + break; + case SC_TRICKDEAD: + if (vd) vd->dead_sit = 1; + tick = -1; + break; + case SC_CONCENTRATION: + val2 = 2 + val1; + if (sd) { //Store the card-bonus data that should not count in the % + val3 = sd->param_bonus[1]; //Agi + val4 = sd->param_bonus[4]; //Dex + } else { + val3 = val4 = 0; + } + break; + case SC_OVERTHRUSTMAX: + val2 = 20*val1; //Power increase + break; + case SC_OVERTHRUST: + //val2 holds if it was casted on self, or is bonus received from others + val3 = 5*val1; //Power increase + if(sd && pc->checkskill(sd,BS_HILTBINDING)>0) + tick += tick / 10; + break; + case SC_ADRENALINE2: + case SC_ADRENALINE: + val3 = (val2) ? 300 : 200; // aspd increase + case SC_WEAPONPERFECT: + if(sd && pc->checkskill(sd,BS_HILTBINDING)>0) + tick += tick / 10; + break; + case SC_LKCONCENTRATION: + val2 = 5*val1; //Batk/Watk Increase + val3 = 10*val1; //Hit Increase + val4 = 5*val1; //Def reduction + sc_start(src, bl, SC_ENDURE, 100, 1, tick); //Endure effect + break; + case SC_ANGELUS: + val2 = 5*val1; //def increase + break; + case SC_IMPOSITIO: + val2 = 5*val1; //watk increase + break; + case SC_MELTDOWN: + val2 = 100*val1; //Chance to break weapon + val3 = 70*val1; //Change to break armor + break; + case SC_TRUESIGHT: + val2 = 10*val1; //Critical increase + val3 = 3*val1; //Hit increase + break; + case SC_SUN_COMFORT: + val2 = (status->get_lv(bl) + st->dex + st->luk)/2; //def increase + break; + case SC_MOON_COMFORT: + val2 = (status->get_lv(bl) + st->dex + st->luk)/10; //flee increase + break; + case SC_STAR_COMFORT: + val2 = (status->get_lv(bl) + st->dex + st->luk); //Aspd increase + break; + case SC_QUAGMIRE: + val2 = (sd?5:10)*val1; //Agi/Dex decrease. + break; - // gs_something1 [Vicious] - case SC_GS_GATLINGFEVER: - val2 = 20*val1; //Aspd increase - val4 = 5*val1; //Flee decrease -#ifndef RENEWAL - val3 = 20+10*val1; //Batk increase -#endif - break; + // gs_something1 [Vicious] + case SC_GS_GATLINGFEVER: + val2 = 20*val1; //Aspd increase + val4 = 5*val1; //Flee decrease + #ifndef RENEWAL + val3 = 20+10*val1; //Batk increase + #endif + break; - case SC_FLING: - if (bl->type == BL_PC) - val2 = 0; //No armor reduction to players. - else - val2 = 5*val1; //Def reduction - val3 = 5*val1; //Def2 reduction - break; - case SC_PROVOKE: - //val2 signals autoprovoke. - val3 = 2+3*val1; //Atk increase - val4 = 5+5*val1; //Def reduction. - break; - case SC_HLIF_AVOID: - //val2 = 10*val1; //Speed change rate. - break; - case SC_HAMI_DEFENCE: - val2 = 2*val1; //Def bonus - break; - case SC_HAMI_BLOODLUST: - val2 = 20+10*val1; //Atk rate change. - val3 = 3*val1; //Leech chance - val4 = 20; //Leech percent - break; - case SC_HLIF_FLEET: - val2 = 30*val1; //Aspd change - val3 = 5+5*val1; //bAtk/wAtk rate change - break; - case SC_MINDBREAKER: - val2 = 20*val1; //matk increase. - val3 = 12*val1; //mdef2 reduction. - break; - case SC_SKA: - val2 = tick/1000; - val3 = rnd()%100; //Def changes randomly every second... - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_JAILED: - //Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time. - tick = val1>0?1000:250; - if (sd) + case SC_FLING: + if (bl->type == BL_PC) + val2 = 0; //No armor reduction to players. + else + val2 = 5*val1; //Def reduction + val3 = 5*val1; //Def2 reduction + break; + case SC_PROVOKE: + //val2 signals autoprovoke. + val3 = 2+3*val1; //Atk increase + val4 = 5+5*val1; //Def reduction. + break; + case SC_HLIF_AVOID: + //val2 = 10*val1; //Speed change rate. + break; + case SC_HAMI_DEFENCE: + val2 = 2*val1; //Def bonus + break; + case SC_HAMI_BLOODLUST: + val2 = 20+10*val1; //Atk rate change. + val3 = 3*val1; //Leech chance + val4 = 20; //Leech percent + break; + case SC_HLIF_FLEET: + val2 = 30*val1; //Aspd change + val3 = 5+5*val1; //bAtk/wAtk rate change + break; + case SC_MINDBREAKER: + val2 = 20*val1; //matk increase. + val3 = 12*val1; //mdef2 reduction. + break; + case SC_SKA: + val2 = tick/1000; + val3 = rnd()%100; //Def changes randomly every second... + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_JAILED: + //Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time. + tick = val1>0?1000:250; + if (sd) + { + if (sd->mapindex != val2) + { + int pos = (bl->x&0xFFFF)|(bl->y<<16); /// Current Coordinates + int map_index = sd->mapindex; /// Current Map + //1. Place in Jail (val2 -> Jail Map, val3 -> x, val4 -> y + pc->setpos(sd,(unsigned short)val2,val3,val4, CLR_TELEPORT); + //2. Set restore point (val3 -> return map, val4 return coords + val3 = map_index; + val4 = pos; + } else if (!val3 || val3 == sd->mapindex) { //Use save point. + val3 = sd->status.save_point.map; + val4 = (sd->status.save_point.x&0xFFFF) + |(sd->status.save_point.y<<16); + } + } + break; + case SC_NJ_UTSUSEMI: + val2=(val1+1)/2; // number of hits blocked + val3=skill->get_blewcount(NJ_UTSUSEMI, val1); //knockback value. + break; + case SC_NJ_BUNSINJYUTSU: + val2=(val1+1)/2; // number of hits blocked + break; + case SC_HLIF_CHANGE: + val2= 30*val1; //Vit increase + val3= 20*val1; //Int increase + break; + case SC_SWOO: + if(st->mode&MD_BOSS) + tick /= 5; //TODO: Reduce skill's duration. But for how long? + break; + case SC_SPIDERWEB: + if( bl->type == BL_PC ) + tick /= 2; + break; + case SC_ARMOR: + //NPC_DEFENDER: + val2 = 80; //Damage reduction + //Attack requirements to be blocked: + val3 = BF_LONG; //Range + val4 = BF_WEAPON|BF_MISC; //Type + break; + case SC_ENCHANTARMS: + //end previous enchants + skill->enchant_elemental_end(bl,type); + //Make sure the received element is valid. + if (val2 >= ELE_MAX) + val2 = val2%ELE_MAX; + else if (val2 < 0) + val2 = rnd()%ELE_MAX; + break; + case SC_CRITICALWOUND: + val2 = 20*val1; //Heal effectiveness decrease + break; + case SC_MAGICMIRROR: + case SC_SLOWCAST: + val2 = 20*val1; //Magic reflection/cast rate + break; + + case SC_STONESKIN: + if (val2 == NPC_ANTIMAGIC) + { //Boost mdef + val2 =-20; + val3 = 20; + } else { //Boost def + val2 = 20; + val3 =-20; + } + val2*=val1; //20% per level + val3*=val1; + break; + case SC_CASH_PLUSEXP: + case SC_CASH_PLUSONLYJOBEXP: + if (val1 < 0) + val1 = 0; + break; + case SC_PLUSAVOIDVALUE: + case SC_CRITICALPERCENT: + val2 = val1*10; //Actual boost (since 100% = 1000) + break; + case SC_SUFFRAGIUM: + val2 = 15 * val1; //Speed cast decrease + break; + case SC_HEALPLUS: + if (val1 < 1) + val1 = 1; + break; + case SC_ILLUSION: + val2 = 5+val1; //Factor by which displayed damage is increased by + break; + case SC_DOUBLECASTING: + val2 = 30+10*val1; //Trigger rate + break; + case SC_KAIZEL: + val2 = 10*val1; //% of life to be revived with + break; + // case SC_ARMORPROPERTY: + // case SC_ARMOR_RESIST: + // Mod your resistance against elements: + // val1 = water | val2 = earth | val3 = fire | val4 = wind + // break; + //case ????: + //Place here SCs that have no SCB_* data, no skill associated, no ICON + //associated, and yet are not wrong/unknown. [Skotlex] + //break; + + case SC_MER_FLEE: + case SC_MER_ATK: + case SC_MER_HIT: + val2 = 15 * val1; + break; + case SC_MER_HP: + case SC_MER_SP: + val2 = 5 * val1; + break; + case SC_REBIRTH: + val2 = 20*val1; //% of life to be revived with + break; + + case SC_MANU_DEF: + case SC_MANU_ATK: + case SC_MANU_MATK: + val2 = 1; // Manuk group + break; + case SC_SPL_DEF: + case SC_SPL_ATK: + case SC_SPL_MATK: + val2 = 2; // Splendide group + break; + /** + * General + **/ + case SC_FEAR: + val2 = 2; + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_BURNING: + val4 = tick / 3000; // Total Ticks to Burn!! + tick_time = 3000; // [GodLesZ] tick time + break; + /** + * Rune Knight + **/ + case SC_DEATHBOUND: + val2 = 500 + 100 * val1; + break; + case SC_STONEHARDSKIN: + if( sd ) + val1 = sd->status.job_level * pc->checkskill(sd, RK_RUNEMASTERY) / 4; //DEF/MDEF Increase + break; + case SC_ABUNDANCE: + val4 = tick / 10000; + tick_time = 10000; // [GodLesZ] tick time + break; + /** + * Arch Bishop + **/ + case SC_RENOVATIO: + val4 = tick / 5000; + tick_time = 5000; + break; + case SC_SECRAMENT: + val2 = 10 * val1; + break; + case SC_VENOMIMPRESS: + val2 = 10 * val1; + break; + case SC_WEAPONBLOCKING: + val2 = 10 + 2 * val1; // Chance + val4 = tick / 5000; + tick_time = 5000; // [GodLesZ] tick time + break; + case SC_TOXIN: + val4 = tick / 10000; + tick_time = 10000; // [GodLesZ] tick time + break; + case SC_MAGICMUSHROOM: + val4 = tick / 4000; + tick_time = 4000; // [GodLesZ] tick time + break; + case SC_PYREXIA: + status->change_start(src, bl,SC_BLIND,10000,val1,0,0,0,30000,11); // Blind status that last for 30 seconds + val4 = tick / 3000; + tick_time = 3000; // [GodLesZ] tick time + break; + case SC_LEECHESEND: + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_OBLIVIONCURSE: + val4 = tick / 3000; + tick_time = 3000; // [GodLesZ] tick time + break; + case SC_CLOAKINGEXCEED: + val2 = ( val1 + 1 ) / 2; // Hits + val3 = 90 + val1 * 10; // Walk speed + if (bl->type == BL_PC) + val4 |= battle_config.pc_cloak_check_type&7; + else + val4 |= battle_config.monster_cloak_check_type&7; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_HALLUCINATIONWALK: + val2 = 50 * val1; // Evasion rate of physical attacks. Flee + val3 = 10 * val1; // Evasion rate of magical attacks. + break; + case SC_WHITEIMPRISON: + status_change_end(bl, SC_BURNING, INVALID_TIMER); + status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); + status_change_end(bl, SC_FREEZE, INVALID_TIMER); + status_change_end(bl, SC_STONE, INVALID_TIMER); + break; + case SC_MARSHOFABYSS: + val2 = 6 * val1; + if( sd ) // half on players + val2 >>= 1; + break; + case SC_FROSTMISTY: + status_change_end(bl, SC_BURNING, INVALID_TIMER); + break; + case SC_READING_SB: + // val2 = sp reduction per second + tick_time = 10000; // [GodLesZ] tick time + break; + case SC_SUMMON1: + case SC_SUMMON2: + case SC_SUMMON3: + case SC_SUMMON4: + case SC_SUMMON5: + val4 = tick / 1000; + if( val4 < 1 ) + val4 = 1; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_SHAPESHIFT: + switch( val1 ) + { + case 1: val2 = ELE_FIRE; break; + case 2: val2 = ELE_EARTH; break; + case 3: val2 = ELE_WIND; break; + case 4: val2 = ELE_WATER; break; + } + break; + case SC_STEALTHFIELD_MASTER: + val4 = tick / 1000; + tick_time = 2000 + (1000 * val1); + break; + case SC_ELECTRICSHOCKER: + case SC_COLD: + case SC_MEIKYOUSISUI: + val4 = tick / 1000; + if( val4 < 1 ) + val4 = 1; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_CAMOUFLAGE: + val4 = tick/1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_WUGDASH: + { + //Store time at which you started running. + int64 currenttick = timer->gettick(); + // Note: this int64 value is stored in two separate int32 variables (FIXME) + val3 = (int)(currenttick&0x00000000ffffffffLL); + val4 = (int)((currenttick&0xffffffff00000000LL)>>32); + } + tick = -1; + break; + case SC__REPRODUCE: + val4 = tick / 1000; + tick_time = 1000; + break; + case SC__SHADOWFORM: { + struct map_session_data * s_sd = map->id2sd(val2); + if( s_sd ) + s_sd->shadowform_id = bl->id; + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + } + break; + case SC__STRIPACCESSARY: + if (!sd) + val2 = 20; + break; + case SC__INVISIBILITY: + val2 = 50 - 10 * val1; // ASPD + val3 = 200 * val1; // CRITICAL + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC__ENERVATION: + val2 = 20 + 10 * val1; // ATK Reduction + if( sd ) pc->delspiritball(sd,sd->spiritball,0); + break; + case SC__GROOMY: + val2 = 20 + 10 * val1; //ASPD. Need to confirm if Movement Speed reduction is the same. [Jobbie] + val3 = 20 * val1; //HIT + if( sd ) { // Removes Animals + if( pc_isriding(sd) ) pc->setriding(sd, 0); + if( pc_isridingdragon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_DRAGON); + if( pc_iswug(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_WUG); + if( pc_isridingwug(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_WUGRIDER); + if( pc_isfalcon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_FALCON); + if( sd->status.pet_id > 0 ) pet->menu(sd, 3); + if( homun_alive(sd->hd) ) homun->vaporize(sd,HOM_ST_REST); + if( sd->md ) mercenary->delete(sd->md,3); + } + break; + case SC__LAZINESS: + val2 = 10 + 10 * val1; // Cast reduction + val3 = 10 * val1; // Flee Reduction + break; + case SC__UNLUCKY: + val2 = 10 * val1; // Crit and Flee2 Reduction + break; + case SC__WEAKNESS: + val2 = 10 * val1; + // bypasses coating protection and MADO + sc_start(src, bl,SC_NOEQUIPWEAPON,100,val1,tick); + sc_start(src, bl,SC_NOEQUIPSHIELD,100,val1,tick); + break; + case SC_GN_CARTBOOST: + if( val1 < 3 ) + val2 = 50; + else if( val1 < 5 ) + val2 = 75; + else + val2 = 100; + break; + case SC_PROPERTYWALK: + val3 = 0; + break; + case SC_WARMER: + status_change_end(bl, SC_FREEZE, INVALID_TIMER); + status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); + status_change_end(bl, SC_COLD, INVALID_TIMER); + break; + case SC_STRIKING: + val1 = 6 - val1;//spcost = 6 - level (lvl1:5 ... lvl 5: 1) + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_BLOOD_SUCKER: { - if (sd->mapindex != val2) + struct block_list *src2 = map->id2bl(val2); + val3 = 1; + if(src2) + val3 = 200 + 100 * val1 + status_get_int(src2); + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + } + break; + case SC_SWING: + val3 = 5 * val1 + val2;//Movement Speed And ASPD Increase + break; + case SC_SYMPHONY_LOVE: + val2 = 12 * val1 + val2 + sd->status.job_level / 4;//MDEF Increase In % + case SC_MOONLIT_SERENADE: + case SC_RUSH_WINDMILL: + val2 = 6 * val1 + val2 + sd->status.job_level / 5; + break; + case SC_ECHOSONG: + val3 = 6 * val1 + val2 + sd->status.job_level / 4;//DEF Increase In % + break; + case SC_HARMONIZE: + val2 = 5 + 5 * val1; + break; + case SC_SIREN: + val4 = tick / 2000; + tick_time = 2000; // [GodLesZ] tick time + break; + case SC_DEEP_SLEEP: + val4 = tick / 2000; + tick_time = 2000; // [GodLesZ] tick time + break; + case SC_SIRCLEOFNATURE: + val2 = 40 * val1;//HP recovery + val3 = 4 * val1;//SP drain + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_SONG_OF_MANA: + val3 = 10 + 5 * val2; + val4 = tick/5000; + tick_time = 5000; // [GodLesZ] tick time + break; + case SC_SATURDAY_NIGHT_FEVER: + /*val2 = 12000 - 2000 * val1;//HP/SP Drain Timer + if ( val2 < 1000 ) + val2 = 1000;//Added to prevent val3 from dividing by 0 when using level 6 or higher through commands. [Rytech] + val3 = tick/val2;*/ + val3 = tick / 3000; + tick_time = 3000;// [GodLesZ] tick time + break; + case SC_GLOOMYDAY: + if ( !val2 ) { + val2 = (val4 > 0 ? max(15, rnd()%(val4*5)) : 0) + val1 * 10; + } + if ( rnd()%10000 < val1*100 ) { // 1% per SkillLv chance + if ( !val3 ) + val3 = 50; + if( sd ) { + if( pc_isriding(sd) ) pc->setriding(sd, 0); + if( pc_isridingdragon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_DRAGON); + } + } + break; + case SC_SITDOWN_FORCE: + case SC_BANANA_BOMB_SITDOWN_POSTDELAY: + if( sd && !pc_issit(sd) ) { - int pos = (bl->x&0xFFFF)|(bl->y<<16); /// Current Coordinates - int mapindex = sd->mapindex; /// Current Map - //1. Place in Jail (val2 -> Jail Map, val3 -> x, val4 -> y - pc->setpos(sd,(unsigned short)val2,val3,val4, CLR_TELEPORT); - //2. Set restore point (val3 -> return map, val4 return coords - val3 = mapindex; - val4 = pos; - } else if (!val3 || val3 == sd->mapindex) { //Use save point. - val3 = sd->status.save_point.map; - val4 = (sd->status.save_point.x&0xFFFF) - |(sd->status.save_point.y<<16); + pc_setsit(sd); + skill->sit(sd,1); + clif->sitting(bl); + } + break; + case SC_DANCE_WITH_WUG: + val3 = 5 + 5 * val2;//ASPD Increase + val4 = 20 + 10 * val2;//Fixed Cast Time Reduction + break; + case SC_LERADS_DEW: + val3 = 200 * val1 + 300 * val2;//MaxHP Increase + break; + case SC_MELODYOFSINK: + val3 = val1 * (2 + val2);//INT Reduction. Formula Includes Caster And 2nd Performer. + val4 = tick/1000; + tick_time = 1000; + break; + case SC_BEYOND_OF_WARCRY: + val3 = val1 * (2 + val2);//STR And Crit Reduction. Formula Includes Caster And 2nd Performer. + val4 = 4 * val1 + 4 * val2;//MaxHP Reduction + break; + case SC_UNLIMITED_HUMMING_VOICE: + { + struct unit_data *ud = unit->bl2ud(bl); + if( ud == NULL ) return 0; + ud->state.skillcastcancel = 0; + val3 = 15 - (3 * val2);//Increased SP Cost. + } + break; + case SC_LG_REFLECTDAMAGE: + val2 = 15 + 5 * val1; + val3 = 25 + 5 * val1; //Number of Reflects + val4 = tick/10000; + tick_time = 10000; // [GodLesZ] tick time + break; + case SC_FORCEOFVANGUARD: + val2 = 8 + 12 * val1; // Chance + val3 = 5 + 2 * val1; // Max rage counters + tick = -1; //endless duration in the client + break; + case SC_EXEEDBREAK: + if( sd ){ + short index = sd->equip_index[EQI_HAND_R]; + val1 = 15 * (sd->status.job_level + val1 * 10); + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) + val1 += (sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->wlv) * status->get_lv(bl) / 100; + } + break; + case SC_PRESTIGE: + val2 = (st->int_ + st->luk) * val1 / 20;// Chance to evade magic damage. + val2 = val2 * status->get_lv(bl) / 200; + val2 += val1; + val1 *= 15; // Defence added + if( sd ) + val1 += 10 * pc->checkskill(sd,CR_DEFENDER); + val1 *= status->get_lv(bl) / 100; + break; + case SC_BANDING: + tick_time = 5000; // [GodLesZ] tick time + break; + case SC_MAGNETICFIELD: + val3 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_INSPIRATION: + if( sd ) { + val2 = 40 * val1 + 3 * sd->status.job_level;// ATK bonus + val3 = sd->status.base_level / 10 + sd->status.job_level / 5;// All stat bonus + } + val4 = tick / 5000; + tick_time = 5000; // [GodLesZ] tick time + status->change_clear_buffs(bl,3); //Remove buffs/debuffs + break; + case SC_LIGHTNINGWALK: // [(Job Level / 2) + (40 + 5 * Skill Level)] % + val1 = (sd?sd->status.job_level:2)/2 + 40 + 5 * val1; + break; + case SC_RAISINGDRAGON: + val3 = tick / 5000; + tick_time = 5000; // [GodLesZ] tick time + break; + case SC_GENTLETOUCH_CHANGE: + {// take note there is no def increase as skill desc says. [malufett] + struct block_list * src2; + val3 = st->agi * val1 / 60; // ASPD increase: [(Target AGI x Skill Level) / 60] % + if( (src2 = map->id2bl(val2)) ){ + val4 = ( 200/status_get_int(src2) ) * val1;// MDEF decrease: MDEF [(200 / Caster INT) x Skill Level] + val2 = ( status_get_dex(src2)/4 + status_get_str(src2)/2 ) * val1 / 5; // ATK increase: ATK [{(Caster DEX / 4) + (Caster STR / 2)} x Skill Level / 5] } } - break; - case SC_NJ_UTSUSEMI: - val2=(val1+1)/2; // number of hits blocked - val3=skill->get_blewcount(NJ_UTSUSEMI, val1); //knockback value. - break; - case SC_NJ_BUNSINJYUTSU: - val2=(val1+1)/2; // number of hits blocked - break; - case SC_HLIF_CHANGE: - val2= 30*val1; //Vit increase - val3= 20*val1; //Int increase - break; - case SC_SWOO: - if(st->mode&MD_BOSS) - tick /= 5; //TODO: Reduce skill's duration. But for how long? - break; - case SC_SPIDERWEB: - if( bl->type == BL_PC ) - tick /= 2; - break; - case SC_ARMOR: - //NPC_DEFENDER: - val2 = 80; //Damage reduction - //Attack requirements to be blocked: - val3 = BF_LONG; //Range - val4 = BF_WEAPON|BF_MISC; //Type - break; - case SC_ENCHANTARMS: - //end previous enchants - skill->enchant_elemental_end(bl,type); - //Make sure the received element is valid. - if (val2 >= ELE_MAX) - val2 = val2%ELE_MAX; - else if (val2 < 0) - val2 = rnd()%ELE_MAX; - break; - case SC_CRITICALWOUND: - val2 = 20*val1; //Heal effectiveness decrease - break; - case SC_MAGICMIRROR: - case SC_SLOWCAST: - val2 = 20*val1; //Magic reflection/cast rate - break; - - case SC_STONESKIN: - if (val2 == NPC_ANTIMAGIC) - { //Boost mdef - val2 =-20; - val3 = 20; - } else { //Boost def - val2 = 20; - val3 =-20; - } - val2*=val1; //20% per level - val3*=val1; - break; - case SC_CASH_PLUSEXP: - case SC_CASH_PLUSONLYJOBEXP: - if (val1 < 0) - val1 = 0; - break; - case SC_PLUSAVOIDVALUE: - case SC_CRITICALPERCENT: - val2 = val1*10; //Actual boost (since 100% = 1000) - break; - case SC_SUFFRAGIUM: - val2 = 15 * val1; //Speed cast decrease - break; - case SC_HEALPLUS: - if (val1 < 1) - val1 = 1; - break; - case SC_ILLUSION: - val2 = 5+val1; //Factor by which displayed damage is increased by - break; - case SC_DOUBLECASTING: - val2 = 30+10*val1; //Trigger rate - break; - case SC_KAIZEL: - val2 = 10*val1; //% of life to be revived with - break; - // case SC_ARMORPROPERTY: - // case SC_ARMOR_RESIST: - // Mod your resistance against elements: - // val1 = water | val2 = earth | val3 = fire | val4 = wind - // break; - //case ????: - //Place here SCs that have no SCB_* data, no skill associated, no ICON - //associated, and yet are not wrong/unknown. [Skotlex] - //break; + break; + case SC_GENTLETOUCH_REVITALIZE: + {// take note there is no vit,aspd,speed increase as skill desc says. [malufett] + struct block_list * src2; + val3 = val1 * 30 + 150; // Natural HP recovery increase: [(Skill Level x 30) + 50] % + if( (src2 = map->id2bl(val2)) ) // the stat def is not shown in the status window and it is process differently + val4 = ( status_get_vit(src2)/4 ) * val1; // STAT DEF increase: [(Caster VIT / 4) x Skill Level] + } + break; + case SC_PYROTECHNIC_OPTION: + val2 = 60; + break; + case SC_HEATER_OPTION: + val2 = 120; // Watk. TODO: Renewal (Atk2) + val3 = (sd ? sd->status.job_level : 0); // % Increase damage. + val4 = 3; // Change into fire element. + break; + case SC_TROPIC_OPTION: + val2 = 180; // Watk. TODO: Renewal (Atk2) + val3 = MG_FIREBOLT; + break; + case SC_AQUAPLAY_OPTION: + val2 = 40; + break; + case SC_COOLER_OPTION: + val2 = 80; // Bonus Matk + val3 = (sd ? sd->status.job_level : 0); // % Freezing chance + val4 = 1; // Change into water elemet + break; + case SC_CHILLY_AIR_OPTION: + val2 = 120; // Matk. TODO: Renewal (Matk1) + val3 = MG_COLDBOLT; + break; + case SC_WIND_STEP_OPTION: + val2 = 50; // % Increase speed and flee. + break; + case SC_BLAST_OPTION: + val2 = (sd ? sd->status.job_level : 0); // % Increase damage + val3 = ELE_WIND; + break; + case SC_WILD_STORM_OPTION: + val2 = MG_LIGHTNINGBOLT; + break; + case SC_PETROLOGY_OPTION: + val2 = 5; + val3 = 50; + break; + case SC_SOLID_SKIN_OPTION: + val2 = 33; // % Increase DEF + break; + case SC_CURSED_SOIL_OPTION: + val2 = 10; + val3 = (sd ? sd->status.job_level : 0); // % Increase Damage + val4 = 2; + break; + case SC_UPHEAVAL_OPTION: + val2 = WZ_EARTHSPIKE; + val3 = 15; // Bonus MaxHP + break; + case SC_CIRCLE_OF_FIRE_OPTION: + val2 = 300; + break; + case SC_FIRE_CLOAK_OPTION: + case SC_WATER_DROP_OPTION: + case SC_WIND_CURTAIN_OPTION: + case SC_STONE_SHIELD_OPTION: + val2 = 100; // Elemental modifier. + break; + case SC_CIRCLE_OF_FIRE: + case SC_FIRE_CLOAK: + case SC_WATER_DROP: + case SC_WATER_SCREEN: + case SC_WIND_CURTAIN: + case SC_WIND_STEP: + case SC_STONE_SHIELD: + case SC_SOLID_SKIN: + val2 = 10; + tick_time = 2000; // [GodLesZ] tick time + break; + case SC_WATER_BARRIER: + val2 = 40; // Increasement. Mdef1 ??? + val3 = 30; // Reductions. Atk2, Flee1, Matk1 ???? + break; + case SC_ZEPHYR: + val2 = 25; // Flee. + break; + case SC_TIDAL_WEAPON: + val2 = 20; // Increase Elemental's attack. + break; + case SC_ROCK_CRUSHER: + case SC_ROCK_CRUSHER_ATK: + case SC_POWER_OF_GAIA: + val2 = 33; + break; + case SC_MELON_BOMB: + case SC_BANANA_BOMB: + val1 = 15; + break; + case SC_STOMACHACHE: + val2 = 8; // SP consume. + val4 = tick / 10000; + tick_time = 10000; // [GodLesZ] tick time + break; + case SC_KYOUGAKU: + val2 = 2*val1 + rand()%(3 * val1); + clif->status_change(bl, SI_ACTIVE_MONSTER_TRANSFORM, 1, 0, 1002, 0, 0); // Poring in disguise + break; + case SC_KAGEMUSYA: + val3 = val1 * 2; + case SC_IZAYOI: + val2 = tick/1000; + tick_time = 1000; + break; + case SC_ZANGETSU: + val2 = val4 = status->get_lv(bl) / 3 + 20 * val1; + val3 = status->get_lv(bl) / 2 + 30 * val1; + val2 = (!(status_get_hp(bl)%2) ? val2 : -val3); + val3 = (!(status_get_sp(bl)%2) ? val4 : -val3); + break; + case SC_GENSOU: + +#define PER( a, lvl ) do { \ + int temp__ = (a); \ + if( temp__ <= 15 ) (lvl) = 1; \ + else if( temp__ <= 30 ) (lvl) = 2; \ + else if( temp__ <= 50 ) (lvl) = 3; \ + else if( temp__ <= 75 ) (lvl) = 4; \ + else (lvl) = 5; \ +} while(0) - case SC_MER_FLEE: - case SC_MER_ATK: - case SC_MER_HIT: - val2 = 15 * val1; - break; - case SC_MER_HP: - case SC_MER_SP: - val2 = 5 * val1; - break; - case SC_REBIRTH: - val2 = 20*val1; //% of life to be revived with - break; + { + int hp = status_get_hp(bl), sp = status_get_sp(bl), lv = 5; - case SC_MANU_DEF: - case SC_MANU_ATK: - case SC_MANU_MATK: - val2 = 1; // Manuk group - break; - case SC_SPL_DEF: - case SC_SPL_ATK: - case SC_SPL_MATK: - val2 = 2; // Splendide group - break; - /** - * General - **/ - case SC_FEAR: - val2 = 2; - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_BURNING: - val4 = tick / 3000; // Total Ticks to Burn!! - tick_time = 3000; // [GodLesZ] tick time - break; - /** - * Rune Knight - **/ - case SC_DEATHBOUND: - val2 = 500 + 100 * val1; - break; - case SC_STONEHARDSKIN: - if( sd ) - val1 = sd->status.job_level * pc->checkskill(sd, RK_RUNEMASTERY) / 4; //DEF/MDEF Increase - break; + if( rand()%100 > (25 + 10 * val1) - status_get_int(bl) / 2) + return 0; + + PER( 100 / (status_get_max_hp(bl) / hp), lv ); + status->heal(bl, (!(hp%2) ? (6-lv) *4 / 100 : -(lv*4) / 100), 0, 1); + + PER( 100 / (status_get_max_sp(bl) / sp), lv ); + status->heal(bl, 0,(!(sp%2) ? (6-lv) *3 / 100 : -(lv*3) / 100), 1); + } +#undef PER + break; + case SC_ANGRIFFS_MODUS: + val2 = 50 + 20 * val1; //atk bonus + val3 = 40 + 20 * val1; // Flee reduction. + val4 = tick/1000; // hp/sp reduction timer + tick_time = 1000; + break; + case SC_NEUTRALBARRIER: + tick_time = tick; + tick = -1; + break; + case SC_GOLDENE_FERSE: + val2 = 10 + 10*val1; //max hp bonus + val3 = 6 + 4 * val1; // Aspd Bonus + val4 = 2 + 2 * val1; // Chance of holy attack + break; + case SC_OVERED_BOOST: + val2 = 300 + 40*val1; //flee bonus + val3 = 179 + 2*val1; //aspd bonus + break; + case SC_GRANITIC_ARMOR: + val2 = 2*val1; //dmg reduction + val3 = 6*val1; //dmg on status end + break; + case SC_MAGMA_FLOW: + val2 = 3*val1; //activation chance + break; + case SC_PYROCLASTIC: + val2 += 10*val1; //atk bonus + break; + case SC_NEEDLE_OF_PARALYZE: //[Lighta] need real info + val2 = 2*val1; //def reduction + val3 = 500*val1; //varcast augmentation + break; + case SC_PAIN_KILLER: //[Lighta] need real info + val2 = 2*val1; //aspd reduction % + val3 = 2*val1; //dmg reduction % + if(sc->data[SC_NEEDLE_OF_PARALYZE]) + sc_start(src, bl, SC_ENDURE, 100, val1, tick); //start endure for same duration + break; + case SC_STYLE_CHANGE: //[Lighta] need real info + tick = -1; + if(val2 == MH_MD_FIGHTING) val2 = MH_MD_GRAPPLING; + else val2 = MH_MD_FIGHTING; + break; + case SC_FULL_THROTTLE: + status_percent_heal(bl,100,0); + val2 = 7 - val1; + tick_time = 1000; + val4 = tick / tick_time; + break; + case SC_KINGS_GRACE: + val2 = 3 + val1; + tick_time = 1000; + val4 = tick / tick_time; + break; + case SC_TELEKINESIS_INTENSE: + val2 = 10 * val1; + val3 = 40 * val1; + break; + case SC_OFFERTORIUM: + val2 = 30 * val1; + break; + case SC_FRIGG_SONG: + val2 = 5 * val1; + val3 = (20 * val1) + 80; + tick_time = 1000; + val4 = tick / tick_time; + break; + case SC_DARKCROW: + val2 = 30 * val1; + break; + case SC_MONSTER_TRANSFORM: + if( !mob->db_checkid(val1) ) + val1 = 1002; // default poring + break; + default: + if( calc_flag == SCB_NONE && status->SkillChangeTable[type] == 0 && status->IconChangeTable[type] == 0 ) + { //Status change with no calc, no icon, and no skill associated...? + ShowError("UnknownStatusChange [%d]\n", type); + return 0; + } + } + } else { //Special considerations when loading SC data. + switch( type ) { + case SC_WEDDING: + case SC_XMAS: + case SC_SUMMER: + case SC_HANBOK: + case SC_OKTOBERFEST: + if( !vd ) break; + clif->changelook(bl,LOOK_BASE,vd->class_); + clif->changelook(bl,LOOK_WEAPON,0); + clif->changelook(bl,LOOK_SHIELD,0); + clif->changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color); + break; + case SC_KAAHI: + val4 = INVALID_TIMER; + break; + case SC_KYOUGAKU: + clif->status_change(bl, SI_ACTIVE_MONSTER_TRANSFORM, 1, 0, 1002, 0, 0); // Poring in disguise + break; + } + } + + /* values that must be set regardless of flag&4 e.g. val_flag */ + switch(type) { case SC_FIGHTINGSPIRIT: val_flag |= 1|2; break; - case SC_ABUNDANCE: - val4 = tick / 10000; - tick_time = 10000; // [GodLesZ] tick time - break; - /** - * Arch Bishop - **/ - case SC_RENOVATIO: - val4 = tick / 5000; - tick_time = 5000; - break; - case SC_SECRAMENT: - val2 = 10 * val1; - break; case SC_VENOMIMPRESS: - val2 = 10 * val1; val_flag |= 1|2; break; case SC_POISONINGWEAPON: val_flag |= 1|2|4; break; case SC_WEAPONBLOCKING: - val2 = 10 + 2 * val1; // Chance - val4 = tick / 3000; - tick_time = 3000; // [GodLesZ] tick time val_flag |= 1|2; break; - case SC_TOXIN: - val4 = tick / 10000; - tick_time = 10000; // [GodLesZ] tick time - break; - case SC_MAGICMUSHROOM: - val4 = tick / 4000; - tick_time = 4000; // [GodLesZ] tick time - break; - case SC_PYREXIA: - status->change_start(bl,SC_BLIND,10000,val1,0,0,0,30000,11); // Blind status that last for 30 seconds - val4 = tick / 3000; - tick_time = 3000; // [GodLesZ] tick time - break; - case SC_LEECHESEND: - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_OBLIVIONCURSE: - val4 = tick / 3000; - tick_time = 3000; // [GodLesZ] tick time - break; case SC_ROLLINGCUTTER: val_flag |= 1; break; case SC_CLOAKINGEXCEED: - val2 = ( val1 + 1 ) / 2; // Hits - val3 = 90 + val1 * 10; // Walk speed val_flag |= 1|2|4; - if (bl->type == BL_PC) - val4 |= battle_config.pc_cloak_check_type&7; - else - val4 |= battle_config.monster_cloak_check_type&7; - tick_time = 1000; // [GodLesZ] tick time break; case SC_HALLUCINATIONWALK: - val2 = 50 * val1; // Evasion rate of physical attacks. Flee - val3 = 10 * val1; // Evasion rate of magical attacks. val_flag |= 1|2|4; break; - case SC_WHITEIMPRISON: - status_change_end(bl, SC_BURNING, INVALID_TIMER); - status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); - status_change_end(bl, SC_FREEZE, INVALID_TIMER); - status_change_end(bl, SC_STONE, INVALID_TIMER); - break; - case SC_MARSHOFABYSS: - val2 = 6 * val1; - if( sd ) // half on players - val2 >>= 1; - break; - case SC_FROSTMISTY: - status_change_end(bl, SC_BURNING, INVALID_TIMER); - break; - case SC_READING_SB: - // val2 = sp reduction per second - tick_time = 5000; // [GodLesZ] tick time - break; case SC_SUMMON1: case SC_SUMMON2: case SC_SUMMON3: case SC_SUMMON4: case SC_SUMMON5: - val4 = tick / 1000; - if( val4 < 1 ) - val4 = 1; - tick_time = 1000; // [GodLesZ] tick time val_flag |= 1; break; - case SC_SHAPESHIFT: - switch( val1 ) - { - case 1: val2 = ELE_FIRE; break; - case 2: val2 = ELE_EARTH; break; - case 3: val2 = ELE_WIND; break; - case 4: val2 = ELE_WATER; break; - } - break; - case SC_ELECTRICSHOCKER: - case SC_COLD: - case SC_MEIKYOUSISUI: - val4 = tick / 1000; - if( val4 < 1 ) - val4 = 1; - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_CAMOUFLAGE: - val4 = tick/1000; - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_WUGDASH: - val4 = timer->gettick(); //Store time at which you started running. - tick = -1; - break; - case SC__SHADOWFORM: { - struct map_session_data * s_sd = map->id2sd(val2); - if( s_sd ) - s_sd->shadowform_id = bl->id; - val4 = tick / 1000; + case SC__SHADOWFORM: val_flag |= 1|2|4; - tick_time = 1000; // [GodLesZ] tick time - } - break; - case SC__STRIPACCESSARY: - if (!sd) - val2 = 20; break; case SC__INVISIBILITY: - val2 = 50 - 10 * val1; // ASPD - val3 = 20 * val1; // CRITICAL - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time val_flag |= 1|2; break; case SC__ENERVATION: - val2 = 20 + 10 * val1; // ATK Reduction val_flag |= 1|2; - if( sd ) pc->delspiritball(sd,sd->spiritball,0); break; case SC__GROOMY: - val2 = 20 + 10 * val1; //ASPD. Need to confirm if Movement Speed reduction is the same. [Jobbie] - val3 = 20 * val1; //HIT val_flag |= 1|2|4; - if( sd ) { // Removes Animals - if( pc_isriding(sd) ) pc->setriding(sd, 0); - if( pc_isridingdragon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_DRAGON); - if( pc_iswug(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_WUG); - if( pc_isridingwug(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_WUGRIDER); - if( pc_isfalcon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_FALCON); - if( sd->status.pet_id > 0 ) pet->menu(sd, 3); - if( homun_alive(sd->hd) ) homun->vaporize(sd,1); - if( sd->md ) mercenary->delete(sd->md,3); - } break; case SC__LAZINESS: - val2 = 10 + 10 * val1; // Cast reduction - val3 = 10 * val1; // Flee Reduction val_flag |= 1|2|4; break; case SC__UNLUCKY: - val2 = 10 * val1; // Crit and Flee2 Reduction val_flag |= 1|2|4; break; case SC__WEAKNESS: - val2 = 10 * val1; val_flag |= 1|2; - // bypasses coating protection and MADO - sc_start(bl,SC_NOEQUIPWEAPON,100,val1,tick); - sc_start(bl,SC_NOEQUIPSHIELD,100,val1,tick); - break; - case SC_GN_CARTBOOST: - if( val1 < 3 ) - val2 = 50; - else if( val1 < 5 ) - val2 = 75; - else - val2 = 100; break; case SC_PROPERTYWALK: val_flag |= 1|2; - val3 = 0; - break; - case SC_WARMER: - status_change_end(bl, SC_FREEZE, INVALID_TIMER); - status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); - status_change_end(bl, SC_COLD, INVALID_TIMER); - break; - case SC_STRIKING: - val1 = 6 - val1;//spcost = 6 - level (lvl1:5 ... lvl 5: 1) - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_BLOOD_SUCKER: - { - struct block_list *src = map->id2bl(val2); - val3 = 1; - if(src) - val3 = 200 + 100 * val1 + status_get_int(src); - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - } - break; - case SC_VACUUM_EXTREME: - tick -= (st->str / 20) * 1000; - val4 = val3 = tick / 100; - tick_time = 100; // [GodLesZ] tick time break; - case SC_SWING: - val2 = 4 * val1; // Walk speed and aspd reduction. - break; - case SC_SYMPHONY_LOVE: - case SC_RUSH_WINDMILL: - case SC_ECHOSONG: - val2 = 6 * val1; - val2 += val3; //Adding 1% * Lesson Bonus - val2 += (int)(val4*2/10); //Adding 0.2% per JobLevel - break; - case SC_MOONLIT_SERENADE: - val2 = 10 * val1; - break; - case SC_HARMONIZE: - val2 = 5 + 5 * val1; - break; - case SC_SIREN: - val4 = tick / 2000; - tick_time = 2000; // [GodLesZ] tick time - break; - case SC_DEEP_SLEEP: - val4 = tick / 2000; - tick_time = 2000; // [GodLesZ] tick time - break; - case SC_SIRCLEOFNATURE: - val2 = 1 + val1; //SP consume - val3 = 40 * val1; //HP recovery - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_SONG_OF_MANA: - val3 = 10 + (2 * val2); - val4 = tick/3000; - tick_time = 3000; // [GodLesZ] tick time - break; - case SC_SATURDAY_NIGHT_FEVER: - if (!val4) val4 = skill->get_time2(status->sc2skill(type),val1); - if (!val4) val4 = 3000; - val3 = tick/val4; - tick_time = val4; // [GodLesZ] tick time - break; - case SC_GLOOMYDAY: - val2 = 20 + 5 * val1; // Flee reduction. - val3 = 15 + 5 * val1; // ASPD reduction. - if( sd && rand()%100 < val1 ){ // (Skill Lv) % - val4 = 1; // reduce walk speed by half. - if( pc_isriding(sd) ) pc->setriding(sd, 0); - if( pc_isridingdragon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_DRAGON); - } - break; - case SC_GLOOMYDAY_SK: - // Random number between [15 ~ (Voice Lesson Skill Level x 5) + (Skill Level x 10)] %. - val2 = 15 + rand()%( (sd?pc->checkskill(sd, WM_LESSON)*5:0) + val1*10 ); - break; - case SC_SITDOWN_FORCE: - case SC_BANANA_BOMB_SITDOWN_POSTDELAY: - if( sd && !pc_issit(sd) ) - { - pc_setsit(sd); - skill->sit(sd,1); - clif->sitting(bl); - } - break; - case SC_DANCE_WITH_WUG: - val3 = (5 * val1) + (1 * val2); //Still need official value. - break; - case SC_LERADS_DEW: - val3 = (5 * val1) + (1 * val2); - break; - case SC_MELODYOFSINK: - val3 = (5 * val1) + (1 * val2); - break; - case SC_BEYOND_OF_WARCRY: - val3 = (5 * val1) + (1 * val2); - break; - case SC_UNLIMITED_HUMMING_VOICE: - { - struct unit_data *ud = unit->bl2ud(bl); - if( ud == NULL ) return 0; - ud->state.skillcastcancel = 0; - val3 = 15 - (2 * val2); - } - break; - case SC_LG_REFLECTDAMAGE: - val2 = 15 + 5 * val1; - val3 = (val1==5)?20:(val1+4)*2; // SP consumption - val4 = tick/10000; - tick_time = 10000; // [GodLesZ] tick time - break; - case SC_FORCEOFVANGUARD: // This is not the official way to handle it but I think we should use it. [pakpil] - val2 = 20 + 12 * (val1 - 1); // Chance - val3 = 5 + (2 * val1); // Max rage counters - tick = -1; //endless duration in the client - tick_time = 6000; // [GodLesZ] tick time + case SC_FORCEOFVANGUARD: val_flag |= 1|2|4; break; - case SC_EXEEDBREAK: - val1 *= 150; // 150 * skill_lv - if( sd && sd->inventory_data[sd->equip_index[EQI_HAND_R]] ) { // Chars. - val1 += (sd->inventory_data[sd->equip_index[EQI_HAND_R]]->weight/10 * sd->inventory_data[sd->equip_index[EQI_HAND_R]]->wlv * status->get_lv(bl) / 100); - val1 += 15 * (sd ? sd->status.job_level:50) + 100; - } else // Mobs - val1 += (400 * status->get_lv(bl) / 100) + (15 * (status->get_lv(bl) / 2)); // About 1138% at mob_lvl 99. Is an aproximation to a standard weapon. [pakpil] - break; - case SC_PRESTIGE: // Based on suggested formula in iRO Wiki and some test, still need more test. [pakpil] - val2 = ((st->int_ + st->luk) / 6) + 5; // Chance to evade magic damage. - val1 *= 15; // Defence added - if( sd ) - val1 += 10 * pc->checkskill(sd,CR_DEFENDER); + case SC_PRESTIGE: val_flag |= 1|2; break; case SC_BANDING: - tick_time = 5000; // [GodLesZ] tick time val_flag |= 1; break; case SC_SHIELDSPELL_DEF: @@ -8407,554 +9063,320 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_SHIELDSPELL_REF: val_flag |= 1|2; break; - case SC_MAGNETICFIELD: - val3 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - break; - case SC_INSPIRATION: - if( sd ) { - val2 = (40 * val1) + (3 * sd->status.job_level); // ATK bonus - val3 = (sd->status.job_level / 10) * 2 + 12; // All stat bonus - } - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - status->change_clear_buffs(bl,3); //Remove buffs/debuffs - break; case SC_SPELLFIST: case SC_CURSEDCIRCLE_ATKER: val_flag |= 1|2|4; break; case SC_CRESCENTELBOW: - val2 = 94 + val1; val_flag |= 1|2; break; - case SC_LIGHTNINGWALK: // [(Job Level / 2) + (40 + 5 * Skill Level)] % - val1 = (sd?sd->status.job_level:2)/2 + 40 + 5 * val1; + case SC_LIGHTNINGWALK: val_flag |= 1; break; - case SC_RAISINGDRAGON: - val3 = tick / 5000; - tick_time = 5000; // [GodLesZ] tick time - break; - case SC_GENTLETOUCH_CHANGE: - {// take note there is no def increase as skill desc says. [malufett] - struct block_list * src; - val3 = st->agi * val1 / 60; // ASPD increase: [(Target AGI x Skill Level) / 60] % - if( (src = map->id2bl(val2)) ){ - val4 = ( 200/status_get_int(src) ) * val1;// MDEF decrease: MDEF [(200 / Caster INT) x Skill Level] - val2 = ( status_get_dex(src)/4 + status_get_str(src)/2 ) * val1 / 5; // ATK increase: ATK [{(Caster DEX / 4) + (Caster STR / 2)} x Skill Level / 5] - } - } - break; - case SC_GENTLETOUCH_REVITALIZE: - {// take note there is no vit,aspd,speed increase as skill desc says. [malufett] - struct block_list * src; - val3 = val1 * 30 + 150; // Natural HP recovery increase: [(Skill Level x 30) + 50] % - if( (src = map->id2bl(val2)) ) // the stat def is not shown in the status window and it is process differently - val4 = ( status_get_vit(src)/4 ) * val1; // STAT DEF increase: [(Caster VIT / 4) x Skill Level] - } - break; case SC_PYROTECHNIC_OPTION: val_flag |= 1|2|4; break; case SC_HEATER_OPTION: - val2 = 120; // Watk. TODO: Renewal (Atk2) - val3 = 33; // % Increase effects. - val4 = 3; // Change into fire element. val_flag |= 1|2|4; break; - case SC_TROPIC_OPTION: - val2 = 180; // Watk. TODO: Renewal (Atk2) - val3 = MG_FIREBOLT; - break; case SC_AQUAPLAY_OPTION: - val2 = 40; val_flag |= 1|2|4; break; case SC_COOLER_OPTION: - val2 = 80; // % Freezing chance - val3 = 33; // % increased damage - val4 = 1; // Change into water elemet val_flag |= 1|2|4; break; case SC_CHILLY_AIR_OPTION: - val2 = 120; // Matk. TODO: Renewal (Matk1) - val3 = MG_COLDBOLT; val_flag |= 1|2; break; case SC_GUST_OPTION: val_flag |= 1|2; break; - case SC_WIND_STEP_OPTION: - val2 = 50; // % Increase speed and flee. - break; case SC_BLAST_OPTION: - val2 = 20; - val3 = ELE_WIND; val_flag |= 1|2|4; break; case SC_WILD_STORM_OPTION: - val2 = MG_LIGHTNINGBOLT; val_flag |= 1|2; break; case SC_PETROLOGY_OPTION: - val2 = 5; - val3 = 50; val_flag |= 1|2|4; break; case SC_CURSED_SOIL_OPTION: - val2 = 10; - val3 = 33; - val4 = 2; val_flag |= 1|2|4; break; case SC_UPHEAVAL_OPTION: - val2 = WZ_EARTHSPIKE; val_flag |= 1|2; break; case SC_CIRCLE_OF_FIRE_OPTION: - val2 = 300; val_flag |= 1|2; break; - case SC_FIRE_CLOAK_OPTION: - case SC_WATER_DROP_OPTION: - case SC_WIND_CURTAIN_OPTION: - case SC_STONE_SHIELD_OPTION: - val2 = 20; // Elemental modifier. Not confirmed. - break; - case SC_CIRCLE_OF_FIRE: - case SC_FIRE_CLOAK: - case SC_WATER_DROP: - case SC_WATER_SCREEN: - case SC_WIND_CURTAIN: - case SC_WIND_STEP: - case SC_STONE_SHIELD: - case SC_SOLID_SKIN: - val2 = 10; - tick_time = 2000; // [GodLesZ] tick time - break; case SC_WATER_BARRIER: - val2 = 40; // Increasement. Mdef1 ??? - val3 = 20; // Reductions. Atk2, Flee1, Matk1 ???? val_flag |= 1|2|4; break; - case SC_ZEPHYR: - val2 = 22; // Flee. + case SC_CASH_PLUSEXP: + case SC_CASH_PLUSONLYJOBEXP: + case SC_MONSTER_TRANSFORM: + case SC_CASH_RECEIVEITEM: + val_flag |= 1; break; - case SC_TIDAL_WEAPON: - val2 = 20; // Increase Elemental's attack. + } + + /* [Ind/Hercules] */ + if( sd && status->DisplayType[type] ) { + int dval1 = 0, dval2 = 0, dval3 = 0; + switch( type ) { + case SC_ALL_RIDING: + dval1 = 1; + break; + default: /* all others: just copy val1 */ + dval1 = val1; + break; + } + status->display_add(sd,type,dval1,dval2,dval3); + } + + //Those that make you stop attacking/walking.... + switch (type) { + case SC_VACUUM_EXTREME: + if(!map_flag_gvg(bl->m)) + unit->stop_walking(bl,1); break; - case SC_ROCK_CRUSHER: - case SC_ROCK_CRUSHER_ATK: - case SC_POWER_OF_GAIA: - val2 = 33; + case SC_FREEZE: + case SC_STUN: + case SC_SLEEP: + case SC_STONE: + case SC_DEEP_SLEEP: + if (sd && pc_issit(sd)) //Avoid sprite sync problems. + pc->setstand(sd); + case SC_TRICKDEAD: + status_change_end(bl, SC_DANCING, INVALID_TIMER); + // Cancel cast when get status [LuzZza] + if (battle_config.sc_castcancel&bl->type) + unit->skillcastcancel(bl, 0); + case SC_WHITEIMPRISON: + unit->stop_attack(bl); + case SC_STOP: + case SC_CONFUSION: + case SC_RG_CCONFINE_M: + case SC_RG_CCONFINE_S: + case SC_SPIDERWEB: + case SC_ELECTRICSHOCKER: + case SC_WUGBITE: + case SC_THORNS_TRAP: + case SC__MANHOLE: + case SC__CHAOS: + case SC_COLD: + case SC_CURSEDCIRCLE_ATKER: + case SC_CURSEDCIRCLE_TARGET: + case SC_FEAR: + case SC_MEIKYOUSISUI: + case SC_KYOUGAKU: + case SC_NEEDLE_OF_PARALYZE: + case SC_DEATHBOUND: + unit->stop_walking(bl,1); break; - case SC_MELON_BOMB: - case SC_BANANA_BOMB: - val1 = 15; + case SC_ANKLESNARE: + if( battle_config.skill_trap_type || !map_flag_gvg(bl->m) ) + unit->stop_walking(bl,1); break; - case SC_STOMACHACHE: - val2 = 8; // SP consume. - val4 = tick / 10000; - tick_time = 10000; // [GodLesZ] tick time + case SC_HIDING: + case SC_CLOAKING: + case SC_CLOAKINGEXCEED: + case SC_CHASEWALK: + case SC_WEIGHTOVER90: + case SC_CAMOUFLAGE: + case SC_SIREN: + unit->stop_attack(bl); break; - case SC_KYOUGAKU: - val2 = 2*val1 + rand()%(3 * val1); - clif->status_change(bl, SI_ACTIVE_MONSTER_TRANSFORM, 1, 0, 1002, 0, 0); // Poring in disguise + case SC_SILENCE: + if (battle_config.sc_castcancel&bl->type) + unit->skillcastcancel(bl, 0); break; - case SC_KAGEMUSYA: - val3 = val1 * 2; - case SC_IZAYOI: - val2 = tick/1000; - tick_time = 1000; - break; - case SC_ZANGETSU: - val2 = val4 = status->get_lv(bl) / 3 + 20 * val1; - val3 = status->get_lv(bl) / 2 + 30 * val1; - val2 = (!(status_get_hp(bl)%2) ? val2 : -val3); - val3 = (!(status_get_sp(bl)%2) ? val4 : -val3); - break; - case SC_GENSOU: - -#define PER( a ) do { \ - if( a <= 15 ) lv = 1; \ - else if( a <= 30 ) lv = 2; \ - else if( a <= 50 ) lv = 3; \ - else if( a <= 75 ) lv = 4; \ -} while(0) - - { - int hp = status_get_hp(bl), sp = status_get_sp(bl), lv = 5; + /* */ + case SC_ITEMSCRIPT: + if( sd ) { + switch( val1 ) { + //case ITEMID_PHREEONI_CARD: + //case ITEMID_GHOSTRING_CARD: + case ITEMID_TAO_GUNKA_CARD: + clif->status_change(bl,SI_MVPCARD_TAOGUNKA,1,tick,0,0,0); + break; + case ITEMID_MISTRESS_CARD: + clif->status_change(bl,SI_MVPCARD_MISTRESS,1,tick,0,0,0); + break; + case ITEMID_ORC_HERO_CARD: + clif->status_change(bl,SI_MVPCARD_ORCHERO,1,tick,0,0,0); + break; + case ITEMID_ORC_LOAD_CARD: + clif->status_change(bl,SI_MVPCARD_ORCLORD,1,tick,0,0,0); + break; + } + } + break; + } - if( rand()%100 > (25 + 10 * val1) - status_get_int(bl) / 2) - return 0; + // Set option as needed. + opt_flag = 1; + switch(type) { + //OPT1 + case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break; + case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break; + case SC_STUN: sc->opt1 = OPT1_STUN; break; + case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break; + case SC_BURNING: sc->opt1 = OPT1_BURNING; break; // Burning need this to be showed correctly. [pakpil] + case SC_WHITEIMPRISON: sc->opt1 = OPT1_IMPRISON; break; + case SC_COLD: sc->opt1 = OPT1_CRYSTALIZE; break; + //OPT2 + case SC_POISON: sc->opt2 |= OPT2_POISON; break; + case SC_CURSE: sc->opt2 |= OPT2_CURSE; break; + case SC_SILENCE: sc->opt2 |= OPT2_SILENCE; break; - PER( 100 / (status_get_max_hp(bl) / hp) ); - status->heal(bl, (!(hp%2) ? (6-lv) *4 / 100 : -(lv*4) / 100), 0, 1); + case SC_CRUCIS: + case SC__CHAOS: + sc->opt2 |= OPT2_SIGNUMCRUCIS; + break; - PER( 100 / (status_get_max_sp(bl) / sp) ); - status->heal(bl, 0,(!(sp%2) ? (6-lv) *3 / 100 : -(lv*3) / 100), 1); - } -#undef PER + case SC_BLIND: sc->opt2 |= OPT2_BLIND; break; + case SC_ANGELUS: sc->opt2 |= OPT2_ANGELUS; break; + case SC_BLOODING: sc->opt2 |= OPT2_BLEEDING; break; + case SC_DPOISON: sc->opt2 |= OPT2_DPOISON; break; + //OPT3 + case SC_TWOHANDQUICKEN: + case SC_ONEHANDQUICKEN: + case SC_SPEARQUICKEN: + case SC_LKCONCENTRATION: + case SC_MER_QUICKEN: + sc->opt3 |= OPT3_QUICKEN; + opt_flag = 0; break; - case SC_ANGRIFFS_MODUS: - val2 = 50 + 20 * val1; //atk bonus - val3 = 40 + 20 * val1; // Flee reduction. - val4 = tick/1000; // hp/sp reduction timer - tick_time = 1000; + case SC_OVERTHRUSTMAX: + case SC_OVERTHRUST: + case SC_SWOO: //Why does it shares the same opt as Overthrust? Perhaps we'll never know... + sc->opt3 |= OPT3_OVERTHRUST; + opt_flag = 0; break; - case SC_NEUTRALBARRIER: - tick_time = tick; - tick = -1; + case SC_ENERGYCOAT: + case SC_SKE: + sc->opt3 |= OPT3_ENERGYCOAT; + opt_flag = 0; break; - case SC_GOLDENE_FERSE: - val2 = 10 + 10*val1; //max hp bonus - val3 = 6 + 4 * val1; // Aspd Bonus - val4 = 2 + 2 * val1; // Chance of holy attack + case SC_INCATKRATE: + //Simulate Explosion Spirits effect for NPC_POWERUP [Skotlex] + if (bl->type != BL_MOB) { + opt_flag = 0; + break; + } + case SC_EXPLOSIONSPIRITS: + sc->opt3 |= OPT3_EXPLOSIONSPIRITS; + opt_flag = 0; + break; + case SC_STEELBODY: + case SC_SKA: + sc->opt3 |= OPT3_STEELBODY; + opt_flag = 0; break; - case SC_OVERED_BOOST: - val2 = 300 + 40*val1; //flee bonus - val3 = 179 + 2*val1; //aspd bonus + case SC_BLADESTOP: + sc->opt3 |= OPT3_BLADESTOP; + opt_flag = 0; break; - case SC_GRANITIC_ARMOR: - val2 = 2*val1; //dmg reduction - val3 = 6*val1; //dmg on status end + case SC_AURABLADE: + sc->opt3 |= OPT3_AURABLADE; + opt_flag = 0; break; - case SC_MAGMA_FLOW: - val2 = 3*val1; //activation chance + case SC_BERSERK: + opt_flag = 0; + sc->opt3 |= OPT3_BERSERK; break; - case SC_PYROCLASTIC: - val2 += 10*val1; //atk bonus +// case ???: // doesn't seem to do anything +// sc->opt3 |= OPT3_LIGHTBLADE; +// opt_flag = 0; +// break; + case SC_DANCING: + if ((val1&0xFFFF) == CG_MOONLIT) + sc->opt3 |= OPT3_MOONLIT; + opt_flag = 0; break; - case SC_NEEDLE_OF_PARALYZE: //[Lighta] need real info - val2 = 2*val1; //def reduction - val3 = 500*val1; //varcast augmentation + case SC_MARIONETTE_MASTER: + case SC_MARIONETTE: + sc->opt3 |= OPT3_MARIONETTE; + opt_flag = 0; break; - case SC_PAIN_KILLER: //[Lighta] need real info - val2 = 2*val1; //aspd reduction % - val3 = 2*val1; //dmg reduction % - if(sc->data[SC_NEEDLE_OF_PARALYZE]) - sc_start(bl, SC_ENDURE, 100, val1, tick); //start endure for same duration + case SC_ASSUMPTIO: + sc->opt3 |= OPT3_ASSUMPTIO; + opt_flag = 0; break; - case SC_STYLE_CHANGE: //[Lighta] need real info - tick = -1; - if(val2 == MH_MD_FIGHTING) val2 = MH_MD_GRAPPLING; - else val2 = MH_MD_FIGHTING; + case SC_WARM: //SG skills [Komurka] + sc->opt3 |= OPT3_WARM; + opt_flag = 0; break; - case SC_FULL_THROTTLE: - status_percent_heal(bl,100,0); - val2 = 7 - val1; - tick_time = 1000; - val4 = tick / tick_time; + case SC_KAITE: + sc->opt3 |= OPT3_KAITE; + opt_flag = 0; break; - case SC_KINGS_GRACE: - val2 = 3 + val1; - tick_time = 1000; - val4 = tick / tick_time; + case SC_NJ_BUNSINJYUTSU: + sc->opt3 |= OPT3_BUNSIN; + opt_flag = 0; break; - case SC_TELEKINESIS_INTENSE: - val2 = 10 * val1; - val3 = 40 * val1; + case SC_SOULLINK: + sc->opt3 |= OPT3_SOULLINK; + opt_flag = 0; break; - case SC_OFFERTORIUM: - val2 = 30 * val1; + case SC_PROPERTYUNDEAD: + sc->opt3 |= OPT3_UNDEAD; + opt_flag = 0; break; - case SC_FRIGG_SONG: - val2 = 5 * val1; - val3 = 1000 + 100 * val1; - tick_time = 10000; - val4 = tick / tick_time; +// case ???: // from DA_CONTRACT (looks like biolab mobs aura) +// sc->opt3 |= OPT3_CONTRACT; +// opt_flag = 0; +// break; + //OPTION + case SC_HIDING: + sc->option |= OPTION_HIDE; + opt_flag = 2; break; - case SC_MONSTER_TRANSFORM: - if( !mob->db_checkid(val1) ) - val1 = 1002; // default poring - val_flag |= 1; + case SC_CLOAKING: + case SC_CLOAKINGEXCEED: + sc->option |= OPTION_CLOAK; + opt_flag = 2; + break; + case SC__INVISIBILITY: + case SC_CHASEWALK: + sc->option |= OPTION_CHASEWALK|OPTION_CLOAK; + opt_flag = 2; + break; + case SC_SIGHT: + sc->option |= OPTION_SIGHT; + break; + case SC_RUWACH: + sc->option |= OPTION_RUWACH; break; - default: - if( calc_flag == SCB_NONE && status->SkillChangeTable[type] == 0 && status->IconChangeTable[type] == 0 ) - { //Status change with no calc, no icon, and no skill associated...? - ShowError("UnknownStatusChange [%d]\n", type); - return 0; - } - } - } else { //Special considerations when loading SC data. - switch( type ) { case SC_WEDDING: + sc->option |= OPTION_WEDDING; + opt_flag |= 0x4; + break; case SC_XMAS: - case SC_SUMMER: - case SC_HANBOK: - if( !vd ) break; - clif->changelook(bl,LOOK_BASE,vd->class_); - clif->changelook(bl,LOOK_WEAPON,0); - clif->changelook(bl,LOOK_SHIELD,0); - clif->changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color); + sc->option |= OPTION_XMAS; + opt_flag |= 0x4; break; - case SC_KAAHI: - val4 = INVALID_TIMER; + case SC_SUMMER: + sc->option |= OPTION_SUMMER; + opt_flag |= 0x4; break; - case SC_SUMMON1: - case SC_SUMMON2: - case SC_SUMMON3: - case SC_SUMMON4: - case SC_SUMMON5: - case SC_MONSTER_TRANSFORM: - val_flag |= 1; + case SC_HANBOK: + sc->option |= OPTION_HANBOK; + opt_flag |= 0x4; break; - case SC_KYOUGAKU: - clif->status_change(bl, SI_ACTIVE_MONSTER_TRANSFORM, 1, 0, 1002, 0, 0); // Poring in disguise + case SC_ORCISH: + sc->option |= OPTION_ORCISH; break; - } - } - - /* [Ind/Hercules] */ - if( sd && status->DisplayType[type] ) { - int dval1 = 0, dval2 = 0, dval3 = 0; - switch( type ) { - case SC_ALL_RIDING: - dval1 = 1; + case SC_FUSION: + sc->option |= OPTION_FLYING; break; - default: /* all others: just copy val1 */ - dval1 = val1; + case SC_OKTOBERFEST: + sc->option |= OPTION_OKTOBERFEST; + opt_flag |= 0x4; break; - } - status->display_add(sd,type,dval1,dval2,dval3); - } - - //Those that make you stop attacking/walking.... - switch (type) { - case SC_FREEZE: - case SC_STUN: - case SC_SLEEP: - case SC_STONE: - case SC_DEEP_SLEEP: - if (sd && pc_issit(sd)) //Avoid sprite sync problems. - pc->setstand(sd); - case SC_TRICKDEAD: - status_change_end(bl, SC_DANCING, INVALID_TIMER); - // Cancel cast when get status [LuzZza] - if (battle_config.sc_castcancel&bl->type) - unit->skillcastcancel(bl, 0); - case SC_WHITEIMPRISON: - unit->stop_attack(bl); - case SC_STOP: - case SC_CONFUSION: - case SC_RG_CCONFINE_M: - case SC_RG_CCONFINE_S: - case SC_SPIDERWEB: - case SC_ELECTRICSHOCKER: - case SC_WUGBITE: - case SC_THORNS_TRAP: - case SC__MANHOLE: - case SC_COLD: - case SC_CURSEDCIRCLE_ATKER: - case SC_CURSEDCIRCLE_TARGET: - case SC_FEAR: - case SC_NETHERWORLD: - case SC_MEIKYOUSISUI: - case SC_KYOUGAKU: - case SC_NEEDLE_OF_PARALYZE: - case SC_DEATHBOUND: - unit->stop_walking(bl,1); - break; - case SC_ANKLESNARE: - if( battle_config.skill_trap_type || !map_flag_gvg(bl->m) ) - unit->stop_walking(bl,1); - break; - case SC_HIDING: - case SC_CLOAKING: - case SC_CLOAKINGEXCEED: - case SC_CHASEWALK: - case SC_WEIGHTOVER90: - case SC_CAMOUFLAGE: - case SC_SIREN: - unit->stop_attack(bl); - break; - case SC_SILENCE: - if (battle_config.sc_castcancel&bl->type) - unit->skillcastcancel(bl, 0); - break; - /* */ - case SC_ITEMSCRIPT: - if( sd ) { - switch( val1 ) { - //case 4121://Phree - //case 4047://Ghostring - case 4302://Gunka - clif->status_change(bl,SI_MVPCARD_TAOGUNKA,1,tick,0,0,0); - break; - case 4132://Mistress - clif->status_change(bl,SI_MVPCARD_MISTRESS,1,tick,0,0,0); - break; - case 4143://Orc Hero - clif->status_change(bl,SI_MVPCARD_ORCHERO,1,tick,0,0,0); - break; - case 4135://Orc Lord - clif->status_change(bl,SI_MVPCARD_ORCLORD,1,tick,0,0,0); - break; - } - } - break; - } - - // Set option as needed. - opt_flag = 1; - switch(type) { - //OPT1 - case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break; - case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break; - case SC_STUN: sc->opt1 = OPT1_STUN; break; - case SC_DEEP_SLEEP: opt_flag = 0; - case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break; - case SC_BURNING: sc->opt1 = OPT1_BURNING; break; // Burning need this to be showed correctly. [pakpil] - case SC_WHITEIMPRISON: sc->opt1 = OPT1_IMPRISON; break; - case SC_COLD: sc->opt1 = OPT1_CRYSTALIZE; break; - //OPT2 - case SC_POISON: sc->opt2 |= OPT2_POISON; break; - case SC_CURSE: sc->opt2 |= OPT2_CURSE; break; - case SC_SILENCE: sc->opt2 |= OPT2_SILENCE; break; - - case SC_CRUCIS: - sc->opt2 |= OPT2_SIGNUMCRUCIS; - break; - - case SC_BLIND: sc->opt2 |= OPT2_BLIND; break; - case SC_ANGELUS: sc->opt2 |= OPT2_ANGELUS; break; - case SC_BLOODING: sc->opt2 |= OPT2_BLEEDING; break; - case SC_DPOISON: sc->opt2 |= OPT2_DPOISON; break; - //OPT3 - case SC_TWOHANDQUICKEN: - case SC_ONEHANDQUICKEN: - case SC_SPEARQUICKEN: - case SC_LKCONCENTRATION: - case SC_MER_QUICKEN: - sc->opt3 |= OPT3_QUICKEN; - opt_flag = 0; - break; - case SC_OVERTHRUSTMAX: - case SC_OVERTHRUST: - case SC_SWOO: //Why does it shares the same opt as Overthrust? Perhaps we'll never know... - sc->opt3 |= OPT3_OVERTHRUST; - opt_flag = 0; - break; - case SC_ENERGYCOAT: - case SC_SKE: - sc->opt3 |= OPT3_ENERGYCOAT; - opt_flag = 0; - break; - case SC_INCATKRATE: - //Simulate Explosion Spirits effect for NPC_POWERUP [Skotlex] - if (bl->type != BL_MOB) { + default: opt_flag = 0; - break; - } - case SC_EXPLOSIONSPIRITS: - sc->opt3 |= OPT3_EXPLOSIONSPIRITS; - opt_flag = 0; - break; - case SC_STEELBODY: - case SC_SKA: - sc->opt3 |= OPT3_STEELBODY; - opt_flag = 0; - break; - case SC_BLADESTOP: - sc->opt3 |= OPT3_BLADESTOP; - opt_flag = 0; - break; - case SC_AURABLADE: - sc->opt3 |= OPT3_AURABLADE; - opt_flag = 0; - break; - case SC_BERSERK: - opt_flag = 0; - sc->opt3 |= OPT3_BERSERK; - break; - // case ???: // doesn't seem to do anything - // sc->opt3 |= OPT3_LIGHTBLADE; - // opt_flag = 0; - // break; - case SC_DANCING: - if ((val1&0xFFFF) == CG_MOONLIT) - sc->opt3 |= OPT3_MOONLIT; - opt_flag = 0; - break; - case SC_MARIONETTE_MASTER: - case SC_MARIONETTE: - sc->opt3 |= OPT3_MARIONETTE; - opt_flag = 0; - break; - case SC_ASSUMPTIO: - sc->opt3 |= OPT3_ASSUMPTIO; - opt_flag = 0; - break; - case SC_WARM: //SG skills [Komurka] - sc->opt3 |= OPT3_WARM; - opt_flag = 0; - break; - case SC_KAITE: - sc->opt3 |= OPT3_KAITE; - opt_flag = 0; - break; - case SC_NJ_BUNSINJYUTSU: - sc->opt3 |= OPT3_BUNSIN; - opt_flag = 0; - break; - case SC_SOULLINK: - sc->opt3 |= OPT3_SOULLINK; - opt_flag = 0; - break; - case SC_PROPERTYUNDEAD: - sc->opt3 |= OPT3_UNDEAD; - opt_flag = 0; - break; - // case ???: // from DA_CONTRACT (looks like biolab mobs aura) - // sc->opt3 |= OPT3_CONTRACT; - // opt_flag = 0; - // break; - //OPTION - case SC_HIDING: - sc->option |= OPTION_HIDE; - opt_flag = 2; - break; - case SC_CLOAKING: - case SC_CLOAKINGEXCEED: - case SC__INVISIBILITY: - sc->option |= OPTION_CLOAK; - opt_flag = 2; - break; - case SC_CHASEWALK: - sc->option |= OPTION_CHASEWALK|OPTION_CLOAK; - opt_flag = 2; - break; - case SC_SIGHT: - sc->option |= OPTION_SIGHT; - break; - case SC_RUWACH: - sc->option |= OPTION_RUWACH; - break; - case SC_WEDDING: - sc->option |= OPTION_WEDDING; - opt_flag |= 0x4; - break; - case SC_XMAS: - sc->option |= OPTION_XMAS; - opt_flag |= 0x4; - break; - case SC_SUMMER: - sc->option |= OPTION_SUMMER; - opt_flag |= 0x4; - break; - case SC_HANBOK: - sc->option |= OPTION_HANBOK; - opt_flag |= 0x4; - break; - case SC_ORCISH: - sc->option |= OPTION_ORCISH; - break; - case SC_FUSION: - sc->option |= OPTION_FLYING; - break; - default: - opt_flag = 0; } //On Aegis, when turning on a status change, first goes the option packet, then the sc packet. @@ -8998,8 +9420,11 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val sce->val4 = val4; if (tick >= 0) sce->timer = timer->add(timer->gettick() + tick, status->change_timer, bl->id, type); - else + else { sce->timer = INVALID_TIMER; //Infinite duration + if( sd ) + chrif->save_scdata_single(sd->status.account_id,sd->status.char_id,type,sce); + } if (calc_flag) status_calc_bl(bl,calc_flag); @@ -9008,81 +9433,81 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val pet->sc_check(sd, type); //Skotlex: Pet Status Effect Healing switch (type) { - case SC_BERSERK: - if (!(sce->val2)) { //don't heal if already set - status->heal(bl, st->max_hp, 0, 1); //Do not use percent_heal as this healing must override BERSERK's block. - status->set_sp(bl, 0, 0); //Damage all SP - } - sce->val2 = 5 * st->max_hp / 100; - break; - case SC_HLIF_CHANGE: - status_percent_heal(bl, 100, 100); - break; - case SC_RUN: - { - struct unit_data *ud = unit->bl2ud(bl); - if( ud ) - ud->state.running = unit->run(bl); - } - break; - case SC_CASH_BOSS_ALARM: - clif->bossmapinfo(sd->fd, map->id2boss(sce->val1), 0); // First Message - break; - case SC_MER_HP: - status_percent_heal(bl, 100, 0); // Recover Full HP - break; - case SC_MER_SP: - status_percent_heal(bl, 0, 100); // Recover Full SP - break; - /** - * Ranger - **/ - case SC_WUGDASH: - { - struct unit_data *ud = unit->bl2ud(bl); - if( ud ) - ud->state.running = unit->wugdash(bl, sd); - } - break; - case SC_COMBOATTACK: - switch (sce->val1) { - case TK_STORMKICK: - clif->skill_nodamage(bl,bl,TK_READYSTORM,1,1); + case SC_BERSERK: + if (!(sce->val2)) { //don't heal if already set + status->heal(bl, st->max_hp, 0, 1); //Do not use percent_heal as this healing must override BERSERK's block. + status->set_sp(bl, 0, 0); //Damage all SP + } + sce->val2 = 5 * st->max_hp / 100; break; - case TK_DOWNKICK: - clif->skill_nodamage(bl,bl,TK_READYDOWN,1,1); + case SC_HLIF_CHANGE: + status_percent_heal(bl, 100, 100); break; - case TK_TURNKICK: - clif->skill_nodamage(bl,bl,TK_READYTURN,1,1); + case SC_RUN: + { + struct unit_data *ud = unit->bl2ud(bl); + if( ud ) + ud->state.running = unit->run(bl); + } break; - case TK_COUNTER: - clif->skill_nodamage(bl,bl,TK_READYCOUNTER,1,1); + case SC_CASH_BOSS_ALARM: + clif->bossmapinfo(sd->fd, map->id2boss(sce->val1), 0); // First Message break; - case MO_COMBOFINISH: - case CH_TIGERFIST: - case CH_CHAINCRUSH: - if (sd) - clif->skillinfo(sd,MO_EXTREMITYFIST, INF_SELF_SKILL); + case SC_MER_HP: + status_percent_heal(bl, 100, 0); // Recover Full HP break; - case TK_JUMPKICK: - if (sd) - clif->skillinfo(sd,TK_JUMPKICK, INF_SELF_SKILL); + case SC_MER_SP: + status_percent_heal(bl, 0, 100); // Recover Full SP break; - case MO_TRIPLEATTACK: - if (sd && pc->checkskill(sd, SR_DRAGONCOMBO) > 0) - clif->skillinfo(sd,SR_DRAGONCOMBO, INF_SELF_SKILL); + /** + * Ranger + **/ + case SC_WUGDASH: + { + struct unit_data *ud = unit->bl2ud(bl); + if( ud ) + ud->state.running = unit->wugdash(bl, sd); + } break; - case SR_FALLENEMPIRE: - if (sd){ - clif->skillinfo(sd,SR_GATEOFHELL, INF_SELF_SKILL); - clif->skillinfo(sd,SR_TIGERCANNON, INF_SELF_SKILL); + case SC_COMBOATTACK: + switch (sce->val1) { + case TK_STORMKICK: + clif->skill_nodamage(bl,bl,TK_READYSTORM,1,1); + break; + case TK_DOWNKICK: + clif->skill_nodamage(bl,bl,TK_READYDOWN,1,1); + break; + case TK_TURNKICK: + clif->skill_nodamage(bl,bl,TK_READYTURN,1,1); + break; + case TK_COUNTER: + clif->skill_nodamage(bl,bl,TK_READYCOUNTER,1,1); + break; + case MO_COMBOFINISH: + case CH_TIGERFIST: + case CH_CHAINCRUSH: + if (sd) + clif->skillinfo(sd,MO_EXTREMITYFIST, INF_SELF_SKILL); + break; + case TK_JUMPKICK: + if (sd) + clif->skillinfo(sd,TK_JUMPKICK, INF_SELF_SKILL); + break; + case MO_TRIPLEATTACK: + if (sd && pc->checkskill(sd, SR_DRAGONCOMBO) > 0) + clif->skillinfo(sd,SR_DRAGONCOMBO, INF_SELF_SKILL); + break; + case SR_FALLENEMPIRE: + if (sd){ + clif->skillinfo(sd,SR_GATEOFHELL, INF_SELF_SKILL); + clif->skillinfo(sd,SR_TIGERCANNON, INF_SELF_SKILL); + } + break; } break; - } - break; - case SC_RAISINGDRAGON: - sce->val2 = st->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] - break; + case SC_RAISINGDRAGON: + sce->val2 = st->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] + break; } if( opt_flag&2 && sd && sd->touching_id ) @@ -9090,7 +9515,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val return 1; } - /*========================================== * Ending all status except those listed. * @TODO maybe usefull for dispel instead reseting a liste there. @@ -9116,25 +9540,16 @@ int status_change_clear(struct block_list* bl, int type) { if(type == 0){ if( status->get_sc_type(i)&SC_NO_REM_DEATH ) { switch (i) { - case SC_ARMOR_PROPERTY://Only when its Holy or Dark that it doesn't dispell on death - if( sc->data[i]->val2 != ELE_HOLY && sc->data[i]->val2 != ELE_DARK ) - break; - default: - continue; + case SC_ARMOR_PROPERTY://Only when its Holy or Dark that it doesn't dispell on death + if( sc->data[i]->val2 != ELE_HOLY && sc->data[i]->val2 != ELE_DARK ) + break; + default: + continue; } } } - if( type == 3 ) { - switch (i) {// TODO: This list may be incomplete - case SC_WEIGHTOVER50: - case SC_WEIGHTOVER90: - case SC_NOCHAT: - case SC_PUSH_CART: - case SC_JAILED: - case SC_ALL_RIDING: - continue; - } - } + if( type == 3 && status->get_sc_type(i)&SC_NO_CLEAR ) + continue; status_change_end(bl, (sc_type)i, INVALID_TIMER); @@ -9152,6 +9567,7 @@ int status_change_clear(struct block_list* bl, int type) { sc->opt2 = 0; sc->opt3 = 0; sc->bs_counter = 0; + sc->fv_counter = 0; #ifndef RENEWAL sc->sg_counter = 0; #endif @@ -9172,7 +9588,10 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const struct status_data *st; struct view_data *vd; int opt_flag=0, calc_flag; - +#ifdef ANTI_MAYAP_CHEAT + bool invisible = false; +#endif + nullpo_ret(bl); sc = status->get_sc(bl); @@ -9186,6 +9605,9 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const if (sce->timer != tid && tid != INVALID_TIMER) return 0; + if( sd && sce->timer == INVALID_TIMER ) + chrif->del_scdata_single(sd->status.account_id,sd->status.char_id,type); + if (tid == INVALID_TIMER) { if (type == SC_ENDURE && sce->val4) //Do not end infinite endure. @@ -9197,19 +9619,19 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const //"Ugly workaround" [Skotlex] //delays status change ending so that a skill that sets opt1 fails to //trigger when it also removed one - case SC_STONE: - sce->val3 = 0; //Petrify time counter. - case SC_FREEZE: - case SC_STUN: - case SC_SLEEP: - if (sce->val1) { - //Removing the 'level' shouldn't affect anything in the code - //since these SC are not affected by it, and it lets us know - //if we have already delayed this attack or not. - sce->val1 = 0; - sce->timer = timer->add(timer->gettick()+10, status->change_timer, bl->id, type); - return 1; - } + case SC_STONE: + sce->val3 = 0; //Petrify time counter. + case SC_FREEZE: + case SC_STUN: + case SC_SLEEP: + if (sce->val1) { + //Removing the 'level' shouldn't affect anything in the code + //since these SC are not affected by it, and it lets us know + //if we have already delayed this attack or not. + sce->val1 = 0; + sce->timer = timer->add(timer->gettick()+10, status->change_timer, bl->id, type); + return 1; + } } } @@ -9221,602 +9643,625 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const status->display_remove(sd,type); } +#ifdef ANTI_MAYAP_CHEAT + if (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE)) + invisible = true; +#endif + vd = status->get_viewdata(bl); calc_flag = status->ChangeFlagTable[type]; switch(type) { - case SC_GRANITIC_ARMOR: - { - int damage = st->max_hp*sce->val3/100; - if(st->hp < damage) //to not kill him - damage = st->hp-1; - status->damage(NULL, bl, damage,0,0,1); - } - break; - case SC_PYROCLASTIC: - if(bl->type == BL_PC) - skill->break_equip(bl,EQP_WEAPON,10000,BCT_SELF); - break; - case SC_RUN: + case SC_GRANITIC_ARMOR: { - struct unit_data *ud = unit->bl2ud(bl); - bool begin_spurt = true; - if (ud) { - if(!ud->state.running) - begin_spurt = false; - ud->state.running = 0; - if (ud->walktimer != INVALID_TIMER) - unit->stop_walking(bl,1); - } - if (begin_spurt && sce->val1 >= 7 - && DIFF_TICK(timer->gettick(), sce->val4) <= 1000 - && (!sd || (sd->weapontype1 == 0 && sd->weapontype2 == 0)) - ) - sc_start(bl,SC_STRUP,100,sce->val1,skill->get_time2(status->sc2skill(type), sce->val1)); + int damage = st->max_hp*sce->val3/100; + if(st->hp < damage) //to not kill him + damage = st->hp-1; + status->damage(NULL, bl, damage,0,0,1); } - break; - case SC_AUTOBERSERK: - if (sc->data[SC_PROVOKE] && sc->data[SC_PROVOKE]->val2 == 1) - status_change_end(bl, SC_PROVOKE, INVALID_TIMER); - break; + break; + case SC_PYROCLASTIC: + if(bl->type == BL_PC) + skill->break_equip(bl,EQP_WEAPON,10000,BCT_SELF); + break; + case SC_RUN: + { + struct unit_data *ud = unit->bl2ud(bl); + bool begin_spurt = true; + // Note: this int64 value is stored in two separate int32 variables (FIXME) + int64 starttick = (int64)sce->val3&0x00000000ffffffffLL; + starttick |= ((int64)sce->val4<<32)&0xffffffff00000000LL; + + if (ud) { + if(!ud->state.running) + begin_spurt = false; + ud->state.running = 0; + if (ud->walktimer != INVALID_TIMER) + unit->stop_walking(bl,1); + } + if (begin_spurt && sce->val1 >= 7 + && DIFF_TICK(timer->gettick(), starttick) <= 1000 + && (!sd || (sd->weapontype1 == 0 && sd->weapontype2 == 0)) + ) + sc_start(bl, bl,SC_STRUP,100,sce->val1,skill->get_time2(status->sc2skill(type), sce->val1)); + } + break; + case SC_AUTOBERSERK: + if (sc->data[SC_PROVOKE] && sc->data[SC_PROVOKE]->val2 == 1) + status_change_end(bl, SC_PROVOKE, INVALID_TIMER); + break; - case SC_ENDURE: - case SC_DEFENDER: - case SC_REFLECTSHIELD: - case SC_AUTOGUARD: - { - struct map_session_data *tsd; - if( bl->type == BL_PC ) { - // Clear Status from others - int i; - for( i = 0; i < 5; i++ ) { - if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) && tsd->sc.data[type] ) + case SC_ENDURE: + case SC_DEFENDER: + case SC_REFLECTSHIELD: + case SC_AUTOGUARD: + { + struct map_session_data *tsd; + if( bl->type == BL_PC ) { + // Clear Status from others + int i; + for( i = 0; i < 5; i++ ) { + if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) && tsd->sc.data[type] ) + status_change_end(&tsd->bl, type, INVALID_TIMER); + } + } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag ) { + // Clear Status from Master + tsd = ((TBL_MER*)bl)->master; + if( tsd && tsd->sc.data[type] ) status_change_end(&tsd->bl, type, INVALID_TIMER); } - } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag ) { - // Clear Status from Master - tsd = ((TBL_MER*)bl)->master; - if( tsd && tsd->sc.data[type] ) - status_change_end(&tsd->bl, type, INVALID_TIMER); } - } - break; - case SC_DEVOTION: - { - struct block_list *d_bl = map->id2bl(sce->val1); - if( d_bl ) { - if( d_bl->type == BL_PC ) - ((TBL_PC*)d_bl)->devotion[sce->val2] = 0; - else if( d_bl->type == BL_MER ) - ((TBL_MER*)d_bl)->devotion_flag = 0; - clif->devotion(d_bl, NULL); - } - - status_change_end(bl, SC_AUTOGUARD, INVALID_TIMER); - status_change_end(bl, SC_DEFENDER, INVALID_TIMER); - status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); - status_change_end(bl, SC_ENDURE, INVALID_TIMER); - } - break; + break; + case SC_DEVOTION: + { + struct block_list *d_bl = map->id2bl(sce->val1); + if( d_bl ) { + if( d_bl->type == BL_PC ) + ((TBL_PC*)d_bl)->devotion[sce->val2] = 0; + else if( d_bl->type == BL_MER ) + ((TBL_MER*)d_bl)->devotion_flag = 0; + clif->devotion(d_bl, NULL); + } - case SC_BLADESTOP: - if(sce->val4) { - int tid = sce->val4; - struct block_list *tbl = map->id2bl(tid); - struct status_change *tsc = status->get_sc(tbl); - sce->val4 = 0; - if(tbl && tsc && tsc->data[SC_BLADESTOP]) { - tsc->data[SC_BLADESTOP]->val4 = 0; - status_change_end(tbl, SC_BLADESTOP, INVALID_TIMER); - } - clif->bladestop(bl, tid, 0); - } - break; - case SC_DANCING: - { - const char* prevfile = "<unknown>"; - int prevline = 0; - struct map_session_data *dsd; - struct status_change_entry *dsc; - struct skill_unit_group *group; + status_change_end(bl, SC_AUTOGUARD, INVALID_TIMER); + status_change_end(bl, SC_DEFENDER, INVALID_TIMER); + status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); + status_change_end(bl, SC_ENDURE, INVALID_TIMER); + } + break; - if( sd ) - { - if( sd->delunit_prevfile ) - {// initially this is NULL, when a character logs in - prevfile = sd->delunit_prevfile; - prevline = sd->delunit_prevline; + case SC_BLADESTOP: + if(sce->val4) { + int target_id = sce->val4; + struct block_list *tbl = map->id2bl(target_id); + struct status_change *tsc = status->get_sc(tbl); + sce->val4 = 0; + if(tbl && tsc && tsc->data[SC_BLADESTOP]) { + tsc->data[SC_BLADESTOP]->val4 = 0; + status_change_end(tbl, SC_BLADESTOP, INVALID_TIMER); } - else + clif->bladestop(bl, target_id, 0); + } + break; + case SC_DANCING: + { + const char* prevfile = "<unknown>"; + int prevline = 0; + struct map_session_data *dsd; + struct status_change_entry *dsc; + struct skill_unit_group *group; + + if( sd ) { - prevfile = "<none>"; + if( sd->delunit_prevfile ) + {// initially this is NULL, when a character logs in + prevfile = sd->delunit_prevfile; + prevline = sd->delunit_prevline; + } + else + { + prevfile = "<none>"; + } + sd->delunit_prevfile = file; + sd->delunit_prevline = line; } - sd->delunit_prevfile = file; - sd->delunit_prevline = line; - } - if(sce->val4 && sce->val4 != BCT_SELF && (dsd=map->id2sd(sce->val4))) - {// end status on partner as well - dsc = dsd->sc.data[SC_DANCING]; - if(dsc) { + if(sce->val4 && sce->val4 != BCT_SELF && (dsd=map->id2sd(sce->val4))) + {// end status on partner as well + dsc = dsd->sc.data[SC_DANCING]; + if(dsc) { - //This will prevent recursive loops. - dsc->val2 = dsc->val4 = 0; + //This will prevent recursive loops. + dsc->val2 = dsc->val4 = 0; - status_change_end(&dsd->bl, SC_DANCING, INVALID_TIMER); + status_change_end(&dsd->bl, SC_DANCING, INVALID_TIMER); + } } - } - if(sce->val2) - {// erase associated land skill - group = skill->id2group(sce->val2); + if(sce->val2) + {// erase associated land skill + group = skill->id2group(sce->val2); + + if( group == NULL ) + { + ShowDebug("status_change_end: SC_DANCING is missing skill unit group (val1=%d, val2=%d, val3=%d, val4=%d, timer=%d, tid=%d, char_id=%d, map=%s, x=%d, y=%d, prev=%s:%d, from=%s:%d). Please report this! (#3504)\n", + sce->val1, sce->val2, sce->val3, sce->val4, sce->timer, tid, + sd ? sd->status.char_id : 0, + mapindex_id2name(map_id2index(bl->m)), bl->x, bl->y, + prevfile, prevline, + file, line); + } - if( group == NULL ) - { - ShowDebug("status_change_end: SC_DANCING is missing skill unit group (val1=%d, val2=%d, val3=%d, val4=%d, timer=%d, tid=%d, char_id=%d, map=%s, x=%d, y=%d, prev=%s:%d, from=%s:%d). Please report this! (#3504)\n", - sce->val1, sce->val2, sce->val3, sce->val4, sce->timer, tid, - sd ? sd->status.char_id : 0, - mapindex_id2name(map_id2index(bl->m)), bl->x, bl->y, - prevfile, prevline, - file, line); + sce->val2 = 0; + skill->del_unitgroup(group,ALC_MARK); } - sce->val2 = 0; - skill->del_unitgroup(group,ALC_MARK); + if((sce->val1&0xFFFF) == CG_MOONLIT) + clif->sc_end(bl,bl->id,AREA,SI_MOON); + + status_change_end(bl, SC_LONGING, INVALID_TIMER); + } + break; + case SC_NOCHAT: + if (sd && sd->status.manner < 0 && tid != INVALID_TIMER) + sd->status.manner = 0; + if (sd && tid == INVALID_TIMER) + { + clif->changestatus(sd,SP_MANNER,sd->status.manner); + clif->updatestatus(sd,SP_MANNER); + } + break; + case SC_SPLASHER: + { + struct block_list *src=map->id2bl(sce->val3); + if(src && tid != INVALID_TIMER) + skill->castend_damage_id(src, bl, sce->val2, sce->val1, timer->gettick(), SD_LEVEL ); + } + break; + case SC_RG_CCONFINE_S: + { + struct block_list *src = sce->val2 ? map->id2bl(sce->val2) : NULL; + struct status_change *sc2 = src ? status->get_sc(src) : NULL; + if (src && sc2 && sc2->data[SC_RG_CCONFINE_M]) { + //If status was already ended, do nothing. + //Decrease count + if (--(sc2->data[SC_RG_CCONFINE_M]->val1) <= 0) //No more holds, free him up. + status_change_end(src, SC_RG_CCONFINE_M, INVALID_TIMER); + } + } + case SC_RG_CCONFINE_M: + if (sce->val2 > 0) { + //Caster has been unlocked... nearby chars need to be unlocked. + int range = 1 + +skill->get_range2(bl, status->sc2skill(type), sce->val1) + +skill->get_range2(bl, TF_BACKSLIDING, 1); //Since most people use this to escape the hold.... + map->foreachinarea(status->change_timer_sub, + bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,BL_CHAR,bl,sce,type,timer->gettick()); } + break; + case SC_COMBOATTACK: + if( sd ) + switch (sce->val1) { + case MO_COMBOFINISH: + case CH_TIGERFIST: + case CH_CHAINCRUSH: + clif->skillinfo(sd, MO_EXTREMITYFIST, 0); + break; + case TK_JUMPKICK: + clif->skillinfo(sd, TK_JUMPKICK, 0); + break; + case MO_TRIPLEATTACK: + if (pc->checkskill(sd, SR_DRAGONCOMBO) > 0) + clif->skillinfo(sd, SR_DRAGONCOMBO, 0); + break; + case SR_FALLENEMPIRE: + clif->skillinfo(sd, SR_GATEOFHELL, 0); + clif->skillinfo(sd, SR_TIGERCANNON, 0); + break; + } + break; - if((sce->val1&0xFFFF) == CG_MOONLIT) - clif->sc_end(bl,bl->id,AREA,SI_MOON); + case SC_MARIONETTE_MASTER: + case SC_MARIONETTE: /// Marionette target + if (sce->val1) { + // check for partner and end their marionette status as well + enum sc_type type2 = (type == SC_MARIONETTE_MASTER) ? SC_MARIONETTE : SC_MARIONETTE_MASTER; + struct block_list *pbl = map->id2bl(sce->val1); + struct status_change* sc2 = pbl ? status->get_sc(pbl) : NULL; + + if (sc2 && sc2->data[type2]) + { + sc2->data[type2]->val1 = 0; + status_change_end(pbl, type2, INVALID_TIMER); + } + } + break; - status_change_end(bl, SC_LONGING, INVALID_TIMER); - } - break; - case SC_NOCHAT: - if (sd && sd->status.manner < 0 && tid != INVALID_TIMER) - sd->status.manner = 0; - if (sd && tid == INVALID_TIMER) - { - clif->changestatus(sd,SP_MANNER,sd->status.manner); - clif->updatestatus(sd,SP_MANNER); - } - break; - case SC_SPLASHER: - { - struct block_list *src=map->id2bl(sce->val3); - if(src && tid != INVALID_TIMER) - skill->castend_damage_id(src, bl, sce->val2, sce->val1, timer->gettick(), SD_LEVEL ); - } - break; - case SC_RG_CCONFINE_S: - { - struct block_list *src = sce->val2 ? map->id2bl(sce->val2) : NULL; - struct status_change *sc2 = src ? status->get_sc(src) : NULL; - if (src && sc2 && sc2->data[SC_RG_CCONFINE_M]) { - //If status was already ended, do nothing. - //Decrease count - if (--(sc2->data[SC_RG_CCONFINE_M]->val1) <= 0) //No more holds, free him up. - status_change_end(src, SC_RG_CCONFINE_M, INVALID_TIMER); + case SC_BERSERK: + if(st->hp > 200 && sc && sc->data[SC__BLOODYLUST]) { + status_percent_heal(bl, 100, 0); + status_change_end(bl, SC__BLOODYLUST, INVALID_TIMER); + } else if(st->hp > 100 && sce->val2) //If val2 is removed, no HP penalty (dispelled?) [Skotlex] + status->set_hp(bl, 100, 0); + if(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4 == 2) { + sc->data[SC_ENDURE]->val4 = 0; + status_change_end(bl, SC_ENDURE, INVALID_TIMER); } - } - case SC_RG_CCONFINE_M: - if (sce->val2 > 0) { - //Caster has been unlocked... nearby chars need to be unlocked. - int range = 1 - +skill->get_range2(bl, status->sc2skill(type), sce->val1) - +skill->get_range2(bl, TF_BACKSLIDING, 1); //Since most people use this to escape the hold.... - map->foreachinarea(status->change_timer_sub, - bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,BL_CHAR,bl,sce,type,timer->gettick()); - } - break; - case SC_COMBOATTACK: - if( sd ) - switch (sce->val1) { - case MO_COMBOFINISH: - case CH_TIGERFIST: - case CH_CHAINCRUSH: - clif->skillinfo(sd, MO_EXTREMITYFIST, 0); - break; - case TK_JUMPKICK: - clif->skillinfo(sd, TK_JUMPKICK, 0); + sc_start4(bl, bl, SC_GDSKILL_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill->get_time(LK_BERSERK, sce->val1)); + if( type == SC_SATURDAY_NIGHT_FEVER ) //Sit down force of Saturday Night Fever has the duration of only 3 seconds. + sc_start(bl,bl,SC_SITDOWN_FORCE,100,sce->val1,skill->get_time2(WM_SATURDAY_NIGHT_FEVER,sce->val1)); + break; + case SC_GOSPEL: + if (sce->val3) { //Clear the group. + struct skill_unit_group* group = skill->id2group(sce->val3); + sce->val3 = 0; + skill->del_unitgroup(group,ALC_MARK); + } + break; + case SC_HERMODE: + if(sce->val3 == BCT_SELF) + skill->clear_unitgroup(bl); + break; + case SC_BASILICA: //Clear the skill area. [Skotlex] + skill->clear_unitgroup(bl); + break; + case SC_TRICKDEAD: + if (vd) vd->dead_sit = 0; + break; + case SC_WARM: + case SC__MANHOLE: + if (sce->val4) { //Clear the group. + struct skill_unit_group* group = skill->id2group(sce->val4); + sce->val4 = 0; + if( group ) /* might have been cleared before status ended, e.g. land protector */ + skill->del_unitgroup(group,ALC_MARK); + } + break; + case SC_KAAHI: + //Delete timer if it exists. + if (sce->val4 != INVALID_TIMER) + timer->delete(sce->val4,status->kaahi_heal_timer); + break; + case SC_JAILED: + if(tid == INVALID_TIMER) break; - case MO_TRIPLEATTACK: - if (pc->checkskill(sd, SR_DRAGONCOMBO) > 0) - clif->skillinfo(sd, SR_DRAGONCOMBO, 0); + //natural expiration. + if(sd && sd->mapindex == sce->val2) + pc->setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT); + break; //guess hes not in jail :P + case SC_HLIF_CHANGE: + if (tid == INVALID_TIMER) break; - case SR_FALLENEMPIRE: - clif->skillinfo(sd, SR_GATEOFHELL, 0); - clif->skillinfo(sd, SR_TIGERCANNON, 0); + // "lose almost all their HP and SP" on natural expiration. + status->set_hp(bl, 10, 0); + status->set_sp(bl, 10, 0); + break; + case SC_AUTOTRADE: + if (tid == INVALID_TIMER) break; - } - break; - - case SC_MARIONETTE_MASTER: - case SC_MARIONETTE: /// Marionette target - if (sce->val1) { - // check for partner and end their marionette status as well - enum sc_type type2 = (type == SC_MARIONETTE_MASTER) ? SC_MARIONETTE : SC_MARIONETTE_MASTER; - struct block_list *pbl = map->id2bl(sce->val1); - struct status_change* sc2 = pbl ? status->get_sc(pbl) : NULL; - - if (sc2 && sc2->data[type2]) - { - sc2->data[type2]->val1 = 0; - status_change_end(pbl, type2, INVALID_TIMER); + // Note: vending/buying is closed by unit_remove_map, no + // need to do it here. + map->quit(sd); + // Because map->quit calls status_change_end with tid -1 + // from here it's not neccesary to continue + return 1; + break; + case SC_STOP: + if( sce->val2 ) { + struct block_list *tbl = map->id2bl(sce->val2); + struct status_change *tsc = NULL; + sce->val2 = 0; + if( tbl && (tsc = status->get_sc(tbl)) && tsc->data[SC_STOP] && tsc->data[SC_STOP]->val2 == bl->id ) + status_change_end(tbl, SC_STOP, INVALID_TIMER); } - } - break; - - case SC_BERSERK: - case SC_SATURDAY_NIGHT_FEVER: - if(st->hp > 200 && sc && sc->data[SC__BLOODYLUST]) { - status_percent_heal(bl, 100, 0); - status_change_end(bl, SC__BLOODYLUST, INVALID_TIMER); - } else if(st->hp > 100 && sce->val2) //If val2 is removed, no HP penalty (dispelled?) [Skotlex] - status->set_hp(bl, 100, 0); - if(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4 == 2) { - sc->data[SC_ENDURE]->val4 = 0; + break; + case SC_LKCONCENTRATION: status_change_end(bl, SC_ENDURE, INVALID_TIMER); - } - sc_start4(bl, SC_GDSKILL_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill->get_time(LK_BERSERK, sce->val1)); - if( type == SC_SATURDAY_NIGHT_FEVER ) //Sit down force of Saturday Night Fever has the duration of only 3 seconds. - sc_start(bl,SC_SITDOWN_FORCE,100,sce->val1,skill->get_time2(WM_SATURDAY_NIGHT_FEVER,sce->val1)); - break; - case SC_GOSPEL: - if (sce->val3) { //Clear the group. - struct skill_unit_group* group = skill->id2group(sce->val3); - sce->val3 = 0; - skill->del_unitgroup(group,ALC_MARK); - } - break; - case SC_HERMODE: - if(sce->val3 == BCT_SELF) - skill->clear_unitgroup(bl); - break; - case SC_BASILICA: //Clear the skill area. [Skotlex] - skill->clear_unitgroup(bl); - break; - case SC_TRICKDEAD: - if (vd) vd->dead_sit = 0; - break; - case SC_WARM: - case SC__MANHOLE: - if (sce->val4) { //Clear the group. - struct skill_unit_group* group = skill->id2group(sce->val4); - sce->val4 = 0; - if( group ) /* might have been cleared before status ended, e.g. land protector */ - skill->del_unitgroup(group,ALC_MARK); - } - break; - case SC_KAAHI: - //Delete timer if it exists. - if (sce->val4 != INVALID_TIMER) - timer->delete(sce->val4,status->kaahi_heal_timer); - break; - case SC_JAILED: - if(tid == INVALID_TIMER) - break; - //natural expiration. - if(sd && sd->mapindex == sce->val2) - pc->setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT); - break; //guess hes not in jail :P - case SC_HLIF_CHANGE: - if (tid == INVALID_TIMER) - break; - // "lose almost all their HP and SP" on natural expiration. - status->set_hp(bl, 10, 0); - status->set_sp(bl, 10, 0); - break; - case SC_AUTOTRADE: - if (tid == INVALID_TIMER) - break; - // Note: vending/buying is closed by unit_remove_map, no - // need to do it here. - map->quit(sd); - // Because map->quit calls status_change_end with tid -1 - // from here it's not neccesary to continue - return 1; - break; - case SC_STOP: - if( sce->val2 ) { - struct block_list* tbl = map->id2bl(sce->val2); - sce->val2 = 0; - if( tbl && (sc = status->get_sc(tbl)) && sc->data[SC_STOP] && sc->data[SC_STOP]->val2 == bl->id ) - status_change_end(tbl, SC_STOP, INVALID_TIMER); - } - break; - case SC_LKCONCENTRATION: - status_change_end(bl, SC_ENDURE, INVALID_TIMER); - break; - /** - * 3rd Stuff - **/ - case SC_MILLENNIUMSHIELD: - clif->millenniumshield(sd,0); - break; - case SC_HALLUCINATIONWALK: - sc_start(bl,SC_HALLUCINATIONWALK_POSTDELAY,100,sce->val1,skill->get_time2(GC_HALLUCINATIONWALK,sce->val1)); - break; - case SC_WHITEIMPRISON: - { - struct block_list* src = map->id2bl(sce->val2); - if( tid == -1 || !src) - break; // Terminated by Damage - status_fix_damage(src,bl,400*sce->val1,clif->damage(bl,bl,timer->gettick(),0,0,400*sce->val1,0,0,0)); - } - break; - case SC_WUGDASH: - { - struct unit_data *ud = unit->bl2ud(bl); - if (ud) { - ud->state.running = 0; - if (ud->walktimer != -1) - unit->stop_walking(bl,1); + break; + /** + * 3rd Stuff + **/ + case SC_MILLENNIUMSHIELD: + clif->millenniumshield(bl,0); + break; + case SC_HALLUCINATIONWALK: + sc_start(bl,bl,SC_HALLUCINATIONWALK_POSTDELAY,100,sce->val1,skill->get_time2(GC_HALLUCINATIONWALK,sce->val1)); + break; + case SC_WHITEIMPRISON: + { + struct block_list* src = map->id2bl(sce->val2); + if( tid == -1 || !src) + break; // Terminated by Damage + status_fix_damage(src,bl,400*sce->val1,clif->damage(bl,bl,0,0,400*sce->val1,0,0,0)); } - } - break; - case SC_ADORAMUS: - status_change_end(bl, SC_BLIND, INVALID_TIMER); - break; - case SC__SHADOWFORM: - { - struct map_session_data *s_sd = map->id2sd(sce->val2); - if( !s_sd ) - break; - s_sd->shadowform_id = 0; - } - break; - case SC_SITDOWN_FORCE: - if( sd && pc_issit(sd) ) { - pc->setstand(sd); - clif->standing(bl); - } - break; - case SC_NEUTRALBARRIER_MASTER: - case SC_STEALTHFIELD_MASTER: - if( sce->val2 ) { - struct skill_unit_group* group = skill->id2group(sce->val2); - sce->val2 = 0; - if( group ) /* might have been cleared before status ended, e.g. land protector */ - skill->del_unitgroup(group,ALC_MARK); - } - break; - case SC_BANDING: - if(sce->val4) { - struct skill_unit_group *group = skill->id2group(sce->val4); - sce->val4 = 0; - if( group ) /* might have been cleared before status ended, e.g. land protector */ - skill->del_unitgroup(group,ALC_MARK); - } - break; - case SC_CURSEDCIRCLE_ATKER: - if( sce->val2 ) // used the default area size cause there is a chance the caster could knock back and can't clear the target. - map->foreachinrange(status->change_timer_sub, bl, battle_config.area_size,BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, timer->gettick()); - break; - case SC_RAISINGDRAGON: - if( sd && sce->val2 && !pc_isdead(sd) ) { - int i; - i = min(sd->spiritball,5); - pc->delspiritball(sd, sd->spiritball, 0); - status_change_end(bl, SC_EXPLOSIONSPIRITS, INVALID_TIMER); - while( i > 0 ) { - pc->addspiritball(sd, skill->get_time(MO_CALLSPIRITS, pc->checkskill(sd,MO_CALLSPIRITS)), 5); - --i; + break; + case SC_WUGDASH: + { + struct unit_data *ud = unit->bl2ud(bl); + if (ud) { + ud->state.running = 0; + if (ud->walktimer != -1) + unit->stop_walking(bl,1); + } } - } - break; - case SC_CURSEDCIRCLE_TARGET: - { - struct block_list *src = map->id2bl(sce->val2); - struct status_change *sc = status->get_sc(src); - if( sc && sc->data[SC_CURSEDCIRCLE_ATKER] && --(sc->data[SC_CURSEDCIRCLE_ATKER]->val2) == 0 ){ - status_change_end(src, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER); - clif->bladestop(bl, sce->val2, 0); - } - } - break; - case SC_BLOOD_SUCKER: - if( sce->val2 ){ + break; + case SC_ADORAMUS: + status_change_end(bl, SC_BLIND, INVALID_TIMER); + break; + case SC__SHADOWFORM: + { + struct map_session_data *s_sd = map->id2sd(sce->val2); + if( !s_sd ) + break; + s_sd->shadowform_id = 0; + } + break; + case SC_SITDOWN_FORCE: + if( sd && pc_issit(sd) ) { + pc->setstand(sd); + clif->standing(bl); + } + break; + case SC_NEUTRALBARRIER_MASTER: + case SC_STEALTHFIELD_MASTER: + if( sce->val2 ) { + struct skill_unit_group* group = skill->id2group(sce->val2); + sce->val2 = 0; + if( group ) /* might have been cleared before status ended, e.g. land protector */ + skill->del_unitgroup(group,ALC_MARK); + } + break; + case SC_BANDING: + if(sce->val4) { + struct skill_unit_group *group = skill->id2group(sce->val4); + sce->val4 = 0; + if( group ) /* might have been cleared before status ended, e.g. land protector */ + skill->del_unitgroup(group,ALC_MARK); + } + break; + case SC_CURSEDCIRCLE_ATKER: + if( sce->val2 ) // used the default area size cause there is a chance the caster could knock back and can't clear the target. + map->foreachinrange(status->change_timer_sub, bl, battle_config.area_size,BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, timer->gettick()); + break; + case SC_RAISINGDRAGON: + if( sd && sce->val2 && !pc_isdead(sd) ) { + int i; + i = min(sd->spiritball,5); + pc->delspiritball(sd, sd->spiritball, 0); + status_change_end(bl, SC_EXPLOSIONSPIRITS, INVALID_TIMER); + while( i > 0 ) { + pc->addspiritball(sd, skill->get_time(MO_CALLSPIRITS, pc->checkskill(sd,MO_CALLSPIRITS)), 5); + --i; + } + } + break; + case SC_CURSEDCIRCLE_TARGET: + { struct block_list *src = map->id2bl(sce->val2); - if(src) { - struct status_change *sc = status->get_sc(src); - sc->bs_counter--; + struct status_change *ssc = status->get_sc(src); + if( ssc && ssc->data[SC_CURSEDCIRCLE_ATKER] && --(ssc->data[SC_CURSEDCIRCLE_ATKER]->val2) == 0 ){ + status_change_end(src, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER); + clif->bladestop(bl, sce->val2, 0); } } - break; - case SC_KYOUGAKU: - clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_ACTIVE_MONSTER_TRANSFORM); - break; - case SC_CLAIRVOYANCE: - calc_flag = SCB_ALL;/* required for overlapping */ - break; - case SC_FULL_THROTTLE: - sc_start(bl,SC_REBOUND,100,sce->val1,skill->get_time2(ALL_FULL_THROTTLE,sce->val1)); - break; - case SC_ITEMSCRIPT: - if( sd ) { - switch( sce->val1 ) { - //case 4121://Phree - //case 4047://Ghostring - case 4302://Gunka - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_TAOGUNKA); - break; - case 4132://Mistress - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_MISTRESS); - break; - case 4143://Orc Hero - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_ORCHERO); - break; - case 4135://Orc Lord - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_ORCLORD); - break; + break; + case SC_BLOOD_SUCKER: + if( sce->val2 ){ + struct block_list *src = map->id2bl(sce->val2); + if(src) { + struct status_change *ssc = status->get_sc(src); + ssc->bs_counter--; + } } - } - break; + break; + case SC_KYOUGAKU: + clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_ACTIVE_MONSTER_TRANSFORM); + break; + case SC_CLAIRVOYANCE: + calc_flag = SCB_ALL;/* required for overlapping */ + break; + case SC_FULL_THROTTLE: + sc_start(bl,bl,SC_REBOUND,100,sce->val1,skill->get_time2(ALL_FULL_THROTTLE,sce->val1)); + break; + case SC_MONSTER_TRANSFORM: + if( sce->val2 ) + status_change_end(bl, (sc_type)sce->val2, INVALID_TIMER); + break; + case SC_ITEMSCRIPT: + if( sd ) { + switch( sce->val1 ) { + //case ITEMID_PHREEONI_CARD: + //case ITEMID_GHOSTRING_CARD: + case ITEMID_TAO_GUNKA_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_TAOGUNKA); + break; + case ITEMID_MISTRESS_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_MISTRESS); + break; + case ITEMID_ORC_HERO_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_ORCHERO); + break; + case ITEMID_ORC_LOAD_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_ORCLORD); + break; + } + } + break; } opt_flag = 1; - switch(type){ - case SC_STONE: - case SC_FREEZE: - case SC_STUN: - case SC_SLEEP: - case SC_DEEP_SLEEP: - case SC_BURNING: - case SC_WHITEIMPRISON: - case SC_COLD: - sc->opt1 = 0; - break; + switch(type) { + case SC_STONE: + case SC_FREEZE: + case SC_STUN: + case SC_SLEEP: + case SC_BURNING: + case SC_WHITEIMPRISON: + case SC_COLD: + sc->opt1 = 0; + break; - case SC_POISON: - case SC_CURSE: - case SC_SILENCE: - case SC_BLIND: - sc->opt2 &= ~(1<<(type-SC_POISON)); - break; - case SC_DPOISON: - sc->opt2 &= ~OPT2_DPOISON; - break; - case SC_CRUCIS: - sc->opt2 &= ~OPT2_SIGNUMCRUCIS; - break; + case SC_POISON: + case SC_CURSE: + case SC_SILENCE: + case SC_BLIND: + sc->opt2 &= ~(1<<(type-SC_POISON)); + break; + case SC_DPOISON: + sc->opt2 &= ~OPT2_DPOISON; + break; + case SC_CRUCIS: + case SC__CHAOS: + sc->opt2 &= ~OPT2_SIGNUMCRUCIS; + break; - case SC_HIDING: - sc->option &= ~OPTION_HIDE; - opt_flag|= 2|4; //Check for warp trigger + AoE trigger - break; - case SC_CLOAKING: - case SC_CLOAKINGEXCEED: - case SC__INVISIBILITY: - sc->option &= ~OPTION_CLOAK; - case SC_CAMOUFLAGE: - opt_flag|= 2; - break; - case SC_CHASEWALK: - sc->option &= ~(OPTION_CHASEWALK|OPTION_CLOAK); - opt_flag|= 2; - break; - case SC_SIGHT: - sc->option &= ~OPTION_SIGHT; - break; - case SC_WEDDING: - sc->option &= ~OPTION_WEDDING; - opt_flag |= 0x4; - break; - case SC_XMAS: - sc->option &= ~OPTION_XMAS; - opt_flag |= 0x4; - break; - case SC_SUMMER: - sc->option &= ~OPTION_SUMMER; - opt_flag |= 0x4; - break; - case SC_HANBOK: - sc->option &= ~OPTION_HANBOK; - opt_flag |= 0x4; - break; - case SC_ORCISH: - sc->option &= ~OPTION_ORCISH; - break; - case SC_RUWACH: - sc->option &= ~OPTION_RUWACH; - break; - case SC_FUSION: - sc->option &= ~OPTION_FLYING; - break; - //opt3 - case SC_TWOHANDQUICKEN: - case SC_ONEHANDQUICKEN: - case SC_SPEARQUICKEN: - case SC_CONCENTRATION: - case SC_MER_QUICKEN: - sc->opt3 &= ~OPT3_QUICKEN; - opt_flag = 0; - break; - case SC_OVERTHRUST: - case SC_OVERTHRUSTMAX: - case SC_SWOO: - sc->opt3 &= ~OPT3_OVERTHRUST; - if( type == SC_SWOO ) - opt_flag = 8; - else + case SC_HIDING: + sc->option &= ~OPTION_HIDE; + opt_flag|= 2|4; //Check for warp trigger + AoE trigger + break; + case SC_CLOAKING: + case SC_CLOAKINGEXCEED: + sc->option &= ~OPTION_CLOAK; + case SC_CAMOUFLAGE: + opt_flag|= 2; + break; + case SC__INVISIBILITY: + case SC_CHASEWALK: + sc->option &= ~(OPTION_CHASEWALK|OPTION_CLOAK); + opt_flag|= 2; + break; + case SC_SIGHT: + sc->option &= ~OPTION_SIGHT; + break; + case SC_WEDDING: + sc->option &= ~OPTION_WEDDING; + opt_flag |= 0x4; + break; + case SC_XMAS: + sc->option &= ~OPTION_XMAS; + opt_flag |= 0x4; + break; + case SC_SUMMER: + sc->option &= ~OPTION_SUMMER; + opt_flag |= 0x4; + break; + case SC_HANBOK: + sc->option &= ~OPTION_HANBOK; + opt_flag |= 0x4; + break; + case SC_OKTOBERFEST: + sc->option &= ~OPTION_OKTOBERFEST; + opt_flag |= 0x4; + break; + case SC_ORCISH: + sc->option &= ~OPTION_ORCISH; + break; + case SC_RUWACH: + sc->option &= ~OPTION_RUWACH; + break; + case SC_FUSION: + sc->option &= ~OPTION_FLYING; + break; + //opt3 + case SC_TWOHANDQUICKEN: + case SC_ONEHANDQUICKEN: + case SC_SPEARQUICKEN: + case SC_CONCENTRATION: + case SC_MER_QUICKEN: + sc->opt3 &= ~OPT3_QUICKEN; opt_flag = 0; - break; - case SC_ENERGYCOAT: - case SC_SKE: - sc->opt3 &= ~OPT3_ENERGYCOAT; - opt_flag = 0; - break; - case SC_INCATKRATE: //Simulated Explosion spirits effect. - if (bl->type != BL_MOB) - { + break; + case SC_OVERTHRUST: + case SC_OVERTHRUSTMAX: + case SC_SWOO: + sc->opt3 &= ~OPT3_OVERTHRUST; + if( type == SC_SWOO ) + opt_flag = 8; + else + opt_flag = 0; + break; + case SC_ENERGYCOAT: + case SC_SKE: + sc->opt3 &= ~OPT3_ENERGYCOAT; opt_flag = 0; break; - } - case SC_EXPLOSIONSPIRITS: - sc->opt3 &= ~OPT3_EXPLOSIONSPIRITS; - opt_flag = 0; - break; - case SC_STEELBODY: - case SC_SKA: - sc->opt3 &= ~OPT3_STEELBODY; - opt_flag = 0; - break; - case SC_BLADESTOP: - sc->opt3 &= ~OPT3_BLADESTOP; - opt_flag = 0; - break; - case SC_AURABLADE: - sc->opt3 &= ~OPT3_AURABLADE; - opt_flag = 0; - break; - case SC_BERSERK: - opt_flag = 0; - sc->opt3 &= ~OPT3_BERSERK; - break; - // case ???: // doesn't seem to do anything - // sc->opt3 &= ~OPT3_LIGHTBLADE; - // opt_flag = 0; - // break; - case SC_DANCING: - if ((sce->val1&0xFFFF) == CG_MOONLIT) - sc->opt3 &= ~OPT3_MOONLIT; - opt_flag = 0; - break; - case SC_MARIONETTE: - case SC_MARIONETTE_MASTER: - sc->opt3 &= ~OPT3_MARIONETTE; - opt_flag = 0; - break; - case SC_ASSUMPTIO: - sc->opt3 &= ~OPT3_ASSUMPTIO; - opt_flag = 0; - break; - case SC_WARM: //SG skills [Komurka] - sc->opt3 &= ~OPT3_WARM; - opt_flag = 0; - break; - case SC_KAITE: - sc->opt3 &= ~OPT3_KAITE; - opt_flag = 0; - break; - case SC_NJ_BUNSINJYUTSU: - sc->opt3 &= ~OPT3_BUNSIN; - opt_flag = 0; - break; - case SC_SOULLINK: - sc->opt3 &= ~OPT3_SOULLINK; - opt_flag = 0; - break; - case SC_PROPERTYUNDEAD: - sc->opt3 &= ~OPT3_UNDEAD; - opt_flag = 0; - break; - // case ???: // from DA_CONTRACT (looks like biolab mobs aura) - // sc->opt3 &= ~OPT3_CONTRACT; - // opt_flag = 0; - // break; - default: - opt_flag = 0; + case SC_INCATKRATE: //Simulated Explosion spirits effect. + if (bl->type != BL_MOB) + { + opt_flag = 0; + break; + } + case SC_EXPLOSIONSPIRITS: + sc->opt3 &= ~OPT3_EXPLOSIONSPIRITS; + opt_flag = 0; + break; + case SC_STEELBODY: + case SC_SKA: + sc->opt3 &= ~OPT3_STEELBODY; + opt_flag = 0; + break; + case SC_BLADESTOP: + sc->opt3 &= ~OPT3_BLADESTOP; + opt_flag = 0; + break; + case SC_AURABLADE: + sc->opt3 &= ~OPT3_AURABLADE; + opt_flag = 0; + break; + case SC_BERSERK: + opt_flag = 0; + sc->opt3 &= ~OPT3_BERSERK; + break; + // case ???: // doesn't seem to do anything + // sc->opt3 &= ~OPT3_LIGHTBLADE; + // opt_flag = 0; + // break; + case SC_DANCING: + if ((sce->val1&0xFFFF) == CG_MOONLIT) + sc->opt3 &= ~OPT3_MOONLIT; + opt_flag = 0; + break; + case SC_MARIONETTE: + case SC_MARIONETTE_MASTER: + sc->opt3 &= ~OPT3_MARIONETTE; + opt_flag = 0; + break; + case SC_ASSUMPTIO: + sc->opt3 &= ~OPT3_ASSUMPTIO; + opt_flag = 0; + break; + case SC_WARM: //SG skills [Komurka] + sc->opt3 &= ~OPT3_WARM; + opt_flag = 0; + break; + case SC_KAITE: + sc->opt3 &= ~OPT3_KAITE; + opt_flag = 0; + break; + case SC_NJ_BUNSINJYUTSU: + sc->opt3 &= ~OPT3_BUNSIN; + opt_flag = 0; + break; + case SC_SOULLINK: + sc->opt3 &= ~OPT3_SOULLINK; + opt_flag = 0; + break; + case SC_PROPERTYUNDEAD: + sc->opt3 &= ~OPT3_UNDEAD; + opt_flag = 0; + break; + // case ???: // from DA_CONTRACT (looks like biolab mobs aura) + // sc->opt3 &= ~OPT3_CONTRACT; + // opt_flag = 0; + // break; + default: + opt_flag = 0; + } + +#ifdef ANTI_MAYAP_CHEAT + if (invisible && !(sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE))) { + clif->fixpos(bl); } +#endif if (calc_flag&SCB_DYE) { //Restore DYE color if (vd && !vd->cloth_color && sce->val4) @@ -9832,7 +10277,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const else if(opt_flag) { clif->changeoption(bl); if( sd && opt_flag&0x4 ) { - clif->changelook(bl,LOOK_BASE,vd->class_); + clif->changelook(bl,LOOK_BASE,sd->vd.class_); clif->get_weapon_view(sd, &sd->vd.weapon, &sd->vd.shield); clif->changelook(bl,LOOK_WEAPON,sd->vd.weapon); clif->changelook(bl,LOOK_SHIELD,sd->vd.shield); @@ -9853,7 +10298,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const return 1; } -int kaahi_heal_timer(int tid, unsigned int tick, int id, intptr_t data) { +int kaahi_heal_timer(int tid, int64 tick, int id, intptr_t data) { struct block_list *bl; struct status_change *sc; struct status_change_entry *sce; @@ -9891,7 +10336,7 @@ int kaahi_heal_timer(int tid, unsigned int tick, int id, intptr_t data) { * For recusive status, like for each 5s we drop sp etc. * Reseting the end timer. *------------------------------------------*/ -int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) { +int status_change_timer(int tid, int64 tick, int id, intptr_t data) { enum sc_type type = (sc_type)data; struct block_list *bl; struct map_session_data *sd; @@ -9924,773 +10369,794 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) { // set the next timer of the sce (don't assume the status still exists) #define sc_timer_next(t,f,i,d) do { \ if( (sce=sc->data[type]) ) \ - sce->timer = timer->add(t,f,i,d); \ + sce->timer = timer->add((t),(f),(i),(d)); \ else \ ShowError("status_change_timer: Unexpected NULL status change id: %d data: %d\n", id, data); \ } while(0) switch(type) { - case SC_MAXIMIZEPOWER: - case SC_CLOAKING: - if(!status->charge(bl, 0, 1)) - break; //Not enough SP to continue. - sc_timer_next(sce->val2+tick, status->change_timer, bl->id, data); - return 0; - - case SC_CHASEWALK: - if(!status->charge(bl, 0, sce->val4)) - break; //Not enough SP to continue. + case SC_MAXIMIZEPOWER: + case SC_CLOAKING: + if(!status->charge(bl, 0, 1)) + break; //Not enough SP to continue. + sc_timer_next(sce->val2+tick, status->change_timer, bl->id, data); + return 0; - if (!sc->data[SC_CHASEWALK2]) { - sc_start(bl, SC_CHASEWALK2,100,1<<(sce->val1-1), - (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE?10:1) //SL bonus -> x10 duration - * skill->get_time2(status->sc2skill(type),sce->val1)); - } - sc_timer_next(sce->val2+tick, status->change_timer, bl->id, data); - return 0; - break; + case SC_CHASEWALK: + if(!status->charge(bl, 0, sce->val4)) + break; //Not enough SP to continue. - case SC_SKA: - if(--(sce->val2)>0) { - sce->val3 = rnd()%100; //Random defense. - sc_timer_next(1000+tick, status->change_timer,bl->id, data); + if (!sc->data[SC_CHASEWALK2]) { + sc_start(bl,bl, SC_CHASEWALK2,100,1<<(sce->val1-1), + (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE?10:1) //SL bonus -> x10 duration + * skill->get_time2(status->sc2skill(type),sce->val1)); + } + sc_timer_next(sce->val2+tick, status->change_timer, bl->id, data); return 0; - } - break; + break; - case SC_HIDING: - if(--(sce->val2)>0) { - if(sce->val2 % sce->val4 == 0 && !status->charge(bl, 0, 1)) - break; //Fail if it's time to substract SP and there isn't. + case SC_SKA: + if(--(sce->val2)>0) { + sce->val3 = rnd()%100; //Random defense. + sc_timer_next(1000+tick, status->change_timer,bl->id, data); + return 0; + } + break; - sc_timer_next(1000+tick, status->change_timer,bl->id, data); - return 0; - } - break; + case SC_HIDING: + if(--(sce->val2)>0) { + if(sce->val2 % sce->val4 == 0 && !status->charge(bl, 0, 1)) + break; //Fail if it's time to substract SP and there isn't. - case SC_SIGHT: - case SC_RUWACH: - case SC_WZ_SIGHTBLASTER: - if(type == SC_WZ_SIGHTBLASTER) - map->foreachinrange(status->change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick); - else - map->foreachinrange(status->change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick); + sc_timer_next(1000+tick, status->change_timer,bl->id, data); + return 0; + } + break; - if( --(sce->val2)>0 ){ - sce->val4 += 250; // use for Shadow Form 2 seconds checking. - sc_timer_next(250+tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_SIGHT: + case SC_RUWACH: + case SC_WZ_SIGHTBLASTER: + if(type == SC_WZ_SIGHTBLASTER) + map->foreachinrange(status->change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick); + else + map->foreachinrange(status->change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick); - case SC_PROVOKE: - if(sce->val2) { //Auto-provoke (it is ended in status->heal) - sc_timer_next(1000*60+tick, status->change_timer, bl->id, data ); - return 0; - } - break; + if( --(sce->val2)>0 ){ + sce->val4 += 250; // use for Shadow Form 2 seconds checking. + sc_timer_next(250+tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_STONE: - if(sc->opt1 == OPT1_STONEWAIT && sce->val3) { - sce->val4 = 0; - unit->stop_walking(bl,1); - unit->stop_attack(bl); - sc->opt1 = OPT1_STONE; - clif->changeoption(bl); - sc_timer_next(1000+tick, status->change_timer, bl->id, data ); - status_calc_bl(bl, status->ChangeFlagTable[type]); - return 0; - } - if(--(sce->val3) > 0) { - if(++(sce->val4)%5 == 0 && st->hp > st->max_hp/4) - status_percent_damage(NULL, bl, 1, 0, false); - sc_timer_next(1000+tick, status->change_timer, bl->id, data ); - return 0; - } - break; + case SC_PROVOKE: + if(sce->val2) { //Auto-provoke (it is ended in status->heal) + sc_timer_next(1000*60+tick, status->change_timer, bl->id, data ); + return 0; + } + break; - case SC_POISON: - if(st->hp <= max(st->max_hp>>2, sce->val4)) //Stop damaging after 25% HP left. + case SC_STONE: + if(sc->opt1 == OPT1_STONEWAIT && sce->val3) { + sce->val4 = 0; + unit->stop_walking(bl,1); + unit->stop_attack(bl); + sc->opt1 = OPT1_STONE; + clif->changeoption(bl); + sc_timer_next(1000+tick, status->change_timer, bl->id, data ); + status_calc_bl(bl, status->ChangeFlagTable[type]); + return 0; + } + if(--(sce->val3) > 0) { + if(++(sce->val4)%5 == 0 && st->hp > st->max_hp/4) + status_percent_damage(NULL, bl, 1, 0, false); + sc_timer_next(1000+tick, status->change_timer, bl->id, data ); + return 0; + } break; - case SC_DPOISON: - if (--(sce->val3) > 0) { - if (!sc->data[SC_SLOWPOISON]) { - if( sce->val2 && bl->type == BL_MOB ) { - struct block_list* src = map->id2bl(sce->val2); - if( src ) - mob->log_damage((TBL_MOB*)bl,src,sce->val4); + + case SC_POISON: + if(st->hp <= max(st->max_hp>>2, sce->val4)) //Stop damaging after 25% HP left. + break; + case SC_DPOISON: + if (--(sce->val3) > 0) { + if (!sc->data[SC_SLOWPOISON]) { + if( sce->val2 && bl->type == BL_MOB ) { + struct block_list* src = map->id2bl(sce->val2); + if( src ) + mob->log_damage((TBL_MOB*)bl,src,sce->val4); + } + map->freeblock_lock(); + status_zap(bl, sce->val4, 0); + if (sc->data[type]) { // Check if the status still last ( can be dead since then ). + sc_timer_next(1000 + tick, status->change_timer, bl->id, data ); + } + map->freeblock_unlock(); + } + return 0; + } + break; + + case SC_TENSIONRELAX: + if(st->max_hp > st->hp && --(sce->val3) > 0) { + sc_timer_next(sce->val4+tick, status->change_timer, bl->id, data); + return 0; + } + break; + + case SC_KNOWLEDGE: + if (!sd) break; + if(bl->m == sd->feel_map[0].m || + bl->m == sd->feel_map[1].m || + bl->m == sd->feel_map[2].m) + { //Timeout will be handled by pc->setpos + sce->timer = INVALID_TIMER; + return 0; + } + break; + + case SC_BLOODING: + if (--(sce->val4) >= 0) { + int hp = rnd()%600 + 200; + struct block_list* src = map->id2bl(sce->val2); + if( src && bl && bl->type == BL_MOB ) { + mob->log_damage((TBL_MOB*)bl,src,sd||hp<st->hp?hp:st->hp-1); } map->freeblock_lock(); - status_zap(bl, sce->val4, 0); - if (sc->data[type]) { // Check if the status still last ( can be dead since then ). - sc_timer_next(1000 + tick, status->change_timer, bl->id, data ); + status_fix_damage(src, bl, sd||hp<st->hp?hp:st->hp-1, 1); + if( sc->data[type] ) { + if( st->hp == 1 ) { + map->freeblock_unlock(); + break; + } + sc_timer_next(10000 + tick, status->change_timer, bl->id, data); } map->freeblock_unlock(); + return 0; } - return 0; - } - break; + break; - case SC_TENSIONRELAX: - if(st->max_hp > st->hp && --(sce->val3) > 0) { - sc_timer_next(sce->val4+tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_S_LIFEPOTION: + case SC_L_LIFEPOTION: + if( sd && --(sce->val4) >= 0 ) { + // val1 < 0 = per max% | val1 > 0 = exact amount + int hp = 0; + if( st->hp < st->max_hp ) + hp = (sce->val1 < 0) ? (int)(sd->status.max_hp * -1 * sce->val1 / 100.) : sce->val1 ; + status->heal(bl, hp, 0, 2); + sc_timer_next((sce->val2 * 1000) + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_KNOWLEDGE: - if (!sd) break; - if(bl->m == sd->feel_map[0].m || - bl->m == sd->feel_map[1].m || - bl->m == sd->feel_map[2].m) - { //Timeout will be handled by pc->setpos - sce->timer = INVALID_TIMER; - return 0; - } - break; + case SC_CASH_BOSS_ALARM: + if( sd && --(sce->val4) >= 0 ) { + struct mob_data *boss_md = map->id2boss(sce->val1); + if( boss_md && sd->bl.m == boss_md->bl.m ) { + clif->bossmapinfo(sd->fd, boss_md, 1); // Update X - Y on minimap + if (boss_md->bl.prev != NULL) { + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } + } + } + break; - case SC_BLOODING: - if (--(sce->val4) >= 0) { - int hp = rnd()%600 + 200; - struct block_list* src = map->id2bl(sce->val2); - if( src && bl && bl->type == BL_MOB ) { - mob->log_damage((TBL_MOB*)bl,src,sd||hp<st->hp?hp:st->hp-1); - } - map->freeblock_lock(); - status_fix_damage(src, bl, sd||hp<st->hp?hp:st->hp-1, 1); - if( sc->data[type] ) { - if( st->hp == 1 ) { - map->freeblock_unlock(); + case SC_DANCING: //SP consumption by time of dancing skills + { + int s = 0; + int sp = 1; + if (--sce->val3 <= 0) + break; + switch(sce->val1&0xFFFF){ + case BD_RICHMANKIM: + case BD_DRUMBATTLEFIELD: + case BD_RINGNIBELUNGEN: + case BD_SIEGFRIED: + case BA_DISSONANCE: + case BA_ASSASSINCROSS: + case DC_UGLYDANCE: + s=3; + break; + case BD_LULLABY: + case BD_ETERNALCHAOS: + case BD_ROKISWEIL: + case DC_FORTUNEKISS: + s=4; + break; + case CG_HERMODE: + case BD_INTOABYSS: + case BA_WHISTLE: + case DC_HUMMING: + case BA_POEMBRAGI: + case DC_SERVICEFORYOU: + s=5; + break; + case BA_APPLEIDUN: + #ifdef RENEWAL + s=5; + #else + s=6; + #endif + break; + case CG_MOONLIT: + //Moonlit's cost is 4sp*skill_lv [Skotlex] + sp= 4*(sce->val1>>16); + //Upkeep is also every 10 secs. + case DC_DONTFORGETME: + s=10; break; } - sc_timer_next(10000 + tick, status->change_timer, bl->id, data); + if( s != 0 && sce->val3 % s == 0 ) { + if (sc->data[SC_LONGING]) + sp*= 3; + if (!status->charge(bl, 0, sp)) + break; + } + sc_timer_next(1000+tick, status->change_timer, bl->id, data); + return 0; } - map->freeblock_unlock(); - return 0; - } - break; - - case SC_S_LIFEPOTION: - case SC_L_LIFEPOTION: - if( sd && --(sce->val4) >= 0 ) { - // val1 < 0 = per max% | val1 > 0 = exact amount - int hp = 0; - if( st->hp < st->max_hp ) - hp = (sce->val1 < 0) ? (int)(sd->status.max_hp * -1 * sce->val1 / 100.) : sce->val1 ; - status->heal(bl, hp, 0, 2); - sc_timer_next((sce->val2 * 1000) + tick, status->change_timer, bl->id, data); - return 0; - } - break; + break; + case SC_BERSERK: + // 5% every 10 seconds [DracoRPG] + if( --( sce->val3 ) > 0 && status->charge(bl, sce->val2, 0) && st->hp > 100 ) { + sc_timer_next(sce->val4+tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_CASH_BOSS_ALARM: - if( sd && --(sce->val4) >= 0 ) { - struct mob_data *boss_md = map->id2boss(sce->val1); - if( boss_md && sd->bl.m == boss_md->bl.m ) { - clif->bossmapinfo(sd->fd, boss_md, 1); // Update X - Y on minimap - if (boss_md->bl.prev != NULL) { - sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + case SC_NOCHAT: + if(sd) { + sd->status.manner++; + clif->changestatus(sd,SP_MANNER,sd->status.manner); + clif->updatestatus(sd,SP_MANNER); + if (sd->status.manner < 0) { + //Every 60 seconds your manner goes up by 1 until it gets back to 0. + sc_timer_next(60000+tick, status->change_timer, bl->id, data); return 0; } } - } - break; + break; - case SC_DANCING: //SP consumption by time of dancing skills - { - int s = 0; - int sp = 1; - if (--sce->val3 <= 0) - break; - switch(sce->val1&0xFFFF){ - case BD_RICHMANKIM: - case BD_DRUMBATTLEFIELD: - case BD_RINGNIBELUNGEN: - case BD_SIEGFRIED: - case BA_DISSONANCE: - case BA_ASSASSINCROSS: - case DC_UGLYDANCE: - s=3; - break; - case BD_LULLABY: - case BD_ETERNALCHAOS: - case BD_ROKISWEIL: - case DC_FORTUNEKISS: - s=4; - break; - case CG_HERMODE: - case BD_INTOABYSS: - case BA_WHISTLE: - case DC_HUMMING: - case BA_POEMBRAGI: - case DC_SERVICEFORYOU: - s=5; - break; - case BA_APPLEIDUN: -#ifdef RENEWAL - s=5; -#else - s=6; -#endif - break; - case CG_MOONLIT: - //Moonlit's cost is 4sp*skill_lv [Skotlex] - sp= 4*(sce->val1>>16); - //Upkeep is also every 10 secs. - case DC_DONTFORGETME: - s=10; - break; + case SC_SPLASHER: + // custom Venom Splasher countdown timer + //if (sce->val4 % 1000 == 0) { + // char counter[10]; + // snprintf (counter, 10, "%d", sce->val4/1000); + // clif->message(bl, counter); + //} + if((sce->val4 -= 500) > 0) { + sc_timer_next(500 + tick, status->change_timer, bl->id, data); + return 0; } - if( s != 0 && sce->val3 % s == 0 ) { - if (sc->data[SC_LONGING]) - sp*= 3; - if (!status->charge(bl, 0, sp)) - break; + break; + + case SC_MARIONETTE_MASTER: + case SC_MARIONETTE: + { + struct block_list *pbl = map->id2bl(sce->val1); + if( pbl && check_distance_bl(bl, pbl, 7) ) { + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } } - sc_timer_next(1000+tick, status->change_timer, bl->id, data); - return 0; - } - break; - case SC_BERSERK: - // 5% every 10 seconds [DracoRPG] - if( --( sce->val3 ) > 0 && status->charge(bl, sce->val2, 0) && st->hp > 100 ) { - sc_timer_next(sce->val4+tick, status->change_timer, bl->id, data); - return 0; - } - break; + break; - case SC_NOCHAT: - if(sd) { - sd->status.manner++; - clif->changestatus(sd,SP_MANNER,sd->status.manner); - clif->updatestatus(sd,SP_MANNER); - if (sd->status.manner < 0) { - //Every 60 seconds your manner goes up by 1 until it gets back to 0. - sc_timer_next(60000+tick, status->change_timer, bl->id, data); + case SC_GOSPEL: + if(sce->val4 == BCT_SELF && --(sce->val2) > 0) { + int hp, sp; + hp = (sce->val1 > 5) ? 45 : 30; + sp = (sce->val1 > 5) ? 35 : 20; + if(!status->charge(bl, hp, sp)) + break; + sc_timer_next(10000+tick, status->change_timer, bl->id, data); return 0; } - } - break; - - case SC_SPLASHER: - // custom Venom Splasher countdown timer - //if (sce->val4 % 1000 == 0) { - // char counter[10]; - // snprintf (counter, 10, "%d", sce->val4/1000); - // clif->message(bl, counter); - //} - if((sce->val4 -= 500) > 0) { - sc_timer_next(500 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + break; - case SC_MARIONETTE_MASTER: - case SC_MARIONETTE: - { - struct block_list *pbl = map->id2bl(sce->val1); - if( pbl && check_distance_bl(bl, pbl, 7) ) { - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + case SC_JAILED: + if(sce->val1 == INT_MAX || --(sce->val1) > 0) { + sc_timer_next(60000+tick, status->change_timer, bl->id,data); return 0; } - } - break; - - case SC_GOSPEL: - if(sce->val4 == BCT_SELF && --(sce->val2) > 0) { - int hp, sp; - hp = (sce->val1 > 5) ? 45 : 30; - sp = (sce->val1 > 5) ? 35 : 20; - if(!status->charge(bl, hp, sp)) - break; - sc_timer_next(10000+tick, status->change_timer, bl->id, data); - return 0; - } - break; - - case SC_JAILED: - if(sce->val1 == INT_MAX || --(sce->val1) > 0) { - sc_timer_next(60000+tick, status->change_timer, bl->id,data); - return 0; - } - break; - - case SC_BLIND: - if(sc->data[SC_FOGWALL]) { - //Blind lasts forever while you are standing on the fog. - sc_timer_next(5000+tick, status->change_timer, bl->id, data); - return 0; - } - break; - case SC_ABUNDANCE: - if(--(sce->val4) > 0) { - status->heal(bl,0,60,0); - sc_timer_next(10000+tick, status->change_timer, bl->id, data); - } - break; - - case SC_PYREXIA: - if( --(sce->val4) > 0 ) { - map->freeblock_lock(); - clif->damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,100,0,0,0); - status_fix_damage(NULL,bl,100,0); - if( sc->data[type] ) { - sc_timer_next(3000+tick,status->change_timer,bl->id,data); - } - map->freeblock_unlock(); - return 0; - } - break; + break; - case SC_LEECHESEND: - if( --(sce->val4) > 0 ) { - int damage = st->max_hp/100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100) - damage += st->vit * (sce->val1 - 3); - unit->skillcastcancel(bl,2); - map->freeblock_lock(); - status->damage(bl, bl, damage, 0, clif->damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,damage,1,0,0), 1); - if( sc->data[type] ) { - sc_timer_next(1000 + tick, status->change_timer, bl->id, data ); - } - map->freeblock_unlock(); - return 0; - } - break; + case SC_BLIND: + if(sc->data[SC_FOGWALL]) { + //Blind lasts forever while you are standing on the fog. + sc_timer_next(5000+tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_ABUNDANCE: + if(--(sce->val4) > 0) { + status->heal(bl,0,60,0); + sc_timer_next(10000+tick, status->change_timer, bl->id, data); + } + break; - case SC_MAGICMUSHROOM: - if( --(sce->val4) > 0 ) { - bool flag = 0; - int damage = st->max_hp * 3 / 100; - if( st->hp <= damage ) - damage = st->hp - 1; // Cannot Kill + case SC_PYREXIA: + if( --(sce->val4) > 0 ) { + map->freeblock_lock(); + clif->damage(bl,bl,status_get_amotion(bl),status_get_dmotion(bl)+500,100,0,0,0); + status_fix_damage(NULL,bl,100,0); + if( sc->data[type] ) { + sc_timer_next(3000+tick,status->change_timer,bl->id,data); + } + map->freeblock_unlock(); + return 0; + } + break; - if( damage > 0 ) { // 3% Damage each 4 seconds + case SC_LEECHESEND: + if( --(sce->val4) > 0 ) { + int damage = st->max_hp/100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100) + damage += st->vit * (sce->val1 - 3); + unit->skillcastcancel(bl,2); map->freeblock_lock(); - status_zap(bl,damage,0); - flag = !sc->data[type]; // Killed? Should not + status->damage(bl, bl, damage, 0, clif->damage(bl,bl,status_get_amotion(bl),status_get_dmotion(bl)+500,damage,1,0,0), 1); + if( sc->data[type] ) { + sc_timer_next(1000 + tick, status->change_timer, bl->id, data ); + } map->freeblock_unlock(); + return 0; } + break; - if( !flag ) { // Random Skill Cast - if (sd && !pc_issit(sd)) { //can't cast if sit - int mushroom_skill_id = 0, i; - unit->stop_attack(bl); - unit->skillcastcancel(bl,1); - do { - i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB; - mushroom_skill_id = skill->magicmushroom_db[i].skill_id; - } - while( mushroom_skill_id == 0 ); + case SC_MAGICMUSHROOM: + if( --(sce->val4) > 0 ) { + bool flag = 0; + int damage = st->max_hp * 3 / 100; + if( st->hp <= damage ) + damage = st->hp - 1; // Cannot Kill + + if( damage > 0 ) { // 3% Damage each 4 seconds + map->freeblock_lock(); + status_zap(bl,damage,0); + flag = !sc->data[type]; // Killed? Should not + map->freeblock_unlock(); + } - switch( skill->get_casttype(mushroom_skill_id) ) { // Magic Mushroom skills are buffs or area damage - case CAST_GROUND: - skill->castend_pos2(bl,bl->x,bl->y,mushroom_skill_id,1,tick,0); - break; - case CAST_NODAMAGE: - skill->castend_nodamage_id(bl,bl,mushroom_skill_id,1,tick,0); - break; - case CAST_DAMAGE: - skill->castend_damage_id(bl,bl,mushroom_skill_id,1,tick,0); - break; + if( !flag ) { // Random Skill Cast + if (sd && !pc_issit(sd)) { //can't cast if sit + int mushroom_skill_id = 0, i; + unit->stop_attack(bl); + unit->skillcastcancel(bl,0); + do { + i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB; + mushroom_skill_id = skill->magicmushroom_db[i].skill_id; + } + while( mushroom_skill_id == 0 ); + + switch( skill->get_casttype(mushroom_skill_id) ) { // Magic Mushroom skills are buffs or area damage + case CAST_GROUND: + skill->castend_pos2(bl,bl->x,bl->y,mushroom_skill_id,1,tick,0); + break; + case CAST_NODAMAGE: + skill->castend_nodamage_id(bl,bl,mushroom_skill_id,1,tick,0); + break; + case CAST_DAMAGE: + skill->castend_damage_id(bl,bl,mushroom_skill_id,1,tick,0); + break; + } } + + clif->emotion(bl,E_HEH); + sc_timer_next(4000+tick,status->change_timer,bl->id,data); } + return 0; + } + break; - clif->emotion(bl,E_HEH); - sc_timer_next(4000+tick,status->change_timer,bl->id,data); + case SC_TOXIN: + if( --(sce->val4) > 0 ) { + //Damage is every 10 seconds including 3%sp drain. + map->freeblock_lock(); + clif->damage(bl,bl,status_get_amotion(bl),1,1,0,0,0); + status->damage(NULL, bl, 1, st->max_sp * 3 / 100, 0, 0); //cancel dmg only if cancelable + if( sc->data[type] ) { + sc_timer_next(10000 + tick, status->change_timer, bl->id, data ); + } + map->freeblock_unlock(); + return 0; } - return 0; - } - break; + break; - case SC_TOXIN: - if( --(sce->val4) > 0 ) { - //Damage is every 10 seconds including 3%sp drain. - map->freeblock_lock(); - clif->damage(bl,bl,tick,status_get_amotion(bl),1,1,0,0,0); - status->damage(NULL, bl, 1, st->max_sp * 3 / 100, 0, 0); //cancel dmg only if cancelable - if( sc->data[type] ) { - sc_timer_next(10000 + tick, status->change_timer, bl->id, data ); - } - map->freeblock_unlock(); - return 0; - } - break; + case SC_OBLIVIONCURSE: + if( --(sce->val4) > 0 ) { + clif->emotion(bl,E_WHAT); + sc_timer_next(3000 + tick, status->change_timer, bl->id, data ); + return 0; + } + break; - case SC_OBLIVIONCURSE: - if( --(sce->val4) > 0 ) { - clif->emotion(bl,E_WHAT); - sc_timer_next(3000 + tick, status->change_timer, bl->id, data ); - return 0; - } - break; + case SC_WEAPONBLOCKING: + if( --(sce->val4) > 0 ) { + if( !status->charge(bl,0,3) ) + break; + sc_timer_next(5000+tick,status->change_timer,bl->id,data); + return 0; + } + break; - case SC_WEAPONBLOCKING: - if( --(sce->val4) > 0 ) { - if( !status->charge(bl,0,3) ) + case SC_CLOAKINGEXCEED: + if(!status->charge(bl,0,10-sce->val1)) break; - sc_timer_next(3000+tick,status->change_timer,bl->id,data); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); return 0; - } - break; - case SC_CLOAKINGEXCEED: - if(!status->charge(bl,0,10-sce->val1)) + case SC_RENOVATIO: + if( --(sce->val4) > 0 ) { + int heal = st->max_hp * 3 / 100; + if( sc && sc->data[SC_AKAITSUKI] && heal ) + heal = ~heal + 1; + status->heal(bl, heal, 0, 2); + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } break; - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - case SC_RENOVATIO: - if( --(sce->val4) > 0 ) { - int heal = st->max_hp * 3 / 100; - if( sc && sc->data[SC_AKAITSUKI] && heal ) - heal = ~heal + 1; - status->heal(bl, heal, 0, 2); - sc_timer_next(5000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_BURNING: + if( --(sce->val4) > 0 ) { + struct block_list *src = map->id2bl(sce->val3); + int damage = 1000 + 3 * status_get_max_hp(bl) / 100; // Deals fixed (1000 + 3%*MaxHP) - case SC_BURNING: - if( --(sce->val4) > 0 ) { - struct block_list *src = map->id2bl(sce->val3); - int damage = 1000 + 3 * status_get_max_hp(bl) / 100; // Deals fixed (1000 + 3%*MaxHP) + map->freeblock_lock(); + clif->damage(bl,bl,0,0,damage,1,9,0); //damage is like endure effect with no walk delay + status->damage(src, bl, damage, 0, 0, 1); - map->freeblock_lock(); - clif->damage(bl,bl,tick,0,0,damage,1,9,0); //damage is like endure effect with no walk delay - status->damage(src, bl, damage, 0, 0, 1); + if( sc->data[type]){ // Target still lives. [LimitLine] + sc_timer_next(3000 + tick, status->change_timer, bl->id, data); + } + map->freeblock_unlock(); + return 0; + } + break; - if( sc->data[type]){ // Target still lives. [LimitLine] - sc_timer_next(3000 + tick, status->change_timer, bl->id, data); + case SC_FEAR: + if( --(sce->val4) > 0 ) { + if( sce->val2 > 0 ) + sce->val2--; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; } - map->freeblock_unlock(); - return 0; - } - break; + break; - case SC_FEAR: - if( --(sce->val4) > 0 ) { - if( sce->val2 > 0 ) - sce->val2--; - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_SUMMON1: + case SC_SUMMON2: + case SC_SUMMON3: + case SC_SUMMON4: + case SC_SUMMON5: + if( --(sce->val4) > 0 ) { + if( !status->charge(bl, 0, 1) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_SUMMON1: - case SC_SUMMON2: - case SC_SUMMON3: - case SC_SUMMON4: - case SC_SUMMON5: - if( --(sce->val4) > 0 ) { - if( !status->charge(bl, 0, 1) ) + case SC_READING_SB: + if( !status->charge(bl, 0, sce->val2) ) { + int i; + for(i = SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) // Also remove stored spell as well. + status_change_end(bl, (sc_type)i, INVALID_TIMER); break; - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + } + sc_timer_next(10000 + tick, status->change_timer, bl->id, data); return 0; - } - break; - case SC_READING_SB: - if( !status->charge(bl, 0, sce->val2) ) { - int i; - for(i = SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) // Also remove stored spell as well. - status_change_end(bl, (sc_type)i, INVALID_TIMER); + case SC_ELECTRICSHOCKER: + if( --(sce->val4) > 0 ) { + status->charge(bl, 0, st->max_sp / 100 * sce->val1 ); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } break; - } - sc_timer_next(5000 + tick, status->change_timer, bl->id, data); - return 0; - case SC_ELECTRICSHOCKER: - if( --(sce->val4) > 0 ) { - status->charge(bl, 0, st->max_sp / 100 * sce->val1 ); - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; - - case SC_CAMOUFLAGE: - if(--(sce->val4) > 0) { - status->charge(bl,0,7 - sce->val1); - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_CAMOUFLAGE: + if(--(sce->val4) > 0) { + status->charge(bl,0,7 - sce->val1); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC__REPRODUCE: - if(!status->charge(bl, 0, 1)) + case SC__REPRODUCE: + if( --(sce->val4) >= 0 ) { + if( !status_charge(bl, 0, 9 - (1 + sce->val1) / 2) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } break; - sc_timer_next(1000+tick, status->change_timer, bl->id, data); - return 0; - case SC__SHADOWFORM: - if( --(sce->val4) > 0 ) { - if( !status->charge(bl, 0, sce->val1 - (sce->val1 - 1)) ) - break; - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC__SHADOWFORM: + if( --(sce->val4) > 0 ) { + if( !status->charge(bl, 0, sce->val1 - (sce->val1 - 1)) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC__INVISIBILITY: - if( --(sce->val4) > 0 ) { - if( !status->charge(bl, 0, (st->sp * 6 - sce->val1) / 100) )// 6% - skill_lv. - break; - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC__INVISIBILITY: + if( --(sce->val4) >= 0 ) { + if( !status->charge(bl, 0, status_get_max_sp(bl) * (12 - sce->val1*2) / 100) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_STRIKING: - if( --(sce->val4) > 0 ) { - if( !status->charge(bl,0, sce->val1 ) ) - break; - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; - case SC_VACUUM_EXTREME: - if( --(sce->val4) > 0 ) { - sc_timer_next(100 + tick, status->change_timer, bl->id, data); - return 0; - } - break; - case SC_BLOOD_SUCKER: - if( --(sce->val4) > 0 ) { - struct block_list *src = map->id2bl(sce->val2); - int damage; - if( !src || (src && (status->isdead(src) || src->m != bl->m || distance_bl(src, bl) >= 12)) ) - break; - map->freeblock_lock(); - damage = sce->val3; - status->damage(src, bl, damage, 0, clif->damage(bl,bl,tick,st->amotion,st->dmotion+200,damage,1,0,0), 1); - unit->skillcastcancel(bl,1); - if ( sc->data[type] ) { + case SC_STRIKING: + if( --(sce->val4) > 0 ) { + if( !status->charge(bl,0, sce->val1 ) ) + break; sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; } - map->freeblock_unlock(); - status->heal(src, damage*(5 + 5 * sce->val1)/100, 0, 0); // 5 + 5% per level - return 0; - } - break; + break; + case SC_BLOOD_SUCKER: + if( --(sce->val4) > 0 ) { + struct block_list *src = map->id2bl(sce->val2); + int damage; + if( !src || (src && (status->isdead(src) || src->m != bl->m || distance_bl(src, bl) >= 12)) ) + break; + map->freeblock_lock(); + damage = sce->val3; + status->damage(src, bl, damage, 0, clif->damage(bl,bl,st->amotion,st->dmotion+200,damage,1,0,0), 1); + unit->skillcastcancel(bl,1); + if ( sc->data[type] ) { + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + } + map->freeblock_unlock(); + status->heal(src, damage*(5 + 5 * sce->val1)/100, 0, 0); // 5 + 5% per level + return 0; + } + break; - case SC_SIREN: - if( --(sce->val4) > 0 ) { - clif->emotion(bl,E_LV); - sc_timer_next(2000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_SIREN: + if( --(sce->val4) > 0 ) { + clif->emotion(bl,E_LV); + sc_timer_next(2000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_DEEP_SLEEP: - if( --(sce->val4) > 0 ) { - // Recovers 1% HP/SP every 2 seconds. - status->heal(bl, st->max_hp / 100, st->max_sp / 100, 2); - sc_timer_next(2000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_DEEP_SLEEP: + if( --(sce->val4) >= 0 ) + {// Recovers 3% of the player's MaxHP/MaxSP every 2 seconds. + status->heal(bl, st->max_hp * 3 / 100, st->max_sp * 3 / 100, 2); + sc_timer_next(2000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_SIRCLEOFNATURE: - if( --(sce->val4) > 0 ) { - if( !status->charge(bl,0,sce->val2) ) - break; - status->heal(bl, sce->val3, 0, 1); - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_SIRCLEOFNATURE: + if( --(sce->val4) >= 0 ) { + if( !status_charge(bl,0,sce->val3) ) + break; + status->heal(bl, sce->val2, 0, 1); + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; - case SC_SONG_OF_MANA: - if( --(sce->val4) > 0 ) { - status->heal(bl,0,sce->val3,3); - sc_timer_next(3000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_SONG_OF_MANA: + if( --(sce->val4) >= 0 ) { + status->heal(bl,0,sce->val3,3); + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_SATURDAY_NIGHT_FEVER: - // 1% HP/SP drain every val4 seconds [Jobbie] - if( --(sce->val3) > 0 ) { - int hp = st->hp / 100; - int sp = st->sp / 100; - if( !status->charge(bl, hp, sp) ) + case SC_SATURDAY_NIGHT_FEVER: + if( --(sce->val3) >= 0 ) { + if( !status_charge(bl, st->max_hp * 1 / 100, st->max_sp * 1 / 100) ) break; - sc_timer_next(sce->val4+tick, status->change_timer, bl->id, data); - return 0; - } - break; - - case SC_COLD: - if( --(sce->val4) > 0 ) { - // Drains 2% of HP and 1% of SP every seconds. - if( bl->type != BL_MOB) // doesn't work on mobs - status->charge(bl, st->max_hp * 2 / 100, st->max_sp / 100); - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + sc_timer_next(3000+tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_FORCEOFVANGUARD: - if( !status->charge(bl,0,20) ) + case SC_MELODYOFSINK: + if( --(sce->val4) >= 0 ) { + status_charge(bl, 0, st->max_sp * ( 2 * sce->val1 + 2 * sce->val2 ) / 100); + sc_timer_next(1000+tick, status->change_timer, bl->id, data); + return 0; + } break; - sc_timer_next(6000 + tick, status->change_timer, bl->id, data); - return 0; - case SC_BANDING: - if( status->charge(bl, 0, 7 - sce->val1) ) { - if( sd ) pc->banding(sd, sce->val1); - sc_timer_next(5000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + case SC_COLD: + if( --(sce->val4) > 0 ) { + // Drains 2% of HP and 1% of SP every seconds. + if( bl->type != BL_MOB) // doesn't work on mobs + status->charge(bl, st->max_hp * 2 / 100, st->max_sp / 100); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_LG_REFLECTDAMAGE: - if( --(sce->val4) > 0 ) { - if( !status->charge(bl,0,sce->val3) ) + case SC_FORCEOFVANGUARD: + if( !status->charge(bl, 0, (24 - 4 * sce->val1)) ) break; sc_timer_next(10000 + tick, status->change_timer, bl->id, data); return 0; - } - break; - case SC_OVERHEAT_LIMITPOINT: - if( --(sce->val1) > 0 ) { // Cooling - sc_timer_next(30000 + tick, status->change_timer, bl->id, data); - } - break; + case SC_BANDING: + if( status->charge(bl, 0, 7 - sce->val1) ) { + if( sd ) pc->banding(sd, sce->val1); + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_OVERHEAT: - { - int damage = st->max_hp / 100; // Suggestion 1% each second - if( damage >= st->hp ) damage = st->hp - 1; // Do not kill, just keep you with 1 hp minimum - map->freeblock_lock(); - status_fix_damage(NULL,bl,damage,clif->damage(bl,bl,tick,0,0,damage,0,0,0)); - if( sc->data[type] ) { + case SC_LG_REFLECTDAMAGE: + if( --(sce->val4) >= 0 ) { + if( !status->charge(bl,0,10) ) + break; sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; } - map->freeblock_unlock(); - } - break; + break; - case SC_MAGNETICFIELD: - { - if( --(sce->val3) <= 0 ) - break; // Time out - if( sce->val2 == bl->id ) { - if( !status->charge(bl,0,14 + (3 * sce->val1)) ) - break; // No more SP status should end, and in the next second will end for the other affected players - } else { - struct block_list *src = map->id2bl(sce->val2); - struct status_change *ssc; - if( !src || (ssc = status->get_sc(src)) == NULL || !ssc->data[SC_MAGNETICFIELD] ) - break; // Source no more under Magnetic Field + case SC_OVERHEAT_LIMITPOINT: + if( --(sce->val1) > 0 ) { // Cooling + sc_timer_next(30000 + tick, status->change_timer, bl->id, data); } - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - } - break; + break; + + case SC_OVERHEAT: + { + int damage = st->max_hp / 100; // Suggestion 1% each second + if( damage >= st->hp ) damage = st->hp - 1; // Do not kill, just keep you with 1 hp minimum + map->freeblock_lock(); + status_fix_damage(NULL,bl,damage,clif->damage(bl,bl,0,0,damage,0,0,0)); + if( sc->data[type] ) { + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + } + map->freeblock_unlock(); + } + break; - case SC_INSPIRATION: - if(--(sce->val4) > 0) { - int hp = st->max_hp * (7-sce->val1) / 100; - int sp = st->max_sp * (9-sce->val1) / 100; + case SC_MAGNETICFIELD: + { + if( --(sce->val3) <= 0 ) + break; // Time out + if( sce->val2 == bl->id ) { + if( !status->charge(bl,0,50) ) + break; // No more SP status should end, and in the next second will end for the other affected players + } else { + struct block_list *src = map->id2bl(sce->val2); + struct status_change *ssc; + if( !src || (ssc = status->get_sc(src)) == NULL || !ssc->data[SC_MAGNETICFIELD] ) + break; // Source no more under Magnetic Field + } + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + } + break; - if( !status->charge(bl,hp,sp) ) break; + case SC_STEALTHFIELD_MASTER: + if(--(sce->val4) >= 0) { + // 1% SP Upkeep Cost + int sp = st->max_sp / 100; + + if( st->sp <= sp ) + status_change_end(bl,SC_STEALTHFIELD_MASTER,INVALID_TIMER); - sc_timer_next(1000+tick,status->change_timer,bl->id, data); - return 0; - } - break; + if( !status_charge(bl,0,sp) ) + break; - case SC_RAISINGDRAGON: - // 1% every 5 seconds [Jobbie] - if( --(sce->val3)>0 && status->charge(bl, sce->val2, 0) ) { - if( !sc->data[type] ) return 0; - sc_timer_next(5000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; + if( !sc->data[SC_STEALTHFIELD_MASTER] ) + break; - case SC_CIRCLE_OF_FIRE: - case SC_FIRE_CLOAK: - case SC_WATER_DROP: - case SC_WATER_SCREEN: - case SC_WIND_CURTAIN: - case SC_WIND_STEP: - case SC_STONE_SHIELD: - case SC_SOLID_SKIN: - if( !status->charge(bl,0,sce->val2) ){ - struct block_list *s_bl = battle->get_master(bl); - if( s_bl ) - status_change_end(s_bl,type+1,INVALID_TIMER); - status_change_end(bl,type,INVALID_TIMER); + sc_timer_next((2000 + 1000 * sce->val1)+tick,status->change_timer,bl->id, data); + return 0; + } break; - } - sc_timer_next(2000 + tick, status->change_timer, bl->id, data); - return 0; - case SC_STOMACHACHE: - if( --(sce->val4) > 0 ) { - status->charge(bl,0,sce->val2); // Reduce 8 every 10 seconds. - if( sd && !pc_issit(sd) ) { // Force to sit every 10 seconds. - pc_stop_walking(sd,1|4); - pc_stop_attack(sd); - pc_setsit(sd); - clif->sitting(bl); + case SC_INSPIRATION: + if(--(sce->val4) >= 0) { + int hp = st->max_hp * (35 - 5 * sce->val1) / 1000; + int sp = st->max_sp * (45 - 5 * sce->val1) / 1000; + + if( !status->charge(bl,hp,sp) ) break; + + sc_timer_next(5000+tick,status->change_timer,bl->id, data); + return 0; } - sc_timer_next(10000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; - case SC_LEADERSHIP: - case SC_GLORYWOUNDS: - case SC_SOULCOLD: - case SC_HAWKEYES: - /* they only end by status_change_end */ - sc_timer_next(600000 + tick, status->change_timer, bl->id, data); - return 0; - case SC_MEIKYOUSISUI: - if( --(sce->val4) > 0 ) { - status->heal(bl, st->max_hp * (sce->val1+1) / 100, st->max_sp * sce->val1 / 100, 0); - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; - case SC_IZAYOI: - case SC_KAGEMUSYA: - if( --(sce->val2) > 0 ) { - if(!status->charge(bl, 0, 1)) break; - sc_timer_next(1000+tick, status->change_timer, bl->id, data); - return 0; - } - break; - case SC_ANGRIFFS_MODUS: - if(--(sce->val4) > 0) { //drain hp/sp - if( !status->charge(bl,100,20) ) break; - sc_timer_next(1000+tick,status->change_timer,bl->id, data); - return 0; - } - break; - case SC_FULL_THROTTLE: - if( --(sce->val4) > 0 ) { - status_percent_damage(bl, bl, sce->val2, 0, false); - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); - return 0; - } - break; - case SC_KINGS_GRACE: - if( --(sce->val4) > 0 ) { - status_percent_heal(bl, sce->val2, 0); - sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + break; + + case SC_RAISINGDRAGON: + // 1% every 5 seconds [Jobbie] + if( --(sce->val3)>0 && status->charge(bl, sce->val2, 0) ) { + if( !sc->data[type] ) return 0; + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + + case SC_CIRCLE_OF_FIRE: + case SC_FIRE_CLOAK: + case SC_WATER_DROP: + case SC_WATER_SCREEN: + case SC_WIND_CURTAIN: + case SC_WIND_STEP: + case SC_STONE_SHIELD: + case SC_SOLID_SKIN: + if( !status->charge(bl,0,sce->val2) ){ + struct block_list *s_bl = battle->get_master(bl); + if( s_bl ) + status_change_end(s_bl,type+1,INVALID_TIMER); + status_change_end(bl,type,INVALID_TIMER); + break; + } + sc_timer_next(2000 + tick, status->change_timer, bl->id, data); return 0; - } - break; - case SC_FRIGG_SONG: - if( --(sce->val4) > 0 ) { - status->heal(bl, sce->val3, 0, 0); - sc_timer_next(10000 + tick, status->change_timer, bl->id, data); + + case SC_STOMACHACHE: + if( --(sce->val4) > 0 ) { + status->charge(bl,0,sce->val2); // Reduce 8 every 10 seconds. + if( sd && !pc_issit(sd) ) { // Force to sit every 10 seconds. + pc_stop_walking(sd,1|4); + pc_stop_attack(sd); + pc_setsit(sd); + clif->sitting(bl); + } + sc_timer_next(10000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_LEADERSHIP: + case SC_GLORYWOUNDS: + case SC_SOULCOLD: + case SC_HAWKEYES: + /* they only end by status_change_end */ + sc_timer_next(600000 + tick, status->change_timer, bl->id, data); return 0; - } - break; + case SC_MEIKYOUSISUI: + if( --(sce->val4) > 0 ) { + status->heal(bl, st->max_hp * (sce->val1+1) / 100, st->max_sp * sce->val1 / 100, 0); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_IZAYOI: + case SC_KAGEMUSYA: + if( --(sce->val2) > 0 ) { + if(!status->charge(bl, 0, 1)) break; + sc_timer_next(1000+tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_ANGRIFFS_MODUS: + if(--(sce->val4) > 0) { //drain hp/sp + if( !status->charge(bl,100,20) ) break; + sc_timer_next(1000+tick,status->change_timer,bl->id, data); + return 0; + } + break; + case SC_FULL_THROTTLE: + if( --(sce->val4) > 0 ) { + status_percent_damage(bl, bl, sce->val2, 0, false); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_KINGS_GRACE: + if( --(sce->val4) > 0 ) { + status_percent_heal(bl, sce->val2, 0); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_FRIGG_SONG: + if( --(sce->val4) > 0 ) { + status->heal(bl, sce->val3, 0, 0); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; } // default for all non-handled control paths is to end the status @@ -10707,7 +11173,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) { struct block_list* src = va_arg(ap,struct block_list*); struct status_change_entry* sce = va_arg(ap,struct status_change_entry*); enum sc_type type = (sc_type)va_arg(ap,int); //gcc: enum args get promoted to int - unsigned int tick = va_arg(ap,unsigned int); + int64 tick = va_arg(ap, int64); if (status->isdead(bl)) return 0; @@ -10715,57 +11181,54 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) { tsc = status->get_sc(bl); switch( type ) { - case SC_SIGHT: /* Reveal hidden ennemy on 3*3 range */ - if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking - rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - case SC_CONCENTRATION: - status_change_end(bl, SC_HIDING, INVALID_TIMER); - status_change_end(bl, SC_CLOAKING, INVALID_TIMER); - status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); - status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); - status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); - break; - case SC_RUWACH: /* Reveal hidden target and deal little dammages if ennemy */ - if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || - tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED] || - tsc->data[SC__INVISIBILITY])) { - status_change_end(bl, SC_HIDING, INVALID_TIMER); - status_change_end(bl, SC_CLOAKING, INVALID_TIMER); - status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); - status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); - status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); - if(battle->check_target( src, bl, BCT_ENEMY ) > 0) - skill->attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0); - } - if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking - rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - break; - case SC_WZ_SIGHTBLASTER: - if (battle->check_target( src, bl, BCT_ENEMY ) > 0 - && status->check_skilluse(src, bl, WZ_SIGHTBLASTER, 2) - ) { - if (sce && !(bl->type&BL_SKILL) //The hit is not counted if it's against a trap - && skill->attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,1,tick,0) - ){ - sce->val2 = 0; //This signals it to end. + case SC_SIGHT: /* Reveal hidden ennemy on 3*3 range */ + if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking + rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + case SC_CONCENTRATION: + status_change_end(bl, SC_HIDING, INVALID_TIMER); + status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + break; + case SC_RUWACH: /* Reveal hidden target and deal little dammages if ennemy */ + if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || + tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED])) { + status_change_end(bl, SC_HIDING, INVALID_TIMER); + status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + if(battle->check_target( src, bl, BCT_ENEMY ) > 0) + skill->attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0); } - } - break; - case SC_RG_CCONFINE_M: - //Lock char has released the hold on everyone... - if (tsc && tsc->data[SC_RG_CCONFINE_S] && tsc->data[SC_RG_CCONFINE_S]->val2 == src->id) { - tsc->data[SC_RG_CCONFINE_S]->val2 = 0; - status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); - } - break; - case SC_CURSEDCIRCLE_TARGET: - if( tsc && tsc->data[SC_CURSEDCIRCLE_TARGET] && tsc->data[SC_CURSEDCIRCLE_TARGET]->val2 == src->id ) { - clif->bladestop(bl, tsc->data[SC_CURSEDCIRCLE_TARGET]->val2, 0); - status_change_end(bl, type, INVALID_TIMER); - } - break; + if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking + rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + break; + case SC_WZ_SIGHTBLASTER: + if (battle->check_target( src, bl, BCT_ENEMY ) > 0 + && status->check_skilluse(src, bl, WZ_SIGHTBLASTER, 2) + ) { + if (sce && !(bl->type&BL_SKILL) //The hit is not counted if it's against a trap + && skill->attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,1,tick,0) + ){ + sce->val2 = 0; //This signals it to end. + } + } + break; + case SC_RG_CCONFINE_M: + //Lock char has released the hold on everyone... + if (tsc && tsc->data[SC_RG_CCONFINE_S] && tsc->data[SC_RG_CCONFINE_S]->val2 == src->id) { + tsc->data[SC_RG_CCONFINE_S]->val2 = 0; + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); + } + break; + case SC_CURSEDCIRCLE_TARGET: + if( tsc && tsc->data[SC_CURSEDCIRCLE_TARGET] && tsc->data[SC_CURSEDCIRCLE_TARGET]->val2 == src->id ) { + clif->bladestop(bl, tsc->data[SC_CURSEDCIRCLE_TARGET]->val2, 0); + status_change_end(bl, type, INVALID_TIMER); + } + break; } return 0; } @@ -10871,7 +11334,7 @@ int status_get_matk(struct block_list *bl, int flag) { st->matk_min = status_base_matk_min(st) + (sd?sd->bonus.ematk:0); st->matk_max = status_base_matk_max(st) + (sd?sd->bonus.ematk:0); #endif - if (bl->type&BL_PC && sd->matk_rate != 100) { + if (sd && sd->matk_rate != 100) { st->matk_max = st->matk_max * sd->matk_rate/100; st->matk_min = st->matk_min * sd->matk_rate/100; } @@ -10943,7 +11406,6 @@ int status_change_clear_buffs (struct block_list* bl, int type) { continue; break; case SC_BERSERK: - case SC_SATURDAY_NIGHT_FEVER: if(type&4) continue; sc->data[i]->val2 = 0; @@ -10961,7 +11423,7 @@ int status_change_clear_buffs (struct block_list* bl, int type) { int status_change_spread( struct block_list *src, struct block_list *bl ) { int i, flag = 0; struct status_change *sc = status->get_sc(src); - unsigned int tick; + int64 tick; struct status_change_data data; if( !sc || !sc->count ) @@ -11003,7 +11465,7 @@ int status_change_spread( struct block_list *src, struct block_list *bl ) { const struct TimerData *td = timer->get(sc->data[i]->timer); if (td == NULL || td->func != status->change_timer || DIFF_TICK(td->tick,tick) < 0) continue; - data.tick = DIFF_TICK(td->tick,tick); + data.tick = DIFF_TICK32(td->tick,tick); } else data.tick = INVALID_TIMER; break; @@ -11038,7 +11500,7 @@ int status_change_spread( struct block_list *src, struct block_list *bl ) { data.val2 = sc->data[i]->val2; data.val3 = sc->data[i]->val3; data.val4 = sc->data[i]->val4; - status->change_start(bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2|8); + status->change_start(src,bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2|8); flag = 1; } } @@ -11211,7 +11673,7 @@ int status_natural_heal(struct block_list* bl, va_list args) { val*=2; sd->state.doridori = 0; if ((rate = pc->checkskill(sd,TK_SPTIME))) - sc_start(bl,status->skill2sc(TK_SPTIME), + sc_start(bl,bl,status->skill2sc(TK_SPTIME), 100,rate,skill->get_time(TK_SPTIME, rate)); if ((sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR &&rnd()%10000 < battle_config.sg_angel_skill_ratio @@ -11231,8 +11693,9 @@ int status_natural_heal(struct block_list* bl, va_list args) { } //Natural heal main timer. -int status_natural_heal_timer(int tid, unsigned int tick, int id, intptr_t data) { - status->natural_heal_diff_tick = DIFF_TICK(tick,status->natural_heal_prev_tick); +int status_natural_heal_timer(int tid, int64 tick, int id, intptr_t data) { + // This difference is always positive and lower than UINT_MAX (~24 days) + status->natural_heal_diff_tick = (unsigned int)cap_value(DIFF_TICK(tick,status->natural_heal_prev_tick), 0, UINT_MAX); map->foreachregen(status->natural_heal); status->natural_heal_prev_tick = tick; return 0; @@ -11431,7 +11894,10 @@ int status_readdb(void) /*========================================== * Status db init and destroy. *------------------------------------------*/ -int do_init_status(void) { +int do_init_status(bool minimal) { + if (minimal) + return 0; + timer->add_func_list(status->change_timer,"status_change_timer"); timer->add_func_list(status->kaahi_heal_timer,"status_kaahi_heal_timer"); timer->add_func_list(status->natural_heal_timer,"status_natural_heal_timer"); @@ -11502,7 +11968,7 @@ void status_defaults(void) { status->set_sp = status_set_sp; status->heal = status_heal; status->revive = status_revive; - + status->fixed_revive = status_fixed_revive; status->get_regen_data = status_get_regen_data; status->get_status_data = status_get_status_data; status->get_base_status = status_get_base_status; |