Implements SC_STONEWAIT (#6794)

* Fixes #6748.
* Implements SC_STONEWAIT to be used with OPT1_STONEWAIT.
* Removes a lot of hard coded OPT1_STONE checks now that the two states are split to their own statuses.
* Fixes SC_STONE not ending when the target receives damage.
* Fixes SC_STONE getting overwritten by other statuses the have OPT1 states.
* SC_STONE should damage the target by 1% of MaxHP, not CurrentHP.
* All skills that give StoneWait aside from Stone Curse are 100ms.
* Confirmed that Sienna Execrate is 8 + 2 * SkillLv seconds of Stone.
* Moves Provoke and Mind Breaker status clearings to the status database.
* Converts EndReturn in the status database from a boolean to a list of statuses. Statuses defined in this list will be ended and then the status making the call will not take affect.
Thanks to @Singe-Horizontal, @Playtester, and @Lemongrass3110!
This commit is contained in:
Aleos
2022-04-08 13:16:18 -04:00
committed by GitHub
parent 3b47defa35
commit cee161e677
11 changed files with 233 additions and 181 deletions

View File

@@ -1622,7 +1622,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
break;
case NPC_PETRIFYATTACK:
sc_start4(src,bl,SC_STONE,(20*skill_lv),skill_lv,0,0,skill_get_time(skill_id,skill_lv),skill_get_time2(skill_id,skill_lv));
sc_start4(src,bl,SC_STONEWAIT,(20*skill_lv),skill_lv,src->id,skill_get_time(skill_id,skill_lv),0,skill_get_time2(skill_id,skill_lv));
break;
case NPC_CURSEATTACK:
sc_start(src,bl,SC_CURSE,(20*skill_lv),skill_lv,skill_get_time2(skill_id,skill_lv));
@@ -7945,15 +7945,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
clif_skill_nodamage(src, bl, skill_id == SM_SELFPROVOKE ? SM_PROVOKE : skill_id, skill_lv, i);
unit_skillcastcancel(bl, 2);
if( tsc && tsc->count )
{
status_change_end(bl, SC_FREEZE, INVALID_TIMER);
if( tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE )
status_change_end(bl, SC_STONE, INVALID_TIMER);
status_change_end(bl, SC_SLEEP, INVALID_TIMER);
status_change_end(bl, SC_TRICKDEAD, INVALID_TIMER);
}
if( dstmd )
{
dstmd->state.provoke_flag = src->id;
@@ -8714,22 +8705,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case MG_STONECURSE:
{
int brate = 0;
if (status_has_mode(tstatus,MD_STATUSIMMUNE)) {
if (sd) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
if (sd)
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
if(status_isimmune(bl) || !tsc)
break;
int32 brate = 0;
if (sd && sd->sc.data[SC_PETROLOGY_OPTION])
brate = sd->sc.data[SC_PETROLOGY_OPTION]->val3;
if (tsc && tsc->data[type]) {
status_change_end(bl, type, INVALID_TIMER);
if (sd) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
if (sc_start4(src,bl,type,(skill_lv*4+20)+brate,
skill_lv, src->id, skill_get_time(skill_id, skill_lv), 0,
skill_get_time2(skill_id,skill_lv)))
@@ -9844,13 +9832,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
unit_skillcastcancel(bl,0);
if(tsc && tsc->count){
status_change_end(bl, SC_FREEZE, INVALID_TIMER);
if(tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE)
status_change_end(bl, SC_STONE, INVALID_TIMER);
status_change_end(bl, SC_SLEEP, INVALID_TIMER);
}
if (dstmd)
mob_target(dstmd, src, skill_get_range2(src, skill_id, skill_lv, true));
}
@@ -10333,8 +10314,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case SC_BURNING:
sc_start4(src,bl,type,100,skill_lv,1000,src->id,0,skill_get_time2(skill_id,skill_lv));
break;
case SC_VOICEOFSIREN:
sc_start2(src,bl,type,100,skill_lv,src->id,skill_get_time2(skill_id,skill_lv));
case SC_STONEWAIT:
sc_start4(src,bl,type,100,skill_lv,src->id,skill_get_time(skill_id, skill_lv), 0, skill_get_time2(skill_id,skill_lv));
break;
default:
sc_start2(src,bl,type,100,skill_lv,src->id,skill_get_time2(skill_id,skill_lv));
@@ -10784,22 +10765,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
if( bl->id == skill_area_temp[1] )
break; // Already work on this target
if( tsc && tsc->data[type] )
status_change_end(bl,type,INVALID_TIMER);
else
status_change_start(src,bl,type,10000,skill_lv,src->id,0,0,skill_get_time(skill_id, skill_lv),SCSTART_NOTICKDEF);
status_change_start(src,bl,type,10000,skill_lv,src->id,skill_get_time(skill_id, skill_lv),0,skill_get_time2(skill_id,skill_lv), SCSTART_NOTICKDEF);
} else {
int rate = 45 + 5 * skill_lv + ( sd? sd->status.job_level : 50 ) / 4;
// IroWiki says Rate should be reduced by target stats, but currently unknown
if( rnd()%100 < rate ) { // Success on First Target
if( !tsc->data[type] )
rate = status_change_start(src,bl,type,10000,skill_lv,src->id,0,0,skill_get_time(skill_id, skill_lv),SCSTART_NOTICKDEF);
else {
rate = 1;
status_change_end(bl,type,INVALID_TIMER);
}
if( rate ) {
if( status_change_start(src,bl,type,10000,skill_lv,src->id,skill_get_time(skill_id, skill_lv),0,skill_get_time2(skill_id,skill_lv), SCSTART_NOTICKDEF) ) {
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
skill_area_temp[1] = bl->id;
map_foreachinallrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_nodamage_id);
@@ -15908,7 +15879,7 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t
case UNT_ZENKAI_LAND:
switch (rnd()%2 + 1) {
case 1:
sc_start2(ss, bl, SC_STONE, sg->val1*5, sg->skill_lv, ss->id, skill_get_time(sg->skill_id, sg->skill_lv));
sc_start4(ss, bl, SC_STONEWAIT, sg->val1*5, sg->skill_lv, ss->id, skill_get_time(sg->skill_id, sg->skill_lv), 0, skill_get_time2(sg->skill_id, sg->skill_lv));
break;
case 2:
sc_start2(ss, bl, SC_POISON, sg->val1*5, sg->skill_lv, ss->id, skill_get_time(sg->skill_id, sg->skill_lv));