From 6096ce0b42a3eee07dc70ae5ef489aa4c30bf515 Mon Sep 17 00:00:00 2001
From: ai4rei <ai4rei@54d463be-8e91-2dee-dedb-b68131a5f0ec>
Date: Sun, 26 Dec 2010 22:36:41 +0000
Subject: * Merged changes from trunk [14496:14630/trunk].

git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/branches/renewal@14632 54d463be-8e91-2dee-dedb-b68131a5f0ec
---
 src/char/char.c               |  404 ++++++------
 src/char/char.h               |    1 -
 src/char/int_guild.c          |    8 +-
 src/char/int_party.c          |    1 -
 src/char/int_storage.c        |   28 +-
 src/char/inter.c              |    2 +-
 src/char_sql/char.c           |  347 +++++------
 src/char_sql/int_guild.c      |    8 +-
 src/char_sql/int_storage.c    |    4 +-
 src/char_sql/inter.c          |    2 +-
 src/common/lock.c             |    9 +-
 src/common/mmo.h              |   16 +-
 src/common/socket.c           |   13 +
 src/common/strlib.c           |   20 +-
 src/common/utils.c            |    9 +
 src/common/utils.h            |    1 +
 src/ladmin/ladmin.c           |    3 +-
 src/login/login.c             |    2 +-
 src/map/atcommand.c           |  203 +++---
 src/map/battle.c              |    6 +-
 src/map/battle.h              |    9 +
 src/map/battleground.c        |    4 +-
 src/map/chrif.c               |   38 +-
 src/map/clif.c                |  692 ++++++++++----------
 src/map/clif.h                |  121 +++-
 src/map/guild.c               |    4 +-
 src/map/homunculus.c          |   50 +-
 src/map/instance.c            |    6 +-
 src/map/intif.c               |   11 +-
 src/map/itemdb.c              |   43 +-
 src/map/itemdb.h              |    7 +-
 src/map/log.c                 |    6 +-
 src/map/map.c                 |   31 +-
 src/map/map.h                 |    3 +
 src/map/mapreg_sql.c          |    4 +-
 src/map/mercenary.c           |    6 +-
 src/map/mob.c                 |  430 +++++--------
 src/map/mob.h                 |    7 +
 src/map/npc.c                 |  237 ++++---
 src/map/party.c               |   97 +--
 src/map/party.h               |    8 +-
 src/map/path.c                |    2 +-
 src/map/pc.c                  |  378 ++++++-----
 src/map/pc.h                  |   20 +-
 src/map/pet.c                 |    8 +-
 src/map/script.c              | 1388 ++++++++++++++++++++++++-----------------
 src/map/script.h              |    7 +
 src/map/skill.c               |   69 +-
 src/map/skill.h               |    3 +-
 src/map/status.c              |  331 +++++-----
 src/map/storage.c             |   63 +-
 src/map/unit.c                |   83 ++-
 src/map/unit.h                |    9 +-
 src/map/vending.c             |    2 +-
 src/plugins/sig.c             |    9 +-
 src/tool/adduser.c            |    6 +-
 src/txt-converter/Makefile.in |    2 +
 57 files changed, 2898 insertions(+), 2383 deletions(-)

(limited to 'src')

diff --git a/src/char/char.c b/src/char/char.c
index 91ad7d33d..6dd131976 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -2,19 +2,16 @@
 // For more information, see LICENCE in the main folder
 
 #include "../common/cbasetypes.h"
-#include "../common/mmo.h"
+#include "../common/core.h"
 #include "../common/db.h"
 #include "../common/lock.h"
 #include "../common/malloc.h"
-#include "../common/core.h"
+#include "../common/mapindex.h"
+#include "../common/mmo.h"
+#include "../common/showmsg.h"
 #include "../common/socket.h"
 #include "../common/strlib.h"
-#include "../common/showmsg.h"
 #include "../common/timer.h"
-#include "../common/lock.h"
-#include "../common/malloc.h"
-#include "../common/mapindex.h"
-#include "../common/showmsg.h"
 #include "../common/utils.h"
 #include "../common/version.h"
 #include "inter.h"
@@ -27,16 +24,8 @@
 #include "char.h"
 
 #include <sys/types.h>
-#ifdef WIN32
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
 #include <time.h>
 #include <signal.h>
-#include <fcntl.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -51,8 +40,13 @@ char friends_txt[1024] = "save/friends.txt";
 char hotkeys_txt[1024] = "save/hotkeys.txt";
 char char_log_filename[1024] = "log/char.log";
 
-int save_log = 1;	// show loading/saving messages
+// show loading/saving messages
+#ifndef TXT_SQL_CONVERT
+int save_log = 1;
+#endif
 
+//If your code editor is having problems syntax highlighting this file, uncomment this and RECOMMENT IT BEFORE COMPILING
+//#undef TXT_SQL_CONVERT
 #ifndef TXT_SQL_CONVERT
 char db_path[1024] = "db";
 
@@ -85,9 +79,12 @@ int email_creation = 0; // disabled by default
 
 bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor]
 int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor]
-char unknown_char_name[1024] = "Unknown"; // Name to use when the requested name cannot be determined
+char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined
 #define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
-char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor]
+char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor]
+
+int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius]
+int char_del_level = 0; //From which level u can delete character [Lupus]
 
 int log_char = 1;	// loggin char or not [devil]
 int log_inter = 1;	// loggin inter or not [devil]
@@ -118,7 +115,7 @@ int char_num, char_max;
 int max_connect_user = 0;
 int gm_allow_level = 99;
 int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
-int start_zeny = 500;
+int start_zeny = 0;
 int start_weapon = 1201;
 int start_armor = 2301;
 int guild_exp_rate = 100;
@@ -173,7 +170,7 @@ struct online_char_data {
 	int char_id;
 	int fd;
 	int waiting_disconnect;
-	short server;
+	short server; // -2: unknown server, -1: not connected, 0+: id of server
 };
 
 static DBMap* online_char_db; // int account_id -> struct online_char_data*
@@ -223,6 +220,7 @@ void set_char_online(int map_id, int char_id, int account_id)
 {
 	struct online_char_data* character;
 	
+	//Check to see for online conflicts
 	character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data);
 	if( character->char_id != -1 && character->server > -1 && character->server != map_id )
 	{
@@ -238,11 +236,13 @@ void set_char_online(int map_id, int char_id, int account_id)
 	if( character->server > -1 )
 		server[character->server].users++;
 
+	//Get rid of disconnect timer
 	if(character->waiting_disconnect != -1) {
 		delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
 		character->waiting_disconnect = -1;
 	}
 
+	//Notify login server
 	if (login_fd > 0 && !session[login_fd]->flag.eof)
 	{	
 		WFIFOHEAD(login_fd,6);
@@ -261,7 +261,7 @@ void set_char_offline(int char_id, int account_id)
 		if( character->server > -1 )
 			if( server[character->server].users > 0 ) // Prevent this value from going negative.
 				server[character->server].users--;
-		
+
 		if(character->waiting_disconnect != -1){
 			delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
 			character->waiting_disconnect = -1;
@@ -678,7 +678,7 @@ int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg
 		tmp_int[46] = mapindex_name2id(tmp_str[2]);
 	}	// Char structure of version 1500 (homun + mapindex maps)
 
-	memcpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex]
+	safestrncpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex]
 	p->char_id = tmp_int[0];
 	p->account_id = tmp_int[1];
 	p->slot = tmp_int[2];
@@ -1150,16 +1150,9 @@ int mmo_char_sync_timer(int tid, unsigned int tick, int id, intptr data)
 	return 0;
 }
 
-//-----------------------------------
-// Function to create a new character
-//-----------------------------------
-int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style)
+int check_char_name(char * name)
 {
-	char name[NAME_LENGTH];
 	int i;
-	
-	safestrncpy(name, name_, NAME_LENGTH);
-	normalize_name(name,TRIM_CHARS);
 
 	// check length of character name
 	if( name[0] == '\0' )
@@ -1174,33 +1167,64 @@ int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, i
 		return -1; // nick reserved for internal server messages
 
 	// Check Authorised letters/symbols in the name of the character
-	if( char_name_option == 1 ) { // only letters/symbols in char_name_letters are authorised
+	if( char_name_option == 1 )
+	{ // only letters/symbols in char_name_letters are authorised
 		for( i = 0; i < NAME_LENGTH && name[i]; i++ )
 			if( strchr(char_name_letters, name[i]) == NULL )
 				return -2;
-	} else
-	if( char_name_option == 2 ) { // letters/symbols in char_name_letters are forbidden
+	}
+	else if( char_name_option == 2 )
+	{ // letters/symbols in char_name_letters are forbidden
 		for( i = 0; i < NAME_LENGTH && name[i]; i++ )
 			if( strchr(char_name_letters, name[i]) != NULL )
 				return -2;
-	} // else, all letters/symbols are authorised (except control char removed before)
+	}
 
 	// check name (already in use?)
-	ARR_FIND( 0, char_num, i,
-		(name_ignoring_case && strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0) ||
-		(!name_ignoring_case && strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0) );
+	if( name_ignoring_case )
+	{
+		ARR_FIND( 0, char_num, i, strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0 );
+	}
+	else
+	{
+		ARR_FIND( 0, char_num, i, strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0 );
+	}
 	if( i < char_num )
 		return -1; // name already exists
 
+	return 0;
+}
+
+//-----------------------------------
+// Function to create a new character
+//-----------------------------------
+int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style)
+{
+	char name[NAME_LENGTH];
+	int i, flag;
+	
+	safestrncpy(name, name_, NAME_LENGTH);
+	normalize_name(name,TRIM_CHARS);
+
+	flag = check_char_name(name);
+	if( flag < 0 )
+		return flag;
+
 	//check other inputs
 	if((slot >= MAX_CHARS) // slots
-	|| (hair_style >= 24) // hair style
-	|| (hair_color >= 9) // hair color
 	|| (str + agi + vit + int_ + dex + luk != 6*5 ) // stats
 	|| (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values
 	|| (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs
 		return -2; // invalid input
 
+	// check the number of already existing chars in this account
+	if( char_per_account != 0 ) {
+		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == -1 );
+
+		if( i >= char_per_account )
+			return -2; // character account limit exceeded
+	}
+
 	// check char slot
 	ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == sd->account_id && char_dat[i].status.slot == slot );
 	if( i < char_num )
@@ -1563,7 +1587,7 @@ void create_online_files(void)
 				j = id[i];
 				// displaying the character name
 				if ((online_display_option & 1) || (online_display_option & 64)) { // without/with 'GM' display
-					strcpy(temp, char_dat[j].status.name);
+					safestrncpy(temp, char_dat[j].status.name, sizeof(temp));
 					//l = isGM(char_dat[j].status.account_id);
 					l = 0; //FIXME: how to get the gm level?
 					if (online_display_option & 64) {
@@ -1611,7 +1635,7 @@ void create_online_files(void)
 				// displaying of the map
 				if (online_display_option & 24) { // 8 or 16
 					// prepare map name
-					memcpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), MAP_NAME_LENGTH);
+					safestrncpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), sizeof(temp));
 					// write map name
 					if (online_display_option & 16) { // map-name AND coordinates
 						fprintf(fp2, "        <td>%s (%d, %d)</td>\n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y);
@@ -1670,10 +1694,11 @@ int count_users(void)
 	int i, users;
 
 	users = 0;
-	for(i = 0; i < MAX_MAP_SERVERS; i++)
-		if (server[i].fd >= 0)
+	for(i = 0; i < MAX_MAP_SERVERS; i++) {
+		if (server[i].fd > 0) {
 			users += server[i].users;
-
+		}
+	}
 	return users;
 }
 
@@ -1738,7 +1763,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
 #endif
 #if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803
 	mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108));
-	offset += 16;
+	offset += MAP_NAME_LENGTH_EXT;
 #endif
 	return 106+offset;
 }
@@ -1807,7 +1832,7 @@ int char_divorce(struct mmo_charstatus *cs)
 	return 0;
 }
 
-int char_married(int pl1,int pl2)
+int char_married(int pl1, int pl2)
 {
 	return (char_dat[pl1].status.char_id == char_dat[pl2].status.partner_id && char_dat[pl2].status.char_id == char_dat[pl1].status.partner_id);
 }
@@ -1850,38 +1875,18 @@ int char_family(int cid1, int cid2, int cid3)
 	return 0;
 }
 
-//Clears the given party id from all characters.
-//Since sometimes the party format changes and parties must be wiped, this 
-//method is required to prevent stress during the "party not found!" stages.
-void char_clearparty(int party_id) 
-{
-	int i;
-	for(i = 0; i < char_num; i++)
-  	{
-		if (char_dat[i].status.party_id == party_id)
-			char_dat[i].status.party_id = 0;
-	}
-}
-
 //----------------------------------------------------------------------
 // Force disconnection of an online player (with account value) by [Yor]
 //----------------------------------------------------------------------
-int disconnect_player(int account_id)
+void disconnect_player(int account_id)
 {
 	int i;
-	struct char_session_data *sd;
+	struct char_session_data* sd;
 
 	// disconnect player if online on char-server
-	for(i = 0; i < fd_max; i++) {
-		if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
-			if (sd->account_id == account_id) {
-				set_eof(i);
-				return 1;
-			}
-		}
-	}
-
-	return 0;
+	ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id );
+	if( i < fd_max )
+		set_eof(i);
 }
 
 // �L�����폜�ɔ����f�[�^�폜
@@ -2005,8 +2010,8 @@ int parse_fromlogin(int fd)
 				//printf("connect login server error : %d\n", RFIFOB(fd,2));
 				ShowError("Can not connect to login-server.\n");
 				ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
-				ShowInfo("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n");
-				ShowInfo("The communication passwords can be changed in map_athena.conf and char_athena.conf\n");
+				ShowError("Also, please make sure your accounts file (default: accounts.txt) has the correct communication username/passwords and the gender of the account is S.\n");
+				ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
 			} else {
 				ShowStatus("Connected to login-server (connection #%d).\n", fd);
 				
@@ -2099,7 +2104,7 @@ int parse_fromlogin(int fd)
 			if (RFIFOREST(fd) < 7)
 				return 0;
 		{
-			int i, j;
+			int j;
 			unsigned char buf[7];
 
 			int acc = RFIFOL(fd,2);
@@ -2107,7 +2112,7 @@ int parse_fromlogin(int fd)
 			RFIFOSKIP(fd,7);
 
 			if( acc > 0 )
-			{
+			{// TODO: Is this even possible?
 				struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
 				if( node != NULL )
 					node->sex = sex;
@@ -2162,6 +2167,8 @@ int parse_fromlogin(int fd)
 				// disconnect player if online on char-server
 				disconnect_player(acc);
 			}
+
+			// notify all mapservers about this change
 			WBUFW(buf,0) = 0x2b0d;
 			WBUFL(buf,2) = acc;
 			WBUFB(buf,6) = sex;
@@ -2235,14 +2242,14 @@ int parse_fromlogin(int fd)
 			RFIFOSKIP(fd,8 + RFIFOL(fd,4));
 		break;
 
-		// account_reg2�ύX�ʒm
+		// reply to an account_reg2 registry request
 		case 0x2729:
 			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
 				return 0;
+
 		{	//Receive account_reg2 registry, forward to map servers.
 			unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
 			memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
-//			WBUFW(buf,0) = 0x2b11;
 			WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
 			mapif_sendall(buf, WBUFW(buf,2));
 			RFIFOSKIP(fd, RFIFOW(fd,2));
@@ -2297,12 +2304,12 @@ int parse_fromlogin(int fd)
 			RFIFOSKIP(fd,6);
 		break;
 
-		// State change of account/ban notification (from login-server) by [Yor]
+		// State change of account/ban notification (from login-server)
 		case 0x2731:
 			if (RFIFOREST(fd) < 11)
 				return 0;
-			// send to all map-servers to disconnect the player
-		{
+
+		{	// send to all map-servers to disconnect the player
 			unsigned char buf[11];
 			WBUFW(buf,0) = 0x2b14;
 			WBUFL(buf,2) = RFIFOL(fd,2);
@@ -2312,6 +2319,7 @@ int parse_fromlogin(int fd)
 		}
 			// disconnect player if online on char-server
 			disconnect_player(RFIFOL(fd,2));
+
 			RFIFOSKIP(fd,11);
 		break;
 
@@ -2351,7 +2359,8 @@ int parse_fromlogin(int fd)
 			idb_remove(auth_db, aid);// reject auth attempts from map-server
 		}
 		break;
-		
+
+		// ip address update signal from login server
 		case 0x2735:
 		{
 			unsigned char buf[2];
@@ -2362,13 +2371,14 @@ int parse_fromlogin(int fd)
 
 			new_ip = host2ip(login_ip_str);
 			if (new_ip && new_ip != login_ip)
-				login_ip = new_ip; //Update login up.
+				login_ip = new_ip; //Update login ip, too.
 
 			new_ip = host2ip(char_ip_str);
 			if (new_ip && new_ip != char_ip)
 			{	//Update ip.
 				char_ip = new_ip;
 				ShowInfo("Updating IP for [%s].\n", char_ip_str);
+				// notify login server about the change
 				WFIFOHEAD(fd,6);
 				WFIFOW(fd,0) = 0x2736;
 				WFIFOL(fd,2) = htonl(char_ip);
@@ -2380,7 +2390,7 @@ int parse_fromlogin(int fd)
 		break;
 
 		default:
-			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", RFIFOW(fd,0));
+			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
 			set_eof(fd);
 			return 0;
 		}
@@ -2498,7 +2508,7 @@ void char_read_fame_list(void)
 		{
 			fame_item.id = char_dat[id[i]].status.char_id;
 			fame_item.fame = char_dat[id[i]].status.fame;
-			strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
+			safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
 
 			memcpy(&smith_fame_list[j],&fame_item,sizeof(struct fame_list));
 			j++;
@@ -2513,7 +2523,7 @@ void char_read_fame_list(void)
 		{
 			fame_item.id = char_dat[id[i]].status.char_id;
 			fame_item.fame = char_dat[id[i]].status.fame;
-			strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
+			safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
 
 			memcpy(&chemist_fame_list[j],&fame_item,sizeof(struct fame_list));
 
@@ -2527,7 +2537,7 @@ void char_read_fame_list(void)
 		{
 			fame_item.id = char_dat[id[i]].status.char_id;
 			fame_item.fame = char_dat[id[i]].status.fame;
-			strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
+			safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
 
 			memcpy(&taekwon_fame_list[j],&fame_item,sizeof(struct fame_list));
 
@@ -2536,6 +2546,7 @@ void char_read_fame_list(void)
 	}
 	DELETE_BUFFER(id);
 }
+
 // Send map-servers the fame ranking lists
 int char_send_fame_list(int fd)
 {
@@ -2565,7 +2576,7 @@ int char_send_fame_list(int fd)
 	// add total packet length
 	WBUFW(buf, 2) = len;
 
-	if(fd!=-1)
+	if (fd != -1)
 		mapif_send(fd, buf, len);
 	else
 		mapif_sendall(buf, len);
@@ -2575,7 +2586,7 @@ int char_send_fame_list(int fd)
 
 void char_update_fame_list(int type, int index, int fame)
 {
-	unsigned char buf[9];
+	unsigned char buf[8];
 	WBUFW(buf,0) = 0x2b22;
 	WBUFB(buf,2) = type;
 	WBUFB(buf,3) = index;
@@ -2588,14 +2599,18 @@ void char_update_fame_list(int type, int index, int fame)
 int char_loadName(int char_id, char* name)
 {
 	int j;
-	for( j = 0; j < char_num && char_dat[j].status.char_id != char_id; ++j )
-		;// find char
+
+	ARR_FIND( 0, char_num, j, char_dat[j].status.char_id == char_id );
 	if( j < char_num )
-		strncpy(name, char_dat[j].status.name, NAME_LENGTH);
+	{
+		safestrncpy(name, char_dat[j].status.name, NAME_LENGTH);
+		return 1;
+	}
 	else
-		strncpy(name, unknown_char_name, NAME_LENGTH);
-
-	return (j < char_num) ? 1 : 0;
+	{
+		safestrncpy(name, unknown_char_name, NAME_LENGTH);
+	}
+	return 0;
 }
 
 int search_mapserver(unsigned short map, uint32 ip, uint16 port);
@@ -2624,6 +2639,7 @@ int parse_frommap(int fd)
 				WBUFW(buf,2) = j * 4 + 10;
 				mapif_sendallwos(fd, buf, WBUFW(buf,2));
 			}
+			memset(&server[id], 0, sizeof(struct mmo_map_server));
 			server[id].fd = -1;
 			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server.
 		}
@@ -2634,8 +2650,6 @@ int parse_frommap(int fd)
 
 	while(RFIFOREST(fd) >= 2)
 	{
-		//ShowDebug("Received packet 0x%4x (%d bytes) from map-server (connection %d)\n", RFIFOW(fd, 0), RFIFOREST(fd), fd);
-
 		switch(RFIFOW(fd,0))
 		{
 
@@ -2727,7 +2741,7 @@ int parse_frommap(int fd)
 			RFIFOSKIP(fd, 10);
 		}
 		break;
-		
+
 		case 0x2afe: //set MAP user count
 			if (RFIFOREST(fd) < 4)
 				return 0;
@@ -2741,12 +2755,14 @@ int parse_frommap(int fd)
 		case 0x2aff: //set MAP users
 			if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
 				return 0;
+		{
 			//TODO: When data mismatches memory, update guild/party online/offline states.
+			int aid, cid;
+			struct online_char_data* character;
+
 			server[id].users = RFIFOW(fd,4);
 			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
 			for(i = 0; i < server[id].users; i++) {
-				int aid, cid;
-				struct online_char_data* character;
 				aid = RFIFOL(fd,6+i*8);
 				cid = RFIFOL(fd,6+i*8+4);
 				character = (struct online_char_data*)idb_ensure(online_char_db, aid, create_online_char_data);
@@ -2756,33 +2772,44 @@ int parse_frommap(int fd)
 						character->account_id, character->char_id, character->server, id, aid, cid);
 					mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
 				}
-				character->char_id = cid;
 				character->server = id;
+				character->char_id = cid;
 			}
 			//If any chars remain in -2, they will be cleaned in the cleanup timer.
-			RFIFOSKIP(fd,6+i*8);
+			RFIFOSKIP(fd,RFIFOW(fd,2));
+		}
 		break;
 
 		case 0x2b01: // Receive character data from map-server for saving
 			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
 				return 0;
+		{
+			int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
+			struct mmo_charstatus* cs;
 
-			ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == RFIFOL(fd,4) && char_dat[i].status.char_id == RFIFOL(fd,8) );
-			if( i < char_num )
+			if (size - 13 != sizeof(struct mmo_charstatus))
+			{
+				ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
+				RFIFOSKIP(fd,size);
+				break;
+			}
+			if( ( cs = search_character(aid, cid) ) != NULL )
 			{
-				memcpy(&char_dat[i].status, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
-				storage_save(char_dat[i].status.account_id, &char_dat[i].status.storage);
+				memcpy(cs, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
+				storage_save(cs->account_id, &cs->storage);
 			}
 
 			if (RFIFOB(fd,12))
-			{	//Flag, set character offline. [Skotlex]
-				set_char_offline(RFIFOL(fd,8),RFIFOL(fd,4));
+			{	//Flag, set character offline after saving. [Skotlex]
+				set_char_offline(cid, aid);
+				WFIFOHEAD(fd,10);
 				WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
-				WFIFOL(fd,2) = RFIFOL(fd,4);
-				WFIFOL(fd,6) = RFIFOL(fd,8);
+				WFIFOL(fd,2) = aid;
+				WFIFOL(fd,6) = cid;
 				WFIFOSET(fd,10);
 			}
-			RFIFOSKIP(fd,RFIFOW(fd,2));
+			RFIFOSKIP(fd,size);
+		}
 		break;
 
 		case 0x2b02: // req char selection
@@ -2805,7 +2832,8 @@ int parse_frommap(int fd)
 			node->login_id2 = login_id2;
 			//node->sex = 0;
 			node->ip = ntohl(ip);
-			node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
+			//node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
+			//node->gmlevel = 0;
 			idb_put(auth_db, account_id, node);
 
 			//Set char to "@ char select" in online db [Kevin]
@@ -2823,22 +2851,15 @@ int parse_frommap(int fd)
 			if (RFIFOREST(fd) < 35)
 				return 0;
 		{
-			unsigned short name;
 			int map_id, map_fd = -1;
 			struct online_char_data* data;
 			struct mmo_charstatus* char_data;
 
-			name = RFIFOW(fd,18);
-			map_id = search_mapserver(name, ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
+			map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
 			if (map_id >= 0)
 				map_fd = server[map_id].fd;
-			for(i = 0; i < char_num; i++) {
-			if (char_dat[i].status.account_id == RFIFOL(fd,2) &&
-			    char_dat[i].status.char_id == RFIFOL(fd,14))
-				break;
-			}
 
-			char_data = i < char_num ? &char_dat[i].status : NULL;
+			char_data = search_character(RFIFOL(fd,2), RFIFOL(fd,14));
 
 			if (map_fd >= 0 && session[map_fd] && char_data) 
 			{	//Send the map server the auth of this player.
@@ -2940,6 +2961,7 @@ int parse_frommap(int fd)
 
 				if( login_fd <= 0 )
 					result = 3; // 3-login-server offline
+				//FIXME: need to move this check to login server [ultramage]
 //				else
 //				if( acc != -1 && isGM(acc) < isGM(account_id) )
 //					result = 2; // 2-gm level too low
@@ -3053,10 +3075,10 @@ int parse_frommap(int fd)
 		break;
 
 		case 0x2b16: // Receive rates [Wizputer]
-			if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8))
+			if( RFIFOREST(fd) < 14 )
 				return 0;
 			// Txt doesn't need this packet, so just skip it
-			RFIFOSKIP(fd,RFIFOW(fd,8));
+			RFIFOSKIP(fd,14);
 		break;
 
 		case 0x2b17: // Character disconnected set online 0 [Wizputer]
@@ -3238,7 +3260,7 @@ int lan_subnetcheck(uint32 ip)
 {
 	int i;
 	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
-	if ( i < subnet_count ) {
+	if( i < subnet_count ) {
 		ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask));
 		return subnet[i].char_ip;
 	} else {
@@ -3255,7 +3277,7 @@ int parse_char(int fd)
 	int map_fd;
 	struct char_session_data* sd;
 	uint32 ipl = session[fd]->client_addr;
-	
+
 	sd = (struct char_session_data*)session[fd]->session_data;
 
 	// disconnect any player if no login-server.
@@ -3265,7 +3287,7 @@ int parse_char(int fd)
 	if(session[fd]->flag.eof)
 	{
 		if( sd != NULL && sd->auth )
-		{
+		{	// already authed client
 			struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
 			if( data != NULL && data->fd == fd)
 				data->fd = -1;
@@ -3377,15 +3399,21 @@ int parse_char(int fd)
 			ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] >= 0 && char_dat[sd->found_char[ch]].status.slot == slot );
 			if (ch == MAX_CHARS)
 			{	//Not found?? May be forged packet.
+				WFIFOHEAD(fd,3);
+				WFIFOW(fd,0) = 0x6c;
+				WFIFOB(fd,2) = 0; // rejected from server
+				WFIFOSET(fd,3);
 				break;
 			}
 			cd = &char_dat[sd->found_char[ch]].status;
 			char_log("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s.\n", sd->account_id, slot, cd->name);
 
 			cd->sex = sd->sex;
-			
+
+			ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, cd->name);
+
 			// searching map server
-			i = search_mapserver(cd->last_point.map,-1,-1);
+			i = search_mapserver(cd->last_point.map, -1, -1);
 
 			// if map is not found, we check major cities
 			if (i < 0) {
@@ -3430,6 +3458,7 @@ int parse_char(int fd)
 				cd->last_point.map = j;
 			}
 
+			//Send NEW auth packet [Kevin]
 			//FIXME: is this case even possible? [ultramage]
 			if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
 			{
@@ -3454,8 +3483,6 @@ int parse_char(int fd)
 			WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
 			WFIFOSET(fd,28);
 
-			ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch);
-
 			// create temporary auth entry
 			CREATE(node, struct auth_node, 1);
 			node->account_id = sd->account_id;
@@ -3495,8 +3522,9 @@ int parse_char(int fd)
 			else
 			{
 				int len;
+
 				// send to player
-				WFIFOHEAD(fd,MAX_CHAR_BUF+2);
+				WFIFOHEAD(fd,2+MAX_CHAR_BUF);
 				WFIFOW(fd,0) = 0x6d;
 				len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat[i].status);
 				WFIFOSET(fd,len);
@@ -3504,7 +3532,7 @@ int parse_char(int fd)
 				// add new entry to the chars list
 				ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
 				if( ch < MAX_CHARS )
-						sd->found_char[ch] = i; // position of the new char in the char_dat[] array
+					sd->found_char[ch] = i; // position of the new char in the char_dat[] array
 			}
 
 			RFIFOSKIP(fd,37);
@@ -3519,12 +3547,13 @@ int parse_char(int fd)
 		{
 			int cid = RFIFOL(fd,2);
 			struct mmo_charstatus* cs = NULL;
+
 			ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
 			memcpy(email, RFIFOP(fd,6), 40);
 			RFIFOSKIP(fd,RFIFOREST(fd)); // hack to make the other deletion packet work
 
 			if (e_mail_check(email) == 0)
-				strncpy(email, "a@a.com", 40); // default e-mail
+				safestrncpy(email, "a@a.com", sizeof(email)); // default e-mail
 
 			// BEGIN HACK: "change email using the char deletion 'confirm email' menu"
 			// if we activated email creation and email is default email
@@ -3587,6 +3616,17 @@ int parse_char(int fd)
 
 			// deletion process
 			cs = &char_dat[sd->found_char[i]].status;
+
+			//check for config char del condition [Lupus]
+			if( ( char_del_level > 0 && cs->base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && cs->base_level <= (unsigned int)(-char_del_level) ) )
+			{
+				WFIFOHEAD(fd,3);
+				WFIFOW(fd,0) = 0x70;
+				WFIFOB(fd,2) = 1;  // This character cannot be deleted.
+				WFIFOSET(fd,3);
+				break;
+			}
+
 			char_delete(cs);
 			if (sd->found_char[i] != char_num - 1) {
 				int j, k;
@@ -3632,9 +3672,25 @@ int parse_char(int fd)
 		// R 028d <account ID>.l <char ID>.l <new name>.24B
 		case 0x28d:
 			FIFOSD_CHECK(34);
-			//not implemented
-			RFIFOSKIP(fd,34);
-		break;
+			{
+				//not implemented
+				RFIFOSKIP(fd,34);
+			}
+			break;
+		//Confirm change name.
+		// 0x28f <char_id>.L
+		case 0x28f:
+			// 0: Sucessfull
+			// 1: This character's name has already been changed. You cannot change a character's name more than once.
+			// 2: User information is not correct.
+			// 3: You have failed to change this character's name.
+			// 4: Another user is using this character name, so please select another one.
+			FIFOSD_CHECK(6);
+			{
+				//not implemented
+				RFIFOSKIP(fd,6);
+			}
+			break;
 
 		// captcha code request (not implemented)
 		// R 07e5 <?>.w <aid>.l
@@ -3752,7 +3808,6 @@ int parse_console(char* buf)
 	return 0;
 }
 
-// �S�Ă�MAP�T�[�o�[�Ƀf�[�^���M�i���M����map�I�̐���Ԃ��j
 int mapif_sendall(unsigned char *buf, unsigned int len)
 {
 	int i, c;
@@ -3771,7 +3826,6 @@ int mapif_sendall(unsigned char *buf, unsigned int len)
 	return c;
 }
 
-// �����ȊO�̑S�Ă�MAP�T�[�o�[�Ƀf�[�^���M�i���M����map�I�̐���Ԃ��j
 int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len)
 {
 	int i, c;
@@ -3789,19 +3843,19 @@ int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len)
 
 	return c;
 }
-// MAP�T�[�o�[�Ƀf�[�^���M�imap�I�����m�F�L��j
+
 int mapif_send(int fd, unsigned char *buf, unsigned int len)
 {
 	int i;
 
 	if (fd >= 0) {
-		for(i = 0; i < MAX_MAP_SERVERS; i++) {
-			if (fd == server[i].fd) {
-				WFIFOHEAD(fd,len);
-				memcpy(WFIFOP(fd,0), buf, len);
-				WFIFOSET(fd,len);
-				return 1;
-			}
+		ARR_FIND( 0, MAX_MAP_SERVERS, i, fd == server[i].fd );
+		if( i < MAX_MAP_SERVERS )
+		{
+			WFIFOHEAD(fd,len);
+			memcpy(WFIFOP(fd,0), buf, len);
+			WFIFOSET(fd,len);
+			return 1;
 		}
 	}
 	return 0;
@@ -4028,7 +4082,7 @@ int char_config_read(const char *cfgName)
 		remove_control_chars(w1);
 		remove_control_chars(w2);
 		if(strcmpi(w1,"timestamp_format") == 0) {
-			strncpy(timestamp_format, w2, 20);
+			safestrncpy(timestamp_format, w2, sizeof(timestamp_format));
 		} else if(strcmpi(w1,"console_silent")==0){
 			ShowInfo("Console Silent Setting: %d\n", atoi(w2));
 			msg_silent = atoi(w2);
@@ -4036,23 +4090,21 @@ int char_config_read(const char *cfgName)
 		} else if(strcmpi(w1,"stdout_with_ansisequence")==0){
 			stdout_with_ansisequence = config_switch(w2);
 		} else if (strcmpi(w1, "userid") == 0) {
-			strncpy(userid, w2, 24);
+			safestrncpy(userid, w2, sizeof(userid));
 		} else if (strcmpi(w1, "passwd") == 0) {
-			strncpy(passwd, w2, 24);
+			safestrncpy(passwd, w2, sizeof(passwd));
 		} else if (strcmpi(w1, "server_name") == 0) {
-			strncpy(server_name, w2, 20);
-			server_name[sizeof(server_name) - 1] = '\0';
+			safestrncpy(server_name, w2, sizeof(server_name));
 			ShowStatus("%s server has been initialized\n", w2);
 		} else if (strcmpi(w1, "wisp_server_name") == 0) {
 			if (strlen(w2) >= 4) {
-				memcpy(wisp_server_name, w2, sizeof(wisp_server_name));
-				wisp_server_name[sizeof(wisp_server_name) - 1] = '\0';
+				safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name));
 			}
 		} else if (strcmpi(w1, "login_ip") == 0) {
 			char ip_str[16];
 			login_ip = host2ip(w2);
 			if (login_ip) {
-				strncpy(login_ip_str, w2, sizeof(login_ip_str));
+				safestrncpy(login_ip_str, w2, sizeof(login_ip_str));
 				ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str));
 			}
 		} else if (strcmpi(w1, "login_port") == 0) {
@@ -4061,14 +4113,14 @@ int char_config_read(const char *cfgName)
 			char ip_str[16];
 			char_ip = host2ip(w2);
 			if (char_ip){
-				strncpy(char_ip_str, w2, sizeof(char_ip_str));
+				safestrncpy(char_ip_str, w2, sizeof(char_ip_str));
 				ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str));
 			}
 		} else if (strcmpi(w1, "bind_ip") == 0) {
 			char ip_str[16];
 			bind_ip = host2ip(w2);
 			if (bind_ip) {
-				strncpy(bind_ip_str, w2, sizeof(bind_ip_str));
+				safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str));
 				ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str));
 			}
 		} else if (strcmpi(w1, "char_port") == 0) {
@@ -4082,14 +4134,14 @@ int char_config_read(const char *cfgName)
 		} else if (strcmpi(w1, "email_creation") == 0) {
 			email_creation = config_switch(w2);
 		} else if (strcmpi(w1, "scdata_txt") == 0) { //By Skotlex
-			strcpy(scdata_txt, w2);
+			safestrncpy(scdata_txt, w2, sizeof(scdata_txt));
 #endif
 		} else if (strcmpi(w1, "char_txt") == 0) {
-			strcpy(char_txt, w2);
+			safestrncpy(char_txt, w2, sizeof(char_txt));
 		} else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw
-			strcpy(friends_txt, w2);
+			safestrncpy(friends_txt, w2, sizeof(friends_txt));
 		} else if (strcmpi(w1, "hotkeys_txt") == 0) { //By davidsiaw
-			strcpy(hotkeys_txt, w2);
+			safestrncpy(hotkeys_txt, w2, sizeof(hotkeys_txt));
 #ifndef TXT_SQL_CONVERT
 		} else if (strcmpi(w1, "max_connect_user") == 0) {
 			max_connect_user = atoi(w2);
@@ -4111,10 +4163,8 @@ int char_config_read(const char *cfgName)
 			if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3)
 				continue;
 			start_point.map = mapindex_name2id(map);
-			if (!start_point.map) {
+			if (!start_point.map)
 				ShowError("Specified start_point %s not found in map-index cache.\n", map);
-				start_point.map = 0;
-			}
 			start_point.x = x;
 			start_point.y = y;
 		} else if (strcmpi(w1, "start_zeny") == 0) {
@@ -4132,21 +4182,25 @@ int char_config_read(const char *cfgName)
 		} else if(strcmpi(w1,"log_char")==0) {		//log char or not [devil]
 			log_char = atoi(w2);
 		} else if (strcmpi(w1, "unknown_char_name") == 0) {
-			strcpy(unknown_char_name, w2);
+			safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name));
 			unknown_char_name[NAME_LENGTH-1] = '\0';
 		} else if (strcmpi(w1, "char_log_filename") == 0) {
-			strcpy(char_log_filename, w2);
+			safestrncpy(char_log_filename, w2, sizeof(char_log_filename));
 		} else if (strcmpi(w1, "name_ignoring_case") == 0) {
 			name_ignoring_case = (bool)config_switch(w2);
 		} else if (strcmpi(w1, "char_name_option") == 0) {
 			char_name_option = atoi(w2);
 		} else if (strcmpi(w1, "char_name_letters") == 0) {
-			strcpy(char_name_letters, w2);
+			safestrncpy(char_name_letters, w2, sizeof(char_name_letters));
+		} else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
+			char_per_account = atoi(w2);
+		} else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus]
+			char_del_level = atoi(w2);
 // online files options
 		} else if (strcmpi(w1, "online_txt_filename") == 0) {
-			strcpy(online_txt_filename, w2);
+			safestrncpy(online_txt_filename, w2, sizeof(online_txt_filename));
 		} else if (strcmpi(w1, "online_html_filename") == 0) {
-			strcpy(online_html_filename, w2);
+			safestrncpy(online_html_filename, w2, sizeof(online_html_filename));
 		} else if (strcmpi(w1, "online_sorting_option") == 0) {
 			online_sorting_option = atoi(w2);
 		} else if (strcmpi(w1, "online_display_option") == 0) {
@@ -4160,7 +4214,7 @@ int char_config_read(const char *cfgName)
 			if (online_refresh_html < 1)
 				online_refresh_html = 1;
 		} else if(strcmpi(w1,"db_path")==0) {
-			strcpy(db_path,w2);
+			safestrncpy(db_path, w2, sizeof(db_path));
 		} else if (strcmpi(w1, "console") == 0) {
 			console = config_switch(w2);
 		} else if (strcmpi(w1, "fame_list_alchemist") == 0) {
@@ -4195,11 +4249,6 @@ int char_config_read(const char *cfgName)
 }
 
 #ifndef TXT_SQL_CONVERT
-int chardb_final(int key, void* data, va_list va)
-{
-	aFree(data);
-	return 0;
-}
 void do_final(void)
 {
 	ShowStatus("Terminating server.\n");
@@ -4209,9 +4258,10 @@ void do_final(void)
 	set_all_offline(-1);
 	flush_fifos();
 	// write online players files with no player
-	online_char_db->clear(online_char_db, NULL); //clean the db...
+	online_char_db->clear(online_char_db, NULL);
 	create_online_files();
-	online_char_db->destroy(online_char_db, NULL); //dispose the db...
+
+	online_char_db->destroy(online_char_db, NULL);
 	auth_db->destroy(auth_db, NULL);
 	
 	if(char_dat) aFree(char_dat);
@@ -4294,11 +4344,11 @@ int do_init(int argc, char **argv)
 		else
 			ShowStatus("Defaulting to %s as our IP address\n", ip_str);
 		if (!login_ip) {
-			strcpy(login_ip_str, ip_str);
+			safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str));
 			login_ip = str2ip(login_ip_str);
 		}
 		if (!char_ip) {
-			strcpy(char_ip_str, ip_str);
+			safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str));
 			char_ip = str2ip(char_ip_str);
 		}
 	}
diff --git a/src/char/char.h b/src/char/char.h
index 8c8d7c554..18bb7b1b5 100644
--- a/src/char/char.h
+++ b/src/char/char.h
@@ -29,7 +29,6 @@ int mapif_send(int fd,unsigned char *buf, unsigned int len);
 int char_married(int pl1,int pl2);
 int char_child(int parent_id, int child_id);
 int char_family(int cid1, int cid2, int cid3);
-void char_clearparty(int party_id);
 
 int char_log(char *fmt, ...);
 
diff --git a/src/char/int_guild.c b/src/char/int_guild.c
index 9a815200f..31cceeff0 100644
--- a/src/char/int_guild.c
+++ b/src/char/int_guild.c
@@ -865,8 +865,8 @@ int mapif_guild_notice(struct guild *g)
 
 	WBUFW(buf,0) = 0x383e;
 	WBUFL(buf,2) = g->guild_id;
-	memcpy(WBUFP(buf,6), g->mes1, 60);
-	memcpy(WBUFP(buf,66), g->mes2, 120);
+	memcpy(WBUFP(buf,6), g->mes1, MAX_GUILDMES1);
+	memcpy(WBUFP(buf,66), g->mes2, MAX_GUILDMES2);
 	mapif_sendall(buf, 186);
 
 	return 0;
@@ -1404,8 +1404,8 @@ int mapif_parse_GuildNotice(int fd, int guild_id, const char *mes1, const char *
 	g = (struct guild*)idb_get(guild_db, guild_id);
 	if (g == NULL)
 		return 0;
-	memcpy(g->mes1, mes1, 60);
-	memcpy(g->mes2, mes2, 120);
+	memcpy(g->mes1, mes1, MAX_GUILDMES1);
+	memcpy(g->mes2, mes2, MAX_GUILDMES2);
 
 	return mapif_guild_notice(g);
 }
diff --git a/src/char/int_party.c b/src/char/int_party.c
index 04d638049..b340aa9cf 100644
--- a/src/char/int_party.c
+++ b/src/char/int_party.c
@@ -488,7 +488,6 @@ int mapif_parse_PartyInfo(int fd, int party_id)
 		mapif_party_info(fd, &p->party);
 	else {
 		mapif_party_noinfo(fd, party_id);
-		char_clearparty(party_id);
 	}
 
 	return 0;
diff --git a/src/char/int_storage.c b/src/char/int_storage.c
index bae72fcf4..2a041b286 100644
--- a/src/char/int_storage.c
+++ b/src/char/int_storage.c
@@ -101,12 +101,12 @@ int guild_storage_tostr(char *str,struct guild_storage *p)
 	str_p+=sprintf(str,"%d,%d\t",p->guild_id,p->storage_amount);
 
 	for(i=0;i<MAX_GUILD_STORAGE;i++)
-		if( (p->storage_[i].nameid) && (p->storage_[i].amount) ){
+		if( (p->items[i].nameid) && (p->items[i].amount) ){
 			str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d",
-				p->storage_[i].id,p->storage_[i].nameid,p->storage_[i].amount,p->storage_[i].equip,
-				p->storage_[i].identify,p->storage_[i].refine,p->storage_[i].attribute);
+				p->items[i].id,p->items[i].nameid,p->items[i].amount,p->items[i].equip,
+				p->items[i].identify,p->items[i].refine,p->items[i].attribute);
 			for(j=0; j<MAX_SLOTS; j++)
-				str_p += sprintf(str_p,",%d",p->storage_[i].card[j]);
+				str_p += sprintf(str_p,",%d",p->items[i].card[j]);
 			str_p += sprintf(str_p," ");
 			f++;
 		}
@@ -138,15 +138,15 @@ int guild_storage_fromstr(char *str,struct guild_storage *p)
 			&tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
 			&tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8)
 		{
-			p->storage_[i].id = tmp_int[0];
-			p->storage_[i].nameid = tmp_int[1];
-			p->storage_[i].amount = tmp_int[2];
-			p->storage_[i].equip = tmp_int[3];
-			p->storage_[i].identify = tmp_int[4];
-			p->storage_[i].refine = tmp_int[5];
-			p->storage_[i].attribute = tmp_int[6];
+			p->items[i].id = tmp_int[0];
+			p->items[i].nameid = tmp_int[1];
+			p->items[i].amount = tmp_int[2];
+			p->items[i].equip = tmp_int[3];
+			p->items[i].identify = tmp_int[4];
+			p->items[i].refine = tmp_int[5];
+			p->items[i].attribute = tmp_int[6];
 			for(j = 0; j < MAX_SLOTS && tmp_str[0] && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++)
-				p->storage_[i].card[j] = tmp_int[0];
+				p->items[i].card[j] = tmp_int[0];
 			next += len;
 			if (str[next] == ' ')
 				next++;
@@ -371,8 +371,8 @@ int inter_guild_storage_delete(int guild_id)
 	if(gs) {
 		int i;
 		for(i=0;i<gs->storage_amount;i++){
-			if(gs->storage_[i].card[0] == (short)0xff00)
-				inter_pet_delete( MakeDWord(gs->storage_[i].card[1],gs->storage_[i].card[2]) );
+			if(gs->items[i].card[0] == (short)0xff00)
+				inter_pet_delete( MakeDWord(gs->items[i].card[1],gs->items[i].card[2]) );
 		}
 		idb_remove(guild_storage_db,guild_id);
 	}
diff --git a/src/char/inter.c b/src/char/inter.c
index 051d8117a..8d9cac99f 100644
--- a/src/char/inter.c
+++ b/src/char/inter.c
@@ -210,7 +210,7 @@ static int inter_config_read(const char *cfgName) {
 		} else if(strcmpi(w1,"log_inter")==0) {
 			log_inter = atoi(w2);
 		} else if(strcmpi(w1, "main_chat_nick")==0){	// Main chat nick [LuzZza]
-			strcpy(main_chat_nick, w2);
+			safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick));
 #endif //TXT_SQL_CONVERT
 		} else if (strcmpi(w1, "import") == 0) {
 			inter_config_read(w2);
diff --git a/src/char_sql/char.c b/src/char_sql/char.c
index 36944cd35..46b645ce6 100644
--- a/src/char_sql/char.c
+++ b/src/char_sql/char.c
@@ -2,17 +2,17 @@
 // For more information, see LICENCE in the main folder
 
 #include "../common/cbasetypes.h"
-#include "../common/strlib.h"
 #include "../common/core.h"
-#include "../common/timer.h"
-#include "../common/mmo.h"
 #include "../common/db.h"
 #include "../common/malloc.h"
 #include "../common/mapindex.h"
+#include "../common/mmo.h"
 #include "../common/showmsg.h"
 #include "../common/socket.h"
-#include "../common/version.h"
+#include "../common/strlib.h"
+#include "../common/timer.h"
 #include "../common/utils.h"
+#include "../common/version.h"
 #include "inter.h"
 #include "int_guild.h"
 #include "int_homun.h"
@@ -60,6 +60,13 @@ char friend_db[256] = "friends";
 char hotkey_db[256] = "hotkey";
 char quest_db[256] = "quest";
 
+// show loading/saving messages
+#ifdef TXT_SQL_CONVERT
+int save_log = 0; //Have the logs be off by default when converting
+#else
+int save_log = 1;
+#endif
+
 //If your code editor is having problems syntax highlighting this file, uncomment this and RECOMMENT IT BEFORE COMPILING
 //#undef TXT_SQL_CONVERT
 #ifndef TXT_SQL_CONVERT
@@ -94,11 +101,11 @@ int char_maintenance = 0;
 bool char_new = true;
 int char_new_display = 0;
 
-int name_ignoring_case = 0; // Allow or not identical name for characters but with a different case by [Yor]
+bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor]
 int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor]
 char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined
 #define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
-char char_name_letters[1024] = ""; // list of letters/symbols used to authorise or not a name of a character. by [Yor]
+char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor]
 
 int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius]
 int char_del_level = 0; //From which level u can delete character [Lupus]
@@ -106,12 +113,6 @@ int char_del_level = 0; //From which level u can delete character [Lupus]
 int log_char = 1;	// loggin char or not [devil]
 int log_inter = 1;	// loggin inter or not [devil]
 
-#ifdef TXT_SQL_CONVERT
-int save_log = 0; //Have the logs be off by default when converting
-#else
-int save_log = 1;
-#endif
-
 // Advanced subnet check [LuzZza]
 struct s_subnet {
 	uint32 mask;
@@ -813,7 +814,6 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
 	return 0;
 }
 
-#define MAX_CHAR_BUF 110 //Max size (for WFIFOHEAD calls)
 int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p);
 
 #ifndef TXT_SQL_CONVERT
@@ -1249,7 +1249,7 @@ int check_char_name(char * name, char * esc_name)
 	// check for reserved names
 	if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 )
 		return -1; // nick reserved for internal server messages
-	
+
 	// Check Authorised letters/symbols in the name of the character
 	if( char_name_option == 1 )
 	{ // only letters/symbols in char_name_letters are authorised
@@ -1264,13 +1264,14 @@ int check_char_name(char * name, char * esc_name)
 				return -2;
 	}
 
+	// check name (already in use?)
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
-	{ // check name (already in use?)
+	{
 		Sql_ShowDebug(sql_handle);
 		return -2;
 	}
 	if( Sql_NumRows(sql_handle) > 0 )
-		return -1; //  name already exists
+		return -1; // name already exists
 
 	return 0;
 }
@@ -1294,8 +1295,6 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag
 
 	//check other inputs
 	if((slot >= MAX_CHARS) // slots
-	|| (hair_style >= 24) // hair style
-	|| (hair_color >= 9) // hair color
 	|| (str + agi + vit + int_ + dex + luk != 6*5 ) // stats
 	|| (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values
 	|| (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs
@@ -1524,27 +1523,26 @@ int delete_char_sql(int char_id)
 	return 0;
 }
 
-//==========================================================================================================
-
+//---------------------------------------------------------------------
+// This function return the number of online players in all map-servers
+//---------------------------------------------------------------------
 int count_users(void)
 {
 	int i, users;
 
-	if (login_fd > 0 && session[login_fd]){
-		users = 0;
-		for(i = 0; i < MAX_MAP_SERVERS; i++) {
-			if (server[i].fd > 0) {
-				users += server[i].users;
-			}
+	users = 0;
+	for(i = 0; i < MAX_MAP_SERVERS; i++) {
+		if (server[i].fd > 0) {
+			users += server[i].users;
 		}
-		return users;
 	}
-	return 0;
+	return users;
 }
 
-/// Writes char data to the buffer in the format used by the client.
-/// Used in packets 0x6b (chars info) and 0x6d (new char info)
+// Writes char data to the buffer in the format used by the client.
+// Used in packets 0x6b (chars info) and 0x6d (new char info)
 // Returns the size
+#define MAX_CHAR_BUF 110 //Max size (for WFIFOHEAD calls)
 int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
 {
 	unsigned short offset = 0;
@@ -1598,15 +1596,18 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
 	WBUFW(buf,104) = p->slot;
 #if PACKETVER >= 20061023
 	WBUFW(buf,106) = ( p->rename > 0 ) ? 0 : 1;
-	offset+=2;
+	offset += 2;
 #endif
 #if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803
 	mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108));
-	offset += 16;
+	offset += MAP_NAME_LENGTH_EXT;
 #endif
 	return 106+offset;
 }
 
+//----------------------------------------
+// Function to send characters to a player
+//----------------------------------------
 int mmo_char_send006b(int fd, struct char_session_data* sd)
 {
 	int j, offset = 0;
@@ -1671,9 +1672,9 @@ int char_child(int parent_id, int child_id)
 	return 0;
 }
 
-int char_family(int pl1, int pl2, int pl3)
+int char_family(int cid1, int cid2, int cid3)
 {
-	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, pl1, pl2, pl3) )
+	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3) )
 		Sql_ShowDebug(sql_handle);
 	else while( SQL_SUCCESS == Sql_NextRow(sql_handle) )
 	{
@@ -1686,9 +1687,9 @@ int char_family(int pl1, int pl2, int pl3)
 		Sql_GetData(sql_handle, 1, &data, NULL); partnerid = atoi(data);
 		Sql_GetData(sql_handle, 2, &data, NULL); childid = atoi(data);
 
-		if( (pl1 == charid    && ((pl2 == partnerid && pl3 == childid  ) || (pl2 == childid   && pl3 == partnerid))) ||
-			(pl1 == partnerid && ((pl2 == charid    && pl3 == childid  ) || (pl2 == childid   && pl3 == charid   ))) ||
-			(pl1 == childid   && ((pl2 == charid    && pl3 == partnerid) || (pl2 == partnerid && pl3 == charid   ))) )
+		if( (cid1 == charid    && ((cid2 == partnerid && cid3 == childid  ) || (cid2 == childid   && cid3 == partnerid))) ||
+			(cid1 == partnerid && ((cid2 == charid    && cid3 == childid  ) || (cid2 == childid   && cid3 == charid   ))) ||
+			(cid1 == childid   && ((cid2 == charid    && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid   ))) )
 		{
 			Sql_FreeResult(sql_handle);
 			return childid;
@@ -1698,6 +1699,20 @@ int char_family(int pl1, int pl2, int pl3)
 	return 0;
 }
 
+//----------------------------------------------------------------------
+// Force disconnection of an online player (with account value) by [Yor]
+//----------------------------------------------------------------------
+void disconnect_player(int account_id)
+{
+	int i;
+	struct char_session_data* sd;
+
+	// disconnect player if online on char-server
+	ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id );
+	if( i < fd_max )
+		set_eof(i);
+}
+
 static void char_auth_ok(int fd, struct char_session_data *sd)
 {
 	struct online_char_data* character;
@@ -1777,17 +1792,17 @@ int parse_fromlogin(int fd)
 				return 0;
 
 			if (RFIFOB(fd,2)) {
-				//printf("connect login server error : %d\n", RFIFOB(fd, 2));
+				//printf("connect login server error : %d\n", RFIFOB(fd,2));
 				ShowError("Can not connect to login-server.\n");
 				ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
 				ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
 				ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
-			}else {
+			} else {
 				ShowStatus("Connected to login-server (connection #%d).\n", fd);
 				
 				//Send online accounts to login server.
 				send_accounts_tologin(-1, gettick(), 0, 0);
-			
+
 				// if no map-server already connected, display a message...
 				ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd > 0 && server[i].map[0] );
 				if( i == MAX_MAP_SERVERS )
@@ -1874,19 +1889,18 @@ int parse_fromlogin(int fd)
 			if (RFIFOREST(fd) < 7)
 				return 0;
 		{
-			unsigned char buf[16];
+			unsigned char buf[7];
 
 			int acc = RFIFOL(fd,2);
 			int sex = RFIFOB(fd,6);
 			RFIFOSKIP(fd,7);
 
 			if( acc > 0 )
-			{
+			{// TODO: Is this even possible?
 				int char_id[MAX_CHARS];
 				int class_[MAX_CHARS];
 				int guild_id[MAX_CHARS];
 				int num;
-				int i;
 				char* data;
 
 				struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
@@ -1935,12 +1949,10 @@ int parse_fromlogin(int fd)
 						inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
 				}
 				Sql_FreeResult(sql_handle);
-			}
 
-			// disconnect player if online on char-server
-			ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == acc );
-			if( i < fd_max )
-				set_eof(i);
+				// disconnect player if online on char-server
+				disconnect_player(acc);
+			}
 
 			// notify all mapservers about this change
 			WBUFW(buf,0) = 0x2b0d;
@@ -1960,8 +1972,8 @@ int parse_fromlogin(int fd)
 			memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
 			WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
 			mapif_sendall(buf, WBUFW(buf,2));
-		}
 			RFIFOSKIP(fd, RFIFOW(fd,2));
+		}
 		break;
 
 		// State change of account/ban notification (from login-server)
@@ -1978,9 +1990,7 @@ int parse_fromlogin(int fd)
 			mapif_sendall(buf, 11);
 		}
 			// disconnect player if online on char-server
-			ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == RFIFOL(fd,2) );
-			if( i < fd_max )
-				set_eof(i);
+			disconnect_player(RFIFOL(fd,2));
 
 			RFIFOSKIP(fd,11);
 		break;
@@ -2032,8 +2042,8 @@ int parse_fromlogin(int fd)
 			mapif_sendall(buf, 2);
 
 			new_ip = host2ip(login_ip_str);
-			if (new_ip && new_ip != login_ip) //Update login ip, too.
-				login_ip = new_ip;
+			if (new_ip && new_ip != login_ip)
+				login_ip = new_ip; //Update login ip, too.
 
 			new_ip = host2ip(char_ip_str);
 			if (new_ip && new_ip != char_ip)
@@ -2046,13 +2056,13 @@ int parse_fromlogin(int fd)
 				WFIFOL(fd,2) = htonl(char_ip);
 				WFIFOSET(fd,6);
 			}
-		}
 
 			RFIFOSKIP(fd,2);
+		}
 		break;
 
 		default:
-			ShowError("Unknown packet 0x%04x received from login server, disconnecting.\n", command);
+			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
 			set_eof(fd);
 			return 0;
 		}
@@ -2180,6 +2190,7 @@ int char_send_fame_list(int fd)
 		mapif_send(fd, buf, len);
 	else
 		mapif_sendall(buf, len);
+
 	return 0;
 }
 
@@ -2205,13 +2216,12 @@ int char_loadName(int char_id, char* name)
 	else if( SQL_SUCCESS == Sql_NextRow(sql_handle) )
 	{
 		Sql_GetData(sql_handle, 0, &data, &len);
-		memset(name, 0, NAME_LENGTH);
-		memcpy(name, data, min(len, NAME_LENGTH));
+		safestrncpy(name, data, NAME_LENGTH);
 		return 1;
 	}
 	else
 	{
-		memcpy(name, unknown_char_name, NAME_LENGTH);
+		safestrncpy(name, unknown_char_name, NAME_LENGTH);
 	}
 	return 0;
 }
@@ -2220,15 +2230,9 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port);
 
 int parse_frommap(int fd)
 {
-	int i = 0, j = 0;
+	int i, j;
 	int id;
 
-	// Sometimes fd=0, and it will cause server crash. Don't know why. :(
-	if (fd <= 0) {
-		ShowError("parse_frommap error fd=%d\n", fd);
-		return 0;
-	}
-
 	ARR_FIND( 0, MAX_MAP_SERVERS, id, server[id].fd == fd );
 	if(id == MAX_MAP_SERVERS)
 		set_eof(fd);
@@ -2260,7 +2264,7 @@ int parse_frommap(int fd)
 
 	while(RFIFOREST(fd) >= 2)
 	{
-		switch(RFIFOW(fd, 0))
+		switch(RFIFOW(fd,0))
 		{
 
 		case 0x2afa: // Receiving map names list from the map-server
@@ -2390,16 +2394,16 @@ int parse_frommap(int fd)
 				return 0;
 		{
 			//TODO: When data mismatches memory, update guild/party online/offline states.
-			int i, aid, cid;
+			int aid, cid;
 			struct online_char_data* character;
 
-			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
 			server[id].users = RFIFOW(fd,4);
+			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
 			for(i = 0; i < server[id].users; i++) {
 				aid = RFIFOL(fd,6+i*8);
 				cid = RFIFOL(fd,6+i*8+4);
 				character = (struct online_char_data*)idb_ensure(online_char_db, aid, create_online_char_data);
-				if (character->server > -1 && character->server != id)
+				if( character->server > -1 && character->server != id )
 				{
 					ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
 						character->account_id, character->char_id, character->server, id, aid, cid);
@@ -2419,6 +2423,7 @@ int parse_frommap(int fd)
 		{
 			int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
 			struct online_char_data* character;
+
 			if (size - 13 != sizeof(struct mmo_charstatus))
 			{
 				ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
@@ -2439,7 +2444,7 @@ int parse_frommap(int fd)
 			}
 
 			if (RFIFOB(fd,12))
-		  	{ //Flag? Set character offline after saving [Skotlex]
+			{	//Flag, set character offline after saving. [Skotlex]
 				set_char_offline(cid, aid);
 				WFIFOHEAD(fd,10);
 				WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
@@ -2530,7 +2535,7 @@ int parse_frommap(int fd)
 				data = (struct online_char_data*)idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
 				data->char_id = char_data->char_id;
 				data->server = map_id; //Update server where char is.
-				
+
 				//Reply with an ack.
 				WFIFOHEAD(fd,30);
 				WFIFOW(fd,0) = 0x2b06;
@@ -2738,22 +2743,17 @@ int parse_frommap(int fd)
 		break;
 
 		case 0x2b16: // Receive rates [Wizputer]
-			if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8))
+			if( RFIFOREST(fd) < 14 )
 				return 0;
 		{
-			char motd[256];
-			char esc_motd[sizeof(motd)*2+1];
 			char esc_server_name[sizeof(server_name)*2+1];
 
-			strncpy(motd, (char*)RFIFOP(fd,10), 255); //First copy it to make sure the motd fits.
-			motd[255] = '\0';
-			Sql_EscapeString(sql_handle, esc_motd, motd);
 			Sql_EscapeString(sql_handle, esc_server_name, server_name);
 
-			if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `ragsrvinfo` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d',`motd`='%s'",
-				fd, esc_server_name, RFIFOW(fd,2), RFIFOW(fd,4), RFIFOW(fd,6), esc_motd) )
+			if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `ragsrvinfo` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
+				fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
 				Sql_ShowDebug(sql_handle);
-			RFIFOSKIP(fd,RFIFOW(fd,8));
+			RFIFOSKIP(fd,14);
 		}
 		break;
 
@@ -2790,7 +2790,7 @@ int parse_frommap(int fd)
 		{
 #ifdef ENABLE_SC_SAVING
 			int count, aid, cid;
-			
+
 			aid = RFIFOL(fd, 4);
 			cid = RFIFOL(fd, 8);
 			count = RFIFOW(fd, 12);
@@ -2939,7 +2939,8 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port)
 	return -1;
 }
 
-int char_mapif_init(int fd)
+// char_mapif�̏����������i���݂�inter_mapif�������̂݁j
+static int char_mapif_init(int fd)
 {
 	return inter_mapif_init(fd);
 }
@@ -2962,8 +2963,8 @@ int lan_subnetcheck(uint32 ip)
 
 int parse_char(int fd)
 {
-	int i, ch = 0;
-	char email[40];	
+	int i, ch;
+	char email[40];
 	unsigned short cmd;
 	int map_fd;
 	struct char_session_data* sd;
@@ -3072,7 +3073,7 @@ int parse_char(int fd)
 			FIFOSD_CHECK(3);
 		{
 			struct mmo_charstatus char_dat;
-			struct mmo_charstatus * cp;
+			struct mmo_charstatus *cd;
 			char* data;
 			int char_id;
 			uint32 subnet_map_ip;
@@ -3084,11 +3085,13 @@ int parse_char(int fd)
 			if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot)
 			  || SQL_SUCCESS != Sql_NextRow(sql_handle)
 			  || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
-			{
-				//Not found?? May be forged packet.
+			{	//Not found?? May be forged packet.
 				Sql_ShowDebug(sql_handle);
 				Sql_FreeResult(sql_handle);
-				//TODO: perhaps add some reply? (otherwise it hangs the client)
+				WFIFOHEAD(fd,3);
+				WFIFOW(fd,0) = 0x6c;
+				WFIFOB(fd,2) = 0; // rejected from server
+				WFIFOSET(fd,3);
 				break;
 			}
 
@@ -3097,8 +3100,8 @@ int parse_char(int fd)
 			mmo_char_fromsql(char_id, &char_dat, true);
 
 			//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
-			cp = (struct mmo_charstatus *)idb_get(char_db_, char_id);
-			cp->sex = sd->sex;
+			cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
+			cd->sex = sd->sex;
 
 			if (log_char) {
 				char esc_name[NAME_LENGTH*2+1];
@@ -3111,7 +3114,7 @@ int parse_char(int fd)
 			ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
 
 			// searching map server
-			i = search_mapserver(char_dat.last_point.map, -1, -1);
+			i = search_mapserver(cd->last_point.map, -1, -1);
 
 			// if map is not found, we check major cities
 			if (i < 0) {
@@ -3127,33 +3130,33 @@ int parse_char(int fd)
 					break;
 				}
 				if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
-					cp->last_point.x = 273;
-					cp->last_point.y = 354;
+					cd->last_point.x = 273;
+					cd->last_point.y = 354;
 				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
-					cp->last_point.x = 120;
-					cp->last_point.y = 100;
+					cd->last_point.x = 120;
+					cd->last_point.y = 100;
 				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
-					cp->last_point.x = 160;
-					cp->last_point.y = 94;
+					cd->last_point.x = 160;
+					cd->last_point.y = 94;
 				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
-					cp->last_point.x = 116;
-					cp->last_point.y = 57;
+					cd->last_point.x = 116;
+					cd->last_point.y = 57;
 				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
-					cp->last_point.x = 87;
-					cp->last_point.y = 117;
+					cd->last_point.x = 87;
+					cd->last_point.y = 117;
 				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
-					cp->last_point.x = 94;
-					cp->last_point.y = 103;
+					cd->last_point.x = 94;
+					cd->last_point.y = 103;
 				} else {
-					ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(char_dat.last_point.map));
+					ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map));
 					WFIFOHEAD(fd,3);
 					WFIFOW(fd,0) = 0x81;
 					WFIFOB(fd,2) = 1; // 01 = Server closed
 					WFIFOSET(fd,3);
 					break;
 				}
-				ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(char_dat.last_point.map), mapindex_id2name(j));
-				cp->last_point.map = j;
+				ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
+				cd->last_point.map = j;
 			}
 
 			//Send NEW auth packet [Kevin]
@@ -3174,9 +3177,9 @@ int parse_char(int fd)
 			//Send player to map
 			WFIFOHEAD(fd,28);
 			WFIFOW(fd,0) = 0x71;
-			WFIFOL(fd,2) = cp->char_id;
-			mapindex_getmapname_ext(mapindex_id2name(cp->last_point.map), (char*)WFIFOP(fd,6));
-			subnet_map_ip = lan_subnetcheck(ipl);
+			WFIFOL(fd,2) = cd->char_id;
+			mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
+			subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
 			WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
 			WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
 			WFIFOSET(fd,28);
@@ -3184,7 +3187,7 @@ int parse_char(int fd)
 			// create temporary auth entry
 			CREATE(node, struct auth_node, 1);
 			node->account_id = sd->account_id;
-			node->char_id = cp->char_id;
+			node->char_id = cd->char_id;
 			node->login_id1 = sd->login_id1;
 			node->login_id2 = sd->login_id2;
 			node->sex = sd->sex;
@@ -3219,8 +3222,6 @@ int parse_char(int fd)
 				case -3: WFIFOB(fd,2) = 0x01; break;
 				}
 				WFIFOSET(fd,3);
-				RFIFOSKIP(fd,37);
-				break;
 			}
 			else
 			{
@@ -3253,7 +3254,6 @@ int parse_char(int fd)
 		{
 			int cid = RFIFOL(fd,2);
 
-			WFIFOHEAD(fd,46);
 			ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
 			memcpy(email, RFIFOP(fd,6), 40);
 			RFIFOSKIP(fd,RFIFOREST(fd)); // hack to make the other deletion packet work
@@ -3270,7 +3270,7 @@ int parse_char(int fd)
 				WFIFOSET(fd,3);
 				break;
 			}
-			
+
 			// check if this char exists
 			ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
 			if( i == MAX_CHARS )
@@ -3313,7 +3313,7 @@ int parse_char(int fd)
 		break;
 
 		// char rename request
-		// R 028d <account ID>.l <char ID>.l <new name>.24B 
+		// R 028d <account ID>.l <char ID>.l <new name>.24B
 		case 0x28d:
 			FIFOSD_CHECK(34);
 			{
@@ -3393,7 +3393,7 @@ int parse_char(int fd)
 			RFIFOSKIP(fd,32);
 		break;
 
-		// log in as map-server
+		// login as map-server
 		case 0x2af8:
 			if (RFIFOREST(fd) < 60)
 				return 0;
@@ -3424,7 +3424,7 @@ int parse_char(int fd)
 				realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
 				char_mapif_init(fd);
 			}
-			
+
 			RFIFOSKIP(fd,60);
 		}
 		return 0; // avoid processing of followup packets here
@@ -3487,7 +3487,6 @@ int parse_console(char* buf)
 	return 0;
 }
 
-// MAP send all
 int mapif_sendall(unsigned char *buf, unsigned int len)
 {
 	int i, c;
@@ -3665,7 +3664,7 @@ static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
 {
 	struct online_char_data *character= (struct online_char_data*)data;
 	if (character->fd != -1)
-		return 0; //Still connected
+		return 0; //Character still connected
 	if (character->server == -2) //Unknown server.. set them offline
 		set_char_offline(character->char_id, character->account_id);
 	if (character->server < 0)
@@ -3758,59 +3757,55 @@ void sql_config_read(const char* cfgName)
 			continue;
 
 		if(!strcmpi(w1,"char_db"))
-			strcpy(char_db,w2);
+			safestrncpy(char_db, w2, sizeof(char_db));
 		else if(!strcmpi(w1,"scdata_db"))
-			strcpy(scdata_db,w2);
+			safestrncpy(scdata_db, w2, sizeof(scdata_db));
 		else if(!strcmpi(w1,"cart_db"))
-			strcpy(cart_db,w2);
+			safestrncpy(cart_db, w2, sizeof(cart_db));
 		else if(!strcmpi(w1,"inventory_db"))
-			strcpy(inventory_db, w2);
+			safestrncpy(inventory_db, w2, sizeof(inventory_db));
 		else if(!strcmpi(w1,"charlog_db"))
-			strcpy(charlog_db,w2);
+			safestrncpy(charlog_db, w2, sizeof(charlog_db));
 		else if(!strcmpi(w1,"storage_db"))
-			strcpy(storage_db,w2);
+			safestrncpy(storage_db, w2, sizeof(storage_db));
 		else if(!strcmpi(w1,"reg_db"))
-			strcpy(reg_db,w2);
+			safestrncpy(reg_db, w2, sizeof(reg_db));
 		else if(!strcmpi(w1,"skill_db"))
-			strcpy(skill_db,w2);
+			safestrncpy(skill_db, w2, sizeof(skill_db));
 		else if(!strcmpi(w1,"interlog_db"))
-			strcpy(interlog_db,w2);
+			safestrncpy(interlog_db, w2, sizeof(interlog_db));
 		else if(!strcmpi(w1,"memo_db"))
-			strcpy(memo_db,w2);
+			safestrncpy(memo_db, w2, sizeof(memo_db));
 		else if(!strcmpi(w1,"guild_db"))
-			strcpy(guild_db,w2);
+			safestrncpy(guild_db, w2, sizeof(guild_db));
 		else if(!strcmpi(w1,"guild_alliance_db"))
-			strcpy(guild_alliance_db,w2);
+			safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db));
 		else if(!strcmpi(w1,"guild_castle_db"))
-			strcpy(guild_castle_db,w2);
+			safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db));
 		else if(!strcmpi(w1,"guild_expulsion_db"))
-			strcpy(guild_expulsion_db,w2);
+			safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db));
 		else if(!strcmpi(w1,"guild_member_db"))
-			strcpy(guild_member_db,w2);
+			safestrncpy(guild_member_db, w2, sizeof(guild_member_db));
 		else if(!strcmpi(w1,"guild_skill_db"))
-			strcpy(guild_skill_db,w2);
+			safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db));
 		else if(!strcmpi(w1,"guild_position_db"))
-			strcpy(guild_position_db,w2);
+			safestrncpy(guild_position_db, w2, sizeof(guild_position_db));
 		else if(!strcmpi(w1,"guild_storage_db"))
-			strcpy(guild_storage_db,w2);
+			safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db));
 		else if(!strcmpi(w1,"party_db"))
-			strcpy(party_db,w2);
+			safestrncpy(party_db, w2, sizeof(party_db));
 		else if(!strcmpi(w1,"pet_db"))
-			strcpy(pet_db,w2);
+			safestrncpy(pet_db, w2, sizeof(pet_db));
 		else if(!strcmpi(w1,"mail_db"))
-			strcpy(mail_db,w2);
+			safestrncpy(mail_db, w2, sizeof(mail_db));
 		else if(!strcmpi(w1,"auction_db"))
-			strcpy(auction_db,w2);
+			safestrncpy(auction_db, w2, sizeof(auction_db));
 		else if(!strcmpi(w1,"friend_db"))
-			strcpy(friend_db,w2);
+			safestrncpy(friend_db, w2, sizeof(friend_db));
 		else if(!strcmpi(w1,"hotkey_db"))
-			strcpy(hotkey_db,w2);
+			safestrncpy(hotkey_db, w2, sizeof(hotkey_db));
 		else if(!strcmpi(w1,"quest_db"))
-			strcpy(quest_db,w2);
-#ifndef TXT_SQL_CONVERT
-		else if(!strcmpi(w1,"db_path"))
-			strcpy(db_path,w2);
-#endif
+			safestrncpy(quest_db,w2,sizeof(quest_db));
 		//support the import command, just like any other config
 		else if(!strcmpi(w1,"import"))
 			sql_config_read(w2);
@@ -3842,30 +3837,28 @@ int char_config_read(const char* cfgName)
 		remove_control_chars(w1);
 		remove_control_chars(w2);
 		if(strcmpi(w1,"timestamp_format") == 0) {
-			strncpy(timestamp_format, w2, 20);
+			safestrncpy(timestamp_format, w2, sizeof(timestamp_format));
 		} else if(strcmpi(w1,"console_silent")==0){
 			ShowInfo("Console Silent Setting: %d\n", atoi(w2));
 			msg_silent = atoi(w2);
 		} else if(strcmpi(w1,"stdout_with_ansisequence")==0){
 			stdout_with_ansisequence = config_switch(w2);
 		} else if (strcmpi(w1, "userid") == 0) {
-			strncpy(userid, w2, 24);
+			safestrncpy(userid, w2, sizeof(userid));
 		} else if (strcmpi(w1, "passwd") == 0) {
-			strncpy(passwd, w2, 24);
+			safestrncpy(passwd, w2, sizeof(passwd));
 		} else if (strcmpi(w1, "server_name") == 0) {
-			strncpy(server_name, w2, 20);
-			server_name[sizeof(server_name) - 1] = '\0';
+			safestrncpy(server_name, w2, sizeof(server_name));
 			ShowStatus("%s server has been initialized\n", w2);
 		} else if (strcmpi(w1, "wisp_server_name") == 0) {
 			if (strlen(w2) >= 4) {
-				memcpy(wisp_server_name, w2, sizeof(wisp_server_name));
-				wisp_server_name[sizeof(wisp_server_name) - 1] = '\0';
+				safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name));
 			}
 		} else if (strcmpi(w1, "login_ip") == 0) {
 			char ip_str[16];
 			login_ip = host2ip(w2);
 			if (login_ip) {
-				strncpy(login_ip_str, w2, sizeof(login_ip_str));
+				safestrncpy(login_ip_str, w2, sizeof(login_ip_str));
 				ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str));
 			}
 		} else if (strcmpi(w1, "login_port") == 0) {
@@ -3874,14 +3867,14 @@ int char_config_read(const char* cfgName)
 			char ip_str[16];
 			char_ip = host2ip(w2);
 			if (char_ip){
-				strncpy(char_ip_str, w2, sizeof(char_ip_str));
+				safestrncpy(char_ip_str, w2, sizeof(char_ip_str));
 				ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str));
 			}
 		} else if (strcmpi(w1, "bind_ip") == 0) {
 			char ip_str[16];
 			bind_ip = host2ip(w2);
 			if (bind_ip) {
-				strncpy(bind_ip_str, w2, sizeof(bind_ip_str));
+				safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str));
 				ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str));
 			}
 		} else if (strcmpi(w1, "char_port") == 0) {
@@ -3931,18 +3924,20 @@ int char_config_read(const char* cfgName)
 		} else if(strcmpi(w1,"log_char")==0) {		//log char or not [devil]
 			log_char = atoi(w2);
 		} else if (strcmpi(w1, "unknown_char_name") == 0) {
-			strcpy(unknown_char_name, w2);
+			safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name));
 			unknown_char_name[NAME_LENGTH-1] = '\0';
 		} else if (strcmpi(w1, "name_ignoring_case") == 0) {
-			name_ignoring_case = config_switch(w2);
+			name_ignoring_case = (bool)config_switch(w2);
 		} else if (strcmpi(w1, "char_name_option") == 0) {
 			char_name_option = atoi(w2);
 		} else if (strcmpi(w1, "char_name_letters") == 0) {
-			strcpy(char_name_letters, w2);
+			safestrncpy(char_name_letters, w2, sizeof(char_name_letters));
 		} else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
 			char_per_account = atoi(w2);
 		} else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus]
 			char_del_level = atoi(w2);
+		} else if(strcmpi(w1,"db_path")==0) {
+			safestrncpy(db_path, w2, sizeof(db_path));
 		} else if (strcmpi(w1, "console") == 0) {
 			console = config_switch(w2);
 		} else if (strcmpi(w1, "fame_list_alchemist") == 0) {
@@ -3970,16 +3965,14 @@ int char_config_read(const char* cfgName)
 		}
 	}
 	fclose(fp);
-	
+
 	ShowInfo("Done reading %s.\n", cfgName);
 	return 0;
 }
 
 void do_final(void)
 {
-	ShowInfo("Doing final stage...\n");
-	//check SQL save progress.
-	//wait until save char complete
+	ShowStatus("Terminating server.\n");
 
 	set_all_offline(-1);
 	set_all_offline_sql();
@@ -3988,22 +3981,20 @@ void do_final(void)
 
 	flush_fifos();
 
-	mapindex_final();
-
 	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ragsrvinfo`") )
 		Sql_ShowDebug(sql_handle);
 
+	char_db_->destroy(char_db_, NULL);
+	online_char_db->destroy(online_char_db, NULL);
+	auth_db->destroy(auth_db, NULL);
+
 	if (login_fd > 0)
 		do_close(login_fd);
 	if (char_fd > 0)
 		do_close(char_fd);
-	char_db_->destroy(char_db_, NULL);
-	online_char_db->destroy(online_char_db, NULL);
-	auth_db->destroy(auth_db, NULL);
 
 	Sql_Free(sql_handle);
-
-	ShowInfo("ok! all done...\n");
+	mapindex_final();
 }
 
 //------------------------------
@@ -4031,7 +4022,7 @@ int do_init(int argc, char **argv)
 	//Read map indexes
 	mapindex_init();
 	start_point.map = mapindex_name2id("new_zone01");
-	
+
 	char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]);
 	char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME);
 	sql_config_read(SQL_CONF_NAME);
@@ -4041,7 +4032,7 @@ int do_init(int argc, char **argv)
 		ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n");
 		ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n");
 	}
-	
+
 	ShowInfo("Finished reading the char-server configuration.\n");
 
 	inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server �ʱ�ȭ
@@ -4066,11 +4057,11 @@ int do_init(int argc, char **argv)
 		else
 			ShowStatus("Defaulting to %s as our IP address\n", ip_str);
 		if (!login_ip) {
-			strcpy(login_ip_str, ip_str);
+			safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str));
 			login_ip = str2ip(login_ip_str);
 		}
 		if (!char_ip) {
-			strcpy(char_ip_str, ip_str);
+			safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str));
 			char_ip = str2ip(char_ip_str);
 		}
 	}
@@ -4089,7 +4080,7 @@ int do_init(int argc, char **argv)
 
 	// send a list of all online account IDs to login server
 	add_timer_func_list(send_accounts_tologin, "send_accounts_tologin");
-	add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour.
+	add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour
 
 	// ???
 	add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect");
diff --git a/src/char_sql/int_guild.c b/src/char_sql/int_guild.c
index 00331e8e6..0b3d77f07 100644
--- a/src/char_sql/int_guild.c
+++ b/src/char_sql/int_guild.c
@@ -1131,8 +1131,8 @@ int mapif_guild_notice(struct guild *g)
 	unsigned char buf[256];
 	WBUFW(buf,0)=0x383e;
 	WBUFL(buf,2)=g->guild_id;
-	memcpy(WBUFP(buf,6),g->mes1,60);
-	memcpy(WBUFP(buf,66),g->mes2,120);
+	memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1);
+	memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2);
 	mapif_sendall(buf,186);
 	return 0;
 }
@@ -1826,8 +1826,8 @@ int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes
 	if(g==NULL)
 		return 0;
 
-	memcpy(g->mes1,mes1,60);
-	memcpy(g->mes2,mes2,120);
+	memcpy(g->mes1,mes1,MAX_GUILDMES1);
+	memcpy(g->mes2,mes2,MAX_GUILDMES2);
 	g->save_flag |= GS_MES;	//Change mes of guild
 	return mapif_guild_notice(g);
 }
diff --git a/src/char_sql/int_storage.c b/src/char_sql/int_storage.c
index 7cab6d5d9..0719685ae 100644
--- a/src/char_sql/int_storage.c
+++ b/src/char_sql/int_storage.c
@@ -76,7 +76,7 @@ int storage_fromsql(int account_id, struct storage_data* p)
 /// Save guild_storage data to sql
 int guild_storage_tosql(int guild_id, struct guild_storage* p)
 {
-	memitemdata_to_sql(p->storage_, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE);
+	memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE);
 	ShowInfo ("guild storage save to DB - guild: %d\n", guild_id);
 	return 0;
 }
@@ -109,7 +109,7 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p)
 
 	for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
 	{
-		item = &p->storage_[i];
+		item = &p->items[i];
 		Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data);
 		Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data);
 		Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data);
diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c
index 2f5c2daff..97c48bdf1 100644
--- a/src/char_sql/inter.c
+++ b/src/char_sql/inter.c
@@ -235,7 +235,7 @@ static int inter_config_read(const char* cfgName)
 		else if(!strcmpi(w1,"log_inter"))
 			log_inter = atoi(w2);
 		else if(!strcmpi(w1,"main_chat_nick"))
-			strcpy(main_chat_nick, w2);
+			safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick));
 #endif //TXT_SQL_CONVERT
 		else if(!strcmpi(w1,"import"))
 			inter_config_read(w2);
diff --git a/src/common/lock.c b/src/common/lock.c
index 5cb4c3a67..643b86e5c 100644
--- a/src/common/lock.c
+++ b/src/common/lock.c
@@ -1,8 +1,9 @@
 // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
 // For more information, see LICENCE in the main folder
 
-#include "../common/cbasetypes.h"
-#include "../common/showmsg.h"
+#include "cbasetypes.h"
+#include "showmsg.h"
+#include "utils.h"
 #include "lock.h"
 
 #include <stdio.h>
@@ -12,12 +13,8 @@
 #include <unistd.h>
 #else
 #include <io.h>
-#define F_OK   0x0
-#define R_OK   0x4
 #endif
 
-#define exists(filename) (!access(filename, F_OK))
-
 // �������݃t�@�C���̕ی쏈��
 // �i�������݂��I���܂ŁA���t�@�C����ۊǂ��Ă����j
 
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 6a78d840c..92adf8af0 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -108,13 +108,6 @@
 #define MAX_QUEST_DB 2000 //Max quests that the server will load
 #define MAX_QUEST_OBJECTIVES 3 //Max quest objectives for a quest
 
-#define MIN_HAIR_STYLE battle_config.min_hair_style
-#define MAX_HAIR_STYLE battle_config.max_hair_style
-#define MIN_HAIR_COLOR battle_config.min_hair_color
-#define MAX_HAIR_COLOR battle_config.max_hair_color
-#define MIN_CLOTH_COLOR battle_config.min_cloth_color
-#define MAX_CLOTH_COLOR battle_config.max_cloth_color
-
 // for produce
 #define MIN_ATTRIBUTE 0
 #define MAX_ATTRIBUTE 4
@@ -147,6 +140,10 @@
 #define END_ACCOUNT_NUM 100000000
 #define START_CHAR_NUM 150000
 
+//Guilds
+#define MAX_GUILDMES1 60
+#define MAX_GUILDMES2 120
+
 //Base Homun skill.
 #define HM_SKILLBASE 8001
 #define MAX_HOMUNSKILL 16
@@ -177,6 +174,7 @@ enum item_types {
 	IT_UNKNOWN2,//9
 	IT_AMMO,    //10
 	IT_DELAYCONSUME,//11
+	IT_CASH = 18,
 	IT_MAX 
 };
 
@@ -240,7 +238,7 @@ struct guild_storage {
 	int guild_id;
 	short storage_status;
 	short storage_amount;
-	struct item storage_[MAX_GUILD_STORAGE];
+	struct item items[MAX_GUILD_STORAGE];
 };
 
 struct s_pet {
@@ -474,7 +472,7 @@ struct guild {
 	char name[NAME_LENGTH],master[NAME_LENGTH];
 	struct guild_member member[MAX_GUILD];
 	struct guild_position position[MAX_GUILDPOSITION];
-	char mes1[60],mes2[120];
+	char mes1[MAX_GUILDMES1],mes2[MAX_GUILDMES2];
 	int emblem_len,emblem_id;
 	char emblem_data[2048];
 	struct guild_alliance alliance[MAX_GUILDALLIANCE];
diff --git a/src/common/socket.c b/src/common/socket.c
index deba0e97b..89c605c9d 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -199,6 +199,10 @@ time_t stall_time = 60;
 uint32 addr_[16];   // ip addresses of local host (host byte order)
 int naddr_ = 0;   // # of ip addresses
 
+// Maximum packet size in bytes, which the client is able to handle.
+// Larger packets cause a buffer overflow and stack corruption.
+static size_t socket_max_client_packet = 20480;
+
 // initial recv buffer size (this will also be the max. size)
 // biggest known packet: S 0153 <len>.w <emblem data>.?B -> 24x24 256 color .bmp (0153 + len.w + 1618/1654/1756 bytes)
 #define RFIFO_SIZE (2*1024)
@@ -643,8 +647,15 @@ int WFIFOSET(int fd, size_t len)
 		exit(EXIT_FAILURE);
 	}
 
+	if( !s->flag.server && len > socket_max_client_packet )
+	{// see declaration of socket_max_client_packet for details
+		ShowError("WFIFOSET: Dropped too large client packet 0x%04x (length=%u, max=%u).\n", WFIFOW(fd,0), len, socket_max_client_packet);
+		return 0;
+	}
+
 	if( !s->flag.server && s->wdata_size+len > WFIFO_MAX )
 	{// reached maximum write fifo size
+		ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%u, ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr));
 		set_eof(fd);
 		return 0;
 	}
@@ -1064,6 +1075,8 @@ int socket_config_read(const char* cfgName)
 			ddos_autoreset = atoi(w2);
 		else if (!strcmpi(w1,"debug"))
 			access_debug = config_switch(w2);
+		else if (!strcmpi(w1,"socket_max_client_packet"))
+			socket_max_client_packet = strtoul(w2, NULL, 0);
 #endif
 		else if (!strcmpi(w1, "import"))
 			socket_config_read(w2);
diff --git a/src/common/strlib.c b/src/common/strlib.c
index 7a6c134e7..019e2d629 100644
--- a/src/common/strlib.c
+++ b/src/common/strlib.c
@@ -12,7 +12,6 @@
 #include <errno.h>
 
 
-
 #define J_MAX_MALLOC_SIZE 65535
 
 // escapes a string in-place (' -> \' , \ -> \\ , % -> _)
@@ -657,7 +656,7 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in
 			end[0] = end[1] = '\0';
 		*out_fields = end + 2;
 	}
-	else if( (opt&SV_TERMINATE_LF) && end[0] == '\r' )
+	else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' )
 	{
 		if( !(opt&SV_KEEP_TERMINATOR) )
 			end[0] = '\0';
@@ -923,18 +922,12 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
 	FILE* fp;
 	int lines = 0;
 	int entries = 0;
-	char* fields[64]; // room for 63 fields ([0] is reserved)
-	int columns;
+	char** fields; // buffer for fields ([0] is reserved)
+	int columns, fields_length;
 	char path[1024], line[1024];
 
 	snprintf(path, sizeof(path), "%s/%s", directory, filename);
 
-	if( maxcols > ARRAYLENGTH(fields)-1 )
-	{
-		ShowError("sv_readdb: Insufficient column storage in parser for file \"%s\" (want %d, have only %d). Increase the capacity in the source code please.\n", path, maxcols, ARRAYLENGTH(fields)-1);
-		return false;
-	}
-
 	// open file
 	fp = fopen(path, "r");
 	if( fp == NULL )
@@ -943,6 +936,10 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
 		return false;
 	}
 
+	// allocate enough memory for the maximum requested amount of columns plus the reserved one
+	fields_length = maxcols+1;
+	fields = aMalloc(fields_length*sizeof(char*));
+
 	// process rows one by one
 	while( fgets(line, sizeof(line), fp) )
 	{
@@ -954,7 +951,7 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
 		if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r')
 			continue;
 
-		columns = sv_split(line, strlen(line), 0, delim, fields, ARRAYLENGTH(fields), (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF));
+		columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF));
 
 		if( columns < mincols )
 		{
@@ -983,6 +980,7 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
 		entries++;
 	}
 
+	aFree(fields);
 	fclose(fp);
 	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path);
 
diff --git a/src/common/utils.c b/src/common/utils.c
index c1128edb4..12123784f 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -14,7 +14,11 @@
 #include <math.h> // floor()
 
 #ifdef WIN32
+	#include <io.h>
 	#include <windows.h>
+	#ifndef F_OK
+		#define F_OK   0x0
+	#endif  /* F_OK */
 #else
 	#include <unistd.h>
 	#include <dirent.h>
@@ -182,6 +186,11 @@ void findfile(const char *p, const char *pat, void (func)(const char*))
 }
 #endif
 
+bool exists(const char* filename)
+{
+	return !access(filename, F_OK);
+}
+
 uint8 GetByte(uint32 val, int idx)
 {
 	switch( idx )
diff --git a/src/common/utils.h b/src/common/utils.h
index 93563dc34..5cf3ff3cf 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -14,6 +14,7 @@
 void dump(FILE* fp, const unsigned char* buffer, int length);
 
 void findfile(const char *p, const char *pat, void (func)(const char*));
+bool exists(const char* filename);
 
 //Caps values to min/max
 #define cap_value(a, min, max) ((a >= max) ? max : (a <= min) ? min : a)
diff --git a/src/ladmin/ladmin.c b/src/ladmin/ladmin.c
index 3f02a240a..d7a78c119 100644
--- a/src/ladmin/ladmin.c
+++ b/src/ladmin/ladmin.c
@@ -261,7 +261,7 @@ int ladmin_log(char *fmt, ...)
 }
 
 //---------------------------------------------
-// Function to return ordonal text of a number.
+// Function to return ordinal text of a number.
 //---------------------------------------------
 char* makeordinal(int number)
 {
@@ -275,7 +275,6 @@ char* makeordinal(int number)
 	} else {
 		return "th";
 	}
-	return "";
 }
 
 //-----------------------------------------------------------------------------------------
diff --git a/src/login/login.c b/src/login/login.c
index e888d21f6..6b3a1bcaf 100644
--- a/src/login/login.c
+++ b/src/login/login.c
@@ -402,7 +402,7 @@ int parse_fromchar(int fd)
 			uint32 login_id1 = RFIFOL(fd,6);
 			uint32 login_id2 = RFIFOL(fd,10);
 			uint8 sex = RFIFOB(fd,14);
-			uint32 ip_ = ntohl(RFIFOL(fd,15));
+			//uint32 ip_ = ntohl(RFIFOL(fd,15));
 			int request_id = RFIFOL(fd,19);
 			RFIFOSKIP(fd,23);
 
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index d48dda0db..95b3dc33e 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -452,7 +452,7 @@ ACMD_FUNC(mapmove)
 		clif_displaymessage(fd, msg_txt(248));
 		return -1;
 	}
-	if (pc_setpos(sd, mapindex, x, y, 3) != 0) {
+	if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) {
 		clif_displaymessage(fd, msg_txt(1)); // Map not found.
 		return -1;
 	}
@@ -535,7 +535,7 @@ ACMD_FUNC(jumpto)
 		return -1;
 	}
 
-	pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, 3);
+	pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
 	sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s
  	clif_displaymessage(fd, atcmd_output);
 
@@ -572,7 +572,7 @@ ACMD_FUNC(jump)
 		x = y = 0; //Invalid cell, use random spot.
 	}
 
-	pc_setpos(sd, sd->mapindex, x, y, 3);
+	pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT);
 	sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d
 	clif_displaymessage(fd, atcmd_output);
 	return 0;
@@ -1114,7 +1114,7 @@ ACMD_FUNC(load)
 		return -1;
 	}
 
-	pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 0);
+	pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT);
 	clif_displaymessage(fd, msg_txt(7)); // Warping to save point..
 
 	return 0;
@@ -1663,15 +1663,15 @@ ACMD_FUNC(item2)
 	if (item_id > 500) {
 		loop = 1;
 		get_count = number;
-		if (item_data->type == 4 || item_data->type == 5 ||
-			item_data->type == 7 || item_data->type == 8) {
+		if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR ||
+			item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) {
 			loop = number;
 			get_count = 1;
-			if (item_data->type == 7) {
+			if (item_data->type == IT_PETEGG) {
 				identify = 1;
 				refine = 0;
 			}
-			if (item_data->type == 8)
+			if (item_data->type == IT_PETARMOR)
 				refine = 0;
 			if (refine > 10)
 				refine = 10;
@@ -1777,8 +1777,10 @@ ACMD_FUNC(baselevelup)
 		sd->status.base_level -= (unsigned int)level;
 		clif_displaymessage(fd, msg_txt(22)); // Base level lowered.
 	}
+	sd->status.base_exp = 0;
 	clif_updatestatus(sd, SP_STATUSPOINT);
 	clif_updatestatus(sd, SP_BASELEVEL);
+	clif_updatestatus(sd, SP_BASEEXP);
 	clif_updatestatus(sd, SP_NEXTBASEEXP);
 	status_calc_pc(sd, 0);
 	if(sd->status.party_id)
@@ -1808,11 +1810,7 @@ ACMD_FUNC(joblevelup)
 		if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow
 			level = pc_maxjoblv(sd) - sd->status.job_level;
 		sd->status.job_level += (unsigned int)level;
-		clif_updatestatus(sd, SP_JOBLEVEL);
-		clif_updatestatus(sd, SP_NEXTJOBEXP);
 		sd->status.skill_point += level;
-		clif_updatestatus(sd, SP_SKILLPOINT);
-		status_calc_pc(sd, 0);
 		clif_misceffect(&sd->bl, 1);
 		clif_displaymessage(fd, msg_txt(24)); // Job level raised.
 	} else {
@@ -1824,18 +1822,20 @@ ACMD_FUNC(joblevelup)
 		if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow
 			level = sd->status.job_level-1;
 		sd->status.job_level -= (unsigned int)level;
-		clif_updatestatus(sd, SP_JOBLEVEL);
-		clif_updatestatus(sd, SP_NEXTJOBEXP);
 		if (sd->status.skill_point < level)
 			pc_resetskill(sd,0);	//Reset skills since we need to substract more points.
 		if (sd->status.skill_point < level)
 			sd->status.skill_point = 0;
 		else
 			sd->status.skill_point -= level;
-		clif_updatestatus(sd, SP_SKILLPOINT);
-		status_calc_pc(sd, 0);
 		clif_displaymessage(fd, msg_txt(25)); // Job level lowered.
 	}
+	sd->status.job_exp = 0;
+	clif_updatestatus(sd, SP_JOBLEVEL);
+	clif_updatestatus(sd, SP_JOBEXP);
+	clif_updatestatus(sd, SP_NEXTJOBEXP);
+	clif_updatestatus(sd, SP_SKILLPOINT);
+	status_calc_pc(sd, 0);
 
 	return 0;
 }
@@ -2308,7 +2308,7 @@ ACMD_FUNC(go)
 			clif_displaymessage(fd, msg_txt(248));
 			return -1;
 		}
-		if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, 3) == 0) {
+		if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) {
 			clif_displaymessage(fd, msg_txt(0)); // Warped.
 		} else {
 			clif_displaymessage(fd, msg_txt(1)); // Map not found.
@@ -3329,7 +3329,7 @@ ACMD_FUNC(recall)
 		clif_displaymessage(fd, "You are not authorized to warp this player from its actual map.");
 		return -1;
 	}
-	pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2);
+	pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
 	sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled!
 	clif_displaymessage(fd, atcmd_output);
 
@@ -3988,7 +3988,7 @@ ACMD_FUNC(recallall)
 					pc_setstand(pl_sd);
 					pc_setrestartvalue(pl_sd,1);
 				}
-				pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2);
+				pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
 			}
 		}
 	}
@@ -4047,7 +4047,7 @@ ACMD_FUNC(guildrecall)
 			if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
 				count++;
 			else
-				pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2);
+				pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
 		}
 	}
 	mapit_free(iter);
@@ -4106,7 +4106,7 @@ ACMD_FUNC(partyrecall)
 			if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
 				count++;
 			else
-				pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2);
+				pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
 		}
 	}
 	mapit_free(iter);
@@ -4704,7 +4704,7 @@ ACMD_FUNC(tonpc)
 	}
 
 	if ((nd = npc_name2id(npcname)) != NULL) {
-		if (pc_setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, 3) == 0)
+		if (pc_setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, CLR_TELEPORT) == 0)
 			clif_displaymessage(fd, msg_txt(0)); // Warped.
 		else
 			return -1;
@@ -5786,7 +5786,7 @@ ACMD_FUNC(skilltree)
 	ent = &skill_tree[c][j];
 
 	meets = 1;
-	for(j=0;j<5;j++)
+	for(j=0;j<MAX_PC_SKILL_REQUIRE;j++)
 	{
 		if( ent->need[j].id && pc_checkskill(sd,ent->need[j].id) < ent->need[j].lv)
 		{
@@ -6352,7 +6352,7 @@ ACMD_FUNC(mobsearch)
 	clif_displaymessage(fd, atcmd_output);
 
 	it = mapit_geteachmob();
-	while( true )
+	for(;;)
 	{
 		TBL_MOB* md = (TBL_MOB*)mapit_next(it);
 		if( md == NULL )
@@ -6502,7 +6502,7 @@ ACMD_FUNC(users)
 
 	// count users on each map
 	iter = mapit_getallusers();
-	while( true )
+	for(;;)
 	{
 		struct map_session_data* sd2 = (struct map_session_data*)mapit_next(iter);
 		if( sd2 == NULL )
@@ -6585,7 +6585,7 @@ ACMD_FUNC(summon)
 	md->master_id=sd->bl.id;
 	md->special_state.ai=1;
 	md->deletetimer=add_timer(tick+(duration*60000),mob_timer_delete,md->bl.id,0);
-	clif_misceffect2(&md->bl,344);
+	clif_specialeffect(&md->bl,344,AREA);
 	mob_spawn(md);
 	sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
 	clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,md->bl.x,md->bl.y,tick);
@@ -6862,26 +6862,36 @@ ACMD_FUNC(identify)
  *------------------------------------------*/
 ACMD_FUNC(gmotd)
 {
-		char buf[CHAT_SIZE_MAX];
-		FILE *fp;
-	nullpo_retr(-1, sd);
-		if((fp = fopen(motd_txt, "r"))!=NULL){
-			while(fgets(buf, sizeof(buf), fp) != NULL)
+	char buf[CHAT_SIZE_MAX];
+	size_t len;
+	FILE* fp;
+
+	if( ( fp = fopen(motd_txt, "r") ) != NULL )
+	{
+		while( fgets(buf, sizeof(buf), fp) )
+		{
+			if( buf[0] == '/' && buf[1] == '/' )
 			{
-				int i;
-				if (buf[0] == '/' && buf[1] == '/')
-					continue;
-				for(i=0; buf[i]; i++){
-					if(buf[i]=='\r' || buf[i]=='\n'){
-						buf[i]=0;
-						break;
-					}
-				}
-				intif_broadcast(buf, strlen(buf)+1, 0);
+				continue;
+			}
+
+			len = strlen(buf);
+
+			while( len && ( buf[len-1] == '\r' || buf[len-1] == '\n' ) )
+			{// strip trailing EOL characters
+				len--;
+			}
+
+			if( len )
+			{
+				buf[len] = 0;
+
+				intif_broadcast(buf, len+1, 0);
 			}
-			fclose(fp);
 		}
-		return 0;
+		fclose(fp);
+	}
+	return 0;
 }
 
 ACMD_FUNC(misceffect)
@@ -7071,7 +7081,7 @@ ACMD_FUNC(showmobs)
 	clif_displaymessage(fd, atcmd_output);
 
 	it = mapit_geteachmob();
-	while( true )
+	for(;;)
 	{
 		TBL_MOB* md = (TBL_MOB*)mapit_next(it);
 		if( md == NULL )
@@ -7124,7 +7134,7 @@ ACMD_FUNC(homlevel)
 	}
 	status_calc_homunculus(hd,0);
 	status_percent_heal(&hd->bl, 100, 100);
-	clif_misceffect2(&hd->bl,568);
+	clif_specialeffect(&hd->bl,568,AREA);
 	return 0;
 }
 
@@ -7390,9 +7400,6 @@ ACMD_FUNC(homshuffle)
  *------------------------------------------*/
 ACMD_FUNC(iteminfo)
 {
-	char *itype[12] = {"Potion/Food", "BUG!", "Usable", "Etc", "Weapon", "Protection", "Card", "Egg", "Pet Acessory", "BUG!", "Arrow"};
-	//, "Lure/Scroll"}; No need, type 11 items are converted to type 2 upon loading [Skotlex]
-
 	struct item_data *item_data, *item_array[MAX_SEARCH];
 	int i, count = 1;
 
@@ -7417,20 +7424,20 @@ ACMD_FUNC(iteminfo)
 		item_data = item_array[i];
 		sprintf(atcmd_output, "Item: '%s'/'%s'[%d] (%d) Type: %s | Extra Effect: %s",
 			item_data->name,item_data->jname,item_data->slot,item_data->nameid,
-			item_data->type < 12 ? itype[item_data->type] : "BUG!", 
+			itemdb_typename(item_data->type), 
 			(item_data->script==NULL)? "None" : "With script"
 		);
 		clif_displaymessage(fd, atcmd_output);
 
-		sprintf(atcmd_output, "NPC Buy:%dz%s, Sell:%dz%s | Weight: %.1f ", item_data->value_buy, item_data->flag.value_notdc ? "(No Discount!)":"", item_data->value_sell, item_data->flag.value_notoc ? "(No Overcharge!)":"", item_data->weight/10. );
+		sprintf(atcmd_output, "NPC Buy:%dz, Sell:%dz | Weight: %.1f ", item_data->value_buy, item_data->value_sell, item_data->weight/10. );
 		clif_displaymessage(fd, atcmd_output);
 
-		if (item_data->maxchance == 10000)
-			strcpy(atcmd_output, " - Available in the shops only");
+		if (item_data->maxchance == -1)
+			strcpy(atcmd_output, " - Available in the shops only.");
 		else if (item_data->maxchance)
 			sprintf(atcmd_output, " - Maximal monsters drop chance: %02.02f%%", (float)item_data->maxchance / 100 );
 		else
-			strcpy(atcmd_output, " - Monsters don't drop this item");
+			strcpy(atcmd_output, " - Monsters don't drop this item.");
 		clif_displaymessage(fd, atcmd_output);
 
 	}
@@ -7700,7 +7707,7 @@ ACMD_FUNC(size)
 	size = atoi(message);
 	if(sd->state.size) {
 		sd->state.size=0;
-		pc_setpos(sd, sd->mapindex, sd->bl.x, sd->bl.y, 3);
+		pc_setpos(sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_TELEPORT);
 	}
 
 	if(size==1) {
@@ -8499,58 +8506,68 @@ ACMD_FUNC(stats)
 ACMD_FUNC(delitem)
 {
 	char item_name[100];
-	int i, number = 0, item_id, item_position, count;
-	struct item_data *item_data;
-	char output[CHAT_SIZE_MAX];
+	int nameid, amount = 0, total, idx;
+	struct item_data* id;
 
 	nullpo_retr(-1, sd);
 
-	memset(item_name, '\0', sizeof(item_name));
-	memset(output, '\0', sizeof(output));
+	if( !message || !*message || ( sscanf(message, "\"%99[^\"]\" %d", item_name, &amount) < 2 && sscanf(message, "%99s %d", item_name, &amount) < 2 ) || amount < 1 )
+	{
+		clif_displaymessage(fd, "Please, enter an item name/id, a quantity and a player name (usage: #delitem <player> <item_name_or_ID> <quantity>).");
+		return -1;
+	}
 
-	if (!message || !*message || (
-		sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 2 &&
-		sscanf(message, "%s %d", item_name, &number) < 2
-	) || number < 1) {
-		clif_displaymessage(fd, "Please, enter an item name/id, a quantity and a player name (usage: #delitem <item_name_or_ID> <quantity> <player>).");
+	if( ( id = itemdb_searchname(item_name) ) != NULL || ( id = itemdb_exists(atoi(item_name)) ) != NULL )
+	{
+		nameid = id->nameid;
+	}
+	else
+	{
+		clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
 		return -1;
 	}
 
-	item_id = 0;
-	if ((item_data = itemdb_searchname(item_name)) != NULL ||
-	    (item_data = itemdb_exists(atoi(item_name))) != NULL)
-		item_id = item_data->nameid;
-	
-	if (item_id > 500) {
-		item_position = pc_search_inventory(sd, item_id);
-		if (item_position >= 0) {
-			count = 0;
-			for(i = 0; i < number && item_position >= 0; i++) {
+	total = amount;
 
-				//Logs (A)dmins items [Lupus]
-				if(log_config.enable_logs&0x400)
-					log_pick_pc(sd, "A", sd->status.inventory[item_position].nameid, -1, &sd->status.inventory[item_position]);
+	// delete items
+	while( amount && ( idx = pc_search_inventory(sd, nameid) ) != -1 )
+	{
+		int delamount = ( amount < sd->status.inventory[idx].amount ) ? amount : sd->status.inventory[idx].amount;
 
-				pc_delitem(sd, item_position, 1, 0, 0);
-				count++;
-				item_position = pc_search_inventory(sd, item_id); // for next loop
-			}
-			sprintf(output, msg_txt(113), count); // %d item(s) removed by a GM.
-			clif_displaymessage(sd->fd, output);
-			if (number == count)
-				sprintf(output, msg_txt(114), count); // %d item(s) removed from the player.
-			else
-				sprintf(output, msg_txt(115), count, count, number); // %d item(s) removed. Player had only %d on %d items.
-			clif_displaymessage(fd, output);
-		} else {
-			clif_displaymessage(fd, msg_txt(116)); // Character does not have the item.
-			return -1;
+		if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET )
+		{// delete pet
+			intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+		}
+
+		//Logs (A)dmins items [Lupus]
+		if( log_config.enable_logs&0x400 )
+		{
+			log_pick_pc(sd, "A", nameid, -delamount, &sd->status.inventory[idx]);
 		}
+
+		pc_delitem(sd, idx, delamount, 0, 0);
+
+		amount-= delamount;
+	}
+
+	// notify target
+	sprintf(atcmd_output, msg_txt(113), total-amount); // %d item(s) removed by a GM.
+	clif_displaymessage(sd->fd, atcmd_output);
+
+	// notify source
+	if( amount == total )
+	{
+		clif_displaymessage(fd, msg_txt(116)); // Character does not have the item.
+	}
+	else if( amount )
+	{
+		sprintf(atcmd_output, msg_txt(115), total-amount, total-amount, total); // %d item(s) removed. Player had only %d on %d items.
+		clif_displaymessage(fd, atcmd_output);
 	}
 	else
 	{
-		clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
-		return -1;
+		sprintf(atcmd_output, msg_txt(114), total); // %d item(s) removed from the player.
+		clif_displaymessage(fd, atcmd_output);
 	}
 
 	return 0;
diff --git a/src/map/battle.c b/src/map/battle.c
index 5c6da69e3..32def23f3 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -1942,8 +1942,8 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 
 			if (sc && sc->data[SC_MIRACLE]) i = 2; //Star anger
 			else
-			ARR_FIND(0, 3, i, t_class == sd->hate_mob[i]);
-			if (i < 3 && (skill=pc_checkskill(sd,sg_info[i].anger_id))) 
+			ARR_FIND(0, MAX_PC_FEELHATE, i, t_class == sd->hate_mob[i]);
+			if (i < MAX_PC_FEELHATE && (skill=pc_checkskill(sd,sg_info[i].anger_id))) 
 			{
 				skillratio = sd->status.base_level + sstatus->dex + sstatus->luk;
 				if (i == 2) skillratio += sstatus->str; //Star Anger
@@ -4004,6 +4004,8 @@ static const struct _battle_data {
 	{ "invincible.nodamage",                &battle_config.invincible_nodamage,             0,      0,      1,              },
 	{ "mob_slave_keep_target",              &battle_config.mob_slave_keep_target,           0,      0,      1,              },
 	{ "autospell_check_range",              &battle_config.autospell_check_range,           0,      0,      1,              },
+	{ "client_reshuffle_dice",              &battle_config.client_reshuffle_dice,           0,      0,      1,              },
+	{ "client_sort_storage",                &battle_config.client_sort_storage,             0,      0,      1,              },
 // BattleGround Settings
 	{ "bg_update_interval",                 &battle_config.bg_update_interval,              1000,   100,    INT_MAX,        },
 	{ "bg_short_attack_damage_rate",        &battle_config.bg_short_damage_rate,            80,     0,      INT_MAX,        },
diff --git a/src/map/battle.h b/src/map/battle.h
index 230a86007..3abc6b0a4 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -96,6 +96,13 @@ bool battle_check_range(struct block_list *src,struct block_list *bl,int range);
 void battle_consume_ammo(struct map_session_data* sd, int skill, int lv);
 // �ݒ�
 
+#define MIN_HAIR_STYLE battle_config.min_hair_style
+#define MAX_HAIR_STYLE battle_config.max_hair_style
+#define MIN_HAIR_COLOR battle_config.min_hair_color
+#define MAX_HAIR_COLOR battle_config.max_hair_color
+#define MIN_CLOTH_COLOR battle_config.min_cloth_color
+#define MAX_CLOTH_COLOR battle_config.max_cloth_color
+
 extern struct Battle_Config
 {
 	int warp_point_debug;
@@ -471,6 +478,8 @@ extern struct Battle_Config
 	int invincible_nodamage;
 	int mob_slave_keep_target;
 	int autospell_check_range;	//Enable range check for autospell bonus. [L0ne_W0lf]
+	int client_reshuffle_dice;  // Reshuffle /dice
+	int client_sort_storage;
 
 	// [BattleGround Settings]
 	int bg_update_interval;
diff --git a/src/map/battleground.c b/src/map/battleground.c
index fad22c38f..1c2a90d90 100644
--- a/src/map/battleground.c
+++ b/src/map/battleground.c
@@ -64,7 +64,7 @@ int bg_team_warp(int bg_id, unsigned short mapindex, short x, short y)
 	struct battleground_data *bg = bg_team_search(bg_id);
 	if( bg == NULL ) return 0;
 	for( i = 0; i < MAX_BG_MEMBERS; i++ )
-		if( bg->members[i].sd != NULL ) pc_setpos(bg->members[i].sd, mapindex, x, y, 3);
+		if( bg->members[i].sd != NULL ) pc_setpos(bg->members[i].sd, mapindex, x, y, CLR_TELEPORT);
 	return 1;
 }
 
@@ -145,7 +145,7 @@ int bg_member_respawn(struct map_session_data *sd)
 		return 0;
 	if( bg->mapindex == 0 )
 		return 0; // Respawn not handled by Core
-	pc_setpos(sd, bg->mapindex, bg->x, bg->y, 0);
+	pc_setpos(sd, bg->mapindex, bg->x, bg->y, CLR_OUTSIGHT);
 	status_revive(&sd->bl, 1, 100);
 
 	return 1; // Warped
diff --git a/src/map/chrif.c b/src/map/chrif.c
index 40e7ca8d1..a9634d2c2 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -74,7 +74,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
 //2b13: Incoming, chrif_accountdeletion -> 'Delete acc XX, if the player is on, kick ....'
 //2b14: Incoming, chrif_accountban -> 'not sure: kick the player with message XY'
 //2b15: FREE
-//2b16: Outgoing, chrif_ragsrvinfo -> 'sends motd / rates ....'
+//2b16: Outgoing, chrif_ragsrvinfo -> 'sends base / job / drop rates ....'
 //2b17: Outgoing, chrif_char_offline -> 'tell the charserver that the char is now offline'
 //2b18: Outgoing, chrif_char_reset_offline -> 'set all players OFF!'
 //2b19: Outgoing, chrif_char_online -> 'tell the charserver that the char .. is online'
@@ -1229,40 +1229,18 @@ int chrif_load_scdata(int fd)
 
 /*==========================================
  * Send rates and motd to char server [Wizputer]
- * S 2b16 <base rate>.w <job rate>.w <drop rate>.w <motd len>.w <motd>.256B
+ * S 2b16 <base rate>.L <job rate>.L <drop rate>.L
  *------------------------------------------*/
- int chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate)
+int chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate)
 {
-	char buf[256];
-	FILE *fp;
-	int i;
-
 	chrif_check(-1);
 
-	WFIFOHEAD(char_fd, sizeof(buf) + 10);
+	WFIFOHEAD(char_fd,14);
 	WFIFOW(char_fd,0) = 0x2b16;
-	WFIFOW(char_fd,2) = base_rate;
-	WFIFOW(char_fd,4) = job_rate;
-	WFIFOW(char_fd,6) = drop_rate;
-	WFIFOW(char_fd,8) = sizeof(buf) + 10;
-
-	if ((fp = fopen(motd_txt, "r")) != NULL) {
-		if (fgets(buf, sizeof(buf), fp) != NULL)
-		{
-			for(i = 0; buf[i]; i++) {
-				if (buf[i] == '\r' || buf[i] == '\n') {
-					buf[i] = 0;
-					break;
-				}
-			}
-			memcpy(WFIFOP(char_fd,10), buf, sizeof(buf));
-		}
-		fclose(fp);
-	} else {
-		memset(buf, 0, sizeof(buf)); //No data found, send empty packets?
-		memcpy(WFIFOP(char_fd,10), buf, sizeof(buf));
-	}
-	WFIFOSET(char_fd,WFIFOW(char_fd,8));
+	WFIFOL(char_fd,2) = base_rate;
+	WFIFOL(char_fd,6) = job_rate;
+	WFIFOL(char_fd,10) = drop_rate;
+	WFIFOSET(char_fd,14);
 	return 0;
 }
 
diff --git a/src/map/clif.c b/src/map/clif.c
index e55a27108..c5796555a 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -168,9 +168,9 @@ static inline unsigned char clif_bl_type(struct block_list *bl) {
 	case BL_ITEM:  return 0x2; //ITEM_TYPE
 	case BL_SKILL: return 0x3; //SKILL_TYPE
 	case BL_CHAT:  return 0x4; //UNKNOWN_TYPE
-	case BL_MOB:   return pcdb_checkid(((TBL_MOB*)bl)->vd->class_)?0x0:0x5; //NPC_MOB_TYPE
+	case BL_MOB:   return pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x5; //NPC_MOB_TYPE
 	case BL_NPC:   return 0x6; //NPC_EVT_TYPE
-	case BL_PET:   return 0x7; //NPC_PET_TYPE
+	case BL_PET:   return pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x7; //NPC_PET_TYPE
 	case BL_HOM:   return 0x8; //NPC_HOM_TYPE
 	case BL_MER:   return 0x9; //NPC_MERSOL_TYPE
 // case BL_ELEM:  return 0xA; //NPC_ELEMENTAL_TYPE
@@ -658,7 +658,7 @@ int clif_clearflooritem(struct flooritem_data *fitem, int fd)
  *       3 - teleported / logged out
  * fd  : the target client
  *------------------------------------------*/
-int clif_clearunit_single(int id, uint8 type, int fd)
+int clif_clearunit_single(int id, clr_type type, int fd)
 {
 	WFIFOHEAD(fd, packet_len(0x80));
 	WFIFOW(fd,0) = 0x80;
@@ -676,7 +676,7 @@ int clif_clearunit_single(int id, uint8 type, int fd)
  *       2 - respawned
  *       3 - teleported / logged out
  *------------------------------------------*/
-int clif_clearunit_area(struct block_list* bl, uint8 type)
+int clif_clearunit_area(struct block_list* bl, clr_type type)
 {
 	unsigned char buf[16];
 
@@ -686,7 +686,7 @@ int clif_clearunit_area(struct block_list* bl, uint8 type)
 	WBUFL(buf,2) = bl->id;
 	WBUFB(buf,6) = type;
 
-	clif_send(buf, packet_len(0x80), bl, type == 1 ? AREA : AREA_WOS);
+	clif_send(buf, packet_len(0x80), bl, type == CLR_DEAD ? AREA : AREA_WOS);
 
 	if(disguised(bl)) {
 		WBUFL(buf,2) = -bl->id;
@@ -699,7 +699,7 @@ int clif_clearunit_area(struct block_list* bl, uint8 type)
 static int clif_clearunit_delayed_sub(int tid, unsigned int tick, int id, intptr data)
 {
 	struct block_list *bl = (struct block_list *)data;
-	clif_clearunit_area(bl, 0);
+	clif_clearunit_area(bl, CLR_OUTSIGHT);
 	aFree(bl);
 	return 0;
 }
@@ -1059,16 +1059,6 @@ static void clif_spiritball_single(int fd, struct map_session_data *sd)
 	WFIFOSET(fd, packet_len(0x1e1));
 }
 
-// new and improved weather display [Valaris]
-static void clif_weather_sub(int fd, int id, int type)
-{
-	WFIFOHEAD(fd,packet_len(0x1f3));
-	WFIFOW(fd,0) = 0x1f3;
-	WFIFOL(fd,2) = id;
-	WFIFOL(fd,6) = type;
-	WFIFOSET(fd,packet_len(0x1f3));
-}
-
 /*==========================================
  *
  *------------------------------------------*/
@@ -1086,24 +1076,24 @@ static void clif_weather_check(struct map_session_data *sd)
 		|| map[m].flag.clouds2)
 	{
 		if (map[m].flag.snow)
-			clif_weather_sub(fd, sd->bl.id, 162);
+			clif_specialeffect_single(&sd->bl, 162, fd);
 		if (map[m].flag.clouds)
-			clif_weather_sub(fd, sd->bl.id, 233);
+			clif_specialeffect_single(&sd->bl, 233, fd);
 		if (map[m].flag.clouds2)
-			clif_weather_sub(fd, sd->bl.id, 516);
+			clif_specialeffect_single(&sd->bl, 516, fd);
 		if (map[m].flag.fog)
-			clif_weather_sub(fd, sd->bl.id, 515);
+			clif_specialeffect_single(&sd->bl, 515, fd);
 		if (map[m].flag.fireworks) {
-			clif_weather_sub(fd, sd->bl.id, 297);
-			clif_weather_sub(fd, sd->bl.id, 299);
-			clif_weather_sub(fd, sd->bl.id, 301);
+			clif_specialeffect_single(&sd->bl, 297, fd);
+			clif_specialeffect_single(&sd->bl, 299, fd);
+			clif_specialeffect_single(&sd->bl, 301, fd);
 		}
 		if (map[m].flag.sakura)
-			clif_weather_sub(fd, sd->bl.id, 163);
+			clif_specialeffect_single(&sd->bl, 163, fd);
 		if (map[m].flag.leaves)
-			clif_weather_sub(fd, sd->bl.id, 333);
+			clif_specialeffect_single(&sd->bl, 333, fd);
 		if (map[m].flag.rain)
-			clif_weather_sub(fd, sd->bl.id, 161);
+			clif_specialeffect_single(&sd->bl, 161, fd);
 	}
 }
 
@@ -1280,13 +1270,14 @@ int clif_homskillinfoblock(struct map_session_data *sd)
 void clif_homskillup(struct map_session_data *sd, int skill_num)
 {	//[orn]
 	struct homun_data *hd;
-	int fd=sd->fd, skillid;
-	WFIFOHEAD(fd, packet_len(0x239));
+	int fd, skillid;
 	nullpo_retv(sd);
 	skillid = skill_num - HM_SKILLBASE;
 
+	fd=sd->fd;
 	hd=sd->hd;
 
+	WFIFOHEAD(fd, packet_len(0x239));
 	WFIFOW(fd,0) = 0x239;
 	WFIFOW(fd,2) = skill_num;
 	WFIFOW(fd,4) = hd->homunculus.hskill[skillid].lv;
@@ -1468,9 +1459,10 @@ void clif_blown(struct block_list *bl)
 	clif_slide(bl, bl->x, bl->y);
 }
 
-/*==========================================
- *
- *------------------------------------------*/
+/// Visually moves(slides) a character to x,y. If the target cell
+/// isn't walkable, the char doesn't move at all. If the char is
+/// sitting it will stand up.
+/// S 0088 <gid>.L <x>.W <y>.W
 void clif_fixpos(struct block_list *bl)
 {
 	unsigned char buf[10];
@@ -1529,9 +1521,7 @@ int clif_buylist(struct map_session_data *sd, struct npc_data *nd)
 		if( id == NULL )
 			continue;
 		WFIFOL(fd, 4+c*11) = val;
-		if (!id->flag.value_notdc)
-			val = pc_modifybuyvalue(sd,val);
-		WFIFOL(fd, 8+c*11) = val;
+		WFIFOL(fd, 8+c*11) = pc_modifybuyvalue(sd,val);
 		WFIFOB(fd,12+c*11) = itemtype(id->type);
 		WFIFOW(fd,13+c*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid;
 		c++;
@@ -1570,9 +1560,7 @@ int clif_selllist(struct map_session_data *sd)
 				continue;
 			WFIFOW(fd,4+c*10)=i+2;
 			WFIFOL(fd,6+c*10)=val;
-			if( !sd->inventory_data[i]->flag.value_notoc )
-				val=pc_modifysellvalue(sd,val);
-			WFIFOL(fd,10+c*10)=val;
+			WFIFOL(fd,10+c*10)=pc_modifysellvalue(sd,val);
 			c++;
 		}
 	}
@@ -2166,7 +2154,7 @@ void clif_equiplist(struct map_session_data *sd)
 	}
 }
 
-void clif_storagelist(struct map_session_data* sd, struct storage_data* stor)
+void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length)
 {
 	struct item_data *id;
 	int i,n,ne;
@@ -2187,21 +2175,21 @@ void clif_storagelist(struct map_session_data* sd, struct storage_data* stor)
 	const int cmd = 28;
 #endif
 
-	buf = (unsigned char*)aMallocA(MAX_STORAGE * s + 4);
-	bufe = (unsigned char*)aMallocA(MAX_STORAGE * cmd + 4);
+	buf = (unsigned char*)aMallocA(items_length * s + 4);
+	bufe = (unsigned char*)aMallocA(items_length * cmd + 4);
 
-	for( i = 0, n = 0, ne = 0; i < MAX_STORAGE; i++ )
+	for( i = 0, n = 0, ne = 0; i < items_length; i++ )
 	{
-		if( stor->items[i].nameid <= 0 )
+		if( items[i].nameid <= 0 )
 			continue;
-		id = itemdb_search(stor->items[i].nameid);
+		id = itemdb_search(items[i].nameid);
 		if( !itemdb_isstackable2(id) )
 		{ //Equippable
 			WBUFW(bufe,ne*cmd+4)=i+1;
-			clif_item_sub(bufe, ne*cmd+6, &stor->items[i], id, id->equip);
-			clif_addcards(WBUFP(bufe, ne*cmd+16), &stor->items[i]);
+			clif_item_sub(bufe, ne*cmd+6, &items[i], id, id->equip);
+			clif_addcards(WBUFP(bufe, ne*cmd+16), &items[i]);
 #if PACKETVER >= 20071002
-			WBUFL(bufe,ne*cmd+24)=stor->items[i].expire_time;
+			WBUFL(bufe,ne*cmd+24)=items[i].expire_time;
 			WBUFW(bufe,ne*cmd+28)=0; //Unknown
 #endif
 			ne++;
@@ -2209,93 +2197,12 @@ void clif_storagelist(struct map_session_data* sd, struct storage_data* stor)
 		else
 		{ //Stackable
 			WBUFW(buf,n*s+4)=i+1;
-			clif_item_sub(buf, n*s+6, &stor->items[i], id,-1);
+			clif_item_sub(buf, n*s+6, &items[i], id,-1);
 #if PACKETVER >= 5
-			clif_addcards(WBUFP(buf,n*s+14), &stor->items[i]);
+			clif_addcards(WBUFP(buf,n*s+14), &items[i]);
 #endif
 #if PACKETVER >= 20080102
-			WBUFL(buf,n*s+22)=stor->items[i].expire_time;
-#endif
-			n++;
-		}
-	}
-	if( n )
-	{
-#if PACKETVER < 5
-		WBUFW(buf,0)=0xa5;
-#elif PACKETVER < 20080102
-		WBUFW(buf,0)=0x1f0;
-#else
-		WBUFW(buf,0)=0x2ea;
-#endif
-		WBUFW(buf,2)=4+n*s;
-		clif_send(buf, WBUFW(buf,2), &sd->bl, SELF);
-	}
-	if( ne )
-	{
-#if PACKETVER < 20071002
-		WBUFW(bufe,0)=0xa6;
-#else
-		WBUFW(bufe,0)=0x2d1;
-#endif
-		WBUFW(bufe,2)=4+ne*cmd;
-		clif_send(bufe, WBUFW(bufe,2), &sd->bl, SELF);
-	}
-
-	if( buf ) aFree(buf);
-	if( bufe ) aFree(bufe);
-}
-
-//Unified storage function which sends all of the storage (requires two packets, one for equipable items and one for stackable ones. [Skotlex]
-void clif_guildstoragelist(struct map_session_data *sd,struct guild_storage *stor)
-{
-	struct item_data *id;
-	int i,n,ne;
-	unsigned char *buf;
-	unsigned char *bufe;
-#if PACKETVER < 5
-	const int s = 10; //Entry size.
-#elif PACKETVER < 20080102
-	const int s = 18;
-#else
-	const int s = 22;
-#endif
-#if PACKETVER < 20071002
-	const int cmd = 20;
-#elif PACKETVER < 20100629
-	const int cmd = 26;
-#else
-	const int cmd = 28;
-#endif
-
-	buf = (unsigned char*)aMallocA(MAX_GUILD_STORAGE * s + 4);
-	bufe = (unsigned char*)aMallocA(MAX_GUILD_STORAGE * cmd + 4);
-
-	for( i = 0, n = 0, ne = 0; i < MAX_GUILD_STORAGE; i++ )
-	{
-		if( stor->storage_[i].nameid <= 0 )
-			continue;
-		id = itemdb_search(stor->storage_[i].nameid);
-		if( !itemdb_isstackable2(id) )
-		{ //Equippable
-			WBUFW(bufe,ne*cmd+4)=i+1;
-			clif_item_sub(bufe, ne*cmd+6, &stor->storage_[i], id, id->equip);
-			clif_addcards(WBUFP(bufe, ne*cmd+16), &stor->storage_[i]);
-#if PACKETVER >= 20071002
-			WBUFL(bufe,ne*cmd+24)=stor->storage_[i].expire_time;
-			WBUFW(bufe,ne*cmd+28)=0; //Unknown
-#endif
-			ne++;
-		}
-		else
-		{ //Stackable
-			WBUFW(buf,n*s+4)=i+1;
-			clif_item_sub(buf, n*s+6, &stor->storage_[i], id,-1);
-#if PACKETVER >= 5
-			clif_addcards(WBUFP(buf,n*s+14), &stor->storage_[i]);
-#endif
-#if PACKETVER >= 20080102
-			WBUFL(buf,n*s+22)=stor->storage_[i].expire_time;
+			WBUFL(buf,n*s+22)=items[i].expire_time;
 #endif
 			n++;
 		}
@@ -3089,23 +2996,7 @@ int clif_misceffect(struct block_list* bl,int type)
 
 	return 0;
 }
-int clif_misceffect2(struct block_list *bl, int type)
-{
-	unsigned char buf[24];
-
-	nullpo_ret(bl);
-
-	memset(buf, 0, packet_len(0x1f3));
-
-	WBUFW(buf,0) = 0x1f3;
-	WBUFL(buf,2) = bl->id;
-	WBUFL(buf,6) = type;
-
-	clif_send(buf, packet_len(0x1f3), bl, AREA);
-
-	return 0;
 
-}
 /*==========================================
  * �\���I�v�V�����ύX
  *------------------------------------------*/
@@ -3226,11 +3117,13 @@ int clif_useitemack(struct map_session_data *sd,int index,int amount,int ok)
 	return 0;
 }
 
-/*==========================================
- * Inform client whether chatroom creation was successful or not
- * R 00d6 <fail>.B
- *------------------------------------------*/
-void clif_createchat(struct map_session_data* sd, int fail)
+/// Inform client whether chatroom creation was successful or not
+/// R 00d6 <flag>.B
+/// flag:
+///  0 = Room has been successfully created (opens chat room)
+///  1 = Room limit exceeded
+///  2 = Same room already exists
+void clif_createchat(struct map_session_data* sd, int flag)
 {
 	int fd;
 
@@ -3239,7 +3132,7 @@ void clif_createchat(struct map_session_data* sd, int fail)
 	fd = sd->fd;
 	WFIFOHEAD(fd,packet_len(0xd6));
 	WFIFOW(fd,0) = 0xd6;
-	WFIFOB(fd,2) = fail;
+	WFIFOB(fd,2) = flag;
 	WFIFOSET(fd,packet_len(0xd6));
 }
 
@@ -3327,10 +3220,18 @@ int clif_clearchat(struct chat_data *cd,int fd)
 	return 0;
 }
 
-/*==========================================
- *
- *------------------------------------------*/
-int clif_joinchatfail(struct map_session_data *sd,int fail)
+/// Displays message (mostly) regarding join chat
+/// failures
+/// R 0x00da <flag>.B
+/// flag:
+///  0 = The room is already full.
+///  1 = Incorrect password, please try again.
+///  2 = You have been kicked out of the room.
+///  4 = You don't have enough money.
+///  5 = You are not the required level.
+///  6 = Too high level for this job.
+///  7 = Not the suitable job for this type of work.
+int clif_joinchatfail(struct map_session_data *sd,int flag)
 {
 	int fd;
 
@@ -3340,7 +3241,7 @@ int clif_joinchatfail(struct map_session_data *sd,int fail)
 
 	WFIFOHEAD(fd,packet_len(0xda));
 	WFIFOW(fd,0) = 0xda;
-	WFIFOB(fd,2) = fail;
+	WFIFOB(fd,2) = flag;
 	WFIFOSET(fd,packet_len(0xda));
 
 	return 0;
@@ -3393,7 +3294,7 @@ int clif_addchat(struct chat_data* cd,struct map_session_data *sd)
 
 /*==========================================
  * Announce the new owner
- * R 00e1 <index>.l <nick>.24B
+ * R 00e1 <owner flag>.l <nick>.24B
  *------------------------------------------*/
 void clif_changechatowner(struct chat_data* cd, struct map_session_data* sd)
 {
@@ -3405,6 +3306,8 @@ void clif_changechatowner(struct chat_data* cd, struct map_session_data* sd)
 	//FIXME: this announces a swap between positions 0 and 1 (probably not what we want) [ultramage]
 	//FIXME: aegis sends obviously incorrect packets; need to figure out what to send to display it correctly :X
 	//TODO: is it just owner swap, or can it do general-purpose reordering?
+	// It's not position, but operator flag, everyone set to 1 gets chat
+	// operator menu (yes, that means a chat may host multiple operators) [Ai4rei]
 
 	WBUFW(buf, 0) = 0xe1;
 	WBUFL(buf, 2) = 1;
@@ -3689,41 +3592,6 @@ void clif_updateguildstorageamount(struct map_session_data* sd, int amount)
 	WFIFOSET(fd,packet_len(0xf2));
 }
 
-/*==========================================
- *
- *------------------------------------------*/
-void clif_guildstorageitemadded(struct map_session_data* sd, struct item* i, int index, int amount)
-{
-	int view,fd;
-	unsigned char *buf;
-#if PACKETVER < 20090603
-	const int cmd = 0xf4;
-#else
-	const int cmd = 0x1c4;
-#endif
-
-	nullpo_retv(sd);
-	nullpo_retv(i);
-	fd=sd->fd;
-	view = itemdb_viewid(i->nameid);
-	buf = WFIFOP(fd,0);
-
-	WFIFOHEAD(fd,packet_len(cmd));
-	WBUFW(buf, 0) = cmd; // Storage item added
-	WBUFW(buf, 2) = index+1; // index
-	WBUFL(buf, 4) = amount; // amount
-	WBUFW(buf, 8) = ( view > 0 ) ? view : i->nameid; // id
-#if PACKETVER >= 20090603
-	WBUFB(buf,10) = itemdb_type(i->nameid); //type
-	buf = WBUFP(buf,1); //Advance 1B
-#endif
-	WBUFB(buf,10) = i->identify; //identify flag
-	WBUFB(buf,11) = i->attribute; // attribute
-	WBUFB(buf,12) = i->refine; //refine
-	clif_addcards(WBUFP(buf,13), i);
-	WFIFOSET(fd,packet_len(cmd));
-}
-
 /*==========================================
  * �J�v���q�ɂ���A�C�e������苎��
  *------------------------------------------*/
@@ -3885,7 +3753,8 @@ static int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int da
 
 /*==========================================
  * Sends a 'damage' packet (src performs action on dst)
- * R 008a <src ID>.l <dst ID>.l <server tick>.l <src speed>.l <dst speed>.l <param1>.w <param2>.w <type>.B <param3>.w
+ * R 008a <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.W <div>.W <type>.B <damage2>.W
+ * R 02e1 <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.L <div>.W <type>.B <damage2>.L
  * 
  * type=00 damage [param1: total damage, param2: div, param3: assassin dual-wield damage]
  * type=01 pick up item
@@ -4131,12 +4000,11 @@ void clif_skill_delunit(struct skill_unit *unit)
 }
 
 /*==========================================
- * Unknown... trap related?
- * Sent when an object gets ankle-snared
+ * Sent when an object gets ankle-snared (ZC_SKILL_UPDATE)
  * Only affects units with class [139,153] client-side
  * R 01ac <object id>.l
  *------------------------------------------*/
-void clif_01ac(struct block_list* bl)
+void clif_skillunit_update(struct block_list* bl)
 {
 	unsigned char buf[6];
 	nullpo_retv(bl);
@@ -4195,7 +4063,7 @@ int clif_outsight(struct block_list *bl,va_list ap)
 		switch(bl->type){
 		case BL_PC:
 			if (sd->vd.class_ != INVISIBLE_CLASS)
-				clif_clearunit_single(bl->id,0,tsd->fd);
+				clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd);
 			if(sd->chatID){
 				struct chat_data *cd;
 				cd=(struct chat_data*)map_id2bl(sd->chatID);
@@ -4213,14 +4081,14 @@ int clif_outsight(struct block_list *bl,va_list ap)
 			break;
 		default:
 			if ((vd=status_get_viewdata(bl)) && vd->class_ != INVISIBLE_CLASS)
-				clif_clearunit_single(bl->id,0,tsd->fd);
+				clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd);
 			break;
 		}
 	}
 	if (sd && sd->fd)
 	{	//sd is watching tbl go out of view.
 		if ((vd=status_get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS)
-			clif_clearunit_single(tbl->id,0,sd->fd);
+			clif_clearunit_single(tbl->id,CLR_OUTSIGHT,sd->fd);
 	}
 	return 0;
 }
@@ -4414,6 +4282,15 @@ int clif_skillup(struct map_session_data *sd,int skill_num)
 
 /*==========================================
  * �X�L���r���G�t�F�N�g�𑗐M����
+ * pl:
+ * 0 = Yellow cast aura
+ * 1 = Water elemental cast aura
+ * 2 = Earth elemental cast aura
+ * 3 = Fire elemental cast aura
+ * 4 = Wind elemental cast aura
+ * 5 = Poison elemental cast aura
+ * 6 = White cast aura
+ * ? = like 0
  *------------------------------------------*/
 int clif_skillcasting(struct block_list* bl,
 	int src_id,int dst_id,int dst_x,int dst_y,int skill_num,int pl, int casttime)
@@ -7081,8 +6958,8 @@ int clif_guild_notice(struct map_session_data* sd, struct guild* g)
 
 	WFIFOHEAD(fd,packet_len(0x16f));
 	WFIFOW(fd,0) = 0x16f;
-	memcpy(WFIFOP(fd,2), g->mes1, 60);
-	memcpy(WFIFOP(fd,62), g->mes2, 120);
+	memcpy(WFIFOP(fd,2), g->mes1, MAX_GUILDMES1);
+	memcpy(WFIFOP(fd,62), g->mes2, MAX_GUILDMES2);
 	WFIFOSET(fd,packet_len(0x16f));
 	return 0;
 }
@@ -7106,7 +6983,12 @@ int clif_guild_invite(struct map_session_data *sd,struct guild *g)
 	return 0;
 }
 /*==========================================
- * �M���h�����o���U����
+ * Reply to invite request
+ * Flag:
+ * 0 = Already in guild.
+ * 1 = Offer rejected.
+ * 2 = Offer accepted.
+ * 3 = Guild full.
  *------------------------------------------*/
 int clif_guild_inviteack(struct map_session_data *sd,int flag)
 {
@@ -7285,7 +7167,11 @@ int clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag)
 	return 0;
 }
 /*==========================================
- * �M���h�G�Ό���
+ * Reply to opposition request
+ * Flag:
+ * 0 = Antagonist has been set.
+ * 1 = Guild has too many Antagonists.
+ * 2 = Already set as an Antagonist.
  *------------------------------------------*/
 int clif_guild_oppositionack(struct map_session_data *sd,int flag)
 {
@@ -7579,20 +7465,17 @@ int clif_wisall(struct map_session_data *sd,int type,int flag)
 /*==========================================
  * Play a BGM! [Rikter/Yommy]
  *------------------------------------------*/
-void clif_playBGM(struct map_session_data* sd, struct block_list* bl, const char* name)
+void clif_playBGM(struct map_session_data* sd, const char* name)
 {
 	int fd;
 
 	nullpo_retv(sd);
-	nullpo_retv(bl);
 
 	fd = sd->fd;
 	WFIFOHEAD(fd,packet_len(0x7fe));
 	WFIFOW(fd,0) = 0x7fe;
 	safestrncpy((char*)WFIFOP(fd,2), name, NAME_LENGTH);
 	WFIFOSET(fd,packet_len(0x7fe));
-
-	return;
 }
 
 /*==========================================
@@ -7742,7 +7625,7 @@ int clif_refresh(struct map_session_data *sd)
 	if( pc_issit(sd) )
 		clif_sitting(&sd->bl); // FIXME: just send to self, not area
 	if( pc_isdead(sd) ) //When you refresh, resend the death packet.
-		clif_clearunit_single(sd->bl.id,1,sd->fd);
+		clif_clearunit_single(sd->bl.id,CLR_DEAD,sd->fd);
 	else
 		clif_changed_dir(&sd->bl, SELF);
 
@@ -7928,6 +7811,9 @@ int clif_charnameupdate (struct map_session_data *ssd)
 	return 0;
 }
 
+/// Visually moves(instant) a character to x,y. The char moves even
+/// when the target cell isn't walkable. If the char is sitting it
+/// stays that way.
 void clif_slide(struct block_list *bl, int x, int y)
 {
 	unsigned char buf[10];
@@ -8014,21 +7900,58 @@ void clif_gospel_info(struct map_session_data *sd, int type)
 	WFIFOSET(fd, packet_len(0x215));
 
 }
+
+/// Multi purpose mission information packet (ZC_STARSKILL).
+/// 0x20e <mapname>.24B <monster_id>.L <star>.B <result>.B
+/// result:
+///      0 = Star Gladiator %s has designed <mapname>'s as the %s.
+///      star:
+///          0 = Place of the Sun
+///          1 = Place of the Moon
+///          2 = Place of the Stars
+///      1 = Star Gladiator %s's %s: <mapname>
+///      star:
+///          0 = Place of the Sun
+///          1 = Place of the Moon
+///          2 = Place of the Stars
+///      10 = Star Gladiator %s has designed <mapname>'s as the %s.
+///      star:
+///          0 = Target of the Sun
+///          1 = Target of the Moon
+///          2 = Target of the Stars
+///      11 = Star Gladiator %s's %s: <mapname used as monster name>
+///      star:
+///          0 = Monster of the Sun
+///          1 = Monster of the Moon
+///          2 = Monster of the Stars
+///      20 = [TaeKwon Mission] Target Monster : <mapname used as monster name> (<star>%)
+///      21 = [Taming Mission] Target Monster : <mapname used as monster name>
+///      22 = [Collector Rank] Target Item : <monster_id used as item id>
+///      30 = [Sun, Moon and Stars Angel] Designed places and monsters have been reset.
+///      40 = Target HP : <monster_id used as HP>
+void clif_starskill(struct map_session_data* sd, const char* mapname, int monster_id, unsigned char star, unsigned char result)
+{
+	int fd = sd->fd;
+
+	WFIFOHEAD(fd,packet_len(0x20e));
+	WFIFOW(fd,0) = 0x20e;
+	safestrncpy((char*)WFIFOP(fd,2), mapname, NAME_LENGTH);
+	WFIFOL(fd,26) = monster_id;
+	WFIFOB(fd,30) = star;
+	WFIFOB(fd,31) = result;
+	WFIFOSET(fd,packet_len(0x20e));
+}
+
 /*==========================================
  * Info about Star Glaldiator save map [Komurka]
  * type: 1: Information, 0: Map registered
  *------------------------------------------*/
 void clif_feel_info(struct map_session_data* sd, unsigned char feel_level, unsigned char type)
 {
-	int fd=sd->fd;
+	char mapname[MAP_NAME_LENGTH_EXT];
 
-	WFIFOHEAD(fd,packet_len(0x20e));
-	WFIFOW(fd,0) = 0x20e;
-	mapindex_getmapname_ext(mapindex_id2name(sd->feel_map[feel_level].index), (char*)WFIFOP(fd,2));
-	WFIFOL(fd,26) = sd->bl.id;
-	WFIFOB(fd,30) = feel_level;
-	WFIFOB(fd,31) = type?1:0;
-	WFIFOSET(fd,packet_len(0x20e));
+	mapindex_getmapname_ext(mapindex_id2name(sd->feel_map[feel_level].index), mapname);
+	clif_starskill(sd, mapname, 0, feel_level, type ? 1 : 0);
 }
 
 /*==========================================
@@ -8037,19 +7960,18 @@ void clif_feel_info(struct map_session_data* sd, unsigned char feel_level, unsig
  *------------------------------------------*/
 void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int class_, unsigned char type)
 {
-	int fd=sd->fd;
-	WFIFOHEAD(fd,packet_len(0x20e));
-	WFIFOW(fd,0)=0x20e;
-	if (pcdb_checkid(class_))
-		strncpy((char*)WFIFOP(fd,2),job_name(class_), NAME_LENGTH);
-	else if (mobdb_checkid(class_))
-		strncpy((char*)WFIFOP(fd,2),mob_db(class_)->jname, NAME_LENGTH);
-	else //Really shouldn't happen...
-		memset(WFIFOP(fd,2), 0, NAME_LENGTH);
-	WFIFOL(fd,26)=sd->bl.id;
-	WFIFOB(fd,30)=hate_level;
-	WFIFOB(fd,31)=type?10:11; //Register/Info
-	WFIFOSET(fd, packet_len(0x20e));
+	if( pcdb_checkid(class_) )
+	{
+		clif_starskill(sd, job_name(class_), class_, hate_level, type ? 10 : 11);
+	}
+	else if( mobdb_checkid(class_) )
+	{
+		clif_starskill(sd, mob_db(class_)->jname, class_, hate_level, type ? 10 : 11);
+	}
+	else
+	{
+		ShowWarning("clif_hate_info: Received invalid class %d for this packet (char_id=%d, hate_level=%u, type=%u).\n", class_, sd->status.char_id, (unsigned int)hate_level, (unsigned int)type);
+	}
 }
 
 /*==========================================
@@ -8057,14 +7979,7 @@ void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int cl
  *------------------------------------------*/
 void clif_mission_info(struct map_session_data *sd, int mob_id, unsigned char progress)
 {
-	int fd=sd->fd;
-	WFIFOHEAD(fd,packet_len(0x20e));
-	WFIFOW(fd,0)=0x20e;
-	strncpy((char*)WFIFOP(fd,2),mob_db(mob_id)->jname, NAME_LENGTH);
-	WFIFOL(fd,26)=mob_id;
-	WFIFOB(fd,30)=progress; //Message to display
-	WFIFOB(fd,31)=20;
-	WFIFOSET(fd, packet_len(0x20e));
+	clif_starskill(sd, mob_db(mob_id)->jname, mob_id, progress, 20);
 }
 
 /*==========================================
@@ -8072,14 +7987,7 @@ void clif_mission_info(struct map_session_data *sd, int mob_id, unsigned char pr
  *------------------------------------------*/
 void clif_feel_hate_reset(struct map_session_data *sd)
 {
-	int fd=sd->fd;
-	WFIFOHEAD(fd,packet_len(0x20e));
-	WFIFOW(fd,0)=0x20e;
-	memset(WFIFOP(fd,2), 0, NAME_LENGTH); //Blank name as all was reset.
-	WFIFOL(fd,26)=sd->bl.id;
-	WFIFOB(fd,30)=0; //Feel/hate level: irrelevant
-	WFIFOB(fd,31)=30;
-	WFIFOSET(fd, packet_len(0x20e));
+	clif_starskill(sd, "", 0, 0, 30);
 }
 
 /*==========================================
@@ -8175,12 +8083,9 @@ void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* ts
 	WFIFOSET(fd, WFIFOW(fd, 2));
 }
 
-/*==========================================
- * View player equip request denied
- * R 0291 <message>.W
- * TODO: this looks like a general-purpose packet to print msgstringtable entries.
- *------------------------------------------*/
-void clif_viewequip_fail(struct map_session_data* sd)
+/// Display msgstringtable.txt string (ZC_MSG)
+/// R 0291 <message>.W
+void clif_msg(struct map_session_data* sd, unsigned short id)
 {
 	int fd;
 	nullpo_retv(sd);
@@ -8188,10 +8093,16 @@ void clif_viewequip_fail(struct map_session_data* sd)
 
 	WFIFOHEAD(fd, packet_len(0x291));
 	WFIFOW(fd, 0) = 0x291;
-	WFIFOW(fd, 2) = 0x54d;	// This controls which message is displayed. 0x54d is the correct one. Maybe it's used for something else too?
+	WFIFOW(fd, 2) = id;  // zero-based msgstringtable.txt index
 	WFIFOSET(fd, packet_len(0x291));
 }
 
+/// View player equip request denied
+void clif_viewequip_fail(struct map_session_data* sd)
+{
+	clif_msg(sd, 0x54d);
+}
+
 /// Validates one global/guild/party/whisper message packet and tries to recognize its components.
 /// Returns true if the packet was parsed successfully.
 /// Formats: 0 - <packet id>.w <packet len>.w (<name> : <message>).?B 00
@@ -8329,6 +8240,10 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error)
 		err = n;\
 //define SET_ERROR
 
+	// FIXME: If the packet is not received at once, this will FAIL.
+	// Figure out, when it happens, that only part of the packet is
+	// received, or fix the function to be able to deal with that
+	// case.
 #define CHECK_PACKET_VER() \
 	if( cmd != clif_config.connect_cmd[packet_ver] || packet_len != packet_db[packet_ver][cmd].len )\
 		;/* not wanttoconnection or wrong length */\
@@ -8561,20 +8476,22 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 	// must use foreachinarea (CIRCULAR_AREA interferes with foreachinrange)
 	map_foreachinarea(clif_getareachar, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_ALL, sd);
 
-	//TODO: merge it with the code below
-	if (battle_config.pet_no_gvg && map_flag_gvg(sd->bl.m) && sd->pd)
-	{	//Return the pet to egg. [Skotlex]
-		clif_displaymessage(sd->fd, "Pets are not allowed in Guild Wars.");
-		pet_menu(sd, 3); //Option 3 is return to egg.
-	}
-
 	// pet
-	if(sd->pd) {
-		map_addblock(&sd->pd->bl);
-		clif_spawn(&sd->pd->bl);
-		clif_send_petdata(sd,sd->pd,0,0);
-		clif_send_petstatus(sd);
-//		skill_unit_move(&sd->pd->bl,gettick(),1);
+	if( sd->pd )
+	{
+		if( battle_config.pet_no_gvg && map_flag_gvg(sd->bl.m) )
+		{	//Return the pet to egg. [Skotlex]
+			clif_displaymessage(sd->fd, "Pets are not allowed in Guild Wars.");
+			pet_menu(sd, 3); //Option 3 is return to egg.
+		}
+		else
+		{
+			map_addblock(&sd->pd->bl);
+			clif_spawn(&sd->pd->bl);
+			clif_send_petdata(sd,sd->pd,0,0);
+			clif_send_petstatus(sd);
+//			skill_unit_move(&sd->pd->bl,gettick(),1);
+		}
 	}
 
 	//homunculus [blackhole89]
@@ -8605,7 +8522,9 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 		sd->state.connect_new = 0;
 		clif_skillinfoblock(sd);
 		clif_hotkeys_send(sd);
+		clif_updatestatus(sd,SP_BASEEXP);
 		clif_updatestatus(sd,SP_NEXTBASEEXP);
+		clif_updatestatus(sd,SP_JOBEXP);
 		clif_updatestatus(sd,SP_NEXTJOBEXP);
 		clif_updatestatus(sd,SP_SKILLPOINT);
 		clif_initialstatus(sd);
@@ -8720,7 +8639,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 
   	// If player is dead, and is spawned (such as @refresh) send death packet. [Valaris]
 	if(pc_isdead(sd))
-		clif_clearunit_area(&sd->bl, 1);
+		clif_clearunit_area(&sd->bl, CLR_DEAD);
 // Uncomment if you want to make player face in the same direction he was facing right before warping. [Skotlex]
 //	else
 //		clif_changed_dir(&sd->bl, SELF);
@@ -8821,7 +8740,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
 	int cmd;
 
 	if (pc_isdead(sd)) {
-		clif_clearunit_area(&sd->bl, 1);
+		clif_clearunit_area(&sd->bl, CLR_DEAD);
 		return;
 	}
 
@@ -8940,6 +8859,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
 	WFIFOW(fd,2) = 8 + textlen;
 	WFIFOL(fd,4) = sd->bl.id;
 	safestrncpy((char*)WFIFOP(fd,8), text, textlen);
+	//FIXME: chat has range of 9 only
 	clif_send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC);
 
 	// send back message to the speaker
@@ -9063,10 +8983,10 @@ void clif_parse_ChangeDir(int fd, struct map_session_data *sd)
  *------------------------------------------*/
 void clif_parse_Emotion(int fd, struct map_session_data *sd)
 {
-	unsigned char buf[64];
+	int emoticon = RFIFOB(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
 
 	if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 2) {
-		if (RFIFOB(fd,2) == 34) {// prevent use of the mute emote [Valaris]
+		if (emoticon == E_MUTE) {// prevent use of the mute emote [Valaris]
 			clif_skill_fail(sd, 1, 0, 1);
 			return;
 		}
@@ -9077,11 +8997,13 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd)
 			return;
 		}
 		sd->emotionlasttime = time(NULL) + 1; // not more than 1 per second (using /commands the client can spam it)
-		
-		WBUFW(buf,0) = 0xc0;
-		WBUFL(buf,2) = sd->bl.id;
-		WBUFB(buf,6) = RFIFOB(fd,2);
-		clif_send(buf, packet_len(0xc0), &sd->bl, AREA);
+
+		if(battle_config.client_reshuffle_dice && emoticon>=E_DICE1 && emoticon<=E_DICE6)
+		{// re-roll dice
+			emoticon = rand()%6+E_DICE1;
+		}
+
+		clif_emotion(&sd->bl, emoticon);
 	} else
 		clif_skill_fail(sd, 1, 0, 1);
 }
@@ -9100,7 +9022,7 @@ void clif_parse_HowManyConnections(int fd, struct map_session_data *sd)
 void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick)
 {
 	if (pc_isdead(sd)) {
-		clif_clearunit_area(&sd->bl, 1);
+		clif_clearunit_area(&sd->bl, CLR_DEAD);
 		return;
 	}
 
@@ -9198,7 +9120,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd)
 {
 	switch(RFIFOB(fd,2)) {
 	case 0x00:
-		pc_respawn(sd,2);
+		pc_respawn(sd,CLR_RESPAWN);
 		break;
 	case 0x01:
 		/*	Rovert's Prevent logout option - Fixed [Valaris]	*/
@@ -9219,7 +9141,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd)
 
 /*==========================================
  * Validates and processes whispered messages
- * S 0096 <packet len>.w <nick>.23B 00 <message>.?B
+ * S 0096 <packet len>.w <nick>.24B <message>.?B
  *------------------------------------------*/
 void clif_parse_WisMessage(int fd, struct map_session_data* sd)
 {
@@ -9416,7 +9338,7 @@ void clif_parse_TakeItem(int fd, struct map_session_data *sd)
 
 	do {
 		if (pc_isdead(sd)) {
-			clif_clearunit_area(&sd->bl, 1);
+			clif_clearunit_area(&sd->bl, CLR_DEAD);
 			break;
 		}
 
@@ -9451,7 +9373,8 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
 {
 	int item_index = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0])-2;
 	int item_amount = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[1]);
-	do {
+
+	for(;;) {
 		if (pc_isdead(sd))
 			break;
 
@@ -9469,7 +9392,7 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
 			break;
 
 		return;
-	} while (0);
+	}
 
 	//Because the client does not like being ignored.
 	clif_dropitem(sd, item_index,0);
@@ -9483,7 +9406,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd)
 	int n;
 
 	if (pc_isdead(sd)) {
-		clif_clearunit_area(&sd->bl, 1);
+		clif_clearunit_area(&sd->bl, CLR_DEAD);
 		return;
 	}
 
@@ -9516,7 +9439,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
 	int index;
 
 	if(pc_isdead(sd)) {
-		clif_clearunit_area(&sd->bl,1);
+		clif_clearunit_area(&sd->bl,CLR_DEAD);
 		return;
 	}
 	index = RFIFOW(fd,2)-2; 
@@ -9559,7 +9482,7 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd)
 	int index;
 
 	if(pc_isdead(sd)) {
-		clif_clearunit_area(&sd->bl,1);
+		clif_clearunit_area(&sd->bl,CLR_DEAD);
 		return;
 	}
 
@@ -9581,7 +9504,7 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
 	struct block_list *bl;
 
 	if(pc_isdead(sd)) {
-		clif_clearunit_area(&sd->bl,1);
+		clif_clearunit_area(&sd->bl,CLR_DEAD);
 		return;
 	}
 
@@ -9592,8 +9515,6 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
 	if (!bl) return;
 	switch (bl->type) {
 		case BL_MOB:
-			clif_parse_ActionRequest_sub(sd, 0x07, bl->id, gettick());
-			break;
 		case BL_PC:
 			clif_parse_ActionRequest_sub(sd, 0x07, bl->id, gettick());
 			break;
@@ -10260,6 +10181,11 @@ void clif_parse_Cooking(int fd,struct map_session_data *sd)
 	//int type = RFIFOW(fd,2); // '1' for cooking, but what do other values mean?
 	int nameid = RFIFOW(fd,4);
 
+	if( sd->menuskill_id != AM_PHARMACY )
+	{
+		return;
+	}
+
 	if (pc_istrading(sd)) {
 		//Make it fail to avoid shop exploits where you sell something different than you see.
 		clif_skill_fail(sd,sd->ud.skillid,0,0);
@@ -10379,9 +10305,15 @@ void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd)
  *------------------------------------------*/
 void clif_parse_ItemIdentify(int fd,struct map_session_data *sd)
 {
+	short idx = RFIFOW(fd,2);
+
 	if (sd->menuskill_id != MC_IDENTIFY)
 		return;
-	skill_identify(sd,RFIFOW(fd,2)-2);
+	if( idx == -1 )
+	{// cancel pressed
+		return;
+	}
+	skill_identify(sd,idx-2);
 	sd->menuskill_val = sd->menuskill_id = 0;
 }
 /*==========================================
@@ -10585,7 +10517,7 @@ void clif_parse_StoragePassword(int fd, struct map_session_data *sd)
 /*==========================================
  * Party creation request
  * S 00f9 <party name>.24S
- * S 01e8 <party name>.24S <item1>.B <item2>.B
+ * S 01e8 <party name>.24S <share flag>.B <share type>.B
  *------------------------------------------*/
 void clif_parse_CreateParty(int fd, struct map_session_data *sd)
 {
@@ -10796,10 +10728,10 @@ void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data* sd)
 {
 	short level = RFIFOW(fd,2);
 	short mapid = RFIFOW(fd,4);
-	short job[6];
+	short job[PARTY_BOOKING_JOBS];
 	int i;
 	
-	for(i=0; i<6; i++)
+	for(i=0; i<PARTY_BOOKING_JOBS; i++)
 		job[i] = RFIFOB(fd,6+i*2);
 
 	party_booking_register(sd, level, mapid, job);
@@ -10832,7 +10764,7 @@ void clif_parse_PartyBookingSearchReq(int fd, struct map_session_data* sd)
 /*==========================================
  * more_result: 0 - no more, 1 - more
  *------------------------------------------*/
-void clif_PartyBookingSearchAck(int fd, unsigned long *index, int count, bool more_result)
+void clif_PartyBookingSearchAck(int fd, struct party_booking_ad_info** results, int count, bool more_result)
 {
 	int i, j;
 	int size = sizeof(struct party_booking_ad_info); // structure size (48)
@@ -10840,17 +10772,16 @@ void clif_PartyBookingSearchAck(int fd, unsigned long *index, int count, bool mo
 	WFIFOHEAD(fd,size*count + 5);
 	WFIFOW(fd,0) = 0x805;
 	WFIFOW(fd,2) = size*count + 5;
-	WFIFOB(fd,4) = (bool)more_result;
+	WFIFOB(fd,4) = more_result;
 	for(i=0; i<count; i++)
 	{
-		pb_ad = party_booking_getdata(index[i]);
-		if(pb_ad == NULL) return;
+		pb_ad = results[i];
 		WFIFOL(fd,i*size+5) = pb_ad->index;
 		memcpy(WFIFOP(fd,i*size+9),pb_ad->charname,NAME_LENGTH);
 		WFIFOL(fd,i*size+33) = pb_ad->starttime;
 		WFIFOW(fd,i*size+37) = pb_ad->p_detail.level;
 		WFIFOW(fd,i*size+39) = pb_ad->p_detail.mapid;
-		for(j=0; j<6; j++)
+		for(j=0; j<PARTY_BOOKING_JOBS; j++)
 			WFIFOW(fd,i*size+41+j*2) = pb_ad->p_detail.job[j];
 	}
 	WFIFOSET(fd,WFIFOW(fd,2));
@@ -10858,7 +10789,7 @@ void clif_PartyBookingSearchAck(int fd, unsigned long *index, int count, bool mo
 
 void clif_parse_PartyBookingDeleteReq(int fd, struct map_session_data* sd)
 {
-	if(party_booking_delete(sd, false))
+	if(party_booking_delete(sd))
 		clif_PartyBookingDeleteAck(sd, 0);
 }
 
@@ -10877,10 +10808,10 @@ void clif_PartyBookingDeleteAck(struct map_session_data* sd, int flag)
 
 void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data* sd)
 {
-	short job[6];
+	short job[PARTY_BOOKING_JOBS];
 	int i;
 	
-	for(i=0; i<6; i++)
+	for(i=0; i<PARTY_BOOKING_JOBS; i++)
 		job[i] = RFIFOW(fd,2+i*2);
 
 	party_booking_update(sd, job);
@@ -10889,32 +10820,32 @@ void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data* sd)
 void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad)
 {
 	int i;
+	uint8 buf[38+PARTY_BOOKING_JOBS*2];
 
 	if(pb_ad == NULL) return;
 
-	WFIFOHEAD(sd->fd,packet_len(0x809));
-	WFIFOW(sd->fd,0) = 0x809;
-	WFIFOL(sd->fd,2) = pb_ad->index;
-	memcpy(WFIFOP(sd->fd,6),pb_ad->charname,NAME_LENGTH);
-	WFIFOL(sd->fd,30) = pb_ad->starttime;
-	WFIFOW(sd->fd,34) = pb_ad->p_detail.level;
-	WFIFOW(sd->fd,36) = pb_ad->p_detail.mapid;
-	for(i=0; i<6; i++)
-		WFIFOW(sd->fd,38+i*2) = pb_ad->p_detail.job[i];
+	WBUFW(buf,0) = 0x809;
+	WBUFL(buf,2) = pb_ad->index;
+	memcpy(WBUFP(buf,6),pb_ad->charname,NAME_LENGTH);
+	WBUFL(buf,30) = pb_ad->starttime;
+	WBUFW(buf,34) = pb_ad->p_detail.level;
+	WBUFW(buf,36) = pb_ad->p_detail.mapid;
+	for(i=0; i<PARTY_BOOKING_JOBS; i++)
+		WBUFW(buf,38+i*2) = pb_ad->p_detail.job[i];
 	
-	WFIFOSET(sd->fd,packet_len(0x809));
+	clif_send(buf, packet_len(0x809), &sd->bl, ALL_CLIENT);
 }
 
 void clif_PartyBookingUpdateNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad)
 {
 	int i;
-	uint8 buf[18];
+	uint8 buf[6+PARTY_BOOKING_JOBS*2];
 
 	if(pb_ad == NULL) return;
 
 	WBUFW(buf,0) = 0x80a;
 	WBUFL(buf,2) = pb_ad->index;
-	for(i=0; i<6; i++)
+	for(i=0; i<PARTY_BOOKING_JOBS; i++)
 		WBUFW(buf,6+i*2) = pb_ad->p_detail.job[i];
 	clif_send(buf,packet_len(0x80a),&sd->bl,ALL_CLIENT); // Now UPDATE all client.
 }
@@ -10941,10 +10872,11 @@ void clif_parse_CloseVending(int fd, struct map_session_data* sd)
  *------------------------------------------*/
 void clif_parse_VendingListReq(int fd, struct map_session_data* sd)
 {
-	vending_vendinglistreq(sd,RFIFOL(fd,2));
-
 	if( sd->npc_id )
-		npc_event_dequeue(sd);
+	{// using an NPC
+		return;
+	}
+	vending_vendinglistreq(sd,RFIFOL(fd,2));
 }
 
 /*==========================================
@@ -11075,6 +11007,7 @@ void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd)
 
 /*==========================================
  * �M���h�����o��E�ύX
+ * S 0155 <packet len>.W {<account id>.L <char id>.L <idx>.L}
  *------------------------------------------*/
 void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd)
 {
@@ -11103,6 +11036,7 @@ void clif_parse_GuildRequestEmblem(int fd,struct map_session_data *sd)
 
 /*==========================================
  * �M���h�G���u�����ύX
+ * S 0153 <packet len>.W <emblem data>.?B
  *------------------------------------------*/
 void clif_parse_GuildChangeEmblem(int fd,struct map_session_data *sd)
 {
@@ -11128,7 +11062,7 @@ void clif_parse_GuildChangeNotice(int fd, struct map_session_data* sd)
 	// compensate for some client defects when using multilanguage mode
 	if (msg1[0] == '|' && msg1[3] == '|') msg1+= 3; // skip duplicate marker
 	if (msg2[0] == '|' && msg2[3] == '|') msg2+= 3; // skip duplicate marker
-	if (msg2[0] == '|') msg2[strnlen(msg2, 120)-1] = '\0'; // delete extra space at the end of string
+	if (msg2[0] == '|') msg2[strnlen(msg2, MAX_GUILDMES2)-1] = '\0'; // delete extra space at the end of string
 
 	guild_change_notice(sd, guild_id, msg1, msg2);
 }
@@ -11186,7 +11120,7 @@ void clif_parse_GuildLeave(int fd,struct map_session_data *sd)
 
 /*==========================================
  * Request to expel a member of a guild
- * S 015b <guild_id>.L <account_id>.L <char_id>.L <reason>.39B 00
+ * S 015b <guild_id>.L <account_id>.L <char_id>.L <reason>.40B
  *------------------------------------------*/
 void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd)
 {
@@ -11458,10 +11392,11 @@ void clif_parse_GMKickAll(int fd, struct map_session_data* sd)
 }
 
 /*==========================================
- * /shift <name>
+ * /remove <account name>
+ * /shift <char name>
  *------------------------------------------*/
 void clif_parse_GMShift(int fd, struct map_session_data *sd)
-{	
+{// FIXME: remove is supposed to receive account name for clients prior 20100803RE
 	char *player_name;
 	int lv;
 
@@ -11480,11 +11415,47 @@ void clif_parse_GMShift(int fd, struct map_session_data *sd)
 	}
 }
 
+
+/// Warps oneself to the location of the character given by account id ( /remove <account id> ).
+/// R 0843 <account id>.L
+void clif_parse_GMRemove2(int fd, struct map_session_data* sd)
+{
+	int account_id, lv;
+	struct map_session_data* pl_sd;
+
+	if( battle_config.atc_gmonly && !pc_isGM(sd) )
+	{
+		return;
+	}
+
+	if( pc_isGM(sd) < ( lv = get_atcommand_level(atcommand_jumpto) ) )
+	{
+		return;
+	}
+
+	account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
+
+	if( ( pl_sd = map_id2sd(account_id) ) != NULL && pc_isGM(sd) >= pc_isGM(pl_sd) )
+	{
+		pc_warpto(sd, pl_sd);
+	}
+
+	if( log_config.gm && lv >= log_config.gm )
+	{
+		char message[32];
+
+		sprintf(message, "/remove %d", account_id);
+		log_atcommand(sd, message);
+	}
+}
+
+
 /*==========================================
- * /recall <name>
+ * /recall <account name>
+ * /summon <char name>
  *------------------------------------------*/
 void clif_parse_GMRecall(int fd, struct map_session_data *sd)
-{
+{// FIXME: recall is supposed to receive account name for clients prior 20100803RE
 	char *player_name;
 	int lv;
 
@@ -11504,8 +11475,44 @@ void clif_parse_GMRecall(int fd, struct map_session_data *sd)
 	}
 }
 
+
+/// Summons a character given by account id to one's own position ( /recall <account id> )
+/// R 0842 <account id>.L
+void clif_parse_GMRecall2(int fd, struct map_session_data* sd)
+{
+	int account_id, lv;
+	struct map_session_data* pl_sd;
+
+	if( battle_config.atc_gmonly && !pc_isGM(sd) )
+	{
+		return;
+	}
+
+	if( pc_isGM(sd) < ( lv = get_atcommand_level(atcommand_recall) ) )
+	{
+		return;
+	}
+
+	account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
+
+	if( ( pl_sd = map_id2sd(account_id) ) != NULL && pc_isGM(sd) >= pc_isGM(pl_sd) )
+	{
+		pc_recall(sd, pl_sd);
+	}
+
+	if( log_config.gm && lv >= log_config.gm )
+	{
+		char message[32];
+
+		sprintf(message, "/recall %d", account_id);
+		log_atcommand(sd, message);
+	}
+}
+
+
 /*==========================================
  * /monster /item 
+ * R 01F3 <name>.24B
  *------------------------------------------*/
 void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd)
 {
@@ -11663,11 +11670,11 @@ void clif_parse_GMReqAccountName(int fd, struct map_session_data *sd)
 
 /*==========================================
  * GM single cell type change request
- * /changemaptype <x> <y> <type>
+ * /changemaptype <x> <y> <type:0-1>
  * S 0198 <x>.W <y>.W <gat>.W
  *------------------------------------------*/
 void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd)
-{
+{// FIXME: type sent by client is 0 or 1 (even if you enter 2+); that suggests, that it is walkable gat attribute
 	int x,y,type;
 
 	if( battle_config.atc_gmonly && !pc_isGM(sd) )
@@ -12107,6 +12114,7 @@ void clif_parse_PVPInfo(int fd,struct map_session_data *sd)
 
 /*==========================================
  * /blacksmith
+ * S 0217
  *------------------------------------------*/
 void clif_parse_Blacksmith(int fd,struct map_session_data *sd)
 {
@@ -12150,6 +12158,7 @@ int clif_fame_blacksmith(struct map_session_data *sd, int points)
 
 /*==========================================
  * /alchemist
+ * S 0218
  *------------------------------------------*/
 void clif_parse_Alchemist(int fd,struct map_session_data *sd)
 {
@@ -12193,6 +12202,7 @@ int clif_fame_alchemist(struct map_session_data *sd, int points)
 
 /*==========================================
  * /taekwon
+ * S 0225
  *------------------------------------------*/
 void clif_parse_Taekwon(int fd,struct map_session_data *sd)
 {
@@ -12234,7 +12244,8 @@ int clif_fame_taekwon(struct map_session_data *sd, int points)
 }
 
 /*==========================================
- * PK Ranking table?
+ * /pk
+ * S 0237
  *------------------------------------------*/
 void clif_parse_RankingPk(int fd,struct map_session_data *sd)
 {
@@ -12259,7 +12270,7 @@ void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd)
 	if (sd->menuskill_id != SG_FEEL)
 		return;
 	i = sd->menuskill_val-1;
-	if (i<0 || i > 2) return; //Bug?
+	if (i<0 || i >= MAX_PC_FEELHATE) return; //Bug?
 
 	sd->feel_map[i].index = map_id2index(sd->bl.m);
 	sd->feel_map[i].m = sd->bl.m;
@@ -12738,9 +12749,10 @@ void clif_parse_Mail_setattach(int fd, struct map_session_data *sd)
 
 /*------------------------------------------
  * Mail Window Operation
+ * S 0246 <flag>.W
  * 0 : Switch to 'new mail' window, or Close mailbox
  * 1 : ???
- * 2 : ???
+ * 2 : Zeny entering start
  *------------------------------------------*/
 void clif_parse_Mail_winopen(int fd, struct map_session_data *sd)
 {
@@ -13592,12 +13604,9 @@ void clif_parse_mercenary_action(int fd, struct map_session_data* sd)
  * 2 = Your mercenary soldier has been fired.
  * 3 = Your mercenary soldier has ran away.
  *------------------------------------------*/
-void clif_mercenary_message(int fd, int message)
+void clif_mercenary_message(struct map_session_data* sd, int message)
 {
-	WFIFOHEAD(fd,4);
-	WFIFOW(fd,0) = 0x0291;
-	WFIFOW(fd,2) = 1266 + message;
-	WFIFOSET(fd,4);
+	clif_msg(sd, 1266 + message);
 }
 
 /*------------------------------------------
@@ -13959,6 +13968,23 @@ void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, b
     return;
 }
 
+/// Displays digital clock digits on top of the screen (ZC_SHOWDIGIT).
+/// type:
+///   0: Displays 'value' for 5 seconds.
+///   1: Incremental counter (1 tick/second), negated 'value' specifies start value (e.g. using -10 lets the counter start at 10).
+///   2: Decremental counter (1 tick/second), negated 'value' specifies start value (does not stop when reaching 0, but overflows).
+///   3: Decremental counter (2 ticks/second), 'value' specifies start value (stops when reaching 0, displays at most 2 digits).
+/// value:
+///   Except for type 3 it is interpreted as seconds for displaying as DD:HH:MM:SS, HH:MM:SS, MM:SS or SS (leftmost '00' is not displayed).
+void clif_showdigit(struct map_session_data* sd, unsigned char type, int value)
+{
+	WFIFOHEAD(sd->fd, packet_len(0x1b1));
+	WFIFOW(sd->fd,0) = 0x1b1;
+	WFIFOB(sd->fd,0) = type;
+	WFIFOL(sd->fd,0) = value;
+	WFIFOSET(sd->fd, packet_len(0x1b1));
+}
+
 /*==========================================
  * �p�P�b�g�f�o�b�O
  *------------------------------------------*/
@@ -13987,10 +14013,10 @@ int clif_parse(int fd)
 	TBL_PC* sd;
 	int pnum;
 
-	//TODO apply deplays or disconnect based on packet throughput [FlavioJS]
+	//TODO apply delays or disconnect based on packet throughput [FlavioJS]
 	// Note: "click masters" can do 80+ clicks in 10 seconds
 
-	for( pnum = 0; pnum < 3; ++pnum )// Limit max packets per cycle to 3 (delay packet spammers) [FlavioJS]
+	for( pnum = 0; pnum < 3; ++pnum )// Limit max packets per cycle to 3 (delay packet spammers) [FlavioJS]  -- This actually aids packet spammers, but stuff like /str+ gets slow without it [Ai4rei]
 	{ // begin main client packet processing loop
 
 	sd = (TBL_PC *)session[fd]->session_data;
@@ -14491,6 +14517,8 @@ static int packetdb_readdb(void)
 		{clif_parse_GMShift,"shift"},
 		{clif_parse_GMChangeMapType,"changemaptype"},
 		{clif_parse_GMRc,"rc"},
+		{clif_parse_GMRecall2,"recall2"},
+		{clif_parse_GMRemove2,"remove2"},
 
 		{clif_parse_NoviceDoriDori,"sndoridori"},
 		{clif_parse_NoviceExplosionSpirits,"snexplosionspirits"},
diff --git a/src/map/clif.h b/src/map/clif.h
index d3a3679f1..ded8ece30 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -78,6 +78,101 @@ typedef enum send_target {
 	BG_AREA_WOS,
 } send_target;
 
+typedef enum emotion_type
+{
+	E_GASP = 0,     // /!
+	E_WHAT,         // /?
+	E_HO,
+	E_LV,
+	E_SWT,
+	E_IC,
+	E_AN,
+	E_AG,
+	E_CASH,         // /$
+	E_DOTS,         // /...
+	E_SCISSORS,     // /gawi --- 10
+	E_ROCK,         // /bawi
+	E_PAPER,        // /bo
+	E_KOREA,
+	E_LV2,
+	E_THX,
+	E_WAH,
+	E_SRY,
+	E_HEH,
+	E_SWT2,
+	E_HMM,          // --- 20
+	E_NO1,
+	E_NO,           // /??
+	E_OMG,
+	E_OH,
+	E_X,
+	E_HLP,
+	E_GO,
+	E_SOB,
+	E_GG,
+	E_KIS,          // --- 30
+	E_KIS2,
+	E_PIF,
+	E_OK,
+	E_MUTE,         // red /... used for muted characters
+	E_INDONESIA,
+	E_BZZ,          // /bzz, /stare
+	E_RICE,
+	E_AWSM,         // /awsm, /cool
+	E_MEH,
+	E_SHY,          // --- 40
+	E_PAT,          // /pat, /goodboy
+	E_MP,           // /mp, /sptime
+	E_SLUR,
+	E_COM,          // /com, /comeon
+	E_YAWN,         // /yawn, /sleepy
+	E_GRAT,         // /grat, /congrats
+	E_HP,           // /hp, /hptime
+	E_PHILIPPINES,
+	E_MALAYSIA,
+	E_SINGAPORE,    // --- 50
+	E_BRAZIL,
+	E_FLASH,        // /fsh
+	E_SPIN,         // /spin
+	E_SIGH,
+	E_PROUD,        // /dum
+	E_LOUD,         // /crwd
+	E_OHNOES,       // /desp, /otl
+	E_DICE1,
+	E_DICE2,
+	E_DICE3,        // --- 60
+	E_DICE4,
+	E_DICE5,
+	E_DICE6,
+	E_INDIA,
+	E_LOOSER,
+	E_RUSSIA,
+	E_VIRGIN,
+	E_PHONE,
+	E_MAIL,
+	E_CHINESE,      // --- 70
+	E_SIGNAL,
+	E_SIGNAL2,
+	E_SIGNAL3,
+	E_HUM,
+	E_ABS,
+	E_OOPS,
+	E_SPIT,
+	E_ENE,
+	E_PANIC,
+	E_WHISP,        // --- 80
+	//
+	E_MAX
+} emotion_type;
+
+typedef enum clr_type
+{
+	CLR_OUTSIGHT = 0,
+	CLR_DEAD,
+	CLR_RESPAWN,
+	CLR_TELEPORT,
+} clr_type;
+
 int clif_setip(const char* ip);
 void clif_setbindip(const char* ip);
 void clif_setport(uint16 port);
@@ -92,8 +187,8 @@ int clif_charselectok(int);
 int clif_dropflooritem(struct flooritem_data *);
 int clif_clearflooritem(struct flooritem_data *,int);
 
-int clif_clearunit_single(int id, uint8 type, int fd);
-int clif_clearunit_area(struct block_list* bl, uint8 type);
+int clif_clearunit_single(int id, clr_type type, int fd);
+int clif_clearunit_area(struct block_list* bl, clr_type type);
 int clif_clearunit_delayed(struct block_list* bl, unsigned int tick);
 int clif_spawn(struct block_list*);	//area
 int clif_walkok(struct map_session_data*);	// self
@@ -133,14 +228,13 @@ int clif_statusupack(struct map_session_data *,int,int,int);	// self
 int clif_equipitemack(struct map_session_data *,int,int,int);	// self
 int clif_unequipitemack(struct map_session_data *,int,int,int);	// self
 int clif_misceffect(struct block_list*,int);	// area
-int clif_misceffect2(struct block_list *bl,int type);
 int clif_changeoption(struct block_list*);	// area
 int clif_changeoption2(struct block_list*);	// area
 int clif_useitemack(struct map_session_data*,int,int,int);	// self
 void clif_GlobalMessage(struct block_list* bl, const char* message);
-void clif_createchat(struct map_session_data* sd, int fail);	// self
+void clif_createchat(struct map_session_data* sd, int flag);	// self
 int clif_dispchat(struct chat_data*,int);	// area or fd
-int clif_joinchatfail(struct map_session_data*,int);	// self
+int clif_joinchatfail(struct map_session_data* sd,int flag);	// self
 int clif_joinchatok(struct map_session_data*,struct chat_data*);	// self
 int clif_addchat(struct chat_data*,struct map_session_data*);	// chat
 void clif_changechatowner(struct chat_data* cd, struct map_session_data* sd);	// chat
@@ -158,7 +252,7 @@ void clif_talkiebox(struct block_list* bl, const char* talkie);
 void clif_wedding_effect(struct block_list *bl);
 void clif_divorced(struct map_session_data* sd, const char* name);
 void clif_callpartner(struct map_session_data *sd);
-void clif_playBGM(struct map_session_data* sd, struct block_list* bl, const char* name);
+void clif_playBGM(struct map_session_data* sd, const char* name);
 void clif_soundeffect(struct map_session_data* sd, struct block_list* bl, const char* name, int type);
 int clif_soundeffectall(struct block_list* bl, const char *name, int type, enum send_target coverage);
 void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick);
@@ -176,14 +270,12 @@ void clif_tradecompleted(struct map_session_data* sd, int fail);
 
 // storage
 #include "storage.h"
-void clif_storagelist(struct map_session_data* sd, struct storage_data* stor);
+void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length);
 void clif_updatestorageamount(struct map_session_data* sd, int amount);
 void clif_storageitemadded(struct map_session_data* sd, struct item* i, int index, int amount);
 void clif_storageitemremoved(struct map_session_data* sd, int index, int amount);
 void clif_storageclose(struct map_session_data* sd);
-void clif_guildstoragelist(struct map_session_data* sd, struct guild_storage* stor);
 void clif_updateguildstorageamount(struct map_session_data* sd, int amount);
-void clif_guildstorageitemadded(struct map_session_data* sd, struct item* i, int index, int amount);
 
 int clif_insight(struct block_list *,va_list);	// map_forallinmovearea callback
 int clif_outsight(struct block_list *,va_list);	// map_forallinmovearea callback
@@ -218,7 +310,7 @@ int clif_produceeffect(struct map_session_data* sd,int flag,int nameid);
 void clif_skill_setunit(struct skill_unit *unit);
 void clif_skill_delunit(struct skill_unit *unit);
 
-void clif_01ac(struct block_list* bl);
+void clif_skillunit_update(struct block_list* bl);
 
 int clif_autospell(struct map_session_data *sd,int skilllv);
 void clif_devotion(struct block_list *src, struct map_session_data *tsd);
@@ -390,6 +482,7 @@ void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, un
 int clif_party_xy_remove(struct map_session_data *sd); //Fix for minimap [Kevin]
 void clif_gospel_info(struct map_session_data *sd, int type);
 void clif_parse_ReqFeel(int fd, struct map_session_data *sd, int skilllv); 
+void clif_starskill(struct map_session_data* sd, const char* mapname, int monster_id, unsigned char star, unsigned char result);
 void clif_feel_info(struct map_session_data *sd, unsigned char feel_level, unsigned char type);
 void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int class_, unsigned char type);
 void clif_mission_info(struct map_session_data *sd, int mob_id, unsigned char progress);
@@ -409,6 +502,8 @@ void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* ts
 void clif_viewequip_fail(struct map_session_data* sd);
 void clif_equipcheckbox(struct map_session_data* sd);
 
+void clif_msg(struct map_session_data* sd, unsigned short id);
+
 //quest system [Kevin] [Inkfish]
 void clif_quest_send_list(struct map_session_data * sd);  
 void clif_quest_send_mission(struct map_session_data * sd);  
@@ -450,7 +545,7 @@ void clif_Adopt_reply(struct map_session_data *sd, int type);
 // MERCENARIES
 void clif_mercenary_info(struct map_session_data *sd);
 void clif_mercenary_skillblock(struct map_session_data *sd);
-void clif_mercenary_message(int fd, int message);
+void clif_mercenary_message(struct map_session_data* sd, int message);
 void clif_mercenary_updatestatus(struct map_session_data *sd, int type);
 
 // RENTAL SYSTEM
@@ -469,9 +564,11 @@ void clif_progressbar_abort(struct map_session_data * sd);
 
 void clif_PartyBookingRegisterAck(struct map_session_data *sd, int flag);
 void clif_PartyBookingDeleteAck(struct map_session_data* sd, int flag);
-void clif_PartyBookingSearchAck(int fd, unsigned long *index, int count, bool more_result);
+void clif_PartyBookingSearchAck(int fd, struct party_booking_ad_info** results, int count, bool more_result);
 void clif_PartyBookingUpdateNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad);
 void clif_PartyBookingDeleteNotify(struct map_session_data* sd, int index);
 void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad);
 
+void clif_showdigit(struct map_session_data* sd, unsigned char type, int value);
+
 #endif /* _CLIF_H_ */
diff --git a/src/map/guild.c b/src/map/guild.c
index cdc978929..f90fc8946 100644
--- a/src/map/guild.c
+++ b/src/map/guild.c
@@ -1068,8 +1068,8 @@ int guild_notice_changed(int guild_id,const char *mes1,const char *mes2)
 	if(g==NULL)
 		return 0;
 
-	memcpy(g->mes1,mes1,60);
-	memcpy(g->mes2,mes2,120);
+	memcpy(g->mes1,mes1,MAX_GUILDMES1);
+	memcpy(g->mes2,mes2,MAX_GUILDMES2);
 
 	for(i=0;i<g->max_member;i++){
 		if((sd=g->member[i].sd)!=NULL)
diff --git a/src/map/homunculus.c b/src/map/homunculus.c
index 97a3274fb..0fbd7cbff 100644
--- a/src/map/homunculus.c
+++ b/src/map/homunculus.c
@@ -68,7 +68,7 @@ int merc_hom_dead(struct homun_data *hd, struct block_list *src)
 	//There's no intimacy penalties on death (from Tharis)
 	struct map_session_data *sd = hd->master;
 
-	clif_emotion(&hd->bl, 16) ;	//wah
+	clif_emotion(&hd->bl, E_WAH);
 
 	//Delete timers when dead.
 	merc_hom_hungry_timer_delete(hd);
@@ -77,7 +77,7 @@ int merc_hom_dead(struct homun_data *hd, struct block_list *src)
 	if (!sd) //unit remove map will invoke unit free
 		return 3;
 
-	clif_emotion(&sd->bl, 28) ; //sob
+	clif_emotion(&sd->bl, E_SOB);
 	//Remove from map (if it has no intimacy, it is auto-removed from memory)
 	return 3;
 }
@@ -107,7 +107,7 @@ int merc_hom_vaporize(struct map_session_data *sd, int flag)
 		memset(hd->blockskill, 0, sizeof(hd->blockskill));
 	clif_hominfo(sd, sd->hd, 0);
 	merc_save(hd);
-	return unit_remove_map(&hd->bl, 0);
+	return unit_remove_map(&hd->bl, CLR_OUTSIGHT);
 }
 
 //delete a homunculus, completely "killing it". 
@@ -119,7 +119,7 @@ int merc_hom_delete(struct homun_data *hd, int emote)
 	sd = hd->master;
 
 	if (!sd)
-		return unit_free(&hd->bl,1);
+		return unit_free(&hd->bl,CLR_DEAD);
 
 	if (emote >= 0)
 		clif_emotion(&sd->bl, emote);
@@ -129,7 +129,7 @@ int merc_hom_delete(struct homun_data *hd, int emote)
 	// Send homunculus_dead to client
 	hd->homunculus.hp = 0;
 	clif_hominfo(sd, hd, 0);
-	return unit_remove_map(&hd->bl,0);
+	return unit_remove_map(&hd->bl,CLR_OUTSIGHT);
 }
 
 int merc_hom_calc_skilltree(struct homun_data *hd)
@@ -147,7 +147,7 @@ int merc_hom_calc_skilltree(struct homun_data *hd)
 			continue; //Skill already known.
 		if(!battle_config.skillfree)
 		{
-			for(j=0;j<5;j++)
+			for(j=0;j<MAX_PC_SKILL_REQUIRE;j++)
 			{
 				if( hskill_tree[c][i].need[j].id &&
 					merc_hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv) 
@@ -291,7 +291,7 @@ int merc_hom_evolution(struct homun_data *hd)
 
 	if(!hd->homunculusDB->evo_class || hd->homunculus.class_ == hd->homunculusDB->evo_class)
 	{
-		clif_emotion(&hd->bl, 4) ;	//swt
+		clif_emotion(&hd->bl, E_SWT);
 		return 0 ;
 	}
 	sd = hd->master;
@@ -317,12 +317,12 @@ int merc_hom_evolution(struct homun_data *hd)
 	hom->luk += 10*rand(min->luk, max->luk);
 	hom->intimacy = 500;
 
-	unit_remove_map(&hd->bl, 0);
+	unit_remove_map(&hd->bl, CLR_OUTSIGHT);
 	map_addblock(&hd->bl);
 
 	clif_spawn(&hd->bl);
-	clif_emotion(&sd->bl, 21);	//no1
-	clif_misceffect2(&hd->bl,568);
+	clif_emotion(&sd->bl, E_NO1);
+	clif_specialeffect(&hd->bl,568,AREA);
 
 	//status_Calc flag&1 will make current HP/SP be reloaded from hom structure
 	hom->hp = hd->battle_status.hp;
@@ -362,7 +362,7 @@ int merc_hom_gainexp(struct homun_data *hd,int exp)
 	if( hd->exp_next == 0 )
 		hd->homunculus.exp = 0 ;
 
-	clif_misceffect2(&hd->bl,568);
+	clif_specialeffect(&hd->bl,568,AREA);
 	status_calc_homunculus(hd,0);
 	status_percent_heal(&hd->bl, 100, 100);
 	return 0;
@@ -448,33 +448,33 @@ int merc_hom_food(struct map_session_data *sd, struct homun_data *hd)
 
 	if ( hd->homunculus.hunger >= 91 ) {
 		merc_hom_decrease_intimacy(hd, 50);
-		emotion = 16;
+		emotion = E_WAH;
 	} else if ( hd->homunculus.hunger >= 76 ) {
 		merc_hom_decrease_intimacy(hd, 5);
-		emotion = 19;
+		emotion = E_SWT2;
 	} else if ( hd->homunculus.hunger >= 26 ) {
 		merc_hom_increase_intimacy(hd, 75);
-		emotion = 2;
+		emotion = E_HO;
 	} else if ( hd->homunculus.hunger >= 11 ) {
 		merc_hom_increase_intimacy(hd, 100);
-		emotion = 2;
+		emotion = E_HO;
 	} else {
 		merc_hom_increase_intimacy(hd, 50);
-		emotion = 2;
+		emotion = E_HO;
 	}
 
 	hd->homunculus.hunger += 10;	//dunno increase value for each food
 	if(hd->homunculus.hunger > 100)
 		hd->homunculus.hunger = 100;
 
-	clif_emotion(&hd->bl,emotion) ;
+	clif_emotion(&hd->bl,emotion);
 	clif_send_homdata(sd,SP_HUNGRY,hd->homunculus.hunger);
 	clif_send_homdata(sd,SP_INTIMATE,hd->homunculus.intimacy / 100);
 	clif_hom_food(sd,foodID,1);
        	
 	// Too much food :/
 	if(hd->homunculus.intimacy == 0)
-		return merc_hom_delete(sd->hd, 23); //omg  
+		return merc_hom_delete(sd->hd, E_OMG);
 
 	return 0;
 }
@@ -500,18 +500,18 @@ static int merc_hom_hungry(int tid, unsigned int tick, int id, intptr data)
 	
 	hd->homunculus.hunger-- ;
 	if(hd->homunculus.hunger <= 10) {
-		clif_emotion(&hd->bl, 6) ;	//an
+		clif_emotion(&hd->bl, E_AN);
 	} else if(hd->homunculus.hunger == 25) {
-		clif_emotion(&hd->bl, 20) ;	//hmm
+		clif_emotion(&hd->bl, E_HMM);
 	} else if(hd->homunculus.hunger == 75) {
-		clif_emotion(&hd->bl, 33) ;	//ok
+		clif_emotion(&hd->bl, E_OK);
 	}  
 	
 	if(hd->homunculus.hunger < 0) {
 		hd->homunculus.hunger = 0;
 		// Delete the homunculus if intimacy <= 100
 		if ( !merc_hom_decrease_intimacy(hd, 100) )
-			return merc_hom_delete(hd, 23); //omg  
+			return merc_hom_delete(hd, E_OMG);
 		clif_send_homdata(sd,SP_INTIMATE,hd->homunculus.intimacy / 100);
 	}
 
@@ -676,7 +676,7 @@ int merc_call_homunculus(struct map_session_data *sd)
 		merc_save(hd); 
 	} else
 		//Warp him to master.
-		unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,0);
+		unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT);
 	return 1;
 }
 
@@ -871,7 +871,7 @@ int merc_hom_shuffle(struct homun_data *hd)
 	clif_homskillinfoblock(sd);
 	status_calc_homunculus(hd,0);
 	status_percent_heal(&hd->bl, 100, 100);
-	clif_misceffect2(&hd->bl,568);
+	clif_specialeffect(&hd->bl,568,AREA);
 
 	return 1;
 }
@@ -1088,7 +1088,7 @@ int read_homunculus_skilldb(void)
 		if (minJobLevelPresent)
 			hskill_tree[classid][j].joblv=atoi(split[3]);
 
-		for(k=0;k<5;k++){
+		for(k=0;k<MAX_PC_SKILL_REQUIRE;k++){
 			hskill_tree[classid][j].need[k].id=atoi(split[3+k*2+minJobLevelPresent]);
 			hskill_tree[classid][j].need[k].lv=atoi(split[3+k*2+minJobLevelPresent+1]);
 		}
diff --git a/src/map/instance.c b/src/map/instance.c
index c1d43c27b..6fa3a2c0a 100644
--- a/src/map/instance.c
+++ b/src/map/instance.c
@@ -235,7 +235,7 @@ int instance_del_load(struct map_session_data* sd, va_list args)
 	if( !sd || sd->bl.m != m )
 		return 0;
 
-	pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 0);
+	pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT);
 	return 1;
 }
 
@@ -439,9 +439,9 @@ void instance_check_kick(struct map_session_data *sd)
 	if( map[m].instance_id )
 	{ // User was on the instance map
 		if( map[m].save.map )
-			pc_setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, 3);
+			pc_setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, CLR_TELEPORT);
 		else
-			pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 3);
+			pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
 	}
 }
 
diff --git a/src/map/intif.c b/src/map/intif.c
index ba5230bab..875baa036 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -698,8 +698,8 @@ int intif_guild_notice(int guild_id,const char *mes1,const char *mes2)
 	WFIFOHEAD(inter_fd,186);
 	WFIFOW(inter_fd,0)=0x303e;
 	WFIFOL(inter_fd,2)=guild_id;
-	memcpy(WFIFOP(inter_fd,6),mes1,60);
-	memcpy(WFIFOP(inter_fd,66),mes2,120);
+	memcpy(WFIFOP(inter_fd,6),mes1,MAX_GUILDMES1);
+	memcpy(WFIFOP(inter_fd,66),mes2,MAX_GUILDMES2);
 	WFIFOSET(inter_fd,186);
 	return 0;
 }
@@ -984,10 +984,7 @@ int intif_parse_LoadGuildStorage(int fd)
 	if(battle_config.save_log)
 		ShowInfo("intif_open_guild_storage: %d\n",RFIFOL(fd,4) );
 	memcpy(gstor,RFIFOP(fd,12),sizeof(struct guild_storage));
-	gstor->storage_status = 1;
-	sd->state.storage_flag = 2;
-	clif_guildstoragelist(sd,gstor);
-	clif_updateguildstorageamount(sd,gstor->storage_amount);
+	storage_guild_storageopen(sd);
 	return 0;
 }
 int intif_parse_SaveGuildStorage(int fd)
@@ -1920,7 +1917,7 @@ int intif_parse_mercenary_received(int fd)
 	if( sizeof(struct s_mercenary) != len )
 	{
 		if( battle_config.etc_log )
-			ShowError("intif: create mercenary data size error %d != %d\n", sizeof(struct s_homunculus), len);
+			ShowError("intif: create mercenary data size error %d != %d\n", sizeof(struct s_mercenary), len);
 		return 0;
 	}
 
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 2096ddf9e..ce10f4f39 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -27,8 +27,6 @@ static struct item_group itemgroup_db[MAX_ITEMGROUP];
 
 struct item_data dummy_item; //This is the default dummy item used for non-existant items. [Skotlex]
 
-int item_delays = 0;
-
 /*==========================================
  * ���O�Ō����p
  *------------------------------------------*/
@@ -182,6 +180,27 @@ struct item_data* itemdb_exists(int nameid)
 	return item;
 }
 
+/// Returns human readable name for given item type.
+/// @param type Type id to retrieve name for ( IT_* ).
+const char* itemdb_typename(int type)
+{
+	switch(type)
+	{
+		case IT_HEALING:        return "Potion/Food";
+		case IT_USABLE:         return "Usable";
+		case IT_ETC:            return "Etc.";
+		case IT_WEAPON:         return "Weapon";
+		case IT_ARMOR:          return "Armor";
+		case IT_CARD:           return "Card";
+		case IT_PETEGG:         return "Pet Egg";
+		case IT_PETARMOR:       return "Pet Accessory";
+		case IT_AMMO:           return "Arrow/Ammunition";
+		case IT_DELAYCONSUME:   return "Delay-Consume Usable";
+		case IT_CASH:           return "Cash Usable";
+	}
+	return "Unknown Type";
+}
+
 /*==========================================
  * Converts the jobid from the format in itemdb 
  * to the format used by the map server. [Skotlex]
@@ -667,7 +686,7 @@ static int itemdb_read_itemtrade(void)
 static int itemdb_read_itemdelay(void)
 {
 	FILE *fp;
-	int nameid, j;
+	int nameid, j, item_delays = 0;
 	char line[1024], *str[10], *p;
 	struct item_data *id;
 
@@ -679,12 +698,12 @@ static int itemdb_read_itemdelay(void)
 
 	while(fgets(line, sizeof(line), fp))
 	{
+		if (line[0] == '/' && line[1] == '/')
+			continue;
 		if (item_delays == MAX_ITEMDELAYS) {
-			ShowError("itemdb_read_itemdelay: Too many entries specified in %s/item_delay.txt!\n", db_path);
+			ShowError("itemdb_read_itemdelay: Too many entries specified in %s/item_delay.txt! Increase MAX_ITEMDELAYS in itemdb.h!\n", db_path);
 			break;
 		}
-		if (line[0] == '/' && line[1] == '/')
-			continue;
 		memset(str, 0, sizeof(str));
 		for (j = 0, p = line; j < 2 && p; j++) {
 			str[j] = p;
@@ -750,6 +769,13 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr
 	safestrncpy(id->jname, str[2], sizeof(id->jname));
 
 	id->type = atoi(str[3]);
+
+	if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_DELAYCONSUME && id->type < IT_CASH ) || id->type >= IT_MAX )
+	{// catch invalid item types
+		ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %d. IT_ETC will be used.\n", id->type, nameid);
+		id->type = IT_ETC;
+	}
+
 	if (id->type == IT_DELAYCONSUME)
 	{	//Items that are consumed only after target confirmation
 		id->type = IT_USABLE;
@@ -809,8 +835,6 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr
 	id->look = atoi(str[18]);
 
 	id->flag.available = 1;
-	id->flag.value_notdc = 0;
-	id->flag.value_notoc = 0;
 	id->view_id = 0;
 	id->sex = itemdb_gendercheck(id); //Apply gender filtering.
 
@@ -1075,7 +1099,10 @@ void itemdb_reload(void)
 	// readjust itemdb pointer cache for each player
 	iter = mapit_geteachpc();
 	for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) )
+	{
+		memset(sd->item_delay, 0, sizeof(sd->item_delay));  // reset item delays
 		pc_setinventorydata(sd);
+	}
 	mapit_free(iter);
 }
 
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index 5b07b5c1b..3fb14b2d4 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -45,7 +45,7 @@ struct item_data {
 	int value_buy;
 	int value_sell;
 	int type;
-	int maxchance; //For logs, for external game info, for scripts: Max drop chance of this item (e.g. 0.01% , etc.. if it = 0, then monsters don't drop it) [Lupus]
+	int maxchance; //For logs, for external game info, for scripts: Max drop chance of this item (e.g. 0.01% , etc.. if it = 0, then monsters don't drop it, -1 denotes items sold in shops only) [Lupus]
 	int sex;
 	int equip;
 	int weight;
@@ -71,8 +71,6 @@ struct item_data {
 	struct script_code *unequip_script;//Script executed once when unequipping.
 	struct {
 		unsigned available : 1;
-		unsigned value_notdc : 1;
-		unsigned value_notoc : 1;
 		short no_equip;
 		unsigned no_refine : 1;	// [celest]
 		unsigned delay_consume : 1;	// Signifies items that are not consumed immediately upon double-click [Skotlex]
@@ -108,14 +106,13 @@ struct item_data* itemdb_exists(int nameid);
 #define itemdb_available(n) (itemdb_exists(n) && itemdb_search(n)->flag.available)
 #define itemdb_viewid(n) (itemdb_search(n)->view_id)
 #define itemdb_autoequip(n) (itemdb_search(n)->flag.autoequip)
+const char* itemdb_typename(int type);
 
 int itemdb_group_bonus(struct map_session_data* sd, int itemid);
 int itemdb_searchrandomid(int flags);
 
 #define itemdb_value_buy(n) itemdb_search(n)->value_buy
 #define itemdb_value_sell(n) itemdb_search(n)->value_sell
-#define itemdb_value_notdc(n) itemdb_search(n)->flag.value_notdc
-#define itemdb_value_notoc(n) itemdb_search(n)->flag.value_notoc
 #define itemdb_canrefine(n) itemdb_search(n)->flag.no_refine
 //Item trade restrictions [Skotlex]
 int itemdb_isdropable_sub(struct item_data *, int, int);
diff --git a/src/map/log.c b/src/map/log.c
index 474a6bb96..bf6133684 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -27,7 +27,7 @@ time_t curtime;
 //Bits: ||
 //2 - Healing items (0)
 //3 - Etc Items(3) + Arrows (10)
-//4 - Usable Items(2) + Scrolls,Lures(11)
+//4 - Usable Items(2) + Scrolls,Lures(11) + Usable Cash Items(18)
 //5 - Weapon(4)
 //6 - Shields,Armor,Headgears,Accessories,etc(5)
 //7 - Cards(6)
@@ -45,14 +45,14 @@ int should_log_item(int filter, int nameid, int amount)
 	if ((filter&1) || // Filter = 1, we log any item
 		(filter&2 && item_data->type == IT_HEALING ) ||
 		(filter&4 && (item_data->type == IT_ETC || item_data->type == IT_AMMO) ) ||
-		(filter&8 && item_data->type == IT_USABLE ) ||
+		(filter&8 && (item_data->type == IT_USABLE || item_data->type == IT_CASH) ) ||
 		(filter&16 && item_data->type == IT_WEAPON ) ||
 		(filter&32 && item_data->type == IT_ARMOR ) ||
 		(filter&64 && item_data->type == IT_CARD ) ||
 		(filter&128 && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) ||
 		(filter&256 && item_data->value_buy >= log_config.price_items_log ) ||		//expensive items
 		(filter&512 && abs(amount) >= log_config.amount_items_log ) ||			//big amount of items
-		(filter&2048 && ((item_data->maxchance <= log_config.rare_items_log) || item_data->nameid == 714) ) //Rare items or Emperium
+		(filter&2048 && ((item_data->maxchance != -1 && item_data->maxchance <= log_config.rare_items_log) || item_data->nameid == 714) ) //Rare items or Emperium
 	) return item_data->nameid;
 
 	return 0;
diff --git a/src/map/map.c b/src/map/map.c
index 309095ff0..b052cd7bc 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -1645,7 +1645,7 @@ int map_quit(struct map_session_data *sd)
 	if( sd->pd ) pet_lootitem_drop(sd->pd, sd);
 	if( sd->state.storage_flag == 1 ) sd->state.storage_flag = 0; // No need to Double Save Storage on Quit.
 
-	unit_remove_map_pc(sd,3);
+	unit_remove_map_pc(sd,CLR_TELEPORT);
 	
 	if( map[sd->bl.m].instance_id )
 	{ // Avoid map conflicts and warnings on next login
@@ -1665,7 +1665,7 @@ int map_quit(struct map_session_data *sd)
 		}
 	}	
 
-	party_booking_delete(sd, true); // Party Booking [Spiria]
+	party_booking_delete(sd); // Party Booking [Spiria]
 	pc_makesavestatus(sd);
 	pc_clean_skilltree(sd);
 	chrif_save(sd,1);
@@ -2150,7 +2150,7 @@ int map_removemobs_sub(struct block_list *bl, va_list ap)
 	if( md->db->mexp > 0 )
 		return 0;
 	
-	unit_free(&md->bl,0);
+	unit_free(&md->bl,CLR_OUTSIGHT);
 
 	return 1;
 }
@@ -2797,6 +2797,20 @@ int map_delmap(char* mapname)
 	return 0;
 }
 
+/// Initializes map flags and adjusts them depending on configuration.
+void map_flags_init(void)
+{
+	int i;
+
+	for( i = 0; i < map_num; i++ )
+	{
+		memset(&map[i].flag, 0, sizeof(map[i].flag));
+
+		if( battle_config.pk_mode )
+			map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
+	}
+}
+
 #define NO_WATER 1000000
 
 /*
@@ -2892,7 +2906,7 @@ int map_readallmaps (void)
 	int i;
 	FILE* fp=NULL;
 	int maps_removed = 0;
-	unsigned char *map_cache_buffer; // Has the uncompressed gat data of all maps, so just one allocation has to be made
+	unsigned char *map_cache_buffer = NULL; // Has the uncompressed gat data of all maps, so just one allocation has to be made
 	unsigned char map_cache_decode_buffer[MAX_MAP_SIZE];
 
 	if( enable_grf )
@@ -2958,8 +2972,6 @@ int map_readallmaps (void)
 		map[i].m = i;
 		memset(map[i].moblist, 0, sizeof(map[i].moblist));	//Initialize moblist [Skotlex]
 		map[i].mob_delete_timer = INVALID_TIMER;	//Initialize timer [Skotlex]
-		if(battle_config.pk_mode)
-			map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
 
 		map[i].bxs = (map[i].xs + BLOCK_SIZE - 1) / BLOCK_SIZE;
 		map[i].bys = (map[i].ys + BLOCK_SIZE - 1) / BLOCK_SIZE;
@@ -2973,6 +2985,9 @@ int map_readallmaps (void)
 		map[i].block_mob = (struct block_list**)aCalloc(size, 1);
 	}
 
+	// intialization and configuration-dependent adjustments of mapflags
+	map_flags_init();
+
 	if( !enable_grf ) {
 		fclose(fp);
 
@@ -3205,7 +3220,7 @@ int inter_config_read(char *cfgName)
 			continue;
 
 		if(strcmpi(w1, "main_chat_nick")==0)
-			strcpy(main_chat_nick, w2);
+			safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick));
 			
 	#ifndef TXT_ONLY
 		else
@@ -3365,7 +3380,7 @@ int cleanup_sub(struct block_list *bl, va_list ap)
 			npc_unload((struct npc_data *)bl);
 			break;
 		case BL_MOB:
-			unit_free(bl,0);
+			unit_free(bl,CLR_OUTSIGHT);
 			break;
 		case BL_PET:
 		//There is no need for this, the pet is removed together with the player. [Skotlex]
diff --git a/src/map/map.h b/src/map/map.h
index 9f25249e2..3b1775e46 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -296,6 +296,8 @@ enum _sp {
 
 	SP_BASEJOB=119,	// 100+19 - celest
 	SP_BASECLASS=120,	//Hmm.. why 100+19? I just use the next one... [Skotlex]
+	SP_KILLERRID=121,
+	SP_KILLEDRID=122,
 
 	// Mercenaries
 	SP_MERCFLEE=165, SP_MERCKILLS=189, SP_MERCFAITH=190,
@@ -628,6 +630,7 @@ int cleanup_sub(struct block_list *bl, va_list ap);
 
 void map_helpscreen(int flag); // [Valaris]
 int map_delmap(char* mapname);
+void map_flags_init(void);
 
 bool map_iwall_set(int m, int x, int y, int size, int dir, bool shootable, const char* wall_name);
 void map_iwall_get(struct map_session_data *sd);
diff --git a/src/map/mapreg_sql.c b/src/map/mapreg_sql.c
index 287aae4f9..f80be56a2 100644
--- a/src/map/mapreg_sql.c
+++ b/src/map/mapreg_sql.c
@@ -122,9 +122,9 @@ static void script_load_mapreg(void)
 		return;
 	}
 
-	SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &varname[0], 32, &length, NULL);
+	SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &varname[0], sizeof(varname), &length, NULL);
 	SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &index, 0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &value[0], 255, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &value[0], sizeof(value), NULL, NULL);
 	
 	while ( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
 	{
diff --git a/src/map/mercenary.c b/src/map/mercenary.c
index 84974e906..79bec2da6 100644
--- a/src/map/mercenary.c
+++ b/src/map/mercenary.c
@@ -244,7 +244,7 @@ int merc_delete(struct mercenary_data *md, int reply)
 	merc_contract_stop(md);
 
 	if( !sd )
-		return unit_free(&md->bl, 0);
+		return unit_free(&md->bl, CLR_OUTSIGHT);
 
 	if( md->devotion_flag )
 	{
@@ -258,8 +258,8 @@ int merc_delete(struct mercenary_data *md, int reply)
 		case 1: mercenary_set_faith(md, -1); break; // -1 Loyalty on Mercenary killed
 	}
 
-	clif_mercenary_message(sd->fd, reply);
-	return unit_remove_map(&md->bl, 0);
+	clif_mercenary_message(sd, reply);
+	return unit_remove_map(&md->bl, CLR_OUTSIGHT);
 }
 
 void merc_contract_stop(struct mercenary_data *md)
diff --git a/src/map/mob.c b/src/map/mob.c
index 413d88f26..d67b470af 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -82,7 +82,6 @@ const int mob_splendide[5] = { 1991, 1992, 1993, 1994, 1995 };
  *------------------------------------------*/
 static int mob_makedummymobdb(int);
 static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr data);
-int mobskill_use(struct mob_data *md,unsigned int tick,int event);
 int mob_skillid2skillidx(int class_,int skillid);
 
 /*==========================================
@@ -276,7 +275,7 @@ int mob_get_random_id(int type, int flag, int lv)
 		(flag&8 && mob->spawn[0].qty < 1)
 	) && (i++) < MAX_MOB_DB);
 
-	if(i >= MAX_MOB_DB)
+	if(i >= MAX_MOB_DB)  // no suitable monster found, use fallback for given list
 		class_ = mob_db_data[0]->summonper[type];
 	return class_;
 }
@@ -449,7 +448,7 @@ int mob_once_spawn(struct map_session_data* sd, int m, short x, short y, const c
 		if (class_ < 0 && battle_config.dead_branch_active)
 			//Behold Aegis's masterful decisions yet again...
 			//"I understand the "Aggressive" part, but the "Can Move" and "Can Attack" is just stupid" - Poki#3
-			sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE, 0, 60000);
+			sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE|MD_ANGRY, 0, 60000);
 	}
 
 	return (md)?md->bl.id : 0; // id of last spawned mob
@@ -547,7 +546,7 @@ static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr dat
 				md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
 				guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
 			}
-			unit_free(&md->bl,0); //Remove guardian.
+			unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian.
 		}
 		return 0;
 	}
@@ -795,7 +794,7 @@ int mob_setdelayspawn(struct mob_data *md)
 	unsigned int spawntime;
 
 	if (!md->spawn) //Doesn't has respawn data!
-		return unit_free(&md->bl,1);
+		return unit_free(&md->bl,CLR_DEAD);
 
 	spawntime = md->spawn->delay1; //Base respawn time
 	if (md->spawn->delay2) //random variance
@@ -826,7 +825,7 @@ int mob_spawn (struct mob_data *md)
 
 	md->last_thinktime = tick;
 	if (md->bl.prev != NULL)
-		unit_remove_map(&md->bl,2);
+		unit_remove_map(&md->bl,CLR_RESPAWN);
 	else
 	if (md->spawn && md->class_ != md->spawn->class_)
 	{
@@ -1121,7 +1120,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
 			md->master_dist > MAX_MINCHASE
 		){
 			md->master_dist = 0;
-			unit_warp(&md->bl,bl->m,bl->x,bl->y,3);
+			unit_warp(&md->bl,bl->m,bl->x,bl->y,CLR_TELEPORT);
 			return 1;
 		}
 
@@ -1761,7 +1760,7 @@ int mob_timer_delete(int tid, unsigned int tick, int id, intptr data)
 		}
 		//for Alchemist CANNIBALIZE [Lupus]
 		md->deletetimer = INVALID_TIMER;
-		unit_free(bl, 3);
+		unit_free(bl, CLR_TELEPORT);
 	}
 	return 0;
 }
@@ -1805,7 +1804,7 @@ int mob_respawn(int tid, unsigned int tick, int id, intptr data)
 
 void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
 {
-	int char_id = 0, flag = 0;
+	int char_id = 0, flag = MDLF_NORMAL;
 
 	if( damage < 0 )
 		return; //Do nothing for absorbed damage.
@@ -1827,7 +1826,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
 		case BL_HOM:
 		{
 			struct homun_data *hd = (TBL_HOM*)src;
-			flag = 1;
+			flag = MDLF_HOMUN;
 			if( hd->master )
 				char_id = hd->master->status.char_id;
 			if( damage )
@@ -1846,7 +1845,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
 		case BL_PET:
 		{
 			struct pet_data *pd = (TBL_PET*)src;
-			flag = 2;
+			flag = MDLF_PET;
 			if( pd->msd )
 			{
 				char_id = pd->msd->status.char_id;
@@ -1960,9 +1959,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		unsigned int base_exp,job_exp;
 	} pt[DAMAGELOG_SIZE];
 	int i,temp,count,pnum=0,m=md->bl.m;
+	int dmgbltypes = 0;  // bitfield of all bl types, that caused damage to the mob and are elligible for exp distribution
 	unsigned int mvp_damage, tick = gettick();
-	unsigned short flaghom = 1; // [Zephyrus] Does the mob only received damage from homunculus?
-	bool rebirth;
+	bool rebirth, homkillonly;
 
 	status = &md->status;
 
@@ -2022,9 +2021,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		count++; //Only logged into same map chars are counted for the total.
 		if (pc_isdead(tsd))
 			continue; // skip dead players
-		if(md->dmglog[i].flag == 1 && !merc_is_hom_active(tsd->hd))
+		if(md->dmglog[i].flag == MDLF_HOMUN && !merc_is_hom_active(tsd->hd))
 			continue; // skip homunc's share if inactive
-		if( md->dmglog[i].flag == 2 && (!tsd->status.pet_id || !tsd->pd) )
+		if( md->dmglog[i].flag == MDLF_PET && (!tsd->status.pet_id || !tsd->pd) )
 			continue; // skip pet's share if inactive
 
 		if(md->dmglog[i].dmg > mvp_damage)
@@ -2037,10 +2036,17 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 
 		tmpsd[i] = tsd; // record as valid damage-log entry
 
-		if(!md->dmglog[i].flag == 1 && flaghom)
-			flaghom = 0; // Damage received from other Types != Homunculus
+		switch( md->dmglog[i].flag )
+		{
+			case MDLF_NORMAL: dmgbltypes|= BL_PC;  break;
+			case MDLF_HOMUN:  dmgbltypes|= BL_HOM; break;
+			case MDLF_PET:    dmgbltypes|= BL_PET; break;
+		}
 	}
 
+	// determines, if the monster was killed by homunculus' damage only
+	homkillonly = (bool)( ( dmgbltypes&BL_HOM ) && !( dmgbltypes&~BL_HOM ) );
+
 	if(!battle_config.exp_calc_type && count > 1)
 	{	//Apply first-attacker 200% exp share bonus
 		//TODO: Determine if this should go before calculating the MVP player instead of after.
@@ -2065,9 +2071,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 			temp = status_get_class(&md->bl);
 			if(sd->sc.data[SC_MIRACLE]) i = 2; //All mobs are Star Targets
 			else
-			ARR_FIND(0, 3, i, temp == sd->hate_mob[i] &&
+			ARR_FIND(0, MAX_PC_FEELHATE, i, temp == sd->hate_mob[i] &&
 				(battle_config.allow_skill_without_day || sg_info[i].day_func()));
-			if(i<3 && (temp=pc_checkskill(sd,sg_info[i].bless_id)))
+			if(i<MAX_PC_FEELHATE && (temp=pc_checkskill(sd,sg_info[i].bless_id)))
 				bonus += (i==2?20:10)*temp;
 		}
 		if(battle_config.mobs_level_up && md->level > md->db->lv) // [Valaris]
@@ -2103,7 +2109,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		else if(md->special_state.size==2)
 			per *=2.;
 
-		if( md->dmglog[i].flag == 2 )
+		if( md->dmglog[i].flag == MDLF_PET )
 			per *= battle_config.pet_attack_exp_rate/100.;
 
 		if(battle_config.zeny_from_mobs && md->level) {
@@ -2118,12 +2124,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		else
 			base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map[m].bexp/100., 1, UINT_MAX);
 		
-		if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == 1) //Homun earned job-exp is always lost.
+		if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == MDLF_HOMUN) //Homun earned job-exp is always lost.
 			job_exp = 0; 
 		else
 			job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map[m].jexp/100., 1, UINT_MAX);
  		
-		if((temp = tmpsd[i]->status.party_id )>0 && !md->dmglog[i].flag == 1) //Homun-done damage (flag 1) is not given to party
+		if((temp = tmpsd[i]->status.party_id )>0 && !md->dmglog[i].flag == MDLF_HOMUN) //Homun-done damage (flag 1) is not given to party
 		{
 			int j;
 			for(j=0;j<pnum && pt[j].id!=temp;j++); //Locate party.
@@ -2155,11 +2161,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 			}
 		}
 		if(flag) {
-			if(base_exp && md->dmglog[i].flag == 1) //tmpsd[i] is null if it has no homunc.
+			if(base_exp && md->dmglog[i].flag == MDLF_HOMUN) //tmpsd[i] is null if it has no homunc.
 				merc_hom_gainexp(tmpsd[i]->hd, base_exp);
 			if(base_exp || job_exp)
 			{
-				if( md->dmglog[i].flag != 2 || battle_config.pet_attack_exp_to_master )
+				if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master )
 					pc_gainexp(tmpsd[i], &md->bl, base_exp, job_exp, false);
 			}
 			if(zeny) // zeny from mobs [Valaris]
@@ -2241,13 +2247,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 			}
 			// Announce first, or else ditem will be freed. [Lance]
 			// By popular demand, use base drop rate for autoloot code. [Skotlex]
-			mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, flaghom);
+			mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, homkillonly);
 		}
 
 		// Ore Discovery [Celest]
 		if (sd == mvp_sd && pc_checkskill(sd,BS_FINDINGORE)>0 && battle_config.finding_ore_rate/10 >= rand()%10000) {
 			ditem = mob_setdropitem(itemdb_searchrandomid(IG_FINDINGORE), 1);
-			mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, 0);
+			mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, homkillonly);
 		}
 
 		if(sd) {
@@ -2273,7 +2279,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 					if (rand()%10000 >= drop_rate)
 						continue;
 					itemid = (sd->add_drop[i].id > 0) ? sd->add_drop[i].id : itemdb_searchrandomid(sd->add_drop[i].group);
-					mob_item_drop(md, dlist, mob_setdropitem(itemid,1), 0, drop_rate, 0);
+					mob_item_drop(md, dlist, mob_setdropitem(itemid,1), 0, drop_rate, homkillonly);
 				}
 			}
 			
@@ -2289,7 +2295,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		// process items looted by the mob
 		if(md->lootitem) {
 			for(i = 0; i < md->lootitem_count; i++)
-				mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, 0);
+				mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly);
 		}
 		if (dlist->item) //There are drop items.
 			add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr)dlist);
@@ -2305,7 +2311,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		dlist->third_charid = (third_sd ? third_sd->status.char_id : 0);
 		dlist->item = NULL;
 		for(i = 0; i < md->lootitem_count; i++)
-			mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, 0);
+			mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly);
 		add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr)dlist);
 	}
 
@@ -2406,12 +2412,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		{
 			if( sd && battle_config.mob_npc_event_type )
 			{
-				pc_setglobalreg(sd,"killerrid",sd->bl.id);
+				pc_setparam(sd, SP_KILLERRID, sd->bl.id);
 				npc_event(sd,md->npc_event,0);
 			}
 			else if( mvp_sd )
 			{
-				pc_setglobalreg(mvp_sd,"killerrid",sd?sd->bl.id:0);
+				pc_setparam(mvp_sd, SP_KILLERRID, sd?sd->bl.id:0);
 				npc_event(mvp_sd,md->npc_event,0);
 			}
 			else
@@ -2419,7 +2425,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		}
 		else if( mvp_sd && !md->state.npc_killmonster )
 		{
-			pc_setglobalreg(mvp_sd,"killedrid",md->class_);
+			pc_setparam(mvp_sd, SP_KILLEDRID, md->class_);
 			npc_script_event(mvp_sd, NPCE_KILLNPC); // PCKillNPC [Lance]
 		}
 		
@@ -2491,7 +2497,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
 				md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
 				guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
 			}
-			unit_free(&md->bl,0); //Remove guardian.
+			unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian.
 		}
 		return 0;
 	}
@@ -2505,7 +2511,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
 			md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
 			guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
 		}
-		unit_free(&md->bl,0);
+		unit_free(&md->bl,CLR_OUTSIGHT);
 		return 0;
 	}
 
@@ -2631,7 +2637,7 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap)
 		return 0;
 
 	map_search_freecell(master, 0, &x, &y, range, range, 0);
-	unit_warp(&md->bl, master->m, x, y,2);
+	unit_warp(&md->bl, master->m, x, y,CLR_RESPAWN);
 	return 1;
 }
 
@@ -3409,9 +3415,7 @@ static bool mob_parse_dbrow(char** str)
 	double exp, maxhp;
 	struct mob_data data;
 	
-	class_ = str[0] ? atoi(str[0]) : 0;
-	if (class_ == 0)
-		return false; //Leave blank lines alone... [Skotlex]
+	class_ = atoi(str[0]);
 	
 	if (class_ <= 1000 || class_ > MAX_MOB_DB) {
 		ShowWarning("Mob with ID: %d not loaded. ID must be in range [%d-%d]\n", class_, 1000, MAX_MOB_DB);
@@ -3552,7 +3556,7 @@ static bool mob_parse_dbrow(char** str)
 		//calculate and store Max available drop chance of the MVP item
 		if (db->mvpitem[i].p) {
 			id = itemdb_search(db->mvpitem[i].nameid);
-			if (id->maxchance == 10000 || (id->maxchance < db->mvpitem[i].p/10 + 1) ) {
+			if (id->maxchance == -1 || (id->maxchance < db->mvpitem[i].p/10 + 1) ) {
 				//item has bigger drop chance or sold in shops
 				id->maxchance = db->mvpitem[i].p/10 + 1; //reduce MVP drop info to not spoil common drop rate
 			}
@@ -3585,6 +3589,7 @@ static bool mob_parse_dbrow(char** str)
 			ratemax = battle_config.item_drop_heal_max;
 			break;
 		case IT_USABLE:
+		case IT_CASH:
 			rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_use_boss : battle_config.item_rate_use;
 			ratemin = battle_config.item_drop_use_min;
 			ratemax = battle_config.item_drop_use_max;
@@ -3613,7 +3618,7 @@ static bool mob_parse_dbrow(char** str)
 		if( db->dropitem[i].p && (class_ < 1324 || class_ > 1363) && (class_ < 1938 || class_ > 1946) )
 		{ //Skip treasure chests.
 			id = itemdb_search(db->dropitem[i].nameid);
-			if (id->maxchance == 10000 || (id->maxchance < db->dropitem[i].p) ) {
+			if (id->maxchance == -1 || (id->maxchance < db->dropitem[i].p) ) {
 				id->maxchance = db->dropitem[i].p; //item has bigger drop chance or sold in shops
 			}
 			for (k = 0; k< MAX_SEARCH; k++) {
@@ -3636,61 +3641,31 @@ static bool mob_parse_dbrow(char** str)
 /*==========================================
  * mob_db.txt reading
  *------------------------------------------*/
-static int mob_readdb(void)
+static bool mob_readdb_sub(char* fields[], int columns, int current)
+{
+	return mob_parse_dbrow(fields);
+}
+
+static void mob_readdb(void)
 {
 	const char* filename[] = { "mob_db.txt", "mob_db2.txt" };
 	int fi;
 	
 	for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
 	{
-		uint32 lines = 0, count = 0;
-		char line[1024];
 		char path[256];
-		FILE* fp;
-		
-		sprintf(path, "%s/%s", db_path, filename[fi]);
-		fp = fopen(path, "r");
-		if(fp == NULL) {
-			if(fi > 0)
-				continue;
-			return -1;
-		}
-		
-		// process rows one by one
-		while(fgets(line, sizeof(line), fp))
+
+		if(fi > 0)
 		{
-			char *str[38+2*MAX_MOB_DROP], *p, *np;
-			int i;
-			
-			lines++;
-			if(line[0] == '/' && line[1] == '/')
-				continue;
-			
-			for(i = 0, p = line; i < 38 + 2*MAX_MOB_DROP; i++)
+			sprintf(path, "%s/%s", db_path, filename[fi]);
+			if(!exists(path))
 			{
-				str[i] = p;
-				if((np = strchr(p, ',')) != NULL) {
-					*np = '\0'; p = np + 1;
-				}
-			}
-			
-			if(i < 38 + 2*MAX_MOB_DROP) {
-				ShowWarning("mob_readdb: Insufficient columns for mob with id: %d, skipping.\n", atoi(str[0]));
 				continue;
 			}
-			
-			if (!mob_parse_dbrow(str))
-				continue;
-			
-			count++;
 		}
 
-		fclose(fp);
-
-		ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename[fi]);
+		sv_readdb(db_path, filename[fi], ',', 38+2*MAX_MOB_DROP, 38+2*MAX_MOB_DROP, -1, &mob_readdb_sub);
 	}
-
-	return 0;
 }
 
 #ifndef TXT_ONLY
@@ -3753,73 +3728,42 @@ static int mob_read_sqldb(void)
 /*==========================================
  * MOB display graphic change data reading
  *------------------------------------------*/
-static int mob_readdb_mobavail(void)
+static bool mob_readdb_mobavail(char* str[], int columns, int current)
 {
-	FILE *fp;
-	char line[1024];
-	int ln=0;
-	int class_,j,k;
-	char *str[20],*p,*np;
+	int class_, k;
 
-	sprintf(line, "%s/mob_avail.txt", db_path);
-	if( (fp=fopen(line,"r"))==NULL ){
-		ShowError("can't read %s\n", line);
-		return -1;
-	}
+	class_=atoi(str[0]);
 
-	while(fgets(line, sizeof(line), fp))
+	if(mob_db(class_) == mob_dummy)	// �l���ُ�Ȃ珈�����Ȃ��B
 	{
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		memset(str,0,sizeof(str));
-
-		for(j=0,p=line;j<12;j++){
-			if((np=strchr(p,','))!=NULL){
-				str[j]=p;
-				*np=0;
-				p=np+1;
-			} else
-				str[j]=p;
-		}
-
-		if(str[0]==NULL)
-			continue;
-
-		class_=atoi(str[0]);
-		if (class_ == 0)
-			continue; //Leave blank lines alone... [Skotlex]
-		
-		if(mob_db(class_) == mob_dummy)	// �l���ُ�Ȃ珈�����Ȃ��B
-			continue;
-
-		k=atoi(str[1]);
-		if(k < 0)
-			continue;
-
-		memset(&mob_db_data[class_]->vd, 0, sizeof(struct view_data));
-		mob_db_data[class_]->vd.class_=k;
-
-		//Player sprites
-		if(pcdb_checkid(k) && j>=12) {
-			mob_db_data[class_]->vd.sex=atoi(str[2]);
-			mob_db_data[class_]->vd.hair_style=atoi(str[3]);
-			mob_db_data[class_]->vd.hair_color=atoi(str[4]);
-			mob_db_data[class_]->vd.weapon=atoi(str[5]);
-			mob_db_data[class_]->vd.shield=atoi(str[6]);
-			mob_db_data[class_]->vd.head_top=atoi(str[7]);
-			mob_db_data[class_]->vd.head_mid=atoi(str[8]);
-			mob_db_data[class_]->vd.head_bottom=atoi(str[9]);
-			mob_db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
-			mob_db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
-		}
-		else if(str[2] && atoi(str[2]) > 0)
-			mob_db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
+		ShowWarning("mob_readdb_mobavail: Unknown mob id %d.\n", class_);
+		return false;
+	}
 
-		ln++;
+	k=atoi(str[1]);
+
+	memset(&mob_db_data[class_]->vd, 0, sizeof(struct view_data));
+	mob_db_data[class_]->vd.class_=k;
+
+	//Player sprites
+	if(pcdb_checkid(k) && columns==12) {
+		mob_db_data[class_]->vd.sex=atoi(str[2]);
+		mob_db_data[class_]->vd.hair_style=atoi(str[3]);
+		mob_db_data[class_]->vd.hair_color=atoi(str[4]);
+		mob_db_data[class_]->vd.weapon=atoi(str[5]);
+		mob_db_data[class_]->vd.shield=atoi(str[6]);
+		mob_db_data[class_]->vd.head_top=atoi(str[7]);
+		mob_db_data[class_]->vd.head_mid=atoi(str[8]);
+		mob_db_data[class_]->vd.head_bottom=atoi(str[9]);
+		mob_db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
+		mob_db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
 	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"mob_avail.txt");
-	return 0;
+	else if(columns==3)
+		mob_db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
+	else if( columns != 2 )
+		return false;
+
+	return true;
 }
 
 /*==========================================
@@ -3842,7 +3786,7 @@ static int mob_read_randommonster(void)
 
 	for( i = 0; i < ARRAYLENGTH(mobfile) && i < MAX_RANDOMMONSTER; i++ )
 	{
-		mob_db_data[0]->summonper[i] = 1002;	// �ݒ肵�Y�ꂽ�ꍇ�̓|�������o��悤�ɂ��Ă���
+		mob_db_data[0]->summonper[i] = 1002;	// Default fallback value, in case the database does not provide one
 		sprintf(line, "%s/%s", db_path, mobfile[i]);
 		fp=fopen(line,"r");
 		if(fp==NULL){
@@ -3894,8 +3838,10 @@ static int mob_read_randommonster(void)
  *------------------------------------------*/
 static bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_msg_id)
 {
+	char* msg;
 	struct mob_chat *ms;
 	int msg_id;
+	size_t len;
 
 	msg_id = atoi(str[0]);
 
@@ -3917,13 +3863,29 @@ static bool mob_parse_row_chatdb(char** str, const char* source, int line, int*
 	//Color
 	ms->color=strtoul(str[1],NULL,0);
 	//Message
-	if(strlen(str[2])>(CHAT_SIZE_MAX-1)){
+	msg = str[2];
+	len = strlen(msg);
+
+	while( len && ( msg[len-1]=='\r' || msg[len-1]=='\n' ) )
+	{// find EOL to strip
+		len--;
+	}
+
+	if(len>(CHAT_SIZE_MAX-1))
+	{
 		if (msg_id != *last_msg_id) {
 			ShowError("mob_chat: readdb: Message too long! Line %d, id: %d\n", line, msg_id);
 			*last_msg_id = msg_id;
 		}
 		return false;
 	}
+	else if( !len )
+	{
+		ShowWarning("mob_parse_row_chatdb: Empty message for id %d.\n", msg_id);
+		return false;
+	}
+
+	msg[len] = 0;  // strip previously found EOL
 	strncpy(ms->msg, str[2], CHAT_SIZE_MAX);
 
 	return true;
@@ -3987,9 +3949,8 @@ static void mob_readchatdb(void)
 
 /*==========================================
  * processes one mob_skill_db entry
- * @param last_mob_id ensures that only one error message per mob id is printed
  *------------------------------------------*/
-static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, int* last_mob_id)
+static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
 {
 	static const struct {
 		char str[32];
@@ -4058,6 +4019,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 		{	"around4",	MST_AROUND4	},
 		{	"around",	MST_AROUND	},
 	};
+	static int last_mob_id = 0;  // ensures that only one error message per mob id is printed
 
 	struct mob_skill *ms, gms;
 	int mob_id;
@@ -4067,9 +4029,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 
 	if (mob_id > 0 && mob_db(mob_id) == mob_dummy)
 	{
-		if (mob_id != *last_mob_id) {
-			ShowError("mob_skill: Non existant Mob id %d at %s, line %d\n", mob_id, source, line);
-			*last_mob_id = mob_id;
+		if (mob_id != last_mob_id) {
+			ShowError("mob_parse_row_mobskilldb: Non existant Mob id %d\n", mob_id);
+			last_mob_id = mob_id;
 		}
 		return false;
 	}
@@ -4089,9 +4051,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 		ARR_FIND( 0, MAX_MOBSKILL, i, (ms = &mob_db_data[mob_id]->skill[i])->skill_id == 0 );
 		if( i == MAX_MOBSKILL )
 		{
-			if (mob_id != *last_mob_id) {
-				ShowError("mob_skill: readdb: too many skills! Line %d in %d[%s]\n", line, mob_id, mob_db_data[mob_id]->sprite);
-				*last_mob_id = mob_id;
+			if (mob_id != last_mob_id) {
+				ShowError("mob_parse_row_mobskilldb: Too many skills for monster %d[%s]\n", mob_id, mob_db_data[mob_id]->sprite);
+				last_mob_id = mob_id;
 			}
 			return false;
 		}
@@ -4102,7 +4064,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 	if( j < ARRAYLENGTH(state) )
 		ms->state = state[j].id;
 	else {
-		ShowWarning("mob_skill: Unrecognized state %s at %s, line %d\n", str[2], source, line);
+		ShowWarning("mob_parse_row_mobskilldb: Unrecognized state %s\n", str[2]);
 		ms->state = MSS_ANY;
 	}
 
@@ -4111,9 +4073,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 	if (j<=0 || j>MAX_SKILL_DB) //fixed Lupus
 	{
 		if (mob_id < 0)
-			ShowError("Invalid Skill ID (%d) for all mobs\n", j);
+			ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for all mobs\n", j);
 		else
-			ShowError("Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite);
+			ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite);
 		return false;
 	}
 	ms->skill_id=j;
@@ -4146,7 +4108,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 	if( j < ARRAYLENGTH(target) )
 		ms->target = target[j].id;
 	else {
-		ShowWarning("mob_skill: Unrecognized target %s at %s, line %d\n", str[9], source, line);
+		ShowWarning("mob_parse_row_mobskilldb: Unrecognized target %s for %d\n", str[9], mob_id);
 		ms->target = MST_TARGET;
 	}
 
@@ -4155,13 +4117,13 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 	{	//Ground skill.
 		if (ms->target > MST_AROUND)
 		{
-			ShowWarning("Wrong mob skill target for ground skill %d (%s) for %s.\n",
+			ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target for ground skill %d (%s) for %s.\n",
 				ms->skill_id, skill_get_name(ms->skill_id),
 				mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite);
 			ms->target = MST_TARGET;
 		}
 	} else if (ms->target > MST_MASTER) {
-		ShowWarning("Wrong mob skill target 'around' for non-ground skill %d (%s) for %s\n.",
+		ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target 'around' for non-ground skill %d (%s) for %s\n.",
 			ms->skill_id, skill_get_name(ms->skill_id),
 			mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite);
 		ms->target = MST_TARGET;
@@ -4172,7 +4134,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 	if( j < ARRAYLENGTH(cond1) )
 		ms->cond1 = cond1[j].id;
 	else {
-		ShowWarning("mob_skill: Unrecognized condition 1 %s at %s, line %d\n", str[10], source, line);
+		ShowWarning("mob_parse_row_mobskilldb: Unrecognized condition 1 %s for %d\n", str[10], mob_id);
 		ms->cond1 = -1;
 	}
 
@@ -4246,7 +4208,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
 /*==========================================
  * mob_skill_db.txt reading
  *------------------------------------------*/
-static int mob_readskilldb(void)
+static void mob_readskilldb(void)
 {
 	const char* filename[] = { "mob_skill_db.txt", "mob_skill_db2.txt" };
 	int fi;
@@ -4254,130 +4216,72 @@ static int mob_readskilldb(void)
 	if( battle_config.mob_skill_rate == 0 )
 	{
 		ShowStatus("Mob skill use disabled. Not reading mob skills.\n");
-		return 0;
+		return;
 	}
 
 	for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
 	{
-		uint32 lines = 0, count = 0;
-		char line[1024];
-		int i;
-		int tmp = 0;
-
 		char path[256];
-		FILE *fp;
-
-		sprintf(path, "%s/%s", db_path, filename[fi]); 
-		fp = fopen(path, "r");
-		if( fp == NULL )
-		{
-			ShowWarning("mob_readskilldb: File not found \"%s\", skipping.\n", path);
-			continue;
-		}
 
-		// process rows one by one
-		while(fgets(line, sizeof(line), fp))
+		if(fi > 0)
 		{
-			char *str[20], *p, *np;
-			int j=0;
-
-			lines++;
-			if(line[0] == '/' && line[1] == '/')
-				continue;
-			memset(str, 0, sizeof(str));
-
-			p = line;
-			while( ISSPACE(*p) )
-				++p;
-			if( *p == '\0' )
-				continue;// empty line
-			for(i = 0; i < 19; i++)
+			sprintf(path, "%s/%s", db_path, filename[fi]);
+			if(!exists(path))
 			{
-				str[i] = p;
-				if((np = strchr(p, ',')) != NULL) {
-					*np = '\0'; p = np + 1; j++;
-				}
-			}
-			
-			if ( j < 18 || str[18]==NULL )
-			{
-				ShowError("mob_readskilldb: Insufficient number of fields for skill at %s, line %d\n", filename[fi], lines);
 				continue;
 			}
-
-			if( !mob_parse_row_mobskilldb(str, path, lines, &tmp) )
-				continue;
-
-			count++;
 		}
-		fclose(fp);
-		ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", filename[fi]);
+
+		sv_readdb(db_path, filename[fi], ',', 19, 19, -1, &mob_parse_row_mobskilldb);
 	}
-	return 0;
 }
 /*==========================================
- * mob_race_db.txt reading
+ * mob_race2_db.txt reading
  *------------------------------------------*/
-static int mob_readdb_race(void)
+static bool mob_readdb_race2(char* fields[], int columns, int current)
 {
-	FILE *fp;
-	char line[1024];
-	int race,j,k;
-	char *str[20],*p,*np;
+	int race, mobid, i;
 
-	sprintf(line, "%s/mob_race2_db.txt", db_path);
-	if( (fp=fopen(line,"r"))==NULL ){
-		ShowError("can't read %s\n", line);
-		return -1;
-	}
-	
-	while(fgets(line, sizeof(line), fp))
-	{
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		memset(str,0,sizeof(str));
+	race = atoi(fields[0]);
 
-		for(j=0,p=line;j<12;j++){
-			if((np=strchr(p,','))!=NULL){
-				str[j]=p;
-				*np=0;
-				p=np+1;
-			} else
-				str[j]=p;
-		}
-		if(str[0]==NULL)
-			continue;
+	if (race < RC2_NONE || race >= RC2_MAX)
+	{
+		ShowWarning("mob_readdb_race2: Unknown race2 %d.\n", race);
+		return false;
+	}
 
-		race=atoi(str[0]);
-		if (race < RC2_NONE || race >= RC2_MAX)
+	for(i = 1; i<columns; i++)
+	{
+		mobid = atoi(fields[i]);
+		if (mob_db(mobid) == mob_dummy)
+		{
+			ShowWarning("mob_readdb_race2: Unknown mob id %d for race2 %d.\n", mobid, race);
 			continue;
-
-		for (j=1; j<20; j++) {
-			if (!str[j])
-				break;
-			k=atoi(str[j]);
-			if (mob_db(k) == mob_dummy)
-				continue;
-			mob_db_data[k]->race2 = race;
 		}
+		mob_db_data[mobid]->race2 = race;
 	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","mob_race2_db.txt");
-	return 0;
+	return true;
 }
 
-void mob_reload(void)
+static void mob_load(void)
 {
-	int i;
 #ifndef TXT_ONLY
-    if(db_use_sqldbs)
-        mob_read_sqldb();
-    else
+	if(db_use_sqldbs)
+		mob_read_sqldb();
+	else
 #endif /* TXT_ONLY */
 	mob_readdb();
 
-	mob_readdb_mobavail();
+	sv_readdb(db_path, "mob_avail.txt", ',', 2, 12, -1, &mob_readdb_mobavail);
 	mob_read_randommonster();
+	mob_readchatdb();
+	mob_readskilldb();
+	sv_readdb(db_path, "mob_race2_db.txt", ',', 2, 20, -1, &mob_readdb_race2);
+}
+
+void mob_reload(void)
+{
+	int i;
 
 	//Mob skills need to be cleared before re-reading them. [Skotlex]
 	for (i = 0; i < MAX_MOB_DB; i++)
@@ -4386,9 +4290,8 @@ void mob_reload(void)
 			memset(&mob_db_data[i]->skill,0,sizeof(mob_db_data[i]->skill));
 			mob_db_data[i]->maxskill=0;
 		}
-	mob_readchatdb();
-	mob_readskilldb();
-	mob_readdb_race();
+
+	mob_load();
 }
 
 void mob_clear_spawninfo()
@@ -4410,18 +4313,7 @@ int do_init_mob(void)
 	item_drop_ers = ers_new(sizeof(struct item_drop));
 	item_drop_list_ers = ers_new(sizeof(struct item_drop_list));
 
-#ifndef TXT_ONLY
-    if(db_use_sqldbs)
-        mob_read_sqldb();
-    else
-#endif /* TXT_ONLY */
-        mob_readdb();
-
-	mob_readdb_mobavail();
-	mob_read_randommonster();
-	mob_readchatdb();
-	mob_readskilldb();
-	mob_readdb_race();
+	mob_load();
 
 	add_timer_func_list(mob_delayspawn,"mob_delayspawn");
 	add_timer_func_list(mob_delay_item_drop,"mob_delay_item_drop");
diff --git a/src/map/mob.h b/src/map/mob.h
index e8bd0a837..ce896646c 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -55,6 +55,13 @@ enum MobSkillState {
 	MSS_ANYTARGET,
 };
 
+enum MobDamageLogFlag
+{
+	MDLF_NORMAL = 0,
+	MDLF_HOMUN,
+	MDLF_PET,
+};
+
 struct mob_skill {
 	enum MobSkillState state;
 	short skill_id,skill_lv;
diff --git a/src/map/npc.c b/src/map/npc.c
index dcfa52193..4b188c177 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -176,7 +176,7 @@ int npc_enable(const char* name, int flag)
 	if (nd->class_ == WARP_CLASS || nd->class_ == FLAG_CLASS)
 	{	//Client won't display option changes for these classes [Toms]
 		if (nd->sc.option&(OPTION_HIDE|OPTION_INVISIBLE))
-			clif_clearunit_area(&nd->bl, 0);
+			clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);
 		else
 			clif_spawn(&nd->bl);
 	} else
@@ -206,7 +206,7 @@ int npc_event_dequeue(struct map_session_data* sd)
 	if(sd->npc_id)
 	{	//Current script is aborted.
 		if(sd->state.using_fake_npc){
-			clif_clearunit_single(sd->npc_id, 0, sd->fd);
+			clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
 			sd->state.using_fake_npc = 0;
 		}
 		if (sd->st) {
@@ -866,7 +866,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int m, int x, int y)
 		case WARP:
 			if( pc_ishiding(sd) )
 				break; // hidden chars cannot use warps
-			pc_setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,0);
+			pc_setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,CLR_OUTSIGHT);
 			break;
 		case SCRIPT:
 			if( npc_ontouch_event(sd,map[m].npc[i]) > 0 && npc_ontouch2_event(sd,map[m].npc[i]) > 0 )
@@ -923,7 +923,7 @@ int npc_touch_areanpc2(struct mob_data *md)
 					xs = map_mapindex2mapid(map[m].npc[i]->u.warp.mapindex);
 					if( m < 0 )
 						break; // Cannot Warp between map servers
-					if( unit_warp(&md->bl, xs, map[m].npc[i]->u.warp.x, map[m].npc[i]->u.warp.y, 0) == 0 )
+					if( unit_warp(&md->bl, xs, map[m].npc[i]->u.warp.x, map[m].npc[i]->u.warp.y, CLR_OUTSIGHT) == 0 )
 						return 1; // Warped
 					break;
 				case SCRIPT:
@@ -1142,14 +1142,24 @@ static int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* i
 {
 	char npc_ev[NAME_LENGTH*2+3];
 	int i;
-	int regkey = add_str("@bought_nameid");
-	int regkey2 = add_str("@bought_quantity");
-	snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnBuyItem", nd->exname);
-	for(i=0;i<n;i++){
-		pc_setreg(sd,regkey+(i<<24),(int)item_list[i*2+1]);
-		pc_setreg(sd,regkey2+(i<<24),(int)item_list[i*2]);
+	int key_nameid = 0;
+	int key_amount = 0;
+
+	// discard old contents
+	script_cleararray_pc(sd, "@bought_nameid", (void*)0);
+	script_cleararray_pc(sd, "@bought_quantity", (void*)0);
+
+	// save list of bought items
+	for( i = 0; i < n; i++ )
+	{
+		script_setarray_pc(sd, "@bought_nameid", i, (void*)(intptr)item_list[i*2+1], &key_nameid);
+		script_setarray_pc(sd, "@bought_quantity", i, (void*)(intptr)item_list[i*2], &key_amount);
 	}
+
+	// invoke event
+	snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnBuyItem", nd->exname);
 	npc_event(sd, npc_ev, 0);
+
 	return 0;
 }
 /*==========================================
@@ -1251,8 +1261,6 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 	nd = npc_checknear(sd,map_id2bl(sd->npc_shopid));
 	if( nd == NULL )
 		return 3;
-	if( nd->master_nd != NULL ) //Script-based shops.
-		return npc_buylist_sub(sd,n,item_list,nd->master_nd);
 	if( nd->subtype != SHOP )
 		return 3;
 
@@ -1287,6 +1295,11 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 			amount = item_list[i*2+0] = 1;
 		}
 
+		if( nd->master_nd )
+		{// Script-controlled shops decide by themselves, what can be bought and for what price.
+			continue;
+		}
+
 		switch( pc_checkadditem(sd,nameid,amount) )
 		{
 			case ADDITEM_EXIST:
@@ -1300,13 +1313,15 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 				return 2;
 		}
 
-		if( !itemdb_value_notdc(nameid) )
-			value = pc_modifybuyvalue(sd,value);
+		value = pc_modifybuyvalue(sd,value);
 
 		z += (double)value * amount;
 		w += itemdb_weight(nameid) * amount;
 	}
 
+	if( nd->master_nd != NULL ) //Script-based shops.
+		return npc_buylist_sub(sd,n,item_list,nd->master_nd);
+
 	if( z > (double)sd->status.zeny )
 		return 1;	// Not enough Zeny
 	if( w + sd->weight > sd->max_weight )
@@ -1356,90 +1371,139 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 	return 0;
 }
 
-/*==========================================
- *
- *------------------------------------------*/
+
+/// npc_selllist for script-controlled shops
+static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd)
+{
+	char npc_ev[NAME_LENGTH*2+3];
+	int i, idx;
+	int key_nameid = 0;
+	int key_amount = 0;
+
+	// discard old contents
+	script_cleararray_pc(sd, "@sold_nameid", (void*)0);
+	script_cleararray_pc(sd, "@sold_quantity", (void*)0);
+
+	// save list of to be sold items
+	for( i = 0; i < n; i++ )
+	{
+		idx = item_list[i*2]-2;
+
+		script_setarray_pc(sd, "@sold_nameid", i, (void*)(intptr)sd->status.inventory[idx].nameid, &key_nameid);
+		script_setarray_pc(sd, "@sold_quantity", i, (void*)(intptr)item_list[i*2+1], &key_amount);
+	}
+
+	// invoke event
+	snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnSellItem", nd->exname);
+	npc_event(sd, npc_ev, 0);
+	return 0;
+}
+
+
+/// Player item selling to npc shop.
+///
+/// @param item_list 'n' pairs <index,amount>
+/// @return result code for clif_parse_NpcSellListSend
 int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
 {
 	double z;
 	int i,skill;
 	struct npc_data *nd;
-	
+
 	nullpo_retr(1, sd);
 	nullpo_retr(1, item_list);
 
-	if ((nd = npc_checknear(sd,map_id2bl(sd->npc_shopid))) == NULL)
+	if( ( nd = npc_checknear(sd, map_id2bl(sd->npc_shopid)) ) == NULL || nd->subtype != SHOP )
+	{
 		return 1;
-	nd = nd->master_nd; //For OnSell triggers.
+	}
 
-	for(i=0,z=0;i<n;i++) {
-		int nameid, idx;
-		short qty;
-		idx = item_list[i*2]-2;
-		qty = (short)item_list[i*2+1];
-		
-		if (idx <0 || idx >=MAX_INVENTORY || qty < 0)
-			break;
-		
-		nameid=sd->status.inventory[idx].nameid;
-		if (nameid == 0 || !sd->inventory_data[idx] ||
-		   sd->status.inventory[idx].amount < qty)
-			break;
-		
-		if (sd->inventory_data[idx]->flag.value_notoc)
-			z+=(double)qty*sd->inventory_data[idx]->value_sell;
-		else
-			z+=(double)qty*pc_modifysellvalue(sd,sd->inventory_data[idx]->value_sell);
+	z = 0;
+
+	// verify the sell list
+	for( i = 0; i < n; i++ )
+	{
+		int nameid, amount, idx, value;
+
+		idx    = item_list[i*2]-2;
+		amount = item_list[i*2+1];
 
-		if(sd->inventory_data[idx]->type == IT_PETEGG &&
-			sd->status.inventory[idx].card[0] == CARD0_PET)
+		if( idx >= MAX_INVENTORY || idx < 0 || amount < 0 )
 		{
-			if(search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0)
-				intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1],sd->status.inventory[idx].card[2]));
+			return 1;
+		}
+
+		nameid = sd->status.inventory[idx].nameid;
+
+		if( !nameid || !sd->inventory_data[idx] || sd->status.inventory[idx].amount < amount )
+		{
+			return 1;
 		}
 
-		if(log_config.enable_logs&0x20) //Logs items, Sold to NPC (S)hop [Lupus]
-			log_pick_pc(sd, "S", nameid, -qty, &sd->status.inventory[idx]);
+		if( nd->master_nd )
+		{// Script-controlled shops decide by themselves, what can be sold and at what price.
+			continue;
+		}
+
+		value = pc_modifysellvalue(sd, sd->inventory_data[idx]->value_sell);
+
+		z+= (double)value*amount;
+	}
+
+	if( nd->master_nd )
+	{// Script-controlled shops
+		return npc_selllist_sub(sd, n, item_list, nd->master_nd);
+	}
+
+	// delete items
+	for( i = 0; i < n; i++ )
+	{
+		int nameid, amount, idx;
+
+		idx    = item_list[i*2]-2;
+		amount = item_list[i*2+1];
+		nameid = sd->status.inventory[idx].nameid;
+
+		//Logs items, Sold to NPC (S)hop [Lupus]
+		if( log_config.enable_logs&0x20 )
+			log_pick_pc(sd, "S", nameid, -amount, &sd->status.inventory[idx]);
+		//Logs
 
-		if(nd) {
-			pc_setreg(sd,add_str("@sold_nameid")+(i<<24),(int)sd->status.inventory[idx].nameid);
-			pc_setreg(sd,add_str("@sold_quantity")+(i<<24),qty);
+		if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET )
+		{
+			if( search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0 )
+			{
+				intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+			}
 		}
-		pc_delitem(sd,idx,qty,0,6);
+
+		pc_delitem(sd, idx, amount, 0, 6);
 	}
 
-	if (z > MAX_ZENY) z = MAX_ZENY;
+	if( z > MAX_ZENY )
+		z = MAX_ZENY;
 
-	if(log_config.zeny) //Logs (S)hopping Zeny [Lupus]
+	//Logs (S)hopping Zeny [Lupus]
+	if( log_config.zeny )
 		log_zeny(sd, "S", sd, (int)z);
+	//Logs
 
-	pc_getzeny(sd,(int)z);
-	
-	if (battle_config.shop_exp > 0 && z > 0 && (skill = pc_checkskill(sd,MC_OVERCHARGE)) > 0) {
-		if (sd->status.skill[MC_OVERCHARGE].flag != 0)
+	pc_getzeny(sd, (int)z);
+
+	// custom merchant shop exp bonus
+	if( battle_config.shop_exp > 0 && z > 0 && ( skill = pc_checkskill(sd,MC_OVERCHARGE) ) > 0)
+	{
+		if( sd->status.skill[MC_OVERCHARGE].flag != 0 )
 			skill = sd->status.skill[MC_OVERCHARGE].flag - 2;
-		if (skill > 0) {
+		if( skill > 0 )
+		{
 			z = z * (double)skill * (double)battle_config.shop_exp/10000.;
-			if (z < 1)
+			if( z < 1 )
 				z = 1;
-			pc_gainexp(sd,NULL,0,(int)z, false);
+			pc_gainexp(sd, NULL, 0, (int)z, false);
 		}
 	}
-		
-	if(nd) {
-		char npc_ev[NAME_LENGTH*2+3];
-		snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnSellItem", nd->exname);
-		npc_event(sd, npc_ev, 0);
-	}
-	
-	if (i<n) {
-		//Error/Exploit... of some sort. If we return 1, the client will not mark
-		//any item as deleted even though a few were sold. In such a case, we
-		//have no recourse but to kick them out so their inventory will refresh
-		//correctly on relog. [Skotlex]
-		if (i) set_eof(sd->fd);
-		return 1;
-	}
+
 	return 0;
 }
 
@@ -1451,7 +1515,7 @@ int npc_remove_map(struct npc_data* nd)
 	if(nd->bl.prev == NULL || nd->bl.m < 0)
 		return 1; //Not assigned to a map.
   	m = nd->bl.m;
-	clif_clearunit_area(&nd->bl,2);
+	clif_clearunit_area(&nd->bl,CLR_RESPAWN);
 	npc_unsetcells(nd);
 	map_delblock(&nd->bl);
 	//Remove npc from map[].npc list. [Skotlex]
@@ -1875,8 +1939,8 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
 				id->name, nameid, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer));
 		}
 		//for logs filters, atcommands and iteminfo script command
-		if( id->maxchance <= 0 )
-			id->maxchance = 10000; //10000 (100% drop chance)would show that the item's sold in NPC Shop
+		if( id->maxchance == 0 )
+			id->maxchance = -1; // -1 would show that the item's sold in NPC Shop
 
 		items[i].nameid = nameid;
 		items[i].value = value;
@@ -2550,7 +2614,7 @@ void npc_setclass(struct npc_data* nd, short class_)
 	if( nd->class_ == class_ )
 		return;
 
-	clif_clearunit_area(&nd->bl, 0);// fade out
+	clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);// fade out
 	nd->class_ = class_;
 	status_set_viewdata(&nd->bl, class_);
 	clif_spawn(&nd->bl);// fade in
@@ -3129,7 +3193,12 @@ void npc_parsesrcfile(const char* filepath)
 			{// Incorrect map, we must skip the script info...
 				ShowError("npc_parsesrcfile: Unknown map '%s' in file '%s', line '%d'. Skipping line...\n", mapname, filepath, strline(buffer,p-buffer));
 				if( strcasecmp(w2,"script") == 0 && count > 3 )
-					p = npc_skip_script(p,buffer,filepath);
+				{
+					if((p = npc_skip_script(p,buffer,filepath)) == NULL)
+					{
+						break;
+					}
+				}
 				p = strchr(p,'\n');// next line
 				continue;
 			}
@@ -3137,7 +3206,12 @@ void npc_parsesrcfile(const char* filepath)
 			if( m < 0 )
 			{// "mapname" is not assigned to this server, we must skip the script info...
 				if( strcasecmp(w2,"script") == 0 && count > 3 )
-					p = npc_skip_script(p,buffer,filepath);
+				{
+					if((p = npc_skip_script(p,buffer,filepath)) == NULL)
+					{
+						break;
+					}
+				}
 				p = strchr(p,'\n');// next line
 				continue;
 			}
@@ -3270,7 +3344,7 @@ int npc_reload(void)
 				npc_unload((struct npc_data *)bl);
 			break;
 		case BL_MOB:
-			unit_free(bl,0);
+			unit_free(bl,CLR_OUTSIGHT);
 			break;
 		}
 	}
@@ -3304,6 +3378,9 @@ int npc_reload(void)
 	npc_warp = npc_shop = npc_script = 0;
 	npc_mob = npc_cache_mob = npc_delay_mob = 0;
 
+	// reset mapflags
+	map_flags_init();
+
 	//TODO: the following code is copy-pasted from do_init_npc(); clean it up
 	// Reloading npcs now
 	for (nsl = npc_src_files; nsl; nsl = nsl->next)
@@ -3350,7 +3427,7 @@ int do_final_npc(void)
 			if (bl->type == BL_NPC)
 				npc_unload((struct npc_data *)bl);
 			else if (bl->type&(BL_MOB|BL_PET|BL_HOM|BL_MER))
-				unit_free(bl, 0);
+				unit_free(bl, CLR_OUTSIGHT);
 		}
 	}
 
diff --git a/src/map/party.c b/src/map/party.c
index e6a7ffd8b..407221cde 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -30,8 +30,9 @@
 
 static DBMap* party_db; // int party_id -> struct party_data*
 static DBMap* party_booking_db; // Party Booking [Spiria]
+static unsigned long party_booking_nextid = 1;
+
 int party_send_xy_timer(int tid, unsigned int tick, int id, intptr data);
-bool check_party_leader(struct map_session_data *sd, struct party_data *p); // Party Booking [Spiria]
 
 /*==========================================
  * Fills the given party_member structure according to the sd provided. 
@@ -515,11 +516,6 @@ int party_leave(struct map_session_data *sd)
 	if( i == MAX_PARTY )
 		return 0;
 
-	if( check_party_leader(sd, p) ){ // when party leader leaves party, cancel booking.
-		party_booking_delete(sd,true);
-		clif_PartyBookingDeleteAck(sd,0);
-	}
-
 	intif_party_leave(p->party.party_id,sd->status.account_id,sd->status.char_id);
 	return 1;
 }
@@ -665,8 +661,6 @@ bool party_changeleader(struct map_session_data *sd, struct map_session_data *ts
 	//Update info.
 	intif_party_leaderchange(p->party.party_id,p->party.member[tmi].account_id,p->party.member[tmi].char_id);
 	clif_party_info(p,NULL);
-	party_booking_delete(sd, true); // Party Booking [Spiria]
-	clif_PartyBookingDeleteAck(sd, 0); // Close small window
 	return true;
 }
 
@@ -1070,52 +1064,25 @@ int party_foreachsamemap(int (*func)(struct block_list*,va_list),struct map_sess
  * Party Booking in KRO [Spiria]
  *------------------------------------------*/
 
-static struct party_booking_ad_info* create_party_booking_data(int party_id)
+static struct party_booking_ad_info* create_party_booking_data(void)
 {
 	struct party_booking_ad_info *pb_ad;
 	CREATE(pb_ad, struct party_booking_ad_info, 1);
-	pb_ad->index = party_id;
+	pb_ad->index = party_booking_nextid++;
 	return pb_ad;
 }
 
-struct party_booking_ad_info* party_booking_getdata(unsigned long index)
-{
-	struct party_booking_ad_info *pb_ad;
-	pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, index);
-	return pb_ad;
-}
-
-bool check_party_leader(struct map_session_data *sd, struct party_data *p)
-{
-	int i;
-
-	if (!sd || !sd->status.party_id) return false;
-
-	if( p == NULL ) return false;
-
-	ARR_FIND(0, MAX_PARTY, i, p->party.member[i].leader && p->party.member[i].online && p->data[i].sd == sd);
-	if(i == MAX_PARTY) return false;
-
-	return true;
-}
-
 void party_booking_register(struct map_session_data *sd, short level, short mapid, short* job)
 {
 	struct party_booking_ad_info *pb_ad;
-	struct party_data *p=party_search(sd->status.party_id);
 	int i;
 
-	if (!check_party_leader(sd, p)) {
-		clif_PartyBookingRegisterAck(sd, 1);
-		return;
-	}
-	
-	pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, p->party.party_id);
+	pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id);
 
 	if( pb_ad == NULL )
 	{
-		pb_ad = create_party_booking_data(p->party.party_id);
-		idb_put(party_booking_db, pb_ad->index, pb_ad);
+		pb_ad = create_party_booking_data();
+		idb_put(party_booking_db, sd->status.char_id, pb_ad);
 	}
 	
 	memcpy(pb_ad->charname,sd->status.name,NAME_LENGTH);
@@ -1123,84 +1090,80 @@ void party_booking_register(struct map_session_data *sd, short level, short mapi
 	pb_ad->p_detail.level = level;
 	pb_ad->p_detail.mapid = mapid;
 
-	for(i=0;i<6;i++)
+	for(i=0;i<PARTY_BOOKING_JOBS;i++)
 		if(job[i] != 0xFF)
 			pb_ad->p_detail.job[i] = job[i];
 		else pb_ad->p_detail.job[i] = -1;
 
 	clif_PartyBookingRegisterAck(sd, 0);
 	clif_PartyBookingInsertNotify(sd, pb_ad); // Notice
-	clif_PartyBookingSearchAck(sd->fd, &pb_ad->index, 1, false); // Update Client!
-	return;
 }
 
 void party_booking_update(struct map_session_data *sd, short* job)
 {
 	int i;
-	struct party_data *p=party_search(sd->status.party_id);
 	struct party_booking_ad_info *pb_ad;
 
-	if (!check_party_leader(sd, p)) {
-		return;
-	}
-
-	pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, p->party.party_id);
+	pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id);
 	
 	if( pb_ad == NULL )
 		return;
 	
 	pb_ad->starttime = (int)time(NULL);// Update time.
 
-	for(i=0;i<6;i++)
+	for(i=0;i<PARTY_BOOKING_JOBS;i++)
 		if(job[i] != 0xFF)
 			pb_ad->p_detail.job[i] = job[i];
 		else pb_ad->p_detail.job[i] = -1;
 
 	clif_PartyBookingUpdateNotify(sd, pb_ad);
-	return;
 }
 
 void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount)
 {
 	struct party_booking_ad_info *pb_ad;
 	int i, count=0;
-	unsigned long index_list[10];
+	struct party_booking_ad_info* result_list[PARTY_BOOKING_RESULTS];
 	bool more_result = false;
 	DBIterator* iter = party_booking_db->iterator(party_booking_db);
 	
-	memset(index_list, 0, sizeof(index_list));
+	memset(result_list, 0, sizeof(result_list));
 	
 	for( pb_ad = (struct party_booking_ad_info*)iter->first(iter,NULL);	iter->exists(iter);	pb_ad = (struct party_booking_ad_info*)iter->next(iter,NULL) )
 	{
-		if (pb_ad->index < lastindex || (pb_ad->p_detail.level < level || pb_ad->p_detail.level-15 > level))
+		if (pb_ad->index < lastindex || (level && (pb_ad->p_detail.level < level-15 || pb_ad->p_detail.level > level)))
 			continue;
-		if (count >= 10){
+		if (count >= PARTY_BOOKING_RESULTS){
 			more_result = true;
 			break;
 		}
 		if (mapid == 0 && job == -1)
-			index_list[count] = pb_ad->index;
+			result_list[count] = pb_ad;
 		else if (mapid == 0) {
-			for(i=0; i<6; i++)
+			for(i=0; i<PARTY_BOOKING_JOBS; i++)
 				if (pb_ad->p_detail.job[i] == job && job != -1)
-					index_list[count] = pb_ad->index;
+					result_list[count] = pb_ad;
 		} else if (job == -1){
 			if (pb_ad->p_detail.mapid == mapid)
-				index_list[count] = pb_ad->index;
+				result_list[count] = pb_ad;
+		}
+		if( result_list[count] )
+		{
+			count++;
 		}
-		count++;
 	}
 	iter->destroy(iter);
-	clif_PartyBookingSearchAck(sd->fd, index_list, count, more_result);
+	clif_PartyBookingSearchAck(sd->fd, result_list, count, more_result);
 }
 
-bool party_booking_delete(struct map_session_data *sd, bool force_delete)
+bool party_booking_delete(struct map_session_data *sd)
 {
-	struct party_data *p=party_search(sd->status.party_id);
-	if (!check_party_leader(sd, p) && !force_delete) {
-		return false;
+	struct party_booking_ad_info* pb_ad;
+
+	if((pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id))!=NULL)
+	{
+		clif_PartyBookingDeleteNotify(sd, pb_ad->index);
+		idb_remove(party_booking_db,sd->status.char_id);
 	}
-	clif_PartyBookingDeleteNotify(sd, sd->status.party_id);
-	idb_remove(party_booking_db,sd->status.party_id);
 	return true;
 }
diff --git a/src/map/party.h b/src/map/party.h
index d396d0fe6..31e46f5ec 100644
--- a/src/map/party.h
+++ b/src/map/party.h
@@ -12,6 +12,9 @@ struct item;
 
 #include <stdarg.h>
 
+#define PARTY_BOOKING_JOBS 6
+#define PARTY_BOOKING_RESULTS 10
+
 struct party_member_data {
 	struct map_session_data *sd;
 	unsigned int hp; //For HP,x,y refreshing.
@@ -34,7 +37,7 @@ struct party_data {
 struct party_booking_detail {
 	short level;
     short mapid;
-    short job[6];
+    short job[PARTY_BOOKING_JOBS];
 };
 
 struct party_booking_ad_info {
@@ -83,10 +86,9 @@ int party_foreachsamemap(int (*func)(struct block_list *,va_list),struct map_ses
 /*==========================================
  * Party Booking in KRO [Spiria]
  *------------------------------------------*/
-struct party_booking_ad_info* party_booking_getdata(unsigned long index);
 void party_booking_register(struct map_session_data *sd, short level, short mapid, short* job);
 void party_booking_update(struct map_session_data *sd, short* job);
 void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount);
-bool party_booking_delete(struct map_session_data *sd, bool force_delete);
+bool party_booking_delete(struct map_session_data *sd);
 
 #endif /* _PARTY_H_ */
diff --git a/src/map/path.c b/src/map/path.c
index e2e3ae44b..bbbb99a08 100644
--- a/src/map/path.c
+++ b/src/map/path.c
@@ -345,7 +345,7 @@ bool path_search(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1,int
 	xs = md->xs-1; // ���炩���߂P���Z���Ă���
 	ys = md->ys-1;
 
-	while(1)
+	for(;;)
 	{
 		int e=0,f=0,dist,cost,dc[4]={0,0,0,0};
 
diff --git a/src/map/pc.c b/src/map/pc.c
index 7ad0ecfe4..94121eba9 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -61,15 +61,13 @@ struct fame_list taekwon_fame_list[MAX_FAME_LIST];
 static unsigned short equip_pos[EQI_MAX]={EQP_ACC_L,EQP_ACC_R,EQP_SHOES,EQP_GARMENT,EQP_HEAD_LOW,EQP_HEAD_MID,EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_AMMO};
 
 #define MOTD_LINE_SIZE 128
-char motd_text[MOTD_LINE_SIZE][256]; // Message of the day buffer [Valaris]
+static char motd_text[MOTD_LINE_SIZE][CHAT_SIZE_MAX]; // Message of the day buffer [Valaris]
 
 struct duel duel_list[MAX_DUEL];
 int duel_count = 0;
 
-extern int item_delays; // [Paradox924X]
-
 //Links related info to the sd->hate_mob[]/sd->feel_map[] entries
-const struct sg_data sg_info[3] = {
+const struct sg_data sg_info[MAX_PC_FEELHATE] = {
 		{ SG_SUN_ANGER, SG_SUN_BLESS, SG_SUN_COMFORT, "PC_FEEL_SUN", "PC_HATE_MOB_SUN", is_day_of_sun },
 		{ SG_MOON_ANGER, SG_MOON_BLESS, SG_MOON_COMFORT, "PC_FEEL_MOON", "PC_HATE_MOB_MOON", is_day_of_moon },
 		{ SG_STAR_ANGER, SG_STAR_BLESS, SG_STAR_COMFORT, "PC_FEEL_STAR", "PC_HATE_MOB_STAR", is_day_of_star }
@@ -532,11 +530,6 @@ int pc_setinventorydata(struct map_session_data *sd)
 	for(i=0;i<MAX_INVENTORY;i++) {
 		id = sd->status.inventory[i].nameid;
 		sd->inventory_data[i] = id?itemdb_search(id):NULL;
-		if(sd->inventory_data[i] && sd->inventory_data[i]->delay > 0) { // Load delays
-			sd->item_delay[item_delays].nameid = sd->inventory_data[i]->nameid;
-			sd->item_delay[item_delays].tick = 0;
-			++item_delays;
-		}
 	}
 	return 0;
 }
@@ -612,7 +605,7 @@ int pc_setequipindex(struct map_session_data *sd)
 
 			if( sd->status.inventory[i].equip & EQP_HAND_L )
 			{
-				if( sd->inventory_data[i] && sd->inventory_data[i]->type == 4 )
+				if( sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON )
 					sd->weapontype2 = sd->inventory_data[i]->look;
 				else
 					sd->weapontype2 = 0;
@@ -847,6 +840,23 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
 		sd->class_ = MAPID_NOVICE;
 	} else
 		sd->class_ = i; 
+
+	// Checks and fixes to character status data, that are required
+	// in case of configuration change or stuff, which cannot be
+	// checked on char-server.
+	if( sd->status.hair < MIN_HAIR_STYLE || sd->status.hair > MAX_HAIR_STYLE )
+	{
+		sd->status.hair = MIN_HAIR_STYLE;
+	}
+	if( sd->status.hair_color < MIN_HAIR_COLOR || sd->status.hair_color > MAX_HAIR_COLOR )
+	{
+		sd->status.hair_color = MIN_HAIR_COLOR;
+	}
+	if( sd->status.clothes_color < MIN_CLOTH_COLOR || sd->status.clothes_color > MAX_CLOTH_COLOR )
+	{
+		sd->status.clothes_color = MIN_CLOTH_COLOR;
+	}
+
 	//Initializations to null/0 unneeded since map_session_data was filled with 0 upon allocation.
 	if(!sd->status.hp) pc_setdead(sd);
 	sd->state.connect_new = 1;
@@ -910,11 +920,11 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
 		sd->hate_mob[i] = -1;
 
 	// �ʒu�̐ݒ�
-	if ((i=pc_setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, 0)) != 0) {
+	if ((i=pc_setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != 0) {
 		ShowError ("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i);
 
 		// try warping to a default map instead (church graveyard)
-		if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, 0) != 0) {
+		if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) {
 			// if we fail again
 			clif_authfail_fd(sd->fd, 0);
 			return false;
@@ -1037,7 +1047,7 @@ int pc_reg_received(struct map_session_data *sd)
 	}
 
 	//SG map and mob read [Komurka]
-	for(i=0;i<3;i++) //for now - someone need to make reading from txt/sql
+	for(i=0;i<MAX_PC_FEELHATE;i++) //for now - someone need to make reading from txt/sql
 	{
 		if ((j = pc_readglobalreg(sd,sg_info[i].feel_var))!=0) {
 			sd->feel_map[i].index = j;
@@ -1206,7 +1216,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
 
 			f = 1;
 			if(!battle_config.skillfree) {
-				for(j = 0; j < 5; j++) {
+				for(j = 0; j < MAX_PC_SKILL_REQUIRE; j++) {
 					if((k=skill_tree[c][i].need[j].id))
 					{
 						if (!sd->status.skill[k].id || sd->status.skill[k].flag == 13)
@@ -1303,7 +1313,7 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill)
 			if( sd->status.skill[id].id ) //Already learned
 				continue;
 			
-			for( j = 0; j < 5; j++ )
+			for( j = 0; j < MAX_PC_SKILL_REQUIRE; j++ )
 			{
 				if( (k = skill_tree[c][i].need[j].id) )
 				{
@@ -1439,7 +1449,7 @@ int pc_disguise(struct map_session_data *sd, int class_)
 
 	if (sd->bl.prev != NULL) {
 		pc_stop_walking(sd, 0);
-		clif_clearunit_area(&sd->bl, 0);
+		clif_clearunit_area(&sd->bl, CLR_OUTSIGHT);
 	}
 
 	if (!class_) {
@@ -1507,13 +1517,7 @@ static int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short
 
 	for( i = 0; i < max && spell[i].id; i++ )  
 	{  
-		if( spell[i].flag == src_skill && spell[i].id == id && spell[i].lv == lv && (spell[i].card_id == card_id || spell[i].rate <= 0 || rate < 0) )  
-		{  
-			if( !battle_config.autospell_stacking && spell[i].rate > 0 && rate > 0 )
-				return 0;
-			rate += spell[i].rate;
-			break; 
-		}  
+		;  // each autospell works independently
 	}
 
 	if( i == max )
@@ -2358,6 +2362,10 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
 		if(sd->state.lr_flag != 2)
 			sd->add_heal2_rate += val;
 		break;
+	case SP_ADD_ITEM_HEAL_RATE:
+		if(sd->state.lr_flag != 2)
+			sd->itemhealrate2 += val;
+		break;
 	default:
 		ShowWarning("pc_bonus: unknown type %d %d !\n",type,val);
 		break;
@@ -3195,6 +3203,9 @@ int pc_checkadditem(struct map_session_data *sd,int nameid,int amount)
 
 	nullpo_ret(sd);
 
+	if(amount > MAX_AMOUNT)
+		return ADDITEM_OVERAMOUNT;
+
 	if(!itemdb_isstackable(nameid))
 		return ADDITEM_NEW;
 
@@ -3206,8 +3217,6 @@ int pc_checkadditem(struct map_session_data *sd,int nameid,int amount)
 		}
 	}
 
-	if(amount > MAX_AMOUNT)
-		return ADDITEM_OVERAMOUNT;
 	return ADDITEM_NEW;
 }
 
@@ -3536,7 +3545,7 @@ int pc_isUseitem(struct map_session_data *sd,int n)
 	if( item == NULL )
 		return 0;
 	//Not consumable item
-	if( item->type != IT_HEALING && item->type != IT_USABLE )
+	if( item->type != IT_HEALING && item->type != IT_USABLE && item->type != IT_CASH )
 		return 0;
 	if( !item->script ) //if it has no script, you can't really consume it!
 		return 0;
@@ -3662,7 +3671,7 @@ int pc_isUseitem(struct map_session_data *sd,int n)
  *------------------------------------------*/
 int pc_useitem(struct map_session_data *sd,int n)
 {
-	unsigned int delay, tick = gettick();
+	unsigned int tick = gettick();
 	int amount, i, nameid;
 	struct script_code *script;
 
@@ -3691,13 +3700,6 @@ int pc_useitem(struct map_session_data *sd,int n)
 
 	// Store information for later use before it is lost (via pc_delitem) [Paradox924X]
 	nameid = sd->inventory_data[n]->nameid;
-	delay = sd->inventory_data[n]->delay;
-
-	if( sd->inventory_data[n]->delay > 0 ) { // Check if there is a delay on this item [Paradox924X]
-		ARR_FIND(0, item_delays, i, sd->item_delay[i].nameid == nameid);
-		if( i < item_delays && DIFF_TICK(sd->item_delay[i].tick, tick) > 0 )
-			return 0; // Delay has not expired yet
-	}
 
 	//Since most delay-consume items involve using a "skill-type" target cursor,
 	//perform a skill-use check before going through. [Skotlex]
@@ -3706,6 +3708,27 @@ int pc_useitem(struct map_session_data *sd,int n)
 	if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != -1 /*|| !status_check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) )
 		return 0;
 
+	if( sd->inventory_data[n]->delay > 0 ) { // Check if there is a delay on this item [Paradox924X]
+		ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid || !sd->item_delay[i].nameid);
+		if( i < MAX_ITEMDELAYS )
+		{
+			if( sd->item_delay[i].nameid )
+			{// found
+				if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 )
+					return 0; // Delay has not expired yet
+			}
+			else
+			{// not yet used item (all slots are initially empty)
+				sd->item_delay[i].nameid = nameid;
+			}
+			sd->item_delay[i].tick = tick + sd->inventory_data[n]->delay;
+		}
+		else
+		{// should not happen
+			ShowError("pc_useitem: Exceeded item delay array capacity! (nameid=%d, char_id=%d)\n", nameid, sd->status.char_id);
+		}
+	}
+
 	sd->itemid = sd->status.inventory[n].nameid;
 	sd->itemindex = n;
 	if(sd->catch_target_class != -1) //Abort pet catching.
@@ -3741,10 +3764,8 @@ int pc_useitem(struct map_session_data *sd,int n)
 
 	//Update item use time.
 	sd->canuseitem_tick = tick + battle_config.item_use_interval;
-	if( itemdb_iscashfood(sd->status.inventory[n].nameid) )
+	if( itemdb_iscashfood(nameid) )
 		sd->canusecashfood_tick = tick + battle_config.cashfood_use_interval;
-	if( delay > 0 && i < item_delays )
-		sd->item_delay[i].tick = tick + delay;
 
 	run_script(script,0,sd->bl.id,fake_nd->bl.id);
 	potion_flag = 0;
@@ -4038,7 +4059,7 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target)
  * 1 - Invalid map index.
  * 2 - Map not in this map-server, and failed to locate alternate map-server.
  *------------------------------------------*/
-int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, uint8 clrtype)
+int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype)
 {
 	struct party_data *p;
 	int m;
@@ -4196,7 +4217,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
 /*==========================================
  * PC�̃����_����?�v
  *------------------------------------------*/
-int pc_randomwarp(struct map_session_data *sd, int type)
+int pc_randomwarp(struct map_session_data *sd, clr_type type)
 {
 	int x,y,i=0;
 	int m;
@@ -4219,6 +4240,45 @@ int pc_randomwarp(struct map_session_data *sd, int type)
 	return 0;
 }
 
+
+/// Warps one player to another.
+/// @param sd player to warp.
+/// @param pl_sd player to warp to.
+int pc_warpto(struct map_session_data* sd, struct map_session_data* pl_sd)
+{
+	if( map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
+	{
+		return -2;
+	}
+
+	if( map[pl_sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
+	{
+		return -3;
+	}
+
+	return pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
+}
+
+
+/// Recalls one player to another.
+/// @param sd player to warp to.
+/// @param pl_sd player to warp.
+int pc_recall(struct map_session_data* sd, struct map_session_data* pl_sd)
+{
+	if( map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
+	{
+		return -2;
+	}
+
+	if( map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
+	{
+		return -3;
+	}
+
+	return pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
+}
+
+
 /*==========================================
  * Records a memo point at sd's current position
  * pos - entry to replace, (-1: shift oldest entry out)
@@ -4704,7 +4764,7 @@ int pc_follow_timer(int tid, unsigned int tick, int id, intptr data)
 			if (!check_distance_bl(&sd->bl, tbl, 5))
 				unit_walktobl(&sd->bl, tbl, 5, 0);
 		} else
-			pc_setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, 3);
+			pc_setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, CLR_TELEPORT);
 	}
 	sd->followtimer = add_timer(
 		tick + 1000,	// increase time a bit to loosen up map's load
@@ -4767,6 +4827,7 @@ int pc_checkbaselevelup(struct map_session_data *sd)
 	
 	clif_updatestatus(sd,SP_STATUSPOINT);
 	clif_updatestatus(sd,SP_BASELEVEL);
+	clif_updatestatus(sd,SP_BASEEXP);
 	clif_updatestatus(sd,SP_NEXTBASEEXP);
 	status_calc_pc(sd,0);
 	status_percent_heal(&sd->bl,100,100);
@@ -4781,7 +4842,7 @@ int pc_checkbaselevelup(struct map_session_data *sd)
 		if (sd->state.snovice_dead_flag)
 			sd->state.snovice_dead_flag = 0; //Reenable steelbody resurrection on dead.
 	} else
-	if((sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON || (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR)
+	if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON )
 	{
 		sc_start(&sd->bl,status_skill2sc(AL_INCAGI),100,10,600000);
 		sc_start(&sd->bl,status_skill2sc(AL_BLESSING),100,10,600000);
@@ -4814,6 +4875,7 @@ int pc_checkjoblevelup(struct map_session_data *sd)
 	} while ((next=pc_nextjobexp(sd)) > 0 && sd->status.job_exp >= next);
 
 	clif_updatestatus(sd,SP_JOBLEVEL);
+	clif_updatestatus(sd,SP_JOBEXP);
 	clif_updatestatus(sd,SP_NEXTJOBEXP);
 	clif_updatestatus(sd,SP_SKILLPOINT);
 	status_calc_pc(sd,0);
@@ -5272,8 +5334,8 @@ int pc_resetlvl(struct map_session_data* sd,int type)
 		sd->status.skill_point=0;
 		sd->status.base_level=1;
 		sd->status.job_level=1;
-		sd->status.base_exp=sd->status.base_exp=0;
-		sd->status.job_exp=sd->status.job_exp=0;
+		sd->status.base_exp=0;
+		sd->status.job_exp=0;
 		if(sd->sc.option !=0)
 			sd->sc.option = 0;
 
@@ -5317,6 +5379,8 @@ int pc_resetlvl(struct map_session_data* sd,int type)
 	clif_updatestatus(sd,SP_BASELEVEL);
 	clif_updatestatus(sd,SP_JOBLEVEL);
 	clif_updatestatus(sd,SP_STATUSPOINT);
+	clif_updatestatus(sd,SP_BASEEXP);
+	clif_updatestatus(sd,SP_JOBEXP);
 	clif_updatestatus(sd,SP_NEXTBASEEXP);
 	clif_updatestatus(sd,SP_NEXTJOBEXP);
 	clif_updatestatus(sd,SP_SKILLPOINT);
@@ -5498,7 +5562,7 @@ int pc_resetfeel(struct map_session_data* sd)
 	int i;
 	nullpo_ret(sd);
 
-	for (i=0; i<3; i++)
+	for (i=0; i<MAX_PC_FEELHATE; i++)
 	{
 		sd->feel_map[i].m = -1;
 		sd->feel_map[i].index = 0;
@@ -5563,7 +5627,7 @@ int pc_skillheal2_bonus(struct map_session_data *sd, int skill_num)
 	return bonus;
 }
 
-void pc_respawn(struct map_session_data* sd, uint8 clrtype)
+void pc_respawn(struct map_session_data* sd, clr_type clrtype)
 {
 	if( !pc_isdead(sd) )
 		return; // not applicable
@@ -5582,7 +5646,7 @@ static int pc_respawn_timer(int tid, unsigned int tick, int id, intptr data)
 	if( sd != NULL )
 	{
 		sd->pvp_point=0;
-		pc_respawn(sd,0);
+		pc_respawn(sd,CLR_OUTSIGHT);
 	}
 
 	return 0;
@@ -5656,7 +5720,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 	}
 
 	pc_setglobalreg(sd,"PC_DIE_COUNTER",sd->die_counter+1);
-	pc_setglobalreg(sd,"killerrid",src?src->id:0);
+	pc_setparam(sd, SP_KILLERRID, src?src->id:0);
 	if( sd->state.bg_id )
 	{
 		struct battleground_data *bg;
@@ -5710,7 +5774,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 	if (src && src->type == BL_PC)
 	{
 		struct map_session_data *ssd = (struct map_session_data *)src;
-		pc_setglobalreg(ssd, "killedrid", sd->bl.id);
+		pc_setparam(ssd, SP_KILLEDRID, sd->bl.id);
 		npc_script_event(ssd, NPCE_KILLPC);
 
 		if (battle_config.pk_mode&2) {
@@ -5966,6 +6030,8 @@ int pc_readparam(struct map_session_data* sd,int type)
 	case SP_KARMA:       val = sd->status.karma; break;
 	case SP_MANNER:      val = sd->status.manner; break;
 	case SP_FAME:        val = sd->status.fame; break;
+	case SP_KILLERRID:   val = sd->killerrid; break;
+	case SP_KILLEDRID:   val = sd->killedrid; break;
 	}
 
 	return val;
@@ -5992,11 +6058,15 @@ int pc_setparam(struct map_session_data *sd,int type,int val)
 		}
 		sd->status.base_level = (unsigned int)val;
 		sd->status.base_exp = 0;
-		clif_updatestatus(sd, SP_BASELEVEL);
+		// clif_updatestatus(sd, SP_BASELEVEL);  // Gets updated at the bottom
 		clif_updatestatus(sd, SP_NEXTBASEEXP);
 		clif_updatestatus(sd, SP_STATUSPOINT);
 		clif_updatestatus(sd, SP_BASEEXP);
 		status_calc_pc(sd, 0);
+		if(sd->status.party_id)
+		{
+			party_send_levelup(sd);
+		}
 		break;
 	case SP_JOBLEVEL:
 		if ((unsigned int)val >= sd->status.job_level) {
@@ -6006,11 +6076,10 @@ int pc_setparam(struct map_session_data *sd,int type,int val)
 		}
 		sd->status.job_level = (unsigned int)val;
 		sd->status.job_exp = 0;
-		clif_updatestatus(sd, SP_JOBLEVEL);
+		// clif_updatestatus(sd, SP_JOBLEVEL);  // Gets updated at the bottom
 		clif_updatestatus(sd, SP_NEXTJOBEXP);
 		clif_updatestatus(sd, SP_JOBEXP);
 		status_calc_pc(sd, 0);
-		clif_updatestatus(sd,type);
 		break;
 	case SP_SKILLPOINT:
 		sd->status.skill_point = val;
@@ -6083,6 +6152,15 @@ int pc_setparam(struct map_session_data *sd,int type,int val)
 	case SP_FAME:
 		sd->status.fame = val;
 		break;
+	case SP_KILLERRID:
+		sd->killerrid = val;
+		return 1;
+	case SP_KILLEDRID:
+		sd->killedrid = val;
+		return 1;
+	default:
+		ShowError("pc_setparam: Attempted to set unknown parameter '%d'.\n", type);
+		return 0;
 	}
 	clif_updatestatus(sd,type);
 
@@ -6122,6 +6200,8 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp)
 		// A potion produced by an Alchemist in the Fame Top 10 gets +50% effect [DracoRPG]
 		if (potion_flag > 1)
 			bonus += bonus*(potion_flag-1)*50/100;
+		//All item bonuses.
+		bonus += sd->itemhealrate2;
 		//Item Group bonuses
 		bonus += bonus*itemdb_group_bonus(sd, itemid)/100;
 		//Individual item bonuses.
@@ -6358,10 +6438,8 @@ int pc_changelook(struct map_session_data *sd,int type,int val)
 
 	switch(type){
 	case LOOK_HAIR:	//Use the battle_config limits! [Skotlex]
-		if (val < battle_config.min_hair_style)
-			val = battle_config.min_hair_style;
-		else if (val > battle_config.max_hair_style)
-			val = battle_config.max_hair_style;
+		val = cap_value(val, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
+
 		if (sd->status.hair != val)
 		{
 			sd->status.hair=val;
@@ -6383,10 +6461,8 @@ int pc_changelook(struct map_session_data *sd,int type,int val)
 		sd->status.head_mid=val;
 		break;
 	case LOOK_HAIR_COLOR:	//Use the battle_config limits! [Skotlex]
-		if (val < battle_config.min_hair_color)
-			val = battle_config.min_hair_color;
-		else if (val > battle_config.max_hair_color)
-			val = battle_config.max_hair_color;
+		val = cap_value(val, MIN_HAIR_COLOR, MAX_HAIR_COLOR);
+
 		if (sd->status.hair_color != val)
 		{
 			sd->status.hair_color=val;
@@ -6396,10 +6472,8 @@ int pc_changelook(struct map_session_data *sd,int type,int val)
 		}
 		break;
 	case LOOK_CLOTHES_COLOR:	//Use the battle_config limits! [Skotlex]
-		if (val < battle_config.min_cloth_color)
-			val = battle_config.min_cloth_color;
-		else if (val > battle_config.max_cloth_color)
-			val = battle_config.max_cloth_color;
+		val = cap_value(val, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
+
 		sd->status.clothes_color=val;
 		break;
 	case LOOK_SHIELD:
@@ -7099,10 +7173,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos)
 		if(id) {
 			if(id->type == IT_WEAPON) {
 				sd->status.shield = 0;
-				if(sd->status.inventory[n].equip == EQP_HAND_L)
-					sd->weapontype2 = id->look;
-				else
-					sd->weapontype2 = 0;
+				sd->weapontype2 = id->look;
 			}
 			else
 			if(id->type == IT_ARMOR) {
@@ -7934,17 +8005,61 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max)
 /*==========================================
  * DB reading.
  * exp.txt        - required experience values
- * job_db1.txt    - weight, hp, sp, aspd
- * job_db2.txt    - job level stat bonuses
  * skill_tree.txt - skill tree for every class
  * attr_fix.txt   - elemental adjustment table
- * size_fix.txt   - size adjustment table for weapons
- * refine_db.txt  - refining data table
+ * statpoint.txt  - status points per base level
  *------------------------------------------*/
+static bool pc_readdb_skilltree(char* fields[], int columns, int current)
+{
+	unsigned char joblv = 0, skilllv;
+	unsigned short skillid;
+	int idx, class_;
+	unsigned int i, offset = 3, skillidx;
+
+	class_  = atoi(fields[0]);
+	skillid = (unsigned short)atoi(fields[1]);
+	skilllv = (unsigned char)atoi(fields[2]);
+
+	if(columns==4+MAX_PC_SKILL_REQUIRE*2)
+	{// job level requirement extra column
+		joblv = (unsigned char)atoi(fields[3]);
+		offset++;
+	}
+
+	if(!pcdb_checkid(class_))
+	{
+		ShowWarning("pc_readdb_skilltree: Invalid job class %d specified.\n", class_);
+		return false;
+	}
+	idx = pc_class2idx(class_);
+
+	//This is to avoid adding two lines for the same skill. [Skotlex]
+	ARR_FIND( 0, MAX_SKILL_TREE, skillidx, skill_tree[idx][skillidx].id == 0 || skill_tree[idx][skillidx].id == skillid );
+	if( skillidx == MAX_SKILL_TREE )
+	{
+		ShowWarning("pc_readdb_skilltree: Unable to load skill %hu into job %d's tree. Maximum number of skills per class has been reached.\n", skillid, class_);
+		return false;
+	}
+	else if(skill_tree[idx][skillidx].id)
+	{
+		ShowNotice("pc_readdb_skilltree: Overwriting skill %hu for job class %d.\n", skillid, class_);
+	}
+
+	skill_tree[idx][skillidx].id    = skillid;
+	skill_tree[idx][skillidx].max   = skilllv;
+	skill_tree[idx][skillidx].joblv = joblv;
+
+	for(i = 0; i < MAX_PC_SKILL_REQUIRE; i++)
+	{
+		skill_tree[idx][skillidx].need[i].id = atoi(fields[i*2+offset]);
+		skill_tree[idx][skillidx].need[i].lv = atoi(fields[i*2+offset+1]);
+	}
+	return true;
+}
+
 int pc_readdb(void)
 {
 	int i,j,k;
-	unsigned int stat;
 	FILE *fp;
 	char line[24000],*p;
 
@@ -8033,53 +8148,7 @@ int pc_readdb(void)
 
 	// �X�L���c��?
 	memset(skill_tree,0,sizeof(skill_tree));
-	sprintf(line, "%s/skill_tree.txt", db_path);
-	fp=fopen(line,"r");
-	if(fp==NULL){
-		ShowError("can't read %s\n", line);
-		return 1;
-	}
-
-	while(fgets(line, sizeof(line), fp))
-	{
-		char *split[50];
-		int f=0, m=3, idx;
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		for(j=0,p=line;j<14 && p;j++){
-			split[j]=p;
-			p=strchr(p,',');
-			if(p) *p++=0;
-		}
-		if(j<13)
-			continue;
-		if (j == 14) {
-			f=1;	// MinJobLvl has been added
-			m++;
-		}
-		// check for bounds [celest]
-		idx = atoi(split[0]);
-		if(!pcdb_checkid(idx))
-			continue;
-		idx = pc_class2idx(idx);
-		k = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex]
-		ARR_FIND( 0, MAX_SKILL_TREE, j, skill_tree[idx][j].id == 0 || skill_tree[idx][j].id == k );
-		if( j == MAX_SKILL_TREE )
-		{
-			ShowWarning("Unable to load skill %d into job %d's tree. Maximum number of skills per class has been reached.\n", k, atoi(split[0]));
-			continue;
-		}
-		skill_tree[idx][j].id=k;
-		skill_tree[idx][j].max=atoi(split[2]);
-		if (f) skill_tree[idx][j].joblv=atoi(split[3]);
-
-		for(k=0;k<5;k++){
-			skill_tree[idx][j].need[k].id=atoi(split[k*2+m]);
-			skill_tree[idx][j].need[k].lv=atoi(split[k*2+m+1]);
-		}
-	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","skill_tree.txt");
+	sv_readdb(db_path, "skill_tree.txt", ',', 3+MAX_PC_SKILL_REQUIRE*2, 4+MAX_PC_SKILL_REQUIRE*2, -1, &pc_readdb_skilltree);
 
 	// ?���C���e?�u��
 	for(i=0;i<4;i++)
@@ -8135,7 +8204,6 @@ int pc_readdb(void)
 	// �X�L���c��?
 	memset(statp,0,sizeof(statp));
 	i=1;
-	stat = 45;	// base points
 	sprintf(line, "%s/statpoint.txt", db_path);
 	fp=fopen(line,"r");
 	if(fp == NULL){
@@ -8144,6 +8212,7 @@ int pc_readdb(void)
 	} else {
 		while(fgets(line, sizeof(line), fp))
 		{
+			int stat;
 			if(line[0]=='/' && line[1]=='/')
 				continue;
 			if ((stat=strtoul(line,NULL,10))<0)
@@ -8157,10 +8226,9 @@ int pc_readdb(void)
 		ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","statpoint.txt");
 	}
 	// generate the remaining parts of the db if necessary
-	for (; i <= MAX_LEVEL; i++) {
-		stat += (i+15)/5;
-		statp[i] = stat;		
-	}
+	statp[0] = 45; // seed value
+	for (; i <= MAX_LEVEL; i++)
+		statp[i] = statp[i-1] + (i-1+15)/5;
 
 	return 0;
 }
@@ -8168,30 +8236,60 @@ int pc_readdb(void)
 // Read MOTD on startup. [Valaris]
 int pc_read_motd(void)
 {
-	FILE *fp;
-	int ln=0,i=0;
+	char* buf, * ptr;
+	unsigned int lines = 0, entries = 0;
+	size_t len;
+	FILE* fp;
+
+	// clear old MOTD
+	memset(motd_text, 0, sizeof(motd_text));
+
+	// read current MOTD
+	if( ( fp = fopen(motd_txt, "r") ) != NULL )
+	{
+		while( entries < MOTD_LINE_SIZE && fgets(motd_text[entries], sizeof(motd_text[entries]), fp) )
+		{
+			lines++;
+
+			buf = motd_text[entries];
 
-	memset(motd_text,0,sizeof(motd_text));
-	if ((fp = fopen(motd_txt, "r")) != NULL) {
-		while ((ln < MOTD_LINE_SIZE) && fgets(motd_text[ln], sizeof(motd_text[ln])-1, fp) != NULL) {
-			if(motd_text[ln][0] == '/' && motd_text[ln][1] == '/')
+			if( buf[0] == '/' && buf[1] == '/' )
+			{
 				continue;
-			for(i=0; motd_text[ln][i]; i++) {
-				if (motd_text[ln][i] == '\r' || motd_text[ln][i]== '\n') {
-					if(i)
-						motd_text[ln][i]=0;
-					else
-						motd_text[ln][0]=' ';
-					ln++;
-					break;
+			}
+
+			len = strlen(buf);
+
+			while( len && ( buf[len-1] == '\r' || buf[len-1] == '\n' ) )
+			{// strip trailing EOL characters
+				len--;
+			}
+
+			if( len )
+			{
+				buf[len] = 0;
+
+				if( ( ptr = strstr(buf, " :") ) != NULL && ptr-buf >= NAME_LENGTH )
+				{// crashes newer clients
+					ShowWarning("Found sequence '"CL_WHITE" :"CL_RESET"' on line '"CL_WHITE"%u"CL_RESET"' in '"CL_WHITE"%s"CL_RESET"'. This can cause newer clients to crash.\n", lines, motd_txt);
 				}
 			}
+			else
+			{// empty line
+				buf[0] = ' ';
+				buf[1] = 0;
+			}
+			entries++;
 		}
 		fclose(fp);
+
+		ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, motd_txt);
 	}
 	else
-		ShowWarning("In function pc_read_motd() -> File '"CL_WHITE"%s"CL_RESET"' not found.\n", motd_txt);
-	
+	{
+		ShowWarning("File '"CL_WHITE"%s"CL_RESET"' not found.\n", motd_txt);
+	}
+
 	return 0;
 }
 
diff --git a/src/map/pc.h b/src/map/pc.h
index 7bf3a050f..2921b4527 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -17,6 +17,8 @@
 #include "mob.h"
 
 #define MAX_PC_BONUS 10
+#define MAX_PC_SKILL_REQUIRE 5
+#define MAX_PC_FEELHATE 3
 
 struct weapon_data {
 	int atkmods[3];
@@ -53,6 +55,7 @@ struct weapon_data {
 
 struct s_autospell {
 	short id, lv, rate, card_id, flag;
+	bool lock;  // bAutoSpellOnSkill: blocks autospell from triggering again, while being executed
 };
 
 struct s_addeffect {
@@ -132,7 +135,6 @@ struct map_session_data {
 		short pmap; // Previous map on Map Change
 		struct guild *gmaster_flag;
 		unsigned int bg_id;
-		unsigned skillonskill : 1;
 		unsigned short user_font;
 		unsigned short autobonus; //flag to indicate if an autobonus is activated. [Inkfish]
 	} state;
@@ -290,6 +292,7 @@ struct map_session_data {
 	int crit_atk_rate;
 	int classchange; // [Valaris]
 	int speed_rate, speed_add_rate, aspd_add;
+	int itemhealrate2; // [Epoque] Increase heal rate of all healing items.
 	unsigned int setitem_hash, setitem_hash2; //Split in 2 because shift operations only work on int ranges. [Skotlex]
 	
 	short splash_range, splash_add_range;
@@ -378,6 +381,8 @@ struct map_session_data {
 	int duel_group; // duel vars [LuzZza]
 	int duel_invite;
 
+	int killerrid, killedrid;
+
 	char away_message[128]; // [LuzZza]
 
 	int cashPoints, kafraPoints;
@@ -543,7 +548,7 @@ bool pc_can_give_items(int level);
 
 int pc_setrestartvalue(struct map_session_data *sd,int type);
 int pc_makesavestatus(struct map_session_data *);
-void pc_respawn(struct map_session_data* sd, uint8 clrtype);
+void pc_respawn(struct map_session_data* sd, clr_type clrtype);
 int pc_setnewpc(struct map_session_data*,int,int,int,unsigned int,int,int);
 bool pc_authok(struct map_session_data* sd, int, time_t, int gmlevel, struct mmo_charstatus* status);
 void pc_authfail(struct map_session_data *);
@@ -564,11 +569,12 @@ int pc_clean_skilltree(struct map_session_data *sd);
 #define pc_checkoverhp(sd) (sd->battle_status.hp == sd->battle_status.max_hp)
 #define pc_checkoversp(sd) (sd->battle_status.sp == sd->battle_status.max_sp)
 
-int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, uint8 clrtype);
+int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype);
 int pc_setsavepoint(struct map_session_data*,short,int,int);
-int pc_randomwarp(struct map_session_data *sd,int type);
+int pc_randomwarp(struct map_session_data *sd,clr_type type);
+int pc_warpto(struct map_session_data* sd, struct map_session_data* pl_sd);
+int pc_recall(struct map_session_data* sd, struct map_session_data* pl_sd);
 int pc_memo(struct map_session_data* sd, int pos);
-int pc_remove_map(struct map_session_data *sd,int clrtype);
 
 int pc_checkadditem(struct map_session_data*,int,int);
 int pc_inventoryblank(struct map_session_data*);
@@ -720,7 +726,7 @@ struct skill_tree_entry {
 	struct {
 		short id;
 		unsigned char lv;
-	} need[5];
+	} need[MAX_PC_SKILL_REQUIRE];
 }; // Celest
 extern struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE];
 
@@ -732,7 +738,7 @@ struct sg_data {
 	char hate_var[NAME_LENGTH];
 	int (*day_func)(void);
 };
-extern const struct sg_data sg_info[3];
+extern const struct sg_data sg_info[MAX_PC_FEELHATE];
 
 void pc_setinvincibletimer(struct map_session_data* sd, int val);
 void pc_delinvincibletimer(struct map_session_data* sd);
diff --git a/src/map/pet.c b/src/map/pet.c
index d02f93446..843f1cc11 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -306,7 +306,7 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd)
 		map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
 	}
 	pd->pet.incuvate = 1;
-	unit_free(&pd->bl,0);
+	unit_free(&pd->bl,CLR_OUTSIGHT);
 
 	status_calc_pc(sd,0);
 	sd->status.pet_id = 0;
@@ -509,7 +509,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id)
 	if (sd->catch_target_class == 0 && !(md->status.mode&MD_BOSS))
 		sd->catch_target_class = md->class_;
 	if(i < 0 || sd->catch_target_class != md->class_) {
-		clif_emotion(&md->bl, 7);	//mob will do /ag if wrong lure is used on them.
+		clif_emotion(&md->bl, E_AG);	//mob will do /ag if wrong lure is used on them.
 		clif_pet_roulette(sd,0);
 		sd->catch_target_class = -1;
 		return 1;
@@ -523,7 +523,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id)
 
 	if(rand()%10000 < pet_catch_rate)
 	{
-		unit_remove_map(&md->bl,0);
+		unit_remove_map(&md->bl,CLR_OUTSIGHT);
 		status_kill(&md->bl);
 		clif_pet_roulette(sd,1);
 		intif_create_pet(sd->status.account_id,sd->status.char_id,pet_db[i].class_,mob_db(pet_db[i].class_)->lv,
@@ -1100,7 +1100,7 @@ int pet_recovery_timer(int tid, unsigned int tick, int id, intptr data)
 		//Detoxify is chosen for now.
 		clif_skill_nodamage(&pd->bl,&sd->bl,TF_DETOXIFY,1,1);
 		status_change_end(&sd->bl,pd->recovery->type,-1);
-		clif_emotion(&pd->bl, 33);
+		clif_emotion(&pd->bl, E_OK);
 	}
 
 	pd->recovery->timer = INVALID_TIMER;
diff --git a/src/map/script.c b/src/map/script.c
index c71debc0d..773f8d6c4 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -67,7 +67,6 @@
 // - 'function FuncName;' function declarations reverting to global functions 
 //   if local label isn't found
 // - join callfunc and callsub's functionality
-// - use script_op2name in the DEBUG_DISASM block
 // - remove dynamic allocation in add_word()
 // - remove GETVALUE / SETVALUE
 // - clean up the set_reg / set_val / setd_sub mess
@@ -160,6 +159,9 @@
 		if( script_hasdata(st,n) ) \
 			(t)=script_getnum(st,n);
 
+/// Maximum amount of elements in script arrays
+#define SCRIPT_MAX_ARRAYSIZE 128
+
 #define SCRIPT_BLOCK_SIZE 512
 enum { LABEL_NEXTLINE=1,LABEL_START };
 
@@ -210,6 +212,7 @@ DBMap* script_get_userfunc_db(){ return userfunc_db; }
 static DBMap* autobonus_db=NULL; // char* script -> char* bytecode
 
 struct Script_Config script_config = {
+	1, // warn_func_mismatch_argtypes
 	1, 65535, 2048, //warn_func_mismatch_paramnum/check_cmdcount/check_gotocount
 	0, INT_MAX, // input_min_value/input_max_value
 	"OnPCDieEvent", //die_event_name
@@ -281,13 +284,11 @@ typedef struct script_function {
 extern script_function buildin_func[];
 
 static struct linkdb_node* sleep_db;// int oid -> struct script_state*
-uint32 crctab[256];
 
 /*==========================================
  * ���[�J���v���g�^�C�v�錾 (�K�v�ȕ��̂�)
  *------------------------------------------*/
 const char* parse_subexpr(const char* p,int limit);
-void push_val(struct script_stack *stack,int type,int val);
 int run_func(struct script_state *st);
 
 enum {
@@ -515,6 +516,44 @@ static void script_reportdata(struct script_data* data)
 	}
 }
 
+
+/// Reports on the console information about the current built-in function.
+static void script_reportfunc(struct script_state* st)
+{
+	int i, params, id;
+	struct script_data* data;
+
+	if( !script_hasdata(st,0) )
+	{// no stack
+		return;
+	}
+
+	data = script_getdata(st,0);
+
+	if( !data_isreference(data) || str_data[reference_getid(data)].type != C_FUNC )
+	{// script currently not executing a built-in function or corrupt stack
+		return;
+	}
+
+	id     = reference_getid(data);
+	params = script_lastdata(st)-1;
+
+	if( params > 0 )
+	{
+		ShowDebug("Function: %s (%d parameter%s):\n", get_str(id), params, ( params == 1 ) ? "" : "s");
+
+		for( i = 2; i <= script_lastdata(st); i++ )
+		{
+			script_reportdata(script_getdata(st,i));
+		}
+	}
+	else
+	{
+		ShowDebug("Function: %s (no parameters)\n", get_str(id));
+	}
+}
+
+
 /*==========================================
  * �G���[���b�Z�[�W�o��
  *------------------------------------------*/
@@ -741,8 +780,8 @@ void set_label(int l,int pos, const char* script_pos)
 {
 	int i,next;
 
-	if(str_data[l].type==C_INT || str_data[l].type==C_PARAM)
-	{	//Prevent overwriting constants values and parameters [Skotlex]
+	if(str_data[l].type==C_INT || str_data[l].type==C_PARAM || str_data[l].type==C_FUNC)
+	{	//Prevent overwriting constants values, parameters and built-in functions [Skotlex]
 		disp_error_message("set_label: invalid label name",script_pos);
 		return;
 	}
@@ -842,7 +881,7 @@ int add_word(const char* p)
 		disp_error_message("script:add_word: invalid word. A word consists of undercores and/or alfanumeric characters, and valid variable prefixes/postfixes.", p);
 
 	// Duplicate the word
-	CREATE(word, char, len+1);
+	word = aMalloc(len+1);
 	memcpy(word, p, len);
 	word[len] = 0;
 	
@@ -1502,7 +1541,7 @@ const char* parse_syntax(const char* p)
 				// function declaration - just register the name
 				int l;
 				l = add_word(func_name);
-				if( str_data[l].type == C_NOP )//## ??? [FlavioJS]
+				if( str_data[l].type == C_NOP )// set type only if the name did not exist before
 					str_data[l].type = C_USERFUNC;
 
 				// if, for , while �̕‚�����
@@ -1528,7 +1567,7 @@ const char* parse_syntax(const char* p)
 
 				// Set the position of the function (label)
 				l=add_word(func_name);
-				if( str_data[l].type == C_NOP )//## ??? [FlavioJS]
+				if( str_data[l].type == C_NOP )// set type only if the name did not exist before
 					str_data[l].type = C_USERFUNC;
 				set_label(l, script_pos, p);
 				if( parse_options&SCRIPT_USE_LABEL_DB )
@@ -2078,54 +2117,30 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
 	{
 		int i = 0,j;
 		while(i < script_pos) {
-			ShowMessage("%06x ",i);
+			c_op op = get_com(script_buf,&i);
+
+			ShowMessage("%06x %s", i, script_op2name(op));
 			j = i;
-			switch(get_com(script_buf,&i)) {
-			case C_EOL:	 printf("C_EOL"); break;
-			case C_INT:	 printf("C_INT %d",get_num(script_buf,&i)); break;
+			switch(op) {
+			case C_INT:
+				ShowMessage(" %d", get_num(script_buf,&i));
+				break;
 			case C_POS:
-				ShowMessage("C_POS  0x%06x",*(int*)(script_buf+i)&0xffffff);
+				ShowMessage(" 0x%06x", *(int*)(script_buf+i)&0xffffff);
 				i += 3;
 				break;
 			case C_NAME:
 				j = (*(int*)(script_buf+i)&0xffffff);
-				ShowMessage("C_NAME %s",j == 0xffffff ? "?? unknown ??" : get_str(j));
+				ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : get_str(j));
 				i += 3;
 				break;
-			case C_ARG:		ShowMessage("C_ARG"); break;
-			case C_FUNC:	ShowMessage("C_FUNC"); break;
-			case C_ADD:	 	ShowMessage("C_ADD"); break;
-			case C_SUB:		ShowMessage("C_SUB"); break;
-			case C_MUL:		ShowMessage("C_MUL"); break;
-			case C_DIV:		ShowMessage("C_DIV"); break;
-			case C_MOD:		ShowMessage("C_MOD"); break;
-			case C_EQ:		ShowMessage("C_EQ"); break;
-			case C_NE:		ShowMessage("C_NE"); break;
-			case C_GT:		ShowMessage("C_GT"); break;
-			case C_GE:		ShowMessage("C_GE"); break;
-			case C_LT:		ShowMessage("C_LT"); break;
-			case C_LE:		ShowMessage("C_LE"); break;
-			case C_AND:		ShowMessage("C_AND"); break;
-			case C_OR:		ShowMessage("C_OR"); break;
-			case C_XOR:		ShowMessage("C_XOR"); break;
-			case C_LAND:	ShowMessage("C_LAND"); break;
-			case C_LOR:		ShowMessage("C_LOR"); break;
-			case C_R_SHIFT:	ShowMessage("C_R_SHIFT"); break;
-			case C_L_SHIFT:	ShowMessage("C_L_SHIFT"); break;
-			case C_NEG:		ShowMessage("C_NEG"); break;
-			case C_NOT:		ShowMessage("C_NOT"); break;
-			case C_LNOT:	ShowMessage("C_LNOT"); break;
-			case C_NOP:		ShowMessage("C_NOP"); break;
-			case C_OP3:		ShowMessage("C_OP3"); break;
 			case C_STR:
 				j = strlen(script_buf + i);
-				ShowMessage("C_STR %s",script_buf + i);
-				i+= j+1;
+				ShowMessage(" %s", script_buf + i);
+				i += j+1;
 				break;
-			default:
-				ShowMessage("unknown");
 			}
-			ShowMessage(CL_CLL "\n");
+			ShowMessage(CL_CLL"\n");
 		}
 	}
 #endif
@@ -2144,6 +2159,7 @@ TBL_PC *script_rid2sd(struct script_state *st)
 	TBL_PC *sd=map_id2sd(st->rid);
 	if(!sd){
 		ShowError("script_rid2sd: fatal error ! player not attached!\n");
+		script_reportfunc(st);
 		script_reportsrc(st);
 		st->state = END;
 	}
@@ -2694,6 +2710,10 @@ struct script_state* script_alloc_state(struct script_code* script, int pos, int
 /// @param st Script state
 void script_free_state(struct script_state* st)
 {
+	if(st->bk_st)
+	{// backup was not restored
+		ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
+	}
 	if( st->sleep.timer != INVALID_TIMER )
 		delete_timer(st->sleep.timer, run_script_timer);
 	script_free_vars(st->stack->var_function);
@@ -2977,6 +2997,94 @@ void op_1(struct script_state* st, int op)
 }
 
 
+/// Checks the type of all arguments passed to a built-in function.
+///
+/// @param st Script state whose stack arguments should be inspected.
+/// @param func Built-in function for which the arguments are intended.
+static void script_check_buildin_argtype(struct script_state* st, int func)
+{
+	char type;
+	int idx, invalid = 0;
+	script_function* sf = &buildin_func[str_data[func].val];
+
+	for( idx = 2; script_hasdata(st, idx); idx++ )
+	{
+		struct script_data* data = script_getdata(st, idx);
+
+		type = sf->arg[idx-2];
+
+		if( type == '?' || type == '*' )
+		{// optional argument or unknown number of optional parameters ( no types are after this )
+			break;
+		}
+		else if( type == 0 )
+		{// more arguments than necessary ( should not happen, as it is checked before )
+			ShowWarning("Found more arguments than necessary.\n");
+			invalid++;
+			break;
+		}
+		else
+		{
+			const char* name = NULL;
+
+			if( data_isreference(data) )
+			{// get name for variables to determine the type they refer to
+				name = reference_getname(data);
+			}
+
+			switch( type )
+			{
+				case 'v':
+					if( !data_isstring(data) && !data_isint(data) && !data_isreference(data) )
+					{// variant
+						ShowWarning("Unexpected type for argument %d. Expected string, number or variable.\n", idx-1);
+						script_reportdata(data);
+						invalid++;
+					}
+					break;
+				case 's':
+					if( !data_isstring(data) && !( data_isreference(data) && is_string_variable(name) ) )
+					{// string
+						ShowWarning("Unexpected type for argument %d. Expected string.\n", idx-1);
+						script_reportdata(data);
+						invalid++;
+					}
+					break;
+				case 'i':
+					if( !data_isint(data) && !( data_isreference(data) && ( reference_toparam(data) || reference_toconstant(data) || !is_string_variable(name) ) ) )
+					{// int ( params and constants are always int )
+						ShowWarning("Unexpected type for argument %d. Expected number.\n", idx-1);
+						script_reportdata(data);
+						invalid++;
+					}
+					break;
+				case 'r':
+					if( !data_isreference(data) )
+					{// variables
+						ShowWarning("Unexpected type for argument %d. Expected variable.\n", idx-1);
+						script_reportdata(data);
+						invalid++;
+					}
+					break;
+				case 'l':
+					if( !data_islabel(data) && !data_isfunclabel(data) )
+					{// label
+						ShowWarning("Unexpected type for argument %d. Expected label.\n", idx-1);
+						script_reportdata(data);
+						invalid++;
+					}
+					break;
+			}
+		}
+	}
+
+	if(invalid)
+	{
+		ShowDebug("Function: %s\n", get_str(func));
+		script_reportsrc(st);
+	}
+}
+
 
 /// Executes a buildin command.
 /// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN>
@@ -3012,6 +3120,11 @@ int run_func(struct script_state *st)
 		return 1;
 	}
 
+	if( script_config.warn_func_mismatch_argtypes )
+	{
+		script_check_buildin_argtype(st, func);
+	}
+
 	if(str_data[func].func){
 		if (str_data[func].func(st)) //Report error
 			script_reportsrc(st);
@@ -3062,8 +3175,6 @@ int run_func(struct script_state *st)
 /*==========================================
  * script execution
  *------------------------------------------*/
-void run_script_main(struct script_state *st);
-
 void run_script(struct script_code *rootscript,int pos,int rid,int oid)
 {
 	struct script_state *st;
@@ -3138,6 +3249,63 @@ int run_script_timer(int tid, unsigned int tick, int id, intptr data)
 	return 0;
 }
 
+/// Detaches script state from possibly attached character and restores it's previous script if any.
+///
+/// @param st Script state to detach.
+/// @param dequeue_event Whether to schedule any queued events, when there was no previous script.
+static void script_detach_state(struct script_state* st, bool dequeue_event)
+{
+	struct map_session_data* sd;
+
+	if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
+	{
+		sd->st = st->bk_st;
+		sd->npc_id = st->bk_npcid;
+
+		if(st->bk_st)
+		{
+			//Remove tag for removal.
+			st->bk_st = NULL;
+			st->bk_npcid = 0;
+		}
+		else if(dequeue_event)
+		{
+			npc_event_dequeue(sd);
+		}
+	}
+	else if(st->bk_st)
+	{// rid was set to 0, before detaching the script state
+		ShowError("script_detach_state: Found previous script state without attached player (rid=%d, oid=%d, state=%d, bk_npcid=%d)\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
+		script_reportsrc(st->bk_st);
+
+		script_free_state(st->bk_st);
+		st->bk_st = NULL;
+	}
+}
+
+/// Attaches script state to possibly attached character and backups it's previous script, if any.
+///
+/// @param st Script state to attach.
+static void script_attach_state(struct script_state* st)
+{
+	struct map_session_data* sd;
+
+	if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
+	{
+		if(st!=sd->st)
+		{
+			if(st->bk_st)
+			{// there is already a backup
+				ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
+			}
+			st->bk_st = sd->st;
+			st->bk_npcid = sd->npc_id;
+		}
+		sd->st = st;
+		sd->npc_id = st->oid;
+	}
+}
+
 /*==========================================
  * �X�N���v�g�̎��s���C������
  *------------------------------------------*/
@@ -3146,22 +3314,10 @@ void run_script_main(struct script_state *st)
 	int cmdcount=script_config.check_cmdcount;
 	int gotocount=script_config.check_gotocount;
 	TBL_PC *sd;
-	//For backing up purposes
-	struct script_state *bk_st = NULL;
-	int bk_npcid = 0;
 	struct script_stack *stack=st->stack;
 	struct npc_data *nd;
 
-	sd = map_id2sd(st->rid);
-
-	if(sd){
-		if(sd->st != st){
-			bk_st = sd->st;
-			bk_npcid = sd->npc_id;
-		}
-		sd->st = st;
-		sd->npc_id = st->oid;
-	}
+	script_attach_state(st);
 
 	nd = map_id2nd(st->oid);
 	if( nd && map[nd->bl.m].instance_id > 0 )
@@ -3260,43 +3416,37 @@ void run_script_main(struct script_state *st)
 
 	if(st->sleep.tick > 0) {
 		//Restore previous script
-		if (sd) {
-			sd->st = bk_st;
-			sd->npc_id = bk_npcid;
-			bk_st = NULL; //Remove tag for removal.
-		}
+		script_detach_state(st, false);
 		//Delay execution
-		sd = map_id2sd(st->rid); // Refresh sd since script might have attached someone while running. [Inkfish]
+		sd = map_id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish]
 		st->sleep.charid = sd?sd->status.char_id:0;
 		st->sleep.timer  = add_timer(gettick()+st->sleep.tick,
 			run_script_timer, st->sleep.charid, (intptr)st);
 		linkdb_insert(&sleep_db, (void*)st->oid, st);
 	}
-	else if(st->state != END && sd){
+	else if(st->state != END && st->rid){
 		//Resume later (st is already attached to player).
-		if(bk_st) {
+		if(st->bk_st) {
 			ShowWarning("Unable to restore stack! Double continuation!\n");
 			//Report BOTH scripts to see if that can help somehow.
 			ShowDebug("Previous script (lost):\n");
-			script_reportsrc(bk_st);
+			script_reportsrc(st->bk_st);
 			ShowDebug("Current script:\n");
 			script_reportsrc(st);
+
+			script_free_state(st->bk_st);
+			st->bk_st = NULL;
 		}
 	} else {
 		//Dispose of script.
-		if (sd)
+		if ((sd = map_id2sd(st->rid))!=NULL)
 		{	//Restore previous stack and save char.
 			if(sd->state.using_fake_npc){
-				clif_clearunit_single(sd->npc_id, 0, sd->fd);
+				clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
 				sd->state.using_fake_npc = 0;
 			}
 			//Restore previous script if any.
-			sd->st = bk_st;
-			sd->npc_id = bk_npcid;
-			if (!bk_st)
-				npc_event_dequeue(sd);
-			else
-				bk_st = NULL; //Remove tag for removal.
+			script_detach_state(st, true);
 			if (sd->state.reg_dirty&2)
 				intif_saveregistry(sd,2);
 			if (sd->state.reg_dirty&1)
@@ -3305,13 +3455,6 @@ void run_script_main(struct script_state *st)
 		script_free_state(st);
 		st = NULL;
 	}
-
-	if (bk_st)
-	{	//Remove previous script
-		script_free_state(bk_st);
-		bk_st = NULL;
-	}
-
 }
 
 int script_config_read(char *cfgName)
@@ -3349,6 +3492,9 @@ int script_config_read(char *cfgName)
 		else if(strcmpi(w1,"input_max_value")==0) {
 			script_config.input_max_value = config_switch(w2);
 		}
+		else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) {
+			script_config.warn_func_mismatch_argtypes = config_switch(w2);
+		}
 		else if(strcmpi(w1,"import")==0){
 			script_config_read(w2);
 		}
@@ -3401,6 +3547,74 @@ void script_add_autobonus(const char *autobonus)
 	}
 }
 
+
+/// resets a temporary character array variable to given value
+void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value)
+{
+	int key;
+	uint8 idx;
+
+	if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
+	{
+		ShowError("script_cleararray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
+		return;
+	}
+
+	key = add_str(varname);
+
+	if( is_string_variable(varname) )
+	{
+		for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
+		{
+			pc_setregstr(sd, reference_uid(key, idx), (const char*)value);
+		}
+	}
+	else
+	{
+		for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
+		{
+			pc_setreg(sd, reference_uid(key, idx), (int)value);
+		}
+	}
+}
+
+
+/// sets a temporary character array variable element idx to given value
+/// @param refcache Pointer to an int variable, which keeps a copy of the reference to varname and must be initialized to 0. Can be NULL if only one element is set.
+void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache)
+{
+	int key;
+
+	if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
+	{
+		ShowError("script_setarray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
+		return;
+	}
+
+	if( idx >= SCRIPT_MAX_ARRAYSIZE )
+	{
+		ShowError("script_setarray_pc: Variable '%s' has invalid index '%d' (char_id=%d).\n", varname, (int)idx, sd->status.char_id);
+		return;
+	}
+
+	key = ( refcache && refcache[0] ) ? refcache[0] : add_str(varname);
+
+	if( is_string_variable(varname) )
+	{
+		pc_setregstr(sd, reference_uid(key, idx), (const char*)value);
+	}
+	else
+	{
+		pc_setreg(sd, reference_uid(key, idx), (int)value);
+	}
+
+	if( refcache )
+	{// save to avoid repeated add_str calls
+		refcache[0] = key;
+	}
+}
+
+
 /*==========================================
  * �I��
  *------------------------------------------*/
@@ -3698,7 +3912,12 @@ BUILDIN_FUNC(menu)
 		sd->state.menu_or_input = 1;
 		clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
 		StringBuf_Destroy(&buf);
-		//TODO what's the maximum number of options that can be displayed and/or received? -> give warning
+
+		if( sd->npc_menu >= 0xff )
+		{// client supports only up to 254 entries; 0 is not used and 255 is reserved for cancel; excess entries are displayed but cause 'uint8' overflow
+			ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
+			script_reportsrc(st);
+		}
 	}
 	else if( sd->npc_menu == 0xff )
 	{// Cancel was pressed
@@ -3780,6 +3999,12 @@ BUILDIN_FUNC(select)
 		sd->state.menu_or_input = 1;
 		clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
 		StringBuf_Destroy(&buf);
+
+		if( sd->npc_menu >= 0xff )
+		{
+			ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
+			script_reportsrc(st);
+		}
 	}
 	else if( sd->npc_menu == 0xff )
 	{// Cancel was pressed
@@ -3842,6 +4067,12 @@ BUILDIN_FUNC(prompt)
 		sd->state.menu_or_input = 1;
 		clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
 		StringBuf_Destroy(&buf);
+
+		if( sd->npc_menu >= 0xff )
+		{
+			ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
+			script_reportsrc(st);
+		}
 	}
 	else if( sd->npc_menu == 0xff )
 	{// Cancel was pressed
@@ -4100,11 +4331,11 @@ BUILDIN_FUNC(warp)
 	y = script_getnum(st,4);
 
 	if(strcmp(str,"Random")==0)
-		ret = pc_randomwarp(sd,3);
+		ret = pc_randomwarp(sd,CLR_TELEPORT);
 	else if(strcmp(str,"SavePoint")==0 || strcmp(str,"Save")==0)
-		ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+		ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
 	else
-		ret = pc_setpos(sd,mapindex_name2id(str),x,y,0);
+		ret = pc_setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT);
 
 	if( ret ) {
 		ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y);
@@ -4124,9 +4355,9 @@ static int buildin_areawarp_sub(struct block_list *bl,va_list ap)
 	x=va_arg(ap,int);
 	y=va_arg(ap,int);
 	if(map == 0)
-		pc_randomwarp((TBL_PC *)bl,3);
+		pc_randomwarp((TBL_PC *)bl,CLR_TELEPORT);
 	else
-		pc_setpos((TBL_PC *)bl,map,x,y,0);
+		pc_setpos((TBL_PC *)bl,map,x,y,CLR_OUTSIGHT);
 	return 0;
 }
 BUILDIN_FUNC(areawarp)
@@ -4212,12 +4443,12 @@ BUILDIN_FUNC(warpchar)
 		return 0;
 
 	if(strcmp(str, "Random") == 0)
-		pc_randomwarp(sd, 3);
+		pc_randomwarp(sd, CLR_TELEPORT);
 	else
 	if(strcmp(str, "SavePoint") == 0)
-		pc_setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, 3);
+		pc_setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
 	else	
-		pc_setpos(sd, mapindex_name2id(str), x, y, 3);
+		pc_setpos(sd, mapindex_name2id(str), x, y, CLR_TELEPORT);
 	
 	return 0;
 } 
@@ -4274,15 +4505,15 @@ BUILDIN_FUNC(warpparty)
 		{
 		case 0: // Random
 			if(!map[pl_sd->bl.m].flag.nowarp)
-				pc_randomwarp(pl_sd,3);
+				pc_randomwarp(pl_sd,CLR_TELEPORT);
 		break;
 		case 1: // SavePointAll
 			if(!map[pl_sd->bl.m].flag.noreturn)
-				pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,3);
+				pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
 		break;
 		case 2: // SavePoint
 			if(!map[pl_sd->bl.m].flag.noreturn)
-				pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+				pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
 		break;
 		case 3: // Leader
 			for(j = 0; j < MAX_PARTY && !p->party.member[j].leader; j++);
@@ -4298,12 +4529,12 @@ BUILDIN_FUNC(warpparty)
 					continue;
 				if(map[pl_sd->bl.m].flag.noreturn || map[pl_sd->bl.m].flag.nowarp)
 					continue;
-				pc_setpos(pl_sd,mapindex,x,y,3);
+				pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
 			}
 		break;
 		case 4: // m,x,y
 			if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp) 
-				pc_setpos(pl_sd,mapindex_name2id(str),x,y,3);
+				pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT);
 		break;
 		}
 	}
@@ -4352,19 +4583,19 @@ BUILDIN_FUNC(warpguild)
 		{
 		case 0: // Random
 			if(!map[pl_sd->bl.m].flag.nowarp)
-				pc_randomwarp(pl_sd,3);
+				pc_randomwarp(pl_sd,CLR_TELEPORT);
 		break;
 		case 1: // SavePointAll
 			if(!map[pl_sd->bl.m].flag.noreturn)
-				pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,3);
+				pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
 		break;
 		case 2: // SavePoint
 			if(!map[pl_sd->bl.m].flag.noreturn)
-				pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+				pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
 		break;
 		case 3: // m,x,y
 			if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
-				pc_setpos(pl_sd,mapindex_name2id(str),x,y,3);
+				pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT);
 		break;
 		}
 	}
@@ -4588,7 +4819,7 @@ static int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isst
 
 	if( isstring )
 	{
-		for( ; idx < 128; ++idx )
+		for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
 		{
 			char* str = (char*)get_val2(st, reference_uid(id, idx), ref);
 			if( str && *str )
@@ -4598,7 +4829,7 @@ static int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isst
 	}
 	else
 	{
-		for( ; idx < 128; ++idx )
+		for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
 		{
 			int32 num = (int32)get_val2(st, reference_uid(id, idx), ref);
 			if( num )
@@ -4651,8 +4882,8 @@ BUILDIN_FUNC(setarray)
 	}
 
 	end = start + script_lastdata(st) - 2;
-	if( end > 127 )
-		end = 127;
+	if( end >= SCRIPT_MAX_ARRAYSIZE )
+		end = SCRIPT_MAX_ARRAYSIZE-1;
 
 	if( is_string_variable(name) )
 	{// string array
@@ -4714,8 +4945,8 @@ BUILDIN_FUNC(cleararray)
 		v = (void*)script_getnum(st, 3);
 
 	end = start + script_getnum(st, 4);
-	if( end > 127 )
-		end = 127;
+	if( end >= SCRIPT_MAX_ARRAYSIZE )
+		end = SCRIPT_MAX_ARRAYSIZE-1;
 
 	for( ; start <= end; ++start )
 		set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2));
@@ -4784,8 +5015,8 @@ BUILDIN_FUNC(copyarray)
 	}
 
 	count = script_getnum(st, 4);
-	if( count > 128 - idx1 )
-		count = 128 - idx1;
+	if( count >= SCRIPT_MAX_ARRAYSIZE - idx1 )
+		count = (SCRIPT_MAX_ARRAYSIZE-1) - idx1;
 	if( count <= 0 || (id1 == id2 && idx1 == idx2) )
 		return 0;// nothing to copy
 
@@ -4802,7 +5033,7 @@ BUILDIN_FUNC(copyarray)
 	{// normal copy
 		for( i = 0; i < count; ++i )
 		{
-			if( idx2 + i < 128 )
+			if( idx2 + i < SCRIPT_MAX_ARRAYSIZE )
 			{
 				v = get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2));
 				set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1));
@@ -4958,7 +5189,7 @@ BUILDIN_FUNC(getelementofarray)
 	}
 
 	i = script_getnum(st, 3);
-	if( i < 0 || i >= 128 )
+	if( i < 0 || i >= SCRIPT_MAX_ARRAYSIZE )
 	{
 		ShowWarning("script:getelementofarray: index out of range (%d)\n", i);
 		script_reportdata(data);
@@ -5154,48 +5385,80 @@ BUILDIN_FUNC(countitem2)
  *------------------------------------------*/
 BUILDIN_FUNC(checkweight)
 {
-	int nameid=0,amount,i;
-	unsigned long weight;
-	TBL_PC *sd;
-	struct script_data *data;
+	int nameid, amount, slots;
+	unsigned int weight;
+	struct item_data* id = NULL;
+	struct map_session_data* sd;
+	struct script_data* data;
 
-	sd = script_rid2sd(st);
-	if( sd == NULL )
+	if( ( sd = script_rid2sd(st) ) == NULL )
+	{
 		return 0;
+	}
 
-	data=script_getdata(st,2);
-	get_val(st,data);
-	if( data_isstring(data) ){
-		const char *name=conv_str(st,data);
-		struct item_data *item_data = itemdb_searchname(name);
-		if( item_data )
-			nameid=item_data->nameid;
-	}else
-		nameid=conv_num(st,data);
+	data = script_getdata(st,2);
+	get_val(st, data);  // convert into value in case of a variable
 
-	amount=script_getnum(st,3);
-	if ( amount<=0 || nameid<500 ) { //if get wrong item ID or amount<=0, don't count weight of non existing items
-		script_pushint(st,0);
-		ShowError("buildin_checkweight: Wrong item ID or amount.\n");
+	if( data_isstring(data) )
+	{// item name
+		id = itemdb_searchname(conv_str(st, data));
+	}
+	else
+	{// item id
+		id = itemdb_exists(conv_num(st, data));
+	}
+
+	if( id == NULL )
+	{
+		ShowError("buildin_checkweight: Invalid item '%s'.\n", script_getstr(st,2));  // returns string, regardless of what it was
+		return 1;
+	}
+
+	nameid = id->nameid;
+	amount = script_getnum(st,3);
+
+	if( amount < 1 )
+	{
+		ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount);
 		return 1;
 	}
 
 	weight = itemdb_weight(nameid)*amount;
-	if( amount > MAX_AMOUNT || weight + sd->weight > sd->max_weight )
+
+	if( weight + sd->weight > sd->max_weight )
+	{// too heavy
 		script_pushint(st,0);
-	else if( itemdb_isstackable(nameid) )
-	{
-		if( (i = pc_search_inventory(sd,nameid)) >= 0 )
-			script_pushint(st,amount + sd->status.inventory[i].amount > MAX_AMOUNT ? 0 : 1);
-		else
-			script_pushint(st,pc_search_inventory(sd,0) >= 0 ? 1 : 0);
+		return 0;
 	}
-	else
+
+	switch( pc_checkadditem(sd, nameid, amount) )
 	{
-		for( i = 0; i < MAX_INVENTORY && amount; ++i )
-			if( sd->status.inventory[i].nameid == 0 )
-				amount--;
-		script_pushint(st,amount ? 0 : 1);
+		case ADDITEM_EXIST:
+			// item is already in inventory, but there is still space for the requested amount
+			break;
+		case ADDITEM_NEW:
+			slots = pc_inventoryblank(sd);
+
+			if( itemdb_isstackable(nameid) )
+			{// stackable
+				if( slots < 1 )
+				{
+					script_pushint(st,0);
+					return 0;
+				}
+			}
+			else
+			{// non-stackable
+				if( slots < amount )
+				{
+					script_pushint(st,0);
+					return 0;
+				}
+			}
+			break;
+		case ADDITEM_OVERAMOUNT:
+			script_pushint(st,0);
+			return 0;
 	}
 
 	return 0;
@@ -5390,8 +5653,8 @@ BUILDIN_FUNC(getitem2)
 }
 
 /*==========================================
- * rentitem <item id>
- * rentitem "<item name>"
+ * rentitem <item id>,<seconds>
+ * rentitem "<item name>",<seconds>
  *------------------------------------------*/
 BUILDIN_FUNC(rentitem)
 {
@@ -5592,10 +5855,160 @@ BUILDIN_FUNC(makeitem)
 
 		map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,0);
 	}
-
-	return 0;
+
+	return 0;
+}
+
+
+/// Counts / deletes the current item given by idx.
+/// Used by buildin_delitem_search
+/// Relies on all input data being already fully valid.
+static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items)
+{
+	int delamount;
+	struct item* inv = &sd->status.inventory[idx];
+
+	delamount = ( amount[0] < inv->amount ) ? amount[0] : inv->amount;
+
+	if( delete_items )
+	{
+		if( sd->inventory_data[idx]->type == IT_PETEGG && inv->card[0] == CARD0_PET )
+		{// delete associated pet
+			intif_delete_petdata(MakeDWord(inv->card[1], inv->card[2]));
+		}
+
+		//Logs items, got from (N)PC scripts [Lupus]
+		if( log_config.enable_logs&0x40 )
+		{
+			log_pick_pc(sd, "N", inv->nameid, -delamount, inv);
+		}
+		//Logs
+
+		pc_delitem(sd, idx, delamount, 0, 0);
+	}
+
+	amount[0]-= delamount;
+}
+
+
+/// Searches for item(s) and checks, if there is enough of them.
+/// Used by delitem and delitem2
+/// Relies on all input data being already fully valid.
+/// @param exact_match will also match item attributes and cards, not just name id
+/// @return true when all items could be deleted, false when there were not enough items to delete
+static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match)
+{
+	bool delete_items = false;
+	int i, amount, important;
+	struct item* inv;
+
+	// prefer always non-equipped items
+	it->equip = 0;
+
+	// when searching for nameid only, prefer additionally
+	if( !exact_match )
+	{
+		// non-refined items
+		it->refine = 0;
+		// card-less items
+		memset(it->card, 0, sizeof(it->card));
+	}
+
+	for(;;)
+	{
+		amount = it->amount;
+		important = 0;
+
+		// 1st pass -- less important items / exact match
+		for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ )
+		{
+			inv = &sd->status.inventory[i];
+
+			if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid )
+			{// wrong/invalid item
+				continue;
+			}
+
+			if( inv->equip != it->equip || inv->refine != it->refine )
+			{// not matching attributes
+				important++;
+				continue;
+			}
+
+			if( exact_match )
+			{
+				if( inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) )
+				{// not matching exact attributes
+					continue;
+				}
+			}
+			else
+			{
+				if( sd->inventory_data[i]->type == IT_PETEGG )
+				{
+					if( inv->card[0] == CARD0_PET && CheckForCharServer() )
+					{// pet which cannot be deleted
+						continue;
+					}
+				}
+				else if( memcmp(inv->card, it->card, sizeof(inv->card)) )
+				{// named/carded item
+					important++;
+					continue;
+				}
+			}
+
+			// count / delete item
+			buildin_delitem_delete(sd, i, &amount, delete_items);
+		}
+
+		// 2nd pass -- any matching item
+		if( amount == 0 || important == 0 )
+		{// either everything was already consumed or no items were skipped
+			;
+		}
+		else for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ )
+		{
+			inv = &sd->status.inventory[i];
+
+			if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid )
+			{// wrong/invalid item
+				continue;
+			}
+
+			if( sd->inventory_data[i]->type == IT_PETEGG && inv->card[0] == CARD0_PET && CheckForCharServer() )
+			{// pet which cannot be deleted
+				continue;
+			}
+
+			if( exact_match )
+			{
+				if( inv->refine != it->refine || inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) )
+				{// not matching attributes
+					continue;
+				}
+			}
+
+			// count / delete item
+			buildin_delitem_delete(sd, i, &amount, delete_items);
+		}
+
+		if( amount )
+		{// not enough items
+			return false;
+		}
+		else if( delete_items )
+		{// we are done with the work
+			return true;
+		}
+		else
+		{// get rid of the items now
+			delete_items = true;
+		}
+	}
 }
 
+
 /// Deletes items from the target/attached player.
 /// Prioritizes ordinary items.
 ///
@@ -5603,8 +6016,8 @@ BUILDIN_FUNC(makeitem)
 /// delitem "<item name>",<amount>{,<account id>}
 BUILDIN_FUNC(delitem)
 {
-	int nameid=0,amount,i,important_item=0;
 	TBL_PC *sd;
+	struct item it;
 	struct script_data *data;
 
 	if( script_hasdata(st,4) )
@@ -5637,89 +6050,30 @@ BUILDIN_FUNC(delitem)
 			st->state = END;
 			return 1;
 		}
-		nameid = id->nameid;// "<item name>"
+		it.nameid = id->nameid;// "<item name>"
 	}
 	else
-		nameid = conv_num(st,data);// <item id>
-
-	amount=script_getnum(st,3);
-
-	if( amount <= 0 )
-		return 0;// nothing to do
-
-	//1st pass
-	//here we won't delete items with CARDS, named items but we count them
-	for(i=0;i<MAX_INVENTORY;i++){
-		//we don't delete wrong item or equipped item
-		if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
-		   sd->status.inventory[i].amount<=0 || sd->status.inventory[i].nameid!=nameid)
-			continue;
-		//1 egg uses 1 cell in the inventory. so it's ok to delete 1 pet / per cycle
-		if(sd->inventory_data[i]->type==IT_PETEGG &&
-			sd->status.inventory[i].card[0] == CARD0_PET)
+	{
+		it.nameid = conv_num(st,data);// <item id>
+		if( !itemdb_exists( it.nameid ) )
 		{
-			if (!intif_delete_petdata(MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2])))
-				continue; //pet couldn't be sent for deletion.
-		} else
-		//is this item important? does it have cards? or Player's name? or Refined/Upgraded
-		if(itemdb_isspecial(sd->status.inventory[i].card[0]) ||
-			sd->status.inventory[i].card[0] ||
-		  	sd->status.inventory[i].refine) {
-			//this is important item, count it (except for pet eggs)
-			if(sd->status.inventory[i].card[0] != CARD0_PET)
-				important_item++;
-			continue;
-		}
-
-		if(sd->status.inventory[i].amount>=amount){
-
-			//Logs items, got from (N)PC scripts [Lupus]
-			if(log_config.enable_logs&0x40)
-				log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -amount, &sd->status.inventory[i]);
-
-			pc_delitem(sd,i,amount,0,0);
-			return 0; //we deleted exact amount of items. now exit
-		} else {
-			amount-=sd->status.inventory[i].amount;
-
-			//Logs items, got from (N)PC scripts [Lupus]
-			if(log_config.enable_logs&0x40) {
-				log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -sd->status.inventory[i].amount, &sd->status.inventory[i]);
-			}
-			//Logs
-
-			pc_delitem(sd,i,sd->status.inventory[i].amount,0,0);
+			ShowError("script:delitem: unknown item \"%d\".\n", it.nameid);
+			st->state = END;
+			return 1;
 		}
 	}
-	//2nd pass
-	//now if there WERE items with CARDs/REFINED/NAMED... and if we still have to delete some items. we'll delete them finally
-	if (important_item>0 && amount>0)
-		for(i=0;i<MAX_INVENTORY;i++){
-			//we don't delete wrong item
-			if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
-				sd->status.inventory[i].amount<=0 || sd->status.inventory[i].nameid!=nameid )
-				continue;
-
-			if(sd->status.inventory[i].amount>=amount){
 
-				//Logs items, got from (N)PC scripts [Lupus]
-				if(log_config.enable_logs&0x40)
-					log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -amount, &sd->status.inventory[i]);
-
-				pc_delitem(sd,i,amount,0,0);
-				return 0; //we deleted exact amount of items. now exit
-			} else {
-				amount-=sd->status.inventory[i].amount;
+	it.amount=script_getnum(st,3);
 
-				//Logs items, got from (N)PC scripts [Lupus]
-				if(log_config.enable_logs&0x40)
-					log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -sd->status.inventory[i].amount, &sd->status.inventory[i]);
+	if( it.amount <= 0 )
+		return 0;// nothing to do
 
-				pc_delitem(sd,i,sd->status.inventory[i].amount,0,0);
-			}
-		}
+	if( buildin_delitem_search(sd, &it, false) )
+	{// success
+		return 0;
+	}
 
-	ShowError("script:delitem: failed to delete %d items (AID=%d item_id=%d).\n", amount, sd->status.account_id, nameid);
+	ShowError("script:delitem: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid);
 	st->state = END;
 	clif_scriptclose(sd, st->oid);
 	return 1;
@@ -5731,9 +6085,8 @@ BUILDIN_FUNC(delitem)
 /// delitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 BUILDIN_FUNC(delitem2)
 {
-	int nameid=0,amount,i=0;
-	int iden,ref,attr,c1,c2,c3,c4;
 	TBL_PC *sd;
+	struct item it;
 	struct script_data *data;
 
 	if( script_hasdata(st,11) )
@@ -5766,59 +6119,37 @@ BUILDIN_FUNC(delitem2)
 			st->state = END;
 			return 1;
 		}
-		nameid = id->nameid;// "<item name>"
+		it.nameid = id->nameid;// "<item name>"
 	}
 	else
-		nameid = conv_num(st,data);// <item id>
-
-	amount=script_getnum(st,3);
-	iden=script_getnum(st,4);
-	ref=script_getnum(st,5);
-	attr=script_getnum(st,6);
-	c1=(short)script_getnum(st,7);
-	c2=(short)script_getnum(st,8);
-	c3=(short)script_getnum(st,9);
-	c4=(short)script_getnum(st,10);
-
-	if( amount <= 0 )
-		return 0;// nothing to do
-
-	for(i=0;i<MAX_INVENTORY;i++){
-	//we don't delete wrong item or equipped item
-		if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
-			sd->status.inventory[i].amount<=0 || sd->status.inventory[i].nameid!=nameid ||
-			sd->status.inventory[i].identify!=iden || sd->status.inventory[i].refine!=ref ||
-			sd->status.inventory[i].attribute!=attr || sd->status.inventory[i].card[0]!=c1 ||
-			sd->status.inventory[i].card[1]!=c2 || sd->status.inventory[i].card[2]!=c3 ||
-			sd->status.inventory[i].card[3]!=c4)
-			continue;
-	//1 egg uses 1 cell in the inventory. so it's ok to delete 1 pet / per cycle
-		if(sd->inventory_data[i]->type==IT_PETEGG && sd->status.inventory[i].card[0] == CARD0_PET)
+	{
+		it.nameid = conv_num(st,data);// <item id>
+		if( !itemdb_exists( it.nameid ) )
 		{
-			if (!intif_delete_petdata( MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2])))
-				continue; //Failed to send delete the pet.
+			ShowError("script:delitem: unknown item \"%d\".\n", it.nameid);
+			st->state = END;
+			return 1;
 		}
+	}
 
-		if(sd->status.inventory[i].amount>=amount){
-
-			//Logs items, got from (N)PC scripts [Lupus]
-			if(log_config.enable_logs&0x40)
-				log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -amount, &sd->status.inventory[i]);
-
-			pc_delitem(sd,i,amount,0,0);
-			return 0; //we deleted exact amount of items. now exit
-		} else {
-			amount-=sd->status.inventory[i].amount;
+	it.amount=script_getnum(st,3);
+	it.identify=script_getnum(st,4);
+	it.refine=script_getnum(st,5);
+	it.attribute=script_getnum(st,6);
+	it.card[0]=(short)script_getnum(st,7);
+	it.card[1]=(short)script_getnum(st,8);
+	it.card[2]=(short)script_getnum(st,9);
+	it.card[3]=(short)script_getnum(st,10);
 
-			//Logs items, got from (N)PC scripts [Lupus]
-			if(log_config.enable_logs&0x40)
-				log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -sd->status.inventory[i].amount, &sd->status.inventory[i]);
+	if( it.amount <= 0 )
+		return 0;// nothing to do
 
-			pc_delitem(sd,i,sd->status.inventory[i].amount,0,0);
-		}
+	if( buildin_delitem_search(sd, &it, true) )
+	{// success
+		return 0;
 	}
 
-	ShowError("script:delitem2: failed to delete %d items (AID=%d item_id=%d).\n", amount, sd->status.account_id, nameid);
+	ShowError("script:delitem2: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid);
 	st->state = END;
 	clif_scriptclose(sd, st->oid);
 	return 1;
@@ -5904,34 +6235,21 @@ BUILDIN_FUNC(getcharid)
 /*==========================================
  *�w��ID��PT���擾
  *------------------------------------------*/
-char *buildin_getpartyname_sub(int party_id)
-{
-	struct party_data *p;
-
-	p=party_search(party_id);
-
-	if(p!=NULL){
-		char *buf;
-		buf=(char *)aMallocA(NAME_LENGTH*sizeof(char));
-		memcpy(buf, p->party.name, NAME_LENGTH);
-		buf[NAME_LENGTH-1] = '\0';
-		return buf;
-	}
-
-	return 0;
-}
 BUILDIN_FUNC(getpartyname)
 {
-	char *name;
 	int party_id;
+	struct party_data* p;
 
-	party_id=script_getnum(st,2);
-	name=buildin_getpartyname_sub(party_id);
-	if(name != NULL)
-		script_pushstr(st,name);
+	party_id = script_getnum(st,2);
+
+	if( ( p = party_search(party_id) ) != NULL )
+	{
+		script_pushstrcopy(st,p->party.name);
+	}
 	else
+	{
 		script_pushconststr(st,"null");
-
+	}
 	return 0;
 }
 /*==========================================
@@ -5952,13 +6270,13 @@ BUILDIN_FUNC(getpartymember)
 			if(p->party.member[i].account_id){
 				switch (type) {
 				case 2:
-					mapreg_setreg(add_str("$@partymemberaid")+(j<<24),p->party.member[i].account_id);
+					mapreg_setreg(reference_uid(add_str("$@partymemberaid"), j),p->party.member[i].account_id);
 					break;
 				case 1:
-					mapreg_setreg(add_str("$@partymembercid")+(j<<24),p->party.member[i].char_id);
+					mapreg_setreg(reference_uid(add_str("$@partymembercid"), j),p->party.member[i].char_id);
 					break;
 				default:
-					mapreg_setregstr(add_str("$@partymembername$")+(j<<24),p->party.member[i].name);
+					mapreg_setregstr(reference_uid(add_str("$@partymembername$"), j),p->party.member[i].name);
 				}
 				j++;
 			}
@@ -6009,75 +6327,58 @@ BUILDIN_FUNC(getpartyleader)
 /*==========================================
  *�w��ID�̃M���h���擾
  *------------------------------------------*/
-char *buildin_getguildname_sub(int guild_id)
+BUILDIN_FUNC(getguildname)
 {
-	struct guild *g=NULL;
-	g=guild_search(guild_id);
+	int guild_id;
+	struct guild* g;
+
+	guild_id = script_getnum(st,2);
 
-	if(g!=NULL){
-		char *buf;
-		buf=(char *)aMallocA(NAME_LENGTH*sizeof(char));
-		memcpy(buf, g->name, NAME_LENGTH);
-		buf[NAME_LENGTH-1] = '\0';
-		return buf;
+	if( ( g = guild_search(guild_id) ) != NULL )
+	{
+		script_pushstrcopy(st,g->name);
 	}
-	return NULL;
-}
-BUILDIN_FUNC(getguildname)
-{
-	char *name;
-	int guild_id=script_getnum(st,2);
-	name=buildin_getguildname_sub(guild_id);
-	if(name != NULL)
-		script_pushstr(st,name);
 	else
+	{
 		script_pushconststr(st,"null");
+	}
 	return 0;
 }
 
 /*==========================================
  *�w��ID��GuildMaster���擾
  *------------------------------------------*/
-char *buildin_getguildmaster_sub(int guild_id)
+BUILDIN_FUNC(getguildmaster)
 {
-	struct guild *g=NULL;
-	g=guild_search(guild_id);
+	int guild_id;
+	struct guild* g;
 
-	if(g!=NULL){
-		char *buf;
-		buf=(char *)aMallocA(NAME_LENGTH*sizeof(char));
-		memcpy(buf, g->master, NAME_LENGTH);
-		buf[NAME_LENGTH-1] = '\0';
-		return buf;
-	}
+	guild_id = script_getnum(st,2);
 
-	return 0;
-}
-BUILDIN_FUNC(getguildmaster)
-{
-	char *master;
-	int guild_id=script_getnum(st,2);
-	master=buildin_getguildmaster_sub(guild_id);
-	if(master!=0)
-		script_pushstr(st,master);
+	if( ( g = guild_search(guild_id) ) != NULL )
+	{
+		script_pushstrcopy(st,g->member[0].name);
+	}
 	else
+	{
 		script_pushconststr(st,"null");
+	}
 	return 0;
 }
 
 BUILDIN_FUNC(getguildmasterid)
 {
-	char *master;
-	TBL_PC *sd=NULL;
-	int guild_id=script_getnum(st,2);
-	master=buildin_getguildmaster_sub(guild_id);
-	if(master!=0){
-		if((sd=map_nick2sd(master)) == NULL){
-			script_pushint(st,0);
-			return 0;
-		}
-		script_pushint(st,sd->status.char_id);
-	}else{
+	int guild_id;
+	struct guild* g;
+
+	guild_id = script_getnum(st,2);
+
+	if( ( g = guild_search(guild_id) ) != NULL )
+	{
+		script_pushint(st,g->member[0].char_id);
+	}
+	else
+	{
 		script_pushint(st,0);
 	}
 	return 0;
@@ -6090,7 +6391,8 @@ BUILDIN_FUNC(strcharinfo)
 {
 	TBL_PC *sd;
 	int num;
-	char *buf;
+	struct guild* g;
+	struct party_data* p;
 
 	sd=script_rid2sd(st);
 	if (!sd) { //Avoid crashing....
@@ -6103,18 +6405,24 @@ BUILDIN_FUNC(strcharinfo)
 			script_pushstrcopy(st,sd->status.name);
 			break;
 		case 1:
-			buf=buildin_getpartyname_sub(sd->status.party_id);
-			if(buf!=0)
-				script_pushstr(st,buf);
+			if( ( p = party_search(sd->status.party_id) ) != NULL )
+			{
+				script_pushstrcopy(st,p->party.name);
+			}
 			else
+			{
 				script_pushconststr(st,"");
+			}
 			break;
 		case 2:
-			buf=buildin_getguildname_sub(sd->status.guild_id);
-			if(buf != NULL)
-				script_pushstr(st,buf);
+			if( ( g = guild_search(sd->status.guild_id) ) != NULL )
+			{
+				script_pushstrcopy(st,g->name);
+			}
 			else
+			{
 				script_pushconststr(st,"");
+			}
 			break;
 		case 3:
 			script_pushconststr(st,map[sd->bl.m].name);
@@ -7534,8 +7842,8 @@ BUILDIN_FUNC(getmobdrops)
 		if( itemdb_exists(mob->dropitem[i].nameid) == NULL )
 			continue;
 
-		mapreg_setreg(add_str("$@MobDrop_item") + (j<<24), mob->dropitem[i].nameid);
-		mapreg_setreg(add_str("$@MobDrop_rate") + (j<<24), mob->dropitem[i].p);
+		mapreg_setreg(reference_uid(add_str("$@MobDrop_item"), j), mob->dropitem[i].nameid);
+		mapreg_setreg(reference_uid(add_str("$@MobDrop_rate"), j), mob->dropitem[i].p);
 
 		j++;
 	}
@@ -7750,8 +8058,15 @@ BUILDIN_FUNC(clone)
 BUILDIN_FUNC(doevent)
 {
 	const char* event = script_getstr(st,2);
+	struct map_session_data* sd;
+
+	if( ( sd = script_rid2sd(st) ) == NULL )
+	{
+		return 0;
+	}
+
 	check_event(st, event);
-	npc_event(map_id2sd(st->rid),event,0);
+	npc_event(sd, event, 0);
 	return 0;
 }
 /*==========================================
@@ -8226,18 +8541,18 @@ BUILDIN_FUNC(getusers)
 
 	flag = script_getnum(st,2);
 
-	if(flag&0x8)
-	{// npc
-		bl = map_id2bl(st->oid);
-	}
-	else if((sd = script_rid2sd(st))!=NULL)
-	{// pc
-		bl = &sd->bl;
-	}
-
 	switch(flag&0x07)
 	{
 		case 0:
+			if(flag&0x8)
+			{// npc
+				bl = map_id2bl(st->oid);
+			}
+			else if((sd = script_rid2sd(st))!=NULL)
+			{// pc
+				bl = &sd->bl;
+			}
+
 			if(bl)
 			{
 				val = map[bl->m].users;
@@ -8657,7 +8972,7 @@ BUILDIN_FUNC(homunculus_evolution)
 		if (sd->hd->homunculus.intimacy > 91000)
 			merc_hom_evolution(sd->hd);
 		else
-			clif_emotion(&sd->hd->bl, 4) ;	//swt
+			clif_emotion(&sd->hd->bl, E_SWT);
 	}
 	return 0;
 }
@@ -9061,23 +9376,23 @@ BUILDIN_FUNC(warpwaitingpc)
 		if( sd == NULL )
 		{
 			ShowDebug("script:warpwaitingpc: no user in chat room position 0 (cd->users=%d,%d/%d)\n", cd->users, i, n);
-			mapreg_setreg(add_str("$@warpwaitingpc")+(i<<24), 0);
+			mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), 0);
 			continue;// Broken npc chat room?
 		}
 
-		mapreg_setreg(add_str("$@warpwaitingpc")+(i<<24), sd->bl.id);
+		mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), sd->bl.id);
 
 		if( strcmp(map_name,"Random") == 0 )
-			pc_randomwarp(sd,3);
+			pc_randomwarp(sd,CLR_TELEPORT);
 		else if( strcmp(map_name,"SavePoint") == 0 )
 		{
 			if( map[sd->bl.m].flag.noteleport )
 				return 0;// can't teleport on this map
 
-			pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 3);
+			pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
 		}
 		else
-			pc_setpos(sd, mapindex_name2id(map_name), x, y, 0);
+			pc_setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT);
 	}
 	mapreg_setreg(add_str("$@warpwaitingpcnum"), i);
 	return 0;
@@ -9087,15 +9402,31 @@ BUILDIN_FUNC(warpwaitingpc)
 // ...
 //
 
+/// Detaches a character from a script.
+///
+/// @param st Script state to detach the character from.
+static void script_detach_rid(struct script_state* st)
+{
+	if(st->rid)
+	{
+		script_detach_state(st, false);
+		st->rid = 0;
+	}
+}
+
 /*==========================================
  * RID�̃A�^�b�`
  *------------------------------------------*/
 BUILDIN_FUNC(attachrid)
 {
 	int rid = script_getnum(st,2);
-	
-	if (map_id2sd(rid)) {
+	struct map_session_data* sd;
+
+	if ((sd = map_id2sd(rid))!=NULL) {
+		script_detach_rid(st);
+
 		st->rid = rid;
+		script_attach_state(st);
 		script_pushint(st,1);
 	} else
 		script_pushint(st,0);
@@ -9106,7 +9437,7 @@ BUILDIN_FUNC(attachrid)
  *------------------------------------------*/
 BUILDIN_FUNC(detachrid)
 {
-	st->rid=0;
+	script_detach_rid(st);
 	return 0;
 }
 /*==========================================
@@ -9495,7 +9826,7 @@ static int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list
 		(sd->status.guild_id != g_id && flag&2) || //Warp out outsiders
 		(sd->status.guild_id == 0)	// Warp out players not in guild [Valaris]
 	)
-		pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+		pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
 	return 1;
 }
 
@@ -9969,7 +10300,7 @@ BUILDIN_FUNC(mapwarp)	// Added by RoVeRT
 				for( i=0; i < g->max_member; i++)
 				{
 					if(g->member[i].sd && g->member[i].sd->bl.m==m){
-						pc_setpos(g->member[i].sd,index,x,y,3);
+						pc_setpos(g->member[i].sd,index,x,y,CLR_TELEPORT);
 					}
 				}
 			}
@@ -9979,7 +10310,7 @@ BUILDIN_FUNC(mapwarp)	// Added by RoVeRT
 			if(p){
 				for(i=0;i<MAX_PARTY; i++){
 					if(p->data[i].sd && p->data[i].sd->bl.m == m){
-						pc_setpos(p->data[i].sd,index,x,y,3);
+						pc_setpos(p->data[i].sd,index,x,y,CLR_TELEPORT);
 					}
 				}
 			}
@@ -10142,7 +10473,7 @@ BUILDIN_FUNC(warppartner)
 
 	mapindex = mapindex_name2id(str);
 	if (mapindex) {
-		pc_setpos(p_sd,mapindex,x,y,0);
+		pc_setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT);
 		script_pushint(st,1);
 	} else
 		script_pushint(st,0);
@@ -10356,7 +10687,7 @@ BUILDIN_FUNC(getitemslots)
 		2 type;
 		3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
 				if = 0, then monsters don't drop it at all (rare or a quest item)
-				if = 10000, then this item is sold in NPC shops only
+				if = -1, then this item is sold in NPC shops only
 		4 sex;
 		5 equip;
 		6 weight;
@@ -10396,7 +10727,7 @@ BUILDIN_FUNC(getiteminfo)
 		2 type;
 		3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
 				if = 0, then monsters don't drop it at all (rare or a quest item)
-				if = 10000, then this item is sold in NPC shops only
+				if = -1, then this item is sold in NPC shops only
 		4 sex;
 		5 equip;
 		6 weight;
@@ -10545,18 +10876,18 @@ BUILDIN_FUNC(getinventorylist)
 	if(!sd) return 0;
 	for(i=0;i<MAX_INVENTORY;i++){
 		if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0){
-			pc_setreg(sd,add_str("@inventorylist_id")+(j<<24),sd->status.inventory[i].nameid);
-			pc_setreg(sd,add_str("@inventorylist_amount")+(j<<24),sd->status.inventory[i].amount);
-			pc_setreg(sd,add_str("@inventorylist_equip")+(j<<24),sd->status.inventory[i].equip);
-			pc_setreg(sd,add_str("@inventorylist_refine")+(j<<24),sd->status.inventory[i].refine);
-			pc_setreg(sd,add_str("@inventorylist_identify")+(j<<24),sd->status.inventory[i].identify);
-			pc_setreg(sd,add_str("@inventorylist_attribute")+(j<<24),sd->status.inventory[i].attribute);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_equip"), j),sd->status.inventory[i].equip);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute);
 			for (k = 0; k < MAX_SLOTS; k++)
 			{
 				sprintf(card_var, "@inventorylist_card%d",k+1);
-				pc_setreg(sd,add_str(card_var)+(j<<24),sd->status.inventory[i].card[k]);
+				pc_setreg(sd,reference_uid(add_str(card_var), j),sd->status.inventory[i].card[k]);
 			}
-			pc_setreg(sd,add_str("@inventorylist_expire")+(j<<24),sd->status.inventory[i].expire_time);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
 			j++;
 		}
 	}
@@ -10571,9 +10902,9 @@ BUILDIN_FUNC(getskilllist)
 	if(!sd) return 0;
 	for(i=0;i<MAX_SKILL;i++){
 		if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0){
-			pc_setreg(sd,add_str("@skilllist_id")+(j<<24),sd->status.skill[i].id);
-			pc_setreg(sd,add_str("@skilllist_lv")+(j<<24),sd->status.skill[i].lv);
-			pc_setreg(sd,add_str("@skilllist_flag")+(j<<24),sd->status.skill[i].flag);
+			pc_setreg(sd,reference_uid(add_str("@skilllist_id"), j),sd->status.skill[i].id);
+			pc_setreg(sd,reference_uid(add_str("@skilllist_lv"), j),sd->status.skill[i].lv);
+			pc_setreg(sd,reference_uid(add_str("@skilllist_flag"), j),sd->status.skill[i].flag);
 			j++;
 		}
 	}
@@ -10665,11 +10996,11 @@ BUILDIN_FUNC(misceffect)
 	if(st->oid && st->oid != fake_nd->bl.id) {
 		struct block_list *bl = map_id2bl(st->oid);
 		if (bl)
-			clif_misceffect2(bl,type);
+			clif_specialeffect(bl,type,AREA);
 	} else{
 		TBL_PC *sd=script_rid2sd(st);
 		if(sd)
-			clif_misceffect2(&sd->bl,type);
+			clif_specialeffect(&sd->bl,type,AREA);
 	}
 	return 0;
 }
@@ -10678,27 +11009,34 @@ BUILDIN_FUNC(misceffect)
  *------------------------------------------*/
 BUILDIN_FUNC(playBGM)
 {
-	TBL_PC* sd = script_rid2sd(st);
-	const char* name = script_getstr(st,2);
+	const char* name;
+	struct map_session_data* sd;
 
-	if(sd)
+	if( ( sd = script_rid2sd(st) ) != NULL )
 	{
-		if(!st->rid)
-			clif_playBGM(sd,map_id2bl(st->oid),name);
-		else
-			clif_playBGM(sd,&sd->bl,name);
+		name = script_getstr(st,2);
+
+		clif_playBGM(sd, name);
 	}
 
 	return 0;
 }
 
-int playBGM_sub(struct block_list* bl,va_list ap)
+static int playBGM_sub(struct block_list* bl,va_list ap)
 {
-	char* name = va_arg(ap,char*);
+	const char* name = va_arg(ap,const char*);
 
-	clif_playBGM((TBL_PC *)bl, bl, name);
+	clif_playBGM(BL_CAST(BL_PC, bl), name);
 
-    return 0;
+	return 0;
+}
+
+static int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args)
+{
+	const char* name = va_arg(args, const char*);
+
+	clif_playBGM(sd, name);
+	return 0;
 }
 
 /*==========================================
@@ -10706,33 +11044,29 @@ int playBGM_sub(struct block_list* bl,va_list ap)
  *------------------------------------------*/
 BUILDIN_FUNC(playBGMall)
 {
-	struct block_list* bl;
 	const char* name;
 
-	bl = (st->rid) ? &(script_rid2sd(st)->bl) : map_id2bl(st->oid);
-	if (!bl)
-		return 0;
-
 	name = script_getstr(st,2);
 
-	if(script_hasdata(st,7))
-	{	// specified part of map
+	if( script_hasdata(st,7) )
+	{// specified part of map
 		const char* map = script_getstr(st,3);
 		int x0 = script_getnum(st,4);
 		int y0 = script_getnum(st,5);
 		int x1 = script_getnum(st,6);
 		int y1 = script_getnum(st,7);
+
 		map_foreachinarea(playBGM_sub, map_mapname2mapid(map), x0, y0, x1, y1, BL_PC, name);
 	}
-	else
-	if(!script_hasdata(st,7))
-	{	// entire map
+	else if( script_hasdata(st,3) )
+	{// entire map
 		const char* map = script_getstr(st,3);
+
 		map_foreachinmap(playBGM_sub, map_mapname2mapid(map), BL_PC, name);
 	}
 	else
-	{
-		ShowError("buildin_playBGMall: insufficient arguments for specific area broadcast.\n");
+	{// entire server
+		map_foreachpc(&playBGM_foreachpc_sub, name);
 	}
 
 	return 0;
@@ -10749,10 +11083,7 @@ BUILDIN_FUNC(soundeffect)
 
 	if(sd)
 	{
-		if(!st->rid)
-			clif_soundeffect(sd,map_id2bl(st->oid),name,type);
-		else
-			clif_soundeffect(sd,&sd->bl,name,type);
+		clif_soundeffect(sd,&sd->bl,name,type);
 	}
 	return 0;
 }
@@ -11702,7 +12033,7 @@ BUILDIN_FUNC(summon)
 			delete_timer(md->deletetimer, mob_timer_delete);
 		md->deletetimer = add_timer(tick+(timeout>0?timeout*1000:60000),mob_timer_delete,md->bl.id,0);
 		mob_spawn (md); //Now it is ready for spawning.
-		clif_misceffect2(&md->bl,344);
+		clif_specialeffect(&md->bl,344,AREA);
 		sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
 	}
 	return 0;
@@ -11723,68 +12054,6 @@ BUILDIN_FUNC(isday)
 	return 0;
 }
 
-/*================================================
- * Check whether another item/card has been
- * equipped - used for 2/15's cards patch [celest]
- *------------------------------------------------*/
-// leave this here, just in case
-#if 0
-BUILDIN_FUNC(isequipped)
-{
-	TBL_PC *sd;
-	int i, j, k, id = 1;
-	int ret = -1;
-
-	sd = script_rid2sd(st);
-	
-	for (i=0; id!=0; i++) {
-		int flag = 0;
-	
-		FETCH (i+2, id) else id = 0;
-		if (id <= 0)
-			continue;
-		
-		for (j=0; j<EQI_MAX; j++) {
-			int index;
-			index = sd->equip_index[j];
-			if(index < 0) continue;
-			if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
-			if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
-			if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
-			
-			if(!sd->inventory_data[index])
-				continue;
-
-			if(itemdb_type(id) != IT_CARD) { //Non card
-				if (sd->inventory_data[index]->nameid != id)
-					continue;
-				flag = 1;
-				break;
-			} else { //Card
-				if (itemdb_isspecial(sd->status.inventory[index].card[0]))
-					continue;
-				for(k=0; k<sd->inventory_data[index]->slot; k++) {
-					if (sd->status.inventory[index].card[k] == id)
-					{
-						flag = 1;
-						break;
-					}
-				}
-			}
-			if (flag) break;
-		}
-		if (ret == -1)
-			ret = flag;
-		else
-			ret &= flag;
-		if (!ret) break;
-	}
-	
-	script_pushint(st,ret);
-	return 0;
-}
-#endif
-
 /*================================================
  * Check how many items/cards in the list are
  * equipped - used for 2/15's cards patch [celest]
@@ -12051,7 +12320,7 @@ BUILDIN_FUNC(setbattleflag)
 	const char *flag, *value;
 
 	flag = script_getstr(st,2);
-	value = script_getstr(st,3);
+	value = script_getstr(st,3);  // HACK: Retrieve number as string (auto-converted) for battle_set_value
 	
 	if (battle_set_value(flag, value) == 0)
 		ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag);
@@ -12142,7 +12411,7 @@ BUILDIN_FUNC(setnpcdisplay)
 	if( newname )
 		npc_setdisplayname(nd, newname);
 
-	if( size != -1 && size != nd->size )
+	if( size != -1 && size != (int)nd->size )
 		nd->size = size;
 	else
 		size = -1;
@@ -12151,7 +12420,7 @@ BUILDIN_FUNC(setnpcdisplay)
 		npc_setclass(nd, class_);
 	else if( size != -1 )
 	{ // Required to update the visual size
-		clif_clearunit_area(&nd->bl, 0);
+		clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);
 		clif_spawn(&nd->bl);
 	}
 
@@ -12231,10 +12500,9 @@ BUILDIN_FUNC(setd)
 {
 	TBL_PC *sd=NULL;
 	char varname[100];
-	const char *value, *buffer;
+	const char *buffer;
 	int elem;
 	buffer = script_getstr(st, 2);
-	value = script_getstr(st, 3);
 
 	if(sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2)
 		elem = 0;
@@ -12249,10 +12517,10 @@ BUILDIN_FUNC(setd)
 		}
 	}
 
-	if(varname[strlen(varname)-1] != '$') {
-		setd_sub(st,sd, varname, elem, (void *)atoi(value),NULL);
+	if( is_string_variable(varname) ) {
+		setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL);
 	} else {
-		setd_sub(st,sd, varname, elem, (void *)value,NULL);
+		setd_sub(st, sd, varname, elem, (void *)script_getnum(st, 3), NULL);
 	}
 	
 	return 0;
@@ -12266,7 +12534,7 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle)
 	const char* query;
 	struct script_data* data;
 	const char* name;
-	int max_rows = 128;// maximum number of rows
+	int max_rows = SCRIPT_MAX_ARRAYSIZE;// maximum number of rows
 	int num_vars;
 	int num_cols;
 
@@ -12413,7 +12681,7 @@ BUILDIN_FUNC(getd)
 		elem = 0;
 
 	// Push the 'pointer' so it's more flexible [Lance]
-	push_val(st->stack, C_NAME, (elem<<24) | add_str(varname));
+	push_val(st->stack, C_NAME, reference_uid(add_str(varname), elem));
 
 	return 0;
 }
@@ -12548,6 +12816,7 @@ BUILDIN_FUNC(npcshopdelitem)
 {
 	const char* npcname = script_getstr(st,2);
 	struct npc_data* nd = npc_name2id(npcname);
+	unsigned int nameid;
 	int n, i;
 	int amount;
 	int size;
@@ -12564,7 +12833,9 @@ BUILDIN_FUNC(npcshopdelitem)
 	// remove specified items from the shop item list
 	for( i = 3; i < 3 + amount; i++ )
 	{
-		ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == script_getnum(st,i) );
+		nameid = script_getnum(st,i);
+
+		ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == nameid );
 		if( n < size )
 		{
 			memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0])*(size-n));
@@ -13016,7 +13287,7 @@ BUILDIN_FUNC(unitwarp)
 
 	bl = map_id2bl(unit_id);
 	if( map >= 0 && bl != NULL )
-		script_pushint(st, unit_warp(bl,map,x,y,0));
+		script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT));
 	else
 		script_pushint(st, 0);
 
@@ -13212,17 +13483,11 @@ BUILDIN_FUNC(unitskillusepos)
 BUILDIN_FUNC(sleep)
 {
 	int ticks;
-	TBL_PC* sd;
 	
 	ticks = script_getnum(st,2);
-	sd = map_id2sd(st->rid);
 
 	// detach the player
-	if( sd && sd->npc_id == st->oid )
-	{
-		sd->npc_id = 0;
-	}
-	st->rid = 0;
+	script_detach_rid(st);
 
 	if( ticks <= 0 )
 	{// do nothing
@@ -13779,9 +14044,9 @@ BUILDIN_FUNC(waitingroom2bg)
 	for( i = 0; i < n && i < MAX_BG_MEMBERS; i++ )
 	{
 		if( (sd = cd->usersd[i]) != NULL && bg_team_join(bg_id, sd) )
-			mapreg_setreg(add_str("$@arenamembers") + (i<<24), sd->bl.id);
+			mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), sd->bl.id);
 		else
-			mapreg_setreg(add_str("$@arenamembers") + (i<<24), 0);
+			mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), 0);
 	}
 
 	mapreg_setreg(add_str("$@arenamembersnum"), i);
@@ -13814,7 +14079,7 @@ BUILDIN_FUNC(waitingroom2bg_single)
 
 	if( bg_team_join(bg_id, sd) )
 	{
-		pc_setpos(sd, mapindex, x, y, 3);
+		pc_setpos(sd, mapindex, x, y, CLR_TELEPORT);
 		script_pushint(st,1);
 	}
 	else
@@ -14283,7 +14548,7 @@ BUILDIN_FUNC(instance_warpall)
 
 	mapindex = map_id2index(m);
 	for( i = 0; i < MAX_PARTY; i++ )
-		if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == st->instance_id ) pc_setpos(pl_sd,mapindex,x,y,3);
+		if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == st->instance_id ) pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
 
 	return 0;
 }
@@ -14451,7 +14716,8 @@ BUILDIN_FUNC(deactivatepset);
 BUILDIN_FUNC(deletepset);
 #endif
 
-
+/// script command definitions
+/// for an explanation on args, see add_buildin_func
 struct script_function buildin_func[] = {
 	// NPC interaction
 	BUILDIN_DEF(mes,"s"),
@@ -14463,21 +14729,21 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(prompt,"s*"),
 	//
 	BUILDIN_DEF(goto,"l"),
-	BUILDIN_DEF(callsub,"i*"),
+	BUILDIN_DEF(callsub,"l*"),
 	BUILDIN_DEF(callfunc,"s*"),
 	BUILDIN_DEF(return,"?"),
 	BUILDIN_DEF(getarg,"i?"),
-	BUILDIN_DEF(jobchange,"i*"),
+	BUILDIN_DEF(jobchange,"i?"),
 	BUILDIN_DEF(jobname,"i"),
-	BUILDIN_DEF(input,"v??"),
+	BUILDIN_DEF(input,"r??"),
 	BUILDIN_DEF(warp,"sii"),
 	BUILDIN_DEF(areawarp,"siiiisii"),
 	BUILDIN_DEF(warpchar,"siii"), // [LuzZza]
-	BUILDIN_DEF(warpparty,"siii*"), // [Fredzilla] [Paradox924X]
+	BUILDIN_DEF(warpparty,"siii?"), // [Fredzilla] [Paradox924X]
 	BUILDIN_DEF(warpguild,"siii"), // [Fredzilla]
 	BUILDIN_DEF(setlook,"ii"),
 	BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it
-	BUILDIN_DEF(set,"ii"),
+	BUILDIN_DEF(set,"rv"),
 	BUILDIN_DEF(setarray,"rv*"),
 	BUILDIN_DEF(cleararray,"rvi"),
 	BUILDIN_DEF(copyarray,"rri"),
@@ -14486,12 +14752,12 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(getelementofarray,"ri"),
 	BUILDIN_DEF(getitem,"vi?"),
 	BUILDIN_DEF(rentitem,"vi"),
-	BUILDIN_DEF(getitem2,"iiiiiiiii*"),
-	BUILDIN_DEF(getnameditem,"is"),
+	BUILDIN_DEF(getitem2,"viiiiiiii?"),
+	BUILDIN_DEF(getnameditem,"vv"),
 	BUILDIN_DEF2(grouprandomitem,"groupranditem","i"),
-	BUILDIN_DEF(makeitem,"iisii"),
-	BUILDIN_DEF(delitem,"ii?"),
-	BUILDIN_DEF(delitem2,"iiiiiiiii?"),
+	BUILDIN_DEF(makeitem,"visii"),
+	BUILDIN_DEF(delitem,"vi?"),
+	BUILDIN_DEF(delitem2,"viiiiiiii?"),
 	BUILDIN_DEF2(enableitemuse,"enable_items",""),
 	BUILDIN_DEF2(disableitemuse,"disable_items",""),
 	BUILDIN_DEF(cutin,"si"),
@@ -14500,13 +14766,13 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(itemheal,"ii"),
 	BUILDIN_DEF(percentheal,"ii"),
 	BUILDIN_DEF(rand,"i?"),
-	BUILDIN_DEF(countitem,"i"),
-	BUILDIN_DEF(countitem2,"iiiiiiii"),
-	BUILDIN_DEF(checkweight,"ii"),
-	BUILDIN_DEF(readparam,"i*"),
-	BUILDIN_DEF(getcharid,"i*"),
+	BUILDIN_DEF(countitem,"v"),
+	BUILDIN_DEF(countitem2,"viiiiiii"),
+	BUILDIN_DEF(checkweight,"vi"),
+	BUILDIN_DEF(readparam,"i?"),
+	BUILDIN_DEF(getcharid,"i?"),
 	BUILDIN_DEF(getpartyname,"i"),
-	BUILDIN_DEF(getpartymember,"i*"),
+	BUILDIN_DEF(getpartymember,"i?"),
 	BUILDIN_DEF(getpartyleader,"i?"),
 	BUILDIN_DEF(getguildname,"i"),
 	BUILDIN_DEF(getguildmaster,"i"),
@@ -14557,16 +14823,16 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(gettime,"i"),
 	BUILDIN_DEF(gettimestr,"si"),
 	BUILDIN_DEF(openstorage,""),
-	BUILDIN_DEF(guildopenstorage,"*"),
+	BUILDIN_DEF(guildopenstorage,""),
 	BUILDIN_DEF(itemskill,"vi"),
 	BUILDIN_DEF(produce,"i"),
 	BUILDIN_DEF(cooking,"i"),
-	BUILDIN_DEF(monster,"siisii*"),
+	BUILDIN_DEF(monster,"siisii?"),
 	BUILDIN_DEF(getmobdrops,"i"),
-	BUILDIN_DEF(areamonster,"siiiisii*"),
+	BUILDIN_DEF(areamonster,"siiiisii?"),
 	BUILDIN_DEF(killmonster,"ss?"),
 	BUILDIN_DEF(killmonsterall,"s?"),
-	BUILDIN_DEF(clone,"siisi*"),
+	BUILDIN_DEF(clone,"siisi????"),
 	BUILDIN_DEF(doevent,"s"),
 	BUILDIN_DEF(donpcevent,"s"),
 	BUILDIN_DEF(cmdothernpc,"ss"),
@@ -14581,14 +14847,14 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(attachnpctimer,"?"), // attached the player id to the npc timer [Celest]
 	BUILDIN_DEF(detachnpctimer,"?"), // detached the player id from the npc timer [Celest]
 	BUILDIN_DEF(playerattached,""), // returns id of the current attached player. [Skotlex]
-	BUILDIN_DEF(announce,"si*"),
-	BUILDIN_DEF(mapannounce,"ssi*"),
-	BUILDIN_DEF(areaannounce,"siiiisi*"),
+	BUILDIN_DEF(announce,"si?????"),
+	BUILDIN_DEF(mapannounce,"ssi?????"),
+	BUILDIN_DEF(areaannounce,"siiiisi?????"),
 	BUILDIN_DEF(getusers,"i"),
 	BUILDIN_DEF(getmapguildusers,"si"),
 	BUILDIN_DEF(getmapusers,"s"),
 	BUILDIN_DEF(getareausers,"siiii"),
-	BUILDIN_DEF(getareadropitem,"siiiii"),
+	BUILDIN_DEF(getareadropitem,"siiiiv"),
 	BUILDIN_DEF(enablenpc,"s"),
 	BUILDIN_DEF(disablenpc,"s"),
 	BUILDIN_DEF(hideoffnpc,"s"),
@@ -14597,7 +14863,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(sc_start2,"iiii?"),
 	BUILDIN_DEF(sc_start4,"iiiiii?"),
 	BUILDIN_DEF(sc_end,"i?"),
-	BUILDIN_DEF(getscrate,"ii*"),
+	BUILDIN_DEF(getscrate,"ii?"),
 	BUILDIN_DEF(debugmes,"s"),
 	BUILDIN_DEF2(catchpet,"pet","i"),
 	BUILDIN_DEF2(birthpet,"bpet",""),
@@ -14605,7 +14871,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(resetstatus,""),
 	BUILDIN_DEF(resetskill,""),
 	BUILDIN_DEF(skillpointcount,""),
-	BUILDIN_DEF(changebase,"i"),
+	BUILDIN_DEF(changebase,"i?"),
 	BUILDIN_DEF(changesex,""),
 	BUILDIN_DEF(waitingroom,"si??"),
 	BUILDIN_DEF(delwaitingroom,"?"),
@@ -14621,22 +14887,22 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(isloggedin,"i?"),
 	BUILDIN_DEF(setmapflagnosave,"ssii"),
 	BUILDIN_DEF(getmapflag,"si"),
-	BUILDIN_DEF(setmapflag,"si*"),
+	BUILDIN_DEF(setmapflag,"si?"),
 	BUILDIN_DEF(removemapflag,"si"),
 	BUILDIN_DEF(pvpon,"s"),
 	BUILDIN_DEF(pvpoff,"s"),
 	BUILDIN_DEF(gvgon,"s"),
 	BUILDIN_DEF(gvgoff,"s"),
-	BUILDIN_DEF(emotion,"i*"),
+	BUILDIN_DEF(emotion,"i??"),
 	BUILDIN_DEF(maprespawnguildid,"sii"),
 	BUILDIN_DEF(agitstart,""),	// <Agit>
 	BUILDIN_DEF(agitend,""),
 	BUILDIN_DEF(agitcheck,""),   // <Agitcheck>
 	BUILDIN_DEF(flagemblem,"i"),	// Flag Emblem
 	BUILDIN_DEF(getcastlename,"s"),
-	BUILDIN_DEF(getcastledata,"si*"),
+	BUILDIN_DEF(getcastledata,"si?"),
 	BUILDIN_DEF(setcastledata,"sii"),
-	BUILDIN_DEF(requestguildinfo,"i*"),
+	BUILDIN_DEF(requestguildinfo,"i?"),
 	BUILDIN_DEF(getequipcardcnt,"i"),
 	BUILDIN_DEF(successremovecards,"i"),
 	BUILDIN_DEF(failedremovecards,"ii"),
@@ -14649,7 +14915,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(getmotherid,""),
 	BUILDIN_DEF(getfatherid,""),
 	BUILDIN_DEF(warppartner,"sii"),
-	BUILDIN_DEF(getitemname,"i"),
+	BUILDIN_DEF(getitemname,"v"),
 	BUILDIN_DEF(getitemslots,"i"),
 	BUILDIN_DEF(makepet,"i"),
 	BUILDIN_DEF(getexp,"ii"),
@@ -14659,9 +14925,9 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(classchange,"ii"),
 	BUILDIN_DEF(misceffect,"i"),
 	BUILDIN_DEF(playBGM,"s"),
-	BUILDIN_DEF(playBGMall,"s*"),
+	BUILDIN_DEF(playBGMall,"s?????"),
 	BUILDIN_DEF(soundeffect,"si"),
-	BUILDIN_DEF(soundeffectall,"si*"),	// SoundEffectAll [Codemaster]
+	BUILDIN_DEF(soundeffectall,"si?????"),	// SoundEffectAll [Codemaster]
 	BUILDIN_DEF(strmobinfo,"ii"),	// display mob data [Valaris]
 	BUILDIN_DEF(guardian,"siisi??"),	// summon guardians
 	BUILDIN_DEF(guardianinfo,"sii"),	// display guardian data [Valaris]
@@ -14674,34 +14940,34 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(petskillsupport,"viiii"), // [Skotlex]
 	BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest]
 	BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris]
-	BUILDIN_DEF(specialeffect,"i*"), // npc skill effect [Valaris]
-	BUILDIN_DEF(specialeffect2,"i*"), // skill effect on players[Valaris]
+	BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris]
+	BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris]
 	BUILDIN_DEF(nude,""), // nude command [Valaris]
-	BUILDIN_DEF(mapwarp,"ssii*"),		// Added by RoVeRT
-	BUILDIN_DEF(atcommand,"*"), // [MouseJstr]
-	BUILDIN_DEF(charcommand,"*"), // [MouseJstr]
+	BUILDIN_DEF(mapwarp,"ssii??"),		// Added by RoVeRT
+	BUILDIN_DEF(atcommand,"s"), // [MouseJstr]
+	BUILDIN_DEF(charcommand,"s"), // [MouseJstr]
 	BUILDIN_DEF(movenpc,"sii"), // [MouseJstr]
-	BUILDIN_DEF(message,"s*"), // [MouseJstr]
-	BUILDIN_DEF(npctalk,"*"), // [Valaris]
+	BUILDIN_DEF(message,"ss"), // [MouseJstr]
+	BUILDIN_DEF(npctalk,"s"), // [Valaris]
 	BUILDIN_DEF(mobcount,"ss"),
 	BUILDIN_DEF(getlook,"i"),
 	BUILDIN_DEF(getsavepoint,"i"),
 	BUILDIN_DEF(npcspeed,"i"), // [Valaris]
 	BUILDIN_DEF(npcwalkto,"ii"), // [Valaris]
 	BUILDIN_DEF(npcstop,""), // [Valaris]
-	BUILDIN_DEF(getmapxy,"siii*"),	//by Lorky [Lupus]
+	BUILDIN_DEF(getmapxy,"rrri?"),	//by Lorky [Lupus]
 	BUILDIN_DEF(checkoption1,"i"),
 	BUILDIN_DEF(checkoption2,"i"),
 	BUILDIN_DEF(guildgetexp,"i"),
 	BUILDIN_DEF(guildchangegm,"is"),
 	BUILDIN_DEF(logmes,"s"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus]
-	BUILDIN_DEF(summon,"si*"), // summons a slave monster [Celest]
+	BUILDIN_DEF(summon,"si??"), // summons a slave monster [Celest]
 	BUILDIN_DEF(isnight,""), // check whether it is night time [Celest]
 	BUILDIN_DEF(isday,""), // check whether it is day time [Celest]
 	BUILDIN_DEF(isequipped,"i*"), // check whether another item/card has been equipped [Celest]
 	BUILDIN_DEF(isequippedcnt,"i*"), // check how many items/cards are being equipped [Celest]
 	BUILDIN_DEF(cardscnt,"i*"), // check how many items/cards are being equipped in the same arm [Lupus]
-	BUILDIN_DEF(getrefine,"*"), // returns the refined number of the current item, or an item with index specified [celest]
+	BUILDIN_DEF(getrefine,""), // returns the refined number of the current item, or an item with index specified [celest]
 	BUILDIN_DEF(night,""), // sets the server to night time
 	BUILDIN_DEF(day,""), // sets the server to day time
 #ifdef PCRE_SUPPORT
@@ -14711,13 +14977,13 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr]
 #endif
 	BUILDIN_DEF(dispbottom,"s"), //added from jA [Lupus]
-	BUILDIN_DEF(getusersname,"*"),
+	BUILDIN_DEF(getusersname,""),
 	BUILDIN_DEF(recovery,""),
 	BUILDIN_DEF(getpetinfo,"i"),
 	BUILDIN_DEF(gethominfo,"i"),
 	BUILDIN_DEF(checkequipedcard,"i"),
-	BUILDIN_DEF(jump_zero,"ii"), //for future jA script compatibility
-	BUILDIN_DEF(globalmes,"s*"),
+	BUILDIN_DEF(jump_zero,"il"), //for future jA script compatibility
+	BUILDIN_DEF(globalmes,"s?"),
 	BUILDIN_DEF(getmapmobs,"s"), //end jA addition
 	BUILDIN_DEF(unequip,"i"), // unequip command [Spectre]
 	BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris]
@@ -14734,22 +15000,22 @@ struct script_function buildin_func[] = {
 	// <--- [zBuffer] List of mathematics commands
 	BUILDIN_DEF(md5,"s"),
 	// [zBuffer] List of dynamic var commands --->
-	BUILDIN_DEF(getd,"*"),
-	BUILDIN_DEF(setd,"*"),
+	BUILDIN_DEF(getd,"s"),
+	BUILDIN_DEF(setd,"sv"),
 	// <--- [zBuffer] List of dynamic var commands
 	BUILDIN_DEF(petstat,"i"),
-	BUILDIN_DEF(callshop,"si"), // [Skotlex]
+	BUILDIN_DEF(callshop,"s?"), // [Skotlex]
 	BUILDIN_DEF(npcshopitem,"sii*"), // [Lance]
 	BUILDIN_DEF(npcshopadditem,"sii*"),
 	BUILDIN_DEF(npcshopdelitem,"si*"),
 	BUILDIN_DEF(npcshopattach,"s?"),
 	BUILDIN_DEF(equip,"i"),
 	BUILDIN_DEF(autoequip,"ii"),
-	BUILDIN_DEF(setbattleflag,"ss"),
+	BUILDIN_DEF(setbattleflag,"si"),
 	BUILDIN_DEF(getbattleflag,"s"),
-	BUILDIN_DEF(setitemscript,"is*"), //Set NEW item bonus script. Lupus
+	BUILDIN_DEF(setitemscript,"is?"), //Set NEW item bonus script. Lupus
 	BUILDIN_DEF(disguise,"i"), //disguise player. Lupus
-	BUILDIN_DEF(undisguise,"*"), //undisguise player. Lupus
+	BUILDIN_DEF(undisguise,""), //undisguise player. Lupus
 	BUILDIN_DEF(getmonsterinfo,"ii"), //Lupus
 	BUILDIN_DEF(axtoi,"s"),
 	BUILDIN_DEF(query_sql,"s*"),
@@ -14780,10 +15046,10 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(warpportal,"iisii"),
 	BUILDIN_DEF2(homunculus_evolution,"homevolution",""),	//[orn]
 	BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""),	//[Zephyrus]
-	BUILDIN_DEF(eaclass,"*"),	//[Skotlex]
-	BUILDIN_DEF(roclass,"i*"),	//[Skotlex]
-	BUILDIN_DEF(checkvending,"*"),
-	BUILDIN_DEF(checkchatting,"*"),
+	BUILDIN_DEF(eaclass,"?"),	//[Skotlex]
+	BUILDIN_DEF(roclass,"i?"),	//[Skotlex]
+	BUILDIN_DEF(checkvending,"?"),
+	BUILDIN_DEF(checkchatting,"?"),
 	BUILDIN_DEF(openmail,""),
 	BUILDIN_DEF(openauction,""),
 	BUILDIN_DEF(checkcell,"siii"),
@@ -14801,7 +15067,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(readbook,"ii"),
 	BUILDIN_DEF(setfont,"i"),
 	BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
-	BUILDIN_DEF(progressbar, "si"),
+	BUILDIN_DEF(progressbar,"si"),
 	BUILDIN_DEF(pushpc,"ii"),
 	// WoE SE
 	BUILDIN_DEF(agitstart2,""),
@@ -14812,7 +15078,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(waitingroom2bg_single,"isiis"),
 	BUILDIN_DEF(bg_team_setxy,"iii"),
 	BUILDIN_DEF(bg_warp,"isii"),
-	BUILDIN_DEF(bg_monster,"isiisi*"),
+	BUILDIN_DEF(bg_monster,"isiisi?"),
 	BUILDIN_DEF(bg_monster_set_team,"ii"),
 	BUILDIN_DEF(bg_leave,""),
 	BUILDIN_DEF(bg_destroy,"i"),
@@ -14830,7 +15096,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(instance_id,"?"),
 	BUILDIN_DEF(instance_set_timeout,"ii?"),
 	BUILDIN_DEF(instance_init,"i"),
-	BUILDIN_DEF(instance_announce,"isi*"),
+	BUILDIN_DEF(instance_announce,"isi?????"),
 	BUILDIN_DEF(instance_npcname,"s?"),
 	BUILDIN_DEF(has_instance,"s?"),
 	BUILDIN_DEF(instance_warpall,"sii?"),
@@ -14839,7 +15105,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(setquest, "i"),
 	BUILDIN_DEF(erasequest, "i"),
 	BUILDIN_DEF(completequest, "i"),
-	BUILDIN_DEF(checkquest, "i*"),
+	BUILDIN_DEF(checkquest, "i?"),
 	BUILDIN_DEF(changequest, "ii"),
 	BUILDIN_DEF(showevent, "ii"),
 	{NULL,NULL,NULL},
diff --git a/src/map/script.h b/src/map/script.h
index aa6b85140..d6ede0e8b 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -11,6 +11,7 @@ extern int potion_hp, potion_per_hp, potion_sp, potion_per_sp;
 extern int potion_target;
 
 extern struct Script_Config {
+	unsigned warn_func_mismatch_argtypes : 1;
 	unsigned warn_func_mismatch_paramnum : 1;
 	int check_cmdcount;
 	int check_gotocount;
@@ -121,6 +122,9 @@ struct script_state {
 		int tick,timer,charid;
 	} sleep;
 	int instance_id;
+	//For backing up purposes
+	struct script_state *bk_st;
+	int bk_npcid;
 };
 
 struct script_reg {
@@ -163,6 +167,9 @@ struct DBMap* script_get_label_db(void);
 struct DBMap* script_get_userfunc_db(void);
 void script_run_autobonus(const char *autobonus,int id, int pos);
 
+void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value);
+void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache);
+
 int script_config_read(char *cfgName);
 int do_init_script(void);
 int do_final_script(void);
diff --git a/src/map/skill.c b/src/map/skill.c
index ccc3d96f9..3c4cbcd21 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -180,9 +180,7 @@ int skill_tree_get_max(int id, int b_class)
 		return skill_get_max(id);
 }
 
-int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
 int skill_frostjoke_scream(struct block_list *bl,va_list ap);
-int status_change_timer_sub(struct block_list *bl, va_list ap);
 int skill_attack_area(struct block_list *bl,va_list ap);
 struct skill_unit_group *skill_locate_element_field(struct block_list *bl); // [Skotlex]
 int skill_graffitiremover(struct block_list *bl, va_list ap); // [Valaris]
@@ -734,7 +732,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
 	case AM_ACIDTERROR:
 		sc_start(bl,SC_BLEEDING,(skilllv*3),skilllv,skill_get_time2(skillid,skilllv));
 		if (skill_break_equip(bl, EQP_ARMOR, 100*skill_get_time(skillid,skilllv), BCT_ENEMY))
-			clif_emotion(bl,23);
+			clif_emotion(bl,E_OMG);
 		break;
 
 	case AM_DEMONSTRATION:
@@ -1093,11 +1091,14 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
 	if( sd == NULL || skillid <= 0 )
 		return 0;
 
-	sd->state.skillonskill = 1;
 	for( i = 0; i < ARRAYLENGTH(sd->autospell3) && sd->autospell3[i].flag; i++ )
 	{
 		if( sd->autospell3[i].flag != skillid )
 			continue;
+
+		if( sd->autospell3[i].lock )
+			continue;  // autospell already being executed
+
 		skill = (sd->autospell3[i].id > 0) ? sd->autospell3[i].id : -sd->autospell3[i].id;
 		if( skillnotok(skill, sd) )
 			continue;
@@ -1115,6 +1116,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
 			continue;
 
 		sd->state.autocast = 1;
+		sd->autospell3[i].lock = true;
 		skill_consume_requirement(sd,skill,skilllv,1);
 		switch( skill_get_casttype(skill) )
 		{
@@ -1122,6 +1124,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
 			case CAST_NODAMAGE: skill_castend_nodamage_id(&sd->bl, tbl, skill, skilllv, tick, 0); break;
 			case CAST_DAMAGE:   skill_castend_damage_id(&sd->bl, tbl, skill, skilllv, tick, 0); break;
 		}
+		sd->autospell3[i].lock = false;
 		sd->state.autocast = 0;
 	}
 
@@ -1139,7 +1142,6 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
 		}
 	}
 
-	sd->state.skillonskill = 0;
 	return 1;
 }
 
@@ -2307,11 +2309,11 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr data)
 
 			switch(skl->skill_id) {
 				case RG_INTIMIDATE:
-					if (unit_warp(src,-1,-1,-1,3) == 0) {
+					if (unit_warp(src,-1,-1,-1,CLR_TELEPORT) == 0) {
 						short x,y;
 						map_search_freecell(src, 0, &x, &y, 1, 1, 0);
 						if (target != src && !status_isdead(target))
-							unit_warp(target, -1, x, y, 3);
+							unit_warp(target, -1, x, y, CLR_TELEPORT);
 					}
 					break;
 				case BA_FROSTJOKER:
@@ -3002,7 +3004,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
 		break;
 
 	case NPC_DARKBREATH:
-		clif_emotion(src,7);
+		clif_emotion(src,E_AG);
 	case SN_FALCONASSAULT:
 	case PA_PRESSURE:
 	case CR_ACIDDEMONSTRATION:
@@ -3098,8 +3100,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
 	{
 		if( sd->state.arrow_atk ) //Consume arrow on last invocation to this skill.
 			battle_consume_ammo(sd, skillid, skilllv);
-		if( !sd->state.skillonskill )
-			skill_onskillusage(sd, bl, skillid, tick);
+		skill_onskillusage(sd, bl, skillid, tick);
 		skill_consume_requirement(sd,skillid,skilllv,2);
 	}
 
@@ -4418,9 +4419,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 			if( sd->state.autocast || ( (sd->skillitem == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skilllv == 1 ) || skilllv == 3 )
 			{
 				if( skilllv == 1 )
-					pc_randomwarp(sd,3);
+					pc_randomwarp(sd,CLR_TELEPORT);
 				else
-					pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+					pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
 				break;
 			}
 
@@ -4430,12 +4431,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 			else
 				clif_skill_warppoint(sd,skillid,skilllv, (unsigned short)-1,sd->status.save_point.map,0,0);
 		} else
-			unit_warp(bl,-1,-1,-1,3);
+			unit_warp(bl,-1,-1,-1,CLR_TELEPORT);
 		break;
 
 	case NPC_EXPULSION:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
-		unit_warp(bl,-1,-1,-1,3);
+		unit_warp(bl,-1,-1,-1,CLR_TELEPORT);
 		break;
 
 	case AL_HOLYWATER:
@@ -5360,7 +5361,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 				case 5:	// 2000HP heal, random teleported
 					status_heal(src, 2000, 0, 0);
 					if( !map_flag_vs(bl->m) )
-						unit_warp(bl, -1,-1,-1, 3);
+						unit_warp(bl, -1,-1,-1, CLR_TELEPORT);
 					break;
 				case 6:	// random 2 other effects
 					if (count == -1)
@@ -5435,7 +5436,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 		{	//Erase death count 1% of the casts
 			dstsd->die_counter = 0;
 			pc_setglobalreg(dstsd,"PC_DIE_COUNTER", 0);
-			clif_misceffect2(bl, 0x152);
+			clif_specialeffect(bl, 0x152, AREA);
 			//SC_SPIRIT invokes status_calc_pc for us.
 		}
 		clif_skill_nodamage(src,bl,skillid,skilllv,
@@ -5530,7 +5531,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 						continue;
 					if(map_getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH))
 						dx[j] = dy[j] = 0;
-					pc_setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], 2);
+					pc_setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], CLR_RESPAWN);
 				}
 			}
 			if (sd)
@@ -5720,8 +5721,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 	{
 		if( sd->state.arrow_atk ) //Consume arrow on last invocation to this skill.
 			battle_consume_ammo(sd, skillid, skilllv);
-		if( !sd->state.skillonskill )
-			skill_onskillusage(sd, bl, skillid, tick);
+		skill_onskillusage(sd, bl, skillid, tick);
 		skill_consume_requirement(sd,skillid,skilllv,2);
 	}
 
@@ -6585,8 +6585,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
 	{
 		if( sd->state.arrow_atk && !(flag&1) ) //Consume arrow if a ground skill was not invoked. [Skotlex]
 			battle_consume_ammo(sd, skillid, skilllv);
-		if( !sd->state.skillonskill )
-			skill_onskillusage(sd, NULL, skillid, tick);
+		skill_onskillusage(sd, NULL, skillid, tick);
 		skill_consume_requirement(sd,skillid,skilllv,2);
 	}
 
@@ -6643,9 +6642,9 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char
 	{
 	case AL_TELEPORT:
 		if(strcmp(map,"Random")==0)
-			pc_randomwarp(sd,3);
+			pc_randomwarp(sd,CLR_TELEPORT);
 		else if (sd->menuskill_val > 1) //Need lv2 to be able to warp here.
-			pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+			pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
 		break;
 
 	case AL_WARP:
@@ -7259,7 +7258,7 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un
 				if( --sg->val1 <= 0 )
 					skill_delunitgroup(sg);
 
-				pc_setpos(sd,m,x,y,3);
+				pc_setpos(sd,m,x,y,CLR_TELEPORT);
 				sg = src->group; // avoid dangling pointer (pc_setpos can cause deletion of 'sg')
 			}
 		} else
@@ -7267,7 +7266,7 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un
 		{
 			int 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,3);
+			unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT);
 		}
 		break;
 
@@ -7569,7 +7568,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
 				}
 				else
 					sec = 3000; //Couldn't trap it?
-				clif_01ac(&src->bl); // mysterious packet
+				clif_skillunit_update(&src->bl);
 				sg->limit = DIFF_TICK(tick,sg->tick)+sec;
 				sg->interval = -1;
 				src->range = 0;
@@ -9307,7 +9306,7 @@ void skill_repairweapon (struct map_session_data *sd, int idx)
 		return;
 	}
 
-	if (itemdb_type(item->nameid)==4)
+	if (itemdb_type(item->nameid)==IT_WEAPON)
 		material = materials [itemdb_wlv(item->nameid)-1]; // Lv1/2/3/4 weapons consume 1 Iron Ore/Iron/Steel/Rough Oridecon
 	else
 		material = materials [2]; // Armors consume 1 Steel
@@ -9358,7 +9357,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx)
 		struct item_data *ditem = sd->inventory_data[idx];
 		item = &sd->status.inventory[idx];
 
-		if(item->nameid > 0 && ditem->type == 4)
+		if(item->nameid > 0 && ditem->type == IT_WEAPON)
 		{
 			if( item->refine >= sd->menuskill_val
 			||  item->refine >= MAX_REFINE		// if it's no longer refineable
@@ -9408,7 +9407,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx)
 				clif_refine(sd->fd,1,idx,item->refine);
 				pc_delitem(sd,idx,1,0,2);
 				clif_misceffect(&sd->bl,2);
-				clif_emotion(&sd->bl, 23);
+				clif_emotion(&sd->bl, E_OMG);
 			}
 		}
 	}
@@ -10162,13 +10161,17 @@ struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count,
 /*==========================================
  *
  *------------------------------------------*/
-int skill_delunitgroup (struct skill_unit_group *group)
+int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int line, const char* func)
 {
 	struct block_list* src;
 	struct unit_data *ud;
 	int i,j;
 
-	nullpo_ret(group);
+	if( group == NULL )
+	{
+		ShowDebug("skill_delunitgroup: group is NULL (source=%s:%d, %s)! Please report this! (#3504)\n", file, line, func);
+		return 0;
+	}
 
 	src=map_id2bl(group->src_id);
 	ud = unit_bl2ud(src);
@@ -10404,13 +10407,13 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap)
 		  			sd = map_charid2sd(group->val1);
 					group->val1 = 0;
 					if (sd && !map[sd->bl.m].flag.nowarp)
-						pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,3);
+						pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
 				}
 				if(group->val2) {
 					sd = map_charid2sd(group->val2);
 					group->val2 = 0;
 					if (sd && !map[sd->bl.m].flag.nowarp)
-						pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,3);
+						pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
 				}
 				skill_delunit(unit);
 			}
diff --git a/src/map/skill.h b/src/map/skill.h
index 04f2e8d28..fc7877be3 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -272,7 +272,8 @@ struct skill_unit_group *skill_unitsetting(struct block_list* src, short skillid
 struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2);
 int skill_delunit(struct skill_unit *unit);
 struct skill_unit_group *skill_initunitgroup(struct block_list* src, int count, short skillid, short skilllv, int unit_id, int limit, int interval);
-int skill_delunitgroup(struct skill_unit_group *group);
+int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int line, const char* func);
+#define skill_delunitgroup(group) skill_delunitgroup_(group,__FILE__,__LINE__,__func__)
 int skill_clear_unitgroup(struct block_list *src);
 int skill_clear_group(struct block_list *bl, int flag);
 
diff --git a/src/map/status.c b/src/map/status.c
index 95d7f3796..449ea8f56 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -8,6 +8,7 @@
 #include "../common/malloc.h"
 #include "../common/utils.h"
 #include "../common/ers.h"
+#include "../common/strlib.h"
 
 #include "map.h"
 #include "path.h"
@@ -831,16 +832,16 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 	status_change_clear(target,0);
 
 	if(flag&4) //Delete from memory. (also invokes map removal code)
-		unit_free(target,1);
+		unit_free(target,CLR_DEAD);
 	else
 	if(flag&2) //remove from map
-		unit_remove_map(target,1);
+		unit_remove_map(target,CLR_DEAD);
 	else
 	{ //Some death states that would normally be handled by unit_remove_map
 		unit_stop_attack(target);
 		unit_stop_walking(target,1);
 		unit_skillcastcancel(target,0);
-		clif_clearunit_area(target,1);
+		clif_clearunit_area(target,CLR_DEAD);
 		skill_unit_move(target,gettick(),4);
 		skill_cleartimerskill(target);
 	}
@@ -1083,7 +1084,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int
 
 		if (sc->data[SC_WINKCHARM] && target && !flag)
 		{	//Prevents skill usage
-			clif_emotion(src, 3);
+			clif_emotion(src, E_LV);
 			return 0;
 		}
 
@@ -1546,8 +1547,13 @@ int status_calc_pet_(struct pet_data *pd, bool first)
 
 	if (first) {
 		memcpy(&pd->status, &pd->db->status, sizeof(struct status_data));
-		pd->status.mode|= MD_CANMOVE; //so they can chase their master!
+		pd->status.mode = MD_CANMOVE; // pets discard all modes, except walking
 		pd->status.speed = pd->petDB->speed;
+
+		if(battle_config.pet_attack_support || battle_config.pet_damage_support)
+		{// attack support requires the pet to be able to attack
+			pd->status.mode|= MD_CANATTACK;
+		}
 	}
 
 	if (battle_config.pet_lv_rate && pd->msd)
@@ -1840,6 +1846,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
 		+ sizeof(sd->aspd_add)
 		+ sizeof(sd->setitem_hash)
 		+ sizeof(sd->setitem_hash2)
+		+ sizeof(sd->itemhealrate2)
 		// shorts
 		+ sizeof(sd->splash_range)
 		+ sizeof(sd->splash_add_range)
@@ -1859,8 +1866,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
 
 	// Autobonus
 	pc_delautobonus(sd,sd->autobonus,ARRAYLENGTH(sd->autobonus),true);
-	pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus),true);
-	pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus),true);
+	pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus2),true);
+	pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true);
 
 	// Parse equipment.
 	for(i=0;i<EQI_MAX-1;i++) {
@@ -3091,6 +3098,9 @@ void status_calc_bl_(struct block_list* bl, enum scb_flag flag, bool first)
 		}
 	}
 
+	if( bl->type == BL_PET )
+		return; // pets are not affected by statuses
+
 	if( first && bl->type == BL_MOB )
 		return; // assume there will be no statuses active
 
@@ -4915,51 +4925,51 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
 			return 0; // Stats only for Mercenaries
 	break;
 	case SC_STRFOOD:
-		if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > val1)
 			return 0;
 	break;
 	case SC_AGIFOOD:
-		if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > val1)
 			return 0;
 	break;
 	case SC_VITFOOD:
-		if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > val1)
 			return 0;
 	break;
 	case SC_INTFOOD:
-		if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > val1)
 			return 0;
 	break;
 	case SC_DEXFOOD:
-		if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > val1)
 			return 0;
 	break;
 	case SC_LUKFOOD:
-		if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > val1)
 			return 0;
 	break;
 	case SC_FOOD_STR_CASH:
-		if (sc->data[SC_STRFOOD] && sc->data[SC_STRFOOD]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_STRFOOD] && sc->data[SC_STRFOOD]->val1 > val1)
 			return 0;
 	break;
 	case SC_FOOD_AGI_CASH:
-		if (sc->data[SC_AGIFOOD] && sc->data[SC_AGIFOOD]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_AGIFOOD] && sc->data[SC_AGIFOOD]->val1 > val1)
 			return 0;
 	break;
 	case SC_FOOD_VIT_CASH:
-		if (sc->data[SC_VITFOOD] && sc->data[SC_VITFOOD]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_VITFOOD] && sc->data[SC_VITFOOD]->val1 > val1)
 			return 0;
 	break;
 	case SC_FOOD_INT_CASH:
-		if (sc->data[SC_INTFOOD] && sc->data[SC_INTFOOD]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_INTFOOD] && sc->data[SC_INTFOOD]->val1 > val1)
 			return 0;
 	break;
 	case SC_FOOD_DEX_CASH:
-		if (sc->data[SC_DEXFOOD] && sc->data[SC_DEXFOOD]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_DEXFOOD] && sc->data[SC_DEXFOOD]->val1 > val1)
 			return 0;
 	break;
 	case SC_FOOD_LUK_CASH:
-		if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 > sc->data[type]->val1)
+		if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 > val1)
 			return 0;
 	break;
 	}
@@ -5084,52 +5094,40 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
 		status_change_end(bl,SC_INCREASEAGI,-1);
 		break;
 	case SC_STRFOOD:
-		if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_FOOD_STR_CASH,-1);
+		status_change_end(bl,SC_FOOD_STR_CASH,-1);
 		break;
 	case SC_AGIFOOD:
-		if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_FOOD_AGI_CASH,-1);
+		status_change_end(bl,SC_FOOD_AGI_CASH,-1);
 		break;
 	case SC_VITFOOD:
-		if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_FOOD_VIT_CASH,-1);
+		status_change_end(bl,SC_FOOD_VIT_CASH,-1);
 		break;
 	case SC_INTFOOD:
-		if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_FOOD_INT_CASH,-1);
+		status_change_end(bl,SC_FOOD_INT_CASH,-1);
 		break;
 	case SC_DEXFOOD:
-		if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_FOOD_DEX_CASH,-1);
+		status_change_end(bl,SC_FOOD_DEX_CASH,-1);
 		break;
 	case SC_LUKFOOD:
-		if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_FOOD_LUK_CASH,-1);
+		status_change_end(bl,SC_FOOD_LUK_CASH,-1);
 		break;
 	case SC_FOOD_STR_CASH:
-		if (sc->data[SC_STRFOOD] && sc->data[SC_STRFOOD]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_STRFOOD,-1);
+		status_change_end(bl,SC_STRFOOD,-1);
 		break;
 	case SC_FOOD_AGI_CASH:
-		if (sc->data[SC_AGIFOOD] && sc->data[SC_AGIFOOD]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_AGIFOOD,-1);
+		status_change_end(bl,SC_AGIFOOD,-1);
 		break;
 	case SC_FOOD_VIT_CASH:
-		if (sc->data[SC_VITFOOD] && sc->data[SC_VITFOOD]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_VITFOOD,-1);
+		status_change_end(bl,SC_VITFOOD,-1);
 		break;
 	case SC_FOOD_INT_CASH:
-		if (sc->data[SC_INTFOOD] && sc->data[SC_INTFOOD]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_INTFOOD,-1);
+		status_change_end(bl,SC_INTFOOD,-1);
 		break;
 	case SC_FOOD_DEX_CASH:
-		if (sc->data[SC_DEXFOOD] && sc->data[SC_DEXFOOD]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_DEXFOOD,-1);
+		status_change_end(bl,SC_DEXFOOD,-1);
 		break;
 	case SC_FOOD_LUK_CASH:
-		if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 <= sc->data[type]->val1)
-			status_change_end(bl,SC_LUKFOOD,-1);
+		status_change_end(bl,SC_LUKFOOD,-1);
 		break;
 	}
 
@@ -5258,7 +5256,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
 		case SC_SIGNUMCRUCIS:
 			val2 = 10 + 4*val1; //Def reduction
 			tick = -1;
-			clif_emotion(bl,4);
+			clif_emotion(bl,E_SWT);
 			break;
 		case SC_MAXIMIZEPOWER:
 			val2 = tick>0?tick:60000;
@@ -5475,7 +5473,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
 		
 		break;
 		case SC_CONFUSION:
-			clif_emotion(bl,1);
+			clif_emotion(bl,E_WHAT);
 			break;
 		case SC_BLEEDING:
 			val4 = tick/10000;
@@ -5945,7 +5943,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
 					int pos =  (bl->x&0xFFFF)|(bl->y<<16), //Current Coordinates
 					map =  sd->mapindex; //Current Map
 					//1. Place in Jail (val2 -> Jail Map, val3 -> x, val4 -> y
-					pc_setpos(sd,(unsigned short)val2,val3,val4, 3);
+					pc_setpos(sd,(unsigned short)val2,val3,val4, CLR_TELEPORT);
 					//2. Set restore point (val3 -> return map, val4 return coords
 					val3 = map;
 					val4 = pos;
@@ -6607,6 +6605,15 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 				if(sce->val2)
 				{// erase associated land skill
 					group = skill_id2group(sce->val2);
+
+					if( group == NULL )
+					{
+						ShowDebug("status_change_end: SC_DANCING is missing skill unit group (val1=%d, val2=%d, val3=%d, val4=%d, timer=%d, tid=%d, char_id=%d, map=%s, x=%d, y=%d). Please report this! (#3504)\n",
+							sce->val1, sce->val2, sce->val3, sce->val4, sce->timer, tid,
+							sd ? sd->status.char_id : 0,
+							mapindex_id2name(map_id2index(bl->m)), bl->x, bl->y);
+					}
+
 					sce->val2 = 0;
 					skill_delunitgroup(group);
 				}
@@ -6728,7 +6735,7 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 				break;
 		  	//natural expiration.
 			if(sd && sd->mapindex == sce->val2)
-				pc_setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, 3);
+				pc_setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT);
 			break; //guess hes not in jail :P
 		case SC_CHANGE:
 			if (tid == -1)
@@ -7668,146 +7675,124 @@ static int status_natural_heal_timer(int tid, unsigned int tick, int id, intptr
 	return 0;
 }
 
-int status_readdb(void)
-{
-	int i,j,class_;
-	FILE *fp;
-	char line[1024], path[1024],*p;
-
-	sprintf(path, "%s/job_db1.txt", db_path);
-	fp=fopen(path,"r"); // Job-specific values (weight, HP, SP, ASPD)
-	if(fp==NULL){
-		ShowError("can't read %s\n", path);
-		return 1;
+/*==========================================
+ * DB reading.
+ * job_db1.txt    - weight, hp, sp, aspd
+ * job_db2.txt    - job level stat bonuses
+ * size_fix.txt   - size adjustment table for weapons
+ * refine_db.txt  - refining data table
+ *------------------------------------------*/
+static bool status_readdb_job1(char* fields[], int columns, int current)
+{// Job-specific values (weight, HP, SP, ASPD)
+	int idx, class_;
+	unsigned int i;
+
+	class_ = atoi(fields[0]);
+
+	if(!pcdb_checkid(class_))
+	{
+		ShowWarning("status_readdb_job1: Invalid job class %d specified.\n", class_);
+		return false;
 	}
-	i = 0;
-	while(fgets(line, sizeof(line), fp))
+	idx = pc_class2idx(class_);
+
+	max_weight_base[idx] = atoi(fields[1]);
+	hp_coefficient[idx]  = atoi(fields[2]);
+	hp_coefficient2[idx] = atoi(fields[3]);
+	sp_coefficient[idx]  = atoi(fields[4]);
+
+	for(i = 0; i < MAX_WEAPON_TYPE; i++)
 	{
-		//NOTE: entry MAX_WEAPON_TYPE is not counted
-		char* split[5 + MAX_WEAPON_TYPE];
-		i++;
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		for(j=0,p=line; j < 5 + MAX_WEAPON_TYPE && p; j++){
-			split[j]=p;
-			p=strchr(p,',');
-			if(p) *p++=0;
-		}
-		if(j < 5 + MAX_WEAPON_TYPE)
-		{	//Weapon #.MAX_WEAPON_TYPE is constantly not load. Fix to that: replace < with <= [blackhole89]
-			ShowDebug("%s: Not enough columns at line %d\n", path, i);
-			continue;
-		}
-		class_ = atoi(split[0]);
-		if(!pcdb_checkid(class_))
-			continue;
-		class_ = pc_class2idx(class_);
-		max_weight_base[class_]=atoi(split[1]);
-		hp_coefficient[class_]=atoi(split[2]);
-		hp_coefficient2[class_]=atoi(split[3]);
-		sp_coefficient[class_]=atoi(split[4]);
-		for(j=0;j<MAX_WEAPON_TYPE;j++)
-			aspd_base[class_][j]=atoi(split[j+5]);
+		aspd_base[idx][i] = atoi(fields[i+5]);
 	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+	return true;
+}
 
-	memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus
-	sprintf(path, "%s/job_db2.txt", db_path);
-	fp=fopen(path,"r");
-	if(fp==NULL){
-		ShowError("can't read %s\n", path);
-		return 1;
+static bool status_readdb_job2(char* fields[], int columns, int current)
+{
+	int idx, class_, i;
+
+	class_ = atoi(fields[0]);
+
+	if(!pcdb_checkid(class_))
+	{
+		ShowWarning("status_readdb_job2: Invalid job class %d specified.\n", class_);
+		return false;
 	}
-	while(fgets(line, sizeof(line), fp))
+	idx = pc_class2idx(class_);
+
+	for(i = 1; i < columns; i++)
 	{
-		char *split[MAX_LEVEL+1]; //Job Level is limited to MAX_LEVEL, so the bonuses should likewise be limited to it. [Skotlex]
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		for(j=0,p=line;j<MAX_LEVEL+1 && p;j++){
-			split[j]=p;
-			p=strchr(p,',');
-			if(p) *p++=0;
-		}
-		class_ = atoi(split[0]);
-		if(!pcdb_checkid(class_))
-		    continue;
-		class_ = pc_class2idx(class_);
-		for(i=1;i<j && split[i];i++)
-			job_bonus[class_][i-1]=atoi(split[i]);
-	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
-
-	// �T�C�Y�␳�e?�u��
-	for(i=0;i<3;i++)
-		for(j=0;j<MAX_WEAPON_TYPE;j++)
-			atkmods[i][j]=100;
-	sprintf(path, "%s/size_fix.txt", db_path);
-	fp=fopen(path,"r");
-	if(fp==NULL){
-		ShowError("can't read %s\n", path);
-		return 1;
+		job_bonus[idx][i-1] = atoi(fields[i]);
 	}
-	i=0;
-	while(fgets(line, sizeof(line), fp))
+	return true;
+}
+
+static bool status_readdb_sizefix(char* fields[], int columns, int current)
+{
+	unsigned int i;
+
+	for(i = 0; i < MAX_WEAPON_TYPE; i++)
 	{
-		char *split[MAX_WEAPON_TYPE];
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		if(atoi(line)<=0)
-			continue;
-		memset(split,0,sizeof(split));
-		for(j=0,p=line;j<MAX_WEAPON_TYPE && p;j++){
-			split[j]=p;
-			p=strchr(p,',');
-			if(p) *p++=0;
-			atkmods[i][j]=atoi(split[j]);
-		}
-		i++;
+		atkmods[current][i] = atoi(fields[i]);
 	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+	return true;
+}
+
+static bool status_readdb_refine(char* fields[], int columns, int current)
+{
+	int i;
+
+	refinebonus[current][0] = atoi(fields[0]);  // stats per safe-upgrade
+	refinebonus[current][1] = atoi(fields[1]);  // stats after safe-limit
+	refinebonus[current][2] = atoi(fields[2]);  // safe limit
+
+	for(i = 0; i < MAX_REFINE; i++)
+	{
+		percentrefinery[current][i] = atoi(fields[3+i]);
+	}
+	return true;
+}
 
-	// ��?�f?�^�e?�u��
-	for(i=0;i<5;i++){
+int status_readdb(void)
+{
+	int i, j;
+
+	// initialize databases to default
+	//
+
+	// job_db1.txt
+	memset(max_weight_base, 0, sizeof(max_weight_base));
+	memset(hp_coefficient, 0, sizeof(hp_coefficient));
+	memset(hp_coefficient2, 0, sizeof(hp_coefficient2));
+	memset(sp_coefficient, 0, sizeof(sp_coefficient));
+	memset(aspd_base, 0, sizeof(aspd_base));
+
+	// job_db2.txt
+	memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus
+
+	// size_fix.txt
+	for(i=0;i<ARRAYLENGTH(atkmods);i++)
+		for(j=0;j<MAX_WEAPON_TYPE;j++)
+			atkmods[i][j]=100;
+
+	// refine_db.txt
+	for(i=0;i<ARRAYLENGTH(percentrefinery);i++){
 		for(j=0;j<MAX_REFINE; j++)
-			percentrefinery[i][j]=100;
+			percentrefinery[i][j]=100;  // success chance
 		percentrefinery[i][j]=0; //Slot MAX+1 always has 0% success chance [Skotlex]
-		refinebonus[i][0]=0;
-		refinebonus[i][1]=0;
-		refinebonus[i][2]=10;
+		refinebonus[i][0]=0;  // stats per safe-upgrade
+		refinebonus[i][1]=0;  // stats after safe-limit
+		refinebonus[i][2]=10;  // safe limit
 	}
 
-	sprintf(path, "%s/refine_db.txt", db_path);
-	fp=fopen(path,"r");
-	if(fp==NULL){
-		ShowError("can't read %s\n", path);
-		return 1;
-	}
-	i=0;
-	while(fgets(line, sizeof(line), fp))
-	{
-		char *split[MAX_REFINE+4];
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		if(atoi(line)<=0)
-			continue;
-		memset(split,0,sizeof(split));
-		for(j=0,p=line;j<MAX_REFINE+4 && p;j++){
-			split[j]=p;
-			p=strchr(p,',');
-			if(p) *p++=0;
-		}
-		refinebonus[i][0]=atoi(split[0]);	// ��?�{?�i�X
-		refinebonus[i][1]=atoi(split[1]);	// ��?��?�{?�i�X
-		refinebonus[i][2]=atoi(split[2]);	// ���S��?���E
-		for(j=0;j<MAX_REFINE && split[j+3];j++)
-			percentrefinery[i][j]=atoi(split[j+3]);
-		i++;
-	}
-	fclose(fp); //Lupus. close this file!!!
-	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+	// read databases
+	//
+
+	sv_readdb(db_path, "job_db1.txt",   ',', 5+MAX_WEAPON_TYPE, 5+MAX_WEAPON_TYPE, -1,                            &status_readdb_job1);
+	sv_readdb(db_path, "job_db2.txt",   ',', 1,                 1+MAX_LEVEL,       -1,                            &status_readdb_job2);
+	sv_readdb(db_path, "size_fix.txt",  ',', MAX_WEAPON_TYPE,   MAX_WEAPON_TYPE,    ARRAYLENGTH(atkmods),         &status_readdb_sizefix);
+	sv_readdb(db_path, "refine_db.txt", ',', 3+MAX_REFINE+1,    3+MAX_REFINE+1,     ARRAYLENGTH(percentrefinery), &status_readdb_refine);
 
 	return 0;
 }
diff --git a/src/map/storage.c b/src/map/storage.c
index 8960f7203..eb64d3eb4 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -42,17 +42,15 @@ static int storage_comp_item(const void *_i1, const void *_i2)
 		return -1;
 	return i1->nameid - i2->nameid;
 }
-/* In case someone wants to use it in the future.
-static void storage_sortitem(struct storage_data* stor)
-{
-	nullpo_retv(stor);
-	qsort(stor->items, MAX_STORAGE, sizeof(struct item), storage_comp_item);
-}
-*/
-static void storage_gsortitem(struct guild_storage* gstor)
+
+static void storage_sortitem(struct item* items, unsigned int size)
 {
-	nullpo_retv(gstor);
-	qsort(gstor->storage_, MAX_GUILD_STORAGE, sizeof(struct item), storage_comp_item);
+	nullpo_retv(items);
+
+	if( battle_config.client_sort_storage )
+	{
+		qsort(items, size, sizeof(struct item), storage_comp_item);
+	}
 }
 
 /*==========================================
@@ -104,7 +102,8 @@ int storage_storageopen(struct map_session_data *sd)
 	}
 	
 	sd->state.storage_flag = 1;
-	clif_storagelist(sd,&sd->status.storage);
+	storage_sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
+	clif_storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
 	clif_updatestorageamount(sd,sd->status.storage.storage_amount);
 	return 0;
 }
@@ -380,7 +379,8 @@ int storage_guild_storageopen(struct map_session_data* sd)
 	
 	gstor->storage_status = 1;
 	sd->state.storage_flag = 2;
-	clif_guildstoragelist(sd,gstor);
+	storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
+	clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
 	clif_updateguildstorageamount(sd,gstor->storage_amount);
 	return 0;
 }
@@ -406,11 +406,11 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
 
 	if(itemdb_isstackable2(data)){ //Stackable
 		for(i=0;i<MAX_GUILD_STORAGE;i++){
-			if(compare_item(&stor->storage_[i], item_data)) {
-				if(stor->storage_[i].amount+amount > MAX_AMOUNT)
+			if(compare_item(&stor->items[i], item_data)) {
+				if(stor->items[i].amount+amount > MAX_AMOUNT)
 					return 1;
-				stor->storage_[i].amount+=amount;
-				clif_guildstorageitemadded(sd,&stor->storage_[i],i,amount);
+				stor->items[i].amount+=amount;
+				clif_storageitemadded(sd,&stor->items[i],i,amount);
 				stor->dirty = 1;
 				if(log_config.enable_logs&0x1000)
 					log_pick_pc(sd, "G", item_data->nameid, -amount, item_data);
@@ -419,15 +419,15 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
 		}
 	}
 	//Add item
-	for(i=0;i<MAX_GUILD_STORAGE && stor->storage_[i].nameid;i++);
+	for(i=0;i<MAX_GUILD_STORAGE && stor->items[i].nameid;i++);
 	
 	if(i>=MAX_GUILD_STORAGE)
 		return 1;
 	
-	memcpy(&stor->storage_[i],item_data,sizeof(stor->storage_[0]));
-	stor->storage_[i].amount=amount;
+	memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
+	stor->items[i].amount=amount;
 	stor->storage_amount++;
-	clif_guildstorageitemadded(sd,&stor->storage_[i],i,amount);
+	clif_storageitemadded(sd,&stor->items[i],i,amount);
 	clif_updateguildstorageamount(sd,stor->storage_amount);
 	stor->dirty = 1;
 	if(log_config.enable_logs&0x1000)
@@ -440,14 +440,14 @@ int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* sto
 	nullpo_retr(1, sd);
 	nullpo_retr(1, stor);
 
-	if(stor->storage_[n].nameid==0 || stor->storage_[n].amount<amount)
+	if(stor->items[n].nameid==0 || stor->items[n].amount<amount)
 		return 1;
 
-	stor->storage_[n].amount-=amount;
+	stor->items[n].amount-=amount;
 	if(log_config.enable_logs&0x1000)
-		log_pick_pc(sd, "G", stor->storage_[n].nameid, amount, &stor->storage_[n]);
-	if(stor->storage_[n].amount==0){
-		memset(&stor->storage_[n],0,sizeof(stor->storage_[0]));
+		log_pick_pc(sd, "G", stor->items[n].nameid, amount, &stor->items[n]);
+	if(stor->items[n].amount==0){
+		memset(&stor->items[n],0,sizeof(stor->items[0]));
 		stor->storage_amount--;
 		clif_updateguildstorageamount(sd,stor->storage_amount);
 	}
@@ -496,13 +496,13 @@ int storage_guild_storageget(struct map_session_data* sd, int index, int amount)
 	if(index<0 || index>=MAX_GUILD_STORAGE)
 		return 0;
 
-	if(stor->storage_[index].nameid <= 0)
+	if(stor->items[index].nameid <= 0)
 		return 0;
 	
-	if(amount < 1 || amount > stor->storage_[index].amount)
+	if(amount < 1 || amount > stor->items[index].amount)
 	  	return 0;
 
-	if((flag = pc_additem(sd,&stor->storage_[index],amount)) == 0)
+	if((flag = pc_additem(sd,&stor->items[index],amount)) == 0)
 		guild_storage_delitem(sd,stor,index,amount);
 	else
 		clif_additem(sd,0,0,flag);
@@ -549,13 +549,13 @@ int storage_guild_storagegettocart(struct map_session_data* sd, int index, int a
 	if(index<0 || index>=MAX_GUILD_STORAGE)
 	  	return 0;
 	
-	if(stor->storage_[index].nameid<=0)
+	if(stor->items[index].nameid<=0)
 		return 0;
 	
-	if(amount < 1 || amount > stor->storage_[index].amount)
+	if(amount < 1 || amount > stor->items[index].amount)
 		return 0;
 
-	if(pc_cart_additem(sd,&stor->storage_[index],amount)==0)
+	if(pc_cart_additem(sd,&stor->items[index],amount)==0)
 		guild_storage_delitem(sd,stor,index,amount);
 
 	return 1;
@@ -584,7 +584,6 @@ int storage_guild_storagesaved(int guild_id)
 		if (stor->dirty && stor->storage_status == 0)
 		{	//Storage has been correctly saved.
 			stor->dirty = 0;
-			storage_gsortitem(stor);
 		}
 		return 1;
 	}
diff --git a/src/map/unit.c b/src/map/unit.c
index 05c0bcb16..df4efef8e 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -641,7 +641,7 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag)
 //Warps a unit/ud to a given map/position. 
 //In the case of players, pc_setpos is used.
 //it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks.
-int unit_warp(struct block_list *bl,short m,short x,short y,int type)
+int unit_warp(struct block_list *bl,short m,short x,short y,clr_type type)
 {
 	struct unit_data *ud;
 	nullpo_ret(bl);
@@ -650,7 +650,7 @@ int unit_warp(struct block_list *bl,short m,short x,short y,int type)
 	if(bl->prev==NULL || !ud)
 		return 1;
 
-	if (type < 0 || type == 1)
+	if (type == CLR_DEAD)
 		//Type 1 is invalid, since you shouldn't warp a bl with the "death" 
 		//animation, it messes up with unit_remove_map! [Skotlex]
 		return 1;
@@ -1305,8 +1305,6 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh
 	return 1;
 }
 
-static int unit_attack_timer(int tid, unsigned int tick, int id, intptr data);
-
 int unit_stop_attack(struct block_list *bl)
 {
 	struct unit_data *ud = unit_bl2ud(bl);
@@ -1800,7 +1798,7 @@ int unit_changeviewsize(struct block_list *bl,short size)
 	} else
 		return 0;
 	if(size!=0)
-		clif_misceffect2(bl,421+size);
+		clif_specialeffect(bl,421+size, AREA);
 	return 0;
 }
 
@@ -1811,7 +1809,7 @@ int unit_changeviewsize(struct block_list *bl,short size)
  * Otherwise it is assumed bl is being warped.
  * On-Kill specific stuff is not performed here, look at status_damage for that.
  *------------------------------------------*/
-int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int line, const char* func)
+int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func)
 {
 	struct unit_data *ud = unit_bl2ud(bl);
 	struct status_change *sc = status_get_sc(bl);
@@ -1960,7 +1958,7 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l
 		{	//If logging out, this is deleted on unit_free
 			clif_clearunit_area(bl,clrtype);
 			map_delblock(bl);
-			unit_free(bl,0);
+			unit_free(bl,CLR_OUTSIGHT);
 			map_freeblock_unlock();
 			return 0;
 		}
@@ -1973,10 +1971,10 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l
 		ud->canact_tick = ud->canmove_tick; //It appears HOM do reset the can-act tick.
 		if( !hd->homunculus.intimacy && !(hd->master && !hd->master->state.active) )
 		{	//If logging out, this is deleted on unit_free
-			clif_emotion(bl, 28) ;	//sob
+			clif_emotion(bl, E_SOB);
 			clif_clearunit_area(bl,clrtype);
 			map_delblock(bl);
-			unit_free(bl,0);
+			unit_free(bl,CLR_OUTSIGHT);
 			map_freeblock_unlock();
 			return 0;
 		}
@@ -1990,7 +1988,7 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l
 		{
 			clif_clearunit_area(bl,clrtype);
 			map_delblock(bl);
-			unit_free(bl,0);
+			unit_free(bl,CLR_OUTSIGHT);
 			map_freeblock_unlock();
 			return 0;
 		}
@@ -2005,11 +2003,11 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l
 	return 1;
 }
 
-void unit_remove_map_pc(struct map_session_data *sd, int clrtype)
+void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype)
 {
 	unit_remove_map(&sd->bl,clrtype);
 
-	if (clrtype == 3) clrtype = 0; //3 is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation.
+	if (clrtype == CLR_TELEPORT) clrtype = CLR_OUTSIGHT; //CLR_TELEPORT is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation.
 
 	if(sd->pd)
 		unit_remove_map(&sd->pd->bl, clrtype);
@@ -2021,19 +2019,17 @@ void unit_remove_map_pc(struct map_session_data *sd, int clrtype)
 
 void unit_free_pc(struct map_session_data *sd)
 {
-	if (sd->pd) unit_free(&sd->pd->bl,0);
-	if (sd->hd) unit_free(&sd->hd->bl,0);
-	if (sd->md) unit_free(&sd->md->bl,0);
-	unit_free(&sd->bl,3);
+	if (sd->pd) unit_free(&sd->pd->bl,CLR_OUTSIGHT);
+	if (sd->hd) unit_free(&sd->hd->bl,CLR_OUTSIGHT);
+	if (sd->md) unit_free(&sd->md->bl,CLR_OUTSIGHT);
+	unit_free(&sd->bl,CLR_TELEPORT);
 }
 
 /*==========================================
  * Function to free all related resources to the bl
  * if unit is on map, it is removed using the clrtype specified
- * If clrtype is <0, no saving is performed. This is only for non-authed
- * objects that shouldn't be on a map yet.
  *------------------------------------------*/
-int unit_free(struct block_list *bl, int clrtype)
+int unit_free(struct block_list *bl, clr_type clrtype)
 {
 	struct unit_data *ud = unit_bl2ud( bl );
 	nullpo_ret(ud);
@@ -2053,8 +2049,8 @@ int unit_free(struct block_list *bl, int clrtype)
 
 			pc_delinvincibletimer(sd);
 			pc_delautobonus(sd,sd->autobonus,ARRAYLENGTH(sd->autobonus),false);
-			pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus),false);
-			pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus),false);
+			pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus2),false);
+			pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),false);
 			
 			if( sd->followtimer != -1 )
 				pc_stop_following(sd);
@@ -2138,15 +2134,12 @@ int unit_free(struct block_list *bl, int clrtype)
 				aFree (pd->loot);
 				pd->loot = NULL;
 			}
-			if( clrtype >= 0 )
-			{
-				if( pd->pet.intimate > 0 )
-					intif_save_petdata(pd->pet.account_id,&pd->pet);
-				else
-				{	//Remove pet.
-					intif_delete_petdata(pd->pet.pet_id);
-					if (sd) sd->status.pet_id = 0;
-				}
+			if( pd->pet.intimate > 0 )
+				intif_save_petdata(pd->pet.account_id,&pd->pet);
+			else
+			{	//Remove pet.
+				intif_delete_petdata(pd->pet.pet_id);
+				if (sd) sd->status.pet_id = 0;
 			}
 			if( sd )
 				sd->pd = NULL;
@@ -2213,16 +2206,13 @@ int unit_free(struct block_list *bl, int clrtype)
 			struct homun_data *hd = (TBL_HOM*)bl;
 			struct map_session_data *sd = hd->master;
 			merc_hom_hungry_timer_delete(hd);
-			if( clrtype >= 0 )
+			if( hd->homunculus.intimacy > 0 )
+				merc_save(hd);
+			else
 			{
-				if( hd->homunculus.intimacy > 0 )
-					merc_save(hd);
-				else
-				{
-					intif_homunculus_requestdelete(hd->homunculus.hom_id);
-					if( sd )
-						sd->status.hom_id = 0;
-				}
+				intif_homunculus_requestdelete(hd->homunculus.hom_id);
+				if( sd )
+					sd->status.hom_id = 0;
 			}
 			if( sd )
 				sd->hd = NULL;
@@ -2232,16 +2222,13 @@ int unit_free(struct block_list *bl, int clrtype)
 		{
 			struct mercenary_data *md = (TBL_MER*)bl;
 			struct map_session_data *sd = md->master;
-			if( clrtype >= 0 )
+			if( mercenary_get_lifetime(md) > 0 )
+				mercenary_save(md);
+			else
 			{
-				if( mercenary_get_lifetime(md) > 0 )
-					mercenary_save(md);
-				else
-				{
-					intif_mercenary_delete(md->mercenary.mercenary_id);
-					if( sd )
-						sd->status.mer_id = 0;
-				}
+				intif_mercenary_delete(md->mercenary.mercenary_id);
+				if( sd )
+					sd->status.mer_id = 0;
 			}
 			if( sd )
 				sd->md = NULL;
diff --git a/src/map/unit.h b/src/map/unit.h
index 3b82dce56..fd5a83208 100644
--- a/src/map/unit.h
+++ b/src/map/unit.h
@@ -9,6 +9,7 @@ struct block_list;
 struct unit_data;
 struct map_session_data;
 
+#include "clif.h"  // clr_type
 #include "map.h" // struct block_list
 #include "path.h" // struct walkpath_data
 #include "skill.h" // struct skill_timerskill, struct skill_unit_group, struct skill_unit_group_tickset
@@ -81,7 +82,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int
 int unit_escape(struct block_list *bl, struct block_list *target, short dist);
 // �ʒu�̋����ړ�(������΂��Ȃ�)
 int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath);
-int unit_warp(struct block_list *bl, short map, short x, short y, int type);
+int unit_warp(struct block_list *bl, short map, short x, short y, clr_type type);
 int unit_setdir(struct block_list *bl,unsigned char dir);
 uint8 unit_getdir(struct block_list *bl);
 int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag);
@@ -114,11 +115,11 @@ void unit_dataset(struct block_list *bl);
 int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2);
 // ���̑�
 struct unit_data* unit_bl2ud(struct block_list *bl);
-void unit_remove_map_pc(struct map_session_data *sd, int clrtype);
+void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype);
 void unit_free_pc(struct map_session_data *sd);
 #define unit_remove_map(bl,clrtype) unit_remove_map_(bl,clrtype,__FILE__,__LINE__,__func__)
-int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int line, const char* func);
-int unit_free(struct block_list *bl, int clrtype);
+int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func);
+int unit_free(struct block_list *bl, clr_type clrtype);
 int unit_changeviewsize(struct block_list *bl,short size);
 
 // ���������[�`��
diff --git a/src/map/vending.c b/src/map/vending.c
index 67e5ebf19..90bff7399 100644
--- a/src/map/vending.c
+++ b/src/map/vending.c
@@ -275,7 +275,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, bool
 
 		sd->vending[i].index = index;
 		sd->vending[i].amount = amount;
-		sd->vending[i].value = cap_value(value, 1, (unsigned int)battle_config.vending_max_value);
+		sd->vending[i].value = cap_value(value, 0, (unsigned int)battle_config.vending_max_value);
 
 		i++; // item successfully added
 	}
diff --git a/src/plugins/sig.c b/src/plugins/sig.c
index 1872d48ff..9db0638ca 100644
--- a/src/plugins/sig.c
+++ b/src/plugins/sig.c
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
+#define __USE_GNU  // required to enable strsignal on some platforms
 #include <string.h>
 #include <time.h>
 #include "../common/plugin.h"
@@ -52,7 +53,6 @@ unsigned long (*getuptime)();
 char *server_name;
 int crash_flag = 0;
 
-extern const char *strsignal(int);
 int sig_final ();
 
 // by Gabuzomeu
@@ -60,9 +60,6 @@ int sig_final ();
 // (sigaction() is POSIX; signal() is not.)  Taken from Stevens' _Advanced
 // Programming in the UNIX Environment_.
 //
-#ifdef WIN32	// windows don't have SIGPIPE
-#define SIGPIPE SIGINT
-#endif
 
 #ifndef POSIX
 #define compat_signal(signo, func) signal(signo, func)
@@ -203,9 +200,7 @@ int sig_init ()
 	compat_signal(SIGSEGV, func);
 	compat_signal(SIGFPE, func);
 	compat_signal(SIGILL, func);
-	#ifndef __WIN32
-		compat_signal(SIGBUS, func);
-	#endif
+	compat_signal(SIGBUS, func);
 
 	return 1;
 }
diff --git a/src/tool/adduser.c b/src/tool/adduser.c
index 2c7461930..5f4dfb6a5 100644
--- a/src/tool/adduser.c
+++ b/src/tool/adduser.c
@@ -75,7 +75,7 @@ int main(int argc, char *argv[])
 	strcpy(username, "");
 	while (strlen(username) < 4 || strlen(username) > 23) {
 		printf("Enter an username (4-23 characters): ");
-		scanf("%s", &username);
+		scanf("%s", username);
 		username[23] = 0;
 		remove_control_chars(username);
 	}
@@ -83,7 +83,7 @@ int main(int argc, char *argv[])
 	strcpy(password, "");
 	while (strlen(password) < 4 || strlen(password) > 23) {
 		printf("Enter a password (4-23 characters): ");
-		scanf("%s", &password);
+		scanf("%s", password);
 		password[23] = 0;
 		remove_control_chars(password);
 	}
@@ -91,7 +91,7 @@ int main(int argc, char *argv[])
 	strcpy(sex, "");
 	while (strcmp(sex, "F") != 0 && strcmp(sex, "M") != 0) {
 		printf("Enter a gender (M for male, F for female): ");
-		scanf("%s", &sex);
+		scanf("%s", sex);
 	}
 
 	FPaccout = fopen(account_txt, "r+");
diff --git a/src/txt-converter/Makefile.in b/src/txt-converter/Makefile.in
index 089d9d276..50e89e34e 100644
--- a/src/txt-converter/Makefile.in
+++ b/src/txt-converter/Makefile.in
@@ -10,6 +10,7 @@ LOGIN_CONVERTER_OBJ = \
 	../common/obj_all/showmsg.o \
 	../common/obj_all/strlib.o \
 	../common/obj_all/timer.o \
+	../common/obj_all/utils.o \
 	../common/obj_sql/sql.o
 LOGIN_CONVERTER_H = \
 	../login/account.h \
@@ -23,6 +24,7 @@ LOGIN_CONVERTER_H = \
 	../common/showmsg.h \
 	../common/strlib.h \
 	../common/timer.h \
+	../common/utils.h \
 	../common/sql.h
 
 CHAR_CONVERTER_OBJ = \
-- 
cgit v1.2.3-70-g09d2