Browse Source

> Hercules merges:
* 620b36d:
Fixing a typo on skill_trap_type description.

* 13317f0:
Spider web no longer triggers on players on non-pvp maps. (bugreport:7234)
(also fixed tab align on switch and a logical thing on skill_additional_effect)

* fc2e159:
@follow will not stop immeadily when turned off, instead of waiting for the current walk path to be complete. (bugreport:6918)

* 638e2b5:
Replaced strncpy with safestrncpy where I found would be beneficial. (bugreport:3080)

* 74ed3ed:
Players in chatrooms can now equip/unequip gear, can talk to NPCS, and can't use consumable items. (bugreport:6097)

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

euphyy 12 years ago
parent
commit
d030e8cfd4

+ 1 - 1
conf/battle/skill.conf

@@ -278,5 +278,5 @@ dancing_weaponswitch_fix: yes
 
 
 // Skill Trap Type
 // Skill Trap Type
 // 0: (official) traps only makes player unable to move after its walk path is complete, and it activates other traps on the way.
 // 0: (official) traps only makes player unable to move after its walk path is complete, and it activates other traps on the way.
-// 1: trap makes player stops moving right when stepping over it.
+// 1: trap makes player stop moving right when stepping over it.
 skill_trap_type: 0
 skill_trap_type: 0

+ 1 - 1
src/char/int_guild.c

@@ -1815,7 +1815,7 @@ int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int le
 	g->member[0].position = 0; //Position 0: guild Master.
 	g->member[0].position = 0; //Position 0: guild Master.
 	g->member[0].modified = GS_MEMBER_MODIFIED;
 	g->member[0].modified = GS_MEMBER_MODIFIED;
 
 
-	strncpy(g->master, name, len);
+	safestrncpy(g->master, name, len);
 	if (len < NAME_LENGTH)
 	if (len < NAME_LENGTH)
 		g->master[len] = '\0';
 		g->master[len] = '\0';
 
 

+ 1 - 1
src/char/int_pet.c

@@ -184,7 +184,7 @@ int mapif_create_pet(int fd, int account_id, int char_id, short pet_class, short
 	short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name)
 	short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name)
 {
 {
 	memset(pet_pt, 0, sizeof(struct s_pet));
 	memset(pet_pt, 0, sizeof(struct s_pet));
-	strncpy(pet_pt->name, pet_name, NAME_LENGTH);
+	safestrncpy(pet_pt->name, pet_name, NAME_LENGTH);
 	if(incuvate == 1)
 	if(incuvate == 1)
 		pet_pt->account_id = pet_pt->char_id = 0;
 		pet_pt->account_id = pet_pt->char_id = 0;
 	else {
 	else {

+ 2 - 2
src/common/mapindex.c

@@ -37,7 +37,7 @@ const char* mapindex_getmapname(const char* string, char* output)
 		len -= 4; // strip .gat extension
 		len -= 4; // strip .gat extension
 	
 	
 	len = min(len, MAP_NAME_LENGTH-1);
 	len = min(len, MAP_NAME_LENGTH-1);
-	strncpy(dest, string, len+1);
+	safestrncpy(dest, string, len+1);
 	memset(&dest[len], '\0', MAP_NAME_LENGTH-len);
 	memset(&dest[len], '\0', MAP_NAME_LENGTH-len);
 	
 	
 	return dest;
 	return dest;
@@ -61,7 +61,7 @@ const char* mapindex_getmapname_ext(const char* string, char* output)
 		ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf);
 		ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf);
 		len--;
 		len--;
 	}
 	}
-	strncpy(dest, buf, len+1);
+	safestrncpy(dest, buf, len+1);
 
 
 	if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) {
 	if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) {
 		strcpy(&dest[len], ".gat");
 		strcpy(&dest[len], ".gat");

+ 1 - 1
src/login/login.c

@@ -1596,7 +1596,7 @@ int login_config_read(const char* cfgName)
 			continue;
 			continue;
 
 
 		if(!strcmpi(w1,"timestamp_format"))
 		if(!strcmpi(w1,"timestamp_format"))
-			strncpy(timestamp_format, w2, 20);
+			safestrncpy(timestamp_format, w2, 20);
 		else if(!strcmpi(w1,"stdout_with_ansisequence"))
 		else if(!strcmpi(w1,"stdout_with_ansisequence"))
 			stdout_with_ansisequence = config_switch(w2);
 			stdout_with_ansisequence = config_switch(w2);
 		else if(!strcmpi(w1,"console_silent")) {
 		else if(!strcmpi(w1,"console_silent")) {

+ 1 - 1
src/map/chrif.c

@@ -246,7 +246,7 @@ int chrif_setip(const char* ip) {
 		return 0;
 		return 0;
 	}
 	}
 	
 	
-	strncpy(char_ip_str, ip, sizeof(char_ip_str));
+	safestrncpy(char_ip_str, ip, sizeof(char_ip_str));
 	
 	
 	ShowInfo("Char Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(char_ip, ip_str));
 	ShowInfo("Char Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(char_ip, ip_str));
 	
 	

+ 6 - 6
src/map/clif.c

@@ -202,7 +202,7 @@ int clif_setip(const char* ip)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	strncpy(map_ip_str, ip, sizeof(map_ip_str));
+	safestrncpy(map_ip_str, ip, sizeof(map_ip_str));
 	ShowInfo("Map Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(map_ip, ip_str));
 	ShowInfo("Map Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(map_ip, ip_str));
 	return 1;
 	return 1;
 }
 }
@@ -10139,7 +10139,7 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
 		if (pc_isdead(sd))
 		if (pc_isdead(sd))
 			break;
 			break;
 
 
-		if (pc_cant_act(sd))
+		if (pc_cant_act2(sd))
 			break;
 			break;
 
 
 		if (sd->sc.count && (
 		if (sd->sc.count && (
@@ -10178,7 +10178,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd)
 		if (sd->npc_id != sd->npc_item_flag)
 		if (sd->npc_id != sd->npc_item_flag)
 			return;
 			return;
 	}
 	}
-	else if (pc_istrading(sd))
+	else if (pc_istrading(sd) || sd->chatID)
 		return;
 		return;
 
 
 	//Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex]
 	//Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex]
@@ -10211,7 +10211,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
 			return;
 			return;
 	} else if (sd->state.storage_flag || sd->sc.opt1)
 	} else if (sd->state.storage_flag || sd->sc.opt1)
 		; //You can equip/unequip stuff while storage is open/under status changes
 		; //You can equip/unequip stuff while storage is open/under status changes
-	else if (pc_cant_act(sd))
+	else if (pc_cant_act2(sd))
 		return;
 		return;
 
 
 	if(!sd->status.inventory[index].identify) {
 	if(!sd->status.inventory[index].identify) {
@@ -10248,7 +10248,7 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd)
 
 
 	if (sd->state.storage_flag || sd->sc.opt1)
 	if (sd->state.storage_flag || sd->sc.opt1)
 		; //You can equip/unequip stuff while storage is open/under status changes
 		; //You can equip/unequip stuff while storage is open/under status changes
-	else if (pc_cant_act(sd))
+	else if (pc_cant_act2(sd))
 		return;
 		return;
 
 
 	index = RFIFOW(fd,2)-2;
 	index = RFIFOW(fd,2)-2;
@@ -10270,7 +10270,7 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
 		return;
 		return;
 	}
 	}
 
 
-	if (pc_cant_act(sd))
+	if (pc_cant_act2(sd))
 		return;
 		return;
 
 
 	bl = map_id2bl(RFIFOL(fd,2));
 	bl = map_id2bl(RFIFOL(fd,2));

+ 3 - 2
src/map/elemental.c

@@ -10,6 +10,7 @@
 #include "../common/showmsg.h"
 #include "../common/showmsg.h"
 #include "../common/utils.h"
 #include "../common/utils.h"
 #include "../common/random.h"
 #include "../common/random.h"
+#include "../common/strlib.h"
 
 
 #include "log.h"
 #include "log.h"
 #include "clif.h"
 #include "clif.h"
@@ -795,8 +796,8 @@ int read_elementaldb(void) {
 
 
 		db = &elemental_db[j];
 		db = &elemental_db[j];
 		db->class_ = atoi(str[0]);
 		db->class_ = atoi(str[0]);
-		strncpy(db->sprite, str[1], NAME_LENGTH);
-		strncpy(db->name, str[2], NAME_LENGTH);
+		safestrncpy(db->sprite, str[1], NAME_LENGTH);
+		safestrncpy(db->name, str[2], NAME_LENGTH);
 		db->lv = atoi(str[3]);
 		db->lv = atoi(str[3]);
 
 
 		status = &db->status;
 		status = &db->status;

+ 3 - 3
src/map/homunculus.c

@@ -709,7 +709,7 @@ int merc_hom_change_name_ack(struct map_session_data *sd, char* name, int flag)
 		clif_displaymessage(sd->fd, msg_txt(280)); // You cannot use this name
 		clif_displaymessage(sd->fd, msg_txt(280)); // You cannot use this name
 		return 0;
 		return 0;
 	}
 	}
-	strncpy(hd->homunculus.name,name,NAME_LENGTH);
+	safestrncpy(hd->homunculus.name,name,NAME_LENGTH);
 	clif_charnameack (0,&hd->bl);
 	clif_charnameack (0,&hd->bl);
 	hd->homunculus.rename_flag = 1;
 	hd->homunculus.rename_flag = 1;
 	clif_hominfo(sd,hd,0);
 	clif_hominfo(sd,hd,0);
@@ -887,7 +887,7 @@ int merc_create_homunculus_request(struct map_session_data *sd, int class_)
 
 
 	memset(&homun, 0, sizeof(struct s_homunculus));
 	memset(&homun, 0, sizeof(struct s_homunculus));
 	//Initial data
 	//Initial data
-	strncpy(homun.name, homunculus_db[i].name, NAME_LENGTH-1);
+	safestrncpy(homun.name, homunculus_db[i].name, NAME_LENGTH-1);
 	homun.class_ = class_;
 	homun.class_ = class_;
 	homun.level = 1;
 	homun.level = 1;
 	homun.hunger = 32; //32%
 	homun.hunger = 32; //32%
@@ -1050,7 +1050,7 @@ static bool read_homunculusdb_sub(char* str[], int columns, int current)
 	}
 	}
 	db->evo_class = classid;
 	db->evo_class = classid;
 	//Name, Food, Hungry Delay, Base Size, Evo Size, Race, Element, ASPD
 	//Name, Food, Hungry Delay, Base Size, Evo Size, Race, Element, ASPD
-	strncpy(db->name,str[2],NAME_LENGTH-1);
+	safestrncpy(db->name,str[2],NAME_LENGTH-1);
 	db->foodID = atoi(str[3]);
 	db->foodID = atoi(str[3]);
 	db->hungryDelay = atoi(str[4]);
 	db->hungryDelay = atoi(str[4]);
 	db->base_size = atoi(str[5]);
 	db->base_size = atoi(str[5]);

+ 2 - 2
src/map/map.c

@@ -3216,7 +3216,7 @@ int map_config_read(char *cfgName)
 		*ptr = '\0';
 		*ptr = '\0';
 
 
 		if(strcmpi(w1,"timestamp_format")==0)
 		if(strcmpi(w1,"timestamp_format")==0)
-			strncpy(timestamp_format, w2, 20);
+			safestrncpy(timestamp_format, w2, 20);
 		else if(strcmpi(w1,"stdout_with_ansisequence")==0)
 		else if(strcmpi(w1,"stdout_with_ansisequence")==0)
 			stdout_with_ansisequence = config_switch(w2);
 			stdout_with_ansisequence = config_switch(w2);
 		else if(strcmpi(w1,"console_silent")==0) {
 		else if(strcmpi(w1,"console_silent")==0) {
@@ -3267,7 +3267,7 @@ int map_config_read(char *cfgName)
 		else if (strcmpi(w1, "charhelp_txt") == 0)
 		else if (strcmpi(w1, "charhelp_txt") == 0)
 			strcpy(charhelp_txt, w2);
 			strcpy(charhelp_txt, w2);
 		else if(strcmpi(w1,"db_path") == 0)
 		else if(strcmpi(w1,"db_path") == 0)
-			strncpy(db_path,w2,255);
+			safestrncpy(db_path,w2,255);
 		else if (strcmpi(w1, "console") == 0) {
 		else if (strcmpi(w1, "console") == 0) {
 			console = config_switch(w2);
 			console = config_switch(w2);
 			if (console)
 			if (console)

+ 2 - 2
src/map/mercenary.c

@@ -404,8 +404,8 @@ static bool read_mercenarydb_sub(char* str[], int columns, int current)
 
 
 	db = &mercenary_db[current];
 	db = &mercenary_db[current];
 	db->class_ = atoi(str[0]);
 	db->class_ = atoi(str[0]);
-	strncpy(db->sprite, str[1], NAME_LENGTH);
-	strncpy(db->name, str[2], NAME_LENGTH);
+	safestrncpy(db->sprite, str[1], NAME_LENGTH);
+	safestrncpy(db->name, str[2], NAME_LENGTH);
 	db->lv = atoi(str[3]);
 	db->lv = atoi(str[3]);
 
 
 	status = &db->status;
 	status = &db->status;

+ 1 - 1
src/map/mob.c

@@ -4120,7 +4120,7 @@ static bool mob_parse_row_chatdb(char** str, const char* source, int line, int*
 	}
 	}
 
 
 	msg[len] = 0;  // strip previously found EOL
 	msg[len] = 0;  // strip previously found EOL
-	strncpy(ms->msg, str[2], CHAT_SIZE_MAX);
+	safestrncpy(ms->msg, str[2], CHAT_SIZE_MAX);
 
 
 	return true;
 	return true;
 }
 }

+ 2 - 2
src/map/npc.c

@@ -1915,7 +1915,7 @@ void npc_addsrcfile(const char* name)
 
 
 	file = (struct npc_src_list*)aMalloc(sizeof(struct npc_src_list) + strlen(name));
 	file = (struct npc_src_list*)aMalloc(sizeof(struct npc_src_list) + strlen(name));
 	file->next = NULL;
 	file->next = NULL;
-	strncpy(file->name, name, strlen(name) + 1);
+	safestrncpy(file->name, name, strlen(name) + 1);
 	if( file_prev == NULL )
 	if( file_prev == NULL )
 		npc_src_files = file;
 		npc_src_files = file;
 	else
 	else
@@ -3605,7 +3605,7 @@ void npc_read_event_script(void)
 		DBData *data;
 		DBData *data;
 
 
 		char name[64]="::";
 		char name[64]="::";
-		strncpy(name+2,config[i].event_name,62);
+		safestrncpy(name+2,config[i].event_name,62);
 
 
 		script_event[i].event_count = 0;
 		script_event[i].event_count = 0;
 		iter = db_iterator(ev_db);
 		iter = db_iterator(ev_db);

+ 2 - 0
src/map/pc.c

@@ -5518,6 +5518,8 @@ int pc_stop_following (struct map_session_data *sd)
 	sd->followtarget = -1;
 	sd->followtarget = -1;
 	sd->ud.target_to = 0;
 	sd->ud.target_to = 0;
 
 
+	unit_stop_walking(&sd->bl, 1);
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 4 - 0
src/map/pc.h

@@ -592,6 +592,10 @@ enum equip_index {
 #define pc_isidle(sd)         ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share )
 #define pc_isidle(sd)         ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share )
 #define pc_istrading(sd)      ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading )
 #define pc_istrading(sd)      ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading )
 #define pc_cant_act(sd)       ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag )
 #define pc_cant_act(sd)       ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag )
+
+/* equals pc_cant_act except it doesn't check for chat rooms */
+#define pc_cant_act2(sd)       ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag )
+
 #define pc_setdir(sd,b,h)     ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
 #define pc_setdir(sd,b,h)     ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
 #define pc_setchatid(sd,n)    ( (sd)->chatID = n )
 #define pc_setchatid(sd,n)    ( (sd)->chatID = n )
 #define pc_ishiding(sd)       ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) )
 #define pc_ishiding(sd)       ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) )

+ 161 - 165
src/map/skill.c

@@ -1560,7 +1560,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
 
 
 			if (skill == AS_SONICBLOW)
 			if (skill == AS_SONICBLOW)
 				pc_stop_attack(sd); //Special case, Sonic Blow autospell should stop the player attacking.
 				pc_stop_attack(sd); //Special case, Sonic Blow autospell should stop the player attacking.
-			if (skill == PF_SPIDERWEB) //Special case, due to its nature of coding.
+			else if (skill == PF_SPIDERWEB) //Special case, due to its nature of coding.
 				type = CAST_GROUND;
 				type = CAST_GROUND;
 
 
 			sd->state.autocast = 1;
 			sd->state.autocast = 1;
@@ -11042,195 +11042,191 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un
 	type = status_skill2sc(sg->skill_id);
 	type = status_skill2sc(sg->skill_id);
 	sce = (sc && type != -1)?sc->data[type]:NULL;
 	sce = (sc && type != -1)?sc->data[type]:NULL;
 	skill_id = sg->skill_id; //In case the group is deleted, we need to return the correct skill id, still.
 	skill_id = sg->skill_id; //In case the group is deleted, we need to return the correct skill id, still.
-	switch (sg->unit_id)
-	{
-	case UNT_SPIDERWEB:
-		if( sc && sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1 > 0 )
-		{ // If you are fiberlocked and can't move, it will only increase your fireweakness level. [Inkfish]
-			sc->data[SC_SPIDERWEB]->val2++;
-			break;
-		}
-		else if( sc )
-		{
-			int sec = skill_get_time2(sg->skill_id,sg->skill_lv);
-			if( status_change_start(bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,8) )
-			{
-				const struct TimerData* td = sc->data[type]?get_timer(sc->data[type]->timer):NULL;
-				if( td )
-					sec = DIFF_TICK(td->tick, tick);
-				map_moveblock(bl, src->bl.x, src->bl.y, tick);
-				clif_fixpos(bl);
-				sg->val2 = bl->id;
+	switch (sg->unit_id) {
+		case UNT_SPIDERWEB:
+			if( sc && sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1 > 0 ) {
+				// If you are fiberlocked and can't move, it will only increase your fireweakness level. [Inkfish]
+				sc->data[SC_SPIDERWEB]->val2++;
+				break;
+			} else if( sc && battle_check_target(&sg->unit->bl,bl,sg->target_flag) > 0 ) {
+				int sec = skill_get_time2(sg->skill_id,sg->skill_lv);
+				if( status_change_start(bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,8) ) {
+					const struct TimerData* td = sc->data[type]?get_timer(sc->data[type]->timer):NULL;
+					if( td )
+						sec = DIFF_TICK(td->tick, tick);
+					map_moveblock(bl, src->bl.x, src->bl.y, tick);
+					clif_fixpos(bl);
+					sg->val2 = bl->id;
+				}
+				else
+					sec = 3000; //Couldn't trap it?
+				sg->limit = DIFF_TICK(tick,sg->tick)+sec;
 			}
 			}
-			else
-				sec = 3000; //Couldn't trap it?
-			sg->limit = DIFF_TICK(tick,sg->tick)+sec;
-		}
-		break;
-	case UNT_SAFETYWALL:
-		if (!sce)
-			sc_start4(bl,type,100,sg->skill_lv,sg->skill_id,sg->group_id,0,sg->limit);
-		break;
+			break;
+		case UNT_SAFETYWALL:
+			if (!sce)
+				sc_start4(bl,type,100,sg->skill_lv,sg->skill_id,sg->group_id,0,sg->limit);
+			break;
 
 
-	case UNT_PNEUMA:
-	case UNT_CHAOSPANIC:
-	case UNT_MAELSTROM:
-		if (!sce)
-			sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
-		break;
-	case UNT_BLOODYLUST:
-		if (sg->src_id == bl->id)
-			break; //Does not affect the caster.
-		if (!sce) {
-			TBL_PC *sd = BL_CAST(BL_PC, bl); //prevent fullheal exploit
-			if (sd && sd->bloodylust_tick && DIFF_TICK(gettick(), sd->bloodylust_tick) < skill_get_time2(SC_BLOODYLUST, 1))
-				clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv,
-					sc_start4(bl, type, 100, sg->skill_lv, 1, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv)));
-			else {
-				if (sd) sd->bloodylust_tick = gettick();
+		case UNT_PNEUMA:
+		case UNT_CHAOSPANIC:
+		case UNT_MAELSTROM:
+			if (!sce)
+				sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
+			break;
+		case UNT_BLOODYLUST:
+			if (sg->src_id == bl->id)
+				break; //Does not affect the caster.
+			if (!sce) {
+				TBL_PC *sd = BL_CAST(BL_PC, bl); //prevent fullheal exploit
+				if (sd && sd->bloodylust_tick && DIFF_TICK(gettick(), sd->bloodylust_tick) < skill_get_time2(SC_BLOODYLUST, 1))
 					clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv,
 					clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv,
-						sc_start4(bl, type, 100, sg->skill_lv, 0, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv)));
+						sc_start4(bl, type, 100, sg->skill_lv, 1, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv)));
+				else {
+					if (sd) sd->bloodylust_tick = gettick();
+						clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv,
+							sc_start4(bl, type, 100, sg->skill_lv, 0, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv)));
+				}
 			}
 			}
-		}
-		break;
+			break;
 
 
-	case UNT_WARP_WAITING: {
-		int working = sg->val1&0xffff;
+		case UNT_WARP_WAITING: {
+			int working = sg->val1&0xffff;
 
 
-		if(bl->type==BL_PC && !working){
-			struct map_session_data *sd = (struct map_session_data *)bl;
-			if((!sd->chatID || battle_config.chat_warpportal)
-				&& sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y)
-			{
-				int x = sg->val2>>16;
-				int y = sg->val2&0xffff;
-				int count = sg->val1>>16;
-				unsigned short m = sg->val3;
+			if(bl->type==BL_PC && !working){
+				struct map_session_data *sd = (struct map_session_data *)bl;
+				if((!sd->chatID || battle_config.chat_warpportal)
+					&& sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y)
+				{
+					int x = sg->val2>>16;
+					int y = sg->val2&0xffff;
+					int count = sg->val1>>16;
+					unsigned short m = sg->val3;
 
 
-				if( --count <= 0 )
-					skill_delunitgroup(sg);
+					if( --count <= 0 )
+						skill_delunitgroup(sg);
 
 
-				if ( map_mapindex2mapid(sg->val3) == sd->bl.m && x == sd->bl.x && y == sd->bl.y )
-					working = 1;/* we break it because officials break it, lovely stuff. */
+					if ( map_mapindex2mapid(sg->val3) == sd->bl.m && x == sd->bl.x && y == sd->bl.y )
+						working = 1;/* we break it because officials break it, lovely stuff. */
 
 
-				sg->val1 = (count<<16)|working;
+					sg->val1 = (count<<16)|working;
 
 
-				pc_setpos(sd,m,x,y,CLR_TELEPORT);
+					pc_setpos(sd,m,x,y,CLR_TELEPORT);
+				}
+			} else if(bl->type == BL_MOB && battle_config.mob_warp&2) {
+				int16 m = map_mapindex2mapid(sg->val3);
+				if (m < 0) break; //Map not available on this map-server.
+				unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT);
 			}
 			}
-		} else if(bl->type == BL_MOB && battle_config.mob_warp&2) {
-			int16 m = map_mapindex2mapid(sg->val3);
-			if (m < 0) break; //Map not available on this map-server.
-			unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT);
 		}
 		}
-	}
-		break;
+			break;
 
 
-	case UNT_QUAGMIRE:
-		if( !sce && battle_check_target(&sg->unit->bl,bl,sg->target_flag) > 0 )
-			sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
-		break;
+		case UNT_QUAGMIRE:
+			if( !sce && battle_check_target(&sg->unit->bl,bl,sg->target_flag) > 0 )
+				sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
+			break;
 
 
-	case UNT_VOLCANO:
-	case UNT_DELUGE:
-	case UNT_VIOLENTGALE:
-		if(!sce)
-			sc_start(bl,type,100,sg->skill_lv,sg->limit);
-		break;
+		case UNT_VOLCANO:
+		case UNT_DELUGE:
+		case UNT_VIOLENTGALE:
+			if(!sce)
+				sc_start(bl,type,100,sg->skill_lv,sg->limit);
+			break;
 
 
-	case UNT_SUITON:
-		if(!sce)
-			sc_start4(bl,type,100,sg->skill_lv,
-			map_flag_vs(bl->m) || battle_check_target(&src->bl,bl,BCT_ENEMY)>0?1:0, //Send val3 =1 to reduce agi.
-			0,0,sg->limit);
-		break;
+		case UNT_SUITON:
+			if(!sce)
+				sc_start4(bl,type,100,sg->skill_lv,
+				map_flag_vs(bl->m) || battle_check_target(&src->bl,bl,BCT_ENEMY)>0?1:0, //Send val3 =1 to reduce agi.
+				0,0,sg->limit);
+			break;
 
 
-	case UNT_HERMODE:
-		if (sg->src_id!=bl->id && battle_check_target(&src->bl,bl,BCT_PARTY|BCT_GUILD) > 0)
-			status_change_clear_buffs(bl,1); //Should dispell only allies.
-	case UNT_RICHMANKIM:
-	case UNT_ETERNALCHAOS:
-	case UNT_DRUMBATTLEFIELD:
-	case UNT_RINGNIBELUNGEN:
-	case UNT_ROKISWEIL:
-	case UNT_INTOABYSS:
-	case UNT_SIEGFRIED:
-		 //Needed to check when a dancer/bard leaves their ensemble area.
-		if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
-			return skill_id;
-		if (!sce)
-			sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
-		break;
-	case UNT_WHISTLE:
-	case UNT_ASSASSINCROSS:
-	case UNT_POEMBRAGI:
-	case UNT_APPLEIDUN:
-	case UNT_HUMMING:
-	case UNT_DONTFORGETME:
-	case UNT_FORTUNEKISS:
-	case UNT_SERVICEFORYOU:
-		if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
-			return 0;
+		case UNT_HERMODE:
+			if (sg->src_id!=bl->id && battle_check_target(&src->bl,bl,BCT_PARTY|BCT_GUILD) > 0)
+				status_change_clear_buffs(bl,1); //Should dispell only allies.
+		case UNT_RICHMANKIM:
+		case UNT_ETERNALCHAOS:
+		case UNT_DRUMBATTLEFIELD:
+		case UNT_RINGNIBELUNGEN:
+		case UNT_ROKISWEIL:
+		case UNT_INTOABYSS:
+		case UNT_SIEGFRIED:
+			 //Needed to check when a dancer/bard leaves their ensemble area.
+			if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
+				return skill_id;
+			if (!sce)
+				sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
+			break;
+		case UNT_WHISTLE:
+		case UNT_ASSASSINCROSS:
+		case UNT_POEMBRAGI:
+		case UNT_APPLEIDUN:
+		case UNT_HUMMING:
+		case UNT_DONTFORGETME:
+		case UNT_FORTUNEKISS:
+		case UNT_SERVICEFORYOU:
+			if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
+				return 0;
 
 
-		if (!sc) return 0;
-		if (!sce)
-			sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
-		else if (sce->val4 == 1) {
-			//Readjust timers since the effect will not last long.
-			sce->val4 = 0;
-			delete_timer(sce->timer, status_change_timer);
-			sce->timer = add_timer(tick+sg->limit, status_change_timer, bl->id, type);
-		}
-		break;
+			if (!sc) return 0;
+			if (!sce)
+				sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
+			else if (sce->val4 == 1) {
+				//Readjust timers since the effect will not last long.
+				sce->val4 = 0;
+				delete_timer(sce->timer, status_change_timer);
+				sce->timer = add_timer(tick+sg->limit, status_change_timer, bl->id, type);
+			}
+			break;
 
 
-	case UNT_FOGWALL:
-		if (!sce)
-		{
-			sc_start4(bl, type, 100, sg->skill_lv, sg->val1, sg->val2, sg->group_id, sg->limit);
-			if (battle_check_target(&src->bl,bl,BCT_ENEMY)>0)
-				skill_additional_effect (ss, bl, sg->skill_id, sg->skill_lv, BF_MISC, ATK_DEF, tick);
-		}
-		break;
+		case UNT_FOGWALL:
+			if (!sce)
+			{
+				sc_start4(bl, type, 100, sg->skill_lv, sg->val1, sg->val2, sg->group_id, sg->limit);
+				if (battle_check_target(&src->bl,bl,BCT_ENEMY)>0)
+					skill_additional_effect (ss, bl, sg->skill_id, sg->skill_lv, BF_MISC, ATK_DEF, tick);
+			}
+			break;
 
 
-	case UNT_GRAVITATION:
-		if (!sce)
-			sc_start4(bl,type,100,sg->skill_lv,0,BCT_ENEMY,sg->group_id,sg->limit);
-		break;
+		case UNT_GRAVITATION:
+			if (!sce)
+				sc_start4(bl,type,100,sg->skill_lv,0,BCT_ENEMY,sg->group_id,sg->limit);
+			break;
 
 
-// officially, icewall has no problems existing on occupied cells [ultramage]
-//	case UNT_ICEWALL: //Destroy the cell. [Skotlex]
-//		src->val1 = 0;
-//		if(src->limit + sg->tick > tick + 700)
-//			src->limit = DIFF_TICK(tick+700,sg->tick);
-//		break;
+		// officially, icewall has no problems existing on occupied cells [ultramage]
+		//	case UNT_ICEWALL: //Destroy the cell. [Skotlex]
+		//		src->val1 = 0;
+		//		if(src->limit + sg->tick > tick + 700)
+		//			src->limit = DIFF_TICK(tick+700,sg->tick);
+		//		break;
 
 
-	case UNT_MOONLIT:
-		//Knockback out of area if affected char isn't in Moonlit effect
-		if (sc && sc->data[SC_DANCING] && (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT)
-			break;
-		if (ss == bl) //Also needed to prevent infinite loop crash.
+		case UNT_MOONLIT:
+			//Knockback out of area if affected char isn't in Moonlit effect
+			if (sc && sc->data[SC_DANCING] && (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT)
+				break;
+			if (ss == bl) //Also needed to prevent infinite loop crash.
+				break;
+			skill_blown(ss,bl,skill_get_blewcount(sg->skill_id,sg->skill_lv),unit_getdir(bl),0);
 			break;
 			break;
-		skill_blown(ss,bl,skill_get_blewcount(sg->skill_id,sg->skill_lv),unit_getdir(bl),0);
-		break;
 
 
-	case UNT_WALLOFTHORN:
-		if( status_get_mode(bl)&MD_BOSS )
-			break;	// iRO Wiki says that this skill don't affect to Boss monsters.
-		if( map_flag_vs(bl->m) || bl->id == src->bl.id || battle_check_target(&src->bl,bl, BCT_ENEMY) == 1 )
-			skill_attack(skill_get_type(sg->skill_id), ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0);
-		break;
+		case UNT_WALLOFTHORN:
+			if( status_get_mode(bl)&MD_BOSS )
+				break;	// iRO Wiki says that this skill don't affect to Boss monsters.
+			if( map_flag_vs(bl->m) || bl->id == src->bl.id || battle_check_target(&src->bl,bl, BCT_ENEMY) == 1 )
+				skill_attack(skill_get_type(sg->skill_id), ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0);
+			break;
 
 
-	case UNT_VOLCANIC_ASH:
-		if (!sce)
-		    sc_start(bl, SC_ASH, 100, sg->skill_lv, skill_get_time(MH_VOLCANIC_ASH, sg->skill_lv));
-		break;
+		case UNT_VOLCANIC_ASH:
+			if (!sce)
+				sc_start(bl, SC_ASH, 100, sg->skill_lv, skill_get_time(MH_VOLCANIC_ASH, sg->skill_lv));
+			break;
 
 
-	case UNT_GD_LEADERSHIP:
-	case UNT_GD_GLORYWOUNDS:
-	case UNT_GD_SOULCOLD:
-	case UNT_GD_HAWKEYES:
-		if ( !sce )
-			sc_start4(bl,type,100,sg->skill_lv,0,0,0,1000);
-		break;
+		case UNT_GD_LEADERSHIP:
+		case UNT_GD_GLORYWOUNDS:
+		case UNT_GD_SOULCOLD:
+		case UNT_GD_HAWKEYES:
+			if ( !sce )
+				sc_start4(bl,type,100,sg->skill_lv,0,0,0,1000);
+			break;
 	}
 	}
 	return skill_id;
 	return skill_id;
 }
 }