diff --git a/db/pre-re/skill_db.yml b/db/pre-re/skill_db.yml index 402b1bf263e..261c616ee64 100644 --- a/db/pre-re/skill_db.yml +++ b/db/pre-re/skill_db.yml @@ -16336,7 +16336,7 @@ Body: Flags: IsNpc: true HitCount: 1 - Duration1: -1 + Duration1: 300000 Status: Invincible - Id: 686 Name: NPC_INVINCIBLEOFF @@ -16348,8 +16348,6 @@ Body: Flags: IsNpc: true HitCount: 1 - Duration1: 60000 - Status: InvincibleOff - Id: 687 Name: NPC_ALLHEAL Description: Full Heal diff --git a/db/pre-re/status.yml b/db/pre-re/status.yml index 8e26af33476..620372a1bcc 100644 --- a/db/pre-re/status.yml +++ b/db/pre-re/status.yml @@ -2824,23 +2824,12 @@ Body: Icon: EFST_INVINCIBLE DurationLookup: NPC_INVINCIBLE CalcFlags: + Aspd: true Speed: true Flags: NoDispell: true NoBanishingBuster: true NoClearance: true - EndOnStart: - Invincibleoff: true - - Status: Invincibleoff - DurationLookup: NPC_INVINCIBLEOFF - CalcFlags: - Speed: true - Flags: - NoDispell: true - NoBanishingBuster: true - NoClearance: true - EndOnStart: - Invincible: true - Status: Manu_Atk Icon: EFST_MANU_ATK Flags: diff --git a/db/re/skill_db.yml b/db/re/skill_db.yml index 44f3e468c79..6c05bd40889 100644 --- a/db/re/skill_db.yml +++ b/db/re/skill_db.yml @@ -16709,7 +16709,7 @@ Body: Flags: IsNpc: true HitCount: 1 - Duration1: -1 + Duration1: 300000 Status: Invincible - Id: 686 Name: NPC_INVINCIBLEOFF @@ -16721,8 +16721,6 @@ Body: Flags: IsNpc: true HitCount: 1 - Duration1: 60000 - Status: InvincibleOff - Id: 687 Name: NPC_ALLHEAL Description: Full Heal @@ -46959,9 +46957,7 @@ Body: Range: 2 Hit: Single HitCount: 1 - Duration1: 10000 Cooldown: 30000 - Status: InvincibleOff - Id: 8401 Name: EL_CIRCLE_OF_FIRE Description: Circle of Fire diff --git a/db/re/status.yml b/db/re/status.yml index 417c6147a06..a43b326527e 100644 --- a/db/re/status.yml +++ b/db/re/status.yml @@ -2928,23 +2928,12 @@ Body: Icon: EFST_INVINCIBLE DurationLookup: NPC_INVINCIBLE CalcFlags: + Aspd: true Speed: true Flags: NoDispell: true NoBanishingBuster: true NoClearance: true - EndOnStart: - Invincibleoff: true - - Status: Invincibleoff - DurationLookup: NPC_INVINCIBLEOFF - CalcFlags: - Speed: true - Flags: - NoDispell: true - NoBanishingBuster: true - NoClearance: true - EndOnStart: - Invincible: true - Status: Manu_Atk Icon: EFST_MANU_ATK Flags: diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 17bfc22d9ad..2698748dcb7 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -1548,11 +1548,6 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam return 0; } - status_change* tsc = status_get_sc(bl); //check target status - - if( tsc && tsc->getSCE(SC_INVINCIBLE) && !tsc->getSCE(SC_INVINCIBLEOFF) ) - return 1; - switch (skill_id) { #ifndef RENEWAL case PA_PRESSURE: @@ -1566,6 +1561,8 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam return damage; //These skills bypass everything else. } + status_change* tsc = status_get_sc(bl); //check target status + // Nothing can reduce the damage, but Safety Wall and Millennium Shield can block it completely. // So can defense sphere's but what the heck is that??? [Rytech] if (skill_id == SJ_NOVAEXPLOSING && !(tsc && (tsc->getSCE(SC_SAFETYWALL) || tsc->getSCE(SC_MILLENNIUMSHIELD)))) { @@ -1880,9 +1877,6 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam } } - if( sc->getSCE(SC_INVINCIBLE) && !sc->getSCE(SC_INVINCIBLEOFF) ) - damage += damage * 75 / 100; - if ((sce = sc->getSCE(SC_BLOODLUST)) && flag&BF_WEAPON && damage > 0 && rnd()%100 < sce->val3) status_heal(src, damage * sce->val4 / 100, 0, 3); @@ -2845,6 +2839,10 @@ bool is_infinite_defense(struct block_list *target, int flag) if(status_has_mode(tstatus,MD_IGNOREMISC) && flag&(BF_MISC) ) return true; + status_change* tsc = status_get_sc(target); + if (tsc && tsc->getSCE(SC_INVINCIBLE)) + return true; + return false; } @@ -4459,10 +4457,11 @@ static unsigned short battle_get_atkpercent(struct block_list& bl, uint16 skill_ atkpercent += sc.getSCE(SC_BLOODLUST)->val2; if (sc.getSCE(SC_FLEET)) atkpercent += sc.getSCE(SC_FLEET)->val3; + if (sc.getSCE(SC_INVINCIBLE)) + atkpercent += sc.getSCE(SC_INVINCIBLE)->val2; /* Only few selected skills should use this function, DO NOT ADD any that are not caused by the skills listed below * TODO: - * NPC_INVINCIBLE (+100) * GD_GUARDUP (2*skLevel+8) * EL_WATERBARRIER (-3) * SC_ENERVATION (-30/-40/-50) diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp index 4bc4c7ffd3f..4eb34d6d28b 100644 --- a/src/map/script_constants.hpp +++ b/src/map/script_constants.hpp @@ -1258,7 +1258,7 @@ //export_constant(SC_IGNOREDEF); export_constant(SC_HELLPOWER); export_constant(SC_INVINCIBLE); - export_constant(SC_INVINCIBLEOFF); + //export_constant(SC_INVINCIBLEOFF); export_constant(SC_MANU_ATK); export_constant(SC_MANU_DEF); export_constant(SC_SPL_ATK); diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 67b1f4ed8c4..00c34b6f4b9 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -7976,8 +7976,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NPC_WEAPONBRAKER: case NPC_BARRIER: case NPC_INVINCIBLE: - case NPC_INVINCIBLEOFF: - case MER_INVINCIBLEOFF2: case RK_DEATHBOUND: case AB_EXPIATIO: case AB_DUPLELIGHT: @@ -9767,43 +9765,43 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SA_SPELLBREAKER: { int sp; - if(tsc && tsc->getSCE(SC_MAGICROD)) { - sp = skill_get_sp(skill_id,skill_lv); - sp = sp * tsc->getSCE(SC_MAGICROD)->val2 / 100; - if(sp < 1) sp = 1; - status_heal(bl,0,sp,2); - status_percent_damage(bl, src, 0, -20, false); //20% max SP damage. - } else { - struct unit_data *ud = unit_bl2ud(bl); - int bl_skill_id=0,bl_skill_lv=0,hp = 0; + if (dstsd && tsc && tsc->getSCE(SC_MAGICROD)) { + // If target enemy player has Magic Rod, then 20% of your SP is transferred to that player + sp = status_percent_damage(bl, src, 0, -20, false); + status_heal(bl, 0, sp, 2); + } + else { + struct unit_data* ud = unit_bl2ud(bl); if (!ud || ud->skilltimer == INVALID_TIMER) break; //Nothing to cancel. - bl_skill_id = ud->skill_id; - bl_skill_lv = ud->skill_lv; - if (status_has_mode(tstatus,MD_STATUSIMMUNE)) { //Only 10% success chance against status immune. [Skotlex] - if (rnd()%100 < 90) + int hp = 0; + if (status_has_mode(tstatus, MD_STATUSIMMUNE)) { //Only 10% success chance against status immune. [Skotlex] + if (rnd_chance(90, 100)) { if (sd) clif_skill_fail( *sd, skill_id ); break; } - } else if (!dstsd || map_flag_vs(bl->m)) //HP damage only on pvp-maps when against players. - hp = tstatus->max_hp/50; //Recover 2% HP [Skotlex] - - clif_skill_nodamage(src,bl,skill_id,skill_lv,1); - unit_skillcastcancel(bl,0); - sp = skill_get_sp(bl_skill_id,bl_skill_lv); - status_zap(bl, hp, sp); - - if (hp && skill_lv >= 5) - hp /= 2; //Recover half damaged HP at level 5 [Skotlex] - else - hp = 0; - - if (sp) //Recover some of the SP used - sp = sp*(25*(skill_lv-1))/100; + } +#ifdef RENEWAL + else // HP damage does not work on bosses in renewal +#endif + if (skill_lv >= 5 && (!dstsd || map_flag_vs(bl->m))) //HP damage only on pvp-maps when against players. + hp = tstatus->max_hp / 50; //Siphon 2% HP at level 5 - if(hp || sp) - status_heal(src, hp, sp, 2); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + unit_skillcastcancel(bl, 0); + sp = skill_get_sp(ud->skill_id, ud->skill_lv); + status_zap(bl, 0, sp); + // Recover some of the SP used + status_heal(src, 0, sp * (25 * (skill_lv - 1)) / 100, 2); + + // If damage would be lethal, it does not deal damage + if (hp && hp < tstatus->hp) { + clif_damage(src, bl, tick, 0, 0, hp, 0, DMG_NORMAL, 0, false); + status_zap(bl, hp, 0); + // Recover 50% of damage dealt + status_heal(src, hp / 2, 0, 2); + } } } break; @@ -10027,6 +10025,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui clif_skill_nodamage(src,bl,skill_id,skill_lv,1); break; + case NPC_INVINCIBLEOFF: + case MER_INVINCIBLEOFF2: + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + status_change_end(bl, SC_INVINCIBLE); + break; + case WE_MALE: { uint8 hp_rate = abs(skill_get_hp_rate(skill_id, skill_lv)); diff --git a/src/map/status.cpp b/src/map/status.cpp index 901c856315f..90677d813b8 100644 --- a/src/map/status.cpp +++ b/src/map/status.cpp @@ -1475,7 +1475,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in flag |= 8; sc = status_get_sc(target); - if( hp && battle_config.invincible_nodamage && src && sc && sc->getSCE(SC_INVINCIBLE) && !sc->getSCE(SC_INVINCIBLEOFF) ) + if (hp && battle_config.invincible_nodamage && src && sc && sc->getSCE(SC_INVINCIBLE)) hp = 1; if( hp && !(flag&1) ) { @@ -2110,12 +2110,6 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui return true; if (tsc && tsc->count) { - /** - * Attacks in invincible are capped to 1 damage and handled in battle.cpp. - * Allow spell break and eske for sealed shrine GDB when in INVINCIBLE state. - **/ - if( tsc->getSCE(SC_INVINCIBLE) && !tsc->getSCE(SC_INVINCIBLEOFF) && skill_id && !(skill_id&(SA_SPELLBREAKER|SL_SKE)) ) - return false; if(!skill_id && tsc->getSCE(SC_TRICKDEAD)) return false; if((skill_id == WZ_STORMGUST || skill_id == WZ_FROSTNOVA || skill_id == NJ_HYOUSYOURAKU || skill_id == NPC_STORMGUST2) @@ -8036,8 +8030,8 @@ static unsigned short status_calc_speed(struct block_list *bl, status_change *sc val = max( val, 55 ); if( sc->getSCE(SC_AVOID) ) val = max( val, 10 * sc->getSCE(SC_AVOID)->val1 ); - if( sc->getSCE(SC_INVINCIBLE) && !sc->getSCE(SC_INVINCIBLEOFF) ) - val = max( val, 75 ); + if (sc->getSCE(SC_INVINCIBLE)) + val = max(val, sc->getSCE(SC_INVINCIBLE)->val3); if( sc->getSCE(SC_CLOAKINGEXCEED) ) val = max( val, sc->getSCE(SC_CLOAKINGEXCEED)->val3); if (sc->getSCE(SC_PARALYSE) && sc->getSCE(SC_PARALYSE)->val3 == 0) @@ -8309,66 +8303,68 @@ static short status_calc_aspd_rate(struct block_list *bl, status_change *sc, int if(!sc || !sc->count) return cap_value(aspd_rate,0,SHRT_MAX); - if( !sc->getSCE(SC_QUAGMIRE) ) { - int max = 0; - if(sc->getSCE(SC_STAR_COMFORT)) - max = sc->getSCE(SC_STAR_COMFORT)->val2; + int max = 0; + if (sc->getSCE(SC_STAR_COMFORT)) + max = sc->getSCE(SC_STAR_COMFORT)->val2; - if(sc->getSCE(SC_TWOHANDQUICKEN) && - max < sc->getSCE(SC_TWOHANDQUICKEN)->val2) - max = sc->getSCE(SC_TWOHANDQUICKEN)->val2; + if (sc->getSCE(SC_TWOHANDQUICKEN) && + max < sc->getSCE(SC_TWOHANDQUICKEN)->val2) + max = sc->getSCE(SC_TWOHANDQUICKEN)->val2; - if(sc->getSCE(SC_ONEHAND) && - max < sc->getSCE(SC_ONEHAND)->val2) - max = sc->getSCE(SC_ONEHAND)->val2; + if (sc->getSCE(SC_ONEHAND) && + max < sc->getSCE(SC_ONEHAND)->val2) + max = sc->getSCE(SC_ONEHAND)->val2; - if(sc->getSCE(SC_MERC_QUICKEN) && - max < sc->getSCE(SC_MERC_QUICKEN)->val2) - max = sc->getSCE(SC_MERC_QUICKEN)->val2; + if (sc->getSCE(SC_MERC_QUICKEN) && + max < sc->getSCE(SC_MERC_QUICKEN)->val2) + max = sc->getSCE(SC_MERC_QUICKEN)->val2; - if(sc->getSCE(SC_ADRENALINE2) && - max < sc->getSCE(SC_ADRENALINE2)->val3) - max = sc->getSCE(SC_ADRENALINE2)->val3; + if (sc->getSCE(SC_ADRENALINE2) && + max < sc->getSCE(SC_ADRENALINE2)->val3) + max = sc->getSCE(SC_ADRENALINE2)->val3; - if(sc->getSCE(SC_ADRENALINE) && - max < sc->getSCE(SC_ADRENALINE)->val3) - max = sc->getSCE(SC_ADRENALINE)->val3; + if (sc->getSCE(SC_ADRENALINE) && + max < sc->getSCE(SC_ADRENALINE)->val3) + max = sc->getSCE(SC_ADRENALINE)->val3; - if(sc->getSCE(SC_SPEARQUICKEN) && - max < sc->getSCE(SC_SPEARQUICKEN)->val2) - max = sc->getSCE(SC_SPEARQUICKEN)->val2; + if (sc->getSCE(SC_SPEARQUICKEN) && + max < sc->getSCE(SC_SPEARQUICKEN)->val2) + max = sc->getSCE(SC_SPEARQUICKEN)->val2; - if(sc->getSCE(SC_GATLINGFEVER) && - max < sc->getSCE(SC_GATLINGFEVER)->val2) - max = sc->getSCE(SC_GATLINGFEVER)->val2; + if (sc->getSCE(SC_GATLINGFEVER) && + max < sc->getSCE(SC_GATLINGFEVER)->val2) + max = sc->getSCE(SC_GATLINGFEVER)->val2; - if(sc->getSCE(SC_FLEET) && - max < sc->getSCE(SC_FLEET)->val2) - max = sc->getSCE(SC_FLEET)->val2; + if (sc->getSCE(SC_FLEET) && + max < sc->getSCE(SC_FLEET)->val2) + max = sc->getSCE(SC_FLEET)->val2; - if(sc->getSCE(SC_ASSNCROS) && max < sc->getSCE(SC_ASSNCROS)->val2) { - if (bl->type!=BL_PC) - max = sc->getSCE(SC_ASSNCROS)->val2; - else - switch(((TBL_PC*)bl)->status.weapon) { - case W_BOW: - case W_REVOLVER: - case W_RIFLE: - case W_GATLING: - case W_SHOTGUN: - case W_GRENADE: - break; - default: - max = sc->getSCE(SC_ASSNCROS)->val2; - } - } - aspd_rate -= max; + if (sc->getSCE(SC_INVINCIBLE) && + max < sc->getSCE(SC_INVINCIBLE)->val4) + max = sc->getSCE(SC_INVINCIBLE)->val4; - if(sc->getSCE(SC_BERSERK)) - aspd_rate -= 300; - else if(sc->getSCE(SC_MADNESSCANCEL)) - aspd_rate -= 200; + if (sc->getSCE(SC_ASSNCROS) && max < sc->getSCE(SC_ASSNCROS)->val2) { + if (bl->type != BL_PC) + max = sc->getSCE(SC_ASSNCROS)->val2; + else + switch (((TBL_PC*)bl)->status.weapon) { + case W_BOW: + case W_REVOLVER: + case W_RIFLE: + case W_GATLING: + case W_SHOTGUN: + case W_GRENADE: + break; + default: + max = sc->getSCE(SC_ASSNCROS)->val2; + } } + aspd_rate -= max; + + if (sc->getSCE(SC_BERSERK)) + aspd_rate -= 300; + else if (sc->getSCE(SC_MADNESSCANCEL)) + aspd_rate -= 200; if( sc->getSCE(i=SC_ASPDPOTION3) || sc->getSCE(i=SC_ASPDPOTION2) || @@ -11570,6 +11566,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_REBIRTH: val2 = 20*val1; // % of life to be revived with break; + case SC_INVINCIBLE: + val2 = 100; // ATKpercent increase + val3 = 50; // Speed increase + val4 = 700; // ASPD increase + break; case SC_MANU_DEF: case SC_MANU_ATK: diff --git a/src/map/status.hpp b/src/map/status.hpp index 682cc92ee83..c8f3446eeb0 100644 --- a/src/map/status.hpp +++ b/src/map/status.hpp @@ -499,8 +499,8 @@ enum sc_type : int16 { //SC_IGNOREDEF, SC_HELLPOWER = 294, SC_INVINCIBLE, //295 - SC_INVINCIBLEOFF, - SC_MANU_ATK, + //SC_INVINCIBLEOFF, + SC_MANU_ATK = 297, SC_MANU_DEF, SC_SPL_ATK, SC_SPL_DEF, //300