소스 검색

Status changes that cause damage reworked (fixes #1033, fixes #448)
* Created a better structure for status changes with intervals and integrated the status changes Stone, Poison, Deadly Poison, Bleeding, Magic Mushroom, Burning, Pyrexia, Leech's End and Toxin into the new structure
-- The exact remaining duration of these status changes will now be stored
-- The correct duration is reloaded when logging back in, you can't avoid a single tick be re-logging
-- It will now show the correct duration on the icon of the status change after re-logging, no longer negative values
-- The durations are now accurately transferred when using Deadly Infect
-- These status changes now use unified code, which makes it much easier to integrate more status changes into this structure with low risk of breaking something
* Removed all the status change specific logging of damage and integrated it into the normal logging behavior
-- The following skills deal "No source" damage: Stone, Poison, Deadly Poison, Bleeding, Coma, Magic Mushroom
-- The following skills deal "Self" damage: Burning, Pyrexia, Leech's End, Toxin
-- "No source" will neither be logged nor contribute to the total damage, your exp share doesn't increase from the damage, but it also won't cause the monster to give less EXP, it won't break freeze or similar status changes, it won't make you stand up, it won't make you stop moving, it won't prevent you from logging out
-- "Self" damage will now be logged and contribute to the total damage, it makes monster give the exp tap bonus, but also makes monsters give less exp the more "self damage" they've taken, it will break freeze and similar status changes, it will make you stand up properly now, it will make you flinch and stop moving, it will prevent you from logging out, but angry type monsters will not lose their aggressive bit from it and it will not cause monsters to use their rude-attack skill
-- Monsters will now use their rude-attack skill on the first rude-attack as long as the damage does not come from self
-- When a monster takes damage from a status change, its HP meter will now be updated
* Burning now has an interval of 3s and a minimum duration of 10s
* Pyrexia now causes blind for Pyrexia's duration instead of just 30s
* Ground Drift's poison base duration is now 60s in pre-re (follow-up to e7150ee)
* Fixed a bug where the minimum duration failed to apply when the received duration was below 1ms
* map_foreachindir and map_foreachinshootarea will now properly print their function names in case of an error
* Updated documentation (transferring source ID is no longer required, remaining tick should now always be in val4)

If this breaks anything, please report asap.

Playtester 9 년 전
부모
커밋
a6f73a6227
9개의 변경된 파일257개의 추가작업 그리고 304개의 파일을 삭제
  1. 1 1
      db/pre-re/skill_cast_db.txt
  2. 17 17
      doc/status_change.txt
  3. 2 2
      src/map/map.c
  4. 28 19
      src/map/mob.c
  5. 1 0
      src/map/mob.h
  6. 1 1
      src/map/pc.c
  7. 2 2
      src/map/skill.c
  8. 204 262
      src/map/status.c
  9. 1 0
      src/map/status.h

+ 1 - 1
db/pre-re/skill_cast_db.txt

@@ -859,7 +859,7 @@
 //-- GS_FULLBUSTER
 //-- GS_FULLBUSTER
 519,0,1200:1400:1600:1800:2000:2200:2400:2600:2800:3000,0,0,10000,0
 519,0,1200:1400:1600:1800:2000:2200:2400:2600:2800:3000,0,0,10000,0
 //-- GS_GROUNDDRIFT (Upkeep2 times are duration of: Stun(lv1), Blind(lv2), Poison(lv3) and Freeze(lv4))
 //-- GS_GROUNDDRIFT (Upkeep2 times are duration of: Stun(lv1), Blind(lv2), Poison(lv3) and Freeze(lv4))
-521,2000,0,0,3000:6000:9000:12000:15000:18000:21000:24000:27000:30000,5000:30000:30000:12000,0
+521,2000,0,0,3000:6000:9000:12000:15000:18000:21000:24000:27000:30000,5000:30000:60000:12000,0
 //==========================================
 //==========================================
 
 
 
 

+ 17 - 17
doc/status_change.txt

@@ -25,9 +25,9 @@
 SC_STONE	()
 SC_STONE	()
 	desc: DEF -50%; if HP>25% lose 1% HP/5 sec; MDEF +25%; change element to Earth Lv 1; ignore Steal & Lex Aeterna; can't move/attack/pick item/use item/use skill/sit/logout
 	desc: DEF -50%; if HP>25% lose 1% HP/5 sec; MDEF +25%; change element to Earth Lv 1; ignore Steal & Lex Aeterna; can't move/attack/pick item/use item/use skill/sit/logout
 	val1:
 	val1:
-	val2: Caster's object ID (for mob_log_damage)
-	val3: Tick
-	val4: Petrifying tick
+	val2: Caster's object ID
+	val3: Incubation time
+	val4: Remaining tick
 
 
 SC_FREEZE	()
 SC_FREEZE	()
 	desc: DEF -50%; FLEE = 0; MDEF +25%; ignore Steal, Lex Aeterna, Storm Gust, Falling Ice Pillar; change element to Water Lv 1; can't move/attack/pick item/use item/sit/logout
 	desc: DEF -50%; FLEE = 0; MDEF +25%; ignore Steal, Lex Aeterna, Storm Gust, Falling Ice Pillar; change element to Water Lv 1; can't move/attack/pick item/use item/sit/logout
@@ -44,9 +44,9 @@ SC_SLEEP	()
 SC_POISON	()
 SC_POISON	()
 	desc: DEF -25%; if HP>25% lose 1.5% + 2 HP/sec; SP Regeneration is disabled
 	desc: DEF -25%; if HP>25% lose 1.5% + 2 HP/sec; SP Regeneration is disabled
 	val1: Skill Level
 	val1: Skill Level
-	val2: Caster's object ID (for mob_log_damage)
-	val3: Tick
-	val4: HP Damage
+	val2: Caster's object ID
+	val3: 
+	val4: Remaining tick
 
 
 SC_CURSE	()
 SC_CURSE	()
 	desc: ATK-25%; LUK = 0; Movement speed -300
 	desc: ATK-25%; LUK = 0; Movement speed -300
@@ -69,14 +69,14 @@ SC_BLEEDING	(SI_BLEEDING)
 	val1: Skill Level
 	val1: Skill Level
 	val2: Caster's object ID (for mob_log_damage)
 	val2: Caster's object ID (for mob_log_damage)
 	val3:
 	val3:
-	val4: Tick
+	val4: Remaining tick
 
 
 SC_DPOISON	()
 SC_DPOISON	()
 	desc: DEF -25%; if HP>25% lose 10/15% HP/sec
 	desc: DEF -25%; if HP>25% lose 10/15% HP/sec
 	val1: Skill Level
 	val1: Skill Level
 	val2: Caster's object ID (for mob_log_damage)
 	val2: Caster's object ID (for mob_log_damage)
-	val3: Tick
-	val4: HP Damage
+	val3: 
+	val4: Remaining tick
 
 
 SC_PROVOKE	(SI_PROVOKE)
 SC_PROVOKE	(SI_PROVOKE)
 	desc: Decrease DEF by (5+(5*Skill Lv))%; Increase ATK by (2+(3*Skill lv))%
 	desc: Decrease DEF by (5+(5*Skill Lv))%; Increase ATK by (2+(3*Skill lv))%
@@ -1283,7 +1283,7 @@ SC_BURNING	(SI_BURNT)
 	val1: Skill Level
 	val1: Skill Level
 	val2: 1000
 	val2: 1000
 	val3: Caster's object ID (for mob_log_damage)
 	val3: Caster's object ID (for mob_log_damage)
-	val4: Tick
+	val4: Remaining tick
 
 
 SC_FREEZING	()
 SC_FREEZING	()
 	desc:
 	desc:
@@ -1519,9 +1519,9 @@ SC_ROLLINGCUTTER	()
 SC_TOXIN	(SI_TOXIN)
 SC_TOXIN	(SI_TOXIN)
 	desc: Inflict damage, which causes the affected entity to flinch every 10 seconds; This will interrupt the skill casting, even if protected against it
 	desc: Inflict damage, which causes the affected entity to flinch every 10 seconds; This will interrupt the skill casting, even if protected against it
 	val1: GC_WEAPONRESEARCH Skill Level
 	val1: GC_WEAPONRESEARCH Skill Level
-	val2: Caster's object ID (for mob_log_damage)
+	val2: Caster's object ID
 	val3:
 	val3:
-	val4: Tick
+	val4: Remaining tick
 
 
 SC_PARALYSE	(SI_PARALYSE)
 SC_PARALYSE	(SI_PARALYSE)
 	desc: Decrease both ASPD and Flee Rate by 10% and halve Movement Speed, which does not stack with Decrease AGI, Quagmire, Marsh Of Abyss or Freezing status
 	desc: Decrease both ASPD and Flee Rate by 10% and halve Movement Speed, which does not stack with Decrease AGI, Quagmire, Marsh Of Abyss or Freezing status
@@ -1540,9 +1540,9 @@ SC_VENOMBLEED	(SI_VENOMBLEED)
 SC_MAGICMUSHROOM	(SI_MAGICMUSHROOM)
 SC_MAGICMUSHROOM	(SI_MAGICMUSHROOM)
 	desc: Force the affected entity to use /heh emote, to randomly use skills and drain 3% of Max HP every 4 seconds
 	desc: Force the affected entity to use /heh emote, to randomly use skills and drain 3% of Max HP every 4 seconds
 	val1: GC_WEAPONRESEARCH Skill Level
 	val1: GC_WEAPONRESEARCH Skill Level
-	val2: Caster's object ID (for mob_log_damage)
+	val2: Caster's object ID
 	val3:
 	val3:
-	val4: Tick
+	val4: Remaining tick
 
 
 SC_DEATHHURT	(SI_DEATHHURT)
 SC_DEATHHURT	(SI_DEATHHURT)
 	desc: Drop the healing effectiveness by 20%; This effect stacks with Critical Wounds
 	desc: Drop the healing effectiveness by 20%; This effect stacks with Critical Wounds
@@ -1556,7 +1556,7 @@ SC_PYREXIA	(SI_PYREXIA)
 	val1: GC_WEAPONRESEARCH Skill Level
 	val1: GC_WEAPONRESEARCH Skill Level
 	val2:
 	val2:
 	val3:
 	val3:
-	val4: Tick
+	val4: Remaining tick
 
 
 SC_OBLIVIONCURSE	(SI_OBLIVIONCURSE)
 SC_OBLIVIONCURSE	(SI_OBLIVIONCURSE)
 	desc: Force the affected entity to use /? emote, block SP Recovery and cause Oblivion status; There is a chance (100% - (Target INT * 0.8)%) of being inflicted, with a minimum of 5%
 	desc: Force the affected entity to use /? emote, block SP Recovery and cause Oblivion status; There is a chance (100% - (Target INT * 0.8)%) of being inflicted, with a minimum of 5%
@@ -1568,9 +1568,9 @@ SC_OBLIVIONCURSE	(SI_OBLIVIONCURSE)
 SC_LEECHESEND	(SI_LEECHESEND)
 SC_LEECHESEND	(SI_LEECHESEND)
 	desc: Drain (Target VIT * (SkillLv - 3)) + (Target HP / 100) HP each second
 	desc: Drain (Target VIT * (SkillLv - 3)) + (Target HP / 100) HP each second
 	val1: GC_WEAPONRESEARCH Skill Level
 	val1: GC_WEAPONRESEARCH Skill Level
-	val2: Caster's object ID (for mob_log_damage)
+	val2: Caster's object ID
 	val3:
 	val3:
-	val4: Tick
+	val4: Remaining tick
 
 
 SC_REFLECTDAMAGE	()
 SC_REFLECTDAMAGE	()
 	desc:
 	desc:

+ 2 - 2
src/map/map.c

@@ -795,7 +795,7 @@ int map_foreachinshootarea(int(*func)(struct block_list*, va_list), int16 m, int
 						bl_list[bl_list_count++] = bl;
 						bl_list[bl_list_count++] = bl;
 
 
 	if (bl_list_count >= BL_LIST_MAX)
 	if (bl_list_count >= BL_LIST_MAX)
-		ShowWarning("map_foreachinarea: block count too many!\n");
+		ShowWarning("map_foreachinshootarea: block count too many!\n");
 
 
 	map_freeblock_lock();
 	map_freeblock_lock();
 
 
@@ -1423,7 +1423,7 @@ int map_foreachindir(int(*func)(struct block_list*, va_list), int16 m, int16 x0,
 	}
 	}
 
 
 	if( bl_list_count >= BL_LIST_MAX )
 	if( bl_list_count >= BL_LIST_MAX )
-		ShowWarning("map_foreachinpath: block count too many!\n");
+		ShowWarning("map_foreachindir: block count too many!\n");
 
 
 	map_freeblock_lock();
 	map_freeblock_lock();
 
 

+ 28 - 19
src/map/mob.c

@@ -40,7 +40,7 @@
 #define MOB_LAZYMOVEPERC(md) (md->state.spotted?1000:0)
 #define MOB_LAZYMOVEPERC(md) (md->state.spotted?1000:0)
 #define MOB_MAX_DELAY (24*3600*1000)
 #define MOB_MAX_DELAY (24*3600*1000)
 #define MAX_MINCHASE 30	//Max minimum chase value to use for mobs.
 #define MAX_MINCHASE 30	//Max minimum chase value to use for mobs.
-#define RUDE_ATTACKED_COUNT 2	//After how many rude-attacks should the skill be used?
+#define RUDE_ATTACKED_COUNT 1	//After how many rude-attacks should the skill be used?
 #define MAX_MOB_CHAT 50 //Max Skill's messages
 #define MAX_MOB_CHAT 50 //Max Skill's messages
 
 
 // On official servers, monsters will only seek targets that are closer to walk to than their
 // On official servers, monsters will only seek targets that are closer to walk to than their
@@ -1565,7 +1565,8 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
 				   )
 				   )
 				) )
 				) )
 			{ // Rude attacked
 			{ // Rude attacked
-				if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT
+				if (abl->id != md->bl.id //Self damage does not cause rude attack
+				&& md->state.attacked_count++ >= RUDE_ATTACKED_COUNT				
 				&& !mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move
 				&& !mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move
 				&& !tbl && unit_escape(&md->bl, abl, rnd()%10 +1))
 				&& !tbl && unit_escape(&md->bl, abl, rnd()%10 +1))
 				{	//Escaped.
 				{	//Escaped.
@@ -2041,8 +2042,6 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
 		return; //Do nothing for absorbed damage.
 		return; //Do nothing for absorbed damage.
 	if( !damage && !(src->type&DEFAULT_ENEMY_TYPE(md)) )
 	if( !damage && !(src->type&DEFAULT_ENEMY_TYPE(md)) )
 		return; //Do not log non-damaging effects from non-enemies.
 		return; //Do not log non-damaging effects from non-enemies.
-	if( src->id == md->bl.id )
-		return; //Do not log self-damage.
 
 
 	switch( src->type )
 	switch( src->type )
 	{
 	{
@@ -2116,6 +2115,12 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
 			md->attacked_id = src->id;
 			md->attacked_id = src->id;
 	}
 	}
 
 
+	//Self damage increases tap bonus
+	if (!char_id && src->id == md->bl.id) {
+		char_id = src->id;
+		flag = MDLF_SELF;
+	}
+
 	if( char_id )
 	if( char_id )
 	{ //Log damage...
 	{ //Log damage...
 		int i,minpos;
 		int i,minpos;
@@ -2154,28 +2159,24 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
 //Call when a mob has received damage.
 //Call when a mob has received damage.
 void mob_damage(struct mob_data *md, struct block_list *src, int damage)
 void mob_damage(struct mob_data *md, struct block_list *src, int damage)
 {
 {
-	if (damage > 0) { //Store total damage...
+	if (src && damage > 0) { //Store total damage...
 		if (UINT_MAX - (unsigned int)damage > md->tdmg)
 		if (UINT_MAX - (unsigned int)damage > md->tdmg)
-			md->tdmg+=damage;
+			md->tdmg += damage;
 		else if (md->tdmg == UINT_MAX)
 		else if (md->tdmg == UINT_MAX)
 			damage = 0; //Stop recording damage once the cap has been reached.
 			damage = 0; //Stop recording damage once the cap has been reached.
 		else { //Cap damage log...
 		else { //Cap damage log...
 			damage = (int)(UINT_MAX - md->tdmg);
 			damage = (int)(UINT_MAX - md->tdmg);
 			md->tdmg = UINT_MAX;
 			md->tdmg = UINT_MAX;
 		}
 		}
-		if (md->state.aggressive) //No longer aggressive, change to retaliate AI.
+		if ((src != &md->bl) && md->state.aggressive) //No longer aggressive, change to retaliate AI.
 			md->state.aggressive = 0;
 			md->state.aggressive = 0;
 		//Log damage
 		//Log damage
-		if (src)
-			mob_log_damage(md, src, damage);
+		mob_log_damage(md, src, damage);
 		md->dmgtick = gettick();
 		md->dmgtick = gettick();
 	}
 	}
 
 
 	if (battle_config.show_mob_info&3)
 	if (battle_config.show_mob_info&3)
-		clif_charnameack (0, &md->bl);
-
-	if (!src)
-		return;
+		clif_charnameack(0, &md->bl);
 
 
 #if PACKETVER >= 20120404
 #if PACKETVER >= 20120404
 	if( battle_config.monster_hp_bars_info){
 	if( battle_config.monster_hp_bars_info){
@@ -2188,6 +2189,9 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage)
 	}
 	}
 #endif
 #endif
 
 
+	if (!src)
+		return;
+
 	if( md->special_state.ai == AI_SPHERE ) {//LOne WOlf explained that ANYONE can trigger the marine countdown skill. [Skotlex]
 	if( md->special_state.ai == AI_SPHERE ) {//LOne WOlf explained that ANYONE can trigger the marine countdown skill. [Skotlex]
 		md->state.alchemist = 1;
 		md->state.alchemist = 1;
 		mobskill_use(md, gettick(), MSC_ALCHEMIST);
 		mobskill_use(md, gettick(), MSC_ALCHEMIST);
@@ -2241,18 +2245,23 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 	// filter out entries not eligible for exp distribution
 	// filter out entries not eligible for exp distribution
 	memset(tmpsd,0,sizeof(tmpsd));
 	memset(tmpsd,0,sizeof(tmpsd));
 	for(i = 0, count = 0, mvp_damage = 0; i < DAMAGELOG_SIZE && md->dmglog[i].id; i++) {
 	for(i = 0, count = 0, mvp_damage = 0; i < DAMAGELOG_SIZE && md->dmglog[i].id; i++) {
-		struct map_session_data* tsd = map_charid2sd(md->dmglog[i].id);
-
-		if(tsd == NULL)
+		struct map_session_data* tsd = NULL;
+		if (md->dmglog[i].flag == MDLF_SELF) {
+			//Self damage counts as exp tap
+			count++;
+			continue;
+		}
+		tsd = map_charid2sd(md->dmglog[i].id);
+		if (tsd == NULL)
 			continue; // skip empty entries
 			continue; // skip empty entries
-		if(tsd->bl.m != m)
+		if (tsd->bl.m != m)
 			continue; // skip players not on this map
 			continue; // skip players not on this map
 		count++; //Only logged into same map chars are counted for the total.
 		count++; //Only logged into same map chars are counted for the total.
 		if (pc_isdead(tsd))
 		if (pc_isdead(tsd))
 			continue; // skip dead players
 			continue; // skip dead players
-		if(md->dmglog[i].flag == MDLF_HOMUN && !hom_is_active(tsd->hd))
+		if (md->dmglog[i].flag == MDLF_HOMUN && !hom_is_active(tsd->hd))
 			continue; // skip homunc's share if inactive
 			continue; // skip homunc's share if inactive
-		if( md->dmglog[i].flag == MDLF_PET && (!tsd->status.pet_id || !tsd->pd) )
+		if (md->dmglog[i].flag == MDLF_PET && (!tsd->status.pet_id || !tsd->pd))
 			continue; // skip pet's share if inactive
 			continue; // skip pet's share if inactive
 
 
 		if(md->dmglog[i].dmg > mvp_damage) {
 		if(md->dmglog[i].dmg > mvp_damage) {

+ 1 - 0
src/map/mob.h

@@ -61,6 +61,7 @@ enum MobDamageLogFlag
 	MDLF_NORMAL = 0,
 	MDLF_NORMAL = 0,
 	MDLF_HOMUN,
 	MDLF_HOMUN,
 	MDLF_PET,
 	MDLF_PET,
+	MDLF_SELF
 };
 };
 
 
 enum size {
 enum size {

+ 1 - 1
src/map/pc.c

@@ -7312,7 +7312,7 @@ void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int h
 	if (hp) clif_updatestatus(sd,SP_HP);
 	if (hp) clif_updatestatus(sd,SP_HP);
 	else return;
 	else return;
 
 
-	if( !src || src == &sd->bl )
+	if (!src)
 		return;
 		return;
 
 
 	if( pc_issit(sd) ) {
 	if( pc_issit(sd) ) {

+ 2 - 2
src/map/skill.c

@@ -7053,7 +7053,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 				break;
 				break;
 			}
 			}
 			if (sc_start4(src,bl,type,(skill_lv*4+20)+brate,
 			if (sc_start4(src,bl,type,(skill_lv*4+20)+brate,
-				skill_lv, src->id, 0, skill_get_time(skill_id, skill_lv),
+				skill_lv, src->id, skill_get_time(skill_id, skill_lv), 0,
 				skill_get_time2(skill_id,skill_lv)))
 				skill_get_time2(skill_id,skill_lv)))
 					clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
 					clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
 			else if(sd) {
 			else if(sd) {
@@ -13412,7 +13412,7 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, uns
 
 
 		case UNT_VENOMDUST:
 		case UNT_VENOMDUST:
 			if(tsc && !tsc->data[type])
 			if(tsc && !tsc->data[type])
-				status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),SCSTART_NONE);
+				status_change_start(ss,bl,type,10000,sg->skill_lv,sg->src_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),SCSTART_NONE);
 			break;
 			break;
 
 
 		case UNT_LANDMINE:
 		case UNT_LANDMINE:

+ 204 - 262
src/map/status.c

@@ -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;

+ 1 - 0
src/map/status.h

@@ -2150,6 +2150,7 @@ struct status_change *status_get_sc(struct block_list *bl);
 int status_isdead(struct block_list *bl);
 int status_isdead(struct block_list *bl);
 int status_isimmune(struct block_list *bl);
 int status_isimmune(struct block_list *bl);
 
 
+int status_get_sc_interval(enum sc_type type);
 int status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_type type, int rate, int tick, unsigned char flag);
 int status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_type type, int rate, int tick, unsigned char flag);
 //Short version, receives rate in 1->100 range, and does not uses a flag setting.
 //Short version, receives rate in 1->100 range, and does not uses a flag setting.
 #define sc_start(src, bl, type, rate, val1, tick) status_change_start(src,bl,type,100*(rate),val1,0,0,0,tick,SCSTART_NONE)
 #define sc_start(src, bl, type, rate, val1, tick) status_change_start(src,bl,type,100*(rate),val1,0,0,0,tick,SCSTART_NONE)