Updates stacking for common statuses (#6807)
* Fixes #6798. * Updates the Fail, End, and EndReturn lists for OPT1 and OPT2 statuses. * Removes the hardcoded OPT1 overwrite prevention check. * OPT1 that have RemoveOnDamaged flag should not get applied again in the same attack. * Fixes Stone status not properly being inflicted by the bAddEff, bAddEff2, bAddEffWhenHit, and bAddEffOnSkill item bonuses. * Fixes Stone status not properly being inflicted by The Hanged Man from Tarot Card of Fate. Thanks to @Playtester!
This commit is contained in:
parent
b17b0c7a0b
commit
53bc2376a6
@ -70,7 +70,6 @@ Body:
|
|||||||
Stun: true
|
Stun: true
|
||||||
Sleep: true
|
Sleep: true
|
||||||
Burning: true
|
Burning: true
|
||||||
#Undead: true
|
|
||||||
End:
|
End:
|
||||||
Aeterna: true
|
Aeterna: true
|
||||||
EndReturn:
|
EndReturn:
|
||||||
@ -89,7 +88,6 @@ Body:
|
|||||||
Stun: true
|
Stun: true
|
||||||
Sleep: true
|
Sleep: true
|
||||||
Burning: true
|
Burning: true
|
||||||
#Undead: true
|
|
||||||
EndReturn:
|
EndReturn:
|
||||||
StoneWait: true
|
StoneWait: true
|
||||||
Stone: true
|
Stone: true
|
||||||
@ -115,8 +113,13 @@ Body:
|
|||||||
Inspiration: true
|
Inspiration: true
|
||||||
Warmer: true
|
Warmer: true
|
||||||
Gvg_Freez: true
|
Gvg_Freez: true
|
||||||
|
Stone: true
|
||||||
|
StoneWait: true
|
||||||
|
Freeze: true
|
||||||
|
Stun: true
|
||||||
|
Sleep: true
|
||||||
|
Burning: true
|
||||||
End:
|
End:
|
||||||
Dancing: true
|
|
||||||
Aeterna: true
|
Aeterna: true
|
||||||
- Status: Stun
|
- Status: Stun
|
||||||
DurationLookup: NPC_STUNATTACK
|
DurationLookup: NPC_STUNATTACK
|
||||||
@ -135,8 +138,7 @@ Body:
|
|||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
Gvg_Stun: true
|
Gvg_Stun: true
|
||||||
End:
|
Stun: true
|
||||||
Dancing: true
|
|
||||||
- Status: Sleep
|
- Status: Sleep
|
||||||
DurationLookup: NPC_SLEEPATTACK
|
DurationLookup: NPC_SLEEPATTACK
|
||||||
States:
|
States:
|
||||||
@ -155,8 +157,7 @@ Body:
|
|||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
Gvg_Sleep: true
|
Gvg_Sleep: true
|
||||||
End:
|
Sleep: true
|
||||||
Dancing: true
|
|
||||||
- Status: Poison
|
- Status: Poison
|
||||||
DurationLookup: NPC_POISON
|
DurationLookup: NPC_POISON
|
||||||
CalcFlags:
|
CalcFlags:
|
||||||
@ -172,6 +173,8 @@ Body:
|
|||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
|
Poison: true
|
||||||
|
Dpoison: true
|
||||||
- Status: Curse
|
- Status: Curse
|
||||||
DurationLookup: NPC_CURSEATTACK
|
DurationLookup: NPC_CURSEATTACK
|
||||||
CalcFlags:
|
CalcFlags:
|
||||||
@ -189,6 +192,7 @@ Body:
|
|||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
Gvg_Curse: true
|
Gvg_Curse: true
|
||||||
|
Curse: true
|
||||||
- Status: Silence
|
- Status: Silence
|
||||||
DurationLookup: NPC_SILENCEATTACK
|
DurationLookup: NPC_SILENCEATTACK
|
||||||
States:
|
States:
|
||||||
@ -204,16 +208,16 @@ Body:
|
|||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
Gvg_Silence: true
|
Gvg_Silence: true
|
||||||
|
Silence: true
|
||||||
- Status: Confusion
|
- Status: Confusion
|
||||||
DurationLookup: NPC_WIDECONFUSE
|
DurationLookup: NPC_WIDECONFUSE
|
||||||
Flags:
|
Flags:
|
||||||
BossResist: true
|
BossResist: true
|
||||||
StopWalking: true
|
StopWalking: true
|
||||||
RemoveOnDamaged: true
|
|
||||||
OverlapFail: true
|
|
||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
|
EndReturn:
|
||||||
Confusion: true
|
Confusion: true
|
||||||
- Status: Blind
|
- Status: Blind
|
||||||
DurationLookup: NPC_BLINDATTACK
|
DurationLookup: NPC_BLINDATTACK
|
||||||
@ -231,6 +235,7 @@ Body:
|
|||||||
Inspiration: true
|
Inspiration: true
|
||||||
Fear: true
|
Fear: true
|
||||||
Gvg_Blind: true
|
Gvg_Blind: true
|
||||||
|
Blind: true
|
||||||
- Status: Bleeding
|
- Status: Bleeding
|
||||||
Icon: EFST_BLOODING
|
Icon: EFST_BLOODING
|
||||||
DurationLookup: NPC_BLEEDING
|
DurationLookup: NPC_BLEEDING
|
||||||
@ -243,7 +248,6 @@ Body:
|
|||||||
BossResist: true
|
BossResist: true
|
||||||
NoSave: true
|
NoSave: true
|
||||||
NoClearance: true
|
NoClearance: true
|
||||||
OverlapFail: true
|
|
||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
@ -257,7 +261,6 @@ Body:
|
|||||||
Flags:
|
Flags:
|
||||||
SendOption: true
|
SendOption: true
|
||||||
BossResist: true
|
BossResist: true
|
||||||
OverlapFail: true
|
|
||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
@ -415,6 +418,8 @@ Body:
|
|||||||
Flags:
|
Flags:
|
||||||
BossResist: true
|
BossResist: true
|
||||||
TaekwonAngel: true
|
TaekwonAngel: true
|
||||||
|
EndReturn:
|
||||||
|
Curse: true
|
||||||
- Status: Signumcrucis
|
- Status: Signumcrucis
|
||||||
Icon: EFST_CRUCIS
|
Icon: EFST_CRUCIS
|
||||||
DurationLookup: AL_CRUCIS
|
DurationLookup: AL_CRUCIS
|
||||||
@ -2840,7 +2845,6 @@ Body:
|
|||||||
Flags:
|
Flags:
|
||||||
BossResist: true
|
BossResist: true
|
||||||
StopWalking: true
|
StopWalking: true
|
||||||
OverlapFail: true
|
|
||||||
Debuff: true
|
Debuff: true
|
||||||
Fail:
|
Fail:
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
@ -2849,6 +2853,8 @@ Body:
|
|||||||
- Status: Burning
|
- Status: Burning
|
||||||
Icon: EFST_BURNT
|
Icon: EFST_BURNT
|
||||||
DurationLookup: RK_DRAGONBREATH
|
DurationLookup: RK_DRAGONBREATH
|
||||||
|
CalcFlags:
|
||||||
|
Mdef: true
|
||||||
Opt1: Burning
|
Opt1: Burning
|
||||||
Flags:
|
Flags:
|
||||||
SendOption: true
|
SendOption: true
|
||||||
@ -2861,8 +2867,6 @@ Body:
|
|||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
CalcFlags:
|
|
||||||
Mdef: true
|
|
||||||
- Status: Freezing
|
- Status: Freezing
|
||||||
Icon: EFST_FROSTMISTY
|
Icon: EFST_FROSTMISTY
|
||||||
DurationLookup: WL_FROSTMISTY
|
DurationLookup: WL_FROSTMISTY
|
||||||
@ -3076,13 +3080,8 @@ Body:
|
|||||||
SetStand: true
|
SetStand: true
|
||||||
StopWalking: true
|
StopWalking: true
|
||||||
StopAttacking: true
|
StopAttacking: true
|
||||||
OverlapFail: true
|
|
||||||
End:
|
End:
|
||||||
Dancing: true
|
|
||||||
Burning: true
|
|
||||||
Freezing: true
|
Freezing: true
|
||||||
Freeze: true
|
|
||||||
Stone: true
|
|
||||||
- Status: Marshofabyss
|
- Status: Marshofabyss
|
||||||
Icon: EFST_MARSHOFABYSS
|
Icon: EFST_MARSHOFABYSS
|
||||||
DurationLookup: WL_MARSHOFABYSS
|
DurationLookup: WL_MARSHOFABYSS
|
||||||
|
@ -71,7 +71,6 @@ Body:
|
|||||||
Stun: true
|
Stun: true
|
||||||
Sleep: true
|
Sleep: true
|
||||||
Burning: true
|
Burning: true
|
||||||
#Undead: true
|
|
||||||
End:
|
End:
|
||||||
Aeterna: true
|
Aeterna: true
|
||||||
EndReturn:
|
EndReturn:
|
||||||
@ -91,7 +90,6 @@ Body:
|
|||||||
Stun: true
|
Stun: true
|
||||||
Sleep: true
|
Sleep: true
|
||||||
Burning: true
|
Burning: true
|
||||||
#Undead: true
|
|
||||||
EndReturn:
|
EndReturn:
|
||||||
StoneWait: true
|
StoneWait: true
|
||||||
Stone: true
|
Stone: true
|
||||||
@ -117,8 +115,14 @@ Body:
|
|||||||
Inspiration: true
|
Inspiration: true
|
||||||
Warmer: true
|
Warmer: true
|
||||||
Gvg_Freez: true
|
Gvg_Freez: true
|
||||||
|
Whiteimprison: true
|
||||||
|
Stone: true
|
||||||
|
StoneWait: true
|
||||||
|
Freeze: true
|
||||||
|
Stun: true
|
||||||
|
Sleep: true
|
||||||
|
Burning: true
|
||||||
End:
|
End:
|
||||||
Dancing: true
|
|
||||||
Aeterna: true
|
Aeterna: true
|
||||||
- Status: Stun
|
- Status: Stun
|
||||||
DurationLookup: NPC_STUNATTACK
|
DurationLookup: NPC_STUNATTACK
|
||||||
@ -137,8 +141,7 @@ Body:
|
|||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
Gvg_Stun: true
|
Gvg_Stun: true
|
||||||
End:
|
Stun: true
|
||||||
Dancing: true
|
|
||||||
- Status: Sleep
|
- Status: Sleep
|
||||||
DurationLookup: NPC_SLEEPATTACK
|
DurationLookup: NPC_SLEEPATTACK
|
||||||
States:
|
States:
|
||||||
@ -157,8 +160,7 @@ Body:
|
|||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
Gvg_Sleep: true
|
Gvg_Sleep: true
|
||||||
End:
|
Sleep: true
|
||||||
Dancing: true
|
|
||||||
- Status: Poison
|
- Status: Poison
|
||||||
DurationLookup: NPC_POISON
|
DurationLookup: NPC_POISON
|
||||||
CalcFlags:
|
CalcFlags:
|
||||||
@ -175,6 +177,8 @@ Body:
|
|||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
|
Poison: true
|
||||||
|
Dpoison: true
|
||||||
- Status: Curse
|
- Status: Curse
|
||||||
DurationLookup: NPC_WIDECURSE
|
DurationLookup: NPC_WIDECURSE
|
||||||
CalcFlags:
|
CalcFlags:
|
||||||
@ -193,6 +197,7 @@ Body:
|
|||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
Gvg_Curse: true
|
Gvg_Curse: true
|
||||||
|
Curse: true
|
||||||
- Status: Silence
|
- Status: Silence
|
||||||
DurationLookup: NPC_SILENCEATTACK
|
DurationLookup: NPC_SILENCEATTACK
|
||||||
States:
|
States:
|
||||||
@ -209,17 +214,17 @@ Body:
|
|||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
Gvg_Silence: true
|
Gvg_Silence: true
|
||||||
|
Silence: true
|
||||||
- Status: Confusion
|
- Status: Confusion
|
||||||
DurationLookup: NPC_WIDECONFUSE
|
DurationLookup: NPC_WIDECONFUSE
|
||||||
Flags:
|
Flags:
|
||||||
BossResist: true
|
BossResist: true
|
||||||
StopWalking: true
|
StopWalking: true
|
||||||
RemoveOnDamaged: true
|
|
||||||
OverlapFail: true
|
|
||||||
SpreadEffect: true
|
SpreadEffect: true
|
||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
|
EndReturn:
|
||||||
Confusion: true
|
Confusion: true
|
||||||
- Status: Blind
|
- Status: Blind
|
||||||
DurationLookup: NPC_BLINDATTACK
|
DurationLookup: NPC_BLINDATTACK
|
||||||
@ -238,6 +243,7 @@ Body:
|
|||||||
Inspiration: true
|
Inspiration: true
|
||||||
Fear: true
|
Fear: true
|
||||||
Gvg_Blind: true
|
Gvg_Blind: true
|
||||||
|
Blind: true
|
||||||
- Status: Bleeding
|
- Status: Bleeding
|
||||||
Icon: EFST_BLOODING
|
Icon: EFST_BLOODING
|
||||||
DurationLookup: NPC_BLEEDING
|
DurationLookup: NPC_BLEEDING
|
||||||
@ -250,7 +256,6 @@ Body:
|
|||||||
BossResist: true
|
BossResist: true
|
||||||
NoSave: true
|
NoSave: true
|
||||||
NoClearance: true
|
NoClearance: true
|
||||||
OverlapFail: true
|
|
||||||
SpreadEffect: true
|
SpreadEffect: true
|
||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
@ -265,7 +270,6 @@ Body:
|
|||||||
Flags:
|
Flags:
|
||||||
SendOption: true
|
SendOption: true
|
||||||
BossResist: true
|
BossResist: true
|
||||||
OverlapFail: true
|
|
||||||
Fail:
|
Fail:
|
||||||
Refresh: true
|
Refresh: true
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
@ -2951,7 +2955,6 @@ Body:
|
|||||||
Flags:
|
Flags:
|
||||||
BossResist: true
|
BossResist: true
|
||||||
StopWalking: true
|
StopWalking: true
|
||||||
OverlapFail: true
|
|
||||||
Debuff: true
|
Debuff: true
|
||||||
Fail:
|
Fail:
|
||||||
Inspiration: true
|
Inspiration: true
|
||||||
@ -3188,12 +3191,8 @@ Body:
|
|||||||
StopWalking: true
|
StopWalking: true
|
||||||
StopAttacking: true
|
StopAttacking: true
|
||||||
StopCasting: true
|
StopCasting: true
|
||||||
OverlapFail: true
|
|
||||||
End:
|
End:
|
||||||
Burning: true
|
|
||||||
Freezing: true
|
Freezing: true
|
||||||
Freeze: true
|
|
||||||
Stone: true
|
|
||||||
- Status: Marshofabyss
|
- Status: Marshofabyss
|
||||||
Icon: EFST_MARSHOFABYSS
|
Icon: EFST_MARSHOFABYSS
|
||||||
DurationLookup: WL_MARSHOFABYSS
|
DurationLookup: WL_MARSHOFABYSS
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
//===== By: ==================================================
|
//===== By: ==================================================
|
||||||
//= rAthena Dev Team
|
//= rAthena Dev Team
|
||||||
//===== Last Updated: ========================================
|
//===== Last Updated: ========================================
|
||||||
//= 20220406
|
//= 20220414
|
||||||
//===== Description: =========================================
|
//===== Description: =========================================
|
||||||
//= Explanation of the status.yml file and structure.
|
//= Explanation of the status.yml file and structure.
|
||||||
//============================================================
|
//============================================================
|
||||||
@ -113,6 +113,7 @@ Opt1: Special effect when status is active (Aegis: BODYSTATE_*). This option is
|
|||||||
|
|
||||||
None - No effect (Default)
|
None - No effect (Default)
|
||||||
Stone - Stone curse effect
|
Stone - Stone curse effect
|
||||||
|
StoneWait - Stone curse incubation effect
|
||||||
Freeze - Freeze effect
|
Freeze - Freeze effect
|
||||||
Stun - Stun effect
|
Stun - Stun effect
|
||||||
Sleep - Sleep effect
|
Sleep - Sleep effect
|
||||||
|
@ -1302,11 +1302,24 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
|
|||||||
type = it.sc;
|
type = it.sc;
|
||||||
time = it.duration;
|
time = it.duration;
|
||||||
|
|
||||||
|
int32 val1 = 7, val2, val3;
|
||||||
|
|
||||||
|
if (type == SC_STONEWAIT) {
|
||||||
|
val2 = src->id;
|
||||||
|
val3 = skill_get_time(status_db.getSkill(type), 7);
|
||||||
|
} else {
|
||||||
|
val2 = 0;
|
||||||
|
if (type == SC_BURNING)
|
||||||
|
val3 = src->id;
|
||||||
|
else
|
||||||
|
val3 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (it.flag&ATF_TARGET)
|
if (it.flag&ATF_TARGET)
|
||||||
status_change_start(src,bl,type,rate,7,0,(type == SC_BURNING)?src->id:0,0,time,SCSTART_NONE);
|
status_change_start(src,bl,type,rate,val1,val2,val3,0,time,SCSTART_NONE);
|
||||||
|
|
||||||
if (it.flag&ATF_SELF)
|
if (it.flag&ATF_SELF)
|
||||||
status_change_start(src,src,type,rate,7,0,(type == SC_BURNING)?src->id:0,0,time,SCSTART_NONE);
|
status_change_start(src,src,type,rate,val1,val2,val3,0,time,SCSTART_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1321,10 +1334,23 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
|
|||||||
type = it.sc;
|
type = it.sc;
|
||||||
time = it.duration;
|
time = it.duration;
|
||||||
|
|
||||||
|
int32 val1 = 7, val2, val3;
|
||||||
|
|
||||||
|
if (type == SC_STONEWAIT) {
|
||||||
|
val2 = src->id;
|
||||||
|
val3 = skill_get_time(status_db.getSkill(type), 7);
|
||||||
|
} else {
|
||||||
|
val2 = 0;
|
||||||
|
if (type == SC_BURNING)
|
||||||
|
val3 = src->id;
|
||||||
|
else
|
||||||
|
val3 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (it.target&ATF_TARGET)
|
if (it.target&ATF_TARGET)
|
||||||
status_change_start(src,bl,type,it.rate,7,0,0,0,time,SCSTART_NONE);
|
status_change_start(src,bl,type,it.rate,val1,val2,val3,0,time,SCSTART_NONE);
|
||||||
if (it.target&ATF_SELF)
|
if (it.target&ATF_SELF)
|
||||||
status_change_start(src,src,type,it.rate,7,0,0,0,time,SCSTART_NONE);
|
status_change_start(src,src,type,it.rate,val1,val2,val3,0,time,SCSTART_NONE);
|
||||||
}
|
}
|
||||||
//"While the damage can be blocked by Pneuma, the chance to break armor remains", irowiki. [Cydh]
|
//"While the damage can be blocked by Pneuma, the chance to break armor remains", irowiki. [Cydh]
|
||||||
if (dmg_lv == ATK_BLOCK && skill_id == AM_ACIDTERROR) {
|
if (dmg_lv == ATK_BLOCK && skill_id == AM_ACIDTERROR) {
|
||||||
@ -2519,11 +2545,24 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
|
|||||||
type = it.sc;
|
type = it.sc;
|
||||||
time = it.duration;
|
time = it.duration;
|
||||||
|
|
||||||
|
int32 val1 = 7, val2, val3;
|
||||||
|
|
||||||
|
if (type == SC_STONEWAIT) {
|
||||||
|
val2 = src->id;
|
||||||
|
val3 = skill_get_time(status_db.getSkill(type), 7);
|
||||||
|
} else {
|
||||||
|
val2 = 0;
|
||||||
|
if (type == SC_BURNING)
|
||||||
|
val3 = src->id;
|
||||||
|
else
|
||||||
|
val3 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (it.flag&ATF_TARGET && src != bl)
|
if (it.flag&ATF_TARGET && src != bl)
|
||||||
status_change_start(src,src,type,rate,7,0,0,0,time,SCSTART_NONE);
|
status_change_start(src,src,type,rate,val1,val2,val3,0,time,SCSTART_NONE);
|
||||||
|
|
||||||
if (it.flag&ATF_SELF && !status_isdead(bl))
|
if (it.flag&ATF_SELF && !status_isdead(bl))
|
||||||
status_change_start(src,bl,type,rate,7,0,0,0,time,SCSTART_NONE);
|
status_change_start(src,bl,type,rate,val1,val2,val3,0,time,SCSTART_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4848,10 +4887,14 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui
|
|||||||
}
|
}
|
||||||
case 8: // THE HANGED MAN - stop, freeze or stoned
|
case 8: // THE HANGED MAN - stop, freeze or stoned
|
||||||
{
|
{
|
||||||
enum sc_type sc[] = { SC_STOP, SC_FREEZE, SC_STONE };
|
enum sc_type sc[] = { SC_STOP, SC_FREEZE, SC_STONEWAIT };
|
||||||
uint8 rand_eff = rnd() % 3;
|
uint8 rand_eff = rnd() % 3;
|
||||||
int time = ((rand_eff == 0) ? skill_get_time2(skill_id, skill_lv) : skill_get_time2(status_db.getSkill(sc[rand_eff]), 1));
|
int time = ((rand_eff == 0) ? skill_get_time2(skill_id, skill_lv) : skill_get_time2(status_db.getSkill(sc[rand_eff]), 1));
|
||||||
sc_start(src, target, sc[rand_eff], 100, skill_lv, time);
|
|
||||||
|
if (sc[rand_eff] == SC_STONEWAIT)
|
||||||
|
sc_start4(src, target, SC_STONEWAIT, 100, skill_lv, src->id, skill_get_time(status_db.getSkill(SC_STONEWAIT), 1), 0, time);
|
||||||
|
else
|
||||||
|
sc_start(src, target, sc[rand_eff], 100, skill_lv, time);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 9: // DEATH - curse, coma and poison
|
case 9: // DEATH - curse, coma and poison
|
||||||
|
@ -1000,8 +1000,15 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in
|
|||||||
for (const auto &it : status_db) {
|
for (const auto &it : status_db) {
|
||||||
sc_type type = static_cast<sc_type>(it.first);
|
sc_type type = static_cast<sc_type>(it.first);
|
||||||
|
|
||||||
if (sc->data[type] && it.second->flag[SCF_REMOVEONDAMAGED])
|
if (sc->data[type] && it.second->flag[SCF_REMOVEONDAMAGED]) {
|
||||||
|
// A status change that gets broken by damage should still be considered when calculating if a status change can be applied or not (for the same attack).
|
||||||
|
// !TODO: This is a temporary solution until we refactor the code so that the calculation of an SC is done at the start of an attack rather than after the damage was applied.
|
||||||
|
if (sc->opt1 > OPT1_NONE && sc->lastEffectTimer == INVALID_TIMER) {
|
||||||
|
sc->lastEffectTimer = add_timer(gettick() + 10, status_clear_lastEffect_timer, target->id, 0);
|
||||||
|
sc->lastEffect = type;
|
||||||
|
}
|
||||||
status_change_end(target, type, INVALID_TIMER);
|
status_change_end(target, type, INVALID_TIMER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((sce=sc->data[SC_ENDURE]) && !sce->val4) {
|
if ((sce=sc->data[SC_ENDURE]) && !sce->val4) {
|
||||||
/** [Skotlex]
|
/** [Skotlex]
|
||||||
@ -8640,6 +8647,8 @@ void status_change_init(struct block_list *bl)
|
|||||||
struct status_change *sc = status_get_sc(bl);
|
struct status_change *sc = status_get_sc(bl);
|
||||||
nullpo_retv(sc);
|
nullpo_retv(sc);
|
||||||
memset(sc, 0, sizeof (struct status_change));
|
memset(sc, 0, sizeof (struct status_change));
|
||||||
|
sc->lastEffect = SC_NONE;
|
||||||
|
sc->lastEffectTimer = INVALID_TIMER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*========================================== [Playtester]
|
/*========================================== [Playtester]
|
||||||
@ -9262,7 +9271,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
// Check failing SCs from list
|
// Check failing SCs from list
|
||||||
if (!scdb->fail.empty()) {
|
if (!scdb->fail.empty()) {
|
||||||
for (const auto &it : scdb->fail) {
|
for (const auto &it : scdb->fail) {
|
||||||
if (it && sc->data[it])
|
// Don't let OPT1 that have RemoveOnDamaged start a new effect in the same attack.
|
||||||
|
if (sc->data[it] || sc->lastEffect == it)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9624,6 +9634,16 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for OPT1 stacking
|
||||||
|
if (sc->opt1 > OPT1_NONE && scdb->opt1 > OPT1_NONE) {
|
||||||
|
for (const auto &status_it : status_db) {
|
||||||
|
sc_type opt1_type = status_it.second->type;
|
||||||
|
|
||||||
|
if (sc->data[opt1_type] && status_it.second->opt1 > OPT1_NONE)
|
||||||
|
status_change_end(bl, opt1_type, INVALID_TIMER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Before overlapping fail, one must check for status cured.
|
// Before overlapping fail, one must check for status cured.
|
||||||
std::vector<sc_type> endlist;
|
std::vector<sc_type> endlist;
|
||||||
|
|
||||||
@ -9652,12 +9672,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
|
|
||||||
// List of hardcoded status cured.
|
// List of hardcoded status cured.
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SC_STONE:
|
|
||||||
if (sc->data[SC_DANCING]) {
|
|
||||||
unit_stop_walking(bl, 1);
|
|
||||||
status_change_end(bl, SC_DANCING, INVALID_TIMER);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SC_BLESSING:
|
case SC_BLESSING:
|
||||||
// !TODO: Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM
|
// !TODO: 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]
|
// !but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm]
|
||||||
@ -9698,9 +9712,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
pc_bonus_script_clear(sd, BSF_REM_ON_MADOGEAR);
|
pc_bonus_script_clear(sd, BSF_REM_ON_MADOGEAR);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// If new SC has OPT1 while unit has OPT1, fail it!
|
|
||||||
if (sc->opt1 && scdb->opt1)
|
|
||||||
return 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12012,14 +12023,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
unit_stop_attack(bl);
|
unit_stop_attack(bl);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SC_WHITEIMPRISON:
|
|
||||||
case SC_DEEPSLEEP:
|
|
||||||
case SC_CRYSTALIZE:
|
|
||||||
case SC_FREEZE:
|
case SC_FREEZE:
|
||||||
case SC_STUN:
|
case SC_STUN:
|
||||||
case SC_GRAVITYCONTROL:
|
case SC_STONE:
|
||||||
if (sc->data[SC_DANCING])
|
if (sc->data[SC_DANCING]) {
|
||||||
unit_stop_walking(bl, 1);
|
unit_stop_walking(bl, 1);
|
||||||
|
status_change_end(bl, SC_DANCING, INVALID_TIMER);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!unit_blown_immune(bl,0x1))
|
if (!unit_blown_immune(bl,0x1))
|
||||||
@ -12383,26 +12393,6 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
|
|||||||
}
|
}
|
||||||
if (sce->timer != INVALID_TIMER) // Could be a SC with infinite duration
|
if (sce->timer != INVALID_TIMER) // Could be a SC with infinite duration
|
||||||
delete_timer(sce->timer,status_change_timer);
|
delete_timer(sce->timer,status_change_timer);
|
||||||
if (sc->opt1)
|
|
||||||
switch (type) {
|
|
||||||
// "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:
|
|
||||||
case SC_STONEWAIT:
|
|
||||||
sce->val4 = -1; // Petrify time
|
|
||||||
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 = add_timer(gettick()+10, status_change_timer, bl->id, type);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(sc->count)--;
|
(sc->count)--;
|
||||||
@ -14495,6 +14485,29 @@ static TIMER_FUNC(status_natural_heal_timer){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the lastEffect value from a target
|
||||||
|
* @param tid: Timer ID
|
||||||
|
* @param tick: Current tick (time)
|
||||||
|
* @param id: Object ID
|
||||||
|
* @param data: data pushed through timer function
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
TIMER_FUNC(status_clear_lastEffect_timer) {
|
||||||
|
block_list *bl = map_id2bl(id);
|
||||||
|
|
||||||
|
if (bl != nullptr) {
|
||||||
|
status_change *sc = status_get_sc(bl);
|
||||||
|
|
||||||
|
if (sc != nullptr) {
|
||||||
|
sc->lastEffect = SC_NONE;
|
||||||
|
sc->lastEffectTimer = INVALID_TIMER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if status is disabled on a map
|
* Check if status is disabled on a map
|
||||||
* @param type: Status Change data
|
* @param type: Status Change data
|
||||||
@ -15184,6 +15197,7 @@ void do_init_status(void) {
|
|||||||
|
|
||||||
add_timer_func_list(status_change_timer,"status_change_timer");
|
add_timer_func_list(status_change_timer,"status_change_timer");
|
||||||
add_timer_func_list(status_natural_heal_timer,"status_natural_heal_timer");
|
add_timer_func_list(status_natural_heal_timer,"status_natural_heal_timer");
|
||||||
|
add_timer_func_list(status_clear_lastEffect_timer, "status_clear_lastEffect_timer");
|
||||||
initDummyData();
|
initDummyData();
|
||||||
status_readdb();
|
status_readdb();
|
||||||
natural_heal_prev_tick = gettick();
|
natural_heal_prev_tick = gettick();
|
||||||
|
@ -3055,6 +3055,8 @@ struct status_change {
|
|||||||
unsigned short opt1;// body state
|
unsigned short opt1;// body state
|
||||||
unsigned short opt2;// health state (bitfield)
|
unsigned short opt2;// health state (bitfield)
|
||||||
unsigned char count;
|
unsigned char count;
|
||||||
|
sc_type lastEffect; // Used to check for stacking damageable SC on the same attack
|
||||||
|
int32 lastEffectTimer; // Timer for lastEffect
|
||||||
//! TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive.
|
//! TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive.
|
||||||
struct {
|
struct {
|
||||||
uint8 move;
|
uint8 move;
|
||||||
@ -3229,6 +3231,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap);
|
|||||||
int status_change_clear(struct block_list* bl, int type);
|
int status_change_clear(struct block_list* bl, int type);
|
||||||
void status_change_clear_buffs(struct block_list* bl, uint8 type);
|
void status_change_clear_buffs(struct block_list* bl, uint8 type);
|
||||||
void status_change_clear_onChangeMap(struct block_list *bl, struct status_change *sc);
|
void status_change_clear_onChangeMap(struct block_list *bl, struct status_change *sc);
|
||||||
|
TIMER_FUNC(status_clear_lastEffect_timer);
|
||||||
|
|
||||||
#define status_calc_mob(md, opt) status_calc_bl_(&(md)->bl, status_db.getSCB_ALL(), opt)
|
#define status_calc_mob(md, opt) status_calc_bl_(&(md)->bl, status_db.getSCB_ALL(), opt)
|
||||||
#define status_calc_pet(pd, opt) status_calc_bl_(&(pd)->bl, status_db.getSCB_ALL(), opt)
|
#define status_calc_pet(pd, opt) status_calc_bl_(&(pd)->bl, status_db.getSCB_ALL(), opt)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user