Browse Source

- Changed the status_change structure to use dynamic rather than static memory to hold the individual status changes, this should have a noticeable impact on the server's memory consumption.
- Had to add a few 'ugly' flags to status_change since now you can't track SC related information while said SC is not active (happens only for Storm Gust, Joint Beat and Magic Power).
- Since I am unable to fully test, watch out for any bugs~


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11786 54d463be-8e91-2dee-dedb-b68131a5f0ec

skotlex 17 years ago
parent
commit
ddf923dba5
18 changed files with 893 additions and 884 deletions
  1. 6 0
      Changelog-Trunk.txt
  2. 1 1
      src/common/mmo.h
  3. 21 21
      src/map/atcommand.c
  4. 127 135
      src/map/battle.c
  5. 4 4
      src/map/charcommand.c
  6. 14 14
      src/map/chrif.c
  7. 34 35
      src/map/clif.c
  8. 13 12
      src/map/map.c
  9. 9 4
      src/map/map.h
  10. 15 20
      src/map/mob.c
  11. 1 1
      src/map/party.c
  12. 50 47
      src/map/pc.c
  13. 1 1
      src/map/pet.c
  14. 177 177
      src/map/skill.c
  15. 1 1
      src/map/skill.h
  16. 341 332
      src/map/status.c
  17. 5 4
      src/map/status.h
  18. 73 75
      src/map/unit.c

+ 6 - 0
Changelog-Trunk.txt

@@ -3,6 +3,12 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
+2007/11/23
+	* Changed the status_change structure to use dynamic rather than static
+	  memory to hold the individual status changes, this should have a noticeable
+	  impact on the server's memory consumption. However, since this is a pretty
+	  large update (and I am unable to fully test all possible situations
+	  relating to status changes), watch out for any bugs. [Skotlex]
 2007/11/22
 	* Moved the reset of references to after the empty script checks in 
 	  parse_script. (fixes bugreport:222 and bugreport:449)

+ 1 - 1
src/common/mmo.h

@@ -436,7 +436,7 @@ enum {
 	GD_SKILLBASE=10000,
 	GD_APPROVAL=10000,
 	GD_KAFRACONTRACT=10001,
-	GD_GUARDIANRESEARCH=10002,
+	GD_GUARDRESEARCH=10002,
 	GD_GUARDUP=10003,
 	GD_EXTENSION=10004,
 	GD_GLORYGUILD=10005,

+ 21 - 21
src/map/atcommand.c

@@ -4950,7 +4950,7 @@ int atcommand_jail(const int fd, struct map_session_data* sd, const char* comman
 		return -1;
 	}
 
-	if (pl_sd->sc.data[SC_JAILED].timer != -1)
+	if (pl_sd->sc.data[SC_JAILED])
 	{
 		clif_displaymessage(fd, msg_txt(118)); // Player warped in jails.
 		return -1;
@@ -5002,7 +5002,7 @@ int atcommand_unjail(const int fd, struct map_session_data* sd, const char* comm
 		return -1;
 	}
 
-	if (pl_sd->sc.data[SC_JAILED].timer == -1)
+	if (!pl_sd->sc.data[SC_JAILED])
 	{
 		clif_displaymessage(fd, msg_txt(119)); // This player is not in jails.
 		return -1;
@@ -5086,10 +5086,10 @@ int atcommand_jailfor(const int fd, struct map_session_data* sd, const char* com
 	}
 
 	//Added by Coltaro
-	if (pl_sd->sc.count && pl_sd->sc.data[SC_JAILED].timer != -1 && 
-		pl_sd->sc.data[SC_JAILED].val1 != INT_MAX)
+	if(pl_sd->sc.data[SC_JAILED] && 
+		pl_sd->sc.data[SC_JAILED]->val1 != INT_MAX)
   	{	//Update the player's jail time
-		jailtime += pl_sd->sc.data[SC_JAILED].val1;
+		jailtime += pl_sd->sc.data[SC_JAILED]->val1;
 		if (jailtime <= 0) {
 			jailtime = 0;
 			clif_displaymessage(pl_sd->fd, msg_txt(120)); // GM has discharge you.
@@ -5131,23 +5131,23 @@ int atcommand_jailtime(const int fd, struct map_session_data* sd, const char* co
 
 	nullpo_retr(-1, sd);
 	
-	if (!sd->sc.count || sd->sc.data[SC_JAILED].timer == -1) {
+	if (!sd->sc.data[SC_JAILED]) {
 		clif_displaymessage(fd, "You are not in jail."); // You are not in jail.
 		return -1;
 	}
 
-	if (sd->sc.data[SC_JAILED].val1 == INT_MAX) {
+	if (sd->sc.data[SC_JAILED]->val1 == INT_MAX) {
 		clif_displaymessage(fd, "You have been jailed indefinitely.");
 		return 0;
 	}
 
-	if (sd->sc.data[SC_JAILED].val1 <= 0) { // Was not jailed with @jailfor (maybe @jail? or warped there? or got recalled?)
+	if (sd->sc.data[SC_JAILED]->val1 <= 0) { // Was not jailed with @jailfor (maybe @jail? or warped there? or got recalled?)
 		clif_displaymessage(fd, "You have been jailed for an unknown amount of time.");
 		return -1;
 	}
 
 	//Get remaining jail time
-	get_jail_time(sd->sc.data[SC_JAILED].val1,&year,&month,&day,&hour,&minute);
+	get_jail_time(sd->sc.data[SC_JAILED]->val1,&year,&month,&day,&hour,&minute);
 	sprintf(atcmd_output,msg_txt(402),"You will remain",year,month,day,hour,minute); // You will remain in jail for %d years, %d months, %d days, %d hours and %d minutes
 
 	clif_displaymessage(fd, atcmd_output);
@@ -6366,8 +6366,8 @@ int atcommand_npctalk(const int fd, struct map_session_data* sd, const char* com
 	struct npc_data *nd;
 
 	if (sd->sc.count && //no "chatting" while muted.
-		(sd->sc.data[SC_BERSERK].timer!=-1 ||
-		(sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT)))
+		(sd->sc.data[SC_BERSERK] ||
+		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)))
 		return -1;
 
 	if (!message || !*message || sscanf(message, "%23[^,], %99[^\n]", name, mes) < 2) {
@@ -6407,8 +6407,8 @@ int atcommand_pettalk(const int fd, struct map_session_data* sd, const char* com
 	}
 
 	if (sd->sc.count && //no "chatting" while muted.
-		(sd->sc.data[SC_BERSERK].timer!=-1 ||
-		(sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT)))
+		(sd->sc.data[SC_BERSERK] ||
+		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)))
 		return -1;
 
 	if (!message || !*message || sscanf(message, "%99[^\n]", mes) < 1) {
@@ -6670,7 +6670,7 @@ int atcommand_unmute(const int fd, struct map_session_data* sd, const char* comm
 		return -1;
 	}
 
-	if(pl_sd->sc.data[SC_NOCHAT].timer == -1) {
+	if(!pl_sd->sc.data[SC_NOCHAT]) {
 		clif_displaymessage(sd->fd,"Player is not muted");
 		return -1;
 	}
@@ -7175,8 +7175,8 @@ int atcommand_homtalk(const int fd, struct map_session_data* sd, const char* com
 	nullpo_retr(-1, sd);
 
 	if (sd->sc.count && //no "chatting" while muted.
-		(sd->sc.data[SC_BERSERK].timer!=-1 ||
-		(sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT)))
+		(sd->sc.data[SC_BERSERK] ||
+		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)))
 		return -1;
 
 	if ( !merc_is_hom_active(sd->hd) ) {
@@ -7564,7 +7564,7 @@ static int atcommand_mutearea_sub(struct block_list *bl,va_list ap)
 		pl_sd->status.manner -= time;
 		if (pl_sd->status.manner < 0)
 			sc_start(&pl_sd->bl,SC_NOCHAT,100,0,0);
-		else if (pl_sd->sc.count && pl_sd->sc.data[SC_NOCHAT].timer != -1)
+		else if (pl_sd->sc.data[SC_NOCHAT])
 			status_change_end(&pl_sd->bl, SC_NOCHAT, -1);
 	}
 	return 0;
@@ -7617,8 +7617,8 @@ int atcommand_me(const int fd, struct map_session_data* sd, const char* command,
 	memset(atcmd_output, '\0', sizeof(atcmd_output));
 
 	if (sd->sc.count && //no "chatting" while muted.
-		(sd->sc.data[SC_BERSERK].timer!=-1 ||
-		(sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT)))
+		(sd->sc.data[SC_BERSERK] ||
+		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)))
 		return -1;
 
 	if (!message || !*message || sscanf(message, "%199[^\n]", tempmes) < 0) {
@@ -8025,7 +8025,7 @@ int atcommand_main(const int fd, struct map_session_data* sd, const char* comman
 				sd->state.mainchat = 1;
 				clif_displaymessage(fd, msg_txt(380)); // Main chat has been activated.
 			}
-			if (sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT) {
+			if (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) {
 				clif_displaymessage(fd, msg_txt(387));
 				return -1;
 			}
@@ -8474,7 +8474,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
 	if( !message || !*message )
 		return false; // shouldn't happen
 	
-	if( sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCOMMAND )
+	if( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCOMMAND )
 		return true; // so that it won't display as normal message
 	
 	if( battle_config.atc_gmonly != 0 && gmlvl == 0 )

+ 127 - 135
src/map/battle.c

@@ -223,24 +223,24 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag
 	ratio = attr_fix_table[def_lv-1][atk_elem][def_type];
 	if (sc && sc->count)
 	{
-		if(sc->data[SC_VOLCANO].timer!=-1 && atk_elem == ELE_FIRE)
-			ratio += enchant_eff[sc->data[SC_VOLCANO].val1-1];
-		if(sc->data[SC_VIOLENTGALE].timer!=-1 && atk_elem == ELE_WIND)
-			ratio += enchant_eff[sc->data[SC_VIOLENTGALE].val1-1];
-		if(sc->data[SC_DELUGE].timer!=-1 && atk_elem == ELE_WATER)
-			ratio += enchant_eff[sc->data[SC_DELUGE].val1-1];
+		if(sc->data[SC_VOLCANO] && atk_elem == ELE_FIRE)
+			ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1];
+		if(sc->data[SC_VIOLENTGALE] && atk_elem == ELE_WIND)
+			ratio += enchant_eff[sc->data[SC_VIOLENTGALE]->val1-1];
+		if(sc->data[SC_DELUGE] && atk_elem == ELE_WATER)
+			ratio += enchant_eff[sc->data[SC_DELUGE]->val1-1];
 	}
 	if (tsc && tsc->count)
 	{
-		if(tsc->data[SC_ARMOR_ELEMENT].timer!=-1)
+		if(tsc->data[SC_ARMOR_ELEMENT])
 		{
-			if (tsc->data[SC_ARMOR_ELEMENT].val1 == atk_elem)
-				ratio -= tsc->data[SC_ARMOR_ELEMENT].val2;
+			if (tsc->data[SC_ARMOR_ELEMENT]->val1 == atk_elem)
+				ratio -= tsc->data[SC_ARMOR_ELEMENT]->val2;
 			else
-			if (tsc->data[SC_ARMOR_ELEMENT].val3 == atk_elem)
-				ratio -= tsc->data[SC_ARMOR_ELEMENT].val4;
+			if (tsc->data[SC_ARMOR_ELEMENT]->val3 == atk_elem)
+				ratio -= tsc->data[SC_ARMOR_ELEMENT]->val4;
 		}
-		if(tsc->data[SC_SPIDERWEB].timer!=-1 && atk_elem == ELE_FIRE)
+		if(tsc->data[SC_SPIDERWEB] && atk_elem == ELE_FIRE)
 		{	// [Celest]
 			damage <<= 1;
 			status_change_end(target, SC_SPIDERWEB, -1);
@@ -256,7 +256,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 {
 	struct map_session_data *sd = NULL;
 	struct status_change *sc;
-	struct status_change_entry *sci;
+	struct status_change_entry *sce;
 
 	nullpo_retr(0, bl);
 
@@ -290,9 +290,9 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 	
 	if (sc && sc->count) {
 		//First, sc_*'s that reduce damage to 0.
-		if (sc->data[SC_SAFETYWALL].timer!=-1 && flag&BF_SHORT && skill_num != NPC_GUIDEDATTACK
+		if (sc->data[SC_SAFETYWALL] && flag&BF_SHORT && skill_num != NPC_GUIDEDATTACK
 		) {
-			struct skill_unit_group *group = (struct skill_unit_group *)sc->data[SC_SAFETYWALL].val3;
+			struct skill_unit_group *group = (struct skill_unit_group *)sc->data[SC_SAFETYWALL]->val3;
 			if (group) {
 				if (--group->val2<=0)
 					skill_delunitgroup(NULL,group);
@@ -301,82 +301,80 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 			status_change_end(bl,SC_SAFETYWALL,-1);
 		}
 	
-		if(sc->data[SC_AUTOGUARD].timer != -1 && flag&BF_WEAPON &&
+		if((sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON &&
 			!(skill_get_nk(skill_num)&NK_NO_CARDFIX_ATK) &&
-			rand()%100 < sc->data[SC_AUTOGUARD].val2)
+			rand()%100 < sce->val2)
 		{
 			int delay;
-			clif_skill_nodamage(bl,bl,CR_AUTOGUARD,sc->data[SC_AUTOGUARD].val1,1);
+			clif_skill_nodamage(bl,bl,CR_AUTOGUARD,sce->val1,1);
 			// different delay depending on skill level [celest]
-			if (sc->data[SC_AUTOGUARD].val1 <= 5)
+			if (sce->val1 <= 5)
 				delay = 300;
-			else if (sc->data[SC_AUTOGUARD].val1 > 5 && sc->data[SC_AUTOGUARD].val1 <= 9)
+			else if (sce->val1 > 5 && sce->val1 <= 9)
 				delay = 200;
 			else
 				delay = 100;
 			unit_set_walkdelay(bl, gettick(), delay, 1);
 
-			if(sc->data[SC_SHRINK].timer != -1 && rand()%100<5*sc->data[SC_AUTOGUARD].val1)
+			if(sc->data[SC_SHRINK] && rand()%100<5*sce->val1)
 				skill_blown(bl,src,skill_get_blewcount(CR_SHRINK,1),-1,0);
 			return 0;
 		}
 
 // -- moonsoul (chance to block attacks with new Lord Knight skill parrying)
 //
-		if(sc->data[SC_PARRYING].timer != -1 && flag&BF_WEAPON &&
-			rand()%100 < sc->data[SC_PARRYING].val2) {
-			clif_skill_nodamage(bl,bl,LK_PARRYING,sc->data[SC_PARRYING].val1,1);
+		if((sce=sc->data[SC_PARRYING]) && flag&BF_WEAPON &&
+			rand()%100 < sce->val2) {
+			clif_skill_nodamage(bl,bl,LK_PARRYING,sce->val1,1);
 			return 0;
 		}
 		
-		if(sc->data[SC_DODGE].timer != -1 && !sc->opt1 &&
-			(flag&BF_LONG || sc->data[SC_SPURT].timer != -1)
+		if(sc->data[SC_DODGE] && !sc->opt1 &&
+			(flag&BF_LONG || sc->data[SC_SPURT])
 			&& rand()%100 < 20) {
 			if (sd && pc_issit(sd)) pc_setstand(sd); //Stand it to dodge.
 			clif_skill_nodamage(bl,bl,TK_DODGE,1,1);
-			if (sc->data[SC_COMBO].timer == -1)
+			if (!sc->data[SC_COMBO])
 				sc_start4(bl, SC_COMBO, 100, TK_JUMPKICK, src->id, 1, 0, 2000);
 			return 0;
 		}
 
-		if(sc->data[SC_HERMODE].timer != -1 && flag&BF_MAGIC)
+		if(sc->data[SC_HERMODE] && flag&BF_MAGIC)
 			return 0;
 
-		if(sc->data[SC_TATAMIGAESHI].timer != -1 && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG)
+		if(sc->data[SC_TATAMIGAESHI] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG)
 			return 0;
 
-		if(sc->data[SC_KAUPE].timer != -1 &&
-			rand()%100 < sc->data[SC_KAUPE].val2 &&
+		if((sce=sc->data[SC_KAUPE]) &&
+			rand()%100 < sce->val2 &&
 			(src->type == BL_PC || !skill_num))
 		{	//Kaupe only blocks all skills of players.
 			clif_specialeffect(bl, 462, AREA);
 			//Shouldn't end until Breaker's non-weapon part connects.
 			if (skill_num != ASC_BREAKER || !(flag&BF_WEAPON))
-				if (--sc->data[SC_KAUPE].val3 <= 0) //We make it work like Safety Wall, even though it only blocks 1 time.
+				if (--(sce->val3) <= 0) //We make it work like Safety Wall, even though it only blocks 1 time.
 					status_change_end(bl, SC_KAUPE, -1);
 			return 0;
 		}
 
-		if ((sc->data[SC_UTSUSEMI].timer != -1 || sc->data[SC_BUNSINJYUTSU].timer != -1)
+		if (((sce=sc->data[SC_UTSUSEMI]) || sc->data[SC_BUNSINJYUTSU])
 		&& 
 			flag&BF_WEAPON && !(skill_get_nk(skill_num)&NK_NO_CARDFIX_ATK))
 		{
-			if (sc->data[SC_UTSUSEMI].timer != -1) {
+			if (sce) {
 				clif_specialeffect(bl, 462, AREA);
-				skill_blown(src,bl,sc->data[SC_UTSUSEMI].val3,-1,0);
+				skill_blown(src,bl,sce->val3,-1,0);
 			}
 			//Both need to be consumed if they are active.
-			if (sc->data[SC_UTSUSEMI].timer != -1 &&
-				--sc->data[SC_UTSUSEMI].val2 <= 0)
+			if (sce && --(sce->val2) <= 0)
 				status_change_end(bl, SC_UTSUSEMI, -1);
-			if (sc->data[SC_BUNSINJYUTSU].timer != -1 &&
-				--sc->data[SC_BUNSINJYUTSU].val2 <= 0)
+			if ((sce=sc->data[SC_BUNSINJYUTSU]) && --(sce->val2) <= 0)
 				status_change_end(bl, SC_BUNSINJYUTSU, -1);
 			return 0;
 		}
 
 		//Now damage increasing effects
-		if(sc->data[SC_AETERNA].timer!=-1 && skill_num != PF_SOULBURN){
+		if(sc->data[SC_AETERNA] && skill_num != PF_SOULBURN){
 			damage<<=1;
 			//Shouldn't end until Breaker's non-weapon part connects.
 			if (skill_num != ASC_BREAKER || !(flag&BF_WEAPON))
@@ -384,35 +382,33 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 		}
 
 		//Finally damage reductions....
-		if(sc->data[SC_ASSUMPTIO].timer != -1){
+		if(sc->data[SC_ASSUMPTIO]){
 			if(map_flag_vs(bl->m))
 				damage=damage*2/3; //Receive 66% damage
 			else
 				damage>>=1; //Receive 50% damage
 		}
 
-		if(sc->data[SC_DEFENDER].timer != -1 &&
+		if(sc->data[SC_DEFENDER] &&
 			(flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
-			damage=damage*(100-sc->data[SC_DEFENDER].val2)/100;
+			damage=damage*(100-sc->data[SC_DEFENDER]->val2)/100;
 
-		if(sc->data[SC_ADJUSTMENT].timer != -1 &&
+		if(sc->data[SC_ADJUSTMENT] &&
 			(flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
 			damage -= 20*damage/100;
 
-		if(sc->data[SC_FOGWALL].timer != -1) {
+		if(sc->data[SC_FOGWALL]) {
 			if(flag&BF_SKILL) //25% reduction
 				damage -= 25*damage/100;
 			else if ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
 				damage >>= 2; //75% reduction
 		}
 
-		if(sc->data[SC_ARMOR].timer != -1 &&
-			sc->data[SC_ARMOR].val3&flag &&
-			sc->data[SC_ARMOR].val4&flag)
-			//NPC_DEFENDER
-			damage -= damage*sc->data[SC_ARMOR].val2/100;
+		if((sce=sc->data[SC_ARMOR]) && //NPC_DEFENDER
+			sce->val3&flag && sce->val4&flag)
+			damage -= damage*sc->data[SC_ARMOR]->val2/100;
 
-		if(sc->data[SC_ENERGYCOAT].timer!=-1 && flag&BF_WEAPON){
+		if(sc->data[SC_ENERGYCOAT] && flag&BF_WEAPON){
 			struct status_data *status = status_get_status_data(bl);
 			int per = 100*status->sp / status->max_sp -1; //100% should be counted as the 80~99% interval
 			per /=20; //Uses 20% SP intervals.
@@ -423,34 +419,32 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 			damage -= damage * 6 * (1+per) / 100;
 		}
 
-		if(sc->data[SC_REJECTSWORD].timer!=-1 && flag&BF_WEAPON &&
+		if((sce=sc->data[SC_REJECTSWORD]) && flag&BF_WEAPON &&
 			// Fixed the condition check [Aalye]
 			(src->type!=BL_PC || (
 				((TBL_PC *)src)->status.weapon == W_DAGGER ||
 				((TBL_PC *)src)->status.weapon == W_1HSWORD ||
 				((TBL_PC *)src)->status.weapon == W_2HSWORD
-			))
+			)) &&
+			rand()%100 < sce->val2
 		){
-			if(rand()%100 < sc->data[SC_REJECTSWORD].val2){
-				damage = damage*50/100;
-				status_fix_damage(bl,src,damage,clif_damage(bl,src,gettick(),0,0,damage,0,0,0));
-				clif_skill_nodamage(bl,bl,ST_REJECTSWORD,sc->data[SC_REJECTSWORD].val1,1);
-				if((--sc->data[SC_REJECTSWORD].val3)<=0)
-					status_change_end(bl, SC_REJECTSWORD, -1);
-			}
+			damage = damage*50/100;
+			status_fix_damage(bl,src,damage,clif_damage(bl,src,gettick(),0,0,damage,0,0,0));
+			clif_skill_nodamage(bl,bl,ST_REJECTSWORD,sce->val1,1);
+			if(--(sce->val3)<=0)
+				status_change_end(bl, SC_REJECTSWORD, -1);
 		}
 
 		//Finally Kyrie because it may, or not, reduce damage to 0.
-		if(sc->data[SC_KYRIE].timer!=-1 && damage > 0){
-			sci=&sc->data[SC_KYRIE];
-			sci->val2-=damage;
+		if((sce = sc->data[SC_KYRIE]) && damage > 0){
+			sce->val2-=damage;
 			if(flag&BF_WEAPON || skill_num == TF_THROWSTONE){
-				if(sci->val2>=0)
+				if(sce->val2>=0)
 					damage=0;
 				else
-				  	damage=-sci->val2;
+				  	damage=-sce->val2;
 			}
-			if((--sci->val3)<=0 || (sci->val2<=0) || skill_num == AL_HOLYLIGHT)
+			if((--sce->val3)<=0 || (sce->val2<=0) || skill_num == AL_HOLYLIGHT)
 				status_change_end(bl, SC_KYRIE, -1);
 		}
 
@@ -458,9 +452,9 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 
 		//Probably not the most correct place, but it'll do here
 		//(since battle_drain is strictly for players currently)
-		if (sc->data[SC_BLOODLUST].timer != -1 && flag&BF_WEAPON && damage > 0 &&
-			rand()%100 < sc->data[SC_BLOODLUST].val3)
-			status_heal(src, damage*sc->data[SC_BLOODLUST].val4/100, 0, 3);
+		if ((sce=sc->data[SC_BLOODLUST]) && flag&BF_WEAPON && damage > 0 &&
+			rand()%100 < sce->val3)
+			status_heal(src, damage*sce->val4/100, 0, 3);
 
 	}
 	//SC effects from caster side. Currently none.
@@ -611,7 +605,7 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int
 
 	if((skill = pc_checkskill(sd,HT_BEASTBANE)) > 0 && (status->race==RC_BRUTE || status->race==RC_INSECT) ) {
 		damage += (skill * 4);
-		if (sd->sc.data[SC_SPIRIT].timer != -1 && sd->sc.data[SC_SPIRIT].val2 == SL_HUNTER)
+		if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_HUNTER)
 			damage += sd->status.str;
 	}
 
@@ -729,7 +723,7 @@ static int battle_calc_base_damage(struct status_data *status, struct weapon_atk
 		}
 	}
 	
-	if (sc && sc->data[SC_MAXIMIZEPOWER].timer!=-1)
+	if (sc && sc->data[SC_MAXIMIZEPOWER])
 		atkmin = atkmax;
 	
 	//Weapon Damage calculation
@@ -1009,7 +1003,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 		
 		if(tsc)
 		{
-			if (tsc->data[SC_SLEEP].timer!=-1 )
+			if (tsc->data[SC_SLEEP])
 				cri <<=1;
 		}
 		switch (skill_num)
@@ -1040,7 +1034,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 	} else {	//Check for Perfect Hit
 		if(sd && sd->perfect_hit > 0 && rand()%100 < sd->perfect_hit)
 			flag.hit = 1;
-		if (sc && sc->data[SC_FUSION].timer != -1) {
+		if (sc && sc->data[SC_FUSION]) {
 			flag.hit = 1; //SG_FUSION always hit [Komurka]
 			flag.idef = flag.idef2 = 1; //def ignore [Komurka]
 		}
@@ -1053,7 +1047,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 					flag.hit = 1;
 					break;
 				case CR_SHIELDBOOMERANG:
-					if (sc && sc->data[SC_SPIRIT].timer != -1 && sc->data[SC_SPIRIT].val2 == SL_CRUSADER)
+					if (sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_CRUSADER)
 						flag.hit = 1;
 					break;
 				case 0:
@@ -1090,7 +1084,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 		hitrate+= sstatus->hit - flee;
 
 		if(wd.flag&BF_LONG && !skill_num && //Fogwall's hit penalty is only for normal ranged attacks.
-			tsc && tsc->data[SC_FOGWALL].timer!=-1)
+			tsc && tsc->data[SC_FOGWALL])
 			hitrate -= 50;
 
 		if(sd && flag.arrow)
@@ -1166,9 +1160,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 				status_zap(src, wd.damage, 0);//Damage to self is always 9%
 				wd.damage2 = 0;
 
-				if (sc && sc->data[SC_SACRIFICE].timer != -1)
+				if (sc && sc->data[SC_SACRIFICE])
 				{
-					if (--sc->data[SC_SACRIFICE].val2 <= 0)
+					if (--sc->data[SC_SACRIFICE]->val2 <= 0)
 						status_change_end(src, SC_SACRIFICE,-1);
 				}
 				break;
@@ -1221,9 +1215,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 				i = (flag.cri?1:0)|
 					(flag.arrow?2:0)|
 					(skill_num == HW_MAGICCRASHER?4:0)|
-					(!skill_num && sc && sc->data[SC_CHANGE].timer!=-1?4:0)|
+					(!skill_num && sc && sc->data[SC_CHANGE]?4:0)|
 					(skill_num == MO_EXTREMITYFIST?8:0)|
-					(sc && sc->data[SC_WEAPONPERFECTION].timer!=-1?8:0);
+					(sc && sc->data[SC_WEAPONPERFECTION]?8:0);
 				if (flag.arrow && sd)
 				switch(sd->status.weapon) {
 					case W_BOW:
@@ -1267,11 +1261,11 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 		//Skill damage modifiers that stack linearly
 		if(sc && skill_num != PA_SACRIFICE)
 		{
-			if(sc->data[SC_OVERTHRUST].timer != -1)
-				skillratio += 5*sc->data[SC_OVERTHRUST].val1;
-			if(sc->data[SC_MAXOVERTHRUST].timer != -1)
-				skillratio += 20*sc->data[SC_MAXOVERTHRUST].val1;
-			if(sc->data[SC_BERSERK].timer != -1)
+			if(sc->data[SC_OVERTHRUST])
+				skillratio += sc->data[SC_OVERTHRUST]->val2;
+			if(sc->data[SC_MAXOVERTHRUST])
+				skillratio += sc->data[SC_MAXOVERTHRUST]->val2;
+			if(sc->data[SC_BERSERK])
 				skillratio += 100;
 		}
 		if (!skill_num)
@@ -1498,7 +1492,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 					break;
 				case TK_JUMPKICK:
 					skillratio += -70 + 10*skill_lv;
-					if (sc && sc->data[SC_COMBO].timer != -1 && sc->data[SC_COMBO].val1 == skill_num)
+					if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_num)
 						skillratio += 10*status_get_lv(src)/3;
 					break;
 				case GS_TRIPLEACTION:
@@ -1597,29 +1591,29 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 
 		//The following are applied on top of current damage and are stackable.
 		if (sc) {
-			if(sc->data[SC_TRUESIGHT].timer != -1)
-				ATK_ADDRATE(2*sc->data[SC_TRUESIGHT].val1);
+			if(sc->data[SC_TRUESIGHT])
+				ATK_ADDRATE(2*sc->data[SC_TRUESIGHT]->val1);
 
-			if(sc->data[SC_EDP].timer != -1 &&
+			if(sc->data[SC_EDP] &&
 			  	skill_num != ASC_BREAKER &&
 				skill_num != ASC_METEORASSAULT &&
 				skill_num != AS_SPLASHER &&
 				skill_num != AS_VENOMKNIFE)
-				ATK_ADDRATE(sc->data[SC_EDP].val3);
+				ATK_ADDRATE(sc->data[SC_EDP]->val3);
 		}
 
 		switch (skill_num) {
 			case AS_SONICBLOW:
-				if (sc && sc->data[SC_SPIRIT].timer != -1 &&
-					sc->data[SC_SPIRIT].val2 == SL_ASSASIN)
+				if (sc && sc->data[SC_SPIRIT] &&
+					sc->data[SC_SPIRIT]->val2 == SL_ASSASIN)
 					ATK_ADDRATE(map_flag_gvg(src->m)?25:100); //+25% dmg on woe/+100% dmg on nonwoe
 
 				if(sd && pc_checkskill(sd,AS_SONICACCEL)>0)
 					ATK_ADDRATE(10);
 			break;
 			case CR_SHIELDBOOMERANG:
-				if(sc && sc->data[SC_SPIRIT].timer != -1 &&
-					sc->data[SC_SPIRIT].val2 == SL_CRUSADER)
+				if(sc && sc->data[SC_SPIRIT] &&
+					sc->data[SC_SPIRIT]->val2 == SL_CRUSADER)
 					ATK_ADDRATE(100);
 				break;
 		}
@@ -1732,8 +1726,8 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 		//Post skill/vit reduction damage increases
 		if (sc && skill_num != LK_SPIRALPIERCE)
 		{	//SC skill damages
-			if(sc->data[SC_AURABLADE].timer!=-1) 
-				ATK_ADD(20*sc->data[SC_AURABLADE].val1);
+			if(sc->data[SC_AURABLADE]) 
+				ATK_ADD(20*sc->data[SC_AURABLADE]->val1);
 		}
 
 		//Refine bonus
@@ -1767,7 +1761,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 				wd.damage2 = battle_addmastery(sd,target,wd.damage2,1);
 
 			if((skill=pc_checkskill(sd,SG_STAR_ANGER)) >0 && (t_class == sd->hate_mob[2] ||
-				(sc && sc->data[SC_MIRACLE].timer!=-1)))
+				(sc && sc->data[SC_MIRACLE])))
 			{
 				skillratio = sd->status.base_level + sstatus->str + sstatus->dex + sstatus->luk;
 				if (skill<4)
@@ -1814,11 +1808,11 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 		}
 		if (flag.lh && wd.damage2 > 0)
 			wd.damage2 = battle_attr_fix(src,target,wd.damage2,s_ele_,tstatus->def_ele, tstatus->ele_lv);
-		if(sc && sc->data[SC_WATK_ELEMENT].timer != -1)
+		if(sc && sc->data[SC_WATK_ELEMENT])
 		{	//Descriptions indicate this means adding a percent of a normal attack in another element. [Skotlex]
 			int damage= battle_calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, (flag.arrow?2:0));
-			damage = damage*sc->data[SC_WATK_ELEMENT].val2/100;
-			damage = battle_attr_fix(src,target,damage,sc->data[SC_WATK_ELEMENT].val1,tstatus->def_ele, tstatus->ele_lv);
+			damage = damage*sc->data[SC_WATK_ELEMENT]->val2/100;
+			damage = battle_attr_fix(src,target,damage,sc->data[SC_WATK_ELEMENT]->val1,tstatus->def_ele, tstatus->ele_lv);
 			ATK_ADD(damage);
 		}
 	}
@@ -2047,9 +2041,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 		{	// Self weapon breaking
 			int breakrate = battle_config.equip_natural_break_rate;
 			if (sc) {
-				if(sc->data[SC_OVERTHRUST].timer!=-1)
+				if(sc->data[SC_OVERTHRUST])
 					breakrate += 10;
-				if(sc->data[SC_MAXOVERTHRUST].timer!=-1)
+				if(sc->data[SC_MAXOVERTHRUST])
 					breakrate += 10;
 			}
 			if (breakrate)
@@ -2064,9 +2058,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 				breakrate[1] += sd->break_armor_rate;
 			}
 			if (sc) {
-				if (sc->data[SC_MELTDOWN].timer!=-1) {
-					breakrate[0] += sc->data[SC_MELTDOWN].val2;
-					breakrate[1] += sc->data[SC_MELTDOWN].val3;
+				if (sc->data[SC_MELTDOWN]) {
+					breakrate[0] += sc->data[SC_MELTDOWN]->val2;
+					breakrate[1] += sc->data[SC_MELTDOWN]->val3;
 				}
 			}	
 			if (breakrate[0])
@@ -2077,7 +2071,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 	}
 
 	//SG_FUSION hp penalty [Komurka]
-	if (sc && sc->data[SC_FUSION].timer!=-1)
+	if (sc && sc->data[SC_FUSION])
 	{
 		int hp= sstatus->max_hp;
 		if (sd && tsd) {
@@ -2243,7 +2237,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						break;
 					case AL_HOLYLIGHT:
 						skillratio += 25;
-						if (sd && sd->sc.data[SC_SPIRIT].timer != -1 && sd->sc.data[SC_SPIRIT].val2 == SL_PRIEST)
+						if (sd && sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_PRIEST)
 							skillratio *= 5; //Does 5x damage include bonuses from other skills?
 						break;
 					case AL_RUWACH:
@@ -2678,27 +2672,25 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl
 int battle_calc_return_damage(struct block_list* bl, int damage, int flag)
 {
 	struct map_session_data* sd = NULL;
-	struct status_change* sc;
 	int rdamage = 0;
 
 	BL_CAST(BL_PC, bl, sd);
-	sc = status_get_sc(bl);
-	if(sc && !sc->count)
-		sc = NULL;
 
 	//Bounces back part of the damage.
 	if (flag & BF_SHORT) {
+		struct status_change* sc;
 		if (sd && sd->short_weapon_damage_return)
 		{
 			rdamage += damage * sd->short_weapon_damage_return / 100;
 			if(rdamage < 1) rdamage = 1;
 		}
-		if (sc && sc->data[SC_REFLECTSHIELD].timer != -1)
+		sc = status_get_sc(bl);
+		if (sc && sc->data[SC_REFLECTSHIELD])
 		{
-			rdamage += damage * sc->data[SC_REFLECTSHIELD].val2 / 100;
+			rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100;
 			if (rdamage < 1) rdamage = 1;
 		}
-	} else if (flag & BF_LONG) {
+	} else {
 		if (sd && sd->long_weapon_damage_return)
 		{
 			rdamage += damage * sd->long_weapon_damage_return / 100;
@@ -2823,14 +2815,13 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 		}
 	}
 
-	if (sc && sc->data[SC_CLOAKING].timer != -1 && !(sc->data[SC_CLOAKING].val4&2))
+	if (sc && sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4&2))
 		status_change_end(src,SC_CLOAKING,-1);
 
 	//Check for counter attacks that block your attack. [Skotlex]
 	if(tsc)
 	{
-		if(tsc->data[SC_AUTOCOUNTER].timer != -1 &&
-			(!sc || sc->data[SC_AUTOCOUNTER].timer == -1) &&
+		if(tsc->data[SC_AUTOCOUNTER] &&
 			status_check_skilluse(target, src, KN_AUTOCOUNTER, 1)
 		)	{
 			int dir = map_calc_dir(target,src->x,src->y);
@@ -2838,7 +2829,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 			int dist = distance_bl(src, target);
 			if(dist <= 0 || (!map_check_dir(dir,t_dir) && dist <= tstatus->rhw.range+1))
 			{
-				int skilllv = tsc->data[SC_AUTOCOUNTER].val1;
+				int skilllv = tsc->data[SC_AUTOCOUNTER]->val1;
 				clif_skillcastcancel(target); //Remove the casting bar. [Skotlex]
 				clif_damage(src, target, tick, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS.
 				status_change_end(target,SC_AUTOCOUNTER,-1);
@@ -2846,8 +2837,8 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 				return 0;
 			}
 		}
-		if (tsc->data[SC_BLADESTOP_WAIT].timer != -1 && !is_boss(src)) {
-			int skilllv = tsc->data[SC_BLADESTOP_WAIT].val1;
+		if (tsc->data[SC_BLADESTOP_WAIT] && !is_boss(src)) {
+			int skilllv = tsc->data[SC_BLADESTOP_WAIT]->val1;
 			int duration = skill_get_time2(MO_BLADESTOP,skilllv);
 			status_change_end(target, SC_BLADESTOP_WAIT, -1);
 			if(sc_start4(src, SC_BLADESTOP, 100, sd?pc_checkskill(sd, MO_BLADESTOP):5, 0, 0, (int)target, duration))
@@ -2863,9 +2854,9 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 	if(sd && (skillv = pc_checkskill(sd,MO_TRIPLEATTACK)) > 0)
 	{
 		int triple_rate= 30 - skillv; //Base Rate
-		if (sc && sc->data[SC_SKILLRATE_UP].timer!=-1 && sc->data[SC_SKILLRATE_UP].val1 == MO_TRIPLEATTACK)
+		if (sc && sc->data[SC_SKILLRATE_UP] && sc->data[SC_SKILLRATE_UP]->val1 == MO_TRIPLEATTACK)
 		{
-			triple_rate+= triple_rate*(sc->data[SC_SKILLRATE_UP].val2)/100;
+			triple_rate+= triple_rate*(sc->data[SC_SKILLRATE_UP]->val2)/100;
 			status_change_end(src,SC_SKILLRATE_UP,-1);
 		}
 		if (rand()%100 < triple_rate)
@@ -2874,10 +2865,10 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 
 	if (sc)
 	{
-		if (sc->data[SC_SACRIFICE].timer != -1)
-			return skill_attack(BF_WEAPON,src,src,target,PA_SACRIFICE,sc->data[SC_SACRIFICE].val1,tick,0);
-		if (sc->data[SC_MAGICALATTACK].timer != -1)
-			return skill_attack(BF_MAGIC,src,src,target,NPC_MAGICALATTACK,sc->data[SC_MAGICALATTACK].val1,tick,0);
+		if (sc->data[SC_SACRIFICE])
+			return skill_attack(BF_WEAPON,src,src,target,PA_SACRIFICE,sc->data[SC_SACRIFICE]->val1,tick,0);
+		if (sc->data[SC_MAGICALATTACK])
+			return skill_attack(BF_MAGIC,src,src,target,NPC_MAGICALATTACK,sc->data[SC_MAGICALATTACK]->val1,tick,0);
 	}
 
 	wd = battle_calc_weapon_attack(src, target, 0, 0, flag);
@@ -2908,12 +2899,12 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 
 	battle_delay_damage(tick+wd.amotion, src, target, wd.flag, 0, 0, damage, wd.dmg_lv, wd.dmotion);
 
-	if (sc && sc->data[SC_AUTOSPELL].timer != -1 && rand()%100 < sc->data[SC_AUTOSPELL].val4) {
+	if (sc && sc->data[SC_AUTOSPELL] && rand()%100 < sc->data[SC_AUTOSPELL]->val4) {
 		int sp = 0;
-		int skillid = sc->data[SC_AUTOSPELL].val2;
-		int skilllv = sc->data[SC_AUTOSPELL].val3;
+		int skillid = sc->data[SC_AUTOSPELL]->val2;
+		int skilllv = sc->data[SC_AUTOSPELL]->val3;
 		int i = rand()%100;
-		if (sc->data[SC_SPIRIT].timer != -1 && sc->data[SC_SPIRIT].val2 == SL_SAGE)
+		if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_SAGE)
 			i = 0; //Max chance, no skilllv reduction. [Skotlex]
 		if (i >= 50) skilllv -= 2;
 		else if (i >= 15) skilllv--;
@@ -2949,20 +2940,21 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 	}
 
 	if (tsc) {
-		if (tsc->data[SC_POISONREACT].timer != -1 && 
-			(rand()%100 < tsc->data[SC_POISONREACT].val3
+		if (tsc->data[SC_POISONREACT] && 
+			(rand()%100 < tsc->data[SC_POISONREACT]->val3
 			|| sstatus->def_ele == ELE_POISON) &&
 //			check_distance_bl(src, target, tstatus->rhw.range+1) && Doesn't checks range! o.O;
 			status_check_skilluse(target, src, TF_POISON, 0)
 		) {	//Poison React
+			struct status_change_entry *sce = tsc->data[SC_POISONREACT];
 			if (sstatus->def_ele == ELE_POISON) {
-				tsc->data[SC_POISONREACT].val2 = 0;
-				skill_attack(BF_WEAPON,target,target,src,AS_POISONREACT,tsc->data[SC_POISONREACT].val1,tick,0);
+				sce->val2 = 0;
+				skill_attack(BF_WEAPON,target,target,src,AS_POISONREACT,sce->val1,tick,0);
 			} else {
 				skill_attack(BF_WEAPON,target,target,src,TF_POISON, 5, tick, 0);
-				--tsc->data[SC_POISONREACT].val2;
+				--sce->val2;
 			}
-			if (tsc->data[SC_POISONREACT].val2 <= 0)
+			if (sce->val2 <= 0)
 				status_change_end(target, SC_POISONREACT, -1);
 		}
 	}

+ 4 - 4
src/map/charcommand.c

@@ -2830,17 +2830,17 @@ int charcommand_jailtime(const int fd, struct map_session_data* sd, const char*
 		return -1;
 	}
 
-	if (pl_sd->sc.data[SC_JAILED].val1 == INT_MAX) {
+	if (pl_sd->sc.data[SC_JAILED]->val1 == INT_MAX) {
 		clif_displaymessage(fd, "You have been jailed indefinitely.");
 		return 0;
 	}
 
-	if (pl_sd->sc.data[SC_JAILED].val1 <= 0) { // Was not jailed with @jailfor (maybe @jail? or warped there? or got recalled?)
+	if (pl_sd->sc.data[SC_JAILED]->val1 <= 0) { // Was not jailed with @jailfor (maybe @jail? or warped there? or got recalled?)
 		clif_displaymessage(fd, "This player has been jailed for an unknown amount of time.");
 		return -1;
 	}
 	//Get remaining jail time
-	get_jail_time(pl_sd->sc.data[SC_JAILED].val1,&year,&month,&day,&hour,&minute);
+	get_jail_time(pl_sd->sc.data[SC_JAILED]->val1,&year,&month,&day,&hour,&minute);
 	sprintf(output,msg_txt(402),"This player will remain",year,month,day,hour,minute); 
 	clif_displaymessage(fd, output);
 
@@ -3861,7 +3861,7 @@ bool is_charcommand(const int fd, struct map_session_data* sd, const char* messa
 	if( !message || !*message )
 		return false;
 
-	if( sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCOMMAND )
+	if( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCOMMAND )
 		return true; // so that it won't display as normal message
 
 	if( battle_config.atc_gmonly != 0 && gmlvl == 0 )

+ 14 - 14
src/map/chrif.c

@@ -1022,6 +1022,7 @@ int chrif_save_scdata(struct map_session_data *sd)
 	int i, count=0;
 	unsigned int tick;
 	struct status_change_data data;
+	struct status_change *sc = &sd->sc;
 	const struct TimerData *timer;
 
 	if (sd->state.finalsave) //Character was already saved?
@@ -1036,17 +1037,21 @@ int chrif_save_scdata(struct map_session_data *sd)
 	WFIFOL(char_fd,8) = sd->status.char_id;
 	for (i = 0; i < SC_MAX; i++)
 	{
-		if (sd->sc.data[i].timer == -1)
+		if (!sc->data[i])
 			continue;
-		timer = get_timer(sd->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); //Duration that is left before ending.
+		if (sc->data[i]->timer != -1)
+		{
+			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); //Duration that is left before ending.
+		} else
+			data.tick = -1; //Infinite duration
 		data.type = i;
-		data.val1 = sd->sc.data[i].val1;
-		data.val2 = sd->sc.data[i].val2;
-		data.val3 = sd->sc.data[i].val3;
-		data.val4 = sd->sc.data[i].val4;
+		data.val1 = sc->data[i]->val1;
+		data.val2 = sc->data[i]->val2;
+		data.val3 = sc->data[i]->val3;
+		data.val4 = sc->data[i]->val4;
 		memcpy(WFIFOP(char_fd,14 +count*sizeof(struct status_change_data)),
 			&data, sizeof(struct status_change_data));
 		count++;
@@ -1086,11 +1091,6 @@ int chrif_load_scdata(int fd)
 	for (i = 0; i < count; i++)
 	{
 		data = (struct status_change_data*)RFIFOP(fd,14 + i*sizeof(struct status_change_data));
-		if (data->tick < 1)
-		{	//Protection against invalid tick values. [Skotlex]
-			ShowWarning("chrif_load_scdata: Received invalid duration (%d ms) for status change %d (character %s)\n", data->tick, data->type, sd->status.name);
-			continue;
-		}
 		status_change_start(&sd->bl, data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 15);
 	}
 #endif

+ 34 - 35
src/map/clif.c

@@ -3675,11 +3675,11 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic
 
 	sc = status_get_sc(dst);
 	if(sc && sc->count) {
-		if(type != 4 && dst->type == BL_PC && sc->data[SC_ENDURE].timer != -1 && !map_flag_gvg(dst->m))
+		if(type != 4 && dst->type == BL_PC && sc->data[SC_ENDURE] && !map_flag_gvg(dst->m))
 			type = 9;
-		if(sc->data[SC_HALLUCINATION].timer != -1) {
-			if(damage > 0) damage = damage*(5+sc->data[SC_HALLUCINATION].val1) + rand()%100;
-			if(damage2 > 0) damage2 = damage2*(5+sc->data[SC_HALLUCINATION].val1) + rand()%100;
+		if(sc->data[SC_HALLUCINATION]) {
+			if(damage) damage = damage*(sc->data[SC_HALLUCINATION]->val2) + rand()%100;
+			if(damage2) damage2 = damage2*(sc->data[SC_HALLUCINATION]->val2) + rand()%100;
 		}
 	}
 
@@ -4246,10 +4246,10 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int
 
 	sc = status_get_sc(dst);
 	if(sc && sc->count) {
-		if(type != 4 && dst->type == BL_PC && sc->data[SC_ENDURE].timer != -1 && !map_flag_gvg(dst->m))
+		if(type != 4 && dst->type == BL_PC && sc->data[SC_ENDURE] && !map_flag_gvg(dst->m))
 			type = 9;
-		if(sc->data[SC_HALLUCINATION].timer != -1 && damage > 0)
-			damage = damage*(5+sc->data[SC_HALLUCINATION].val1) + rand()%100;
+		if(sc->data[SC_HALLUCINATION] && damage)
+			damage = damage*(sc->data[SC_HALLUCINATION]->val2) + rand()%100;
 	}
 
 #if PACKETVER < 3
@@ -4337,8 +4337,8 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in
 	sc = status_get_sc(dst);
 
 	if(sc && sc->count) {
-		if(sc->data[SC_HALLUCINATION].timer != -1 && damage > 0)
-			damage = damage*(5+sc->data[SC_HALLUCINATION].val1) + rand()%100;
+		if(sc->data[SC_HALLUCINATION] && damage)
+			damage = damage*(sc->data[SC_HALLUCINATION]->val2) + rand()%100;
 	}
 
 	WBUFW(buf,0)=0x115;
@@ -8084,7 +8084,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
 	else if (pc_cant_act(sd))
 		return;
 
-	if(sd->sc.count && sd->sc.data[SC_RUN].timer != -1)
+	if(sd->sc.data[SC_RUN])
 		return;
 
 	pc_delinvincibletimer(sd);
@@ -8109,7 +8109,7 @@ void clif_parse_QuitGame(int fd, struct map_session_data *sd)
 	WFIFOW(fd,0) = 0x18b;
 
 	/*	Rovert's prevent logout option fixed [Valaris]	*/
-	if (sd->sc.data[SC_CLOAKING].timer==-1 && sd->sc.data[SC_HIDING].timer==-1 &&
+	if (!sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] &&
 		(!battle_config.prevent_logout || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout)
 	) {
 		clif_setwaitclose(fd);
@@ -8176,7 +8176,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
 	if( is_atcommand(fd, sd, message) || is_charcommand(fd, sd, message) )
 		return;
 
-	if( sd->sc.data[SC_BERSERK].timer != -1 || (sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT) )
+	if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) )
 		return;
 
 	if( battle_config.min_chat_delay )
@@ -8355,9 +8355,9 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
 	}
 
 	if (sd->sc.count &&
-		(sd->sc.data[SC_TRICKDEAD].timer != -1 ||
-	 	sd->sc.data[SC_AUTOCOUNTER].timer != -1 ||
-		sd->sc.data[SC_BLADESTOP].timer != -1))
+		(sd->sc.data[SC_TRICKDEAD] ||
+	 	sd->sc.data[SC_AUTOCOUNTER] ||
+		sd->sc.data[SC_BLADESTOP]))
 		return;
 
 	pc_stop_walking(sd, 1);
@@ -8404,8 +8404,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
 			break;
 
 		if (sd->sc.count && (
-			sd->sc.data[SC_DANCING].timer != -1 ||
-			(sd->sc.data[SC_GRAVITATION].timer != -1 && sd->sc.data[SC_GRAVITATION].val3 == BCT_SELF)
+			sd->sc.data[SC_DANCING] ||
+			(sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF)
 		)) //No sitting during these states either.
 			break;
 
@@ -8487,7 +8487,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd)
 	if (is_atcommand(fd, sd, message) || is_charcommand(fd, sd, message) )
 		return;
 
-	if (sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT))
+	if (sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))
 		return;
 
 	if (battle_config.min_chat_delay)
@@ -8665,9 +8665,9 @@ void clif_parse_TakeItem(int fd, struct map_session_data *sd)
 			break;
 		
 		if(sd->sc.count && (
-			sd->sc.data[SC_TRICKDEAD].timer != -1 ||
-			sd->sc.data[SC_BLADESTOP].timer != -1 ||
-			(sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOITEM))
+			sd->sc.data[SC_TRICKDEAD] ||
+			sd->sc.data[SC_BLADESTOP] ||
+			(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM))
 		)
 			break;
 
@@ -8696,9 +8696,9 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
 		return;
 
 	if (sd->sc.count && (
-		sd->sc.data[SC_AUTOCOUNTER].timer != -1 ||
-		sd->sc.data[SC_BLADESTOP].timer != -1 ||
-		(sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOITEM)
+		sd->sc.data[SC_AUTOCOUNTER] ||
+		sd->sc.data[SC_BLADESTOP] ||
+		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM)
 	))
 		return;
 
@@ -8768,7 +8768,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
 	else if (pc_cant_act(sd))
 		return;
 
-	if(sd->sc.data[SC_BLADESTOP].timer!=-1 || sd->sc.data[SC_BERSERK].timer!=-1 )
+	if(sd->sc.data[SC_BLADESTOP] || sd->sc.data[SC_BERSERK])
 		return;
 
 	if(!sd->status.inventory[index].identify) {
@@ -8916,7 +8916,7 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd)
 	char s_title[CHATROOM_TITLE_SIZE];
 	char s_password[CHATROOM_PASS_SIZE];
 
-	if (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOROOM)
+	if (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM)
 		return;
 	if(battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 4) {
 		clif_skill_fail(sd,1,0,3);
@@ -9241,10 +9241,10 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
 
 	sd->skillitem = sd->skillitemlv = 0;
 	if (skillnum == MO_EXTREMITYFIST) {
-		if ((sd->sc.data[SC_COMBO].timer == -1 ||
-			(sd->sc.data[SC_COMBO].val1 != MO_COMBOFINISH &&
-			sd->sc.data[SC_COMBO].val1 != CH_TIGERFIST &&
-			sd->sc.data[SC_COMBO].val1 != CH_CHAINCRUSH))) {
+		if ((!sd->sc.data[SC_COMBO] ||
+			(sd->sc.data[SC_COMBO]->val1 != MO_COMBOFINISH &&
+			sd->sc.data[SC_COMBO]->val1 != CH_TIGERFIST &&
+			sd->sc.data[SC_COMBO]->val1 != CH_CHAINCRUSH))) {
 			if (!sd->state.skill_flag ) {
 				sd->state.skill_flag = 1;
 				clif_skillinfo(sd, MO_EXTREMITYFIST, INF_ATTACK_SKILL, -1);
@@ -9256,8 +9256,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
 		}
 	}
 	if (skillnum == TK_JUMPKICK) {
-		if (sd->sc.data[SC_COMBO].timer == -1 ||
-			sd->sc.data[SC_COMBO].val1 != TK_JUMPKICK) {
+		if (!sd->sc.data[SC_COMBO] || sd->sc.data[SC_COMBO]->val1 != TK_JUMPKICK) {
 			if (!sd->state.skill_flag ) {
 				sd->state.skill_flag = 1;
 				clif_skillinfo(sd, TK_JUMPKICK, INF_ATTACK_SKILL, -1);
@@ -9893,7 +9892,7 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd)
 	if( is_atcommand(fd, sd, message) || is_charcommand(fd, sd, message) )
 		return;
 
-	if( sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT) )
+	if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) )
 		return;
 
 	if( battle_config.min_chat_delay )
@@ -9950,7 +9949,7 @@ void clif_parse_OpenVending(int fd, struct map_session_data* sd)
 	bool flag = (bool)RFIFOB(fd,84);
 	const uint8* data = (uint8*)RFIFOP(fd,85);
 
-	if( sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOROOM )
+	if( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM )
 		return;
 	if( map[sd->bl.m].flag.novending || map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOVENDING) ) {
 		clif_displaymessage (sd->fd, msg_txt(276)); // "You can't open shop on this map"
@@ -10165,7 +10164,7 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd)
 	if( is_atcommand(fd, sd, message) || is_charcommand(fd, sd, message) )
 		return;
 
-	if( sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT) )
+	if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) )
 		return;
 
 	if( battle_config.min_chat_delay )

+ 13 - 12
src/map/map.c

@@ -454,17 +454,17 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick)
 		skill_unit_move(bl,tick,2);
 		sc = status_get_sc(bl);
 		if (sc && sc->count) {
-			if (sc->data[SC_CLOSECONFINE].timer != -1)
+			if (sc->data[SC_CLOSECONFINE])
 				status_change_end(bl, SC_CLOSECONFINE, -1);
-			if (sc->data[SC_CLOSECONFINE2].timer != -1)
+			if (sc->data[SC_CLOSECONFINE2])
 				status_change_end(bl, SC_CLOSECONFINE2, -1);
-//			if (sc->data[SC_BLADESTOP].timer != -1) //Won't stop when you are knocked away, go figure...
+//			if (sc->data[SC_BLADESTOP]) //Won't stop when you are knocked away, go figure...
 //				status_change_end(bl, SC_BLADESTOP, -1);
-			if (sc->data[SC_BASILICA].timer != -1)
+			if (sc->data[SC_BASILICA])
 				status_change_end(bl, SC_BASILICA, -1);
-			if (sc->data[SC_TATAMIGAESHI].timer != -1)
+			if (sc->data[SC_TATAMIGAESHI])
 				status_change_end(bl, SC_TATAMIGAESHI, -1);
-			if (sc->data[SC_MAGICROD].timer != -1)
+			if (sc->data[SC_MAGICROD])
 				status_change_end(bl, SC_MAGICROD, -1);
 		}
 	} else
@@ -484,12 +484,12 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick)
 		skill_unit_move(bl,tick,3);
 		if (sc) {
 			if (sc->count) {
-				if (sc->data[SC_CLOAKING].timer != -1)
-					skill_check_cloaking(bl, sc);
-				if (sc->data[SC_DANCING].timer != -1)
-					skill_unit_move_unit_group((struct skill_unit_group *)sc->data[SC_DANCING].val2, bl->m, x1-x0, y1-y0);
-				if (sc->data[SC_WARM].timer != -1)
-					skill_unit_move_unit_group((struct skill_unit_group *)sc->data[SC_WARM].val4, bl->m, x1-x0, y1-y0);
+				if (sc->data[SC_CLOAKING])
+					skill_check_cloaking(bl, sc->data[SC_CLOAKING]);
+				if (sc->data[SC_DANCING])
+					skill_unit_move_unit_group((struct skill_unit_group *)sc->data[SC_DANCING]->val2, bl->m, x1-x0, y1-y0);
+				if (sc->data[SC_WARM])
+					skill_unit_move_unit_group((struct skill_unit_group *)sc->data[SC_WARM]->val4, bl->m, x1-x0, y1-y0);
 			}
 		}
 	} else
@@ -3073,6 +3073,7 @@ void do_final(void)
 	do_final_guild();
 	do_final_party();
 	do_final_pc();
+	do_final_status();
 	do_final_pet();
 	do_final_mob();
 	do_final_msg();

+ 9 - 4
src/map/map.h

@@ -374,12 +374,17 @@ struct status_change_entry {
 };
 
 struct status_change {
-	struct status_change_entry data[SC_MAX];
-	short count;
+	unsigned int option;// effect state
+	unsigned int opt3;// skill state
 	unsigned short opt1;// body state
 	unsigned short opt2;// health state
-	unsigned int opt3;
-	unsigned int option;// effect state
+	unsigned char count;
+	//TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive.
+	unsigned char jb_flag; //Joint Beat type flag
+	unsigned short mp_matk_min, mp_matk_max; //Previous matk min/max for ground spells (Amplify magic power)
+	int sg_id; //ID of the previous Storm gust that hit you
+	unsigned char sg_counter; //Storm gust counter (previous hits from storm gust)
+	struct status_change_entry *data[SC_MAX];
 };
 
 struct s_vending {

+ 15 - 20
src/map/mob.c

@@ -1141,13 +1141,13 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
 		return 0;
 
 	// Abnormalities
-	if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.data[SC_BLADESTOP].timer != -1)
+	if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.data[SC_BLADESTOP])
   	{	//Should reset targets.
 		md->target_id = md->attacked_id = 0;
 		return 0;
 	}
 
-	if (md->sc.count && md->sc.data[SC_BLIND].timer != -1)
+	if (md->sc.count && md->sc.data[SC_BLIND])
 		view_range = 3;
 	else
 		view_range = md->db->range2;
@@ -1181,7 +1181,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
 			if (!battle_check_range(&md->bl, tbl, md->status.rhw.range) &&
 				(	//Can't attack back and can't reach back.
 					(!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 &&
-					  	(battle_config.mob_ai&0x2 || md->sc.data[SC_SPIDERWEB].timer != -1)) ||
+					  	(battle_config.mob_ai&0x2 || md->sc.data[SC_SPIDERWEB])) ||
 					(!mob_can_reach(md, tbl, md->min_chase, MSS_RUSH))
 				) &&
 				md->state.attacked_count++ >= RUDE_ATTACKED_COUNT &&
@@ -1200,7 +1200,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
 				(!battle_check_range(&md->bl, abl, md->status.rhw.range) &&
 					( //Reach check
 					(!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 &&
-							(battle_config.mob_ai&0x2 || md->sc.data[SC_SPIDERWEB].timer != -1)) ||
+							(battle_config.mob_ai&0x2 || md->sc.data[SC_SPIDERWEB])) ||
 						!mob_can_reach(md, abl, dist+md->db->range3, MSS_RUSH)
 					)
 				)
@@ -1787,9 +1787,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 	md->state.skillstate = MSS_DEAD;	
 	mobskill_use(md,tick,-1);	//On Dead skill.
 
-	if (md->sc.data[SC_KAIZEL].timer != -1)
+	if (md->sc.data[SC_KAIZEL])
 	{	//Revive in a bit.
-		add_timer(gettick()+3000, mob_respawn, md->bl.id, 10*md->sc.data[SC_KAIZEL].val1); //% of life to rebirth with
+		add_timer(gettick()+3000, mob_respawn, md->bl.id, md->sc.data[SC_KAIZEL]->val2); //% of life to rebirth with
 		map_delblock(&md->bl);
 		return 1; //Return 1 to only clear the object.
 	}
@@ -1900,8 +1900,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 
 		bonus = 100;
 		
-		if (md->sc.data[SC_RICHMANKIM].timer != -1)
-			bonus += md->sc.data[SC_RICHMANKIM].val2;
+		if (md->sc.data[SC_RICHMANKIM])
+			bonus += md->sc.data[SC_RICHMANKIM]->val2;
 
 		if(battle_config.mobs_level_up && md->level > md->db->lv) // [Valaris]
 			bonus += (md->level-md->db->lv)*battle_config.mobs_level_up_exp_rate;
@@ -2017,13 +2017,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 
 			// attempt to drop the item
 			if (rand() % 10000 >= drop_rate)
-			{
-				if (sd && sd->sc.data[SC_ITEMBOOST].timer != -1)
-				{
-					if (rand() % 10000 >= drop_rate)
-						continue; // Double try by Bubble Gum
-				}
-				else
+			{	// Double try by Bubble Gum
+				if (!(sd && sd->sc.data[SC_ITEMBOOST] && rand() % 10000 < drop_rate))
 					continue;
 			}
 
@@ -2667,11 +2662,11 @@ int mob_getfriendstatus_sub(struct block_list *bl,va_list ap)
 	if( cond2==-1 ){
 		int j;
 		for(j=SC_COMMON_MIN;j<=SC_COMMON_MAX && !flag;j++){
-			if ((flag=(md->sc.data[j].timer!=-1))) //Once an effect was found, break out. [Skotlex]
+			if ((flag=(md->sc.data[j] != NULL))) //Once an effect was found, break out. [Skotlex]
 				break;
 		}
 	}else
-		flag=( md->sc.data[cond2].timer!=-1 );
+		flag=( md->sc.data[cond2] != NULL );
 	if( flag^( cond1==MSC_FRIENDSTATUSOFF ) )
 		(*fr)=md;
 
@@ -2755,10 +2750,10 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
 						flag = 0;
 					} else if (ms[i].cond2 == -1) {
 						for (j = SC_COMMON_MIN; j <= SC_COMMON_MAX; j++)
-							if ((flag = (md->sc.data[j].timer != -1)) != 0)
+							if ((flag = (md->sc.data[j]!=NULL)) != 0)
 								break;
 					} else {
-						flag = (md->sc.data[ms[i].cond2].timer != -1);
+						flag = (md->sc.data[ms[i].cond2]!=NULL);
 					}
 					flag ^= (ms[i].cond1 == MSC_MYSTATUSOFF); break;
 				case MSC_FRIENDHPLTMAXRATE:	// friend HP < maxhp%
@@ -3236,7 +3231,7 @@ static bool mob_parse_dbrow(char** str)
 	}
 
 	if (mob_db_data[class_] == NULL)
-		mob_db_data[class_] = aCalloc(1, sizeof (struct mob_data));
+		mob_db_data[class_] = aCalloc(1, sizeof (struct mob_db));
 	
 	db = mob_db_data[class_];
 	status = &db->status;

+ 1 - 1
src/map/party.c

@@ -663,7 +663,7 @@ int party_skill_check(struct map_session_data *sd, int party_id, int skillid, in
 				break;
 			case MO_COMBOFINISH: //Increase Counter rate of Star Gladiators
 				if((p_sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR
-					&& sd->sc.data[SC_READYCOUNTER].timer != -1
+					&& sd->sc.data[SC_READYCOUNTER]
 					&& pc_checkskill(p_sd,SG_FRIEND)) {
 					sc_start4(&p_sd->bl,SC_SKILLRATE_UP,100,TK_COUNTER,
 						50+50*pc_checkskill(p_sd,SG_FRIEND), //+100/150/200% rate

+ 50 - 47
src/map/pc.c

@@ -339,7 +339,7 @@ int pc_makesavestatus(struct map_session_data *sd)
 	//status change load/saving. [Skotlex]
 	sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING);
 		
-	if (sd->sc.count && sd->sc.data[SC_JAILED].timer != -1)
+	if (sd->sc.data[SC_JAILED])
 	{	//When Jailed, do not move last point.
 		if(pc_isdead(sd)){
 			pc_setrestartvalue(sd,0);
@@ -563,16 +563,16 @@ int pc_isequip(struct map_session_data *sd,int n)
 		return 0;
 	if (sd->sc.count) {
 			
-		if(item->equip & EQP_ARMS && item->type == IT_WEAPON && sd->sc.data[SC_STRIPWEAPON].timer != -1) // Also works with left-hand weapons [DracoRPG]
+		if(item->equip & EQP_ARMS && item->type == IT_WEAPON && sd->sc.data[SC_STRIPWEAPON]) // Also works with left-hand weapons [DracoRPG]
 			return 0;
-		if(item->equip & EQP_SHIELD && item->type == IT_ARMOR && sd->sc.data[SC_STRIPSHIELD].timer != -1)
+		if(item->equip & EQP_SHIELD && item->type == IT_ARMOR && sd->sc.data[SC_STRIPSHIELD])
 			return 0;
-		if(item->equip & EQP_ARMOR && sd->sc.data[SC_STRIPARMOR].timer != -1)
+		if(item->equip & EQP_ARMOR && sd->sc.data[SC_STRIPARMOR])
 			return 0;
-		if(item->equip & EQP_HELM && sd->sc.data[SC_STRIPHELM].timer != -1)
+		if(item->equip & EQP_HELM && sd->sc.data[SC_STRIPHELM])
 			return 0;
 
-		if (sd->sc.data[SC_SPIRIT].timer != -1 && sd->sc.data[SC_SPIRIT].val2 == SL_SUPERNOVICE) {
+		if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_SUPERNOVICE) {
 			//Spirit of Super Novice equip bonuses. [Skotlex]
 			if (sd->status.base_level > 90 && item->equip & EQP_HELM)
 				return 1; //Can equip all helms
@@ -964,7 +964,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
 			sd->status.skill[i].lv=(sd->status.skill[i].flag==1)?0:sd->status.skill[i].flag-2;
 			sd->status.skill[i].flag=0;
 		}
-		if(sd->sc.count && sd->sc.data[SC_SPIRIT].timer != -1 && sd->sc.data[SC_SPIRIT].val2 == SL_BARDDANCER && i >= DC_HUMMING && i<= DC_SERVICEFORYOU)
+		if(sd->sc.count && sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_BARDDANCER && i >= DC_HUMMING && i<= DC_SERVICEFORYOU)
 		{ //Enable Bard/Dancer spirit linked skills.
 			if (sd->status.sex) { //Link dancer skills to bard.
 				sd->status.skill[i].id=i;
@@ -1024,7 +1024,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
 				if(!sd->status.skill[id].lv && (
 					(inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
 					inf2&INF2_WEDDING_SKILL ||
-					(inf2&INF2_SPIRIT_SKILL && !(sd->sc.count && sd->sc.data[SC_SPIRIT].timer != -1))
+					(inf2&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SPIRIT])
 				))
 					continue; //Cannot be learned via normal means. Note this check DOES allows raising already known skills.
 
@@ -1106,7 +1106,7 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill)
 			if(!sd->status.skill[id].lv && (
 				(j&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
 				j&INF2_WEDDING_SKILL ||
-				(j&INF2_SPIRIT_SKILL && !(sd->sc.count && sd->sc.data[SC_SPIRIT].timer != -1))
+				(j&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SPIRIT])
 			))
 				continue; //Cannot be learned via normal means.
 
@@ -1177,7 +1177,7 @@ int pc_updateweightstatus(struct map_session_data *sd)
 
 	nullpo_retr(1, sd);
 
-	old_overweight = (sd->sc.data[SC_WEIGHT90].timer != -1) ? 2 : (sd->sc.data[SC_WEIGHT50].timer != -1) ? 1 : 0;
+	old_overweight = (sd->sc.data[SC_WEIGHT90]) ? 2 : (sd->sc.data[SC_WEIGHT50]) ? 1 : 0;
 	new_overweight = (pc_is90overweight(sd)) ? 2 : (pc_is50overweight(sd)) ? 1 : 0;
 
 	if( old_overweight == new_overweight )
@@ -3092,12 +3092,12 @@ int pc_useitem(struct map_session_data *sd,int n)
 		return 0;
 
 	if (sd->sc.count && (
-		sd->sc.data[SC_BERSERK].timer!=-1 ||
-		sd->sc.data[SC_MARIONETTE].timer!=-1 ||
-		(sd->sc.data[SC_GRAVITATION].timer!=-1 && sd->sc.data[SC_GRAVITATION].val3 == BCT_SELF) ||
-		sd->sc.data[SC_TRICKDEAD].timer != -1 ||
-		sd->sc.data[SC_BLADESTOP].timer != -1 ||
-		(sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOITEM)
+		sd->sc.data[SC_BERSERK] ||
+		sd->sc.data[SC_MARIONETTE] ||
+		(sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) ||
+		sd->sc.data[SC_TRICKDEAD] ||
+		sd->sc.data[SC_BLADESTOP] ||
+		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM)
 	))
 		return 0;
 
@@ -3123,7 +3123,7 @@ int pc_useitem(struct map_session_data *sd,int n)
 		pc_famerank(MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3]), MAPID_ALCHEMIST))
 	{
 	    potion_flag = 2; // Famous player's potions have 50% more efficiency
-		 if (sd->sc.data[SC_SPIRIT].timer != -1 && sd->sc.data[SC_SPIRIT].val2 == SL_ROGUE)
+		 if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_ROGUE)
 			 potion_flag = 3; //Even more effective potions.
 	}
 
@@ -3399,7 +3399,7 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target)
 		return 0;
 
 	md = (TBL_MOB*)target;
-	if(md->state.steal_coin_flag || md->sc.data[SC_STONE].timer != -1 || md->sc.data[SC_FREEZE].timer != -1)
+	if(md->state.steal_coin_flag || md->sc.data[SC_STONE] || md->sc.data[SC_FREEZE])
 		return 0;
 
 	if (md->class_>=1324 && md->class_<1364)
@@ -3439,19 +3439,21 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
 	{	//Misc map-changing settings
 		if (sd->sc.count)
 		{ //Cancel some map related stuff.
-			if (sd->sc.data[SC_JAILED].timer != -1)
+			if (sd->sc.data[SC_JAILED])
 				return 1; //You may not get out!
-			if (sd->sc.data[SC_WARM].timer != -1)
+			if (sd->sc.data[SC_WARM])
 				status_change_end(&sd->bl,SC_WARM,-1);
-			if (sd->sc.data[SC_SUN_COMFORT].timer != -1)
+			if (sd->sc.data[SC_SUN_COMFORT])
 				status_change_end(&sd->bl,SC_SUN_COMFORT,-1);
-			if (sd->sc.data[SC_MOON_COMFORT].timer != -1)
+			if (sd->sc.data[SC_MOON_COMFORT])
 				status_change_end(&sd->bl,SC_MOON_COMFORT,-1);
-			if (sd->sc.data[SC_STAR_COMFORT].timer != -1)
+			if (sd->sc.data[SC_STAR_COMFORT])
 				status_change_end(&sd->bl,SC_STAR_COMFORT,-1);
-			if (sd->sc.data[SC_KNOWLEDGE].timer != -1) {
-				delete_timer(sd->sc.data[SC_KNOWLEDGE].timer, status_change_timer);
-				sd->sc.data[SC_KNOWLEDGE].timer = add_timer(gettick() + skill_get_time(SG_KNOWLEDGE, sd->sc.data[SC_KNOWLEDGE].val1), status_change_timer, sd->bl.id, SC_KNOWLEDGE);
+			if (sd->sc.data[SC_KNOWLEDGE]) {
+				struct status_change_entry *sce = sd->sc.data[SC_KNOWLEDGE];
+				if (sce->timer != -1)
+					delete_timer(sce->timer, status_change_timer);
+				sce->timer = add_timer(gettick() + skill_get_time(SG_KNOWLEDGE, sce->val1), status_change_timer, sd->bl.id, SC_KNOWLEDGE);
 			}
 		}
 		if (battle_config.clear_unit_onwarp&BL_PC)
@@ -3677,18 +3679,18 @@ int pc_checkallowskill(struct map_session_data *sd)
 	
 	for (i = 0; i < ARRAYLENGTH(scw_list); i++)
 	{	// Skills requiring specific weapon types
-		if(sd->sc.data[scw_list[i]].timer!=-1 &&
+		if(sd->sc.data[scw_list[i]] &&
 			!pc_check_weapontype(sd,skill_get_weapontype(StatusSkillChangeTable[scw_list[i]])))
 			status_change_end(&sd->bl,scw_list[i],-1);
 	}
 	
-	if(sd->sc.data[SC_SPURT].timer!=-1 && sd->status.weapon)
+	if(sd->sc.data[SC_SPURT] && sd->status.weapon)
 		// Spurt requires bare hands (feet, in fact xD)
 		status_change_end(&sd->bl,SC_SPURT,-1);
 	
 	if(sd->status.shield <= 0) { // Skills requiring a shield
 		for (i = 0; i < ARRAYLENGTH(scs_list); i++)
-			if(sd->sc.data[scs_list[i]].timer!=-1)
+			if(sd->sc.data[scs_list[i]])
 				status_change_end(&sd->bl,scs_list[i],-1);
 	}
 	return 0;
@@ -4199,7 +4201,7 @@ static void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsi
 	//SG additional exp from Blessings [Komurka] - probably can be optimalized ^^;;
 	temp = status_get_class(src);
 	if(temp == sd->hate_mob[2] &&
-		(battle_config.allow_skill_without_day || is_day_of_star() || sd->sc.data[SC_MIRACLE].timer!=-1))
+		(battle_config.allow_skill_without_day || is_day_of_star() || sd->sc.data[SC_MIRACLE]))
 		bonus += 20*pc_checkskill(sd,SG_STAR_BLESS);
 	else
 	if(temp == sd->hate_mob[1] &&
@@ -4214,8 +4216,8 @@ static void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsi
 		(int)(status_get_lv(src) - sd->status.base_level) >= 20)
 		bonus += 15; // pk_mode additional exp if monster >20 levels [Valaris]	
 
-	if (sd->sc.data[SC_EXPBOOST].timer != -1)
-		bonus += sd->sc.data[SC_EXPBOOST].val1;
+	if (sd->sc.data[SC_EXPBOOST])
+		bonus += sd->sc.data[SC_EXPBOOST]->val1;
 
 	if (!bonus)
 	  	return;
@@ -5104,7 +5106,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 	if(battle_config.death_penalty_type && sd->state.snovice_dead_flag != 1
 		&& (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE	// only novices will receive no penalty
 		&& !map[sd->bl.m].flag.noexppenalty && !map_flag_gvg(sd->bl.m)
-		&& sd->sc.data[SC_BABY].timer == -1 && sd->sc.data[SC_LIFEINSURANCE].timer == -1)
+		&& !sd->sc.data[SC_BABY] && !sd->sc.data[SC_LIFEINSURANCE])
 	{
 		unsigned int base_penalty =0;
 		if (battle_config.death_penalty_base > 0) {
@@ -5228,16 +5230,17 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 		return 1;
 	}
 
-	if (sd->sc.count && sd->sc.data[SC_KAIZEL].timer != -1)
+	if (sd->sc.data[SC_KAIZEL])
 	{
-		j = sd->sc.data[SC_KAIZEL].val1; //Kaizel Lv.
+		j = sd->sc.data[SC_KAIZEL]->val1; //Kaizel Lv.
+		i = sd->sc.data[SC_KAIZEL]->val2; //Revive %
 		pc_setstand(sd);
 		status_change_clear(&sd->bl,0);
 		clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,1,1);
 		if(sd->special_state.restart_full_recover)
 			status_percent_heal(&sd->bl, 100, 100);
 		else
-			status_percent_heal(&sd->bl, 10*j, 0);
+			status_percent_heal(&sd->bl, i, 0);
 		clif_resurrection(&sd->bl, 1);
 		if(battle_config.pc_invincible_time)
 			pc_setinvincibletimer(sd, battle_config.pc_invincible_time);
@@ -5489,8 +5492,8 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp)
 			hp = hp * bonus / 100;
 
 		// Recovery Potion
-		if( sd->sc.count && sd->sc.data[SC_INCHEALRATE].timer!=-1 )
-			hp += (int)(hp * sd->sc.data[SC_INCHEALRATE].val1/100.);
+		if( sd->sc.data[SC_INCHEALRATE] )
+			hp += (int)(hp * sd->sc.data[SC_INCHEALRATE]->val1/100.);
 	}
 	if(sp) {
 		bonus = 100 + (sd->battle_status.int_<<1)
@@ -5502,10 +5505,10 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp)
 			sp = sp * bonus / 100;
 	}
 
-	if (sd->sc.count && sd->sc.data[SC_CRITICALWOUND].timer!=-1)
+	if (sd->sc.data[SC_CRITICALWOUND])
 	{
-		hp -= hp * sd->sc.data[SC_CRITICALWOUND].val2 / 100;
-		sp -= sp * sd->sc.data[SC_CRITICALWOUND].val2 / 100;
+		hp -= hp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100;
+		sp -= sp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100;
 	}
 
 	return status_heal(&sd->bl, hp, sp, 1);
@@ -5606,7 +5609,7 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
 		for(i = 0; i < MAX_SKILL_TREE && (id = skill_tree[class_][i].id) > 0; i++) {
 			//Remove status specific to your current tree skills.
 			id = SkillStatusChangeTable(id);
-			if (id > SC_COMMON_MAX && sd->sc.data[id].timer != -1)
+			if (id > SC_COMMON_MAX && sd->sc.data[id])
 				status_change_end(&sd->bl, id, -1);
 		}
 	}
@@ -6372,7 +6375,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos)
 
 // -- moonsoul (if player is berserk then cannot equip)
 //
-	if(sd->sc.count && sd->sc.data[SC_BERSERK].timer!=-1){
+	if(sd->sc.data[SC_BERSERK]){
 		clif_equipitemack(sd,n,0,0);	// fail
 		return 0;
 	}
@@ -6513,7 +6516,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag)
 
 // -- moonsoul	(if player is berserk then cannot unequip)
 //
-	if(!(flag&2) && sd->sc.count && (sd->sc.data[SC_BLADESTOP].timer!=-1 || sd->sc.data[SC_BERSERK].timer!=-1)){
+	if(!(flag&2) && sd->sc.count && (sd->sc.data[SC_BLADESTOP] || sd->sc.data[SC_BERSERK])){
 		clif_unequipitemack(sd,n,0,0);
 		return 0;
 	}
@@ -6535,7 +6538,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag)
 		sd->status.weapon = sd->weapontype2;
 		pc_calcweapontype(sd);
 		clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
-		if(sd->sc.data[SC_DANCING].timer!=-1) //When unequipping, stop dancing. [Skotlex]
+		if(sd->sc.data[SC_DANCING]) //When unequipping, stop dancing. [Skotlex]
 			skill_stop_dancing(&sd->bl);
 	}
 	if(sd->status.inventory[n].equip & EQP_HAND_L) {
@@ -6571,7 +6574,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag)
 		status_calc_pc(sd,0);
 	}
 
-	if(sd->sc.count && sd->sc.data[SC_SIGNUMCRUCIS].timer != -1 && !battle_check_undead(sd->battle_status.race,sd->battle_status.def_ele))
+	if(sd->sc.data[SC_SIGNUMCRUCIS] && !battle_check_undead(sd->battle_status.race,sd->battle_status.def_ele))
 		status_change_end(&sd->bl,SC_SIGNUMCRUCIS,-1);
 
 	//OnUnEquip script [Skotlex]
@@ -7091,7 +7094,7 @@ int map_night_timer(int tid, unsigned int tick, int id, int data)
 void pc_setstand(struct map_session_data *sd){
 	nullpo_retv(sd);
 
-	if(sd->sc.count && sd->sc.data[SC_TENSIONRELAX].timer!=-1)
+	if(sd->sc.data[SC_TENSIONRELAX])
 		status_change_end(&sd->bl,SC_TENSIONRELAX,-1);
 
 	//Reset sitting tick.

+ 1 - 1
src/map/pet.c

@@ -1127,7 +1127,7 @@ int pet_recovery_timer(int tid,unsigned int tick,int id,int data)
 		return 0;
 	}
 
-	if(sd->sc.count && sd->sc.data[pd->recovery->type].timer != -1)
+	if(sd->sc.data[pd->recovery->type])
 	{	//Display a heal animation? 
 		//Detoxify is chosen for now.
 		clif_skill_nodamage(&pd->bl,&sd->bl,TF_DETOXIFY,1,1);

File diff suppressed because it is too large
+ 177 - 177
src/map/skill.c


+ 1 - 1
src/map/skill.h

@@ -246,7 +246,7 @@ int skill_autospell(struct map_session_data *md,int skillid);
 
 int skill_calc_heal(struct block_list *src, struct block_list *target, int skill_lv);
 
-int skill_check_cloaking(struct block_list *bl, struct status_change *sc);
+int skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce);
 
 // ƒXƒe?ƒ^ƒXˆÙ�í
 int skill_enchant_elemental_end(struct block_list *bl, int type);

File diff suppressed because it is too large
+ 341 - 332
src/map/status.c


+ 5 - 4
src/map/status.h

@@ -272,10 +272,10 @@ enum sc_type {
 	SC_MAGICMIRROR,
 	SC_SLOWCAST,
 	SC_SUMMER,
-	SC_EXPBOOST, // Field Guide
-	SC_ITEMBOOST, // Bubble Gum
-	SC_BOSSMAPINFO, // Convex Mirror
-	SC_LIFEINSURANCE, // Life Insurance
+	SC_EXPBOOST,
+	SC_ITEMBOOST,
+	SC_BOSSMAPINFO, 
+	SC_LIFEINSURANCE, //260
 	SC_INCCRI,
 	SC_INCDEF,
 	SC_INCBASEATK,
@@ -692,5 +692,6 @@ int status_check_visibility(struct block_list *src, struct block_list *target);
 
 int status_readdb(void);
 int do_init_status(void);
+void do_final_status(void);
 
 #endif /* _STATUS_H_ */

+ 73 - 75
src/map/unit.c

@@ -299,7 +299,7 @@ int unit_walktoxy( struct block_list *bl, short x, short y, int flag)
 	ud->to_y = y;
 	
 	sc = status_get_sc(bl);
-	if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position
+	if (sc && sc->data[SC_CONFUSION]) //Randomize the target position
 		map_random_dir(bl, &ud->to_x, &ud->to_y);
 
 	if(ud->walktimer != -1) {
@@ -367,7 +367,7 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int
 	ud->state.attack_continue = flag&2?1:0; //Chase to attack.
 
 	sc = status_get_sc(bl);
-	if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position
+	if (sc && sc->data[SC_CONFUSION]) //Randomize the target position
 		map_random_dir(bl, &ud->to_x, &ud->to_y);
 
 	if(ud->walktimer != -1) {
@@ -404,19 +404,18 @@ int unit_run(struct block_list *bl)
 	short to_x,to_y,dir_x,dir_y;
 	int i;
 
-	if (!sc || !sc->count || sc->data[SC_RUN].timer == -1)
+	if (!(sc && sc->data[SC_RUN]))
 		return 0;
 	
 	if (!unit_can_move(bl)) {
-		if(sc->data[SC_RUN].timer!=-1)
-			status_change_end(bl,SC_RUN,-1);
+		status_change_end(bl,SC_RUN,-1);
 		return 0;
 	}
 	
 	to_x = bl->x;
 	to_y = bl->y;
-	dir_x = dirx[sc->data[SC_RUN].val2];
-	dir_y = diry[sc->data[SC_RUN].val2];
+	dir_x = dirx[sc->data[SC_RUN]->val2];
+	dir_y = diry[sc->data[SC_RUN]->val2];
 
 	for(i=0;i<AREA_SIZE;i++)
 	{
@@ -430,7 +429,7 @@ int unit_run(struct block_list *bl)
 		//If you can't run forward, you must be next to a wall, so bounce back. [Skotlex]
 		clif_status_change(bl, SI_BUMP, 1);
 		status_change_end(bl,SC_RUN,-1);
-		skill_blown(bl,bl,skill_get_blewcount(TK_RUN,sc->data[SC_RUN].val1),unit_getdir(bl),0);
+		skill_blown(bl,bl,skill_get_blewcount(TK_RUN,sc->data[SC_RUN]->val1),unit_getdir(bl),0);
 		clif_fixpos(bl); //Why is a clif_slide (skill_blown) AND a fixpos needed? Ask Aegis.
 		clif_status_change(bl, SI_BUMP, 0);
 		return 0;
@@ -446,7 +445,7 @@ int unit_run(struct block_list *bl)
 		// copy-paste from above
 		clif_status_change(bl, SI_BUMP, 1);
 		status_change_end(bl,SC_RUN,-1);
-		skill_blown(bl,bl,skill_get_blewcount(TK_RUN,sc->data[SC_RUN].val1),unit_getdir(bl),0);
+		skill_blown(bl,bl,skill_get_blewcount(TK_RUN,sc->data[SC_RUN]->val1),unit_getdir(bl),0);
 		clif_fixpos(bl);
 		clif_status_change(bl, SI_BUMP, 0);
 		return 0;
@@ -722,25 +721,25 @@ int unit_can_move(struct block_list *bl)
 			return 0;
 
 		if (sc->count && (
-			sc->data[SC_ANKLE].timer != -1
-			|| sc->data[SC_AUTOCOUNTER].timer !=-1
-			|| sc->data[SC_TRICKDEAD].timer !=-1
-			|| sc->data[SC_BLADESTOP].timer !=-1
-			|| sc->data[SC_BLADESTOP_WAIT].timer !=-1
-			|| sc->data[SC_SPIDERWEB].timer !=-1
-			|| (sc->data[SC_DANCING].timer !=-1 && sc->data[SC_DANCING].val4 && (
-				sc->data[SC_LONGING].timer == -1 ||
-				(sc->data[SC_DANCING].val1&0xFFFF) == CG_MOONLIT ||
-				(sc->data[SC_DANCING].val1&0xFFFF) == CG_HERMODE
+			sc->data[SC_ANKLE]
+			|| sc->data[SC_AUTOCOUNTER]
+			|| sc->data[SC_TRICKDEAD]
+			|| sc->data[SC_BLADESTOP]
+			|| sc->data[SC_BLADESTOP_WAIT]
+			|| sc->data[SC_SPIDERWEB]
+			|| (sc->data[SC_DANCING] && sc->data[SC_DANCING]->val4 && (
+				sc->data[SC_LONGING] ||
+				(sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT ||
+				(sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE
 			))
-			|| (sc->data[SC_GOSPEL].timer !=-1 && sc->data[SC_GOSPEL].val4 == BCT_SELF)	// cannot move while gospel is in effect
-			|| sc->data[SC_STOP].timer != -1
-			|| sc->data[SC_CLOSECONFINE].timer != -1
-			|| sc->data[SC_CLOSECONFINE2].timer != -1
-			|| (sc->data[SC_CLOAKING].timer != -1 && //Need wall at level 1-2
-				sc->data[SC_CLOAKING].val1 < 3 && !(sc->data[SC_CLOAKING].val4&1))
-			|| sc->data[SC_MADNESSCANCEL].timer != -1
-			|| (sc->data[SC_GRAVITATION].timer != -1 && sc->data[SC_GRAVITATION].val3 == BCT_SELF)
+			|| (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF)	// cannot move while gospel is in effect
+			|| sc->data[SC_STOP]
+			|| sc->data[SC_CLOSECONFINE]
+			|| sc->data[SC_CLOSECONFINE2]
+			|| (sc->data[SC_CLOAKING] && //Need wall at level 1-2
+				sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1))
+			|| sc->data[SC_MADNESSCANCEL]
+			|| (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF)
 		))
 			return 0;
 	}
@@ -817,16 +816,16 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
 		switch(skill_num)
 		{	//Check for skills that auto-select target
 		case MO_CHAINCOMBO:
-			if (sc && sc->data[SC_BLADESTOP].timer != -1){
-				if ((target=(struct block_list *)sc->data[SC_BLADESTOP].val4) == NULL)
+			if (sc && sc->data[SC_BLADESTOP]){
+				if ((target=(struct block_list *)sc->data[SC_BLADESTOP]->val4) == NULL)
 					return 0;
 			}
 			break;
 		case TK_JUMPKICK:
 		case TK_COUNTER:
 		case HT_POWER:
-			if (sc && sc->data[SC_COMBO].timer != -1 && sc->data[SC_COMBO].val1 == skill_num)
-				target_id = sc->data[SC_COMBO].val2;
+			if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_num)
+				target_id = sc->data[SC_COMBO]->val2;
 			break;
 		case WE_MALE:
 		case WE_FEMALE:
@@ -958,10 +957,10 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
 			casttime += casttime * min(skill_lv, sd->spiritball);
 	break;
 	case MO_EXTREMITYFIST:
-		if (sc && sc->data[SC_COMBO].timer != -1 &&
-		   (sc->data[SC_COMBO].val1 == MO_COMBOFINISH ||
-			sc->data[SC_COMBO].val1 == CH_TIGERFIST ||
-			sc->data[SC_COMBO].val1 == CH_CHAINCRUSH))
+		if (sc && sc->data[SC_COMBO] &&
+		   (sc->data[SC_COMBO]->val1 == MO_COMBOFINISH ||
+			sc->data[SC_COMBO]->val1 == CH_TIGERFIST ||
+			sc->data[SC_COMBO]->val1 == CH_CHAINCRUSH))
 			casttime = 0;
 		temp = 1;
 	break;
@@ -969,11 +968,11 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
 		temp = 1;
 	break;
 	case ST_CHASEWALK:
-		if (sc && sc->data[SC_CHASEWALK].timer != -1)
+		if (sc && sc->data[SC_CHASEWALK])
 			casttime = 0;
 	break;
 	case TK_RUN:
-		if (sc && sc->data[SC_RUN].timer != -1)
+		if (sc && sc->data[SC_RUN])
 			casttime = 0;
 	break;
 	case KN_CHARGEATK:
@@ -1033,8 +1032,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
 	ud->skillid      = skill_num;
 	ud->skilllv      = skill_lv;
 
- 	if(sc && sc->data[SC_CLOAKING].timer != -1 &&
-		!(sc->data[SC_CLOAKING].val4&4) && skill_num != AS_CLOAKING)
+ 	if(sc && sc->data[SC_CLOAKING] &&
+		!(sc->data[SC_CLOAKING]->val4&4) && skill_num != AS_CLOAKING)
 	{
 		status_change_end(src,SC_CLOAKING,-1);
 		if (!src->prev) return 0; //Warped away!
@@ -1137,8 +1136,7 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh
 	ud->skilly       = skill_y;
 	ud->skilltarget  = 0;
 
-	if (sc && sc->data[SC_CLOAKING].timer != -1 &&
-		!(sc->data[SC_CLOAKING].val4&4))
+	if (sc && sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4&4))
 	{
 		status_change_end(src,SC_CLOAKING,-1);
 		if (!src->prev) return 0; //Warped away!
@@ -1621,43 +1619,43 @@ int unit_remove_map(struct block_list *bl, int clrtype)
 	ud->attackabletime = ud->canmove_tick /*= ud->canact_tick*/ = gettick();
 	
 	if(sc && sc->count ) { //map-change/warp dispells.
-		if(sc->data[SC_BLADESTOP].timer!=-1)
+		if(sc->data[SC_BLADESTOP])
 			status_change_end(bl,SC_BLADESTOP,-1);
-		if(sc->data[SC_BASILICA].timer!=-1)
+		if(sc->data[SC_BASILICA])
 			status_change_end(bl,SC_BASILICA,-1);
-		if(sc->data[SC_ANKLE].timer != -1)
+		if(sc->data[SC_ANKLE])
 			status_change_end(bl, SC_ANKLE, -1);
-		if (sc->data[SC_TRICKDEAD].timer != -1)
+		if (sc->data[SC_TRICKDEAD])
 			status_change_end(bl, SC_TRICKDEAD, -1);
-		if (sc->data[SC_BLADESTOP].timer!=-1)
+		if (sc->data[SC_BLADESTOP])
 			status_change_end(bl,SC_BLADESTOP,-1);
-		if (sc->data[SC_RUN].timer!=-1)
+		if (sc->data[SC_RUN])
 			status_change_end(bl,SC_RUN,-1);
-		if (sc->data[SC_DANCING].timer!=-1) // clear dance effect when warping [Valaris]
+		if (sc->data[SC_DANCING]) // clear dance effect when warping [Valaris]
 			skill_stop_dancing(bl);
-		if (sc->data[SC_WARM].timer!=-1)
+		if (sc->data[SC_WARM])
 			status_change_end(bl, SC_WARM, -1);
-		if (sc->data[SC_DEVOTION].timer!=-1)
+		if (sc->data[SC_DEVOTION])
 			status_change_end(bl,SC_DEVOTION,-1);
-		if (sc->data[SC_MARIONETTE].timer!=-1)
+		if (sc->data[SC_MARIONETTE])
 			status_change_end(bl,SC_MARIONETTE,-1);
-		if (sc->data[SC_MARIONETTE2].timer!=-1)
+		if (sc->data[SC_MARIONETTE2])
 			status_change_end(bl,SC_MARIONETTE2,-1);
-		if (sc->data[SC_CLOSECONFINE].timer!=-1)
+		if (sc->data[SC_CLOSECONFINE])
 			status_change_end(bl,SC_CLOSECONFINE,-1);
-		if (sc->data[SC_CLOSECONFINE2].timer!=-1)
+		if (sc->data[SC_CLOSECONFINE2])
 			status_change_end(bl,SC_CLOSECONFINE2,-1);
-		if (sc->data[SC_HIDING].timer!=-1)
+		if (sc->data[SC_HIDING])
 			status_change_end(bl, SC_HIDING, -1);
-		if (sc->data[SC_CLOAKING].timer!=-1)
+		if (sc->data[SC_CLOAKING])
 			status_change_end(bl, SC_CLOAKING, -1);
-		if (sc->data[SC_CHASEWALK].timer!=-1)
+		if (sc->data[SC_CHASEWALK])
 			status_change_end(bl, SC_CHASEWALK, -1);
-		if (sc->data[SC_GOSPEL].timer != -1 && sc->data[SC_GOSPEL].val4 == BCT_SELF)
+		if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF)
 			status_change_end(bl, SC_GOSPEL, -1);
-		if (sc->data[SC_CHANGE].timer!=-1)
+		if (sc->data[SC_CHANGE])
 			status_change_end(bl, SC_CHANGE, -1);
-		if (sc->data[SC_MIRACLE].timer!=-1)
+		if (sc->data[SC_MIRACLE])
 			status_change_end(bl, SC_MIRACLE, -1);
 	}
 
@@ -1764,39 +1762,39 @@ int unit_free(struct block_list *bl, int clrtype)
 
 		//Status that are not saved...
 		if(sd->sc.count) {
-			if(sd->sc.data[SC_SPURT].timer!=-1)
+			if(sd->sc.data[SC_SPURT])
 				status_change_end(bl,SC_SPURT,-1);
-			if(sd->sc.data[SC_BERSERK].timer!=-1)
+			if(sd->sc.data[SC_BERSERK])
 				status_change_end(bl,SC_BERSERK,-1);
-			if(sd->sc.data[SC_TRICKDEAD].timer!=-1)
+			if(sd->sc.data[SC_TRICKDEAD])
 				status_change_end(bl,SC_TRICKDEAD,-1);
-			if(sd->sc.data[SC_GUILDAURA].timer!=-1)
+			if(sd->sc.data[SC_GUILDAURA])
 				status_change_end(bl,SC_GUILDAURA,-1);
 			if (battle_config.debuff_on_logout&1) {
-				if(sd->sc.data[SC_ORCISH].timer!=-1)
+				if(sd->sc.data[SC_ORCISH])
 					status_change_end(bl,SC_ORCISH,-1);
-				if(sd->sc.data[SC_STRIPWEAPON].timer!=-1)
+				if(sd->sc.data[SC_STRIPWEAPON])
 					status_change_end(bl,SC_STRIPWEAPON,-1);
-				if(sd->sc.data[SC_STRIPARMOR].timer!=-1)
+				if(sd->sc.data[SC_STRIPARMOR])
 					status_change_end(bl,SC_STRIPARMOR,-1);
-				if(sd->sc.data[SC_STRIPSHIELD].timer!=-1)
+				if(sd->sc.data[SC_STRIPSHIELD])
 					status_change_end(bl,SC_STRIPSHIELD,-1);
-				if(sd->sc.data[SC_STRIPHELM].timer!=-1)
+				if(sd->sc.data[SC_STRIPHELM])
 					status_change_end(bl,SC_STRIPHELM,-1);
-				if(sd->sc.data[SC_EXTREMITYFIST].timer!=-1)
+				if(sd->sc.data[SC_EXTREMITYFIST])
 					status_change_end(bl,SC_EXTREMITYFIST,-1);
-				if(sd->sc.data[SC_EXPLOSIONSPIRITS].timer!=-1)
+				if(sd->sc.data[SC_EXPLOSIONSPIRITS])
 					status_change_end(bl,SC_EXPLOSIONSPIRITS,-1);
-				if(sd->sc.data[SC_REGENERATION].timer!=-1 && sd->sc.data[SC_REGENERATION].val4)
+				if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4)
 					status_change_end(bl,SC_REGENERATION,-1);
 			}
 			if (battle_config.debuff_on_logout&2)
 			{
-				if(sd->sc.data[SC_MAXIMIZEPOWER].timer!=-1)
+				if(sd->sc.data[SC_MAXIMIZEPOWER])
 					status_change_end(bl,SC_MAXIMIZEPOWER,-1);
-				if(sd->sc.data[SC_MAXOVERTHRUST].timer!=-1)
+				if(sd->sc.data[SC_MAXOVERTHRUST])
 					status_change_end(bl,SC_MAXOVERTHRUST,-1);
-				if(sd->sc.data[SC_STEELBODY].timer!=-1)
+				if(sd->sc.data[SC_STEELBODY])
 					status_change_end(bl,SC_STEELBODY,-1);
 			}
 		}

Some files were not shown because too many files changed in this diff