|
@@ -7304,6 +7304,34 @@ void status_change_init(struct block_list *bl)
|
|
memset(sc, 0, sizeof (struct status_change));
|
|
memset(sc, 0, sizeof (struct status_change));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*========================================== [Playtester]
|
|
|
|
+* Returns the interval for status changes that iterate multiple times
|
|
|
|
+* through the timer (e.g. those that deal damage in regular intervals)
|
|
|
|
+* @param type: Status change (SC_*)
|
|
|
|
+*------------------------------------------*/
|
|
|
|
+int status_get_sc_interval(enum sc_type type)
|
|
|
|
+{
|
|
|
|
+ switch (type) {
|
|
|
|
+ case SC_POISON:
|
|
|
|
+ case SC_DPOISON:
|
|
|
|
+ case SC_LEECHESEND:
|
|
|
|
+ return 1000;
|
|
|
|
+ case SC_BURNING:
|
|
|
|
+ case SC_PYREXIA:
|
|
|
|
+ return 3000;
|
|
|
|
+ case SC_MAGICMUSHROOM:
|
|
|
|
+ return 4000;
|
|
|
|
+ case SC_STONE:
|
|
|
|
+ return 5000;
|
|
|
|
+ case SC_BLEEDING:
|
|
|
|
+ case SC_TOXIN:
|
|
|
|
+ return 10000;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Applies SC defense to a given status change
|
|
* Applies SC defense to a given status change
|
|
* This function also determines whether or not the status change will be applied
|
|
* This function also determines whether or not the status change will be applied
|
|
@@ -7606,13 +7634,9 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
|
|
if (!(rnd()%10000 < rate))
|
|
if (!(rnd()%10000 < rate))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- // Even if a status change doesn't have a duration, it should still trigger
|
|
|
|
- if (tick < 1)
|
|
|
|
- return 1;
|
|
|
|
-
|
|
|
|
// Duration cannot be reduced
|
|
// Duration cannot be reduced
|
|
if (flag&SCSTART_NOTICKDEF)
|
|
if (flag&SCSTART_NOTICKDEF)
|
|
- return tick;
|
|
|
|
|
|
+ return max(tick, 1);
|
|
|
|
|
|
tick -= tick*tick_def/10000;
|
|
tick -= tick*tick_def/10000;
|
|
tick -= tick_def2;
|
|
tick -= tick_def2;
|
|
@@ -7620,7 +7644,6 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
|
|
// Minimum durations
|
|
// Minimum durations
|
|
switch (type) {
|
|
switch (type) {
|
|
case SC_ANKLE:
|
|
case SC_ANKLE:
|
|
- case SC_BURNING:
|
|
|
|
case SC_MARSHOFABYSS:
|
|
case SC_MARSHOFABYSS:
|
|
case SC_DEEPSLEEP:
|
|
case SC_DEEPSLEEP:
|
|
tick = max(tick, 5000); // Minimum duration 5s
|
|
tick = max(tick, 5000); // Minimum duration 5s
|
|
@@ -7628,6 +7651,7 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
|
|
case SC_FREEZING:
|
|
case SC_FREEZING:
|
|
tick = max(tick, 6000); // Minimum duration 6s
|
|
tick = max(tick, 6000); // Minimum duration 6s
|
|
break;
|
|
break;
|
|
|
|
+ case SC_BURNING:
|
|
case SC_STASIS:
|
|
case SC_STASIS:
|
|
tick = max(tick, 10000); // Minimum duration 10s
|
|
tick = max(tick, 10000); // Minimum duration 10s
|
|
break;
|
|
break;
|
|
@@ -8935,10 +8959,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|
break;
|
|
break;
|
|
|
|
|
|
case SC_STONE:
|
|
case SC_STONE:
|
|
- val4 = max(val4, 100); // Incubation time
|
|
|
|
- val3 = (tick-val4)/100; // Petrified timer iterations
|
|
|
|
- if(val3 < 1) val3 = 1;
|
|
|
|
- tick = val4;
|
|
|
|
|
|
+ val3 = max(val3, 100); // Incubation time
|
|
|
|
+ val4 = max(tick-val3, 100); // Petrify time
|
|
|
|
+ tick = val3;
|
|
calc_flag = 0; // Actual status changes take effect on petrified state.
|
|
calc_flag = 0; // Actual status changes take effect on petrified state.
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -8948,34 +8971,30 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|
int diff = status->max_hp*(bl->type==BL_PC?10:15)/100;
|
|
int diff = status->max_hp*(bl->type==BL_PC?10:15)/100;
|
|
if (status->hp - diff < status->max_hp>>2)
|
|
if (status->hp - diff < status->max_hp>>2)
|
|
diff = status->hp - (status->max_hp>>2);
|
|
diff = status->hp - (status->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);
|
|
|
|
- }
|
|
|
|
status_zap(bl, diff, 0);
|
|
status_zap(bl, diff, 0);
|
|
}
|
|
}
|
|
- case SC_POISON:
|
|
|
|
// Fall through
|
|
// Fall through
|
|
- 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) ? 2 + status->max_hp/50 : 2 + status->max_hp*3/200;
|
|
|
|
- else
|
|
|
|
- val4 = (type == SC_DPOISON) ? 2 + status->max_hp/100 : 2 + status->max_hp/200;
|
|
|
|
|
|
+ case SC_POISON:
|
|
|
|
+ case SC_BLEEDING:
|
|
|
|
+ case SC_BURNING:
|
|
|
|
+ case SC_TOXIN:
|
|
|
|
+ case SC_MAGICMUSHROOM:
|
|
|
|
+ case SC_LEECHESEND:
|
|
|
|
+ tick_time = status_get_sc_interval(type);
|
|
|
|
+ val4 = tick-tick_time; // Remaining time
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SC_PYREXIA:
|
|
|
|
+ //Causes blind for duration of pyrexia, unreducable and unavoidable, but can be healed with e.g. green potion
|
|
|
|
+ status_change_start(src,bl,SC_BLIND,10000,val1,0,0,0,tick,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
|
|
|
|
+ tick_time = status_get_sc_interval(type);
|
|
|
|
+ val4 = tick-tick_time; // Remaining time
|
|
break;
|
|
break;
|
|
|
|
|
|
case SC_CONFUSION:
|
|
case SC_CONFUSION:
|
|
if (!val4)
|
|
if (!val4)
|
|
clif_emotion(bl,E_WHAT);
|
|
clif_emotion(bl,E_WHAT);
|
|
break;
|
|
break;
|
|
- case SC_BLEEDING:
|
|
|
|
- val4 = tick/10000;
|
|
|
|
- if (!val4) val4 = 1;
|
|
|
|
- tick_time = 10000; // [GodLesZ] tick time
|
|
|
|
- break;
|
|
|
|
case SC_S_LIFEPOTION:
|
|
case SC_S_LIFEPOTION:
|
|
case SC_L_LIFEPOTION:
|
|
case SC_L_LIFEPOTION:
|
|
if( val1 == 0 ) return 0;
|
|
if( val1 == 0 ) return 0;
|
|
@@ -9219,11 +9238,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|
}
|
|
}
|
|
|
|
|
|
case SC_COMA: // Coma. Sends a char to 1HP. If val2, do not zap sp
|
|
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,status->hp - 1);
|
|
|
|
- }
|
|
|
|
status_zap(bl, status->hp-1, val2?0:status->sp);
|
|
status_zap(bl, status->hp-1, val2?0:status->sp);
|
|
return 1;
|
|
return 1;
|
|
break;
|
|
break;
|
|
@@ -9561,10 +9575,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|
val4 = tick / 1000;
|
|
val4 = tick / 1000;
|
|
tick_time = 1000; // [GodLesZ] tick time
|
|
tick_time = 1000; // [GodLesZ] tick time
|
|
break;
|
|
break;
|
|
- case SC_BURNING:
|
|
|
|
- val4 = tick / 2000; // Total Ticks to Burn!!
|
|
|
|
- tick_time = 2000; // [GodLesZ] tick time
|
|
|
|
- break;
|
|
|
|
|
|
|
|
/* Rune Knight */
|
|
/* Rune Knight */
|
|
case SC_DEATHBOUND:
|
|
case SC_DEATHBOUND:
|
|
@@ -9598,23 +9608,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|
val4 = tick / 5000;
|
|
val4 = tick / 5000;
|
|
tick_time = 5000; // [GodLesZ] tick time
|
|
tick_time = 5000; // [GodLesZ] tick time
|
|
break;
|
|
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,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF); // 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:
|
|
case SC_OBLIVIONCURSE:
|
|
val4 = tick / 3000;
|
|
val4 = tick / 3000;
|
|
tick_time = 3000; // [GodLesZ] tick time
|
|
tick_time = 3000; // [GodLesZ] tick time
|
|
@@ -10331,6 +10324,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|
clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
|
|
clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
|
|
clif_changelook(bl,LOOK_BODY2,0);
|
|
clif_changelook(bl,LOOK_BODY2,0);
|
|
break;
|
|
break;
|
|
|
|
+ case SC_STONE:
|
|
|
|
+ if (val3 > 0)
|
|
|
|
+ break; //Incubation time still active
|
|
|
|
+ //Fall through
|
|
|
|
+ case SC_POISON:
|
|
|
|
+ case SC_DPOISON:
|
|
|
|
+ case SC_BLEEDING:
|
|
|
|
+ case SC_BURNING:
|
|
|
|
+ case SC_TOXIN:
|
|
|
|
+ case SC_MAGICMUSHROOM:
|
|
|
|
+ case SC_PYREXIA:
|
|
|
|
+ case SC_LEECHESEND:
|
|
|
|
+ tick_time = tick;
|
|
|
|
+ tick = tick_time + max(val4,0);
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
|
|
// Values that must be set regardless of flag&4 e.g. val_flag [Ind]
|
|
// Values that must be set regardless of flag&4 e.g. val_flag [Ind]
|
|
@@ -10500,7 +10508,12 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|
opt_flag = 1;
|
|
opt_flag = 1;
|
|
switch(type) {
|
|
switch(type) {
|
|
// OPT1
|
|
// OPT1
|
|
- case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break;
|
|
|
|
|
|
+ case SC_STONE:
|
|
|
|
+ if (val3 > 0)
|
|
|
|
+ sc->opt1 = OPT1_STONEWAIT;
|
|
|
|
+ else
|
|
|
|
+ sc->opt1 = OPT1_STONE;
|
|
|
|
+ break;
|
|
case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break;
|
|
case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break;
|
|
case SC_STUN: sc->opt1 = OPT1_STUN; break;
|
|
case SC_STUN: sc->opt1 = OPT1_STUN; break;
|
|
case SC_DEEPSLEEP: opt_flag = 0;
|
|
case SC_DEEPSLEEP: opt_flag = 0;
|
|
@@ -11018,7 +11031,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
|
|
// delays status change ending so that a skill that sets opt1 fails to
|
|
// delays status change ending so that a skill that sets opt1 fails to
|
|
// trigger when it also removed one
|
|
// trigger when it also removed one
|
|
case SC_STONE:
|
|
case SC_STONE:
|
|
- sce->val3 = 0; // Petrify time counter.
|
|
|
|
|
|
+ sce->val4 = -1; // Petrify time
|
|
case SC_FREEZE:
|
|
case SC_FREEZE:
|
|
case SC_STUN:
|
|
case SC_STUN:
|
|
case SC_SLEEP:
|
|
case SC_SLEEP:
|
|
@@ -11743,6 +11756,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|
struct status_data *status;
|
|
struct status_data *status;
|
|
struct status_change *sc;
|
|
struct status_change *sc;
|
|
struct status_change_entry *sce;
|
|
struct status_change_entry *sce;
|
|
|
|
+ int interval = status_get_sc_interval(type);
|
|
|
|
+ bool dounlock = false;
|
|
|
|
|
|
bl = map_id2bl(id);
|
|
bl = map_id2bl(id);
|
|
if(!bl) {
|
|
if(!bl) {
|
|
@@ -11837,8 +11852,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|
break;
|
|
break;
|
|
|
|
|
|
case SC_STONE:
|
|
case SC_STONE:
|
|
- if(sc->opt1 == OPT1_STONEWAIT && sce->val3) {
|
|
|
|
- sce->val4 = 0;
|
|
|
|
|
|
+ if (sc->opt1 == OPT1_STONEWAIT && sce->val4) {
|
|
|
|
+ sce->val3 = 0; //Incubation time used up
|
|
unit_stop_attack(bl);
|
|
unit_stop_attack(bl);
|
|
if (sc->data[SC_DANCING]) {
|
|
if (sc->data[SC_DANCING]) {
|
|
unit_stop_walking(bl, 1);
|
|
unit_stop_walking(bl, 1);
|
|
@@ -11847,45 +11862,117 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|
status_change_end(bl, SC_AETERNA, INVALID_TIMER);
|
|
status_change_end(bl, SC_AETERNA, INVALID_TIMER);
|
|
sc->opt1 = OPT1_STONE;
|
|
sc->opt1 = OPT1_STONE;
|
|
clif_changeoption(bl);
|
|
clif_changeoption(bl);
|
|
- sc_timer_next(100+tick,status_change_timer, bl->id, data );
|
|
|
|
|
|
+ sc_timer_next(min(sce->val4, interval) + tick, status_change_timer, bl->id, data);
|
|
|
|
+ sce->val4 -= interval; //Remaining time
|
|
status_calc_bl(bl, StatusChangeFlagTable[type]);
|
|
status_calc_bl(bl, StatusChangeFlagTable[type]);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
- if (++(sce->val4)%50 == 0 && status->hp > status->max_hp/4) {
|
|
|
|
- if (sce->val2 && bl->type == BL_MOB) {
|
|
|
|
- struct block_list *src = map_id2bl(sce->val2);
|
|
|
|
-
|
|
|
|
- if (src)
|
|
|
|
- mob_log_damage((TBL_MOB*)bl, src, apply_rate(status->hp, 1));
|
|
|
|
- }
|
|
|
|
|
|
+ if (sce->val4 >= 0 && !(sce->val3) && status->hp > status->max_hp / 4) {
|
|
status_percent_damage(NULL, bl, 1, 0, false);
|
|
status_percent_damage(NULL, bl, 1, 0, false);
|
|
}
|
|
}
|
|
- if(--(sce->val3) > 0) {
|
|
|
|
- sc_timer_next(100+tick,status_change_timer, bl->id, data );
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case SC_POISON:
|
|
case SC_POISON:
|
|
case SC_DPOISON:
|
|
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);
|
|
|
|
- }
|
|
|
|
|
|
+ if (sce->val4 >= 0 && !sc->data[SC_SLOWPOISON]) {
|
|
|
|
+ int64 damage = 0;
|
|
|
|
+ if (sd)
|
|
|
|
+ damage = (type == SC_DPOISON) ? 2 + status->max_hp / 50 : 2 + status->max_hp * 3 / 200;
|
|
|
|
+ else
|
|
|
|
+ damage = (type == SC_DPOISON) ? 2 + status->max_hp / 100 : 2 + status->max_hp / 200;
|
|
|
|
+ if (status->hp > max(status->max_hp / 4, damage)) // Stop damaging after 25% HP left.
|
|
|
|
+ status_zap(bl, damage, 0);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SC_BLEEDING:
|
|
|
|
+ if (sce->val4 >= 0) {
|
|
|
|
+ int64 damage = rnd() % 600 + 200;
|
|
|
|
+ if (!sd && damage >= status->hp)
|
|
|
|
+ damage = status->hp - 1; // No deadly damage for monsters
|
|
|
|
+ map_freeblock_lock();
|
|
|
|
+ dounlock = true;
|
|
|
|
+ status_zap(bl, damage, 0);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SC_BURNING:
|
|
|
|
+ if (sce->val4 >= 0) {
|
|
|
|
+ int64 damage = 1000 + (3 * status->max_hp) / 100; // Deals fixed (1000 + 3%*MaxHP)
|
|
|
|
+ map_freeblock_lock();
|
|
|
|
+ dounlock = true;
|
|
|
|
+ status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, 0, 1, damage, 1, DMG_NORMAL, 0));
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SC_TOXIN:
|
|
|
|
+ if (sce->val4 >= 0) { // Damage is every 10 seconds including 3%sp drain.
|
|
|
|
+ map_freeblock_lock();
|
|
|
|
+ dounlock = true;
|
|
|
|
+ status_damage(bl, bl, 1, status->max_sp * 3 / 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 1, 1, DMG_NORMAL, 0), 0);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SC_MAGICMUSHROOM:
|
|
|
|
+ if (sce->val4 >= 0) {
|
|
|
|
+ bool flag = 0;
|
|
|
|
+ int64 damage = status->max_hp * 3 / 100;
|
|
|
|
+ if (status->hp <= damage)
|
|
|
|
+ damage = status->hp - 1; // Cannot Kill
|
|
|
|
+
|
|
|
|
+ if (damage > 0) { // 3% Damage each 4 seconds
|
|
map_freeblock_lock();
|
|
map_freeblock_lock();
|
|
- if(status->hp >= max(status->max_hp>>2, sce->val4)) // Stop damaging after 25% HP left.
|
|
|
|
- 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_zap(bl, damage, 0);
|
|
|
|
+ flag = !sc->data[type]; // Killed? Should not
|
|
map_freeblock_unlock();
|
|
map_freeblock_unlock();
|
|
}
|
|
}
|
|
- return 0;
|
|
|
|
|
|
+
|
|
|
|
+ if (!flag) { // Random Skill Cast
|
|
|
|
+ if (skill_magicmushroom_count && sd && !pc_issit(sd)) { // Can't cast if sit
|
|
|
|
+ int mushroom_skill_id = 0, checked = 0, checked_max = MAX_SKILL_MAGICMUSHROOM_DB * 3;
|
|
|
|
+ unit_stop_attack(bl);
|
|
|
|
+ unit_skillcastcancel(bl, 1);
|
|
|
|
+ do {
|
|
|
|
+ int i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB;
|
|
|
|
+ mushroom_skill_id = skill_magicmushroom_db[i].skill_id;
|
|
|
|
+ } while (checked++ < checked_max && mushroom_skill_id == 0);
|
|
|
|
+
|
|
|
|
+ if (!skill_get_index(mushroom_skill_id))
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SC_PYREXIA:
|
|
|
|
+ if (sce->val4 >= 0) {
|
|
|
|
+ map_freeblock_lock();
|
|
|
|
+ dounlock = true;
|
|
|
|
+ status_fix_damage(bl, bl, 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 100, 1, DMG_NORMAL, 0));
|
|
}
|
|
}
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
+ case SC_LEECHESEND:
|
|
|
|
+ if (sce->val4 >= 0) {
|
|
|
|
+ int64 damage = status->vit * (sce->val1 - 3) + status->max_hp / 100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100)
|
|
|
|
+ map_freeblock_lock();
|
|
|
|
+ dounlock = true;
|
|
|
|
+ status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, damage, 1, DMG_NORMAL, 0));
|
|
|
|
+ unit_skillcastcancel(bl, 2);
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
|
|
|
|
case SC_TENSIONRELAX:
|
|
case SC_TENSIONRELAX:
|
|
@@ -11906,26 +11993,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
|
|
|
|
- case SC_BLEEDING:
|
|
|
|
- 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 < status->hp ? hp : status->hp - 1 );
|
|
|
|
- map_freeblock_lock();
|
|
|
|
- status_fix_damage(src, bl, sd||hp<status->hp?hp:status->hp-1, 1);
|
|
|
|
- if( sc->data[type] ) {
|
|
|
|
- if( status->hp == 1 ) {
|
|
|
|
- map_freeblock_unlock();
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- sc_timer_next(10000 + tick, status_change_timer, bl->id, data);
|
|
|
|
- }
|
|
|
|
- map_freeblock_unlock();
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
case SC_S_LIFEPOTION:
|
|
case SC_S_LIFEPOTION:
|
|
case SC_L_LIFEPOTION:
|
|
case SC_L_LIFEPOTION:
|
|
if( sd && --(sce->val4) >= 0 ) {
|
|
if( sd && --(sce->val4) >= 0 ) {
|
|
@@ -12083,114 +12150,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|
}
|
|
}
|
|
break;
|
|
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,DMG_NORMAL,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;
|
|
|
|
-
|
|
|
|
- case SC_LEECHESEND:
|
|
|
|
- if( --(sce->val4) >= 0 ) {
|
|
|
|
- int damage = status->vit * (sce->val1 - 3) + status->max_hp / 100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100)
|
|
|
|
-
|
|
|
|
- if (sce->val2 && bl->type == BL_MOB) {
|
|
|
|
- struct block_list *src2 = map_id2bl(sce->val2);
|
|
|
|
-
|
|
|
|
- if (src2)
|
|
|
|
- mob_log_damage((TBL_MOB*)bl, src2, damage);
|
|
|
|
- }
|
|
|
|
- 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,DMG_NORMAL,0), 0);
|
|
|
|
- unit_skillcastcancel(bl, 2);
|
|
|
|
- if (sc->data[type]) {
|
|
|
|
- sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
|
|
|
|
- }
|
|
|
|
- map_freeblock_unlock();
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case SC_MAGICMUSHROOM:
|
|
|
|
- if( --(sce->val4) >= 0 ) {
|
|
|
|
- bool flag = 0;
|
|
|
|
- int damage = status->max_hp * 3 / 100;
|
|
|
|
- if( status->hp <= damage )
|
|
|
|
- damage = status->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();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (sce->val2 && bl->type == BL_MOB) {
|
|
|
|
- struct block_list *src2 = map_id2bl(sce->val2);
|
|
|
|
-
|
|
|
|
- if (src2)
|
|
|
|
- mob_log_damage((TBL_MOB*)bl, src2, damage);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if( !flag ) { // Random Skill Cast
|
|
|
|
- if (skill_magicmushroom_count && sd && !pc_issit(sd)) { // Can't cast if sit
|
|
|
|
- int mushroom_skill_id = 0, checked = 0, checked_max = MAX_SKILL_MAGICMUSHROOM_DB * 3;
|
|
|
|
- unit_stop_attack(bl);
|
|
|
|
- unit_skillcastcancel(bl,1);
|
|
|
|
- do {
|
|
|
|
- int i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB;
|
|
|
|
- mushroom_skill_id = skill_magicmushroom_db[i].skill_id;
|
|
|
|
- }
|
|
|
|
- while( checked++ < checked_max && mushroom_skill_id == 0 );
|
|
|
|
-
|
|
|
|
- if (!skill_get_index(mushroom_skill_id))
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- 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;
|
|
|
|
-
|
|
|
|
- case SC_TOXIN:
|
|
|
|
- if( --(sce->val4) >= 0 ) { // Damage is every 10 seconds including 3%sp drain.
|
|
|
|
- if (sce->val2 && bl->type == BL_MOB) {
|
|
|
|
- struct block_list *src2 = map_id2bl(sce->val2);
|
|
|
|
-
|
|
|
|
- if (src2)
|
|
|
|
- mob_log_damage((TBL_MOB*)bl, src2, 1);
|
|
|
|
- }
|
|
|
|
- map_freeblock_lock();
|
|
|
|
- clif_damage(bl,bl,tick,status_get_amotion(bl),1,1,0,DMG_NORMAL,0);
|
|
|
|
- status_damage(NULL, bl, 1, status->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:
|
|
case SC_OBLIVIONCURSE:
|
|
if( --(sce->val4) >= 0 ) {
|
|
if( --(sce->val4) >= 0 ) {
|
|
clif_emotion(bl,E_WHAT);
|
|
clif_emotion(bl,E_WHAT);
|
|
@@ -12225,24 +12184,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|
}
|
|
}
|
|
break;
|
|
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)
|
|
|
|
-
|
|
|
|
- if (src && bl->type == BL_MOB)
|
|
|
|
- mob_log_damage((TBL_MOB*)bl, src, damage);
|
|
|
|
- map_freeblock_lock();
|
|
|
|
- clif_damage(bl,bl,tick,0,0,damage,1,DMG_MULTI_HIT_ENDURE,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(2000 + tick, status_change_timer, bl->id, data);
|
|
|
|
- }
|
|
|
|
- map_freeblock_unlock();
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
case SC_FEAR:
|
|
case SC_FEAR:
|
|
if( --(sce->val4) >= 0 ) {
|
|
if( --(sce->val4) >= 0 ) {
|
|
if( sce->val2 > 0 )
|
|
if( sce->val2 > 0 )
|
|
@@ -12657,8 +12598,19 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- // Default for all non-handled control paths is to end the status
|
|
|
|
|
|
+ // If status has an interval and there is at least 100ms remaining time, wait for next interval
|
|
|
|
+ if(interval > 0 && sc->data[type] && sce->val4 >= 100) {
|
|
|
|
+ sc_timer_next(min(sce->val4,interval)+tick, status_change_timer, bl->id, data);
|
|
|
|
+ sce->val4 -= interval;
|
|
|
|
+ if (dounlock)
|
|
|
|
+ map_freeblock_unlock();
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ if (dounlock)
|
|
|
|
+ map_freeblock_unlock();
|
|
|
|
+
|
|
|
|
+ // Default for all non-handled control paths is to end the status
|
|
return status_change_end( bl,type,tid );
|
|
return status_change_end( bl,type,tid );
|
|
#undef sc_timer_next
|
|
#undef sc_timer_next
|
|
}
|
|
}
|
|
@@ -12965,7 +12917,7 @@ int status_change_spread(struct block_list *src, struct block_list *bl, bool typ
|
|
{
|
|
{
|
|
int i, flag = 0;
|
|
int i, flag = 0;
|
|
struct status_change *sc = status_get_sc(src);
|
|
struct status_change *sc = status_get_sc(src);
|
|
- const struct TimerData *timer;
|
|
|
|
|
|
+ const struct TimerData *timer = NULL;
|
|
unsigned int tick;
|
|
unsigned int tick;
|
|
struct status_change_data data;
|
|
struct status_change_data data;
|
|
|
|
|
|
@@ -12981,6 +12933,11 @@ int status_change_spread(struct block_list *src, struct block_list *bl, bool typ
|
|
for( i = SC_COMMON_MIN; i < SC_MAX; i++ ) {
|
|
for( i = SC_COMMON_MIN; i < SC_MAX; i++ ) {
|
|
if( !sc->data[i] || i == SC_COMMON_MAX )
|
|
if( !sc->data[i] || i == SC_COMMON_MAX )
|
|
continue;
|
|
continue;
|
|
|
|
+ if (sc->data[i]->timer != INVALID_TIMER) {
|
|
|
|
+ timer = get_timer(sc->data[i]->timer);
|
|
|
|
+ if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick, tick) < 0)
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
|
|
switch( i ) {
|
|
switch( i ) {
|
|
// Debuffs that can be spread.
|
|
// Debuffs that can be spread.
|
|
@@ -13009,44 +12966,29 @@ int status_change_spread(struct block_list *src, struct block_list *bl, bool typ
|
|
//case SC_BITE:
|
|
//case SC_BITE:
|
|
case SC_FREEZING:
|
|
case SC_FREEZING:
|
|
case SC_VENOMBLEED:
|
|
case SC_VENOMBLEED:
|
|
- if( sc->data[i]->timer != INVALID_TIMER ) {
|
|
|
|
- timer = get_timer(sc->data[i]->timer);
|
|
|
|
- if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick,tick) < 0)
|
|
|
|
- continue;
|
|
|
|
- data.tick = DIFF_TICK(timer->tick,tick);
|
|
|
|
- } else
|
|
|
|
|
|
+ if (sc->data[i]->timer != INVALID_TIMER)
|
|
|
|
+ data.tick = DIFF_TICK(timer->tick, tick);
|
|
|
|
+ else
|
|
data.tick = INVALID_TIMER;
|
|
data.tick = INVALID_TIMER;
|
|
break;
|
|
break;
|
|
// Special cases
|
|
// Special cases
|
|
- case SC_POISON:
|
|
|
|
- case SC_DPOISON:
|
|
|
|
- data.tick = sc->data[i]->val3 * 1000;
|
|
|
|
- break;
|
|
|
|
|
|
+ case SC_TOXIN:
|
|
|
|
+ case SC_MAGICMUSHROOM:
|
|
|
|
+ case SC_PYREXIA:
|
|
case SC_LEECHESEND:
|
|
case SC_LEECHESEND:
|
|
if (type)
|
|
if (type)
|
|
continue;
|
|
continue;
|
|
- case SC_FEAR:
|
|
|
|
- data.tick = sc->data[i]->val4 * 1000;
|
|
|
|
- break;
|
|
|
|
|
|
+ case SC_POISON:
|
|
|
|
+ case SC_DPOISON:
|
|
|
|
+ case SC_BLEEDING:
|
|
case SC_BURNING:
|
|
case SC_BURNING:
|
|
- data.tick = sc->data[i]->val4 * 2000;
|
|
|
|
- break;
|
|
|
|
- case SC_PYREXIA:
|
|
|
|
- if (type)
|
|
|
|
- continue;
|
|
|
|
- //case SC_OBLIVIONCURSE: // Players are not affected by Oblivion Curse.
|
|
|
|
- data.tick = sc->data[i]->val4 * 3000;
|
|
|
|
- break;
|
|
|
|
- case SC_MAGICMUSHROOM:
|
|
|
|
- if (type)
|
|
|
|
- continue;
|
|
|
|
- data.tick = sc->data[i]->val4 * 4000;
|
|
|
|
|
|
+ if (sc->data[i]->timer != INVALID_TIMER)
|
|
|
|
+ data.tick = DIFF_TICK(timer->tick, tick) + sc->data[i]->val4;
|
|
|
|
+ else
|
|
|
|
+ data.tick = INVALID_TIMER;
|
|
break;
|
|
break;
|
|
- case SC_TOXIN:
|
|
|
|
- if (type)
|
|
|
|
- continue;
|
|
|
|
- case SC_BLEEDING:
|
|
|
|
- data.tick = sc->data[i]->val4 * 10000;
|
|
|
|
|
|
+ case SC_FEAR:
|
|
|
|
+ data.tick = sc->data[i]->val4 * 1000;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
continue;
|
|
continue;
|